Skip to content

Commit

Permalink
Refactore MalGraphAlgorithm and LongestPath.
Browse files Browse the repository at this point in the history
  • Loading branch information
jecisc committed Oct 14, 2019
1 parent 3b845cf commit 59a35d9
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 51 deletions.
116 changes: 81 additions & 35 deletions src/Moose-Algos-Graph/MalGraphAlgorithm.class.st
@@ -1,5 +1,5 @@
"
I'm the common superclass for all Graphes related algorithms.
I'm the common superclass for all graphs related algorithms.
I store edges and nodes and provides convenience methods to add, access and find nodes or edges.
Once configured, send the run message to execute the algorithm.
Expand All @@ -9,37 +9,28 @@ Class {
#superclass : #Object,
#instVars : [
'nodes',
'edges'
'edges',
'nodeSortBlock'
],
#category : #'Moose-Algos-Graph'
}

{ #category : #private }
MalGraphAlgorithm >> addEdge: eModel from: source to: target [

| edge sourceNode targetNode unknownNode |
unknownNode := false.
sourceNode := self findNode: (source value: eModel)
ifAbsent: [ unknownNode := true ].
targetNode := self findNode: (target value: eModel)
ifAbsent: [ unknownNode := true ].

unknownNode ifFalse: [
self edgeClass ifNil: [
sourceNode to: targetNode.
MalGraphAlgorithm >> addEdge: eModel from: source to: target [
| edge sourceNode targetNode |
sourceNode := self findNode: (source value: eModel) ifAbsent: [ ^ nil ].
targetNode := self findNode: (target value: eModel) ifAbsent: [ ^ nil ].
self edgeClass
ifNil: [ sourceNode to: targetNode.
targetNode from: sourceNode.
^ nil
] ifNotNil: [
edge := self edgeClass with: eModel.
^ nil ]
ifNotNil: [ edge := self edgeClass with: eModel.
sourceNode to: targetNode edge: edge.
targetNode from: sourceNode edge: edge.
edge from: sourceNode.
edge to: targetNode.
self edges add: edge.
^ edge
]
].
^ nil
self edges add: edge.
^ edge ]
]

{ #category : #'building - graph' }
Expand All @@ -66,6 +57,15 @@ MalGraphAlgorithm >> addNodesFrom: model childrenBlock: childrenBlock [
self addEdge: { parent model . child } from: #first to: #second ]
]

{ #category : #testing }
MalGraphAlgorithm >> canUseSortedNodes [
"New implementation of the algos to have better performances to find nodes"

"If nodes are sorted following this block, the find method will be a lot faster. The block should be set on the run method and the nodes sorted at this moment"

^ nodeSortBlock isNotNil
]

{ #category : #configuration }
MalGraphAlgorithm >> edgeClass [
^ nil
Expand Down Expand Up @@ -93,38 +93,65 @@ MalGraphAlgorithm >> edges: aCollection from: source to: target weight: weightFu

{ #category : #'building - graph' }
MalGraphAlgorithm >> edges: aCollection from: source toAll: targets [
aCollection
do: [ :eModel |
(targets value: eModel)
do: [:target|
self
addEdge: {source value: eModel . target}
aCollection
do: [ :eModel |
(targets value: eModel)
do: [ :target |
self
addEdge:
{(source value: eModel).
target}
from: #first
to: #second ] ]
]

{ #category : #private }
MalGraphAlgorithm >> ensureNodesAreSorted [
"New implementation of the algos to have better performances to find nodes"
"If one change is made in the node list, one should call again sortNodes"

nodeSortBlock ifNotNil: [ ^ self ].
self nodeSortBlock: [ :a :b | a model hash <= b model hash ].
self sortNodes
]

{ #category : #private }
MalGraphAlgorithm >> findBinaryBlock: aModel [
"New implementation of the algos to have better performances to find nodes"
^ [ :aNode |
aNode model = aModel
ifTrue: [ 0 ]
ifFalse: [ aModel hash < aNode model hash
ifTrue: [ -1 ]
ifFalse: [ 1 ] ] ]
]

{ #category : #accessing }
MalGraphAlgorithm >> findEdge: aModel [
^ self edges detect: [:edge | edge model = aModel]
]

{ #category : #accessing }
MalGraphAlgorithm >> findNode: aModel [
^ self nodes detect: [:aNode | aNode model = aModel ]
self canUseSortedNodes
ifFalse: [ ^ self nodes detect: [ :aNode | aNode model = aModel ] ].
^ self nodes findBinary: (self findBinaryBlock: aModel)
]

{ #category : #accessing }
MalGraphAlgorithm >> findNode: aModel ifAbsent: aBlock [
^ self nodes
detect: [:node | node model = aModel]
ifNone: aBlock
self canUseSortedNodes
ifFalse: [ ^ self nodes detect: [ :node | node model = aModel ] ifNone: aBlock ].
^ self nodes
findBinary: (self findBinaryBlock: aModel) ifNone: aBlock
]

{ #category : #accessing }
MalGraphAlgorithm >> findNode: aModel ifFound: aBlock [
^ self nodes
detect: [:node | node model = aModel]
ifFound: aBlock
self canUseSortedNodes
ifFalse: [ ^ self nodes detect: [ :node | node model = aModel ] ifFound: aBlock ].
"New implementation of the algos to have better performances to find nodes"
self notYetImplemented
]

{ #category : #accessing }
Expand All @@ -143,6 +170,11 @@ MalGraphAlgorithm >> nodeClass [
^ MalGraphNode
]

{ #category : #accessing }
MalGraphAlgorithm >> nodeSortBlock: aBlockClosure [
nodeSortBlock := aBlockClosure
]

{ #category : #accessing }
MalGraphAlgorithm >> nodes [
^ nodes
Expand All @@ -154,6 +186,14 @@ MalGraphAlgorithm >> nodes: aNodeList [
do: [ :model | self addNodeFor: model ]
]

{ #category : #adding }
MalGraphAlgorithm >> nodesFromSet: aSet [
"Ensure that the collection do not contains any duplicated item"

self assert: aSet class == Set.
nodes addAll: (aSet collect: [ :aModel | self nodeClass with: aModel ])
]

{ #category : #private }
MalGraphAlgorithm >> privateEdges: aCollection [

Expand All @@ -171,3 +211,9 @@ MalGraphAlgorithm >> run [

self subclassResponsibility
]

{ #category : #private }
MalGraphAlgorithm >> sortNodes [
self canUseSortedNodes ifFalse: [ ^self ].
self nodes sort: nodeSortBlock.
]
30 changes: 14 additions & 16 deletions src/Moose-Algos-Graph/MalLongestPath.class.st
Expand Up @@ -10,7 +10,6 @@ Class {
#superclass : #MalGraphAlgorithm,
#instVars : [
'previousRanks',
'currentRank',
'rootNodes',
'leafNodes',
'maxIterations'
Expand All @@ -30,20 +29,17 @@ MalLongestPath >> computeRootNodes [

{ #category : #computing }
MalLongestPath >> computeStep [
| nodesToManage |
self isCompleted
ifFalse: [
currentRank := OrderedCollection new.
nodesToManage := self nodes reject: [ :node | previousRanks includes: node ].
nodesToManage
do: [ :node |
(previousRanks includesAll: node previousNodes)
ifTrue: [
currentRank add: node.
node pathWeight: (node previousNodes max: [ :maxNode | maxNode pathWeight ]) + 1 ] ].
previousRanks addAll: currentRank.
maxIterations := maxIterations -1.
self computeStep ]
| currentRank |
self isCompleted ifTrue: [ ^ self ].
currentRank := OrderedCollection new.
(self nodes difference: previousRanks)
select: [ :node | previousRanks includesAll: node previousNodes ]
thenDo: [ :node |
currentRank add: node.
node pathWeight: (node previousNodes max: [ :maxNode | maxNode pathWeight ]) + 1 ].
previousRanks addAll: currentRank.
maxIterations := maxIterations - 1.
self computeStep
]

{ #category : #configuration }
Expand All @@ -54,6 +50,7 @@ MalLongestPath >> edgeClass [
{ #category : #initialization }
MalLongestPath >> initialize [
super initialize.
maxIterations := -1.
previousRanks := OrderedCollection new
]

Expand All @@ -65,7 +62,7 @@ MalLongestPath >> initializeRootNodes [

{ #category : #testing }
MalLongestPath >> isCompleted [
maxIterations = 0
maxIterations isZero
ifTrue: [ self error: 'Algorithm should be finished by now...'.
^ true ].
^ (self leafNodes anySatisfy: [ :node | node pathWeight = Float infinity ]) not
Expand Down Expand Up @@ -101,6 +98,7 @@ MalLongestPath >> rootNodes: aCollectionOfNodes [

{ #category : #running }
MalLongestPath >> run [
self ensureNodesAreSorted.
self initializeRootNodes.
self computeLeafNodes.
previousRanks addAll: self rootNodes.
Expand Down

0 comments on commit 59a35d9

Please sign in to comment.