From e556054d729e8614d9d64eedfb0d6581ad2a3b17 Mon Sep 17 00:00:00 2001 From: CyrilFerlicot Date: Tue, 31 Oct 2023 17:23:18 +0100 Subject: [PATCH] Improve topological sorting - Add instance creation methods - Add an example in the class comment - Add helpers - Make error first class error --- src/AI-Algorithms-Graph/AIAstar.class.st | 40 ++++++------ src/AI-Algorithms-Graph/AIBFS.class.st | 28 +++++---- .../AIBellmanFord.class.st | 30 ++++----- src/AI-Algorithms-Graph/AIDijkstra.class.st | 38 ++++++------ .../AIGraphAlgorithm.class.st | 56 +++++++++-------- .../AIGraphReducer.class.st | 30 ++++----- src/AI-Algorithms-Graph/AIHits.class.st | 26 ++++---- src/AI-Algorithms-Graph/AIKruskal.class.st | 20 +++--- .../AILongestPathInDAG.class.st | 34 +++++----- .../AILongestPathInDCG.class.st | 32 +++++----- src/AI-Algorithms-Graph/AINotADAG.class.st | 16 +++++ src/AI-Algorithms-Graph/AIPrim.class.st | 17 ++--- .../AIShortestPathInDAG.class.st | 34 +++++----- src/AI-Algorithms-Graph/AITarjan.class.st | 24 +++---- .../AITopologicalSorting.class.st | 62 +++++++++++++++---- .../AIWeightedHits.class.st | 16 ++--- .../ManifestAIAlgorithmsGraph.class.st | 12 ++-- src/AI-Algorithms-Graph/package.st | 2 +- 18 files changed, 300 insertions(+), 217 deletions(-) create mode 100644 src/AI-Algorithms-Graph/AINotADAG.class.st diff --git a/src/AI-Algorithms-Graph/AIAstar.class.st b/src/AI-Algorithms-Graph/AIAstar.class.st index 089ecca..59a4cd3 100644 --- a/src/AI-Algorithms-Graph/AIAstar.class.st +++ b/src/AI-Algorithms-Graph/AIAstar.class.st @@ -4,34 +4,36 @@ A* is a graph traversal and path search algorithm, which is used in many fields Pseudocode and implementation for the approach is taken from: https://github.com/tatut/aoc2021-smalltalk/blob/main/src/AoC2021/AStar.class.st " Class { - #name : #AIAstar, - #superclass : #AIGraphAlgorithm, + #name : 'AIAstar', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #configuration } +{ #category : 'configuration' } AIAstar >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #accessing } +{ #category : 'accessing' } AIAstar >> end [ ^ end ] -{ #category : #accessing } +{ #category : 'accessing' } AIAstar >> end: endModel [ end := self findNode: endModel ] -{ #category : #running } +{ #category : 'running' } AIAstar >> heuristicFrom: startModel to: endModel [ "We are using a version of dijkstra algorithm here with all weights the for every node (value 1). @@ -78,27 +80,27 @@ AIAstar >> heuristicFrom: startModel to: endModel [ ^ pathD ] -{ #category : #actions } +{ #category : 'actions' } AIAstar >> newPriorityQueue [ "We use the Heap object defined in the SequenceableCollections package." ^ Heap new ] -{ #category : #configuration } +{ #category : 'configuration' } AIAstar >> nodeClass [ ^ AIPathDistanceNode ] -{ #category : #running } +{ #category : 'running' } AIAstar >> pathDistance [ "Needs to be editted" ^ self end pathDistance ] -{ #category : #backtracking } +{ #category : 'backtracking' } AIAstar >> reconstructPath [ | path previous | @@ -113,13 +115,13 @@ AIAstar >> reconstructPath [ ^ path ] -{ #category : #actions } +{ #category : 'actions' } AIAstar >> removeMostPromisingPair: aPriorityQueue [ ^ aPriorityQueue removeFirst ] -{ #category : #initialization } +{ #category : 'initialization' } AIAstar >> reset [ self nodes do: [ :node | @@ -129,7 +131,7 @@ AIAstar >> reset [ previousNode: nil ] ] -{ #category : #running } +{ #category : 'running' } AIAstar >> run [ | pq cameFrom gScore fScore gs fs | @@ -179,14 +181,14 @@ AIAstar >> run [ ] ] -{ #category : #running } +{ #category : 'running' } AIAstar >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AIAstar >> runFrom: startModel to: endModel [ self start: startModel. @@ -194,20 +196,20 @@ AIAstar >> runFrom: startModel to: endModel [ ^ self run ] -{ #category : #accessing } +{ #category : 'accessing' } AIAstar >> start [ ^ start ] -{ #category : #accessing } +{ #category : 'accessing' } AIAstar >> start: startModel [ start := self findNode: startModel. start pathDistance: 0 ] -{ #category : #private } +{ #category : 'private' } AIAstar >> updateDistance: newDistance of: aNode previousNode: previousNode [ aNode previousNode: previousNode. diff --git a/src/AI-Algorithms-Graph/AIBFS.class.st b/src/AI-Algorithms-Graph/AIBFS.class.st index a6a9fe9..c7d3904 100644 --- a/src/AI-Algorithms-Graph/AIBFS.class.st +++ b/src/AI-Algorithms-Graph/AIBFS.class.st @@ -14,35 +14,37 @@ shortestPath := bfs runFrom: 1 to: 4 This will return `#( 1 4 )`. " Class { - #name : #AIBFS, - #superclass : #AIGraphAlgorithm, + #name : 'AIBFS', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end', 'queue' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #accessing } +{ #category : 'accessing' } AIBFS >> end [ ^ end ] -{ #category : #accessing } +{ #category : 'accessing' } AIBFS >> end: endModel [ end := self findNode: endModel ] -{ #category : #configuration } +{ #category : 'configuration' } AIBFS >> nodeClass [ ^ AIBFSNode ] -{ #category : #actions } +{ #category : 'actions' } AIBFS >> reconstructPath [ | path previous | @@ -57,7 +59,7 @@ AIBFS >> reconstructPath [ ^ path ] -{ #category : #actions } +{ #category : 'actions' } AIBFS >> resetValues [ nodes do: [ :aNode | @@ -67,7 +69,7 @@ AIBFS >> resetValues [ distance: nil ] ] -{ #category : #running } +{ #category : 'running' } AIBFS >> run [ | node neighbours | @@ -89,14 +91,14 @@ AIBFS >> run [ next previousNode: node ] ] ] ] -{ #category : #running } +{ #category : 'running' } AIBFS >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AIBFS >> runFrom: startModel to: endModel [ self runFrom: startModel. @@ -104,13 +106,13 @@ AIBFS >> runFrom: startModel to: endModel [ ^ self reconstructPath ] -{ #category : #accessing } +{ #category : 'accessing' } AIBFS >> start [ ^ start ] -{ #category : #accessing } +{ #category : 'accessing' } AIBFS >> start: startModel [ start := self findNode: startModel diff --git a/src/AI-Algorithms-Graph/AIBellmanFord.class.st b/src/AI-Algorithms-Graph/AIBellmanFord.class.st index 2c74bd6..3f68c16 100644 --- a/src/AI-Algorithms-Graph/AIBellmanFord.class.st +++ b/src/AI-Algorithms-Graph/AIBellmanFord.class.st @@ -2,34 +2,36 @@ The Bellman Ford algorithm calculates the shortest path in any kind of graph. The graph edges can have negative weights and this algo hanldes negative cycles. If a negative cycle is detected, the path distance of that node is set to negative infinity " Class { - #name : #AIBellmanFord, - #superclass : #AIGraphAlgorithm, + #name : 'AIBellmanFord', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #configuration } +{ #category : 'configuration' } AIBellmanFord >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #accessing } +{ #category : 'accessing' } AIBellmanFord >> end: aModel [ end := (self findNode: aModel) ] -{ #category : #configuration } +{ #category : 'configuration' } AIBellmanFord >> nodeClass [ ^ AIPathDistanceNode ] -{ #category : #actions } +{ #category : 'actions' } AIBellmanFord >> reconstructPath [ | path previous | @@ -47,7 +49,7 @@ AIBellmanFord >> reconstructPath [ ^ path ] -{ #category : #running } +{ #category : 'running' } AIBellmanFord >> relaxEdges [ | anEdgeHasBeenRelaxed | @@ -65,7 +67,7 @@ AIBellmanFord >> relaxEdges [ anEdgeHasBeenRelaxed ifFalse: [ ^ self ] ] ] -{ #category : #running } +{ #category : 'running' } AIBellmanFord >> relaxEdgesToNegativeInfinity [ "This method is called after a first relaxation has ocurred already. The algorithm is the same as the previous one but with the only difference that now if an edge can be relaxed we set the path distance as negative infinity because means that the edge is part of a negative cycle." @@ -84,7 +86,7 @@ AIBellmanFord >> relaxEdgesToNegativeInfinity [ anEdgeHasBeenRelaxed ifFalse: [ ^ self ] ] ] -{ #category : #actions } +{ #category : 'actions' } AIBellmanFord >> reset [ self nodes do: [ :node | @@ -93,7 +95,7 @@ AIBellmanFord >> reset [ previousNode: nil ] ] -{ #category : #running } +{ #category : 'running' } AIBellmanFord >> run [ start pathDistance: 0. @@ -105,14 +107,14 @@ AIBellmanFord >> run [ self relaxEdgesToNegativeInfinity ] -{ #category : #running } +{ #category : 'running' } AIBellmanFord >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AIBellmanFord >> runFrom: startModel to: endModel [ self runFrom: startModel. @@ -120,7 +122,7 @@ AIBellmanFord >> runFrom: startModel to: endModel [ ^ self reconstructPath ] -{ #category : #accessing } +{ #category : 'accessing' } AIBellmanFord >> start: aModel [ start := (self findNode: aModel). diff --git a/src/AI-Algorithms-Graph/AIDijkstra.class.st b/src/AI-Algorithms-Graph/AIDijkstra.class.st index ad4e44d..b84592a 100644 --- a/src/AI-Algorithms-Graph/AIDijkstra.class.st +++ b/src/AI-Algorithms-Graph/AIDijkstra.class.st @@ -5,34 +5,36 @@ Dijkstra's algorithm is an algorithm for finding the shortest paths between node The current implementation of this algo is the naive one. To improve it, Implement the data structure ""priority queue"" is needed. That is the key to improve the time complexity. Now, the priority queue is implemented as a list and the method `removeMostPromisingPair:` does a iteration to the list O(N) to retrieve the most promising pair. We can implement the priority queue as heap for example. " Class { - #name : #AIDijkstra, - #superclass : #AIGraphAlgorithm, + #name : 'AIDijkstra', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #configuration } +{ #category : 'configuration' } AIDijkstra >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #accessing } +{ #category : 'accessing' } AIDijkstra >> end [ ^ end ] -{ #category : #accessing } +{ #category : 'accessing' } AIDijkstra >> end: endModel [ end := (self findNode: endModel) ] -{ #category : #actions } +{ #category : 'actions' } AIDijkstra >> newPriorityQueue [ "We use the Heap object defined in the SequenceableCollections package." @@ -40,19 +42,19 @@ AIDijkstra >> newPriorityQueue [ ^ Heap new ] -{ #category : #configuration } +{ #category : 'configuration' } AIDijkstra >> nodeClass [ ^ AIPathDistanceNode ] -{ #category : #running } +{ #category : 'running' } AIDijkstra >> pathDistance [ ^ self end pathDistance ] -{ #category : #backtracking } +{ #category : 'backtracking' } AIDijkstra >> reconstructPath [ | path previous | @@ -67,13 +69,13 @@ AIDijkstra >> reconstructPath [ ^ path ] -{ #category : #actions } +{ #category : 'actions' } AIDijkstra >> removeMostPromisingPair: aPriorityQueue [ ^ aPriorityQueue removeFirst ] -{ #category : #initialization } +{ #category : 'initialization' } AIDijkstra >> reset [ self nodes do: [ :node | @@ -83,7 +85,7 @@ AIDijkstra >> reset [ previousNode: nil ] ] -{ #category : #running } +{ #category : 'running' } AIDijkstra >> run [ | pq | @@ -112,14 +114,14 @@ AIDijkstra >> run [ pq add: edge to] ] ] ] ] ] -{ #category : #running } +{ #category : 'running' } AIDijkstra >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AIDijkstra >> runFrom: startModel to: endModel [ self runFrom: startModel. @@ -127,20 +129,20 @@ AIDijkstra >> runFrom: startModel to: endModel [ ^ self reconstructPath ] -{ #category : #accessing } +{ #category : 'accessing' } AIDijkstra >> start [ ^ start ] -{ #category : #accessing } +{ #category : 'accessing' } AIDijkstra >> start: startModel [ start := (self findNode: startModel). start pathDistance: 0 ] -{ #category : #private } +{ #category : 'private' } AIDijkstra >> updateDistance: newDistance of: aNode previousNode: previousNode [ aNode previousNode: previousNode. diff --git a/src/AI-Algorithms-Graph/AIGraphAlgorithm.class.st b/src/AI-Algorithms-Graph/AIGraphAlgorithm.class.st index 7806fe6..a601f0e 100644 --- a/src/AI-Algorithms-Graph/AIGraphAlgorithm.class.st +++ b/src/AI-Algorithms-Graph/AIGraphAlgorithm.class.st @@ -5,24 +5,26 @@ I store edges and nodes and provides convenience methods to add, access and find Once configured, send the run message to execute the algorithm. " Class { - #name : #AIGraphAlgorithm, - #superclass : #Object, + #name : 'AIGraphAlgorithm', + #superclass : 'Object', #instVars : [ 'nodes', 'edges', 'sortingBlock', 'nodeDictionary' ], - #category : #'AI-Algorithms-Graph-Core' + #category : 'AI-Algorithms-Graph-Core', + #package : 'AI-Algorithms-Graph', + #tag : 'Core' } -{ #category : #testing } +{ #category : 'testing' } AIGraphAlgorithm class >> isAbstract [ ^ self = AIGraphAlgorithm ] -{ #category : #private } +{ #category : 'private' } AIGraphAlgorithm >> addEdge: edgeModel from: sourceBlock to: targetBlock [ | edge sourceNode targetNode | @@ -43,7 +45,7 @@ AIGraphAlgorithm >> addEdge: edgeModel from: sourceBlock to: targetBlock [ edge ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> addNodeFor: aModel [ | newNode | @@ -56,7 +58,7 @@ AIGraphAlgorithm >> addNodeFor: aModel [ ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> addNodesFrom: model childrenBlock: childrenBlock [ "recursively add nodes from the model" @@ -78,7 +80,7 @@ AIGraphAlgorithm >> addNodesFrom: model childrenBlock: childrenBlock [ to: [ :each | each second ] ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> addNodesFromDifferentGraph: aNodeList [ "Adds nodes from another graph. This is useful for example when you want to add all the nodes, and its adjacencies, from one graph to another. For example, first running a graph reducing algo and then do a topological sort. First create the graph reduced graph and then add its nodes to a topological sort graph. " @@ -92,26 +94,26 @@ AIGraphAlgorithm >> addNodesFromDifferentGraph: aNodeList [ to: [ :each | each value ] ] ] ] -{ #category : #configuration } +{ #category : 'configuration' } AIGraphAlgorithm >> edgeClass [ ^ nil ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> edges [ ^ edges ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> edges: aCollection from: source to: target [ aCollection do: [ :eModel | self addEdge: eModel from: source to: target ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> edges: aCollection from: source to: target weight: weightFunction [ | edge | @@ -120,7 +122,7 @@ AIGraphAlgorithm >> edges: aCollection from: source to: target weight: weightFun edge ifNotNil: [ edge weight: (weightFunction value: eModel) ] ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> edges: aCollection from: source toAll: targets [ aCollection do: [ :eModel | @@ -133,7 +135,7 @@ AIGraphAlgorithm >> edges: aCollection from: source toAll: targets [ to: [ :each | each second ] ] ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> edgesByPair: aCollection [ " aCollection must be a collection where the incoming edge has to be in the first position and the outgoing esge has to be in the second position. @@ -146,14 +148,14 @@ AIGraphAlgorithm >> edgesByPair: aCollection [ to: [ :each | each second ] ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> emptyGraph [ edges := edges copyEmpty. nodes := nodes copyEmpty ] -{ #category : #private } +{ #category : 'private' } AIGraphAlgorithm >> findBinaryBlock: aModel [ "New implementation of the algos to have better performances to find nodes. The nodes and edges are sorted from low to high according to their has number." @@ -161,7 +163,7 @@ AIGraphAlgorithm >> findBinaryBlock: aModel [ ^ [ :aNode | aModel hash - aNode model hash ] ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> findEdge: aModel [ "^ edges findBinary: (self findBinaryBlock: aModel)" @@ -169,7 +171,7 @@ AIGraphAlgorithm >> findEdge: aModel [ ^ edges detect: [ :edge | edge model = aModel ] ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> findNode: aModel [ "^ nodes findBinary: (self findBinaryBlock: aModel)." @@ -181,7 +183,7 @@ AIGraphAlgorithm >> findNode: aModel [ ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> findNode: aModel ifAbsent: aBlock [ "^ nodes findBinary: (self findBinaryBlock: aModel) ifNone: aBlock" @@ -191,7 +193,7 @@ AIGraphAlgorithm >> findNode: aModel ifAbsent: aBlock [ ^nodeDictionary at: aModel ifAbsent: aBlock. ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> findNode: aModel ifFound: aBlock [ "^ nodes @@ -204,13 +206,13 @@ AIGraphAlgorithm >> findNode: aModel ifFound: aBlock [ ^nodeDictionary at: aModel ifPresent: aBlock. ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> graph [ ^ { nodes. edges } ] -{ #category : #initialization } +{ #category : 'initialization' } AIGraphAlgorithm >> initialize [ sortingBlock := [ :a :b | a model hash <= b model hash ]. @@ -219,31 +221,31 @@ AIGraphAlgorithm >> initialize [ nodeDictionary := Dictionary new. ] -{ #category : #configuration } +{ #category : 'configuration' } AIGraphAlgorithm >> nodeClass [ ^ AIGraphNode ] -{ #category : #accessing } +{ #category : 'accessing' } AIGraphAlgorithm >> nodes [ ^ nodes ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> nodes: aNodeList [ aNodeList do: [ :model | self addNodeFor: model ] ] -{ #category : #'building - graph' } +{ #category : 'building - graph' } AIGraphAlgorithm >> rawNodes: aRawNodeList [ nodes := aRawNodeList ] -{ #category : #running } +{ #category : 'running' } AIGraphAlgorithm >> run [ self subclassResponsibility diff --git a/src/AI-Algorithms-Graph/AIGraphReducer.class.st b/src/AI-Algorithms-Graph/AIGraphReducer.class.st index 1a9abbb..12a6401 100644 --- a/src/AI-Algorithms-Graph/AIGraphReducer.class.st +++ b/src/AI-Algorithms-Graph/AIGraphReducer.class.st @@ -6,22 +6,24 @@ circuitsNodes instance variable will collect all nodes created by merging nodes This algorithm is not merging the weights of the graph. However, reducing a weighted graphs needs an specific way of doing it according to the use case. " Class { - #name : #AIGraphReducer, - #superclass : #AIGraphAlgorithm, + #name : 'AIGraphReducer', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'circuits', 'collapsedNodes' ], - #category : #'AI-Algorithms-Graph-Strongly Connected Components' + #category : 'AI-Algorithms-Graph-Strongly Connected Components', + #package : 'AI-Algorithms-Graph', + #tag : 'Strongly Connected Components' } -{ #category : #updating } +{ #category : 'updating' } AIGraphReducer >> addCollapsedNodes [ nodes addAll: collapsedNodes ] -{ #category : #actions } +{ #category : 'actions' } AIGraphReducer >> adjacenciesFor: aMergedNodeList [ "Obtains the adjacent nodes of the merged nodes. Then removes the references to the same merged nodes (to avoid referencing a merged node). Because all the merged nodes are now a same 'reduced' node" @@ -31,7 +33,7 @@ AIGraphReducer >> adjacenciesFor: aMergedNodeList [ as: Set) difference: aMergedNodeList) asOrderedCollection ] -{ #category : #running } +{ #category : 'running' } AIGraphReducer >> findCircuits [ | tarjanCircuits | @@ -43,20 +45,20 @@ AIGraphReducer >> findCircuits [ circuit collect: [ :each | self findNode: each ] ] ] -{ #category : #initialization } +{ #category : 'initialization' } AIGraphReducer >> initialize [ super initialize. collapsedNodes := OrderedCollection new. circuits := OrderedCollection new ] -{ #category : #configuration } +{ #category : 'configuration' } AIGraphReducer >> nodeClass [ ^ AIReducedGraphNode ] -{ #category : #reducing } +{ #category : 'reducing' } AIGraphReducer >> reduceGraph [ circuits do: [ :each | self reduceNodesInCircuit: each ]. @@ -65,7 +67,7 @@ AIGraphReducer >> reduceGraph [ self replaceReferencesToMergedNodes ] -{ #category : #reducing } +{ #category : 'reducing' } AIGraphReducer >> reduceNodesInCircuit: aCircuit [ "This method created a reduced node (called circuit node) that contains all the nodes that are inside a circuit inside a strongly connected component that the Tarjan algorithm found." @@ -77,14 +79,14 @@ AIGraphReducer >> reduceNodesInCircuit: aCircuit [ yourself) ] -{ #category : #updating } +{ #category : 'updating' } AIGraphReducer >> removeMergedNodes [ nodes removeAll: (collapsedNodes flatCollect: [ :each | each mergedNodes ]) ] -{ #category : #reducing } +{ #category : 'reducing' } AIGraphReducer >> replaceReferencesToMergedNode: aReducedNode [ "Replace the adjacencies of aReducedNode to merged nodes to reference the reduced node instead. For example, is aReducedNode has an an adjacency to node A, but node A has been reduced to node R, replace the adjacency of A with R." @@ -105,14 +107,14 @@ AIGraphReducer >> replaceReferencesToMergedNode: aReducedNode [ addAll: newAdjacencies asSet ] -{ #category : #reducing } +{ #category : 'reducing' } AIGraphReducer >> replaceReferencesToMergedNodes [ nodes do: [ :reducedNode | self replaceReferencesToMergedNode: reducedNode ] ] -{ #category : #running } +{ #category : 'running' } AIGraphReducer >> run [ self findCircuits. diff --git a/src/AI-Algorithms-Graph/AIHits.class.st b/src/AI-Algorithms-Graph/AIHits.class.st index dba0f80..ef03a8e 100644 --- a/src/AI-Algorithms-Graph/AIHits.class.st +++ b/src/AI-Algorithms-Graph/AIHits.class.st @@ -4,15 +4,17 @@ From wikipedia: Hyperlink-Induced Topic Search (HITS; also known as hubs and authorities) is a link analysis algorithm that rates Web pages, developed by Jon Kleinberg. The idea behind Hubs and Authorities stemmed from a particular insight into the creation of web pages when the Internet was originally forming; that is, certain web pages, known as hubs, served as large directories that were not actually authoritative in the information that they held, but were used as compilations of a broad catalog of information that led users direct to other authoritative pages. In other words, a good hub represents a page that pointed to many other pages, while a good authority represents a page that is linked by many different hubs. " Class { - #name : #AIHits, - #superclass : #AIGraphAlgorithm, + #name : 'AIHits', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'k' ], - #category : #'AI-Algorithms-Graph-Hits' + #category : 'AI-Algorithms-Graph-Hits', + #package : 'AI-Algorithms-Graph', + #tag : 'Hits' } -{ #category : #running } +{ #category : 'running' } AIHits >> computeAuthoritiesFor: aNode [ aNode auth: @@ -21,7 +23,7 @@ AIHits >> computeAuthoritiesFor: aNode [ into: [ :sum :node | sum + node hub ]) ] -{ #category : #running } +{ #category : 'running' } AIHits >> computeHubsFor: aNode [ aNode hub: @@ -30,14 +32,14 @@ AIHits >> computeHubsFor: aNode [ into: [ :sum :node | sum + node auth ]) ] -{ #category : #initialization } +{ #category : 'initialization' } AIHits >> initialize [ super initialize. k := 20 ] -{ #category : #running } +{ #category : 'running' } AIHits >> initializeNodes [ nodes do: [ :n | @@ -45,7 +47,7 @@ AIHits >> initializeNodes [ n hub: 1.0 ] ] -{ #category : #configuration } +{ #category : 'configuration' } AIHits >> k [ "Number of iterations" @@ -53,19 +55,19 @@ AIHits >> k [ ^ k ] -{ #category : #configuration } +{ #category : 'configuration' } AIHits >> k: aNumberOfIterations [ k := aNumberOfIterations ] -{ #category : #configuration } +{ #category : 'configuration' } AIHits >> nodeClass [ ^ AIHitsNode ] -{ #category : #running } +{ #category : 'running' } AIHits >> normalizeScores [ | authNorm hubNorm | @@ -88,7 +90,7 @@ AIHits >> normalizeScores [ n hub: n hub / hubNorm ] ] -{ #category : #running } +{ #category : 'running' } AIHits >> run [ self initializeNodes. diff --git a/src/AI-Algorithms-Graph/AIKruskal.class.st b/src/AI-Algorithms-Graph/AIKruskal.class.st index 1cf6b45..f0d6ba7 100644 --- a/src/AI-Algorithms-Graph/AIKruskal.class.st +++ b/src/AI-Algorithms-Graph/AIKruskal.class.st @@ -6,46 +6,48 @@ See https://en.wikipedia.org/wiki/Kruskal%27s_algorithm For having the time complexity of O(E log E) this algorithm uses the disjoint-set data structure. See the node class of this algorithm for more information about that data structure. Uses the disjoint-set to check, in linear time, if a cycle will be formed when joining two edges. " Class { - #name : #AIKruskal, - #superclass : #AIGraphAlgorithm, + #name : 'AIKruskal', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'sortBlock' ], - #category : #'AI-Algorithms-Graph-Kruskal' + #category : 'AI-Algorithms-Graph-Kruskal', + #package : 'AI-Algorithms-Graph', + #tag : 'Kruskal' } -{ #category : #configuration } +{ #category : 'configuration' } AIKruskal >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #initialization } +{ #category : 'initialization' } AIKruskal >> initialize [ super initialize. self minSpanningTree ] -{ #category : #configuration } +{ #category : 'configuration' } AIKruskal >> maxSpanningTree [ sortBlock := [ :e1 :e2 | e1 weight > e2 weight ] ] -{ #category : #configuration } +{ #category : 'configuration' } AIKruskal >> minSpanningTree [ sortBlock := [ :e1 :e2 | e1 weight < e2 weight ] ] -{ #category : #configuration } +{ #category : 'configuration' } AIKruskal >> nodeClass [ ^ AIDisjointSetNode ] -{ #category : #running } +{ #category : 'running' } AIKruskal >> run [ | treeEdges sortedEdges | diff --git a/src/AI-Algorithms-Graph/AILongestPathInDAG.class.st b/src/AI-Algorithms-Graph/AILongestPathInDAG.class.st index f5d7562..c921cf0 100644 --- a/src/AI-Algorithms-Graph/AILongestPathInDAG.class.st +++ b/src/AI-Algorithms-Graph/AILongestPathInDAG.class.st @@ -10,47 +10,49 @@ The algorithm is: - IF (v pathWeight > u pathWeight + (-1)*weight(u, v)) THEN v pathWeight: u pathWeight + weight(u, v) " Class { - #name : #AILongestPathInDAG, - #superclass : #AIGraphAlgorithm, + #name : 'AILongestPathInDAG', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #configuration } +{ #category : 'configuration' } AILongestPathInDAG >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #accessing } +{ #category : 'accessing' } AILongestPathInDAG >> end [ ^ end ] -{ #category : #accessing } +{ #category : 'accessing' } AILongestPathInDAG >> end: aModel [ end := self findNode: aModel ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> initializePathWeights [ nodes do: [ :node | node pathDistance: Float infinity ]. start pathDistance: 0 ] -{ #category : #configuration } +{ #category : 'configuration' } AILongestPathInDAG >> nodeClass [ ^ AIPathDistanceNode ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> reconstructPath [ | path previous | @@ -65,7 +67,7 @@ AILongestPathInDAG >> reconstructPath [ ^ path ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> run [ | stack sortedNode | @@ -80,14 +82,14 @@ AILongestPathInDAG >> run [ self updatePathDistance: nextEdge previousNode: sortedNode ] ] ] ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> runFrom: startModel to: endModel [ self runFrom: startModel. @@ -95,19 +97,19 @@ AILongestPathInDAG >> runFrom: startModel to: endModel [ ^ self reconstructPath ] -{ #category : #accessing } +{ #category : 'accessing' } AILongestPathInDAG >> start [ ^ start ] -{ #category : #accessing } +{ #category : 'accessing' } AILongestPathInDAG >> start: aModel [ start := self findNode: aModel ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> topologicalSortedNodes [ | topSorter | @@ -118,7 +120,7 @@ AILongestPathInDAG >> topologicalSortedNodes [ ^ topSorter topologicalSortedElements ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDAG >> updatePathDistance: edge previousNode: previousNode [ edge to pathDistance: previousNode pathDistance + edge weight. diff --git a/src/AI-Algorithms-Graph/AILongestPathInDCG.class.st b/src/AI-Algorithms-Graph/AILongestPathInDCG.class.st index c908328..4773c46 100644 --- a/src/AI-Algorithms-Graph/AILongestPathInDCG.class.st +++ b/src/AI-Algorithms-Graph/AILongestPathInDCG.class.st @@ -2,40 +2,42 @@ A variation of Bellman Ford algorithm that calculates the longest path in any kind of graph (including Directed Cyclic Graphs (DCG)). The graph edges can have negative weights and this algo hanldes negative cycles. If a negative cycle is detected, the path distance of that node is set to negative infinity. " Class { - #name : #AILongestPathInDCG, - #superclass : #AIGraphAlgorithm, + #name : 'AILongestPathInDCG', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #configuration } +{ #category : 'configuration' } AILongestPathInDCG >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #accessing } +{ #category : 'accessing' } AILongestPathInDCG >> end: aModel [ end := (self findNode: aModel) ] -{ #category : #configuration } +{ #category : 'configuration' } AILongestPathInDCG >> nodeClass [ ^ AIPathDistanceNode ] -{ #category : #actions } +{ #category : 'actions' } AILongestPathInDCG >> pathPositive [ self nodes do: [ :node | node pathDistance: -1 * node pathDistance ] ] -{ #category : #actions } +{ #category : 'actions' } AILongestPathInDCG >> reconstructPath [ | path previous | @@ -53,7 +55,7 @@ AILongestPathInDCG >> reconstructPath [ ^ path ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDCG >> relaxEdges [ | anEdgeHasBeenRelaxed | @@ -71,7 +73,7 @@ AILongestPathInDCG >> relaxEdges [ anEdgeHasBeenRelaxed ifFalse: [ ^ self ] ] ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDCG >> relaxEdgesToNegativeInfinity [ "This method is called after a first relaxation has ocurred already. The algorithm is the same as the previous one but with the only difference that now if an edge can be relaxed @@ -92,7 +94,7 @@ AILongestPathInDCG >> relaxEdgesToNegativeInfinity [ anEdgeHasBeenRelaxed ifFalse: [ ^ self ] ] ] -{ #category : #actions } +{ #category : 'actions' } AILongestPathInDCG >> reset [ self nodes do: [ :node | @@ -101,7 +103,7 @@ AILongestPathInDCG >> reset [ previousNode: nil ] ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDCG >> run [ self reset. @@ -115,14 +117,14 @@ AILongestPathInDCG >> run [ self pathPositive ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDCG >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AILongestPathInDCG >> runFrom: startModel to: endModel [ self runFrom: startModel. @@ -130,7 +132,7 @@ AILongestPathInDCG >> runFrom: startModel to: endModel [ ^ self reconstructPath ] -{ #category : #accessing } +{ #category : 'accessing' } AILongestPathInDCG >> start: aModel [ start := self findNode: aModel. diff --git a/src/AI-Algorithms-Graph/AINotADAG.class.st b/src/AI-Algorithms-Graph/AINotADAG.class.st new file mode 100644 index 0000000..318fe29 --- /dev/null +++ b/src/AI-Algorithms-Graph/AINotADAG.class.st @@ -0,0 +1,16 @@ +" +I am raised when an algorithm should have run on a DAG but the collection was not a DAG. +" +Class { + #name : 'AINotADAG', + #superclass : 'Error', + #category : 'AI-Algorithms-Graph-Topological Sorting', + #package : 'AI-Algorithms-Graph', + #tag : 'Topological Sorting' +} + +{ #category : 'accessing' } +AINotADAG >> messageText [ + + ^ messageText ifNil: [ messageText := 'Not a DAG (Directed Acyclic Graph)' ] +] diff --git a/src/AI-Algorithms-Graph/AIPrim.class.st b/src/AI-Algorithms-Graph/AIPrim.class.st index feb8548..df95d36 100644 --- a/src/AI-Algorithms-Graph/AIPrim.class.st +++ b/src/AI-Algorithms-Graph/AIPrim.class.st @@ -4,24 +4,25 @@ Prim's algorithm (also known as Jarník's algorithm) is a greedy algorithm that For more, see: https://en.wikipedia.org/wiki/Prim%27s_algorithm " Class { - #name : #AIPrim, - #superclass : #AIGraphAlgorithm, - #category : #'AI-Algorithms-Graph' + #name : 'AIPrim', + #superclass : 'AIGraphAlgorithm', + #category : 'AI-Algorithms-Graph', + #package : 'AI-Algorithms-Graph' } -{ #category : #configuration } +{ #category : 'configuration' } AIPrim >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #initialization } +{ #category : 'initialization' } AIPrim >> initialize [ super initialize ] -{ #category : #accessing } +{ #category : 'accessing' } AIPrim >> minNode [ | lowNode lowKey | @@ -33,13 +34,13 @@ AIPrim >> minNode [ ^ lowNode ] -{ #category : #configuration } +{ #category : 'configuration' } AIPrim >> nodeClass [ ^ AIBFSNode ] -{ #category : #running } +{ #category : 'running' } AIPrim >> run [ | curNode curEdge treeEdges fromNode toNode primEdge | diff --git a/src/AI-Algorithms-Graph/AIShortestPathInDAG.class.st b/src/AI-Algorithms-Graph/AIShortestPathInDAG.class.st index aec7fa8..7db4ec1 100644 --- a/src/AI-Algorithms-Graph/AIShortestPathInDAG.class.st +++ b/src/AI-Algorithms-Graph/AIShortestPathInDAG.class.st @@ -10,47 +10,49 @@ The algorithm is: - IF (v pathWeight > u pathWeight + weight(u, v)) THEN v pathWeight: u pathWeight + weight(u, v) " Class { - #name : #AIShortestPathInDAG, - #superclass : #AIGraphAlgorithm, + #name : 'AIShortestPathInDAG', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'start', 'end' ], - #category : #'AI-Algorithms-Graph-Shortest path' + #category : 'AI-Algorithms-Graph-Shortest path', + #package : 'AI-Algorithms-Graph', + #tag : 'Shortest path' } -{ #category : #configuration } +{ #category : 'configuration' } AIShortestPathInDAG >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #accessing } +{ #category : 'accessing' } AIShortestPathInDAG >> end [ ^ end ] -{ #category : #accessing } +{ #category : 'accessing' } AIShortestPathInDAG >> end: aModel [ end := self findNode: aModel ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> initializePathWeights [ nodes do: [ :node | node pathDistance: Float infinity ]. start pathDistance: 0 ] -{ #category : #configuration } +{ #category : 'configuration' } AIShortestPathInDAG >> nodeClass [ ^ AIPathDistanceNode ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> reconstructPath [ | path previous | @@ -65,7 +67,7 @@ AIShortestPathInDAG >> reconstructPath [ ^ path ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> run [ | stack sortedNode | @@ -80,14 +82,14 @@ AIShortestPathInDAG >> run [ ifTrue: [ self updatePathDistance: nextEdge previousNode: sortedNode ] ] ] ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> runFrom: startModel [ self start: startModel. self run ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> runFrom: startModel to: endModel [ self runFrom: startModel. @@ -95,19 +97,19 @@ AIShortestPathInDAG >> runFrom: startModel to: endModel [ ^ self reconstructPath ] -{ #category : #accessing } +{ #category : 'accessing' } AIShortestPathInDAG >> start [ ^ start ] -{ #category : #accessing } +{ #category : 'accessing' } AIShortestPathInDAG >> start: aModel [ start := self findNode: aModel ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> topologicalSortedNodes [ | topSorter | @@ -118,7 +120,7 @@ AIShortestPathInDAG >> topologicalSortedNodes [ ^ topSorter topologicalSortedElements ] -{ #category : #running } +{ #category : 'running' } AIShortestPathInDAG >> updatePathDistance: edge previousNode: previousNode [ edge to pathDistance: previousNode pathDistance + edge weight. diff --git a/src/AI-Algorithms-Graph/AITarjan.class.st b/src/AI-Algorithms-Graph/AITarjan.class.st index caafbcc..e9ae666 100644 --- a/src/AI-Algorithms-Graph/AITarjan.class.st +++ b/src/AI-Algorithms-Graph/AITarjan.class.st @@ -16,17 +16,19 @@ tarjan stronglyConnectedComponents " Class { - #name : #AITarjan, - #superclass : #AIGraphAlgorithm, + #name : 'AITarjan', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'stack', 'runningIndex', 'sccs' ], - #category : #'AI-Algorithms-Graph-Strongly Connected Components' + #category : 'AI-Algorithms-Graph-Strongly Connected Components', + #package : 'AI-Algorithms-Graph', + #tag : 'Strongly Connected Components' } -{ #category : #running } +{ #category : 'running' } AITarjan >> addNewSccForNode: aTarjanNode [ | currentNode stronglyConnectedComponent | @@ -41,13 +43,13 @@ AITarjan >> addNewSccForNode: aTarjanNode [ stronglyConnectedComponent do: [ :each | each cycleNodes: stronglyConnectedComponent ] ] -{ #category : #accessing } +{ #category : 'accessing' } AITarjan >> circuits [ ^ self stronglyConnectedComponents select: [ :each | each size > 1 ] ] -{ #category : #testing } +{ #category : 'testing' } AITarjan >> isRootNode: aTarjanNode [ "Finding a 'root' node means that we found a strongly connected component. The 'root' node represents the beginning of that strongly connected component" @@ -55,20 +57,20 @@ AITarjan >> isRootNode: aTarjanNode [ ^ aTarjanNode tarjanIndex = aTarjanNode tarjanLowlink ] -{ #category : #configuration } +{ #category : 'configuration' } AITarjan >> nodeClass [ ^ AITarjanNode ] -{ #category : #running } +{ #category : 'running' } AITarjan >> putOnStack: aTarjanNode [ stack push: aTarjanNode. aTarjanNode inStack: true ] -{ #category : #running } +{ #category : 'running' } AITarjan >> run [ sccs := OrderedCollection new. @@ -79,14 +81,14 @@ AITarjan >> run [ ^ self stronglyConnectedComponents ] -{ #category : #accessing } +{ #category : 'accessing' } AITarjan >> stronglyConnectedComponents [ sccs ifNil: [ self run ]. ^ sccs collect: [ :component | component collect: [ :each | each model ] ] ] -{ #category : #running } +{ #category : 'running' } AITarjan >> traverse: aTarjanNode [ aTarjanNode tarjanIndex: runningIndex. diff --git a/src/AI-Algorithms-Graph/AITopologicalSorting.class.st b/src/AI-Algorithms-Graph/AITopologicalSorting.class.st index bc4e644..e4d5587 100644 --- a/src/AI-Algorithms-Graph/AITopologicalSorting.class.st +++ b/src/AI-Algorithms-Graph/AITopologicalSorting.class.st @@ -3,31 +3,70 @@ I am Kahn's Algorithm for topological sorting. I do the toplogical sorting in li From Wikipedia: A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge uv from vertex u to vertex v, u comes before v in the ordering. For instance, the vertices of the graph may represent tasks to be performed, and the edges may represent constraints that one task must be performed before another; in this application, a topological ordering is just a valid sequence for the tasks. A topological ordering is possible if and only if the graph has no directed cycles, that is, if it is a directed acyclic graph (DAG). + +## Example + +Here is an example of use: Let's imagine we have a collection of number from 1 to 10 and 1 and 4 requires 9 to be before, 4 and 6 requires 2 to be before and 3 and 4 requires 7 to be before. We can do our sorting like this: + +```st + +dependencies := Dictionary new + at: 9 put: #( 1 4); + at: 2 put: #( 4 6); + at: 7 put: #( 3 4); + yourself. + +AITopologicalSorting sort: #( 1 2 3 4 5 6 7 8 9 10 ) followingIncomingProperty: [ :int | dependencies at: int ifAbsent: [ #() ] ] + +``` " Class { - #name : #AITopologicalSorting, - #superclass : #AIGraphAlgorithm, + #name : 'AITopologicalSorting', + #superclass : 'AIGraphAlgorithm', #instVars : [ 'topologicalSortedElements', 'nodesWithNoIncomingEdges' ], - #category : #'AI-Algorithms-Graph-Topological Sorting' + #category : 'AI-Algorithms-Graph-Topological Sorting', + #package : 'AI-Algorithms-Graph', + #tag : 'Topological Sorting' } -{ #category : #running } +{ #category : 'instance creation' } +AITopologicalSorting class >> nodes: aCollection incomingEdgesProperty: aValuable [ + + ^ self new + nodes: aCollection; + addIncomingEdgesFollowing: aValuable; + yourself +] + +{ #category : 'instance creation' } +AITopologicalSorting class >> sort: nodes followingIncomingProperty: aValuable [ + + ^ (self nodes: nodes incomingEdgesProperty: aValuable) run +] + +{ #category : 'adding' } +AITopologicalSorting >> addIncomingEdgesFollowing: aBlock [ + + self edges: (nodes flatCollect: [ :node | (aBlock value: node model) collect: [ :each | node model -> each ] ]) from: #key to: #value +] + +{ #category : 'running' } AITopologicalSorting >> gatherNoIncomingNodes [ nodesWithNoIncomingEdges addAll: (nodes select: [ :node | node isLeaf ]) ] -{ #category : #private } +{ #category : 'private' } AITopologicalSorting >> graphHasEdges [ ^ nodes anySatisfy: [ :node | node adjacentNodes isNotEmpty ] ] -{ #category : #running } +{ #category : 'running' } AITopologicalSorting >> initializeElements [ topologicalSortedElements := OrderedCollection new. @@ -36,13 +75,13 @@ AITopologicalSorting >> initializeElements [ nodesWithNoIncomingEdges := LinkedList new ] -{ #category : #configuration } +{ #category : 'configuration' } AITopologicalSorting >> nodeClass [ ^ AINodeWithPrevious ] -{ #category : #private } +{ #category : 'private' } AITopologicalSorting >> removeEdgesOf: aNode [ aNode adjacentNodes do: [ :node | @@ -51,7 +90,7 @@ AITopologicalSorting >> removeEdgesOf: aNode [ aNode adjacentNodes: #( ) ] -{ #category : #running } +{ #category : 'running' } AITopologicalSorting >> run [ self initializeElements. @@ -62,12 +101,11 @@ AITopologicalSorting >> run [ topologicalSortedElements addLast: node model. self removeEdgesOf: node ]. - self graphHasEdges ifTrue: [ - Error signal: 'Not a DAG (Directed Acyclic Graph)' ]. + self graphHasEdges ifTrue: [ AINotADAG signal ]. ^ topologicalSortedElements ] -{ #category : #accessing } +{ #category : 'accessing' } AITopologicalSorting >> topologicalSortedElements [ ^ topologicalSortedElements diff --git a/src/AI-Algorithms-Graph/AIWeightedHits.class.st b/src/AI-Algorithms-Graph/AIWeightedHits.class.st index e962e1d..032be12 100644 --- a/src/AI-Algorithms-Graph/AIWeightedHits.class.st +++ b/src/AI-Algorithms-Graph/AIWeightedHits.class.st @@ -8,12 +8,14 @@ For more information, refer to this papers: Where is detailed how using a weighted graph can improve the results of the Hits algorithm. " Class { - #name : #AIWeightedHits, - #superclass : #AIHits, - #category : #'AI-Algorithms-Graph-Hits' + #name : 'AIWeightedHits', + #superclass : 'AIHits', + #category : 'AI-Algorithms-Graph-Hits', + #package : 'AI-Algorithms-Graph', + #tag : 'Hits' } -{ #category : #running } +{ #category : 'running' } AIWeightedHits >> computeAuthoritiesFor: aNode [ aNode auth: (aNode incomingEdges @@ -21,7 +23,7 @@ AIWeightedHits >> computeAuthoritiesFor: aNode [ into: [ :sum :edge | sum + (edge weight * edge from hub) ]) ] -{ #category : #running } +{ #category : 'running' } AIWeightedHits >> computeHubsFor: aNode [ aNode hub: (aNode outgoingEdges @@ -29,13 +31,13 @@ AIWeightedHits >> computeHubsFor: aNode [ into: [ :sum :edge | sum + (edge weight * edge to auth) ]) ] -{ #category : #configuration } +{ #category : 'configuration' } AIWeightedHits >> edgeClass [ ^ AIWeightedEdge ] -{ #category : #configuration } +{ #category : 'configuration' } AIWeightedHits >> nodeClass [ ^ AIWeightedHitsNode diff --git a/src/AI-Algorithms-Graph/ManifestAIAlgorithmsGraph.class.st b/src/AI-Algorithms-Graph/ManifestAIAlgorithmsGraph.class.st index eb4c95e..704a5b3 100644 --- a/src/AI-Algorithms-Graph/ManifestAIAlgorithmsGraph.class.st +++ b/src/AI-Algorithms-Graph/ManifestAIAlgorithmsGraph.class.st @@ -2,17 +2,19 @@ I am the manifest of the package. " Class { - #name : #ManifestAIAlgorithmsGraph, - #superclass : #PackageManifest, - #category : #'AI-Algorithms-Graph-Manifest' + #name : 'ManifestAIAlgorithmsGraph', + #superclass : 'PackageManifest', + #category : 'AI-Algorithms-Graph-Manifest', + #package : 'AI-Algorithms-Graph', + #tag : 'Manifest' } -{ #category : #'code-critics' } +{ #category : 'code-critics' } ManifestAIAlgorithmsGraph class >> ruleModifiesCollectionRuleV1FalsePositive [ ^ #(#(#(#RGMethodDefinition #(#AITarjan #addNewSccForNode: #false)) #'2021-08-17T12:43:07.085916+02:00') ) ] -{ #category : #'code-critics' } +{ #category : 'code-critics' } ManifestAIAlgorithmsGraph class >> ruleTempsReadBeforeWrittenRuleV1FalsePositive [ ^ #(#(#(#RGMethodDefinition #(#AITarjan #addNewSccForNode: #false)) #'2021-08-17T12:43:10.336858+02:00') ) ] diff --git a/src/AI-Algorithms-Graph/package.st b/src/AI-Algorithms-Graph/package.st index 07f9068..abadad0 100644 --- a/src/AI-Algorithms-Graph/package.st +++ b/src/AI-Algorithms-Graph/package.st @@ -1 +1 @@ -Package { #name : #'AI-Algorithms-Graph' } +Package { #name : 'AI-Algorithms-Graph' }