|
| 1 | +""" |
| 2 | +Kleene Algebra |
| 3 | +
|
| 4 | +
|
| 5 | +- https://www.philipzucker.com/bryzzowski_kat/ |
| 6 | +- https://www.cs.uoregon.edu/research/summerschool/summer24/topics.php#Silva |
| 7 | +
|
| 8 | +""" |
| 9 | + |
| 10 | +import kdrag as kd |
| 11 | +import kdrag.smt as smt |
| 12 | + |
| 13 | +K = smt.DeclareSort("Kleene") |
| 14 | +zero = smt.Const("_0", K) |
| 15 | +one = smt.Const("_1", K) |
| 16 | +x, y, z, w, e, f = smt.Consts("x y z w e f", K) |
| 17 | +par = smt.Function("par", K, K, K) |
| 18 | +seq = smt.Function("seq", K, K, K) |
| 19 | +star = smt.Function("star", K, K) |
| 20 | +kd.notation.or_.register(K, par) |
| 21 | +kd.notation.add.register(K, par) |
| 22 | +kd.notation.matmul.register(K, seq) |
| 23 | +kd.notation.mul.register(K, seq) |
| 24 | +kd.notation.le.register(K, lambda x, y: smt.Eq(par(x, y), y)) |
| 25 | + |
| 26 | + |
| 27 | +par_assoc = kd.axiom(smt.ForAll([x, y, z], x + (y + z) == (x + y) + z)) |
| 28 | +par_comm = kd.axiom(smt.ForAll([x, y], x + y == y + x)) |
| 29 | +par_idem = kd.axiom(smt.ForAll([x], x + x == x)) |
| 30 | +par_zero = kd.axiom(smt.ForAll([x], x + zero == x)) |
| 31 | + |
| 32 | +zero_par = kd.prove(smt.ForAll([x], zero + x == x), by=[par_comm, par_zero]) |
| 33 | + |
| 34 | +seq_assoc = kd.axiom(smt.ForAll([x, y, z], x * (y * z) == (x * y) * z)) |
| 35 | +seq_zero = kd.axiom(smt.ForAll([x], x * zero == zero)) |
| 36 | +seq_one = kd.axiom(smt.ForAll([x], x * one == x)) |
| 37 | + |
| 38 | +rdistrib = kd.axiom(smt.ForAll([x, y, z], x * (y + z) == x * y + x * z)) |
| 39 | +ldistrib = kd.axiom(smt.ForAll([x, y, z], (y + z) * x == y * x + z * x)) |
| 40 | + |
| 41 | +unfold = kd.axiom(smt.ForAll([e], star(e) == one + e * star(e))) |
| 42 | + |
| 43 | +# If a set shrinks, star(e) is less than it |
| 44 | + |
| 45 | +least_fix = kd.axiom(smt.ForAll([x, e, f], f + e * x <= x, star(e) * f <= x)) |
| 46 | + |
| 47 | +KLEENE = [ |
| 48 | + par_assoc, |
| 49 | + par_comm, |
| 50 | + par_idem, |
| 51 | + par_zero, |
| 52 | + seq_assoc, |
| 53 | + seq_zero, |
| 54 | + seq_one, |
| 55 | + rdistrib, |
| 56 | + ldistrib, |
| 57 | + unfold, |
| 58 | + least_fix, |
| 59 | +] |
| 60 | +par_monotone = kd.prove( |
| 61 | + smt.ForAll([x, y, z, w], x <= y, z <= w, x + z <= y + w), |
| 62 | + by=[par_assoc, par_comm], |
| 63 | +) |
| 64 | + |
| 65 | +seq_monotone = kd.prove( |
| 66 | + smt.ForAll([x, y, z, w], x <= y, z <= w, x * z <= y * w), |
| 67 | + by=[rdistrib, ldistrib, par_assoc], |
| 68 | +) |
| 69 | + |
| 70 | +star_seq_star = kd.tactics.vprove( |
| 71 | + smt.ForAll([x], star(x) * star(x) == star(x)), by=KLEENE |
| 72 | +) |
| 73 | +# z3 takes 0.5 seconds. Vampire is actually faster despite all the overhead |
| 74 | +star_star = kd.tactics.vprove(smt.ForAll([x], star(star(x)) == star(x)), by=KLEENE) |
| 75 | + |
| 76 | +Test = smt.DeclareSort("Test") |
| 77 | +guard = smt.Function("guard", Test, K, K) |
| 78 | +and_ = smt.Function("and", Test, Test, Test) |
| 79 | +or_ = smt.Function("or", Test, Test, Test) |
| 80 | +not_ = smt.Function("not", Test, Test) |
| 81 | +true = smt.Const("true", Test) |
| 82 | +false = smt.Const("false", Test) |
| 83 | +kd.notation.invert.register(Test, not_) |
| 84 | + |
| 85 | +a, b, c, d = smt.Consts("a b c d", Test) |
| 86 | + |
| 87 | + |
| 88 | +def while_(t, c): |
| 89 | + return star(guard(t, c)) * guard(~t, one) |
0 commit comments