         return result
     }
 
+    /**
+     Adds a new edge between two vertices in the graph.
+
+     This is a symmetric operation in undirected graphs - each vertex is added
+     to the other's neighbors list. Order of parameters does not matter.
+
+     - parameter from: One vertex of the desired edge.
+     - parameter to: The other vertex of the edge.
+
+     - throws: `GraphError.VertexNotPresent` if either vertex is not in the
+       graph.
+
+     - complexity: O(1) - I assume here that [].append() is O(1).
+     */
+    public func addEdge(from: Vertex, to: Vertex) throws {
+        guard let _ = adjacencyList[from] else {
+            throw GraphError.VertexNotPresent
+        }
+        guard let _ = adjacencyList[to] else {
+            throw GraphError.VertexNotPresent
+        }
+        // What should this do if the edge already exists? Throw? no-op?
+        // multiple edges?
+        adjacencyList[from]!.append(to)
+        adjacencyList[to]!.append(from)
+        // This is another thing: cannot use the guard let bindings of these
+        // optionals, since append mutates. My next thought would be to use
+        // guard var =, but apparently that is getting deprecated.
+    }
+
+    /**
+     Removes an edge from one vertex to another.
+
+     In undirected graphs, this is also symmetric. Order of the parameters
+     does not matter. Each vertex will be removed from the other's neighbors
+     list.
+
+     - parameter from: The source of the edge to remove.
+     - parameter to: The destination of the edge to remove.
+
+     - throws: `GraphError.EdgeNotPresent` if the edge is not in the graph,
+       `GraphError.VertexNotPresent` if either vertex isn't in the graph.
+
+     - complexity: O(V), or O(D)
+     */
+    public func removeEdge(from: Vertex, to: Vertex) throws {
+        guard let neighborsFrom = adjacencyList[from] else {
+            throw GraphError.VertexNotPresent
+        }
+        guard let _ = adjacencyList[to] else {
+            throw GraphError.VertexNotPresent
+        }
+        guard neighborsFrom.contains(to) else {
+            throw GraphError.EdgeNotPresent
+        }
+
+        removeFromArray(to, fromArr: &adjacencyList[from]!)
+        removeFromArray(from, fromArr: &adjacencyList[to]!)
+        // same as above, would like to use guard var, need to look for
+        // alternatives.
+    }
+}
+
+
+/**
+ Directed adjacency list. When using this class, source is different from
+ destination vertex in an edge.
+
+ In other words, if u is in v's neighbor array, v may not be in u's unless the
+ antiparallel edge exists in the graph.
+ */
+public class DirectedAList<Vertex: Hashable>: AdjacencyList<Vertex>,
+                                                    DirectedGraph {
+    
+    required public override init() {
+        super.init()
+    }
+
+    /**
+     A computed array of all the edges in the graph, as tuples of vertices.
+
+     Source of the edge is the first element, so that (v, u) means v -> u.
+
+     - complexity: O(E)
+     */
+    public var edges: [(Vertex, Vertex)] {
+        get {
+            var result = [(Vertex, Vertex)]()
+            for (vertex, neighbors) in adjacencyList {
+                for neighbor in neighbors {
+                    result.append((vertex, neighbor))
+                }
+            }
+            return result
+        }
+    }
+
+    /**
+     Adds a new edge from one vertex to another in the graph.
+
+     This is an asymmetric operation: order of arguments matters!
+
+     - parameter from: the source vertex of the desired edge
+     - parameter to: the destination vertex of the desired edge
+       in other words, the edge (from -> to) will be added
+
+     - throws: `GraphError.VertexNotPresent` if either vertex is not in the
+       graph.
+
+     - complexity: O(1)
+     */
+    public func addEdge(from: Vertex, to: Vertex) throws {
+        guard let _ = adjacencyList[from] else {
+            throw GraphError.VertexNotPresent
+        }
+        guard let _ = adjacencyList[to] else {
+            throw GraphError.VertexNotPresent
+        }
+        adjacencyList[from]!.append(to)
+    }
+
+    /**
+     Remove an edge from the graph.
+
+     - parameter from: the source vertex of the edge to remove.
+     - parameter to: the destination vertex of the edge to remove.
+
+     - throws: `GraphError.EdgeNotPresent` if the edge doesn't exist in the
+       graph, `GraphError.VertexNotPresent` if either vertex doesn't exist.
+
+     - complexity: O(V), or O(D)
+     */
+    public func removeEdge(from: Vertex, to: Vertex) throws {
+        guard let neighborsFrom = adjacencyList[from] else {
+            throw GraphError.VertexNotPresent
+        }
+        guard let _ = adjacencyList[to] else {
+            throw GraphError.VertexNotPresent
+        }
+        guard neighborsFrom.contains(to) else {
+            throw GraphError.EdgeNotPresent
+        }
+        removeFromArray(to, fromArr: &adjacencyList[from]!)
+    }
+}
+
+
+/**
+ Implementation of a weighted undirected graph using an adjacency list.
+
+ The weights are stored separately from the edges, in a dictionary of
+ dictionaries. Weights are Doubles.
+ */
+final public class WeightedUndirectedAList<Vertex: Hashable> :
+                AdjacencyList<Vertex>, WeightedUndirectedGraph {
+
+    // Adding a vertex should add an empty entry to the outer weightTable?
+
+    /**
+     A dictionary of dictionaries that stores the weight of the vertices.
+
+     Accessed like weightTable[from][to] to get the weight of the edge
+     (from, to).
+
+     Currently each edge weight is stored as either weightTable[from][to] or
+     weightTable[to][from], based on the order of parameters when the edge is
+     added. So the weight of (v, u) might be in wT[v][u] or wT[u][v]. This
+     saves space but increases the complexity of some code.
+     */
+    private var weightTable = [Vertex: [Vertex: Double]]()
+
+    required public override init() {
+        super.init()
+    }
+
+    /**
+     Computed property which is an array of edges in the graph, represented as
+     (Vertex, Vertex) tuples. Read-only.
+     */
+    public var edges: [(Vertex, Vertex)] {
+        var result = [(Vertex, Vertex)]()
+        var visited = Set<Vertex>()
+        for (vertex, neighbors) in adjacencyList {
+            for neighbor in neighbors {
+                if !visited.contains(neighbor) {
+                    result.append((vertex, neighbor))
+                }
+            }
+            visited.insert(vertex)
+        }
+        return result
+    }
+
 
     /**
      Computes the weight associated with the given edge.
 
      - parameter to: The `source` of the desired edge.
      - parameter from: The `destination` of the desired edge.
-
-     - returns: The weight associated with the given edge, a Double.
-
-     - throws: `GraphError.VertexNotPresent` if either vertex not in the graph
-       or, `GraphError.EdgeNotPresent` if the edge does not exist in the graph.
+       Note: Since this is an undirected graph, the order of the parameters
+       does not matter. weight(from, to) == weight(to, from)
+
+     - returns: The weight associated with the given edge, a Double, or nil if
+       the edge is not in the graph.
+
+     - throws: `GraphError.VertexNotPresent` if either vertex not in the graph.
      */
     public func weight(from: Vertex, to: Vertex) throws -> Double? {
         guard adjacencyList[from] != nil else {

            guard let _ = adjacencyList[neighbor] else {
                throw GraphError.VertexNotPresent
                // If this happens, the vertex to remove has a neighbor
                // which is not in the graph. Very bad.
            }
            removeFromArray(vertex, fromArr: &adjacencyList[neighbor]!)
        }

        }
    }
}

/**
 A weighted directed Adjacency List implementation of weighted, directed
 graphs. Similar to the WeightedUndirected adjacency list, but with asymmetric
 edges.

 Weights are stored separately from edges, in a nested dictionary of type
 [Vertex: [Vertex: Double]].
 */
final public class WeightedDirectedAList<Vertex: Hashable> :
                AdjacencyList<Vertex>, WeightedDirectedGraph {
    
    /**
     A nested dictionary stores the weight of each edge, and is accessed like
     weightTable[from][to]. Direction matters in this class, so that is the
     weight of the edge from -> to.
     */
    private var weightTable = [Vertex: [Vertex: Double]]()

    required public override init() {
        super.init()
    }

    /**
     A computed property which is an array of edges in the graph, represented
     as (Vertex, Vertex) tuples. Read-only.
     */
    public var edges: [(Vertex, Vertex)] {
        var result = [(Vertex, Vertex)]()
        for (vertex, neighbors) in adjacencyList {
            for neighbor in neighbors {
                result.append((vertex, neighbor))
            }
        }
        return result
    }

    /**
     Computes the weight associated with the given edge, by looking it up
     in the weight table.

     Like other methods on directed graphs, the order of the parameters is
     important. weight(from, to) may exist while weight(to, from) is nil.

     - parameter from: the source vertex of the desired edge.
     - parameter to: the destination vertex of the desired edge.

     - returns: The weight of the edge (from -> to), a Double, or nil if the
       edge does not exist in the graph.

     - throws: `GraphError.VertexNotPresent` if either vertex doesn't exist.
     */
    public func weight(from: Vertex, to: Vertex) throws -> Double? {
        guard adjacencyList[from] != nil else {
            throw GraphError.VertexNotPresent
        }
        guard adjacencyList[to] != nil else {
            throw GraphError.VertexNotPresent
        }

        return weightTable[from]?[to]
    }

    /**
     Adds a new edge of unspecified weight to the graph.

     Required to satisfy graph protocol - this is bad.
     Currently, this adds a zero-weight edge.
    
     Probably don't use it with weighted adjacency lists.
     */
    public func addEdge(from: Vertex, to: Vertex) throws {
        try addEdge(from, to: to, weight: 0.0)
    }

    /**
     Adds a new weighted edge to the graph from one vertex to another.

     Changes the graph in-place to add the weighted edge.

     - parameter from: The source of the edge to add.
     - parameter to: The source of the edge to add.
     - parameter weight: The weight of the egde to add, a double.

     - throws: `GraphError.VertexNotPresent` if either vertex doesn't exist.
     */
    public func addEdge(from: Vertex, to: Vertex, weight: Double) throws {
        guard adjacencyList[from] != nil else {
            throw GraphError.VertexNotPresent
        }
        guard adjacencyList[to] != nil else {
            throw GraphError.VertexNotPresent
        }
        adjacencyList[from]!.append(to)

        if weightTable[from] == nil {
            weightTable[from] = [to: weight]
        } else {
            weightTable[from]![to] = weight
        }
    }

    /**
     Remove an edge between two given vertices in the graph.

     - parameter from: The source of the edge to remove.
     - parameter to: The destination of the edge to remove.
     Not interchangable. This removes (from -> to) but doesn't touch the edge
     (to -> from).

     - throws: `GraphError.VertexNotPresent if those vertices don't exist,
       and `GraphError.EdgeNotPresent` if the edge doesn't exist.
     */
    public func removeEdge(from: Vertex, to: Vertex) throws {
        guard adjacencyList[from] != nil else {
            throw GraphError.VertexNotPresent
        }
        guard let neighborsTo = adjacencyList[to] else {
            throw GraphError.VertexNotPresent
        }
        guard neighborsTo.contains(from) else {
            throw GraphError.EdgeNotPresent
        }
        guard weightTable[from]?[to] != nil else {
            throw GraphError.EdgeNotPresent
            // This is even worse than just edge not present, because it means
            // the edge exists in the adjacencyList but not the weight table.
        }

        removeFromArray(to, fromArr: &adjacencyList[from]!)

        weightTable[from]!.removeValueForKey(to)
    }
}
