From 21a580bcf0752d24834beb229a832f9a44b58288 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Sun, 3 Feb 2019 18:38:24 +0100 Subject: [PATCH 01/19] updated to Swift 4.2 syntax --- .../AdjacencyList.swift | 10 +-- .../ElementaryCyclesSearch.swift | 34 +++++----- .../SCCResult.swift | 4 +- .../StrongConnectedComponents.swift | 66 +++++++++---------- 4 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift b/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift index 7d5a612..248e660 100644 --- a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift +++ b/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift @@ -28,18 +28,18 @@ import Foundation * that are direct successornodes of the node. */ class func getAdjacencyList( adjacencyMatrix: Array>) -> Array> { - var list = [Array](count: adjacencyMatrix.count, repeatedValue: []) + var list = [Array](repeating: [], count: adjacencyMatrix.count) - for var i = 0; i < adjacencyMatrix.count; ++i { + for i in 0..>, graphNodes: Array) { self.graphNodes = graphNodes; - self.adjList = AdjacencyList.getAdjacencyList(matrix); + self.adjList = AdjacencyList.getAdjacencyList(adjacencyMatrix: matrix); } /** @@ -73,25 +73,25 @@ import Foundation */ func getElementaryCycles() -> Array> { self.cycles = Array>() - self.blocked = [Bool](count:self.adjList.count, repeatedValue:false) - self.B = [Array](count: self.adjList.count, repeatedValue: []) + self.blocked = [Bool](repeating:false, count:self.adjList.count) + self.B = [Array](repeating: [], count: self.adjList.count) self.stack = [Int]() let sccs = StrongConnectedComponents(adjList: self.adjList) var s = 0 while(true) { - let sccResult = sccs.getAdjacencyList(s) + let sccResult = sccs.getAdjacencyList(node: s) if let result = sccResult { let scc = result.adjList s = result.lowestNodeId - for var j = 0; j() - for var j = 0; j < self.stack!.count; ++j { + for j in 0.. 0) { let w = Bnode.first! - Bnode.removeAtIndex(0) + Bnode.remove(at:0) if (self.blocked![w]) { - self.unblock(w) + self.unblock(node: w) } } } -} \ No newline at end of file +} diff --git a/Graphs/Johnson's algorithm - Swift/SCCResult.swift b/Graphs/Johnson's algorithm - Swift/SCCResult.swift index 871c6ac..b36abe5 100644 --- a/Graphs/Johnson's algorithm - Swift/SCCResult.swift +++ b/Graphs/Johnson's algorithm - Swift/SCCResult.swift @@ -17,10 +17,10 @@ import Foundation self.adjList = adjList self.lowestNodeId = lowestNodeId nodeIDsOfSCC = [] - for var index = lowestNodeId; index < adjList.count; ++index { + for index in lowestNodeId.. 0) { self.nodeIDsOfSCC.insert(index) } } } -} \ No newline at end of file +} diff --git a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift b/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift index ddeca83..0691249 100644 --- a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift +++ b/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift @@ -78,25 +78,25 @@ import Foundation * connected component; null, if no such component exists */ func getAdjacencyList(node:Int) -> SCCResult? { - self.visited = [Bool](count: self.adjListOriginal.count, repeatedValue: false) - self.lowlink = [Int](count: self.adjListOriginal.count, repeatedValue: 0) - self.number = [Int](count: self.adjListOriginal.count, repeatedValue: 0) + self.visited = [Bool](repeating: false, count: self.adjListOriginal.count) + self.lowlink = [Int](repeating: 0, count: self.adjListOriginal.count) + self.number = [Int](repeating: 0, count: self.adjListOriginal.count) self.stack = Array() self.currentSCCs = Array>() - makeAdjListSubgraph(node) + makeAdjListSubgraph(node: node) - for var i = node; i 0){ return SCCResult(adjList: ad, lowestNodeId: j) } @@ -117,19 +117,19 @@ import Foundation * @param node Node with lowest index in the subgraph */ func makeAdjListSubgraph(node: Int) { - self.adjList = Array>(count:self.adjListOriginal.count, repeatedValue:[]) + self.adjList = Array>(repeating:[], count:self.adjListOriginal.count) - for var i = node; i < self.adjList?.count; ++i { + for i in node..() - for var j = 0; j < self.adjListOriginal[i].count; ++j { + for j in 0..= node { successors.append(self.adjListOriginal[i][j]); } } if (successors.count > 0) { - self.adjList![i] = [Int](count:successors.count, repeatedValue:0) - for var j = 0; j < successors.count; ++j { + self.adjList![i] = [Int](repeating:0, count:successors.count) + for j in 0.. Array? { - var min = self.adjList?.count + var min = self.adjList!.count var currScc : Array?; - for var i = 0; i < self.currentSCCs?.count; ++i { + for i in 0..?) -> Array>?{ var lowestIdAdjacencyList : Array>? if let n = nodes { - lowestIdAdjacencyList = [Array](count: self.adjList!.count, repeatedValue: []) - for var i = 0; i < lowestIdAdjacencyList!.count; ++i { + lowestIdAdjacencyList = [Array](repeating: [], count: self.adjList!.count) + for i in 0.. self.number![root]) // simple scc's with just one node will not be added @@ -225,10 +225,10 @@ import Foundation } class func test() { - var nodes = [String](count: 10, repeatedValue: "") - var adjMatrix = [[Bool]](count: 10, repeatedValue: [Bool](count: 10, repeatedValue: false)); + var nodes = [String](repeating: "", count: 10) + var adjMatrix = [[Bool]](repeating: [Bool](repeating: false, count: 10), count: 10); - for var i = 0; i < 10; ++i { + for i in 0..<10 { nodes[i] = "Node " + String(i); } @@ -245,12 +245,12 @@ import Foundation adjMatrix[8][6] = true; adjMatrix[6][1] = true; - let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes) + let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes as Array) let cycles = ecs.getElementaryCycles() - for var i = 0; i " @@ -261,4 +261,4 @@ import Foundation print(representation + "\n") } } -} \ No newline at end of file +} From 7fcb5c45ec12c4fc5e99d5f9d8dd118b063b8782 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Thu, 7 Feb 2019 05:44:41 +0100 Subject: [PATCH 02/19] Working on SystemsThinking I believe I fixed the issues around wrong Graphviz direction of edges. --- Graphs/Johnson's algorithm - Swift/AdjacencyList.swift | 2 +- Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift b/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift index 248e660..b1752e0 100644 --- a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift +++ b/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift @@ -38,7 +38,7 @@ import Foundation } } - list[i] = [Int](count:v.count, repeatedValue: 0) + list[i] = [Int](repeating: 0, count:v.count) for j in 0.. Date: Sat, 16 Mar 2019 00:44:42 +0100 Subject: [PATCH 03/19] QuickEntry command! Yeah! looking again at decorations, removed QualityAssessment Class node separation / node rank can now go up to 500 Decision Tree Run can now deal with window closing, has a result presentation new file with simple user dialogs. --- Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift b/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift index e50887e..1707c89 100644 --- a/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift +++ b/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift @@ -90,7 +90,7 @@ import Foundation self.B![j] = [Int]() } - findCycles(v: s, s: s, adjList: scc) + let _ = findCycles(v: s, s: s, adjList: scc) s = s + 1 }else { break From 26d6c99c85ecd9699d7fc6e7c39074a0ea6beba5 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Thu, 11 Apr 2019 08:31:04 +0200 Subject: [PATCH 04/19] updated graphviz. --- Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift b/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift index 1707c89..b9cd1ca 100644 --- a/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift +++ b/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift @@ -144,7 +144,7 @@ import Foundation } } - let indexToRemove = self.stack!.index(of: v) + let indexToRemove = self.stack!.firstIndex(of: v) if let index = indexToRemove { self.stack!.remove(at: index) } From 4c8c22948e2e88bd2e20814fffd0fde320dba75f Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Sun, 4 Aug 2019 21:17:58 +0200 Subject: [PATCH 05/19] New NodeViewPart implementation is working indeed. Started looking into MultiTextNode smaller fixes where asserts are too restrictive. --- Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift b/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift index b9cd1ca..fb7cdb2 100644 --- a/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift +++ b/Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift @@ -146,7 +146,7 @@ import Foundation let indexToRemove = self.stack!.firstIndex(of: v) if let index = indexToRemove { - self.stack!.remove(at: index) + self.stack?.remove(at: index) } return f } From 05c1e31d8761112c058f3c960b00744b9f042904 Mon Sep 17 00:00:00 2001 From: TheMadOne <72d8610d@opayq.com> Date: Mon, 18 Nov 2019 21:44:50 +0100 Subject: [PATCH 06/19] removed some forced unwraps. --- .../StrongConnectedComponents.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift b/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift index 0691249..ea6b942 100644 --- a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift +++ b/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift @@ -251,11 +251,12 @@ import Foundation let cycle = cycles[i] var representation = "" for j in 0.. " - }else { - representation += node as! String + if let node = cycle[j] as? String { + if j < cycle.count - 1 { + representation += node + " -> " + }else { + representation += node + } } } print(representation + "\n") From 0837c23b3bdf0acab8c571caf13eb0b6c3362126 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Tue, 11 Feb 2020 06:46:20 +0100 Subject: [PATCH 07/19] migrating towards swift package manager For that I needed to move all files. --- .gitignore | 5 + Package.swift | 28 ++ README.md | 12 + Sources/JohnsonsAlgo/AdjacencyList.swift | 50 ++++ .../JohnsonsAlgo/ElementaryCyclesSearch.swift | 170 +++++++++++ Sources/JohnsonsAlgo/SCCResult.swift | 26 ++ .../StrongConnectedComponents.swift | 264 ++++++++++++++++++ .../JohnsonsAlgoTests/JohnsonsAlgoTests.swift | 15 + Tests/JohnsonsAlgoTests/XCTestManifests.swift | 9 + Tests/LinuxMain.swift | 7 + 10 files changed, 586 insertions(+) create mode 100644 .gitignore create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/JohnsonsAlgo/AdjacencyList.swift create mode 100644 Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift create mode 100644 Sources/JohnsonsAlgo/SCCResult.swift create mode 100644 Sources/JohnsonsAlgo/StrongConnectedComponents.swift create mode 100644 Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift create mode 100644 Tests/JohnsonsAlgoTests/XCTestManifests.swift create mode 100644 Tests/LinuxMain.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95c4320 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..ec04e3b --- /dev/null +++ b/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version:5.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "JohnsonsAlgo", + products: [ + // Products define the executables and libraries produced by a package, and make them visible to other packages. + .library( + name: "JohnsonsAlgo", + targets: ["JohnsonsAlgo"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "JohnsonsAlgo", + dependencies: []), + .testTarget( + name: "JohnsonsAlgoTests", + dependencies: ["JohnsonsAlgo"]), + ] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..9568600 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# JohnsonsAlgo + +Swift library that implements the Jonhson Cycle algorithm to find circuits in a directed graph +Wikipedia: "https://en.wikipedia.org/wiki/Johnson's_algorithm" + +Original Author : Frank Meyer (Java implementation) +Swift Adaption: Marc Matta +Swift Package Manager Adaption: Klaus Kneupner + +known issues: sometimes the algo will end in a recursive loop, depending on the sequence of nodes provided. Details yet unknown. + + diff --git a/Sources/JohnsonsAlgo/AdjacencyList.swift b/Sources/JohnsonsAlgo/AdjacencyList.swift new file mode 100644 index 0000000..b1752e0 --- /dev/null +++ b/Sources/JohnsonsAlgo/AdjacencyList.swift @@ -0,0 +1,50 @@ +// +// AdjacencyList.swift +// AFN-Magical-Record-Example +// +// Created by marc matta on 12/3/15. +// Copyright © 2015 Cocoa Star Apps. All rights reserved. +// + +import Foundation + +/** + * Calculates the adjacency-list for a given adjacency-matrix. + * + * + * @author Frank Meyer, web@normalisiert.de + * @version 1.0, 26.08.2006 + * + */ +@objc public class AdjacencyList : NSObject { + /** + * Calculates a adjacency-list for a given array of an adjacency-matrix. + * + * @param adjacencyMatrix array with the adjacency-matrix that represents + * the graph + * @return int[][]-array of the adjacency-list of given nodes. The first + * dimension in the array represents the same node as in the given + * adjacency, the second dimension represents the indicies of those nodes, + * that are direct successornodes of the node. + */ + class func getAdjacencyList( adjacencyMatrix: Array>) -> Array> { + var list = [Array](repeating: [], count: adjacencyMatrix.count) + + for i in 0..
+* +* The implementation uses the algorithm of Donald B. Johnson for the search of +* the elementary cycles. For a description of the algorithm see:
+* Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph. +* SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.

+* +* The algorithm of Johnson is based on the search for strong connected +* components in a graph. For a description of this part see:
+* Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM +* Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.
+* +* @author Frank Meyer, web_at_normalisiert_dot_de +* @version 1.2, 22.03.2009 +* +*/ + +@objc public class ElementaryCyclesSearch : NSObject { + /** List of cycles */ + private var cycles : Array>? + + /** Adjacency-list of graph */ + private var adjList : Array> + + /** Graphnodes */ + private var graphNodes : Array + + /** Blocked nodes, used by the algorithm of Johnson */ + private var blocked : Array? + + /** B-Lists, used by the algorithm of Johnson */ + private var B : Array>? + + /** Stack for nodes, used by the algorithm of Johnson */ + private var stack : Array? + + /** + * Constructor. + * + * @param matrix adjacency-matrix of the graph + * @param graphNodes array of the graphnodes of the graph; this is used to + * build sets of the elementary cycles containing the objects of the original + * graph-representation + */ + init(matrix: Array>, graphNodes: Array) { + self.graphNodes = graphNodes; + self.adjList = AdjacencyList.getAdjacencyList(adjacencyMatrix: matrix); + } + + /** + * Returns List::List::Object with the Lists of nodes of all elementary + * cycles in the graph. + * + * @return List::List::Object with the Lists of the elementary cycles. + */ + func getElementaryCycles() -> Array> { + self.cycles = Array>() + self.blocked = [Bool](repeating:false, count:self.adjList.count) + self.B = [Array](repeating: [], count: self.adjList.count) + self.stack = [Int]() + + let sccs = StrongConnectedComponents(adjList: self.adjList) + var s = 0 + + while(true) { + let sccResult = sccs.getAdjacencyList(node: s) + if let result = sccResult { + let scc = result.adjList + s = result.lowestNodeId + for j in 0..> ) -> Bool { + var f = false; + self.stack?.append(v) + self.blocked![v] = true; + + for i in 0..() + for j in 0.. 0) { + let w = Bnode.first! + Bnode.remove(at:0) + if (self.blocked![w]) { + self.unblock(node: w) + } + } + } +} diff --git a/Sources/JohnsonsAlgo/SCCResult.swift b/Sources/JohnsonsAlgo/SCCResult.swift new file mode 100644 index 0000000..b36abe5 --- /dev/null +++ b/Sources/JohnsonsAlgo/SCCResult.swift @@ -0,0 +1,26 @@ +// +// SCCResi;.swift +// AFN-Magical-Record-Example +// +// Created by marc matta on 12/3/15. +// Copyright © 2015 Cocoa Star Apps. All rights reserved. +// + +import Foundation + +@objc public class SCCResult : NSObject{ + var nodeIDsOfSCC : Set + var adjList : Array> + var lowestNodeId : Int + + init(adjList: Array>, lowestNodeId: Int) { + self.adjList = adjList + self.lowestNodeId = lowestNodeId + nodeIDsOfSCC = [] + for index in lowestNodeId.. 0) { + self.nodeIDsOfSCC.insert(index) + } + } + } +} diff --git a/Sources/JohnsonsAlgo/StrongConnectedComponents.swift b/Sources/JohnsonsAlgo/StrongConnectedComponents.swift new file mode 100644 index 0000000..0691249 --- /dev/null +++ b/Sources/JohnsonsAlgo/StrongConnectedComponents.swift @@ -0,0 +1,264 @@ +// +// StrongConnectedComponents.swift +// AFN-Magical-Record-Example +// +// Created by marc matta on 12/3/15. +// Copyright © 2015 Cocoa Star Apps. All rights reserved. +// + +import Foundation +/** + * This is a helpclass for the search of all elementary cycles in a graph + * with the algorithm of Johnson. For this it searches for strong connected + * components, using the algorithm of Tarjan. The constructor gets an + * adjacency-list of a graph. Based on this graph, it gets a nodenumber s, + * for which it calculates the subgraph, containing all nodes + * {s, s + 1, ..., n}, where n is the highest nodenumber in the original + * graph (e.g. it builds a subgraph with all nodes with higher or same + * nodenumbers like the given node s). It returns the strong connected + * component of this subgraph which contains the lowest nodenumber of all + * nodes in the subgraph.

+ * + * For a description of the algorithm for calculating the strong connected + * components see:
+ * Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM + * Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.
+ * For a description of the algorithm for searching all elementary cycles in + * a directed graph see:
+ * Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph. + * SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.

+ * + * @author Frank Meyer, web_at_normalisiert_dot_de + * @version 1.1, 22.03.2009 + * + */ +@objc public class StrongConnectedComponents :NSObject { + /** Adjacency-list of original graph */ + private var adjListOriginal : Array> + + /** Adjacency-list of currently viewed subgraph */ + private var adjList : Array>? + + /** Helpattribute for finding scc's */ + private var visited : Array? + + /** Helpattribute for finding scc's */ + private var stack : Array? + + /** Helpattribute for finding scc's */ + private var lowlink : Array? + + /** Helpattribute for finding scc's */ + private var number : Array? + + /** Helpattribute for finding scc's */ + private var sccCounter : Int = 0 + + /** Helpattribute for finding scc's */ + private var currentSCCs : Array>? + + /** + * Constructor. + * + * @param adjList adjacency-list of the graph + */ + init(adjList:Array>){ + self.adjListOriginal = adjList + } + + /** + * This method returns the adjacency-structure of the strong connected + * component with the least vertex in a subgraph of the original graph + * induced by the nodes {s, s + 1, ..., n}, where s is a given node. Note + * that trivial strong connected components with just one node will not + * be returned. + * + * @param node node s + * @return SCCResult with adjacency-structure of the strong + * connected component; null, if no such component exists + */ + func getAdjacencyList(node:Int) -> SCCResult? { + self.visited = [Bool](repeating: false, count: self.adjListOriginal.count) + self.lowlink = [Int](repeating: 0, count: self.adjListOriginal.count) + self.number = [Int](repeating: 0, count: self.adjListOriginal.count) + self.stack = Array() + self.currentSCCs = Array>() + + makeAdjListSubgraph(node: node) + + for i in node.. 0){ + return SCCResult(adjList: ad, lowestNodeId: j) + } + + } + } + } + } + } + + return nil + } + + /** + * Builds the adjacency-list for a subgraph containing just nodes + * >= a given index. + * + * @param node Node with lowest index in the subgraph + */ + func makeAdjListSubgraph(node: Int) { + self.adjList = Array>(repeating:[], count:self.adjListOriginal.count) + + for i in node..() + for j in 0..= node { + successors.append(self.adjListOriginal[i][j]); + } + } + + if (successors.count > 0) { + self.adjList![i] = [Int](repeating:0, count:successors.count) + for j in 0.. Array? { + var min = self.adjList!.count + var currScc : Array?; + for i in 0..?) -> Array>?{ + var lowestIdAdjacencyList : Array>? + if let n = nodes { + lowestIdAdjacencyList = [Array](repeating: [], count: self.adjList!.count) + for i in 0.. 0)) { + var next = -1; + var scc = [Int]() + repeat { + next = self.stack!.last! + self.stack!.remove(at:stack!.count - 1) + scc.append(next) + } while (self.number![next] > self.number![root]) + // simple scc's with just one node will not be added + if (scc.count > 1) { + self.currentSCCs!.append(scc) + } + } + } + + class func test() { + var nodes = [String](repeating: "", count: 10) + var adjMatrix = [[Bool]](repeating: [Bool](repeating: false, count: 10), count: 10); + + for i in 0..<10 { + nodes[i] = "Node " + String(i); + } + + adjMatrix[0][1] = true; + adjMatrix[1][2] = true; + adjMatrix[2][0] = true; + adjMatrix[2][6] = true; + adjMatrix[3][4] = true; + adjMatrix[4][5] = true; + adjMatrix[4][6] = true; + adjMatrix[5][3] = true; + adjMatrix[6][7] = true; + adjMatrix[7][8] = true; + adjMatrix[8][6] = true; + adjMatrix[6][1] = true; + + let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes as Array) + let cycles = ecs.getElementaryCycles() + for i in 0.. " + }else { + representation += node as! String + } + } + print(representation + "\n") + } + } +} diff --git a/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift b/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift new file mode 100644 index 0000000..3f84b0e --- /dev/null +++ b/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift @@ -0,0 +1,15 @@ +import XCTest +@testable import JohnsonsAlgo + +final class JohnsonsAlgoTests: XCTestCase { + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(JohnsonsAlgo().text, "Hello, World!") + } + + static var allTests = [ + ("testExample", testExample), + ] +} diff --git a/Tests/JohnsonsAlgoTests/XCTestManifests.swift b/Tests/JohnsonsAlgoTests/XCTestManifests.swift new file mode 100644 index 0000000..a3932d4 --- /dev/null +++ b/Tests/JohnsonsAlgoTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !canImport(ObjectiveC) +public func allTests() -> [XCTestCaseEntry] { + return [ + testCase(JohnsonsAlgoTests.allTests), + ] +} +#endif diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..c9c922d --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import JohnsonsAlgoTests + +var tests = [XCTestCaseEntry]() +tests += JohnsonsAlgoTests.allTests() +XCTMain(tests) From 87840023c8ebc8d5fdc732a50ed166fdb8bc3ec5 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Tue, 11 Feb 2020 06:48:03 +0100 Subject: [PATCH 08/19] Still migrating towards swift package manager deleted old files --- .../AdjacencyList.swift | 50 ---- .../ElementaryCyclesSearch.swift | 170 ----------- .../SCCResult.swift | 26 -- .../StrongConnectedComponents.swift | 264 ------------------ Graphs/Johnson's algorithm - Swift/readme.rtf | 6 - 5 files changed, 516 deletions(-) delete mode 100644 Graphs/Johnson's algorithm - Swift/AdjacencyList.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/SCCResult.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/readme.rtf diff --git a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift b/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift deleted file mode 100644 index b1752e0..0000000 --- a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// AdjacencyList.swift -// AFN-Magical-Record-Example -// -// Created by marc matta on 12/3/15. -// Copyright © 2015 Cocoa Star Apps. All rights reserved. -// - -import Foundation - -/** - * Calculates the adjacency-list for a given adjacency-matrix. - * - * - * @author Frank Meyer, web@normalisiert.de - * @version 1.0, 26.08.2006 - * - */ -@objc public class AdjacencyList : NSObject { - /** - * Calculates a adjacency-list for a given array of an adjacency-matrix. - * - * @param adjacencyMatrix array with the adjacency-matrix that represents - * the graph - * @return int[][]-array of the adjacency-list of given nodes. The first - * dimension in the array represents the same node as in the given - * adjacency, the second dimension represents the indicies of those nodes, - * that are direct successornodes of the node. - */ - class func getAdjacencyList( adjacencyMatrix: Array>) -> Array> { - var list = [Array](repeating: [], count: adjacencyMatrix.count) - - for i in 0..
-* -* The implementation uses the algorithm of Donald B. Johnson for the search of -* the elementary cycles. For a description of the algorithm see:
-* Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph. -* SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.

-* -* The algorithm of Johnson is based on the search for strong connected -* components in a graph. For a description of this part see:
-* Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM -* Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.
-* -* @author Frank Meyer, web_at_normalisiert_dot_de -* @version 1.2, 22.03.2009 -* -*/ - -@objc public class ElementaryCyclesSearch : NSObject { - /** List of cycles */ - private var cycles : Array>? - - /** Adjacency-list of graph */ - private var adjList : Array> - - /** Graphnodes */ - private var graphNodes : Array - - /** Blocked nodes, used by the algorithm of Johnson */ - private var blocked : Array? - - /** B-Lists, used by the algorithm of Johnson */ - private var B : Array>? - - /** Stack for nodes, used by the algorithm of Johnson */ - private var stack : Array? - - /** - * Constructor. - * - * @param matrix adjacency-matrix of the graph - * @param graphNodes array of the graphnodes of the graph; this is used to - * build sets of the elementary cycles containing the objects of the original - * graph-representation - */ - init(matrix: Array>, graphNodes: Array) { - self.graphNodes = graphNodes; - self.adjList = AdjacencyList.getAdjacencyList(adjacencyMatrix: matrix); - } - - /** - * Returns List::List::Object with the Lists of nodes of all elementary - * cycles in the graph. - * - * @return List::List::Object with the Lists of the elementary cycles. - */ - func getElementaryCycles() -> Array> { - self.cycles = Array>() - self.blocked = [Bool](repeating:false, count:self.adjList.count) - self.B = [Array](repeating: [], count: self.adjList.count) - self.stack = [Int]() - - let sccs = StrongConnectedComponents(adjList: self.adjList) - var s = 0 - - while(true) { - let sccResult = sccs.getAdjacencyList(node: s) - if let result = sccResult { - let scc = result.adjList - s = result.lowestNodeId - for j in 0..> ) -> Bool { - var f = false; - self.stack?.append(v) - self.blocked![v] = true; - - for i in 0..() - for j in 0.. 0) { - let w = Bnode.first! - Bnode.remove(at:0) - if (self.blocked![w]) { - self.unblock(node: w) - } - } - } -} diff --git a/Graphs/Johnson's algorithm - Swift/SCCResult.swift b/Graphs/Johnson's algorithm - Swift/SCCResult.swift deleted file mode 100644 index b36abe5..0000000 --- a/Graphs/Johnson's algorithm - Swift/SCCResult.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// SCCResi;.swift -// AFN-Magical-Record-Example -// -// Created by marc matta on 12/3/15. -// Copyright © 2015 Cocoa Star Apps. All rights reserved. -// - -import Foundation - -@objc public class SCCResult : NSObject{ - var nodeIDsOfSCC : Set - var adjList : Array> - var lowestNodeId : Int - - init(adjList: Array>, lowestNodeId: Int) { - self.adjList = adjList - self.lowestNodeId = lowestNodeId - nodeIDsOfSCC = [] - for index in lowestNodeId.. 0) { - self.nodeIDsOfSCC.insert(index) - } - } - } -} diff --git a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift b/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift deleted file mode 100644 index 0691249..0000000 --- a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift +++ /dev/null @@ -1,264 +0,0 @@ -// -// StrongConnectedComponents.swift -// AFN-Magical-Record-Example -// -// Created by marc matta on 12/3/15. -// Copyright © 2015 Cocoa Star Apps. All rights reserved. -// - -import Foundation -/** - * This is a helpclass for the search of all elementary cycles in a graph - * with the algorithm of Johnson. For this it searches for strong connected - * components, using the algorithm of Tarjan. The constructor gets an - * adjacency-list of a graph. Based on this graph, it gets a nodenumber s, - * for which it calculates the subgraph, containing all nodes - * {s, s + 1, ..., n}, where n is the highest nodenumber in the original - * graph (e.g. it builds a subgraph with all nodes with higher or same - * nodenumbers like the given node s). It returns the strong connected - * component of this subgraph which contains the lowest nodenumber of all - * nodes in the subgraph.

- * - * For a description of the algorithm for calculating the strong connected - * components see:
- * Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM - * Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.
- * For a description of the algorithm for searching all elementary cycles in - * a directed graph see:
- * Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph. - * SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.

- * - * @author Frank Meyer, web_at_normalisiert_dot_de - * @version 1.1, 22.03.2009 - * - */ -@objc public class StrongConnectedComponents :NSObject { - /** Adjacency-list of original graph */ - private var adjListOriginal : Array> - - /** Adjacency-list of currently viewed subgraph */ - private var adjList : Array>? - - /** Helpattribute for finding scc's */ - private var visited : Array? - - /** Helpattribute for finding scc's */ - private var stack : Array? - - /** Helpattribute for finding scc's */ - private var lowlink : Array? - - /** Helpattribute for finding scc's */ - private var number : Array? - - /** Helpattribute for finding scc's */ - private var sccCounter : Int = 0 - - /** Helpattribute for finding scc's */ - private var currentSCCs : Array>? - - /** - * Constructor. - * - * @param adjList adjacency-list of the graph - */ - init(adjList:Array>){ - self.adjListOriginal = adjList - } - - /** - * This method returns the adjacency-structure of the strong connected - * component with the least vertex in a subgraph of the original graph - * induced by the nodes {s, s + 1, ..., n}, where s is a given node. Note - * that trivial strong connected components with just one node will not - * be returned. - * - * @param node node s - * @return SCCResult with adjacency-structure of the strong - * connected component; null, if no such component exists - */ - func getAdjacencyList(node:Int) -> SCCResult? { - self.visited = [Bool](repeating: false, count: self.adjListOriginal.count) - self.lowlink = [Int](repeating: 0, count: self.adjListOriginal.count) - self.number = [Int](repeating: 0, count: self.adjListOriginal.count) - self.stack = Array() - self.currentSCCs = Array>() - - makeAdjListSubgraph(node: node) - - for i in node.. 0){ - return SCCResult(adjList: ad, lowestNodeId: j) - } - - } - } - } - } - } - - return nil - } - - /** - * Builds the adjacency-list for a subgraph containing just nodes - * >= a given index. - * - * @param node Node with lowest index in the subgraph - */ - func makeAdjListSubgraph(node: Int) { - self.adjList = Array>(repeating:[], count:self.adjListOriginal.count) - - for i in node..() - for j in 0..= node { - successors.append(self.adjListOriginal[i][j]); - } - } - - if (successors.count > 0) { - self.adjList![i] = [Int](repeating:0, count:successors.count) - for j in 0.. Array? { - var min = self.adjList!.count - var currScc : Array?; - for i in 0..?) -> Array>?{ - var lowestIdAdjacencyList : Array>? - if let n = nodes { - lowestIdAdjacencyList = [Array](repeating: [], count: self.adjList!.count) - for i in 0.. 0)) { - var next = -1; - var scc = [Int]() - repeat { - next = self.stack!.last! - self.stack!.remove(at:stack!.count - 1) - scc.append(next) - } while (self.number![next] > self.number![root]) - // simple scc's with just one node will not be added - if (scc.count > 1) { - self.currentSCCs!.append(scc) - } - } - } - - class func test() { - var nodes = [String](repeating: "", count: 10) - var adjMatrix = [[Bool]](repeating: [Bool](repeating: false, count: 10), count: 10); - - for i in 0..<10 { - nodes[i] = "Node " + String(i); - } - - adjMatrix[0][1] = true; - adjMatrix[1][2] = true; - adjMatrix[2][0] = true; - adjMatrix[2][6] = true; - adjMatrix[3][4] = true; - adjMatrix[4][5] = true; - adjMatrix[4][6] = true; - adjMatrix[5][3] = true; - adjMatrix[6][7] = true; - adjMatrix[7][8] = true; - adjMatrix[8][6] = true; - adjMatrix[6][1] = true; - - let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes as Array) - let cycles = ecs.getElementaryCycles() - for i in 0.. " - }else { - representation += node as! String - } - } - print(representation + "\n") - } - } -} diff --git a/Graphs/Johnson's algorithm - Swift/readme.rtf b/Graphs/Johnson's algorithm - Swift/readme.rtf deleted file mode 100644 index 80a8ebf..0000000 --- a/Graphs/Johnson's algorithm - Swift/readme.rtf +++ /dev/null @@ -1,6 +0,0 @@ - -Swift library that implements the Jonhson Cycle algorithm to find circuits in a directed graph - -Original Author : Frank Meyer (Java implementation) - -Wikipedia: "https://en.wikipedia.org/wiki/Johnson's_algorithm" From 5594aa9871d1eacc85fa79def9e25bfd909f1243 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Tue, 11 Feb 2020 06:55:48 +0100 Subject: [PATCH 09/19] made ElementaryCyclesSearch OPEN --- Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift index fb7cdb2..0907cf8 100644 --- a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift +++ b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift @@ -33,7 +33,7 @@ import Foundation * */ -@objc public class ElementaryCyclesSearch : NSObject { +@objc open class ElementaryCyclesSearch : NSObject { /** List of cycles */ private var cycles : Array>? From 054479f69a3fcb053173d9dd9ad23bd42201b892 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Tue, 11 Feb 2020 07:07:17 +0100 Subject: [PATCH 10/19] init and getElementCycles now declared OPEN --- Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift index 0907cf8..dcb6004 100644 --- a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift +++ b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift @@ -60,7 +60,7 @@ import Foundation * build sets of the elementary cycles containing the objects of the original * graph-representation */ - init(matrix: Array>, graphNodes: Array) { + open init(matrix: Array>, graphNodes: Array) { self.graphNodes = graphNodes; self.adjList = AdjacencyList.getAdjacencyList(adjacencyMatrix: matrix); } @@ -71,7 +71,7 @@ import Foundation * * @return List::List::Object with the Lists of the elementary cycles. */ - func getElementaryCycles() -> Array> { + open func getElementaryCycles() -> Array> { self.cycles = Array>() self.blocked = [Bool](repeating:false, count:self.adjList.count) self.B = [Array](repeating: [], count: self.adjList.count) From 95ae4095c252f679de791fcddec414899d2ac088 Mon Sep 17 00:00:00 2001 From: klauskneupner Date: Tue, 11 Feb 2020 07:09:01 +0100 Subject: [PATCH 11/19] init now PUBLIC --- Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift index dcb6004..5053a8d 100644 --- a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift +++ b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift @@ -60,7 +60,7 @@ import Foundation * build sets of the elementary cycles containing the objects of the original * graph-representation */ - open init(matrix: Array>, graphNodes: Array) { + public init(matrix: Array>, graphNodes: Array) { self.graphNodes = graphNodes; self.adjList = AdjacencyList.getAdjacencyList(adjacencyMatrix: matrix); } From 82985316fdab29c24fecdaceb9e9ef748e6ebec4 Mon Sep 17 00:00:00 2001 From: TheMadOne <72d8610d@opayq.com> Date: Thu, 9 Apr 2020 07:27:19 +0200 Subject: [PATCH 12/19] deleted old files --- .../AdjacencyList.swift | 50 ---- .../ElementaryCyclesSearch.swift | 170 ----------- .../SCCResult.swift | 26 -- .../StrongConnectedComponents.swift | 265 ------------------ 4 files changed, 511 deletions(-) delete mode 100644 Graphs/Johnson's algorithm - Swift/AdjacencyList.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/ElementaryCyclesSearch.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/SCCResult.swift delete mode 100644 Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift diff --git a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift b/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift deleted file mode 100644 index b1752e0..0000000 --- a/Graphs/Johnson's algorithm - Swift/AdjacencyList.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// AdjacencyList.swift -// AFN-Magical-Record-Example -// -// Created by marc matta on 12/3/15. -// Copyright © 2015 Cocoa Star Apps. All rights reserved. -// - -import Foundation - -/** - * Calculates the adjacency-list for a given adjacency-matrix. - * - * - * @author Frank Meyer, web@normalisiert.de - * @version 1.0, 26.08.2006 - * - */ -@objc public class AdjacencyList : NSObject { - /** - * Calculates a adjacency-list for a given array of an adjacency-matrix. - * - * @param adjacencyMatrix array with the adjacency-matrix that represents - * the graph - * @return int[][]-array of the adjacency-list of given nodes. The first - * dimension in the array represents the same node as in the given - * adjacency, the second dimension represents the indicies of those nodes, - * that are direct successornodes of the node. - */ - class func getAdjacencyList( adjacencyMatrix: Array>) -> Array> { - var list = [Array](repeating: [], count: adjacencyMatrix.count) - - for i in 0..
-* -* The implementation uses the algorithm of Donald B. Johnson for the search of -* the elementary cycles. For a description of the algorithm see:
-* Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph. -* SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.

-* -* The algorithm of Johnson is based on the search for strong connected -* components in a graph. For a description of this part see:
-* Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM -* Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.
-* -* @author Frank Meyer, web_at_normalisiert_dot_de -* @version 1.2, 22.03.2009 -* -*/ - -@objc public class ElementaryCyclesSearch : NSObject { - /** List of cycles */ - private var cycles : Array>? - - /** Adjacency-list of graph */ - private var adjList : Array> - - /** Graphnodes */ - private var graphNodes : Array - - /** Blocked nodes, used by the algorithm of Johnson */ - private var blocked : Array? - - /** B-Lists, used by the algorithm of Johnson */ - private var B : Array>? - - /** Stack for nodes, used by the algorithm of Johnson */ - private var stack : Array? - - /** - * Constructor. - * - * @param matrix adjacency-matrix of the graph - * @param graphNodes array of the graphnodes of the graph; this is used to - * build sets of the elementary cycles containing the objects of the original - * graph-representation - */ - init(matrix: Array>, graphNodes: Array) { - self.graphNodes = graphNodes; - self.adjList = AdjacencyList.getAdjacencyList(adjacencyMatrix: matrix); - } - - /** - * Returns List::List::Object with the Lists of nodes of all elementary - * cycles in the graph. - * - * @return List::List::Object with the Lists of the elementary cycles. - */ - func getElementaryCycles() -> Array> { - self.cycles = Array>() - self.blocked = [Bool](repeating:false, count:self.adjList.count) - self.B = [Array](repeating: [], count: self.adjList.count) - self.stack = [Int]() - - let sccs = StrongConnectedComponents(adjList: self.adjList) - var s = 0 - - while(true) { - let sccResult = sccs.getAdjacencyList(node: s) - if let result = sccResult { - let scc = result.adjList - s = result.lowestNodeId - for j in 0..> ) -> Bool { - var f = false; - self.stack?.append(v) - self.blocked![v] = true; - - for i in 0..() - for j in 0.. 0) { - let w = Bnode.first! - Bnode.remove(at:0) - if (self.blocked![w]) { - self.unblock(node: w) - } - } - } -} diff --git a/Graphs/Johnson's algorithm - Swift/SCCResult.swift b/Graphs/Johnson's algorithm - Swift/SCCResult.swift deleted file mode 100644 index b36abe5..0000000 --- a/Graphs/Johnson's algorithm - Swift/SCCResult.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// SCCResi;.swift -// AFN-Magical-Record-Example -// -// Created by marc matta on 12/3/15. -// Copyright © 2015 Cocoa Star Apps. All rights reserved. -// - -import Foundation - -@objc public class SCCResult : NSObject{ - var nodeIDsOfSCC : Set - var adjList : Array> - var lowestNodeId : Int - - init(adjList: Array>, lowestNodeId: Int) { - self.adjList = adjList - self.lowestNodeId = lowestNodeId - nodeIDsOfSCC = [] - for index in lowestNodeId.. 0) { - self.nodeIDsOfSCC.insert(index) - } - } - } -} diff --git a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift b/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift deleted file mode 100644 index ea6b942..0000000 --- a/Graphs/Johnson's algorithm - Swift/StrongConnectedComponents.swift +++ /dev/null @@ -1,265 +0,0 @@ -// -// StrongConnectedComponents.swift -// AFN-Magical-Record-Example -// -// Created by marc matta on 12/3/15. -// Copyright © 2015 Cocoa Star Apps. All rights reserved. -// - -import Foundation -/** - * This is a helpclass for the search of all elementary cycles in a graph - * with the algorithm of Johnson. For this it searches for strong connected - * components, using the algorithm of Tarjan. The constructor gets an - * adjacency-list of a graph. Based on this graph, it gets a nodenumber s, - * for which it calculates the subgraph, containing all nodes - * {s, s + 1, ..., n}, where n is the highest nodenumber in the original - * graph (e.g. it builds a subgraph with all nodes with higher or same - * nodenumbers like the given node s). It returns the strong connected - * component of this subgraph which contains the lowest nodenumber of all - * nodes in the subgraph.

- * - * For a description of the algorithm for calculating the strong connected - * components see:
- * Robert Tarjan: Depth-first search and linear graph algorithms. In: SIAM - * Journal on Computing. Volume 1, Nr. 2 (1972), pp. 146-160.
- * For a description of the algorithm for searching all elementary cycles in - * a directed graph see:
- * Donald B. Johnson: Finding All the Elementary Circuits of a Directed Graph. - * SIAM Journal on Computing. Volumne 4, Nr. 1 (1975), pp. 77-84.

- * - * @author Frank Meyer, web_at_normalisiert_dot_de - * @version 1.1, 22.03.2009 - * - */ -@objc public class StrongConnectedComponents :NSObject { - /** Adjacency-list of original graph */ - private var adjListOriginal : Array> - - /** Adjacency-list of currently viewed subgraph */ - private var adjList : Array>? - - /** Helpattribute for finding scc's */ - private var visited : Array? - - /** Helpattribute for finding scc's */ - private var stack : Array? - - /** Helpattribute for finding scc's */ - private var lowlink : Array? - - /** Helpattribute for finding scc's */ - private var number : Array? - - /** Helpattribute for finding scc's */ - private var sccCounter : Int = 0 - - /** Helpattribute for finding scc's */ - private var currentSCCs : Array>? - - /** - * Constructor. - * - * @param adjList adjacency-list of the graph - */ - init(adjList:Array>){ - self.adjListOriginal = adjList - } - - /** - * This method returns the adjacency-structure of the strong connected - * component with the least vertex in a subgraph of the original graph - * induced by the nodes {s, s + 1, ..., n}, where s is a given node. Note - * that trivial strong connected components with just one node will not - * be returned. - * - * @param node node s - * @return SCCResult with adjacency-structure of the strong - * connected component; null, if no such component exists - */ - func getAdjacencyList(node:Int) -> SCCResult? { - self.visited = [Bool](repeating: false, count: self.adjListOriginal.count) - self.lowlink = [Int](repeating: 0, count: self.adjListOriginal.count) - self.number = [Int](repeating: 0, count: self.adjListOriginal.count) - self.stack = Array() - self.currentSCCs = Array>() - - makeAdjListSubgraph(node: node) - - for i in node.. 0){ - return SCCResult(adjList: ad, lowestNodeId: j) - } - - } - } - } - } - } - - return nil - } - - /** - * Builds the adjacency-list for a subgraph containing just nodes - * >= a given index. - * - * @param node Node with lowest index in the subgraph - */ - func makeAdjListSubgraph(node: Int) { - self.adjList = Array>(repeating:[], count:self.adjListOriginal.count) - - for i in node..() - for j in 0..= node { - successors.append(self.adjListOriginal[i][j]); - } - } - - if (successors.count > 0) { - self.adjList![i] = [Int](repeating:0, count:successors.count) - for j in 0.. Array? { - var min = self.adjList!.count - var currScc : Array?; - for i in 0..?) -> Array>?{ - var lowestIdAdjacencyList : Array>? - if let n = nodes { - lowestIdAdjacencyList = [Array](repeating: [], count: self.adjList!.count) - for i in 0.. 0)) { - var next = -1; - var scc = [Int]() - repeat { - next = self.stack!.last! - self.stack!.remove(at:stack!.count - 1) - scc.append(next) - } while (self.number![next] > self.number![root]) - // simple scc's with just one node will not be added - if (scc.count > 1) { - self.currentSCCs!.append(scc) - } - } - } - - class func test() { - var nodes = [String](repeating: "", count: 10) - var adjMatrix = [[Bool]](repeating: [Bool](repeating: false, count: 10), count: 10); - - for i in 0..<10 { - nodes[i] = "Node " + String(i); - } - - adjMatrix[0][1] = true; - adjMatrix[1][2] = true; - adjMatrix[2][0] = true; - adjMatrix[2][6] = true; - adjMatrix[3][4] = true; - adjMatrix[4][5] = true; - adjMatrix[4][6] = true; - adjMatrix[5][3] = true; - adjMatrix[6][7] = true; - adjMatrix[7][8] = true; - adjMatrix[8][6] = true; - adjMatrix[6][1] = true; - - let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes as Array) - let cycles = ecs.getElementaryCycles() - for i in 0.. " - }else { - representation += node - } - } - } - print(representation + "\n") - } - } -} From 081168d3b4007c393f5165593673d02f5098b868 Mon Sep 17 00:00:00 2001 From: Vithanco Date: Sun, 28 Jun 2020 20:38:22 +0200 Subject: [PATCH 13/19] Update README.md proper line breaks --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9568600..73aa984 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ Swift library that implements the Jonhson Cycle algorithm to find circuits in a directed graph Wikipedia: "https://en.wikipedia.org/wiki/Johnson's_algorithm" -Original Author : Frank Meyer (Java implementation) -Swift Adaption: Marc Matta -Swift Package Manager Adaption: Klaus Kneupner +Original Author: Frank Meyer (Java implementation) +Swift Adaption: Marc Matta +Swift Package Manager Adaption: Klaus Kneupner -known issues: sometimes the algo will end in a recursive loop, depending on the sequence of nodes provided. Details yet unknown. +Known issues: sometimes the algo will end in a recursive loop, depending on the sequence of nodes provided. Details yet unknown. From 91a67d2dc80e7ab455dc6f5a2a3bcbf734fffeec Mon Sep 17 00:00:00 2001 From: TheMadOne <72d8610d@opayq.com> Date: Sun, 28 Jun 2020 20:46:53 +0200 Subject: [PATCH 14/19] removed @objc declarations --- Sources/JohnsonsAlgo/AdjacencyList.swift | 2 +- Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift | 2 +- Sources/JohnsonsAlgo/SCCResult.swift | 2 +- Sources/JohnsonsAlgo/StrongConnectedComponents.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/JohnsonsAlgo/AdjacencyList.swift b/Sources/JohnsonsAlgo/AdjacencyList.swift index b1752e0..626eea5 100644 --- a/Sources/JohnsonsAlgo/AdjacencyList.swift +++ b/Sources/JohnsonsAlgo/AdjacencyList.swift @@ -16,7 +16,7 @@ import Foundation * @version 1.0, 26.08.2006 * */ -@objc public class AdjacencyList : NSObject { +public class AdjacencyList { /** * Calculates a adjacency-list for a given array of an adjacency-matrix. * diff --git a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift index e944b5a..a132cb2 100644 --- a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift +++ b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift @@ -33,7 +33,7 @@ import Foundation * */ -@objc open class ElementaryCyclesSearch : NSObject { +open class ElementaryCyclesSearch { /** List of cycles */ private var cycles : Array>? diff --git a/Sources/JohnsonsAlgo/SCCResult.swift b/Sources/JohnsonsAlgo/SCCResult.swift index b36abe5..74a9d2f 100644 --- a/Sources/JohnsonsAlgo/SCCResult.swift +++ b/Sources/JohnsonsAlgo/SCCResult.swift @@ -8,7 +8,7 @@ import Foundation -@objc public class SCCResult : NSObject{ +public class SCCResult { var nodeIDsOfSCC : Set var adjList : Array> var lowestNodeId : Int diff --git a/Sources/JohnsonsAlgo/StrongConnectedComponents.swift b/Sources/JohnsonsAlgo/StrongConnectedComponents.swift index 0691249..c439622 100644 --- a/Sources/JohnsonsAlgo/StrongConnectedComponents.swift +++ b/Sources/JohnsonsAlgo/StrongConnectedComponents.swift @@ -32,7 +32,7 @@ import Foundation * @version 1.1, 22.03.2009 * */ -@objc public class StrongConnectedComponents :NSObject { +public class StrongConnectedComponents { /** Adjacency-list of original graph */ private var adjListOriginal : Array> From e770154245f5884bfdec922ad39b4f49dc5f6bfd Mon Sep 17 00:00:00 2001 From: TheMadOne <72d8610d@opayq.com> Date: Mon, 29 Jun 2020 21:55:47 +0200 Subject: [PATCH 15/19] remove old stuff --- Graphs/Johnson's algorithm - Swift/readme.rtf | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 Graphs/Johnson's algorithm - Swift/readme.rtf diff --git a/Graphs/Johnson's algorithm - Swift/readme.rtf b/Graphs/Johnson's algorithm - Swift/readme.rtf deleted file mode 100644 index 80a8ebf..0000000 --- a/Graphs/Johnson's algorithm - Swift/readme.rtf +++ /dev/null @@ -1,6 +0,0 @@ - -Swift library that implements the Jonhson Cycle algorithm to find circuits in a directed graph - -Original Author : Frank Meyer (Java implementation) - -Wikipedia: "https://en.wikipedia.org/wiki/Johnson's_algorithm" From 31936365610260eb8140dc588bf3a8a70c550a38 Mon Sep 17 00:00:00 2001 From: Vithanco Date: Sun, 1 May 2022 21:19:35 +0200 Subject: [PATCH 16/19] Update JohnsonsAlgoTests.swift added problematic matrix. Will now try to fix this. --- Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift b/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift index 3f84b0e..5067a28 100644 --- a/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift +++ b/Tests/JohnsonsAlgoTests/JohnsonsAlgoTests.swift @@ -7,9 +7,12 @@ final class JohnsonsAlgoTests: XCTestCase { // Use XCTAssert and related functions to verify your tests produce the correct // results. XCTAssertEqual(JohnsonsAlgo().text, "Hello, World!") + + let bigMatrix = [[false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, true, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, true, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false], [false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, true, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]] } static var allTests = [ ("testExample", testExample), ] + } From d02f7fa36250b726e6afe84685f3a0dcb7545b6e Mon Sep 17 00:00:00 2001 From: Vithanco Date: Sat, 14 May 2022 09:49:52 +0200 Subject: [PATCH 17/19] test cases created. Throws an error if computation fails. --- Sources/JohnsonsAlgo/AdjacencyList.swift | 3 +++ .../JohnsonsAlgo/ElementaryCyclesSearch.swift | 20 ++++++++++++++---- .../StrongConnectedComponents.swift | 4 ++-- .../JohnsonsAlgoTests/JohnsonsAlgoTests.swift | 21 +++++++++++++------ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Sources/JohnsonsAlgo/AdjacencyList.swift b/Sources/JohnsonsAlgo/AdjacencyList.swift index 626eea5..0abcdd6 100644 --- a/Sources/JohnsonsAlgo/AdjacencyList.swift +++ b/Sources/JohnsonsAlgo/AdjacencyList.swift @@ -8,6 +8,9 @@ import Foundation +public typealias AdjacencyMatrix = Array> +//public typealias AdjacencyList = Array> + /** * Calculates the adjacency-list for a given adjacency-matrix. * diff --git a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift index a132cb2..7771543 100644 --- a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift +++ b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift @@ -8,6 +8,13 @@ import Foundation +public typealias Matrix = Array> + +public enum GraphErrors: Error { + case algoIssue + case missingObject +} + /** * Searchs all elementary cycles in a given directed graph. The implementation * is independent from the concrete objects that represent the graphnodes, it @@ -71,7 +78,7 @@ open class ElementaryCyclesSearch { * * @return List::List::Object with the Lists of the elementary cycles. */ - open func getElementaryCycles() -> Array> { + open func getElementaryCycles() throws -> Array> { self.cycles = Array>() self.blocked = [Bool](repeating:false, count:self.adjList.count) self.B = [Array](repeating: [], count: self.adjList.count) @@ -90,7 +97,7 @@ open class ElementaryCyclesSearch { self.B![j] = [Int]() } - let _ = findCycles(v: s, s: s, adjList: scc) + let _ = try findCycles(v: s, s: s, adjList: scc) s = s + 1 }else { break @@ -110,8 +117,13 @@ open class ElementaryCyclesSearch { * connected component s is part of. * @return true, if cycle found; false otherwise */ - func findCycles(v: Int, s: Int, adjList:Array> ) -> Bool { + func findCycles(v: Int, s: Int, adjList:Array> ) throws -> Bool { var f = false; + + + if stack?.contains(v) ?? false { + throw GraphErrors.algoIssue + } self.stack?.append(v) self.blocked![v] = true; @@ -127,7 +139,7 @@ open class ElementaryCyclesSearch { self.cycles?.append(cycle); f = true; } else if (!self.blocked![w]) { - if (findCycles(v: w, s: s, adjList: adjList)) { + if (try findCycles(v: w, s: s, adjList: adjList)) { f = true; } } diff --git a/Sources/JohnsonsAlgo/StrongConnectedComponents.swift b/Sources/JohnsonsAlgo/StrongConnectedComponents.swift index c439622..4ba9600 100644 --- a/Sources/JohnsonsAlgo/StrongConnectedComponents.swift +++ b/Sources/JohnsonsAlgo/StrongConnectedComponents.swift @@ -224,7 +224,7 @@ public class StrongConnectedComponents { } } - class func test() { + class func test() throws { var nodes = [String](repeating: "", count: 10) var adjMatrix = [[Bool]](repeating: [Bool](repeating: false, count: 10), count: 10); @@ -246,7 +246,7 @@ public class StrongConnectedComponents { adjMatrix[6][1] = true; let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes as Array) - let cycles = ecs.getElementaryCycles() + let cycles = try ecs.getElementaryCycles() for i in 0.. Date: Sat, 14 May 2022 13:54:51 +0200 Subject: [PATCH 18/19] added testing, prevent crashing --- Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift index 7771543..66cf74c 100644 --- a/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift +++ b/Sources/JohnsonsAlgo/ElementaryCyclesSearch.swift @@ -79,6 +79,9 @@ open class ElementaryCyclesSearch { * @return List::List::Object with the Lists of the elementary cycles. */ open func getElementaryCycles() throws -> Array> { + if let result = cycles { + return result + } self.cycles = Array>() self.blocked = [Bool](repeating:false, count:self.adjList.count) self.B = [Array](repeating: [], count: self.adjList.count) @@ -122,6 +125,7 @@ open class ElementaryCyclesSearch { if stack?.contains(v) ?? false { + self.cycles = Array>() throw GraphErrors.algoIssue } self.stack?.append(v) From 1eb94533e9774cfacf4c97301b13bf427ff26993 Mon Sep 17 00:00:00 2001 From: Vithanco Date: Sat, 14 May 2022 13:58:47 +0200 Subject: [PATCH 19/19] like before --- .../StrongComponentTest.swift | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 Tests/JohnsonsAlgoTests/StrongComponentTest.swift diff --git a/Tests/JohnsonsAlgoTests/StrongComponentTest.swift b/Tests/JohnsonsAlgoTests/StrongComponentTest.swift new file mode 100644 index 0000000..a9ca01d --- /dev/null +++ b/Tests/JohnsonsAlgoTests/StrongComponentTest.swift @@ -0,0 +1,94 @@ +// +// StrongComponentTest.swift +// JohnsonsAlgoTests +// +// Created by Klaus Kneupner on 07/05/2022. +// + + +import XCTest +@testable import JohnsonsAlgo + +final class StrongComponentTests: XCTestCase { + + func buildEmptyGraph(n: Int) -> (AdjacencyMatrix, Array) { + var nodes = [String](repeating: "", count: n) + let adjMatrix = [[Bool]](repeating: [Bool](repeating: false, count: n), count: n); + + for i in 0..) + let cycles = try ecs.getElementaryCycles() + for i in 0.. " + }else { + representation += node as! String + } + } + print(representation + "\n") + } + } + + // from: https://en.wikipedia.org/wiki/Strongly_connected_component + func testWikiExample () throws { + var (adjMatrix,nodes) = buildEmptyGraph(n: 8) + adjMatrix[0][1] = true + adjMatrix[1][2] = true + adjMatrix[1][4] = true + adjMatrix[1][5] = true + adjMatrix[2][3] = true + adjMatrix[2][6] = true + adjMatrix[3][2] = true + adjMatrix[3][7] = true + adjMatrix[4][0] = true + adjMatrix[4][5] = true + adjMatrix[5][6] = true + adjMatrix[6][5] = true + adjMatrix[7][6] = true + adjMatrix[7][3] = true + + let ecs = ElementaryCyclesSearch(matrix: adjMatrix, graphNodes: nodes) + let cycles = try ecs.getElementaryCycles() + for i in 0.. " + }else { + representation += node + } + } + print(representation + "\n") + } + XCTAssertEqual(cycles.count,3 ) + + } +}