class MemoryEfficientGraph<N> extends HashMutableDirectedGraph<N> {

  HashMap<N, N> self = new HashMap<N, N>();

  @Override
  public void addNode(N o) {
    super.addNode(o);
    self.put(o, o);
  }

  @Override
  public void removeNode(N o) {
    super.removeNode(o);
    self.remove(o);
  }

  @Override
  public void addEdge(N from, N to) {
    if (containsNode(from) && containsNode(to)) {
      super.addEdge(self.get(from), self.get(to));
    } else if (!containsNode(from)) {
      throw new RuntimeException(from.toString() + " not in graph!");
    } else {
      throw new RuntimeException(to.toString() + " not in graph!");
    }
  }

  @Override
  public void removeEdge(N from, N to) {<FILL_FUNCTION_BODY>}
}

    if (containsNode(from) && containsNode(to)) {
      super.removeEdge(self.get(from), self.get(to));
    } else if (!containsNode(from)) {
      throw new RuntimeException(from.toString() + " not in graph!");
    } else {
      throw new RuntimeException(to.toString() + " not in graph!");
    }
  
<methods>public void <init>() ,public void <init>(HashMutableDirectedGraph<N>) ,public void addEdge(N, N) ,public void addNode(N) ,public void clearAll() ,public java.lang.Object clone() ,public boolean containsEdge(N, N) ,public boolean containsNode(N) ,public List<N> getHeads() ,public List<N> getNodes() ,public List<N> getPredsOf(N) ,public Set<N> getPredsOfAsSet(N) ,public List<N> getSuccsOf(N) ,public Set<N> getSuccsOfAsSet(N) ,public List<N> getTails() ,public Iterator<N> iterator() ,public void printGraph() ,public void removeEdge(N, N) ,public void removeNode(N) ,public int size() <variables>protected final non-sealed Set<N> heads,private static final org.slf4j.Logger logger,protected final non-sealed Map<N,Set<N>> nodeToPreds,protected final non-sealed Map<N,Set<N>> nodeToSuccs,protected final non-sealed Set<N> tails