aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--plugins/romega/ReflOmegaCore.v208
-rw-r--r--plugins/romega/const_omega.ml3
-rw-r--r--plugins/romega/const_omega.mli3
-rw-r--r--plugins/romega/refl_omega.ml34
4 files changed, 134 insertions, 114 deletions
diff --git a/plugins/romega/ReflOmegaCore.v b/plugins/romega/ReflOmegaCore.v
index f95cfe364..d242264a9 100644
--- a/plugins/romega/ReflOmegaCore.v
+++ b/plugins/romega/ReflOmegaCore.v
@@ -75,6 +75,18 @@ Module Type Int.
(** Btw, lt_0_1 could be deduced from this last axiom *)
+ (** Now we also require a division function.
+ It is deliberately underspecified, since that's enough
+ for the proofs below. But the most appropriate variant
+ (and the one needed to stay in sync with the omega engine)
+ is "Floor" (the historical version of Coq's [Z.div]). *)
+
+ Parameter diveucl : t -> t -> t * t.
+ Notation "i / j" := (fst (diveucl i j)).
+ Notation "i 'mod' j" := (snd (diveucl i j)).
+ Axiom diveucl_spec :
+ forall i j, j<>0 -> i = j * (i/j) + (i mod j).
+
End Int.
@@ -133,6 +145,9 @@ Module Z_as_Int <: Int.
Definition le_lt_int := Z.lt_le_pred.
+ Definition diveucl := Z.div_eucl.
+ Definition diveucl_spec := Z.div_mod.
+
End Z_as_Int.
@@ -1124,6 +1139,50 @@ Proof.
rewrite IHt2. simpl. apply plus_assoc.
Qed.
+(** Division by a constant
+
+ All the non-constant coefficients should be exactly dividable *)
+
+Fixpoint scalar_div (t : term) (k : int) : option (term * int) :=
+ match t with
+ | v * Tint x + l =>
+ let (q,r) := diveucl x k in
+ if (r =? 0)%I then
+ match scalar_div l k with
+ | None => None
+ | Some (u,c) => Some (v * Tint q + u, c)
+ end
+ else None
+ | Tint x =>
+ let (q,r) := diveucl x k in
+ Some (Tint q, r)
+ | _ => None
+ end%term.
+
+Lemma scalar_div_stable e t k u c : k<>0 ->
+ scalar_div t k = Some (u,c) ->
+ interp_term e (u * Tint k + Tint c) = interp_term e t.
+Proof.
+ revert u c.
+ induction t; simpl; Simplify; try easy.
+ - intros u c Hk. assert (H := diveucl_spec t0 k Hk).
+ simpl in H.
+ destruct diveucl as (q,r). simpl in H. rewrite H.
+ injection 1 as <- <-. simpl. f_equal. apply mult_comm.
+ - intros u c Hk.
+ destruct t1; simpl; Simplify; try easy.
+ destruct t1_2; simpl; Simplify; try easy.
+ assert (H := diveucl_spec t0 k Hk).
+ simpl in H.
+ destruct diveucl as (q,r). simpl in H. rewrite H.
+ case beq_reflect; [intros -> | easy].
+ destruct (scalar_div t2 k) as [(u',c')|] eqn:E; [|easy].
+ injection 1 as <- ->. simpl.
+ rewrite <- (IHt2 u' c Hk); simpl; auto.
+ rewrite plus_0_r , (mult_comm k q). symmetry. apply OMEGA11.
+Qed.
+
+
(** Fusion of two equations.
From two normalized equations, this fusion will produce
@@ -1337,16 +1396,15 @@ Qed.
First, the final steps leading to a contradiction:
- [O_BAD_CONSTANT i] : hypothesis i has a constant body
and this constant is not compatible with the kind of i.
- - [O_NOT_EXACT_DIVIDE i k1 k2 t] :
- equation i has a body equivalent to [k1*t+k2] with [0<k2<k1].
+ - [O_NOT_EXACT_DIVIDE i k] :
+ equation i can be factorized as some [k*t+c] with [0<c<k].
Now, the intermediate steps leading to a new hypothesis:
- - [O_EXACT_DIVIDE i k1 t cont] :
- (dis)equation i has a body equivalent to [k1*t] with [k1<>0],
- we change it (in-place) for (dis)equation [0=t].
- - [O_DIV_APPROX i k1 k2 t cont] :
- inequation i has a body equivalent to [k1*t+k2] with [0<k1]
- and [k2<k1], we change it (in-place) for inequation [0<=t].
+ - [O_DIVIDE i k cont] :
+ the body of hypothesis i could be factorized as [k*t+c]
+ with either [k<>0] and [c=0] for a (dis)equation, or
+ [0<k] and [c<k] for an inequation. We change in-place the
+ body of i for [t].
- [O_SUM k1 i1 k2 i2 cont] : creates a new hypothesis whose
kind depends on the kind of hypotheses [i1] and [i2], and
whose body is [k1*body(i1) + k2*body(i2)]. Depending of the
@@ -1362,10 +1420,9 @@ Definition idx := nat. (** Index of an hypothesis in the list *)
Inductive t_omega : Set :=
| O_BAD_CONSTANT : idx -> t_omega
- | O_NOT_EXACT_DIVIDE : idx -> int -> int -> term -> t_omega
+ | O_NOT_EXACT_DIVIDE : idx -> int -> t_omega
- | O_EXACT_DIVIDE : idx -> int -> term -> t_omega -> t_omega
- | O_DIV_APPROX : idx -> int -> int -> term -> t_omega -> t_omega
+ | O_DIVIDE : idx -> int -> t_omega -> t_omega
| O_SUM : int -> idx -> int -> idx -> t_omega -> t_omega
| O_MERGE_EQ : idx -> idx -> t_omega -> t_omega
| O_SPLIT_INEQ : idx -> t_omega -> t_omega -> t_omega.
@@ -1391,84 +1448,84 @@ Proof.
rewrite le_lt_iff. intuition.
Qed.
-(** [NOT_EXACT_DIVIDE] *)
+(** [O_NOT_EXACT_DIVIDE] *)
-Definition not_exact_divide (i : nat) (k1 k2 : int) (body : term)
- (l : hyps) :=
+Definition not_exact_divide (i : nat) (k : int) (l : hyps) :=
match nth_hyps i l with
| EqTerm (Tint Nul) b =>
- if (Nul =? 0) &&
- (scalar_mult_add body k1 k2 =? b)%term &&
- (0 <? k2) &&
- (k2 <? k1)
- then absurd
+ match scalar_div b k with
+ | Some (body,c) =>
+ if (Nul =? 0) && (0 <? c) && (c <? k) then absurd
else l
+ | None => l
+ end
| _ => l
end.
-Theorem not_exact_divide_valid :
- forall (i : nat)(k1 k2 : int) (body : term),
- valid_hyps (not_exact_divide i k1 k2 body).
+Theorem not_exact_divide_valid i k :
+ valid_hyps (not_exact_divide i k).
Proof.
unfold valid_hyps, not_exact_divide; intros.
- generalize (nth_valid ep e i lp); Simplify.
- rewrite <-H1, scalar_mult_add_stable. simpl.
- intros.
- absurd (interp_term e body * k1 + k2 = 0).
- - now apply OMEGA4.
- - symmetry; auto.
+ generalize (nth_valid ep e i lp).
+ destruct (nth_hyps i lp); simpl; auto.
+ destruct t0; auto.
+ destruct (scalar_div t1 k) as [(body,c)|] eqn:E; auto.
+ Simplify.
+ assert (k <> 0).
+ { intro. apply (lt_not_eq 0 k); eauto using lt_trans. }
+ apply (scalar_div_stable e) in E; auto. simpl in E.
+ intros H'; rewrite <- H' in E; auto.
+ exfalso. revert E. now apply OMEGA4.
Qed.
(** Now, the steps generating a new equation. *)
-(** [O_EXACT_DIVIDE] *)
+(** [O_DIVIDE] *)
-Definition exact_divide (k : int) (body : term) (prop : proposition) :=
+Definition divide (k : int) (prop : proposition) :=
match prop with
| EqTerm (Tint o) b =>
- if (o =? 0) && (scalar_mult body k =? b)%term && negb (k =? 0)
- then EqTerm (Tint 0) body
- else TrueTerm
+ match scalar_div b k with
+ | Some (body,c) =>
+ if (o =? 0) && (c =? 0) && negb (k =? 0)
+ then EqTerm (Tint 0) body
+ else TrueTerm
+ | None => TrueTerm
+ end
| NeqTerm (Tint o) b =>
- if (o =? 0) && (scalar_mult body k =? b)%term && negb (k =? 0)
- then NeqTerm (Tint 0) body
- else TrueTerm
- | _ => TrueTerm
- end.
-
-Theorem exact_divide_valid :
- forall (k : int) (t : term), valid1 (exact_divide k t).
-Proof.
- unfold valid1, exact_divide; intros k t ep e p1;
- Simplify; simpl; auto; subst;
- rewrite scalar_mult_stable; simpl; intros.
- - destruct (mult_integral _ _ (eq_sym H0)); intuition.
- - contradict H0; rewrite <- H0, mult_0_l; auto.
-Qed.
-
-(** [O_DIV_APPROX] *)
-
-Definition divide_and_approx (k1 k2 : int) (body : term)
- (prop : proposition) :=
- match prop with
+ match scalar_div b k with
+ | Some (body,c) =>
+ if (o =? 0) && (c =? 0) && negb (k =? 0)
+ then NeqTerm (Tint 0) body
+ else TrueTerm
+ | None => TrueTerm
+ end
| LeqTerm (Tint o) b =>
- if (o =? 0) &&
- (scalar_mult_add body k1 k2 =? b)%term &&
- (0 <? k1) &&
- (k2 <? k1)
+ match scalar_div b k with
+ | Some (body,c) =>
+ if (o =? 0) && (0 <? k) && (c <? k)
then LeqTerm (Tint 0) body
else prop
- | _ => prop
+ | None => prop
+ end
+ | _ => TrueTerm
end.
-Theorem divide_and_approx_valid :
- forall (k1 k2 : int) (body : term),
- valid1 (divide_and_approx k1 k2 body).
+Theorem divide_valid k : valid1 (divide k).
Proof.
- unfold valid1, divide_and_approx.
- intros k1 k2 body ep e p1. Simplify. subst.
- rewrite scalar_mult_add_stable. simpl.
- intro H; now apply mult_le_approx with (3 := H).
+ unfold valid1, divide; intros ep e p;
+ destruct p; simpl; auto;
+ destruct t0; simpl; auto;
+ destruct scalar_div as [(body,c)|] eqn:E; simpl; Simplify; auto.
+ - apply (scalar_div_stable e) in E; auto. simpl in E.
+ intros H'; rewrite <- H' in E. rewrite plus_0_r in E.
+ apply mult_integral in E. intuition.
+ - apply (scalar_div_stable e) in E; auto. simpl in E.
+ intros H' H''. now rewrite <- H'', mult_0_l, plus_0_l in E.
+ - assert (k <> 0).
+ { intro. apply (lt_not_eq 0 k); eauto using lt_trans. }
+ apply (scalar_div_stable e) in E; auto. simpl in E. rewrite <- E.
+ intro H'. now apply mult_le_approx with (3 := H').
Qed.
(** [O_SUM]. Invariant: [k1] and [k2] non-nul. *)
@@ -1591,12 +1648,9 @@ Qed.
Fixpoint execute_omega (t : t_omega) (l : hyps) : lhyps :=
match t with
| O_BAD_CONSTANT i => singleton (bad_constant i l)
- | O_NOT_EXACT_DIVIDE i k1 k2 body =>
- singleton (not_exact_divide i k1 k2 body l)
- | O_EXACT_DIVIDE n k body cont =>
- execute_omega cont (apply_oper_1 n (exact_divide k body) l)
- | O_DIV_APPROX n k1 k2 body cont =>
- execute_omega cont (apply_oper_1 n (divide_and_approx k1 k2 body) l)
+ | O_NOT_EXACT_DIVIDE i k => singleton (not_exact_divide i k l)
+ | O_DIVIDE i k cont =>
+ execute_omega cont (apply_oper_1 i (divide k) l)
| O_SUM k1 i1 k2 i2 cont =>
execute_omega cont (apply_oper_2 i1 i2 (sum k1 k2) l)
| O_MERGE_EQ i1 i2 cont =>
@@ -1610,14 +1664,10 @@ Proof.
simple induction tr; unfold valid_list_hyps, valid_hyps; simpl.
- intros; left; now apply bad_constant_valid.
- intros; left; now apply not_exact_divide_valid.
- - intros m k body t' Ht' ep e lp H; apply Ht';
- apply
- (apply_oper_1_valid m (exact_divide k body)
- (exact_divide_valid k body) ep e lp H).
- - intros m k1 k2 body t' Ht' ep e lp H; apply Ht';
+ - intros m k t' Ht' ep e lp H; apply Ht';
apply
- (apply_oper_1_valid m (divide_and_approx k1 k2 body)
- (divide_and_approx_valid k1 k2 body) ep e lp H).
+ (apply_oper_1_valid m (divide k)
+ (divide_valid k) ep e lp H).
- intros k1 i1 k2 i2 t' Ht' ep e lp H; apply Ht';
apply
(apply_oper_2_valid i1 i2 (sum k1 k2) (sum_valid k1 k2) ep e
diff --git a/plugins/romega/const_omega.ml b/plugins/romega/const_omega.ml
index ce47ef16a..a10ce68b4 100644
--- a/plugins/romega/const_omega.ml
+++ b/plugins/romega/const_omega.ml
@@ -102,9 +102,8 @@ let coq_p_imp = lazy (constant "Timp")
let coq_p_prop = lazy (constant "Tprop")
let coq_s_bad_constant = lazy (constant "O_BAD_CONSTANT")
-let coq_s_div_approx = lazy (constant "O_DIV_APPROX")
+let coq_s_divide = lazy (constant "O_DIVIDE")
let coq_s_not_exact_divide = lazy (constant "O_NOT_EXACT_DIVIDE")
-let coq_s_exact_divide = lazy (constant "O_EXACT_DIVIDE")
let coq_s_sum = lazy (constant "O_SUM")
let coq_s_merge_eq = lazy (constant "O_MERGE_EQ")
let coq_s_split_ineq =lazy (constant "O_SPLIT_INEQ")
diff --git a/plugins/romega/const_omega.mli b/plugins/romega/const_omega.mli
index b4599c831..ca23ed6c4 100644
--- a/plugins/romega/const_omega.mli
+++ b/plugins/romega/const_omega.mli
@@ -43,9 +43,8 @@ val coq_p_imp : Term.constr lazy_t
val coq_p_prop : Term.constr lazy_t
val coq_s_bad_constant : Term.constr lazy_t
-val coq_s_div_approx : Term.constr lazy_t
+val coq_s_divide : Term.constr lazy_t
val coq_s_not_exact_divide : Term.constr lazy_t
-val coq_s_exact_divide : Term.constr lazy_t
val coq_s_sum : Term.constr lazy_t
val coq_s_merge_eq : Term.constr lazy_t
val coq_s_split_ineq : Term.constr lazy_t
diff --git a/plugins/romega/refl_omega.ml b/plugins/romega/refl_omega.ml
index 6ef53837c..e56605076 100644
--- a/plugins/romega/refl_omega.ml
+++ b/plugins/romega/refl_omega.ml
@@ -365,23 +365,6 @@ let reified_of_proposition env f =
let reified_of_eq env (l,r) =
app coq_p_eq [| reified_of_formula env l; reified_of_formula env r |]
-(* \subsection{Omega vers COQ réifié} *)
-
-let reified_of_omega env body constant =
- let coeff_constant =
- app coq_t_int [| Z.mk constant |] in
- let mk_coeff {c;v} t =
- let coef =
- app coq_t_mult
- [| reified_of_formula env (Oatom v);
- app coq_t_int [| Z.mk c |] |] in
- app coq_t_plus [|coef; t |] in
- List.fold_right mk_coeff body coeff_constant
-
-let reified_of_omega env body c =
- try reified_of_omega env body c
- with reraise -> display_eq display_omega_var (body,c); raise reraise
-
(* \section{Opérations sur les équations}
Ces fonctions préparent les traces utilisées par la tactique réfléchie
pour faire des opérations de normalisation sur les équations. *)
@@ -873,23 +856,12 @@ let rec reify_trace env env_hyp = function
| CONTRADICTION (e1,e2) :: [] ->
sum_bad false (hyp_idx env_hyp e1.id) (hyp_idx env_hyp e2.id)
| NOT_EXACT_DIVIDE (e1,k) :: [] ->
- let e2_constant = floor_div e1.constant k in
- let d = e1.constant - e2_constant * k in
- let e2_body = map_eq_linear (fun c -> c / k) e1.body in
mkApp (Lazy.force coq_s_not_exact_divide,
- [| hyp_idx env_hyp e1.id; Z.mk k; Z.mk d;
- reified_of_omega env e2_body e2_constant |])
- | DIVIDE_AND_APPROX (e1,e2,k,d) :: l ->
- mkApp (Lazy.force coq_s_div_approx,
- [| hyp_idx env_hyp e1.id; Z.mk k; Z.mk d;
- reified_of_omega env e2.body e2.constant;
- reify_trace env env_hyp l |])
+ [| hyp_idx env_hyp e1.id; Z.mk k |])
+ | DIVIDE_AND_APPROX (e1,_,k,_) :: l
| EXACT_DIVIDE (e1,k) :: l ->
- let e2_body = map_eq_linear (fun c -> c / k) e1.body in
- let e2_constant = floor_div e1.constant k in
- mkApp (Lazy.force coq_s_exact_divide,
+ mkApp (Lazy.force coq_s_divide,
[| hyp_idx env_hyp e1.id; Z.mk k;
- reified_of_omega env e2_body e2_constant;
reify_trace env env_hyp l |])
| MERGE_EQ(e3,e1,e2) :: l ->
mkApp (Lazy.force coq_s_merge_eq,