context Node { | |
constraint NotInCycle { | |
check : not self.allIncoming().includes(self) | |
message : "Node " + self.label + | |
" is part of a directed cycle" | |
} | |
} | |
context Edge { | |
constraint MustDefineSource { | |
check : self.source.isDefined() | |
message : "Edge does not have a source node" | |
} | |
constraint MustDefineTarget { | |
check : self.target.isDefined() | |
message : "Edge does not have a target node" | |
} | |
constraint PositiveWeight { | |
guard : self.satisfies("MustDefineSource") and | |
self.satisfies("MustDefineTarget") | |
check : self.weight >= 0 | |
message : "Edge " + self.source.label + "->" + | |
self.target.label + " has a negative weight" | |
} | |
} | |
operation Node allIncoming() : Set { | |
return self.allIncoming(Set{}); | |
} | |
operation Node allIncoming(visited : Set) : Set { | |
for (n in self.incoming.collect(e|e.source)) { | |
if (not visited.includes(n)) { | |
visited.add(n); | |
visited.addAll(n.allIncoming(visited)); | |
} | |
} | |
return visited; | |
} |