public Path shortestPath(Vertex a, Vertex b) {
    	checkVertexExistence(a);
    	checkVertexExistence(b);
    	
    	// case that a and b are the same edge
    	if (a.equals(b)) {
    		List<Vertex> result = new ArrayList<>();
    		result.add(new Vertex(a));
    		return new Path(result, 0);
    	}
    	
    	Map<Vertex, Set<Edge>> adjacency = vertexToEdge;
    	Set<Vertex> known = new HashSet<>();
    	List<Vertex> vertices = new ArrayList<>();
    	PriorityQueue<Vertex> pq = new PriorityQueue<>();
    	
    	// add all vertices to master list
    	for (Vertex v : vertices()) {
    		vertices.add(new Vertex(v));
    	}
    	
    	// add start value to priority queue and master list
    	Vertex start = new Vertex(a.getLabel(), 0, null);
    	pq.add(start);
    	vertices.set(vertices.indexOf(a), start);
  
    	Vertex end = null;
    	
    	// visit each vertex once
    	for (int i = 0; i < vertices().size(); i++) {
    		Vertex current = pq.remove();
    		// mark as known and get adjacent edges
    		if (!known.contains(current)) { 
	    		known.add(current);
	    		Set<Edge> adj = adjacency.get(current);
	    		// examine every adjacent edge, assign costs
	    		for (Edge e : adj) {
	    			Vertex destination = e.getDestination();
	    			int newCost = e.getWeight() + current.getCost();
	    			int destCost = vertices.get(vertices.indexOf(destination)).getCost();
	    			// if lower cost is found, change cost
	    			if (newCost < destCost) {
	    				Vertex replaceVtx = new Vertex(destination.getLabel(), newCost, current);
        				if (replaceVtx.equals(b)) {
        					end = replaceVtx;
        				}
	    				vertices.set(vertices.indexOf(destination), replaceVtx);
		    			pq.add(replaceVtx);
	    			}
	    		}
    		}
    	}
    	
    	if (end == null) return null;
    	
    	List<Vertex> result = new LinkedList<>();  // store result to return
    	int cost = vertices.get(vertices.indexOf(end)).getCost();	
    		
    	result.add(end);
    	
    	// find shortest path
    	while(end.getPath() != null) {
    		result.add(new Vertex(end.getPath()));
    		end = end.getPath();
    	}
    	
    	Collections.reverse(result);
    	
    	return new Path(result, cost);
    }