Finished Chapter 4

This commit is contained in:
WGAVermeer
2026-03-10 13:05:37 +01:00
parent 059f9724c4
commit 61da31dcdc
5 changed files with 364 additions and 0 deletions

96
chap_4/e4_1.dfy Normal file
View File

@@ -0,0 +1,96 @@
datatype BYTree = BlueLeaf | YellowLeaf | Node(left: BYTree, right: BYTree)
function ReverseColors(t: BYTree): BYTree {
match t
case BlueLeaf => YellowLeaf
case YellowLeaf => BlueLeaf
case Node(left, right) => BYTree.Node(ReverseColors(left), ReverseColors(right))
}
method TestReverseColors() {
var a := BYTree.Node(BlueLeaf, BYTree.Node(BlueLeaf, YellowLeaf));
var b := BYTree.Node(YellowLeaf, BYTree.Node(YellowLeaf, BlueLeaf));
assert ReverseColors(a) == b;
assert ReverseColors(b) == a;
var c := BYTree.Node(BYTree.Node(YellowLeaf, BlueLeaf), BlueLeaf);
var d := BYTree.Node(BYTree.Node(BlueLeaf, YellowLeaf), YellowLeaf);
assert ReverseColors(c) == d;
assert ReverseColors(d) == c;
var e := BlueLeaf;
assert ReverseColors(e) != e;
}
function Oceanize(t: BYTree): BYTree {
match t
case BlueLeaf | YellowLeaf => BlueLeaf
case Node(left, right) => BYTree.Node(Oceanize(left), Oceanize(right))
}
method testOceanize() {
var a := BYTree.Node(BlueLeaf, YellowLeaf);
var b := BYTree.Node(BlueLeaf, BlueLeaf);
assert Oceanize(a) == b;
}
function LeftDepth(t: BYTree): nat {
if t.BlueLeaf? || t.YellowLeaf? then 1
else 1 + LeftDepth(t.left)
}
predicate HasLeftTreeMatch(t: BYTree, u: BYTree) {
match t
case Node(left, right) => left == u // || HasLeftTree(left, u) || HasLeftTree(right, u)
case BlueLeaf => false
case YellowLeaf => false
}
predicate HasLeftTreeCon(t: BYTree, u: BYTree) {
if t.BlueLeaf? then false
else if t.YellowLeaf? then false
else t.left == u
}
predicate HLT(t: BYTree, u: BYTree) {
HasLeftTreeMatch(t, u) && HasLeftTreeCon(t, u)
}
method testHasLeftTree() {
var a := BYTree.Node(BlueLeaf, YellowLeaf);
var b := BlueLeaf;
var c := BYTree.Node(a, b);
assert HLT(a, b);
assert !HLT(b, a);
assert HLT(c, a);
assert !HLT(c, b);
}
datatype Color = Blue | Yellow | Green | Red
datatype ColoredTree = Leaf(Color) | Node(ColoredTree, ColoredTree)
predicate IsSwedishColoredTree(t: ColoredTree) {
match t {
case Leaf(Color) =>
match Color {
case Blue => true
case Yellow => true
case Green => false
case Red => false
}
case Node(left, right) => IsSwedishColoredTree(left) && IsSwedishColoredTree(right)
}
}
method testIsSwedischColoredTree() {
var a := ColoredTree.Node(Leaf(Blue), Leaf(Green));
assert !IsSwedishColoredTree(a);
var b := ColoredTree.Node(Leaf(Blue), Leaf(Yellow));
assert IsSwedishColoredTree(b);
}

9
chap_4/e4_5.dfy Normal file
View File

@@ -0,0 +1,9 @@
datatype Tree<T> = Leaf(data: T)
| Node(left: Tree<T>, right: Tree<T>)
function Mirror<T>(t: Tree<T>): Tree<T> {
match t
case Leaf(_) => t
case Node(left, right) => Node(Mirror(right), Mirror(left))
}

137
chap_4/e4_6.dfy Normal file
View File

@@ -0,0 +1,137 @@
datatype Expr = Const(nat) | Var(string) | Node(op: Op, args: List<Expr>)
datatype Op = Add | Mul
datatype List<T> = Nil | Cons(head: T, tail: List<T>)
function Eval(e: Expr, env: map<string, nat>): nat
requires GoodEnv(e, env)
{
match e
case Const(c) => c
case Var(s) => env[s]
case Node(op, args) => EvalList(op, args, env)
}
/* E.4.9 => The default decreases clause use lexicographical ordering of the arguments.
This implies the following decreases clause:
decreases op, args, env
But as "op" is either Add or Mul which and does not have fixed order in a list<Expr>
it jumps around.
for example 10 * 5 + 3 * 10.
=> Node(Mul, Cons(Const(10), Cons()))
*/
function EvalList(op: Op, args: List<Expr>,
env: map<string, nat>): nat
decreases args
requires GoodEnvList(args, env)
{
match args
case Nil =>
(match op case Add => 0 case Mul => 1)
case Cons(e, tail) =>
var v0, v1 := Eval(e, env), EvalList(op, tail, env);
match op
case Add => v0 + v1
case Mul => v0 * v1
}
predicate GoodEnv(e: Expr, env: map<string, nat>) {
match e
case Const(_) => true
case Var(s) => s in env.Keys
case Node(_, args) => GoodEnvList(args, env)
}
predicate GoodEnvList(args: List<Expr>, env: map<string, nat>)
{
match args
case Nil => true
case Cons(e, tail) => GoodEnv(e, env) && GoodEnvList(tail, env)
}
ghost method TestGoodEnvExtensive() {
// ---------- Simple constants ----------
var c1 := Const(5);
assert GoodEnv(c1, map[]);
// ---------- Single variable ----------
var v1 := Var("x");
var env1 := map["x" := 10];
assert GoodEnv(v1, env1);
var env2 := map["y" := 10];
assert !GoodEnv(v1, env2);
// ---------- Simple Node ----------
var e1 := Node(Add, Cons(Const(2), Cons(Const(3), Nil)));
assert GoodEnv(e1, map[]);
// ---------- Node with variable ----------
var e2 := Node(Add, Cons(Var("x"), Cons(Const(4), Nil)));
var env3 := map["x" := 7];
assert GoodEnv(e2, env3);
var env4 := map["y" := 7];
assert !GoodEnv(e2, env4);
// ---------- Multiple variables ----------
var e3 :=
Node(Mul,
Cons(Var("x"),
Cons(Var("y"),
Cons(Const(5), Nil))));
var env5 := map["x" := 1, "y" := 2];
assert GoodEnv(e3, env5);
var env6 := map["x" := 1];
assert !GoodEnv(e3, env6);
// ---------- Nested nodes ----------
var nested :=
Node(Add,
Cons(
Node(Mul,
Cons(Var("x"),
Cons(Const(3), Nil))),
Cons(
Node(Add,
Cons(Const(1),
Cons(Var("y"), Nil))),
Nil)));
var env7 := map["x" := 2, "y" := 4];
assert GoodEnv(nested, env7);
var env8 := map["x" := 2];
assert !GoodEnv(nested, env8);
// ---------- Deep tree ----------
var deep :=
Node(Add,
Cons(
Node(Add,
Cons(
Node(Mul,
Cons(Var("a"),
Cons(Const(2), Nil))),
Cons(Const(3), Nil))),
Cons(
Node(Mul,
Cons(Const(4),
Cons(Var("b"), Nil))),
Nil)));
var env9 := map["a" := 1, "b" := 5];
assert GoodEnv(deep, env9);
var env10 := map["a" := 1];
assert !GoodEnv(deep, env10);
}