Library AAC_tactics.Tutorial
Tutorial for using the aac_tactics library.
Introductory example
Section introduction.
Import ZArith.
Import Instances.Z.
Variables a b c : Z.
Hypothesis H: ∀ x, x + Z.opp x = 0.
Goal a + b + c + Z.opp (c + a) = b.
aac_rewrite H.
aac_reflexivity.
Qed.
Goal a + c + Z.opp (b + a + Z.opp b) = c.
do 2 aac_rewrite H.
reflexivity.
Qed.
Notes:
- the tactic handles arbitrary function symbols like Zopp (as long as they are proper morphisms w.r.t. the considered equivalence relation);
- here, ring would have done the job.
Usage
Section base.
Context {X} {R} {E: Equivalence R}
{plus}
{dot}
{zero}
{one}
{dot_A: @Associative X R dot }
{plus_A: @Associative X R plus }
{plus_C: @Commutative X R plus }
{dot_Proper :Proper (R ==> R ==> R) dot}
{plus_Proper :Proper (R ==> R ==> R) plus}
{Zero : Unit R plus zero}
{One : Unit R dot one}
.
Notation "x == y" := (R x y) (at level 70).
Notation "x * y" := (dot x y) (at level 40, left associativity).
Notation "1" := (one).
Notation "x + y" := (plus x y) (at level 50, left associativity).
Notation "0" := (zero).
In the very first example, ring would have solved the
goal. Here, since dot does not necessarily distribute over plus,
it is not possible to rely on it.
Section reminder.
Hypothesis H : ∀ x, x × x == x.
Variables a b c : X.
Goal (a+b+c)*(c+a+b) == a+b+c.
aac_rewrite H.
aac_reflexivity.
Qed.
The tactic starts by normalising terms, so that trailing units
are always eliminated.
The tactic can deal with "proper" morphisms of arbitrary arity
(here f and g, or Zopp earlier): it rewrites under such
morphisms (g), and, more importantly, it is able to reorder
terms modulo AC under these morphisms (f).
Section morphisms.
Variable f : X → X → X.
Hypothesis Hf : Proper (R ==> R ==> R) f.
Variable g : X → X.
Hypothesis Hg : Proper (R ==> R) g.
Variable a b: X.
Hypothesis H : ∀ x y, x+f (b+y) x == y+x.
Goal g ((f (a+b) a) + a) == g (a+a).
aac_rewrite H.
reflexivity.
Qed.
End morphisms.
Selecting what and where to rewrite
Section occurrence.
Variable f : X → X.
Variable a : X.
Hypothesis Hf : Proper (R ==> R) f.
Hypothesis H : ∀ x, x + x == x.
Goal f(a+a)+f(a+a) == f a.
In case there are several possible solutions, one can print
the different solutions using the aac_instances tactic (in
proof-general, look at buffer *coq* ):
the default choice is the occurrence with the smallest
possible context (number 0), but one can choose the desired
one;
aac_rewrite H.
reflexivity.
Qed.
End occurrence.
Section subst.
Variables a b c d : X.
Hypothesis H: ∀ x y, a×x×y×b == a*(x+y)*b.
Hypothesis H': ∀ x, x + x == x.
Goal a×c×d×c×d×b == a×c×d×b.
reflexivity.
Qed.
End occurrence.
Section subst.
Variables a b c d : X.
Hypothesis H: ∀ x y, a×x×y×b == a*(x+y)*b.
Hypothesis H': ∀ x, x + x == x.
Goal a×c×d×c×d×b == a×c×d×b.
Here, there is only one possible occurrence, but several substitutions;
one can select them with the proper keyword.
As expected, one can use both keywords together to select the
occurrence and the substitution. We also provide a keyword to
specify that the rewrite should be done in the right-hand side of
the equation.
Section both.
Variables a b c d : X.
Hypothesis H: ∀ x y, a×x×y×b == a*(x+y)*b.
Hypothesis H': ∀ x, x + x == x.
Goal a×c×d×c×d×b×b == a*(c×d×b)*b.
aac_instances H.
aac_rewrite H at 1 subst 1.
aac_instances H.
aac_rewrite H.
aac_rewrite H'.
aac_rewrite H at 0 subst 1 in_right.
aac_reflexivity.
Qed.
End both.
Distinction between aac_rewrite and aacu_rewrite:
while we get solutions with the aacu_× tactics.
We introduced this distinction because it allows us to rule
out dummy cases in common situations:
6 solutions without units,
more than 52 with units.
Declaring instances
Section Peano.
Import Arith.
Instance aac_plus_Assoc : Associative eq plus := plus_assoc.
Instance aac_plus_Comm : Commutative eq plus := plus_comm.
Instance aac_one : Unit eq mult 1 :=
Build_Unit eq mult 1 mult_1_l mult_1_r.
Instance aac_zero_plus : Unit eq plus O :=
Build_Unit eq plus (O) plus_0_l plus_0_r.
Two (or more) operations may share the same units: in the
following example, 0 is understood as the unit of max as well as
the unit of plus.
Instance aac_max_Comm : Commutative eq Max.max := Max.max_comm.
Instance aac_max_Assoc : Associative eq Max.max := Max.max_assoc.
Instance aac_zero_max : Unit eq Max.max O :=
Build_Unit eq Max.max 0 Max.max_0_l Max.max_0_r.
Variable a b c : nat.
Goal Max.max (a + 0) 0 = a.
aac_reflexivity.
Qed.
Furthermore, several operators can be mixed:
Hypothesis H : ∀ x y z, Max.max (x + y) (x + z) = x+ Max.max y z.
Goal Max.max (a + b) (c + (a × 1)) = Max.max c b + a.
aac_instances H. aac_rewrite H. aac_reflexivity.
Qed.
Goal Max.max (a + b) (c + Max.max (a*1+0) 0) = a + Max.max b c.
aac_instances H. aac_rewrite H. aac_reflexivity.
Qed.
Working with inequations
or in the right member of inequations, using the in_right keyword
Similarly, one can rewrite inequations in inequations,
possibly in the right-hand side.
Goal (∀ x, x ≤ x + x) → a + b ≤ a + b + b + a.
intro Hx.
aac_rewrite <- Hx in_right.
reflexivity.
Qed.
intro Hx.
aac_rewrite <- Hx in_right.
reflexivity.
Qed.
aac_reflexivity deals with "trivial" inequations too
In the last three examples, there were no equivalence relation
involved in the goal. However, we actually had to guess the
equivalence relation with respect to which the operators
(plus,max,0) were AC. In this case, it was Leibniz equality
eq so that it was automatically inferred; more generally, one
can specify which equivalence relation to use by declaring
instances of the AAC_lift type class:
Normalising goals
Section AAC_normalise.
Import Instances.Z.
Import ZArith.
Open Scope Z_scope.
Variable a b c d : Z.
Goal a + (b + c×c×d) + a + 0 + d*1 = a.
aac_normalise.
Abort.
End AAC_normalise.
Lemma Zabs_triangle : ∀ x y, Z.abs (x + y) ≤ Z.abs x + Z.abs y .
Proof Z.abs_triangle.
Lemma Zplus_opp_r : ∀ x, x + -x = 0.
Proof Zplus_opp_r.
The following morphisms are required to perform the required rewrites
Instance Zminus_compat : Proper (Z.ge ==> Z.le) Z.opp.
Proof. intros x y. lia. Qed.
Instance Proper_Zplus : Proper (Z.le ==> Z.le ==> Z.le) Zplus.
Proof. firstorder. Qed.
Goal ∀ a b, Z.abs a - Z.abs b ≤ Z.abs (a - b).
intros. unfold Zminus.
aac_instances <- (Zminus_diag b).
aac_rewrite <- (Zminus_diag b) at 3.
unfold Zminus.
aac_rewrite Z.abs_triangle.
aac_rewrite Zplus_opp_r.
aac_reflexivity.
Qed.
Proof. intros x y. lia. Qed.
Instance Proper_Zplus : Proper (Z.le ==> Z.le ==> Z.le) Zplus.
Proof. firstorder. Qed.
Goal ∀ a b, Z.abs a - Z.abs b ≤ Z.abs (a - b).
intros. unfold Zminus.
aac_instances <- (Zminus_diag b).
aac_rewrite <- (Zminus_diag b) at 3.
unfold Zminus.
aac_rewrite Z.abs_triangle.
aac_rewrite Zplus_opp_r.
aac_reflexivity.
Qed.
Notation "x ^2" := (x×x) (at level 40).
Notation "2 ⋅ x" := (x+x) (at level 41).
Lemma Hbin1: ∀ x y, (x+y)^2 = x^2 + y^2 + 2⋅x×y. Proof. intros; ring. Qed.
Lemma Hbin2: ∀ x y, x^2 + y^2 = (x+y)^2 + -(2⋅x×y). Proof. intros; ring. Qed.
Lemma Hopp : ∀ x, x + -x = 0. Proof Zplus_opp_r.
Variables a b c : Z.
Hypothesis H : c^2 + 2⋅(a+1)*b = (a+1+b)^2.
Goal a^2 + b^2 + 2⋅a + 1 = c^2.
aacu_rewrite <- Hbin1.
rewrite Hbin2.
aac_rewrite <- H.
aac_rewrite Hopp.
aac_reflexivity.
Qed.