-
Notifications
You must be signed in to change notification settings - Fork 1
/
GraphNode.class.st
155 lines (133 loc) · 3.73 KB
/
GraphNode.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"
Abstract class for nodes that are held in a graph.
Each node holds on to a corresponding object that is the value of that node.
Subclasses add state/behaviour to represent edges in the graph.
"
Class {
#name : #GraphNode,
#superclass : #Object,
#instVars : [
'value'
],
#category : #'Mathematics-Graphs-Parts'
}
{ #category : #comparing }
GraphNode >> = anObject [
"Comparison is delegated to the value of the node.
Argument and receiver are reversed to dereference through other GraphNodes."
^anObject = value
]
{ #category : #statistics }
GraphNode >> clusteringCoefficient [
| links k |
links := Set new.
self neighborsDo: [:n1 |
self neighborsDo: [:n2 |
(n1 ~= n2 and: [n1 hasEdgeTo: n2])
ifTrue: [links add: {n1 value. n2 value}]]].
k := self neighbors size.
^ links size / (k * (k - 1))
]
{ #category : #'accessing edges' }
GraphNode >> degree [
"How many edges does this node have?"
self subclassResponsibility
]
{ #category : #'testing edges' }
GraphNode >> hasEdgeTo: anObject [
"Is there an edge from this node to anObject?"
self subclassResponsibility
]
{ #category : #'testing edges' }
GraphNode >> hasLoop [
^ self hasEdgeTo: self
]
{ #category : #comparing }
GraphNode >> hash [
^value hash
]
{ #category : #'testing edges' }
GraphNode >> isLeaf [
^self degree = 0
]
{ #category : #'testing edges' }
GraphNode >> isReflexive [
^ self hasEdgeTo: self
]
{ #category : #'testing edges' }
GraphNode >> isSimple [
^ self neighbors asSet size = self neighbors size and: [self hasLoop not]
]
{ #category : #'testing edges' }
GraphNode >> isSymmetric [
self neighborsDo: [:each| (each hasEdgeTo: self) ifFalse: [^ false]].
^ true
]
{ #category : #'testing edges' }
GraphNode >> isTransitive [
self neighborsDo: [:each|
each neighborsDo: [:other| (other hasEdgeTo: self) ifFalse: [^ false]]].
^ true
]
{ #category : #enumerating }
GraphNode >> markDo: aBlock [
"Visit each node in the graph once, applying aBlock.
A node is only visited after at least one of its predecessors, but not necessarily after all the predecessors."
| todo visited |
todo := Set with: self.
visited := Set new.
[todo isEmpty] whileFalse:
[| node |
node := todo anyOne.
visited add: node.
aBlock value: node.
node neighborsDo:
[ :child |
(visited includes: child)
ifFalse: [todo add: child]].
todo remove: node]
]
{ #category : #'accessing edges' }
GraphNode >> neighbors [
"Return a collection of nodes connected to outgoing edges."
self subclassResponsibility
]
{ #category : #'accessing edges' }
GraphNode >> neighborsAndLabelsDo: aBlock [
"Evaluate aBlock for each node connected to an outgoing edge, and the label on that edge (nil if no label)."
"The default definition assumes no labels are present."
self neighborsDo: [ :n | aBlock value: n value: nil]
]
{ #category : #'accessing edges' }
GraphNode >> neighborsDo: aBlock [
"Evaluate aBlock for each node connected to an outgoing edge."
self subclassResponsibility
]
{ #category : #printing }
GraphNode >> printOn: aStream [
aStream nextPut: $[; print: value; nextPut: $]
]
{ #category : #operations }
GraphNode >> span [
"Answer the spanning tree of the receiver."
| tree |
tree := RootedDigraph ordered.
tree roots: (Set with: self).
self markDo: [:each| tree add: each].
^ tree
]
{ #category : #'accessing value' }
GraphNode >> value [
^value
]
{ #category : #'accessing value' }
GraphNode >> value: anObject [
value := anObject
]
{ #category : #enumerating }
GraphNode >> walkPre: preBlock post: postBlock [
"Recursively walk the subtree rooted at me. Apply preBlock to each node, then walk the subtree below node, then apply postBlock to the node."
preBlock value: self.
self neighborsDo: [ :child | child walkPre: preBlock post: postBlock].
postBlock value: self
]