(* *********************************************************************** *)
(*  This is part of aac_tactics, it is distributed under the terms of the  *)
(*         GNU Lesser General Public License version 3                     *)
(*              (see file LICENSE for more details)                        *)
(*                                                                         *)
(*       Copyright 2009-2010: Thomas Braibant, Damien Pous.                *)
(* *********************************************************************** *)

Currently known limitations and caveats of AAC Tactics


From Coq Require NArith PeanoNat.
From AAC_tactics Require Import AAC.
From AAC_tactics Require Instances.

Limitations

Dependent parameters

The type of the rewriting hypothesis must be of the form
forall (x_1: T_1) ... (x_n: T_n), R l r
where R is a relation over some type T and such that for all variable x_i appearing in the left-hand side (l), we actually have T_i = T. The goal should be of the form S g d, where S is a relation on T.
In other words, we cannot instantiate arguments of an exogeneous type.

Section parameters.

  Context {X} {R} {E: @Equivalence X R} {plus}
   {plus_A: Associative R plus} {plus_C: Commutative R plus}
   {plus_Proper: Proper (R ==> R ==> R) plus}
   {zero} {Zero: Unit R plus zero}.

  Notation "x == y" := (R x y) (at level 70).
  Notation "x + y" := (plus x y) (at level 50, left associativity).
  Notation "0" := (zero).

  Variable f : nat -> X -> X.

In Hf, since the parameter n has type nat, it cannot be instantiated automatically
  Hypothesis Hf: forall n x, f n x + x == x.
  Hypothesis Hf': forall n, Proper (R ==> R) (f n).

  Goal forall a b k, a + f k (b+a) + b == a+b.
    intros.
aac_rewrite does not instantiate n automatically
    Fail aac_rewrite Hf.
of course, this argument can be given explicitly
    aac_rewrite (Hf k).
    aac_reflexivity.
  Qed.

For the same reason, we cannot handle higher-order parameters (here, g)
  Hypothesis H : forall g x y, g x + g y == g (x + y).
  Variable g : X -> X.
  Hypothesis Hg : Proper (R ==> R) g.

  Goal forall a b c, g a + g b + g c == g (a + b + c).
    intros.
    Fail aac_rewrite H.
    do 2 aac_rewrite (H g). aac_reflexivity.
  Qed.

End parameters.

Exogeneous morphisms

We do not handle "exogeneous" morphisms: morphisms that move from type T to some other type T'.

Section morphism.
  Import NArith PeanoNat.
  Import Instances.N Instances.Peano.

  Open Scope nat_scope.

Typically, although N_of_nat is a proper morphism from @eq nat to @eq N, we cannot rewrite under N_of_nat
  Goal forall a b: nat, N_of_nat (a+b-(b+a)) = 0%N.
    intros.
    Fail aac_rewrite Nat.sub_diag.
  Abort.

More generally, this prevents us from rewriting under propositional contexts
  Context {P} {HP : Proper (@eq nat ==> iff) P}.
  Hypothesis H : P 0.

  Goal forall a b, P (a + b - (b + a)).
    intros a b.
    Fail aac_rewrite Nat.sub_diag.
a solution is to introduce an evar to replace the part to be rewritten - this tiresome process should be improved in the future; here, it can be done using eapply and the morphism
    eapply HP.
    aac_rewrite Nat.sub_diag.
    reflexivity.
    exact H.
  Qed.

  Goal forall a b, a+b-(b+a) = 0 /\ b-b = 0.
    intros.
similarly, we need to bring equations to the toplevel before being able to rewrite
    Fail aac_rewrite Nat.sub_diag.
    split; aac_rewrite Nat.sub_diag; reflexivity.
  Qed.

End morphism.

Treatment of variance with inequations

We do not take variance into account when we compute the set of solutions to a matching problem modulo AC. As a consequence, aac_instances may propose solutions for which aac_rewrite will fail, due to the lack of adequate morphisms.

Section ineq.
  Import ZArith.
  Import Instances.Z.

  Open Scope Z_scope.

  #[local] Instance Z_add_incr: Proper (Z.le ==> Z.le ==> Z.le) Z.add.
  Proof. intros ? ? H ? ? H'. apply Zplus_le_compat; assumption. Qed.

  Hypothesis H : forall x, x+x <= x.

  Goal forall a b c, c + - (a + a) + b + b <= c.
    intros.
this fails because the first solution is not valid (Z.opp is not increasing)
    Fail aac_rewrite H.
    aac_instances H.
on the contrary, the second solution is valid:
    aac_rewrite H at 1.
currently, we cannot filter out such invalid solutions in an easy way; this should be fixed in the future
  Abort.

End ineq.

Caveats

Special treatment for units

S 0 is considered as a unit for multiplication whenever a Nat.mul appears in the goal. The downside is that S x does not match 1, and 1 does not match S (0 + 0) whenever Nat.mul appears in the goal.

Section Peano.
  Import Instances.Peano.

  Hypothesis H : forall x, x + S x = S (x+x).

  Goal 1 = 1.
OK (no multiplication around), x is instantiated with O
    aacu_rewrite H.
  Abort.

  Goal 1 * 1 = 1.
fails since 1 is seen as a unit, not the application of the morphism S to the constant O
    Fail aacu_rewrite H.
  Abort.

  Hypothesis H': forall x, x + 1 = 1 + x.

  Goal forall a, a + S (0+0) = 1 + a.
OK (no multiplication around), x is instantiated with a
    intro. aac_rewrite H'.
  Abort.

  Goal forall a, a * a + S (0+0) = 1 + a * a.
fails: although S (0+0) is understood as the application of the morphism S to the constant O, it is not recognised as the unit S O of multiplication
    intro. Fail aac_rewrite H'.
  Abort.

More generally, similar counter-intuitive behaviours can appear when declaring an applied morphism as a unit
End Peano.

Existential variables

We implemented an algorithm for matching modulo AC, not for unifying modulo AC. As a consequence, existential variables appearing in a goal are considered as constants and will not be instantiated.

Section evars.
  Import ZArith.
  Import Instances.Z.

  Variable P: Prop.
  Hypothesis H: forall x y, x + y + x = x -> P.
  Hypothesis idem: forall x, x + x = x.

  Goal P.
    eapply H.
this works: x is instantiated with an evar
    aac_rewrite idem.
    instantiate (2 := 0).
this does work but there are remaining evars in the end
    symmetry. aac_reflexivity.
  Abort.

  Hypothesis H': forall x, 3+x = x -> P.

  Goal P.
    eapply H'.
this fails since we do not instantiate evars
    Fail aac_rewrite idem.
  Abort.

End evars.

Distinction between aac_rewrite and aacu_rewrite


Section U.
  Context {X} {R} {E: @Equivalence X R}
   {dot} {dot_A: Associative R dot} {dot_Proper: Proper (R ==> R ==> R) dot}
   {one} {One: Unit R dot one}.

  Infix "==" := R (at level 70).
  Infix "*" := dot.
  Notation "1" := one.

in some situations, the aac_rewrite tactic allows instantiations of a variable with a unit, when the variable occurs directly under a function symbol:
  Variable f : X -> X.
  Hypothesis Hf : Proper (R ==> R) f.
  Hypothesis dot_inv_left : forall x, f x*x == x.

  Goal f 1 == 1.
    aac_rewrite dot_inv_left. reflexivity.
  Qed.

this behaviour seems desirable in most situations: these solutions with units are less peculiar than the other ones, since the unit comes from the goal; however, this policy is not properly enforced for now (hard to do with the current algorithm):
  Hypothesis dot_inv_right : forall x, x*f x == x.

  Goal f 1 == 1.
    Fail aac_rewrite dot_inv_right.
    aacu_rewrite dot_inv_right. reflexivity.
  Qed.

End U.

Rewriting units

Section V.
  Context {X} {R} {E: @Equivalence X R}
  {dot} {dot_A: Associative R dot} {dot_Proper: Proper (R ==> R ==> R) dot}
  {one} {One: Unit R dot one}.

  Infix "==" := R (at level 70).
  Infix "*" := dot.
  Notation "1" := one.

aac_rewrite uses the symbols appearing in the goal and the hypothesis to infer the AC and A operations. In the following example, dot appears neither in the left-hand-side of the goal, nor in the right-hand side of the hypothesis. Hence, 1 is not recognised as a unit. To circumvent this problem, we can force aac_rewrite to take into account a given operation, by giving it an extra argument. This extra argument seems useful only in this peculiar case.

  Lemma inv_unique: forall x y y', x*y == 1 -> y'*x == 1 -> y==y'.
  Proof.
    intros x y y' Hxy Hy'x.
    aac_instances <- Hy'x [dot].
    aac_rewrite <- Hy'x at 1 [dot].
    aac_rewrite Hxy. aac_reflexivity.
  Qed.

End V.

Rewriting too many things


Section W.
  Import Instances.Peano.

  Variables a b c: nat.
  Hypothesis H: 0 = c.

  Goal b*(a+a) <= b*(c+a+a+1).
aac_rewrite finds a pattern modulo AC that matches a given hypothesis, and then makes a call to setoid_rewrite. This setoid_rewrite can unfortunately make several rewrites (in a non-intuitive way: below, the 1 in the right-hand side is rewritten into S c)
    aac_rewrite H.
to this end, we provide a companion tactic to aac_rewrite and aacu_rewrite, that makes the transitivity step, but not the setoid_rewrite; this allows the user to select the relevant occurrences in which to rewrite:
    aac_pattern H at 2. setoid_rewrite H at 1.
  Abort.

End W.

Rewriting nullifiable patterns


Section Z.
  Import Instances.Peano.

If the pattern of the rewritten hypothesis does not contain "hard" symbols (like constants, function symbols, AC or A symbols without units), there can be infinitely many subterms such that the pattern matches: it is possible to build "subterms" modulo ACU that make the size of the term increase (by making neutral elements appear in a layered fashion). Hence, we settled with heuristics to propose only "some" of these solutions. In such cases, the tactic displays a (conservative) warning.

  Variables a b c: nat.
  Variable f: nat -> nat.
  Hypothesis H0: forall x, 0 = x - x.
  Hypothesis H1: forall x, 1 = x * x.

  Goal a + b * c = c.
    aac_instances H0.
in this case, only three solutions are proposed, while there are infinitely many solutions, for example:
  • a+b*c*(1+)
  • a+b*c*(1+0*(1+ ))
  • ...
  Abort.

If the pattern is a unit or can be instantiated to be equal to a unit

The heuristic is to make the unit appear at each possible position in the term, e.g. transforming a into 1*a and a*1, but this process is not recursive (we will not transform 1*a) into (1+0*1)*a.

  Goal a+b+c = c.
    aac_instances H0 [mult].
1 solution, we miss solutions like (a+b+c*(1+0*(1+[]))) and so on
    aac_instances H1 [mult].
7 solutions, we miss solutions like (a+b+c+0*(1+0*[]))
  Abort.

Another example of the former case

In the following, the hypothesis can be instantiated to be equal to 1.

  Hypothesis H : forall x y, (x+y)*x = x*x + y*x.

  Goal a*a+b*a + c = c.
here, only one solution if we use the aac_instance tactic
    aac_instances <- H.
there are 8 solutions using aacu_instances (but, here, there are infinitely many different solutions); we miss, e.g., a*a +b*a + (x*x + y*x)*c, which seems to be more peculiar
    aacu_instances <- H.
the 7 last solutions are the same as if we were matching 1
    aacu_instances H1.
  Abort.

The behavior of the tactic is not satisfying in this case. It is still unclear how to handle properly this kind of situation; we plan to investigate this in the future.
End Z.