%{ The big algebraic software is a [[tactical theorem proving|tactical theorem prover]] written as a Twelf [[logic program]] by [[User:Rsimmons|Rob]] at Princeton University as part of the Foundational Proof Carrying Code system. }% %{ == Preexisting logic == }% %{ In the Princeton FPCC project where this was developed, many of the definitions below were more general (for instance, equality was on anything, not just numbers) and many things stated here as axioms were lemmas that had corresponding proofs. These are just the definitions and lemmas that were used within the solver. }% tnum : type. tform : type. pf : tform -> type. imp : tform -> tform -> tform. %infix right 10 imp. and : tform -> tform -> tform. %infix right 12 and. == : tnum -> tnum -> tform. %infix none 18 ==. >= : tnum -> tnum -> tform. %infix none 18 >=. < : tnum -> tnum -> tform. %infix none 18 <. != : tnum -> tnum -> tform. %infix none 18 !=. > : tnum -> tnum -> tform = [x][y] y < x. %infix none 18 >. <= : tnum -> tnum -> tform = [x][y] y >= x. %infix none 18 <=. imp_i : (pf A -> pf B) -> pf (A imp B). imp_e : pf (A imp B) -> pf A -> pf B. and_i : pf A -> pf B -> pf (A and B). and_e1 : pf (A and B) -> pf A. and_e2 : pf (A and B) -> pf B. cut : pf A -> (pf A -> pf B) -> pf B. cut2 : pf A -> pf A' -> (pf A -> pf A' -> pf B) -> pf B. cut3 : pf A -> pf A' -> pf A'' -> (pf A -> pf A' -> pf A'' -> pf B) -> pf B. congr : {h: tnum -> tform} pf (A == B) -> pf (h B) -> pf (h A). gt->geq : pf (A > B) -> pf (A >= B). gt->neq : pf (A > B) -> pf (A != B). lt->neq : pf (A < B) -> pf (A != B). eq->geq : pf (A == B) -> pf (A >= B). eq->leq : pf (A == B) -> pf (A <= B). not_eie : pf (A != B) -> (pf (C == D) -> pf (A == B)) -> pf (C != D). not_ein : pf (A < B) -> (pf (C >= D) -> pf (A >= B)) -> pf (C < D). zero : tnum. one : tnum. one>zero : pf (one > zero). + : tnum -> tnum -> tnum. %infix left 22 +. * : tnum -> tnum -> tnum. %infix left 23 *. neg : tnum -> tnum. - = [a][b] a + neg b. %infix left 22 -. succ = [x] x + one. pred = [x] x - one. two = succ one. refl : pf (A == A). symm : pf (A == B) -> pf (B == A). trans : pf (A == B) -> pf (B == C) -> pf (A == C). trans3 : pf (A == B) -> pf (B == C) -> pf (C == D) -> pf (A == D). trans4 : pf (A == B) -> pf (B == C) -> pf (C == D) -> pf (D == E) -> pf (A == E). trans5 : pf (A == B) -> pf (B == C) -> pf (C == D) -> pf (D == E) -> pf (E == F) -> pf (A == F). trans_geq_eq : pf (A >= B) -> pf (B == C) -> pf (A >= C). trans_eq_geq : pf (A == B) -> pf (B >= C) -> pf (A >= C). comm_plus : pf (A + B == B + A). plus_zero : pf (A + zero == A). zero_plus : pf (zero + A == A). plus_cong : pf (A == B) -> pf (C == D) -> pf (A + C == B + D). plus_cong2 : pf (A == B) -> pf (C + A == C + B) = [p1] plus_cong refl p1. plus_cong1 : pf (A == B) -> pf (A + C == B + C) = [p1] plus_cong p1 refl. plus_assoc : pf (A + B + C == A + (B + C)). assoc_plus : pf (A + (B + C) == A + B + C) = symm plus_assoc. neg_plus : pf (neg A + neg B == neg (A + B)). plus_inv : pf (A - A == zero). inv_plus : pf (neg A + A == zero) = trans comm_plus plus_inv. geq_plus_cong1 : pf (A >= B) -> pf (A + C >= B + C). comm_times : pf (A * B == B * A). times_assoc : pf (A * B * C == A * (B * C)). assoc_times : pf (A * (B * C) == A * B * C) = symm times_assoc. times_assoc : pf (A * B * C == A * (B * C)). times_cong : pf (A == B) -> pf (C == D) -> pf (A * C == B * D). times_cong2 : pf (A == B) -> pf (C * A == C * B) = [p1] times_cong refl p1. times_cong1 : pf (A == B) -> pf (A * C == B * C) = [p1] times_cong p1 refl. neg_times1 : pf (neg A * B == neg (A * B)). neg_times2 : pf (A * neg B == neg (A * B)). neg_times : pf (neg A * neg B == A * B). times_one : pf (A * one == A). one_times : pf (one * A == A) = trans comm_times times_one. times_zero : pf (A * zero == zero). times_elim2 : pf (A != zero) -> pf (B * A == C * A) -> pf (B == C). geq_times_cong1 : pf (A >= zero) -> pf (B >= C) -> pf (B * A >= C * A). geq_times_elim1 : pf (A > zero) -> pf (A * B >= A * C) -> pf (B >= C). geq_times_elim2 : pf (A > zero) -> pf (B * A >= C * A) -> pf (B >= C). geq_times_cong1_neg : pf (A <= zero) -> pf (B >= C) -> pf (B * A <= C * A). geq_times_elim2_neg : pf (A < zero) -> pf (B * A >= C * A) -> pf (B <= C). neg_cong : pf (A == B) -> pf (neg A == neg B). neg_elim : pf (neg A == neg B) -> pf (A == B). neg_neg_e : pf (neg (neg A) == A). neg_zero : pf (neg zero == zero). distrib : pf (A * (B + C) == A * B + A * C). distrib_right : pf ((A + B) * C == A * C + B * C). cancel_a+b-b : pf (A + B - B == A) = symm (trans3 (symm plus_zero) (plus_cong2 (symm plus_inv)) assoc_plus). cancel_a+b-b' : pf (A + (B - B) == A) = trans assoc_plus cancel_a+b-b. cancel_a-b+b : pf (A - B + B == A) = symm (trans4 (symm cancel_a+b-b) plus_assoc (plus_cong2 comm_plus) assoc_plus). cancel_a-b+b' : pf (A + (neg B + B) == A) = trans assoc_plus cancel_a-b+b. cancel_a+b-a : pf (A + B - A == B) = symm (trans3 (symm cancel_a-b+b) comm_plus assoc_plus). cancel_a+b-a' : pf (A + (B - A) == B) = trans assoc_plus cancel_a+b-a. cancel_a-a+b : pf (A - A + B == B) = trans3 comm_plus assoc_plus cancel_a+b-b. cancel_a-a+b' : pf (A + (neg A + B) == B) = trans assoc_plus cancel_a-a+b. cancel_-a+a+b : pf (neg A + A + B == B) = trans (plus_cong1 comm_plus) cancel_a-a+b. cancel_-a+a+b' : pf (neg A + (A + B) == B) = trans assoc_plus cancel_-a+a+b. cancel_-a+b+a : pf (neg A + B + A == B) = trans4 plus_assoc (plus_cong2 comm_plus) assoc_plus cancel_-a+a+b. cancel_-a+b+a' : pf (neg A + (B + A) == B) = trans assoc_plus cancel_-a+b+a. %{ == Parts of the solver == }% nomatch = zero. match = one. listify : tnum -> tnum -> tnum -> type = [a][pos][neg] pf (a == pos - neg). %deterministic listify. %mode listify +A -Pos -Neg. %{ === Normalization === }% plusify : tnum -> tnum -> tnum -> type = [a][x][y] pf (a == x - y). %deterministic plusify. %mode plusify +A -X -Y. timesify : tnum -> tnum -> tnum -> tnum -> type = [b][x][y][sign] pf (b * sign == x * y). %deterministic timesify. %mode timesify +B -X -Y -Sign. catchtimes : tnum -> tnum -> tnum -> tnum -> tnum -> tnum -> tnum -> type = [a][b][x][y][sign][pos][neg] pf (b * sign == x * y imp a + b == pos - neg). %deterministic catchtimes. %mode catchtimes +A +B +X +Y +Sign -Pos -Neg. %{ === Matching === }% trim : tnum -> tnum -> tnum -> tnum -> type = [a][b][c][d] pf (a - b == c - d). %deterministic trim. %mode trim +A +B -X -Y. findarr_mult : tnum -> tnum -> tnum -> tnum -> type = [a][b][c][m] pf (a == b * c and m == m). %deterministic findarr_mult. %mode findarr_mult +A -B -Z +M. rearrange : tnum -> tnum -> tnum -> tnum -> type = [a][b][c][d] pf (a - b == c - d). %deterministic rearrange. %mode rearrange +A +B +C +D. %{ === Main solver interface === }% algebra_solver : tform -> type = [a] pf a. %deterministic algebra_solver. algebra_fact : tform -> type = [a] pf a. %mode algebra_fact -Fact. atom_replace : tnum -> tnum -> type = [a][b] pf (a == b). %mode atom_replace -A -B. algebra_times_hint_intern : tnum -> tnum -> type = [a][b] pf (a + b == a + b). %mode algebra_times_hint_intern -Predicate -Conclusion. algebra_times_hint : tnum -> type = [a] pf (a == a). %mode algebra_times_hint -Hint. %{ == Implementation == }% %{ === Normalization === }% %{ ==== Listify ==== }% %{ Decomposes equations into list form 0 + (1 * A * B * C) + D - E + (1 * F * G) +... }% %clause listify_imp : listify A Pos Neg <- plusify (zero + A) Pos Neg = [p1: pf (zero + A == Pos - Neg)] trans3 (symm plus_zero) comm_plus p1. %{ ==== Timesify ==== }% %{ timesify B X S Z - Creates a one-terminated list (1 * A * B * C * ...) * B - the input * X - the output list * Y - signals a special condition ** zero if a zero is encountered and the term is equal to zero ** (P + Q) if a sum is encountered and the product needs to be distributed ** one if the list is successfully processed * Sign - takes on all change-of-sign information }% %clause timesify_neg : timesify (B * (neg C)) X Y (neg Sign) <- timesify (B * C) X Y Sign = [p1 : pf (B * C * Sign == X * Y)] trans4 times_assoc (times_cong2 neg_times) (symm times_assoc) p1. %clause timesify_swap : timesify (B * (C * D)) X Y Sign <- timesify (B * C * D) X Y Sign = [p1] (trans (times_cong1 (symm times_assoc)) p1). %clause timesify_zero : timesify (B * zero) one zero one = trans3 times_one times_zero (symm times_zero). %clause timesify_remove : timesify (B * one) X Y Sign <- timesify B X Y Sign = [p1: pf (B * Sign == X * Y)] cut (trans3 times_assoc (times_cong2 comm_times) assoc_times) [p2: pf (B * one * Sign == B * Sign * one)] trans3 p2 times_one p1. %clause timesify_end_plus : timesify (B * (P + Q)) B (P + Q) one = times_one. %clause timesify_step : timesify (B * C) (X * C) Y Sign <- timesify B X Y Sign = [p1: pf (B * Sign == X * Y)] trans3 (trans3 times_assoc (times_cong2 comm_times) assoc_times) (times_cong1 p1) (trans3 times_assoc (times_cong2 (comm_times)) assoc_times). %clause timesify_end_one : timesify one one one one = refl. %{ ==== Catchtimes ==== }% %{ catchtimes A B X Y Sign Pos Neg - unravels to the correct sign * A - The as-yet unprocessed bit of the equation * B - The single term that was passed to timesify * X - The list returned from timesify * Y - The signal variable from timesify * Sign - the correct sign * Pos - The master positive term list * Neg - The master negative term list }% %clause catch_neg1: catchtimes A B (neg X) Y (neg Sign) Pos Neg <- catchtimes A B X Y Sign Pos Neg = [p1: pf (B * Sign == X * Y imp A + B == Pos - Neg)] imp_i [p2: pf (B * neg Sign == neg X * Y)] cut (trans3 (symm neg_times2) p2 neg_times1) [p3 : pf (neg (B * Sign) == neg (X * Y))] imp_e p1 (neg_elim p3). %clause catch_neg2 : catchtimes A B X Y (neg Sign) Pos Neg <- catchtimes A B (neg X) Y Sign Pos Neg = [p1: pf (B * Sign == neg X * Y imp A + B == Pos - Neg)] imp_i [p2: pf (B * neg Sign == X * Y)] cut (trans3 (symm neg_neg_e) (neg_cong (trans (symm neg_times2) p2)) (symm neg_times1)) [p3: pf (B * Sign == neg X * Y)] imp_e p1 p3. %clause catch_zero : catchtimes A B X zero one Pos Neg <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] imp_i [p2: pf (B * one == X * zero)] cut (trans3 (symm times_one) p2 times_zero) [p3: pf (B == zero)] trans3 (plus_cong2 (p3)) plus_zero p1. %clause catch_neg_one : catchtimes A B (neg X) one one Pos (Neg + X) <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] imp_i [p2: pf (B * one == neg X * one)] cut (trans3 (symm times_one) p2 times_one) [p3: pf (B == neg X)] cut (trans (plus_cong p1 p3) plus_assoc) [p4: pf (A + B == Pos + (neg Neg - X))] trans p4 (plus_cong2 neg_plus). %clause catch_one : catchtimes A B X one one (Pos + X) Neg <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] imp_i [p2: pf (B * one == X * one)] cut (trans3 (symm times_one) p2 times_one) [p3: pf (B == X)] trans4 (plus_cong p1 p3) plus_assoc (plus_cong2 comm_plus) assoc_plus. %clause catch_break : catchtimes A B X (P + Q) one Pos Neg <- plusify (A + X * P + X * Q) Pos Neg = [p1: pf (A + X * P + X * Q == Pos - Neg)] imp_i [p2: pf (B * one == X * (P + Q))] cut (trans3 (symm times_one) p2 distrib) [p3: pf (B == X * P + X * Q)] trans3 (plus_cong2 p3) assoc_plus p1. %{ ==== Plusify ==== }% %{ plusify - Creates a zero-termiated list (0 + A + B + C +...) }% %clause plusify_minus : plusify (A - (B + C)) Pos Neg <- plusify (A - B - C) Pos Neg = [p1] trans3 (plus_cong2 (symm neg_plus)) assoc_plus p1. %clause plusify_swap : plusify (A + (B + C)) Pos Neg <- plusify (A + B + C) Pos Neg = [p1] trans assoc_plus p1. %clause plusify_neg_one : plusify (A + neg one * B) Pos Neg <- plusify (A - B) Pos Neg = [p1] trans (plus_cong2 (trans neg_times1 (neg_cong one_times))) p1. %clause plusify_neg_one' : plusify (A + B * (neg one)) Pos Neg <- plusify (A - B) Pos Neg = [p1] trans (plus_cong2 comm_times) (plusify_neg_one p1). %clause plusify_neg : plusify (A - (neg B)) Pos Neg <- plusify (A + B) Pos Neg = [p1] trans (plus_cong2 neg_neg_e) p1. %clause plusify_remove_neg : plusify (A - zero) Pos Neg <- plusify A Pos Neg = [p1] trans3 (plus_cong2 neg_zero) plus_zero p1. %clause plusify_remove : plusify (A + zero) Pos Neg <- plusify A Pos Neg = [p1] trans plus_zero p1. %clause plusify_step_mult_neg : plusify (A - (B * C)) Pos Neg <- timesify (one * B * neg C) X Y Sign <- catchtimes A (B * neg C) X Y Sign Pos Neg = [p1: pf (B * neg C * Sign == X * Y imp A + B * neg C == Pos - Neg)] [p2: pf (one * B * neg C * Sign == X * Y)] cut (trans5 times_assoc (symm one_times) assoc_times assoc_times p2) [p3: pf (B * neg C * Sign == X * Y)] cut (imp_e p1 p3) [p4: pf (A + B * neg C == Pos - Neg)] trans (plus_cong2 (symm neg_times2)) p4. %clause plusify_step_mult : plusify (A + (B * C)) Pos Neg <- timesify (one * B * C) X Y Sign <- catchtimes A (B * C) X Y Sign Pos Neg = [p1: pf (B * C * Sign == X * Y imp A + B * C == Pos - Neg)] [p2: pf (one * B * C * Sign == X * Y)] cut (trans5 times_assoc (symm one_times) assoc_times assoc_times p2) [p3: pf (B * C * Sign == X * Y)] imp_e p1 p3. %clause plusify_step_neg_one : plusify (A - one) Pos (Neg + one) <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] trans3 (plus_cong1 p1) plus_assoc (plus_cong2 neg_plus). %clause plusify_step_one : plusify (A + one) (Pos + one) Neg <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] trans4 (plus_cong1 p1) plus_assoc (plus_cong2 comm_plus) assoc_plus. %clause plusify_step_neg : plusify (A - B) Pos (Neg + (one * B)) <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] trans3 (plus_cong p1 (neg_cong (symm one_times))) plus_assoc (plus_cong2 neg_plus). %clause plusify_step : plusify (A + B) (Pos + (one * B)) Neg <- plusify A Pos Neg = [p1: pf (A == Pos - Neg)] trans (plus_cong p1 (symm one_times)) (trans3 plus_assoc (plus_cong2 comm_plus) assoc_plus). %clause plusify_zero : plusify zero zero zero = symm plus_inv. %{ ==== Testing ==== }% %solve __P : {a}{b} listify (a * (b - one)) _ _. %solve __P : {a} listify (succ a * pred a) _ _. % %solve __P : {a} listify (pred (a * a) + (a - a)) _ _. %solve __P : listify zero _ _. %solve __P : {a}{b}{m}{n}{q} listify (a * one + (a * m + n * b) * q) _ _. %solve __P : {a}{b}{m}{n}{q} listify (a + q * a * m + q * n * b) _ _. %solve __P : {a}{b} listify (zero + (a + b)) _ _. %solve __P : {a}{b}{c}{d}{e} listify (c + (d + e) + (a + b)) _ _. % (zero + c + d + e + a + b). %solve __P : {a}{b}{d} listify (a * (succ one) + (b * (succ d) + d) * a) _ _. %solve __P : listify (one * (one + one) + (one * (one + one) + one) * one) _ _. %solve __P : {a}{b} listify (a * b) _ _. %solve __P : {a}{b}{c} listify (a + c * (c * c) * one + b * (b * b) * zero) _ _. %solve __P : {a} listify (neg (one * neg a)) _ _. %solve __P : {a}{b}{c} listify (zero - (a + neg b * c) + a * neg b) _ _. %solve __P : {a}{b}{c} listify (zero - (a + b * neg c) + a * neg b) _ _. %solve __P : {a} listify (one * (neg a)) _ _. %solve __P : {a}{b}{c} timesify (one * (neg a * neg (b * neg c))) _ _ _. %solve __P : {a}{b} listify ((neg a * neg b)) _ _. %solve __P : listify (neg one * neg one * neg one * neg one) _ _. %solve __P : {a} listify a _ _. %solve __P : listify (neg (neg (neg (neg (neg (neg zero))))) * one + zero) _ _. %solve __P : {a}{b} timesify (one * (a + b)) _ _ _. %solve __P : {a} listify (pred a * succ a) _ _. %{ === Matching === }% %{ ==== Trim ==== }% %{ TRIM - takes two lists, and makes a single pass at removing items from the first list and putting them in the second list. Fails unless at least one element (the top element in the first list) is trimmed. }% %clause trim_get : trim (A + C) (B + C) A B = cut (trans plus_assoc (plus_cong2 (plus_cong2 (symm neg_plus)))) [p2: pf (A + C - (B + C) == A + (C + (neg B - C)))] cut (trans (plus_cong2 assoc_plus) (plus_cong2 cancel_a+b-a)) [p3: pf (A + (C + (neg B - C)) == A - B)] trans p2 p3. %clause trim_getmult : trim (A + C) (B + D) A B <- findarr_mult C D one nomatch = [p2: pf (C == D * one and zero == zero)] cut (trans (and_e1 p2) times_one) [p3: pf (C == D)] cut (congr ([i] C - B - i == neg B) (symm p3) cancel_a+b-a) [p4: pf (C - B - D == neg B)] cut (trans3 (plus_cong2 (symm neg_plus)) assoc_plus p4) [p5: pf (C - (B + D) == neg B)] trans plus_assoc (plus_cong2 p5). %clause trim_step1 : trim (A + C) B (X + C) Y <- trim A B X Y = [p1: pf (A - B == X - Y)] cut (trans3 (trans3 plus_assoc (plus_cong2 comm_plus) assoc_plus) (plus_cong1 p1) (trans3 plus_assoc (plus_cong2 comm_plus) assoc_plus)) [p2: pf (A + C - B == X + C - Y)] p2. %clause trim_step2 : trim A (B + C) X (Y + C) <- trim A B X Y = [p1: pf (A - B == X - Y)] trans3 (plus_cong2 (symm neg_plus)) (trans3 assoc_plus (plus_cong1 p1) plus_assoc) (plus_cong2 neg_plus). %{ ==== Findarr_mult ==== }% % FINDARR_MULT - more complex than trim, cycles through a product to % Uses a quadratic algorithm, but in most cases the length of the proof % is dominated by the list creation, not the %clause fam_neg : findarr_mult (neg X) (neg Y) Z M <- findarr_mult X Y Z M = [p1: pf (X == Y * Z and M == M)] and_i (trans (neg_cong (and_e1 p1)) (symm neg_times1)) refl. %clause fam_step : findarr_mult (X * B) (Y * B) Z M <- findarr_mult X Y Z match = [p1: pf (X == Y * Z and match == match)] cut (trans (times_cong1 (and_e1 p1)) (trans3 times_assoc (times_cong2 comm_times) assoc_times)) [p2: pf (X * B == Y * B * Z)] and_i p2 refl. %clause fam_step2 : findarr_mult (X * B) (Y * C) Z M <- atom_replace B C <- findarr_mult X Y Z match = [p1][p2] congr ([i] (X * B == Y * i * Z and M == M)) (symm p2) (fam_step p1). %clause fam_step2' : findarr_mult (X * B) (Y * C) Z M <- atom_replace C B <- findarr_mult X Y Z match = [p1][p2] congr ([i] (X * B == Y * i * Z and M == M)) p2 (fam_step p1). %clause fam_swap : findarr_mult X (Y * B) Z M <- findarr_mult X Y (Z * B) M = [p1: pf (X == Y * (Z * B) and M == M)] cut p1 [_] and_i (trans3 (and_e1 p1) (times_cong2 comm_times) (symm times_assoc)) refl. %clause fam_finish : findarr_mult one one one M = and_i (symm times_one) refl. %clause fam_one : findarr_mult X one Y match <- findarr_mult X Y one nomatch = [p1: pf (X == Y * one and nomatch == nomatch)] and_i (trans (and_e1 p1) comm_times) refl. %{ ==== Rearrange ==== }% % REARRANGE % Handles the finishing steps of the solver %clause rearr_finish : rearrange zero zero zero zero = refl. %clause rearr_end : rearrange A B zero zero <- trim A B X Y <- rearrange X Y zero zero = [p1: pf (X - Y == zero - zero)] [p2: pf (A - B == X - Y)] trans p2 p1. %clause rearr_right : rearrange zero zero C D <- trim C D X Y <- rearrange X Y zero zero = [p1][p2] symm (rearr_end p1 p2). %clause rearr_pos : rearrange A zero C zero <- trim A C X Y <- rearrange X Y zero zero = [p1: pf (X - Y == zero - zero)] [p2: pf (A - C == X - Y)] cut (trans3 p2 p1 plus_inv) [p3: pf (A - C == zero)] cut (trans3 (symm cancel_a-b+b) (plus_cong1 p3) zero_plus) [p4: pf (A == C)] plus_cong1 p4. %clause rearr_neg : rearrange zero B zero D <- trim B D X Y <- rearrange X Y zero zero = [p1: pf (X - Y == zero - zero)] [p2: pf (B - D == X - Y)] cut (trans3 p2 p1 plus_inv) [p3: pf (B - D == zero)] cut (trans3 (symm cancel_a-b+b) (plus_cong1 p3) zero_plus) [p4: pf (B == D)] plus_cong2 (neg_cong p4). plus_swap : pf (A - B == C - D) -> pf (A - C == B - D) = [p1] cut (trans3 (symm cancel_a-b+b) (plus_cong1 p1) comm_plus) [p2: pf (A == B + (C - D))] cut (trans3 (plus_cong1 p2) plus_assoc (plus_cong2 cancel_a+b-a)) [p3: pf (A - C == B - D)] p3. plus_swap2 : pf (A + B == C + D) -> pf (A - D == C - B) = [p1] cut (trans5 (symm cancel_a+b-b) (plus_cong1 p1) plus_assoc (plus_cong2 comm_plus) assoc_plus) [p2: pf (A == C - B + D)] trans (plus_cong1 p2) cancel_a+b-b. %clause rearr_one : rearrange A B C zero <- trim A C X Y <- trim X B Z W <- rearrange Z W Y zero = [p1: pf (Z - W == Y - zero)] [p2: pf (X - B == Z - W)] [p3: pf (A - C == X - Y)] cut (plus_swap (trans p2 p1)) [p4: pf (X - Y == B - zero)] plus_swap (trans p3 p4). %clause rearr_two : rearrange A B zero D <- trim B D X Y <- trim A X Z W <- rearrange Z W zero Y = [p1: pf (Z - W == zero - Y)] [p2: pf (A - X == Z - W)] [p3: pf (B - D == X - Y)] cut (plus_swap (trans p2 p1)) [p4: pf (A - zero == X - Y)] plus_swap (trans p4 (symm p3)). %clause rearr_three : rearrange C zero A B <- trim A C X Y <- trim X B Z W <- rearrange Z W Y zero = [p1][p2][p3] symm (rearr_one p1 p2 p3). %clause rearr_four : rearrange zero D A B <- trim B D X Y <- trim A X Z W <- rearrange Z W zero Y = [p1][p2][p3] symm (rearr_two p1 p2 p3). %clause rearr_any1 : rearrange A B C D <- trim A B X Y <- rearrange X C Y D = [p1: pf (X - C == Y - D)] [p2: pf (A - B == X - Y)] trans p2 (plus_swap p1). %clause rearr_any2 : rearrange A B C D <- trim A C X Y <- rearrange X B Y D = [p1: pf (X - B == Y - D)] [p2: pf (A - C == X - Y)] plus_swap (trans p2 (plus_swap p1)). %clause solver_short1 : algebra_solver (A == A) = refl. %clause solver_short2a : algebra_solver (A + B == A + C) <- algebra_solver (B == C) = plus_cong2. %clause solver_short2b : algebra_solver (A + B == C + B) <- algebra_solver (A == C) = plus_cong1. %clause solver_rearrange : algebra_solver (A == B) <- listify A Pos Neg <- listify B Pos' Neg' <- rearrange Pos Neg Pos' Neg' = [p1][p2][p3] trans3 p3 p1 (symm p2). %clause fact_one_gt : algebra_fact (one > zero) = one>zero. %clause fact_gt->geq : algebra_fact (A >= B) <- algebra_fact (A > B) = gt->geq. %clause fact_gt->neq : algebra_fact (A != B) <- algebra_fact (A > B) = gt->neq. %clause fact_lt->neq : algebra_fact (A != B) <- algebra_fact (A < B) = lt->neq. %clause fact_eq->geq : algebra_fact (A >= B) <- algebra_fact (A == B) = eq->geq. %clause fact_eq->leq : algebra_fact (A <= B) <- algebra_fact (A == B) = eq->leq. %clause hintmod1 : algebra_times_hint_intern A B <- algebra_times_hint A <- algebra_times_hint B = [p1][p2] cut2 p1 p2 [_][_] refl. %clause hintmod2 : algebra_times_hint_intern A one <- algebra_times_hint A = [p1] cut p1 [_] refl. %clause hintmod3 : algebra_times_hint_intern one A <- algebra_times_hint A = [p1] cut p1 [_] refl. eq_arrange : pf (A - B == C - D) -> pf (A == B) -> pf (C == D) = [p1: pf (A - B == C - D)] [p2: pf (A == B)] cut (trans3 (symm p1) (plus_cong1 p2) plus_inv) [p3: pf (C - D == zero)] trans3 (symm cancel_a-b+b) (plus_cong1 p3) zero_plus. %clause solver_eq : algebra_solver (A == B imp C == D) <- algebra_solver (A + D == C + B) = [p1] imp_i [p2] eq_arrange (plus_swap2 p1) p2. %clause solver_eq_times : algebra_solver (A == B imp C == D) <- algebra_times_hint_intern X Y <- algebra_fact (Y != zero) <- algebra_solver (A * X + D * Y == C * Y + B * X) = [p1][p2][p3] cut p3 [_] imp_i [p4] cut (imp_e (solver_eq p1) (times_cong1 p4)) [p5: pf (C * Y == D * Y)] times_elim2 p2 p5. %clause solver_eq_neg : algebra_solver (A == B imp C == D) <- algebra_solver (D + B == C + A) = [p1] imp_i [p2] eq_arrange (plus_swap2 (trans comm_plus (plus_swap2 p1))) (neg_cong p2). %clause solver_eq_neg_times : algebra_solver (A == B imp C == D) <- algebra_times_hint_intern X Y <- algebra_fact (Y != zero) <- algebra_solver (D * Y + B * X == C * Y + A * X) = [p1][p2][p3] cut p3 [_] imp_i [p4] cut (imp_e (solver_eq_neg p1) (times_cong1 p4)) [p5: pf (C * Y == D * Y)] times_elim2 p2 p5. geq_arrange : pf (A + D == C + B) -> pf (A >= B) -> pf (C >= D) = [p0: pf (A + D == C + B)] [p1: pf (A >= B)] cut (plus_swap2 p0) [p2: pf (A - B == C - D)] cut (trans_geq_eq (geq_plus_cong1 p1) plus_inv) [p3: pf (A - B >= zero)] cut (trans_eq_geq (symm p2) p3) [p4: pf (C - D >= zero)] cut (trans_eq_geq (symm cancel_a-b+b) (geq_plus_cong1 p4)) [p5: pf (C >= zero + D)] trans_geq_eq p5 zero_plus. %clause solver_geq : algebra_solver (A >= B imp C >= D) <- algebra_solver (A + D == C + B) = [p1] imp_i [p2] geq_arrange p1 p2. %clause solver_geq_times1 : algebra_solver (A >= B imp C >= D) <- algebra_times_hint_intern X Y <- algebra_fact (X >= zero) <- algebra_fact (Y > zero) <- algebra_solver (A * X + D * Y == C * Y + B * X) = [p1][p2][p3][p4] cut p4 [_] imp_i [p5] cut (imp_e (solver_geq p1) (geq_times_cong1 p3 p5)) [p6: pf (C * Y >= D * Y)] geq_times_elim2 p2 p6. %clause solver_geq_times2 : algebra_solver (A <= B imp C >= D) <- algebra_times_hint_intern X Y <- algebra_fact (X <= zero) <- algebra_fact (Y > zero) <- algebra_solver (A * X + D * Y == C * Y + B * X) = [p1][p2][p3][p4] cut p4 [_] imp_i [p5] cut3 p1 p2 p3 [_][_][_] cut (imp_e (solver_geq p1) (geq_times_cong1_neg p3 p5)) [p6: pf (C * Y >= D * Y)] geq_times_elim2 p2 p6. %clause solver_geq_times3 : algebra_solver (A >= B imp C <= D) <- algebra_times_hint_intern X Y <- algebra_fact (X >= zero) <- algebra_fact (Y < zero) <- algebra_solver (A * X + D * Y == C * Y + B * X) = [p1][p2][p3][p4] cut p4 [_] imp_i [p5] cut3 p1 p2 p3 [_][_][_] cut (imp_e (solver_geq p1) (geq_times_cong1 p3 p5)) [p6: pf (C * Y >= D * Y)] geq_times_elim2_neg p2 p6. %clause solver_geq_times4 : algebra_solver (A <= B imp C <= D) <- algebra_times_hint_intern X Y <- algebra_fact (X <= zero) <- algebra_fact (Y < zero) <- algebra_solver (A * X + D * Y == C * Y + B * X) = [p1][p2][p3][p4] cut p4 [_] imp_i [p5] cut3 p1 p2 p3 [_][_][_] cut (imp_e (solver_geq p1) (geq_times_cong1_neg p3 p5)) [p6: pf (C * Y >= D * Y)] geq_times_elim2_neg p2 p6. %clause solver_neq : algebra_solver (A != B imp C != D) <- algebra_solver (C == D imp A == B) = [p1] imp_i [p2] not_eie p2 (imp_e p1). %clause solver_gt : algebra_solver (A < B imp C < D) <- algebra_solver (C >= D imp A >= B) = [p1] imp_i [p2] not_ein p2 (imp_e p1). %{ == Test cases for the solver == }% %solve __P : {a}{b}{c} algebra_solver (a > b imp a + c > c + b). %solve __P : {a}{b}{c} algebra_solver (a - b + c >= zero imp a >= b - c). %solve __P : {a}{b}{c} algebra_solver (a >= b imp neg a + c <= neg b + c). %solve __P : algebra_solver (one - one == zero). %solve __P : algebra_solver (one - one == two - two). %solve __P : {a}algebra_solver (two - two + a == one + a * (one + zero) - one). %solve __P : {a}{b}{c}{d} algebra_solver (a - b == c - d imp a - c == b - d). %solve __P : {a} algebra_solver (succ a * pred a == pred (a * a)). %solve __P : {a}{b}{c} algebra_solver (a - (b - c) == (a - b) + (c * one)). %solve __P : {a}{b}{c} algebra_solver (a + b == c * (one - one) + b + a). %solve __P : {a}{b}{c}{d}{e} algebra_solver (a - b + (c - d) + e == e - d + (((neg b) + c) + a)). %solve __P : {a}{b}{c} algebra_solver (c + (a + b) == a + zero + zero + b + zero + c). %solve __P : {a}{b} algebra_solver (neg (a + b) == (neg a) + (neg b)). %solve __P : {a}{b}{c} algebra_solver (a - (b - c) == (a + c) - b). %solve __P : {a}{b}{c} algebra_solver (neg one * (neg one * a + neg one * (b + c)) == neg (neg one * a) - (neg one * (b + c))). %solve __P : {a}{b}{c}{d}{e}{f}{g}{h}{i} algebra_solver (a * (b + (c * (d + (e * (f + (g * (h + i))))))) == a * (b + (c * (d + (e * (f + (g * (h))))))) + a * (c * one * e) * g * i). %solve __P : {a}{b}{c}{d}{e}{f} algebra_solver (a + b + c + d + e + f == f + e + d + c + b + a). %solve __P : {a}{b} algebra_solver (a * b == b * a). %solve __P : {a}{b}{c}{d} algebra_solver (a * (b + c) + (d * (c + a)) == c * d + (a * (b + c + d))). %solve __P : {a}{b}{d} algebra_solver (a * (d * (one + b) + one + b) + a == a * (succ one) + (b * (succ d) + d) * a). %solve __P : {a}{b}{c} algebra_solver ((c + b) + (a - one) * b == c + a * b + b - b). %solve __P : {a}{b}{m}{n}{q} algebra_solver (a * one + (a * m + n * b) * q == a * (one + m * q) + n * b * q). %solve __P : {a}{b}{m}{n}{q} algebra_solver (a * one + (a * m + n * b) * q == a * one + q * a * m + q * n * b). %solve __P : {a}{b} algebra_solver (a * zero + zero == zero * b). %solve __P : {a}{b} algebra_solver (a * (b * b) + a * zero == a * b * b). %solve __P : {a}{b}{c} algebra_solver (a * one * zero * b + c * (a + b) == b * c + zero * a + c * (a + zero)). %solve __P : algebra_solver (neg zero == zero). %solve __P : {a}{b} algebra_solver (a * (b * b) * one + a * zero == a * b * b). %query 0 * __P : {a}{b} algebra_solver (a == b). %solve __P : {a}{b}{c} algebra_solver (a * b * c == c * b * a). %solve __P : {a}{b}{m}{n}{q} algebra_solver (a - (m * a + n * b) * q == (one - q * m) * a + (neg (q * n)) * b). %solve __P : {a}{b} algebra_solver (a == b imp neg a == neg b). %solve __P : {a}{b} algebra_solver (a > b imp neg a < neg b). %solve __P : {a}{b} algebra_solver (a * one == b imp a == b * one). %solve __P : {a}{b} algebra_solver (a * one >= b imp a >= b * one). %solve __P : {a}{b} algebra_solver (a >= b imp neg b >= neg a). %solve __P : {a}{b} algebra_solver (a != b imp neg a != neg b). %solve __P : {a}{b}{c} algebra_solver (a > b imp c < a + (b - c) * neg one). %solve __P : {a}{b} algebra_times_hint b -> algebra_solver (a == one imp a * b == b ). %query * 1 __P : {a}{b} algebra_solver (a * b + a == a + b * a). %query 1 * __P : {a}{b} algebra_solver (a * b + a == a + b * a). %solve __P : {a}{b}{c} algebra_solver (a - b == a - b + c - c). %solve __P : {a}{b}{c} algebra_solver (a == b imp a + c == b + c). %solve __P : {a}{b}{c}{d} atom_replace a c -> atom_replace d c -> algebra_solver (a + b + c + c == b + c + c + d). %solve __P : {a}{b}{c} atom_replace b c -> algebra_solver (a + b == c + a). %solve __P : {a}{b}{c} atom_replace b c -> algebra_solver (a == b imp a - c == zero). %solve __P : {a}{b}{c} atom_replace b c -> algebra_solver (a - b == neg c + a). %solve __P : {a}{b}{c} atom_replace b c -> algebra_solver (a - a == b - c). %solve __P : {a}{b}{c}{d} algebra_times_hint c -> algebra_solver (a - b == d imp a * c == c * d + c * b). %solve __P : {a}{b}{c} algebra_times_hint a -> algebra_fact (a != zero) -> algebra_solver (neg a * c == neg (b * a) imp b - c == zero). %solve __P : {a}{b}{c}{d} algebra_times_hint (a + d) -> algebra_fact (a + d != zero) -> atom_replace b d -> algebra_solver ((neg a - b) * c == neg (d * a) - d * b imp b == c). %solve __P : {a}{b}{c}{d} algebra_times_hint (a + b * c) -> algebra_fact (a + b * c > zero) -> algebra_solver (d > one imp a * (d - one) > b * c * (one - d)). %query 0 * __P : {a}{b}{c}{d}{e} algebra_times_hint (a + e) -> algebra_fact (a + e > zero) -> algebra_times_hint b -> algebra_solver (c * (a + e) == d * (a) imp b * c == b * d). %solve __P : {a}{b}{c}{d}{e}{f}{g} algebra_times_hint (a + b * c) -> algebra_fact (a + b * c > zero) -> algebra_times_hint d -> algebra_solver ((a + b * c) * (e * f - one) == (g + one) * (a + b * c) imp d * (e * f - one) == d * (g + one)). %solve ex_27 : {a}{b}{c} algebra_times_hint a -> algebra_solver (a * (b - c) != zero imp b != c). %solve ex_28 : {a}{b}{c} algebra_times_hint (a + b) -> algebra_fact (a + b < zero) -> algebra_solver (a * (c - zero) - b == a - b * c imp zero == one - c). %solve ex_29 : {a}{b}{c}{d} algebra_times_hint a -> algebra_fact (a < zero) -> algebra_times_hint b -> algebra_fact (b >= zero) -> algebra_solver (c * a >= a * (d + zero) imp b * c * one <= b * d ). ex_30 : pf (A < zero) -> pf (B >= zero) -> pf (C * A >= A * (D + zero)) -> pf (B * C * one <= B * D) = [p1][p2][p3] imp_e (ex_29 A B C D refl p1 refl p2) p3.