Skip to content

Commit

Permalink
refactor Graph implementation
Browse files Browse the repository at this point in the history
- define an abstract class called AbstractGraph, with two concrete implementations: AdjacencyListGraph and AdjacencyMatrixGraph
- improve some method naming, especially those dealing with creating (un)directed edges
- make a framework target, and add xcodeproj and playground to a workspace to import the framework module so we don't need to duplicate the implementation in the playground
- update README to reflect the new implementations/concepts

consequently, the APSP implementation is updated to use the refactored Graph implementation, plus:
- improvements to doc comments
- remove redundant parameter in FloydWarshallResult.recursePathFrom
- changed the test case ported from the book to reflect the exact names of the graph vertices
  • Loading branch information
armcknight committed Jun 5, 2016
1 parent 2b58f9f commit 495303b
Show file tree
Hide file tree
Showing 33 changed files with 1,434 additions and 536 deletions.
23 changes: 12 additions & 11 deletions All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
//: Playground - noun: a place where people can play

import Graph
import APSP

var graph = Graph<String>()
var graph = AdjacencyListGraph<String>()

let v1 = graph.createVertex("Montreal")
let v2 = graph.createVertex("New York")
let v3 = graph.createVertex("Boston")
let v4 = graph.createVertex("Portland")
let v5 = graph.createVertex("Portsmouth")

graph.connect(v1, to: v2, withWeight: 3)
graph.connect(v1, to: v5, withWeight: -4)
graph.connect(v1, to: v3, withWeight: 8)
graph.addDirectedEdge(v1, to: v2, withWeight: 3)
graph.addDirectedEdge(v1, to: v5, withWeight: -4)
graph.addDirectedEdge(v1, to: v3, withWeight: 8)

graph.connect(v2, to: v4, withWeight: 1)
graph.connect(v2, to: v5, withWeight: 7)
graph.addDirectedEdge(v2, to: v4, withWeight: 1)
graph.addDirectedEdge(v2, to: v5, withWeight: 7)

graph.connect(v3, to: v2, withWeight: 4)
graph.addDirectedEdge(v3, to: v2, withWeight: 4)

graph.connect(v4, to: v1, withWeight: 2)
graph.connect(v4, to: v3, withWeight: -5)
graph.addDirectedEdge(v4, to: v1, withWeight: 2)
graph.addDirectedEdge(v4, to: v3, withWeight: -5)

graph.connect(v5, to: v4, withWeight: 6)
graph.addDirectedEdge(v5, to: v4, withWeight: 6)

let result = FloydWarshall<String>.apply(graph)

let path = result.path(fromVertex: v1, toVertex: v4, inGraph: graph)
let path = result.path(fromVertex: v1, toVertex: v4, inGraph: graph)
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
version = "3.0">
<TimelineItems>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=790&amp;EndingColumnNumber=44&amp;EndingLineNumber=28&amp;StartingColumnNumber=3&amp;StartingLineNumber=27&amp;Timestamp=484286078.350375"
documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=888&amp;EndingColumnNumber=44&amp;EndingLineNumber=29&amp;StartingColumnNumber=3&amp;StartingLineNumber=28&amp;Timestamp=486844329.035763"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=4&amp;CharacterRangeLoc=727&amp;EndingColumnNumber=9&amp;EndingLineNumber=28&amp;StartingColumnNumber=5&amp;StartingLineNumber=28&amp;Timestamp=484286078.357412"
documentLocation = "#CharacterRangeLen=4&amp;CharacterRangeLoc=825&amp;EndingColumnNumber=9&amp;EndingLineNumber=29&amp;StartingColumnNumber=5&amp;StartingLineNumber=29&amp;Timestamp=486844329.036018"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
Expand Down
86 changes: 68 additions & 18 deletions All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,37 @@
objects = {

/* Begin PBXBuildFile section */
491AA3821CE8C5F700A2E2C5 /* Graph.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 491AA37F1CE8C5C900A2E2C5 /* Graph.framework */; };
493D8DE31CDD2A1C0089795A /* APSPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DE21CDD2A1C0089795A /* APSPTests.swift */; };
493D8DF41CDD5B960089795A /* APSP.h in Headers */ = {isa = PBXBuildFile; fileRef = 493D8DF31CDD5B960089795A /* APSP.h */; settings = {ATTRIBUTES = (Public, ); }; };
493D8DF91CDD5B9B0089795A /* FloydWarshall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DD81CDC38C60089795A /* FloydWarshall.swift */; };
493D8DFA1CDD5B9E0089795A /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DDA1CDD29C80089795A /* Helpers.swift */; };
493D8DFB1CDD5BDE0089795A /* AdjacencyMatrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 493D8DB91CDC34D00089795A /* AdjacencyMatrix.swift */; };
49BFA27A1CDD93F400522D66 /* APSP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49BFA2791CDD93F400522D66 /* APSP.swift */; };
49BFA2801CDE742900522D66 /* APSP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 493D8DF11CDD5B960089795A /* APSP.framework */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
491AA37E1CE8C5C900A2E2C5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 49BFA2FD1CDF886B00522D66;
remoteInfo = Graph;
};
491AA3801CE8C5C900A2E2C5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 49BFA3071CDF886B00522D66;
remoteInfo = GraphTests;
};
491AA3831CE8C5F900A2E2C5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 49BFA2FC1CDF886B00522D66;
remoteInfo = Graph;
};
49BFA27E1CDE742700522D66 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 493D8D7E1CDC2DAE0089795A /* Project object */;
Expand All @@ -27,7 +48,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
493D8DB91CDC34D00089795A /* AdjacencyMatrix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjacencyMatrix.swift; sourceTree = "<group>"; };
491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Graph.xcodeproj; path = ../../Graph/Graph.xcodeproj; sourceTree = "<group>"; };
493D8DD81CDC38C60089795A /* FloydWarshall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloydWarshall.swift; sourceTree = "<group>"; };
493D8DDA1CDD29C80089795A /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
493D8DE01CDD2A1C0089795A /* APSPTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APSPTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -52,16 +73,26 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
491AA3821CE8C5F700A2E2C5 /* Graph.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
491AA37A1CE8C5C900A2E2C5 /* Products */ = {
isa = PBXGroup;
children = (
491AA37F1CE8C5C900A2E2C5 /* Graph.framework */,
491AA3811CE8C5C900A2E2C5 /* GraphTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
493D8D7D1CDC2DAE0089795A = {
isa = PBXGroup;
children = (
493D8DB71CDC34D00089795A /* Graph */,
491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */,
493D8D881CDC2DAE0089795A /* APSP */,
493D8DE11CDD2A1C0089795A /* APSPTests */,
493D8D871CDC2DAE0089795A /* Products */,
Expand Down Expand Up @@ -89,15 +120,6 @@
path = APSP;
sourceTree = "<group>";
};
493D8DB71CDC34D00089795A /* Graph */ = {
isa = PBXGroup;
children = (
493D8DB91CDC34D00089795A /* AdjacencyMatrix.swift */,
);
name = Graph;
path = ../../Graph;
sourceTree = "<group>";
};
493D8DE11CDD2A1C0089795A /* APSPTests */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -151,6 +173,7 @@
buildRules = (
);
dependencies = (
491AA3841CE8C5F900A2E2C5 /* PBXTargetDependency */,
);
name = APSP;
productName = APSP;
Expand All @@ -165,7 +188,7 @@
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = "Andrew McKnight";
ORGANIZATIONNAME = "Swift Algorithm Club";
TargetAttributes = {
493D8DDF1CDD2A1C0089795A = {
CreatedOnToolsVersion = 7.3;
Expand All @@ -185,6 +208,12 @@
mainGroup = 493D8D7D1CDC2DAE0089795A;
productRefGroup = 493D8D871CDC2DAE0089795A /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 491AA37A1CE8C5C900A2E2C5 /* Products */;
ProjectRef = 491AA3791CE8C5C900A2E2C5 /* Graph.xcodeproj */;
},
);
projectRoot = "";
targets = (
493D8DDF1CDD2A1C0089795A /* APSPTests */,
Expand All @@ -193,6 +222,23 @@
};
/* End PBXProject section */

/* Begin PBXReferenceProxy section */
491AA37F1CE8C5C900A2E2C5 /* Graph.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Graph.framework;
remoteRef = 491AA37E1CE8C5C900A2E2C5 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
491AA3811CE8C5C900A2E2C5 /* GraphTests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = GraphTests.xctest;
remoteRef = 491AA3801CE8C5C900A2E2C5 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */

/* Begin PBXResourcesBuildPhase section */
493D8DDE1CDD2A1C0089795A /* Resources */ = {
isa = PBXResourcesBuildPhase;
Expand Down Expand Up @@ -226,13 +272,17 @@
49BFA27A1CDD93F400522D66 /* APSP.swift in Sources */,
493D8DF91CDD5B9B0089795A /* FloydWarshall.swift in Sources */,
493D8DFA1CDD5B9E0089795A /* Helpers.swift in Sources */,
493D8DFB1CDD5BDE0089795A /* AdjacencyMatrix.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
491AA3841CE8C5F900A2E2C5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Graph;
targetProxy = 491AA3831CE8C5F900A2E2C5 /* PBXContainerItemProxy */;
};
49BFA27F1CDE742700522D66 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 493D8DF01CDD5B960089795A /* APSP */;
Expand Down Expand Up @@ -329,7 +379,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = APSPTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSPTests;
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
Expand All @@ -340,7 +390,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = APSPTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSPTests;
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
Expand All @@ -358,7 +408,7 @@
INFOPLIST_FILE = APSP/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSP;
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
Expand All @@ -379,7 +429,7 @@
INFOPLIST_FILE = APSP/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.armcknight.APSP;
PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
Expand Down
1 change: 0 additions & 1 deletion All-Pairs Shortest Paths/APSP/APSP/APSP.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// APSP
//
// Created by Andrew McKnight on 5/6/16.
// Copyright © 2016 Andrew McKnight. All rights reserved.
//

#import <Cocoa/Cocoa.h>
Expand Down
18 changes: 9 additions & 9 deletions All-Pairs Shortest Paths/APSP/APSP/APSP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,31 @@
// APSP
//
// Created by Andrew McKnight on 5/6/16.
// Copyright © 2016 Andrew McKnight. All rights reserved.
//

import Foundation
import Graph

/**
APSPAlgorithm is a protocol for encapsulating an All-Pairs Shortest Paths algorithm. It provides a single function `apply` that accepts a `Graph` and returns an object conforming to `APSPResult`.
`APSPAlgorithm` is a protocol for encapsulating an All-Pairs Shortest Paths algorithm. It provides a single function `apply` that accepts a subclass of `AbstractGraph` and returns an object conforming to `APSPResult`.
*/
protocol APSPAlgorithm {
public protocol APSPAlgorithm {

associatedtype Q
associatedtype Q: Hashable
associatedtype P: APSPResult

static func apply(graph: Graph<Q>) -> P
static func apply(graph: AbstractGraph<Q>) -> P

}

/**
APSPResult is a protocol defining functions `distance` and `path`, allowing for opaque queries into the actual data structures that represent the APSP solution according to the algorithm used.
`APSPResult` is a protocol defining functions `distance` and `path`, allowing for opaque queries into the actual data structures that represent the APSP solution according to the algorithm used.
*/
protocol APSPResult {
public protocol APSPResult {

associatedtype T
associatedtype T: Hashable

func distance(fromVertex from: Vertex<T>, toVertex to: Vertex<T>) -> Double?
func path(fromVertex from: Vertex<T>, toVertex to: Vertex<T>, inGraph graph: Graph<T>) -> [T]?
func path(fromVertex from: Vertex<T>, toVertex to: Vertex<T>, inGraph graph: AbstractGraph<T>) -> [T]?

}
Loading

0 comments on commit 495303b

Please sign in to comment.