diff options
Diffstat (limited to 'src/Algebra/Field.v')
-rw-r--r-- | src/Algebra/Field.v | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/src/Algebra/Field.v b/src/Algebra/Field.v new file mode 100644 index 000000000..ddd2737a3 --- /dev/null +++ b/src/Algebra/Field.v @@ -0,0 +1,481 @@ +Require Import Crypto.Util.Relations Crypto.Util.Tactics. +Require Import Coq.Classes.RelationClasses Coq.Classes.Morphisms. +Require Import Crypto.Algebra Crypto.Algebra.Ring Crypto.Algebra.IntegralDomain. +Require Coq.setoid_ring.Field_theory. + +Section Field. + Context {T eq zero one opp add mul sub inv div} `{@field T eq zero one opp add sub mul inv div}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "*" := mul. + + Lemma right_multiplicative_inverse : forall x : T, ~ eq x zero -> eq (mul x (inv x)) one. + Proof. + intros. rewrite commutative. auto using left_multiplicative_inverse. + Qed. + + Lemma left_inv_unique x ix : ix * x = one -> ix = inv x. + Proof. + intro Hix. + assert (ix*x*inv x = inv x). + - rewrite Hix, left_identity; reflexivity. + - rewrite <-associative, right_multiplicative_inverse, right_identity in H0; trivial. + intro eq_x_0. rewrite eq_x_0, Ring.mul_0_r in Hix. + apply (zero_neq_one(eq:=eq)). assumption. + Qed. + Definition inv_unique := left_inv_unique. + + Lemma right_inv_unique x ix : x * ix = one -> ix = inv x. + Proof. rewrite commutative. apply left_inv_unique. Qed. + + Lemma div_one x : div x one = x. + Proof. + rewrite field_div_definition. + rewrite <-(inv_unique 1 1); apply monoid_is_right_identity. + Qed. + + Lemma mul_cancel_l_iff : forall x y, y <> 0 -> + (x * y = y <-> x = one). + Proof. + intros. + split; intros. + + rewrite <-(right_multiplicative_inverse y) by assumption. + rewrite <-H1 at 1; rewrite <-associative. + rewrite right_multiplicative_inverse by assumption. + rewrite right_identity. + reflexivity. + + rewrite H1; apply left_identity. + Qed. + + Lemma field_theory_for_stdlib_tactic : Field_theory.field_theory 0 1 add mul sub opp div inv eq. + Proof. + constructor. + { apply Ring.ring_theory_for_stdlib_tactic. } + { intro H01. symmetry in H01. auto using (zero_neq_one(eq:=eq)). } + { apply field_div_definition. } + { apply left_multiplicative_inverse. } + Qed. + + Context (eq_dec:DecidableRel eq). + + Global Instance is_mul_nonzero_nonzero : @is_zero_product_zero_factor T eq 0 mul. + Proof. + split. intros x y Hxy. + eapply not_not; try typeclasses eauto; []; intuition idtac; eapply (zero_neq_one(eq:=eq)). + transitivity ((inv y * (inv x * x)) * y). + - rewrite <-!associative, Hxy, !Ring.mul_0_r; reflexivity. + - rewrite left_multiplicative_inverse, right_identity, left_multiplicative_inverse by trivial. + reflexivity. + Qed. + + Global Instance integral_domain : @integral_domain T eq zero one opp add sub mul. + Proof. + split; auto using field_commutative_ring, field_is_zero_neq_one, is_mul_nonzero_nonzero. + Qed. +End Field. + +Lemma isomorphism_to_subfield_field + {T EQ ZERO ONE OPP ADD SUB MUL INV DIV} + {Equivalence_EQ: @Equivalence T EQ} + {Proper_OPP:Proper(EQ==>EQ)OPP} + {Proper_ADD:Proper(EQ==>EQ==>EQ)ADD} + {Proper_SUB:Proper(EQ==>EQ==>EQ)SUB} + {Proper_MUL:Proper(EQ==>EQ==>EQ)MUL} + {Proper_INV:Proper(EQ==>EQ)INV} + {Proper_DIV:Proper(EQ==>EQ==>EQ)DIV} + {R eq zero one opp add sub mul inv div} {fieldR:@field R eq zero one opp add sub mul inv div} + {phi} + {eq_phi_EQ: forall x y, eq (phi x) (phi y) -> EQ x y} + {neq_zero_one : (not (EQ ZERO ONE))} + {phi_opp : forall a, eq (phi (OPP a)) (opp (phi a))} + {phi_add : forall a b, eq (phi (ADD a b)) (add (phi a) (phi b))} + {phi_sub : forall a b, eq (phi (SUB a b)) (sub (phi a) (phi b))} + {phi_mul : forall a b, eq (phi (MUL a b)) (mul (phi a) (phi b))} + {phi_inv : forall a, eq (phi (INV a)) (inv (phi a))} + {phi_div : forall a b, eq (phi (DIV a b)) (div (phi a) (phi b))} + {phi_zero : eq (phi ZERO) zero} + {phi_one : eq (phi ONE) one} + : @field T EQ ZERO ONE OPP ADD SUB MUL INV DIV. +Proof. + repeat split; eauto with core typeclass_instances; intros; + eapply eq_phi_EQ; + repeat rewrite ?phi_opp, ?phi_add, ?phi_sub, ?phi_mul, ?phi_inv, ?phi_zero, ?phi_one, ?phi_inv, ?phi_div; + auto using (associative (op := add)), (commutative (op := add)), (left_identity (op := add)), (right_identity (op := add)), + (associative (op := mul)), (commutative (op := mul)), (left_identity (op := mul)), (right_identity (op := mul)), + (left_inverse(op:=add)), (right_inverse(op:=add)), (left_distributive (add := add)), (right_distributive (add := add)), + (ring_sub_definition(sub:=sub)), field_div_definition. + apply left_multiplicative_inverse; rewrite <-phi_zero; auto. +Qed. + +Lemma Proper_ext : forall {A} (f g : A -> A) eq, Equivalence eq -> + (forall x, eq (g x) (f x)) -> Proper (eq==>eq) f -> Proper (eq==>eq) g. +Proof. + repeat intro. + transitivity (f x); auto. + transitivity (f y); auto. + symmetry; auto. +Qed. + +Lemma Proper_ext2 : forall {A} (f g : A -> A -> A) eq, Equivalence eq -> + (forall x y, eq (g x y) (f x y)) -> Proper (eq==>eq ==>eq) f -> Proper (eq==>eq==>eq) g. +Proof. + repeat intro. + transitivity (f x x0); auto. + transitivity (f y y0); match goal with H : Proper _ f |- _=> try apply H end; auto. + symmetry; auto. +Qed. + +Lemma equivalent_operations_field + {T EQ ZERO ONE OPP ADD SUB MUL INV DIV} + {EQ_equivalence : Equivalence EQ} + {zero one opp add sub mul inv div} + {fieldR:@field T EQ zero one opp add sub mul inv div} + {EQ_opp : forall a, EQ (OPP a) (opp a)} + {EQ_inv : forall a, EQ (INV a) (inv a)} + {EQ_add : forall a b, EQ (ADD a b) (add a b)} + {EQ_sub : forall a b, EQ (SUB a b) (sub a b)} + {EQ_mul : forall a b, EQ (MUL a b) (mul a b)} + {EQ_div : forall a b, EQ (DIV a b) (div a b)} + {EQ_zero : EQ ZERO zero} + {EQ_one : EQ ONE one} + : @field T EQ ZERO ONE OPP ADD SUB MUL INV DIV. +Proof. + repeat (exact _||intro||split); rewrite_hyp ->?*; try reflexivity; + auto using (associative (op := add)), (commutative (op := add)), (left_identity (op := add)), (right_identity (op := add)), + (associative (op := mul)), (commutative (op := mul)), (left_identity (op := mul)), (right_identity (op := mul)), + (left_inverse(op:=add)), (right_inverse(op:=add)), (left_distributive (add := add)), (right_distributive (add := add)), + (ring_sub_definition(sub:=sub)), field_div_definition; + try solve [(eapply Proper_ext2 || eapply Proper_ext); + eauto using group_inv_Proper, monoid_op_Proper, ring_mul_Proper, ring_sub_Proper, + field_inv_Proper, field_div_Proper]. + + apply left_multiplicative_inverse. + symmetry in EQ_zero. rewrite EQ_zero. assumption. + + eapply field_is_zero_neq_one; eauto; rewrite_hyp <-?*; reflexivity. +Qed. + +Section Homomorphism. + Context {F EQ ZERO ONE OPP ADD MUL SUB INV DIV} `{@field F EQ ZERO ONE OPP ADD SUB MUL INV DIV}. + Context {K eq zero one opp add mul sub inv div} `{@field K eq zero one opp add sub mul inv div}. + Context {phi:F->K}. + Local Infix "=" := eq. Local Infix "=" := eq : type_scope. + Context `{@Ring.is_homomorphism F EQ ONE ADD MUL K eq one add mul phi}. + + Lemma homomorphism_multiplicative_inverse + : forall x, not (EQ x ZERO) + -> phi (INV x) = inv (phi x). + Proof. + intros. + eapply inv_unique. + rewrite <-Ring.homomorphism_mul. + rewrite left_multiplicative_inverse; auto using Ring.homomorphism_one. + Qed. + + Lemma homomorphism_multiplicative_inverse_complete + { EQ_dec : DecidableRel EQ } + : forall x, (EQ x ZERO -> phi (INV x) = inv (phi x)) + -> phi (INV x) = inv (phi x). + Proof. + intros x ?; destruct (dec (EQ x ZERO)); auto using homomorphism_multiplicative_inverse. + Qed. + + Lemma homomorphism_div + : forall x y, not (EQ y ZERO) + -> phi (DIV x y) = div (phi x) (phi y). + Proof. + intros. rewrite !field_div_definition. + rewrite Ring.homomorphism_mul, homomorphism_multiplicative_inverse; + (eauto || reflexivity). + Qed. + + Lemma homomorphism_div_complete + { EQ_dec : DecidableRel EQ } + : forall x y, (EQ y ZERO -> phi (INV y) = inv (phi y)) + -> phi (DIV x y) = div (phi x) (phi y). + Proof. + intros. rewrite !field_div_definition. + rewrite Ring.homomorphism_mul, homomorphism_multiplicative_inverse_complete; + (eauto || reflexivity). + Qed. +End Homomorphism. + +Section Homomorphism_rev. + Context {F EQ ZERO ONE OPP ADD SUB MUL INV DIV} {fieldF:@field F EQ ZERO ONE OPP ADD SUB MUL INV DIV}. + Context {H} {eq : H -> H -> Prop} {zero one : H} {opp : H -> H} {add sub mul : H -> H -> H} {inv : H -> H} {div : H -> H -> H}. + Context {phi:F->H} {phi':H->F}. + Local Infix "=" := EQ. Local Infix "=" := EQ : type_scope. + Context (phi'_phi_id : forall A, phi' (phi A) = A) + (phi'_eq : forall a b, EQ (phi' a) (phi' b) <-> eq a b) + {phi'_zero : phi' zero = ZERO} + {phi'_one : phi' one = ONE} + {phi'_opp : forall a, phi' (opp a) = OPP (phi' a)} + (phi'_add : forall a b, phi' (add a b) = ADD (phi' a) (phi' b)) + (phi'_sub : forall a b, phi' (sub a b) = SUB (phi' a) (phi' b)) + (phi'_mul : forall a b, phi' (mul a b) = MUL (phi' a) (phi' b)) + {phi'_inv : forall a, phi' (inv a) = INV (phi' a)} + (phi'_div : forall a b, phi' (div a b) = DIV (phi' a) (phi' b)). + + Lemma field_and_homomorphism_from_redundant_representation + : @field H eq zero one opp add sub mul inv div + /\ @Ring.is_homomorphism F EQ ONE ADD MUL H eq one add mul phi + /\ @Ring.is_homomorphism H eq one add mul F EQ ONE ADD MUL phi'. + Proof. + repeat match goal with + | [ H : field |- _ ] => destruct H; try clear H + | [ H : commutative_ring |- _ ] => destruct H; try clear H + | [ H : ring |- _ ] => destruct H; try clear H + | [ H : abelian_group |- _ ] => destruct H; try clear H + | [ H : group |- _ ] => destruct H; try clear H + | [ H : monoid |- _ ] => destruct H; try clear H + | [ H : is_commutative |- _ ] => destruct H; try clear H + | [ H : is_left_multiplicative_inverse |- _ ] => destruct H; try clear H + | [ H : is_left_distributive |- _ ] => destruct H; try clear H + | [ H : is_right_distributive |- _ ] => destruct H; try clear H + | [ H : is_zero_neq_one |- _ ] => destruct H; try clear H + | [ H : is_associative |- _ ] => destruct H; try clear H + | [ H : is_left_identity |- _ ] => destruct H; try clear H + | [ H : is_right_identity |- _ ] => destruct H; try clear H + | [ H : Equivalence _ |- _ ] => destruct H; try clear H + | [ H : is_left_inverse |- _ ] => destruct H; try clear H + | [ H : is_right_inverse |- _ ] => destruct H; try clear H + | _ => intro + | _ => split + | [ H : eq _ _ |- _ ] => apply phi'_eq in H + | [ |- eq _ _ ] => apply phi'_eq + | [ H : (~eq _ _)%type |- _ ] => pose proof (fun pf => H (proj1 (@phi'_eq _ _) pf)); clear H + | [ H : EQ _ _ |- _ ] => rewrite H + | _ => progress erewrite ?phi'_zero, ?phi'_one, ?phi'_opp, ?phi'_add, ?phi'_sub, ?phi'_mul, ?phi'_inv, ?phi'_div, ?phi'_phi_id by reflexivity + | [ H : _ |- _ ] => progress erewrite ?phi'_zero, ?phi'_one, ?phi'_opp, ?phi'_add, ?phi'_sub, ?phi'_mul, ?phi'_inv, ?phi'_div, ?phi'_phi_id in H by reflexivity + | _ => solve [ eauto ] + end. + Qed. +End Homomorphism_rev. + +Ltac guess_field := + match goal with + | |- ?eq _ _ => constr:(_:Algebra.field (eq:=eq)) + | |- not (?eq _ _) => constr:(_:Algebra.field (eq:=eq)) + | [H: ?eq _ _ |- _ ] => constr:(_:Algebra.field (eq:=eq)) + | [H: not (?eq _ _) |- _] => constr:(_:Algebra.field (eq:=eq)) + end. + +Ltac goal_to_field_equality fld := + let eq := match type of fld with Algebra.field(eq:=?eq) => eq end in + match goal with + | [ |- eq _ _] => idtac + | [ |- not (eq ?x ?y) ] => apply not_exfalso; intro; goal_to_field_equality fld + | _ => exfalso; + match goal with + | H: not (eq _ _) |- _ => apply not_exfalso in H; apply H + | _ => apply (field_is_zero_neq_one(field:=fld)) + end + end. + +Ltac _introduce_inverse fld d d_nz := + let eq := match type of fld with Algebra.field(eq:=?eq) => eq end in + let mul := match type of fld with Algebra.field(mul:=?mul) => mul end in + let one := match type of fld with Algebra.field(one:=?one) => one end in + let inv := match type of fld with Algebra.field(inv:=?inv) => inv end in + match goal with [H: eq (mul d _) one |- _ ] => fail 1 | _ => idtac end; + let d_i := fresh "i" in + unique pose proof (right_multiplicative_inverse(H:=fld) _ d_nz); + set (inv d) as d_i in *; + clearbody d_i. + +Ltac inequalities_to_inverse_equations fld := + let eq := match type of fld with Algebra.field(eq:=?eq) => eq end in + let zero := match type of fld with Algebra.field(zero:=?zero) => zero end in + let div := match type of fld with Algebra.field(div:=?div) => div end in + let sub := match type of fld with Algebra.field(sub:=?sub) => sub end in + repeat match goal with + | [H: not (eq _ _) |- _ ] => + lazymatch type of H with + | not (eq ?d zero) => _introduce_inverse fld d H + | not (eq zero ?d) => _introduce_inverse fld d (symmetry(R:=fun a b => not (eq a b)) H) + | not (eq ?x ?y) => _introduce_inverse fld (sub x y) (Ring.neq_sub_neq_zero _ _ H) + end + end. + +Ltac _nonzero_tac fld := + solve [trivial | IntegralDomain.solve_constant_nonzero | goal_to_field_equality fld; nsatz; IntegralDomain.solve_constant_nonzero]. + +Ltac _inverse_to_equation_by fld d tac := + let eq := match type of fld with Algebra.field(eq:=?eq) => eq end in + let zero := match type of fld with Algebra.field(zero:=?zero) => zero end in + let one := match type of fld with Algebra.field(one:=?one) => one end in + let mul := match type of fld with Algebra.field(mul:=?mul) => mul end in + let div := match type of fld with Algebra.field(div:=?div) => div end in + let inv := match type of fld with Algebra.field(inv:=?inv) => inv end in + let d_nz := fresh "nz" in + assert (not (eq d zero)) as d_nz by tac; + lazymatch goal with + | H: eq (mul ?di d) one |- _ => rewrite <-!(left_inv_unique(H:=fld) _ _ H) in * + | H: eq (mul d ?di) one |- _ => rewrite <-!(right_inv_unique(H:=fld) _ _ H) in * + | _ => _introduce_inverse constr:(fld) constr:(d) d_nz + end; + clear d_nz. + +Ltac inverses_to_equations_by fld tac := + let eq := match type of fld with Algebra.field(eq:=?eq) => eq end in + let zero := match type of fld with Algebra.field(zero:=?zero) => zero end in + let inv := match type of fld with Algebra.field(inv:=?inv) => inv end in + repeat match goal with + | |- context[inv ?d] => _inverse_to_equation_by fld d tac + | H: context[inv ?d] |- _ => _inverse_to_equation_by fld d tac + end. + +Ltac divisions_to_inverses fld := + rewrite ?(field_div_definition(field:=fld)) in *. + +Ltac fsatz := + let fld := guess_field in + goal_to_field_equality fld; + inequalities_to_inverse_equations fld; + divisions_to_inverses fld; + inverses_to_equations_by fld ltac:(solve_debugfail ltac:(_nonzero_tac fld)); + nsatz; + solve_debugfail ltac:(IntegralDomain.solve_constant_nonzero). + +Module _fsatz_test. + Section _test. + Context {F eq zero one opp add sub mul inv div} + {fld:@Algebra.field F eq zero one opp add sub mul inv div} + {eq_dec:DecidableRel eq}. + Local Infix "=" := eq. Local Notation "a <> b" := (not (a = b)). + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "*" := mul. + Local Infix "-" := sub. Local Infix "/" := div. + + Lemma inv_hyp a b c d (H:a*inv b=inv d*c) (bnz:b<>0) (dnz:d<>0) : a*d = b*c. + Proof. fsatz. Qed. + + Lemma inv_goal a b c d (H:a=b+c) (anz:a<>0) : inv a*d + 1 = (d+b+c)*inv(b+c). + Proof. fsatz. Qed. + + Lemma div_hyp a b c d (H:a/b=c/d) (bnz:b<>0) (dnz:d<>0) : a*d = b*c. + Proof. fsatz. Qed. + + Lemma div_goal a b c d (H:a=b+c) (anz:a<>0) : d/a + 1 = (d+b+c)/(b+c). + Proof. fsatz. Qed. + + Lemma zero_neq_one : 0 <> 1. + Proof. fsatz. Qed. + + Lemma transitivity_contradiction a b c (ab:a=b) (bc:b=c) (X:a<>c) : False. + Proof. fsatz. Qed. + + Lemma algebraic_contradiction a b c (A:a+b=c) (B:a-b=c) (X:a*a - b*b <> c*c) : False. + Proof. fsatz. Qed. + + Lemma division_by_zero_in_hyps (bad:1/0 + 1 = (1+1)/0): 1 = 1. + Proof. fsatz. Qed. + Lemma division_by_zero_in_hyps_eq_neq (bad:1/0 + 1 = (1+1)/0): 1 <> 0. fsatz. Qed. + Lemma division_by_zero_in_hyps_neq_neq (bad:1/0 <> (1+1)/0): 1 <> 0. fsatz. Qed. + Import BinNums. + + Context {char_gt_15:@Ring.char_gt F eq zero one opp add sub mul 15}. + + Local Notation two := (one+one) (only parsing). + Local Notation three := (one+one+one) (only parsing). + Local Notation seven := (three+three+one) (only parsing). + Local Notation nine := (three+three+three) (only parsing). + + Lemma fractional_equation_solution x (A:x<>1) (B:x<>opp two) (C:x*x+x <> two) (X:nine/(x*x + x - two) = three/(x+two) + seven*inv(x-1)) : x = opp one / (three+two). + Proof. fsatz. Qed. + + Lemma fractional_equation_no_solution x (A:x<>1) (B:x<>opp two) (C:x*x+x <> two) (X:nine/(x*x + x - two) = opp three/(x+two) + seven*inv(x-1)) : False. + Proof. fsatz. Qed. + End _test. +End _fsatz_test. + +Section ExtraLemmas. + Context {F eq zero one opp add sub mul inv div} `{F_field:field F eq zero one opp add sub mul inv div} {eq_dec:DecidableRel eq}. + Local Infix "+" := add. Local Infix "*" := mul. Local Infix "-" := sub. Local Infix "/" := div. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + + Example _only_two_square_roots_test x y : x * x = y * y -> x <> opp y -> x = y. + Proof. intros; fsatz. Qed. + + Lemma only_two_square_roots' x y : x * x = y * y -> x <> y -> x <> opp y -> False. + Proof. intros; fsatz. Qed. + + Lemma only_two_square_roots x y z : x * x = z -> y * y = z -> x <> y -> x <> opp y -> False. + Proof. + intros; setoid_subst z; eauto using only_two_square_roots'. + Qed. + + Lemma only_two_square_roots'_choice x y : x * x = y * y -> x = y \/ x = opp y. + Proof. + intro H. + destruct (dec (eq x y)); [ left; assumption | right ]. + destruct (dec (eq x (opp y))); [ assumption | exfalso ]. + eapply only_two_square_roots'; eassumption. + Qed. + + Lemma only_two_square_roots_choice x y z : x * x = z -> y * y = z -> x = y \/ x = opp y. + Proof. + intros; setoid_subst z; eauto using only_two_square_roots'_choice. + Qed. +End ExtraLemmas. + +(** We look for hypotheses of the form [x^2 = y^2] and [x^2 = z] together with [y^2 = z], and prove that [x = y] or [x = opp y] *) +Ltac pose_proof_only_two_square_roots x y H eq opp mul := + not constr_eq x y; + lazymatch x with + | opp ?x' => pose_proof_only_two_square_roots x' y H eq opp mul + | _ + => lazymatch y with + | opp ?y' => pose_proof_only_two_square_roots x y' H eq opp mul + | _ + => match goal with + | [ H' : eq x y |- _ ] + => let T := type of H' in fail 1 "The hypothesis" H' "already proves" T + | [ H' : eq y x |- _ ] + => let T := type of H' in fail 1 "The hypothesis" H' "already proves" T + | [ H' : eq x (opp y) |- _ ] + => let T := type of H' in fail 1 "The hypothesis" H' "already proves" T + | [ H' : eq y (opp x) |- _ ] + => let T := type of H' in fail 1 "The hypothesis" H' "already proves" T + | [ H' : eq (opp x) y |- _ ] + => let T := type of H' in fail 1 "The hypothesis" H' "already proves" T + | [ H' : eq (opp y) x |- _ ] + => let T := type of H' in fail 1 "The hypothesis" H' "already proves" T + | [ H' : eq (mul x x) (mul y y) |- _ ] + => pose proof (only_two_square_roots'_choice x y H') as H + | [ H0 : eq (mul x x) ?z, H1 : eq (mul y y) ?z |- _ ] + => pose proof (only_two_square_roots_choice x y z H0 H1) as H + end + end + end. +Ltac reduce_only_two_square_roots x y eq opp mul := + let H := fresh in + pose_proof_only_two_square_roots x y H eq opp mul; + destruct H; + try setoid_subst y. +(** Remove duplicates; solve goals by contradiction, and, if goals still remain, substitute the square roots *) +Ltac post_clean_only_two_square_roots x y := + try (unfold not in *; + match goal with + | [ H : (?T -> False)%type, H' : ?T |- _ ] => exfalso; apply H; exact H' + | [ H : (?R ?x ?x -> False)%type |- _ ] => exfalso; apply H; reflexivity + end); + try setoid_subst x; try setoid_subst y. +Ltac only_two_square_roots_step eq opp mul := + match goal with + | [ H : not (eq ?x (opp ?y)) |- _ ] + (* this one comes first, because it the procedure is asymmetric + with respect to [x] and [y], and this order is more likely to + lead to solving goals by contradiction. *) + => is_var x; is_var y; reduce_only_two_square_roots x y eq opp mul; post_clean_only_two_square_roots x y + | [ H : eq (mul ?x ?x) (mul ?y ?y) |- _ ] + => reduce_only_two_square_roots x y eq opp mul; post_clean_only_two_square_roots x y + | [ H : eq (mul ?x ?x) ?z, H' : eq (mul ?y ?y) ?z |- _ ] + => reduce_only_two_square_roots x y eq opp mul; post_clean_only_two_square_roots x y + end. +Ltac only_two_square_roots := + let fld := guess_field in + lazymatch type of fld with + | @field ?F ?eq ?zero ?one ?opp ?add ?sub ?mul ?inv ?div + => repeat only_two_square_roots_step eq opp mul + end.
\ No newline at end of file |