open util/ternary
open util/ordering[Atom] as A
sig Atom {edges: Int -> Atom}
one sig A,B,C,D,E,F,G,H,I,J
extends Atom {}
-- For efficiency: define ordering on nodes to make div unnecessary
fun weight[g: Atom -> Int -> Atom]: Int {
-- Assume: no self-loops
-- Note .*A/next will overflow at 6 int
sum a: Atom | sum b: a.^A/next | a.g.b
}
-- For efficiency: FIX A WEIGHTED GRAPH
-- For efficiency: Turn on "infer partial instance" + define plainly
fact fixed {
edges =
A->4->D + D->5->I + A->6->B + B->4->C + A->3->C +
B->3->E + C->5->D + C->2->E + E->6->F + E->5->G +
D->2->H + D->3->F + F->4->G + F->2->H + H->2->I +
G->3->J + H->5->J + I->4->J +
D->4->A + I->5->D + B->6->A + C->4->B + C->3->A +
E->3->B + D->5->C + E->2->C + F->6->E + G->5->E +
H->2->D + F->3->D + G->4->F + H->2->F + I->2->H +
J->3->G + J->5->H + J->4->I
}
pred isUndirectedTree[r: Atom -> Atom] {
-- FILL
}
pred spans[graph1, graph2: Atom -> Atom] {
-- FILL
}
pred spanningTree[tree, graph2: Atom -> Atom] {
spans[tree, graph2]
isUndirectedTree[tree]
}
run spanningTree for exactly 5 Atom, 8 int
pred properWeights[g: Atom -> Int -> Atom] {
-- one weight per edge and weights within [1, 10]
all a1, a2: Atom | lone i: Int | a1->i->a2 in g
all i : Atom.g.Atom | i > 0 and i < 11
-- symmetric weights
all a1, a2: Atom | a1.g.a2 = a2.g.a1
}
pred minSpanningTree[tree, wgraph: Atom -> Int -> Atom] {
spanningTree[select13[tree], select13[wgraph]]
properWeights[wgraph]
-- need to specify this because spans version won't look at weights
tree in wgraph
all tree2: Atom -> Int -> Atom | {
(spanningTree[select13[tree2], select13[wgraph]] and
tree2 in wgraph) implies
weight[tree2] >= weight[tree]
}
}
run minSpanningTree for exactly 4 Atom, 8 int
run bigger {
some tree: Atom -> Int -> Atom | {
minSpanningTree[tree, edges]
}
} for exactly 10 Atom, 6 int