-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathAbstractVertex.scala
168 lines (146 loc) · 5.29 KB
/
AbstractVertex.scala
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
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
* @author Philip Stutz
*
* Copyright 2010 University of Zurich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.signalcollect
import akka.event.LoggingAdapter
import akka.event.Logging
abstract class AbstractVertex[Id, State] extends Vertex[Id, State, Any, Any] {
/**
* hashCode is cached for better performance
*/
override lazy val hashCode = id.hashCode // Lazy to prevent premature initialization when using Java API.
def afterInitialization(graphEditor: GraphEditor[Any, Any]) = {}
/**
* Access to the outgoing edges is required for some calculations and for executing the signal operations.
* It is a map so we can support fast edge removals.
*
* Currently a Java HashMap is used as the implementation, but we will replace it with a more specialized
* implementation in a future release.
*/
var outgoingEdges = Map.empty[Any, Edge[Any]]
/** The edges that this vertex is connected to. */
def edges: Traversable[Edge[Any]] = outgoingEdges.values
/** The state of this vertex when it last signaled. */
var lastSignalState: Option[State] = None
/** Keeps track if edges get modified so we know we should signal again */
var edgesModifiedSinceSignalOperation = false
/** Keeps track if edges get modified so we know we should collect again */
var edgesModifiedSinceCollectOperation = false
/**
* Adds a new outgoing `Edge`
*
* @param e the edge to be added.
*/
def addEdge(edge: Edge[Any], graphEditor: GraphEditor[Any, Any]): Boolean = {
outgoingEdges.get(edge.targetId) match {
case None =>
edgesModifiedSinceSignalOperation = true
edgesModifiedSinceCollectOperation = true
outgoingEdges += ((edge.targetId, edge))
edge.onAttach(this, graphEditor)
true
case Some(edge) =>
false
}
}
/**
* Removes an outgoing {@link Edge} from this {@link Vertex}.
* @param e the edge to be added.
*/
def removeEdge(targetId: Any, graphEditor: GraphEditor[Any, Any]): Boolean = {
val outgoingEdge = outgoingEdges.get(targetId)
outgoingEdge match {
case None =>
false
case Some(edge) =>
edgesModifiedSinceSignalOperation = true
edgesModifiedSinceCollectOperation = true
outgoingEdges -= targetId
true
}
}
/**
* Removes all outgoing {@link Edge}s from this {@link Vertex}.
* @return returns the number of {@link Edge}s that were removed.
*/
def removeAllEdges(graphEditor: GraphEditor[Any, Any]): Int = {
val edgesRemoved = outgoingEdges.size
for (outgoingEdge <- outgoingEdges.keys.toSeq) { // Convert to sequence to avoid concurrent modification exception in Java map.
removeEdge(outgoingEdge, graphEditor)
}
edgesRemoved
}
/**
* This method tells this Vertex to execute the signal operation
* on all its outgoing edges. This method is going to be
* called by the Signal/Collect framework during its execution (i.e. the
* Worker implementation.
*
* @see Worker
* @see Edge#executeSignalOperation
*/
def executeSignalOperation(graphEditor: GraphEditor[Any, Any]) {
edgesModifiedSinceSignalOperation = false
lastSignalState = Some(state)
doSignal(graphEditor)
}
def doSignal(graphEditor: GraphEditor[Any, Any]) {
outgoingEdges.values.foreach(_.executeSignalOperation(this, graphEditor))
}
/**
* Function that gets called by the framework whenever this vertex is supposed to collect new signals.
*
* @param graphEditor an instance of GraphEditor which can be used by this vertex to interact with the graph.
*/
def executeCollectOperation(graphEditor: GraphEditor[Any, Any]) {
edgesModifiedSinceCollectOperation = false
}
/**
* This method is used by the framework in order to decide if the vertex' signal operation should be executed.
* The higher the returned value the more likely the vertex will be scheduled for executing its signal method.
* @return the score value.
*/
def scoreSignal: Double = {
if (edgesModifiedSinceSignalOperation) {
1
} else {
lastSignalState match {
case Some(oldState) if oldState == state => 0
case noStateOrStateChanged => 1
}
}
}
/** Returns the number of outgoing edges of this [com.signalcollect.interfaces.Vertex] */
def edgeCount = outgoingEdges.size
/**
* Returns "VertexClassName(id=ID, state=STATE)"
*/
override def toString: String = {
this.getClass.getSimpleName + "(id=" + id + ", state=" + state + ")"
}
/**
* This method gets called by the framework before the vertex gets removed.
*/
def beforeRemoval(graphEditor: GraphEditor[Any, Any]) = {}
/**
* Returns the ids of the target vertices of outgoing edges of the vertex.
*/
def targetIds: Iterable[Any] = {
outgoingEdges.keys
}
}