I have a simple Graph, whose node have an integral Depth attribute. I need to be assured that the difference in depth between any two adjacent nodes on the graph is 0 or 1. I first wrote my own abs[] function, and then a checkDepth predicate. I don't understand why it doesn't work and I'm sure there's a better way to do this!
pred checkDepth[r: Node -> Node] {
let d1 = dom[r].depth, d2 =ran[r].depth |
abs[d1 - d2] <= 1
}
fun abs[i:Int] : Int {
i >= 0 =>
i
else
0 - i
}
abstract sig Node {
depth: Int
}
{
depth >= 0
}
sig Graph {
nodes: set Node,
edge: set Node -> Node
}
{
noSelfLoops[edge]
forest[edge]
//check all pairs of edges here for abs(depth) = 1
checkDepth[edge]
Let me refine my previous comment.
I'm appending two files here, graph_edge and graph_noedge, I prefixed and suffixed them with and . graph_edge, does what I intended. That is, the difference in "depth" between any two nodes in the graph is always <= 1. graph_noedge only assures that the difference between ONE set of adjacent nodes is <= 1. I don't understand why. It seems that logically by adding the Edge class in graph_edge I added no new information or rules to the system. The implementation in graph_edge is much cleaner, and to me, expresses better the logic of what I want.
open util/graph[Node]
abstract sig Node {
depth: Int
}
{
depth >= 0
}
sig Task extends Node {}
{
all t:Task { t not in leaves[Graph.edge]}
all t:Task { t not in roots[Graph.edge]}
depth > 0
}
sig Input extends Node {}
{
Input in roots[Graph.edge]
depth = 0
}
sig Output extends Node {}
{
Output in leaves[Graph.edge]
all o:Output { o not in roots[Graph.edge] }
depth >= 0
}
sig Graph {
edge: set Node->Node
}
{
noSelfLoops[edge]
forest[edge]
//satisfies only one edge
abs[int[dom[edge].depth] - int[ran[edge].depth]] = 1
I'm appending two files here, graph_edge and graph_noedge, I prefixed and suffixed them with and . graph_edge, does what I intended. That is, the difference in "depth" between any two nodes in the graph is always <= 1. graph_noedge only assures that the difference between ONE set of adjacent nodes is <= 1. I don't understand why. It seems that logically by adding the Edge class in graph_edge I added no new information or rules to the system. The implementation in graph_edge is much cleaner, and to me, expresses better the logic of what I want.
open util/graph[Node]
abstract sig Node {
depth: Int
}
{
depth >= 0
}
sig Task extends Node {}
{
all t:Task { t not in leaves[Graph.edge]}
all t:Task { t not in roots[Graph.edge]}
depth > 0
}
sig Input extends Node {}
{
Input in roots[Graph.edge]
depth = 0
}
sig Output extends Node {}
{
Output in leaves[Graph.edge]
all o:Output { o not in roots[Graph.edge] }
depth >= 0
}
sig Graph {
edge: set Node->Node
}
{
noSelfLoops[edge]
forest[edge]
//satisfies only one edge
abs[int[dom[edge].depth] - int[ran[edge].depth]] = 1
}
fun abs[i:Int] : Int {
i >= 0 =>
i
else
0 - i
}
check checkAbs {
all i:Int | abs[i] + abs[0 - i] = abs[i] + abs[i]
abs[0] = 0
}
pred example {
#Input >= 1
#Output >= 1
#Task >= 2
}
run example for 1 Graph, 4 Node
open util/graph[Node]
abstract sig Node {
depth: Int
}
{
depth >= 0
}
sig Task extends Node {}
{
all t:Task { t not in leaves[Graph.edge.rel]}
all t:Task { t not in roots[Graph.edge.rel]}
depth > 0
}
sig Input extends Node {}
{
Input in roots[Graph.edge.rel]
depth = 0
}
sig Output extends Node {}
{
Output in leaves[Graph.edge.rel]
all o:Output { o not in roots[Graph.edge.rel] }
depth >= 0
}
sig Edge {
from: Node,
to: Node,
rel: from -> to
}
{
from != to
}
sig Graph {
edge: set Edge
}
{
noSelfLoops[edge.rel]
forest[edge.rel]
all e:edge {
abs[int[e.from.depth] - int[e.to.depth]] <= 1
}
}
fun abs[i:Int] : Int {
i >= 0 =>
i
else
0 - i
}
check checkAbs {
all i:Int | abs[i] + abs[0 - i] = abs[i] + abs[i]
abs[0] = 0
}
pred example {
#Input >= 1
#Output >= 1
#Task >= 2
}
run example for 1 Graph, 4 Node, 3 Edge