From 7d220f8b61649646692983872626d6a8042446a9 Mon Sep 17 00:00:00 2001 From: letouzey Date: Fri, 20 Mar 2009 01:22:58 +0000 Subject: Directory 'contrib' renamed into 'plugins', to end confusion with archive of user contribs git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@11996 85f007b7-540e-0410-9357-904b9bb8a0f7 --- plugins/fourier/Fourier.v | 21 ++ plugins/fourier/Fourier_util.v | 222 +++++++++++++ plugins/fourier/fourier.ml | 205 ++++++++++++ plugins/fourier/fourierR.ml | 629 +++++++++++++++++++++++++++++++++++ plugins/fourier/fourier_plugin.mllib | 3 + plugins/fourier/g_fourier.ml4 | 17 + 6 files changed, 1097 insertions(+) create mode 100644 plugins/fourier/Fourier.v create mode 100644 plugins/fourier/Fourier_util.v create mode 100644 plugins/fourier/fourier.ml create mode 100644 plugins/fourier/fourierR.ml create mode 100644 plugins/fourier/fourier_plugin.mllib create mode 100644 plugins/fourier/g_fourier.ml4 (limited to 'plugins/fourier') diff --git a/plugins/fourier/Fourier.v b/plugins/fourier/Fourier.v new file mode 100644 index 000000000..07b2973a4 --- /dev/null +++ b/plugins/fourier/Fourier.v @@ -0,0 +1,21 @@ +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* 0 < a -> a * x1 < a * y1. +intros; apply Rmult_lt_compat_l; assumption. +Qed. + +Lemma Rfourier_le : forall x1 y1 a:R, x1 <= y1 -> 0 < a -> a * x1 <= a * y1. +red in |- *. +intros. +case H; auto with real. +Qed. + +Lemma Rfourier_lt_lt : + forall x1 y1 x2 y2 a:R, + x1 < y1 -> x2 < y2 -> 0 < a -> x1 + a * x2 < y1 + a * y2. +intros x1 y1 x2 y2 a H H0 H1; try assumption. +apply Rplus_lt_compat. +try exact H. +apply Rfourier_lt. +try exact H0. +try exact H1. +Qed. + +Lemma Rfourier_lt_le : + forall x1 y1 x2 y2 a:R, + x1 < y1 -> x2 <= y2 -> 0 < a -> x1 + a * x2 < y1 + a * y2. +intros x1 y1 x2 y2 a H H0 H1; try assumption. +case H0; intros. +apply Rplus_lt_compat. +try exact H. +apply Rfourier_lt; auto with real. +rewrite H2. +rewrite (Rplus_comm y1 (a * y2)). +rewrite (Rplus_comm x1 (a * y2)). +apply Rplus_lt_compat_l. +try exact H. +Qed. + +Lemma Rfourier_le_lt : + forall x1 y1 x2 y2 a:R, + x1 <= y1 -> x2 < y2 -> 0 < a -> x1 + a * x2 < y1 + a * y2. +intros x1 y1 x2 y2 a H H0 H1; try assumption. +case H; intros. +apply Rfourier_lt_le; auto with real. +rewrite H2. +apply Rplus_lt_compat_l. +apply Rfourier_lt; auto with real. +Qed. + +Lemma Rfourier_le_le : + forall x1 y1 x2 y2 a:R, + x1 <= y1 -> x2 <= y2 -> 0 < a -> x1 + a * x2 <= y1 + a * y2. +intros x1 y1 x2 y2 a H H0 H1; try assumption. +case H0; intros. +red in |- *. +left; try assumption. +apply Rfourier_le_lt; auto with real. +rewrite H2. +case H; intros. +red in |- *. +left; try assumption. +rewrite (Rplus_comm x1 (a * y2)). +rewrite (Rplus_comm y1 (a * y2)). +apply Rplus_lt_compat_l. +try exact H3. +rewrite H3. +red in |- *. +right; try assumption. +auto with real. +Qed. + +Lemma Rlt_zero_pos_plus1 : forall x:R, 0 < x -> 0 < 1 + x. +intros x H; try assumption. +rewrite Rplus_comm. +apply Rle_lt_0_plus_1. +red in |- *; auto with real. +Qed. + +Lemma Rlt_mult_inv_pos : forall x y:R, 0 < x -> 0 < y -> 0 < x * / y. +intros x y H H0; try assumption. +replace 0 with (x * 0). +apply Rmult_lt_compat_l; auto with real. +ring. +Qed. + +Lemma Rlt_zero_1 : 0 < 1. +exact Rlt_0_1. +Qed. + +Lemma Rle_zero_pos_plus1 : forall x:R, 0 <= x -> 0 <= 1 + x. +intros x H; try assumption. +case H; intros. +red in |- *. +left; try assumption. +apply Rlt_zero_pos_plus1; auto with real. +rewrite <- H0. +replace (1 + 0) with 1. +red in |- *; left. +exact Rlt_zero_1. +ring. +Qed. + +Lemma Rle_mult_inv_pos : forall x y:R, 0 <= x -> 0 < y -> 0 <= x * / y. +intros x y H H0; try assumption. +case H; intros. +red in |- *; left. +apply Rlt_mult_inv_pos; auto with real. +rewrite <- H1. +red in |- *; right; ring. +Qed. + +Lemma Rle_zero_1 : 0 <= 1. +red in |- *; left. +exact Rlt_zero_1. +Qed. + +Lemma Rle_not_lt : forall n d:R, 0 <= n * / d -> ~ 0 < - n * / d. +intros n d H; red in |- *; intros H0; try exact H0. +generalize (Rgt_not_le 0 (n * / d)). +intros H1; elim H1; try assumption. +replace (n * / d) with (- - (n * / d)). +replace 0 with (- -0). +replace (- (n * / d)) with (- n * / d). +replace (-0) with 0. +red in |- *. +apply Ropp_gt_lt_contravar. +red in |- *. +exact H0. +ring. +ring. +ring. +ring. +Qed. + +Lemma Rnot_lt0 : forall x:R, ~ 0 < 0 * x. +intros x; try assumption. +replace (0 * x) with 0. +apply Rlt_irrefl. +ring. +Qed. + +Lemma Rlt_not_le_frac_opp : forall n d:R, 0 < n * / d -> ~ 0 <= - n * / d. +intros n d H; try assumption. +apply Rgt_not_le. +replace 0 with (-0). +replace (- n * / d) with (- (n * / d)). +apply Ropp_lt_gt_contravar. +try exact H. +ring. +ring. +Qed. + +Lemma Rnot_lt_lt : forall x y:R, ~ 0 < y - x -> ~ x < y. +unfold not in |- *; intros. +apply H. +apply Rplus_lt_reg_r with x. +replace (x + 0) with x. +replace (x + (y - x)) with y. +try exact H0. +ring. +ring. +Qed. + +Lemma Rnot_le_le : forall x y:R, ~ 0 <= y - x -> ~ x <= y. +unfold not in |- *; intros. +apply H. +case H0; intros. +left. +apply Rplus_lt_reg_r with x. +replace (x + 0) with x. +replace (x + (y - x)) with y. +try exact H1. +ring. +ring. +right. +rewrite H1; ring. +Qed. + +Lemma Rfourier_gt_to_lt : forall x y:R, y > x -> x < y. +unfold Rgt in |- *; intros; assumption. +Qed. + +Lemma Rfourier_ge_to_le : forall x y:R, y >= x -> x <= y. +intros x y; exact (Rge_le y x). +Qed. + +Lemma Rfourier_eqLR_to_le : forall x y:R, x = y -> x <= y. +exact Req_le. +Qed. + +Lemma Rfourier_eqRL_to_le : forall x y:R, y = x -> x <= y. +exact Req_le_sym. +Qed. + +Lemma Rfourier_not_ge_lt : forall x y:R, (x >= y -> False) -> x < y. +exact Rnot_ge_lt. +Qed. + +Lemma Rfourier_not_gt_le : forall x y:R, (x > y -> False) -> x <= y. +exact Rnot_gt_le. +Qed. + +Lemma Rfourier_not_le_gt : forall x y:R, (x <= y -> False) -> x > y. +exact Rnot_le_lt. +Qed. + +Lemma Rfourier_not_lt_ge : forall x y:R, (x < y -> False) -> x >= y. +exact Rnot_lt_ge. +Qed. diff --git a/plugins/fourier/fourier.ml b/plugins/fourier/fourier.ml new file mode 100644 index 000000000..dd54aea29 --- /dev/null +++ b/plugins/fourier/fourier.ml @@ -0,0 +1,205 @@ +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* match ie.coef with + [] -> raise (Failure "empty ineq") + |(c::r) -> if rinf c r0 + then pop ie lneg + else if rinf r0 c then pop ie lpos + else pop ie lnul) + s; + [!lneg;!lnul;!lpos] +;; +(* initialise les histoires d'une liste d'inéquations données par leurs listes de coefficients et leurs strictitudes (!): +(add_hist [(equation 1, s1);...;(équation n, sn)]) += +[{équation 1, [1;0;...;0], s1}; + {équation 2, [0;1;...;0], s2}; + ... + {équation n, [0;0;...;1], sn}] +*) +let add_hist le = + let n = List.length le in + let i=ref 0 in + List.map (fun (ie,s) -> + let h =ref [] in + for k=1 to (n-(!i)-1) do pop r0 h; done; + pop r1 h; + for k=1 to !i do pop r0 h; done; + i:=!i+1; + {coef=ie;hist=(!h);strict=s}) + le +;; +(* additionne deux inéquations *) +let ie_add ie1 ie2 = {coef=List.map2 rplus ie1.coef ie2.coef; + hist=List.map2 rplus ie1.hist ie2.hist; + strict=ie1.strict || ie2.strict} +;; +(* multiplication d'une inéquation par un rationnel (positif) *) +let ie_emult a ie = {coef=List.map (fun x -> rmult a x) ie.coef; + hist=List.map (fun x -> rmult a x) ie.hist; + strict= ie.strict} +;; +(* on enlève le premier coefficient *) +let ie_tl ie = {coef=List.tl ie.coef;hist=ie.hist;strict=ie.strict} +;; +(* le premier coefficient: "tête" de l'inéquation *) +let hd_coef ie = List.hd ie.coef +;; + +(* calcule toutes les combinaisons entre inéquations de tête négative et inéquations de tête positive qui annulent le premier coefficient. +*) +let deduce_add lneg lpos = + let res=ref [] in + List.iter (fun i1 -> + List.iter (fun i2 -> + let a = rop (hd_coef i1) in + let b = hd_coef i2 in + pop (ie_tl (ie_add (ie_emult b i1) + (ie_emult a i2))) res) + lpos) + lneg; + !res +;; +(* élimination de la première variable à partir d'une liste d'inéquations: +opération qu'on itère dans l'algorithme de Fourier. +*) +let deduce1 s = + match (partitionne s) with + [lneg;lnul;lpos] -> + let lnew = deduce_add lneg lpos in + (List.map ie_tl lnul)@lnew + |_->assert false +;; +(* algorithme de Fourier: on élimine successivement toutes les variables. +*) +let deduce lie = + let n = List.length (fst (List.hd lie)) in + let lie=ref (add_hist lie) in + for i=1 to n-1 do + lie:= deduce1 !lie; + done; + !lie +;; + +(* donne [] si le système a des solutions, +sinon donne [c,s,lc] +où lc est la combinaison linéaire des inéquations de départ +qui donne 0 < c si s=true + ou 0 <= c sinon +cette inéquation étant absurde. +*) +let unsolvable lie = + let lr = deduce lie in + let res = ref [] in + (try (List.iter (fun e -> + match e with + {coef=[c];hist=lc;strict=s} -> + if (rinf c r0 && (not s)) || (rinfeq c r0 && s) + then (res := [c,s,lc]; + raise (Failure "contradiction found")) + |_->assert false) + lr) + with _ -> ()); + !res +;; + +(* Exemples: + +let test1=[[r1;r1;r0],true;[rop r1;r1;r1],false;[r0;rop r1;rop r1],false];; +deduce test1;; +unsolvable test1;; + +let test2=[ +[r1;r1;r0;r0;r0],false; +[r0;r1;r1;r0;r0],false; +[r0;r0;r1;r1;r0],false; +[r0;r0;r0;r1;r1],false; +[r1;r0;r0;r0;r1],false; +[rop r1;rop r1;r0;r0;r0],false; +[r0;rop r1;rop r1;r0;r0],false; +[r0;r0;rop r1;rop r1;r0],false; +[r0;r0;r0;rop r1;rop r1],false; +[rop r1;r0;r0;r0;rop r1],false +];; +deduce test2;; +unsolvable test2;; + +*) diff --git a/plugins/fourier/fourierR.ml b/plugins/fourier/fourierR.ml new file mode 100644 index 000000000..908267700 --- /dev/null +++ b/plugins/fourier/fourierR.ml @@ -0,0 +1,629 @@ +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* r0;; + +let flin_add f x c = + let cx = flin_coef f x in + Hashtbl.remove f.fhom x; + Hashtbl.add f.fhom x (rplus cx c); + f +;; +let flin_add_cste f c = + {fhom=f.fhom; + fcste=rplus f.fcste c} +;; + +let flin_one () = flin_add_cste (flin_zero()) r1;; + +let flin_plus f1 f2 = + let f3 = flin_zero() in + Hashtbl.iter (fun x c -> let _=flin_add f3 x c in ()) f1.fhom; + Hashtbl.iter (fun x c -> let _=flin_add f3 x c in ()) f2.fhom; + flin_add_cste (flin_add_cste f3 f1.fcste) f2.fcste; +;; + +let flin_minus f1 f2 = + let f3 = flin_zero() in + Hashtbl.iter (fun x c -> let _=flin_add f3 x c in ()) f1.fhom; + Hashtbl.iter (fun x c -> let _=flin_add f3 x (rop c) in ()) f2.fhom; + flin_add_cste (flin_add_cste f3 f1.fcste) (rop f2.fcste); +;; +let flin_emult a f = + let f2 = flin_zero() in + Hashtbl.iter (fun x c -> let _=flin_add f2 x (rmult a c) in ()) f.fhom; + flin_add_cste f2 (rmult a f.fcste); +;; + +(*****************************************************************************) +open Vernacexpr + +type ineq = Rlt | Rle | Rgt | Rge + +let string_of_R_constant kn = + match Names.repr_con kn with + | MPfile dir, sec_dir, id when + sec_dir = empty_dirpath && + string_of_dirpath dir = "Coq.Reals.Rdefinitions" + -> string_of_label id + | _ -> "constant_not_of_R" + +let rec string_of_R_constr c = + match kind_of_term c with + Cast (c,_,_) -> string_of_R_constr c + |Const c -> string_of_R_constant c + | _ -> "not_of_constant" + +let rec rational_of_constr c = + match kind_of_term c with + | Cast (c,_,_) -> (rational_of_constr c) + | App (c,args) -> + (match (string_of_R_constr c) with + | "Ropp" -> + rop (rational_of_constr args.(0)) + | "Rinv" -> + rinv (rational_of_constr args.(0)) + | "Rmult" -> + rmult (rational_of_constr args.(0)) + (rational_of_constr args.(1)) + | "Rdiv" -> + rdiv (rational_of_constr args.(0)) + (rational_of_constr args.(1)) + | "Rplus" -> + rplus (rational_of_constr args.(0)) + (rational_of_constr args.(1)) + | "Rminus" -> + rminus (rational_of_constr args.(0)) + (rational_of_constr args.(1)) + | _ -> failwith "not a rational") + | Const kn -> + (match (string_of_R_constant kn) with + "R1" -> r1 + |"R0" -> r0 + | _ -> failwith "not a rational") + | _ -> failwith "not a rational" +;; + +let rec flin_of_constr c = + try( + match kind_of_term c with + | Cast (c,_,_) -> (flin_of_constr c) + | App (c,args) -> + (match (string_of_R_constr c) with + "Ropp" -> + flin_emult (rop r1) (flin_of_constr args.(0)) + | "Rplus"-> + flin_plus (flin_of_constr args.(0)) + (flin_of_constr args.(1)) + | "Rminus"-> + flin_minus (flin_of_constr args.(0)) + (flin_of_constr args.(1)) + | "Rmult"-> + (try (let a=(rational_of_constr args.(0)) in + try (let b = (rational_of_constr args.(1)) in + (flin_add_cste (flin_zero()) (rmult a b))) + with _-> (flin_add (flin_zero()) + args.(1) + a)) + with _-> (flin_add (flin_zero()) + args.(0) + (rational_of_constr args.(1)))) + | "Rinv"-> + let a=(rational_of_constr args.(0)) in + flin_add_cste (flin_zero()) (rinv a) + | "Rdiv"-> + (let b=(rational_of_constr args.(1)) in + try (let a = (rational_of_constr args.(0)) in + (flin_add_cste (flin_zero()) (rdiv a b))) + with _-> (flin_add (flin_zero()) + args.(0) + (rinv b))) + |_->assert false) + | Const c -> + (match (string_of_R_constant c) with + "R1" -> flin_one () + |"R0" -> flin_zero () + |_-> assert false) + |_-> assert false) + with _ -> flin_add (flin_zero()) + c + r1 +;; + +let flin_to_alist f = + let res=ref [] in + Hashtbl.iter (fun x c -> res:=(c,x)::(!res)) f; + !res +;; + +(* Représentation des hypothèses qui sont des inéquations ou des équations. +*) +type hineq={hname:constr; (* le nom de l'hypothèse *) + htype:string; (* Rlt, Rgt, Rle, Rge, eqTLR ou eqTRL *) + hleft:constr; + hright:constr; + hflin:flin; + hstrict:bool} +;; + +(* Transforme une hypothese h:t en inéquation flin<0 ou flin<=0 +*) +let ineq1_of_constr (h,t) = + match (kind_of_term t) with + App (f,args) -> + (match kind_of_term f with + Const c when Array.length args = 2 -> + let t1= args.(0) in + let t2= args.(1) in + (match (string_of_R_constant c) with + "Rlt" -> [{hname=h; + htype="Rlt"; + hleft=t1; + hright=t2; + hflin= flin_minus (flin_of_constr t1) + (flin_of_constr t2); + hstrict=true}] + |"Rgt" -> [{hname=h; + htype="Rgt"; + hleft=t2; + hright=t1; + hflin= flin_minus (flin_of_constr t2) + (flin_of_constr t1); + hstrict=true}] + |"Rle" -> [{hname=h; + htype="Rle"; + hleft=t1; + hright=t2; + hflin= flin_minus (flin_of_constr t1) + (flin_of_constr t2); + hstrict=false}] + |"Rge" -> [{hname=h; + htype="Rge"; + hleft=t2; + hright=t1; + hflin= flin_minus (flin_of_constr t2) + (flin_of_constr t1); + hstrict=false}] + |_->assert false) + | Ind (kn,i) -> + if IndRef(kn,i) = Coqlib.glob_eq then + let t0= args.(0) in + let t1= args.(1) in + let t2= args.(2) in + (match (kind_of_term t0) with + Const c -> + (match (string_of_R_constant c) with + "R"-> + [{hname=h; + htype="eqTLR"; + hleft=t1; + hright=t2; + hflin= flin_minus (flin_of_constr t1) + (flin_of_constr t2); + hstrict=false}; + {hname=h; + htype="eqTRL"; + hleft=t2; + hright=t1; + hflin= flin_minus (flin_of_constr t2) + (flin_of_constr t1); + hstrict=false}] + |_-> assert false) + |_-> assert false) + else + assert false + |_-> assert false) + |_-> assert false +;; + +(* Applique la méthode de Fourier à une liste d'hypothèses (type hineq) +*) + +let fourier_lineq lineq1 = + let nvar=ref (-1) in + let hvar=Hashtbl.create 50 in (* la table des variables des inéquations *) + List.iter (fun f -> + Hashtbl.iter (fun x _ -> if not (Hashtbl.mem hvar x) then begin + nvar:=(!nvar)+1; + Hashtbl.add hvar x (!nvar) + end) + f.hflin.fhom) + lineq1; + let sys= List.map (fun h-> + let v=Array.create ((!nvar)+1) r0 in + Hashtbl.iter (fun x c -> v.(Hashtbl.find hvar x)<-c) + h.hflin.fhom; + ((Array.to_list v)@[rop h.hflin.fcste],h.hstrict)) + lineq1 in + unsolvable sys +;; + +(*********************************************************************) +(* Defined constants *) + +let get = Lazy.force +let constant = Coqlib.gen_constant "Fourier" + +(* Standard library *) +open Coqlib +let coq_sym_eqT = lazy (build_coq_eq_sym ()) +let coq_False = lazy (build_coq_False ()) +let coq_not = lazy (build_coq_not ()) +let coq_eq = lazy (build_coq_eq ()) + +(* Rdefinitions *) +let constant_real = constant ["Reals";"Rdefinitions"] + +let coq_Rlt = lazy (constant_real "Rlt") +let coq_Rgt = lazy (constant_real "Rgt") +let coq_Rle = lazy (constant_real "Rle") +let coq_Rge = lazy (constant_real "Rge") +let coq_R = lazy (constant_real "R") +let coq_Rminus = lazy (constant_real "Rminus") +let coq_Rmult = lazy (constant_real "Rmult") +let coq_Rplus = lazy (constant_real "Rplus") +let coq_Ropp = lazy (constant_real "Ropp") +let coq_Rinv = lazy (constant_real "Rinv") +let coq_R0 = lazy (constant_real "R0") +let coq_R1 = lazy (constant_real "R1") + +(* RIneq *) +let coq_Rinv_1 = lazy (constant ["Reals";"RIneq"] "Rinv_1") + +(* Fourier_util *) +let constant_fourier = constant ["fourier";"Fourier_util"] + +let coq_Rlt_zero_1 = lazy (constant_fourier "Rlt_zero_1") +let coq_Rlt_zero_pos_plus1 = lazy (constant_fourier "Rlt_zero_pos_plus1") +let coq_Rle_zero_pos_plus1 = lazy (constant_fourier "Rle_zero_pos_plus1") +let coq_Rlt_mult_inv_pos = lazy (constant_fourier "Rlt_mult_inv_pos") +let coq_Rle_zero_zero = lazy (constant_fourier "Rle_zero_zero") +let coq_Rle_zero_1 = lazy (constant_fourier "Rle_zero_1") +let coq_Rle_mult_inv_pos = lazy (constant_fourier "Rle_mult_inv_pos") +let coq_Rnot_lt0 = lazy (constant_fourier "Rnot_lt0") +let coq_Rle_not_lt = lazy (constant_fourier "Rle_not_lt") +let coq_Rfourier_gt_to_lt = lazy (constant_fourier "Rfourier_gt_to_lt") +let coq_Rfourier_ge_to_le = lazy (constant_fourier "Rfourier_ge_to_le") +let coq_Rfourier_eqLR_to_le = lazy (constant_fourier "Rfourier_eqLR_to_le") +let coq_Rfourier_eqRL_to_le = lazy (constant_fourier "Rfourier_eqRL_to_le") + +let coq_Rfourier_not_ge_lt = lazy (constant_fourier "Rfourier_not_ge_lt") +let coq_Rfourier_not_gt_le = lazy (constant_fourier "Rfourier_not_gt_le") +let coq_Rfourier_not_le_gt = lazy (constant_fourier "Rfourier_not_le_gt") +let coq_Rfourier_not_lt_ge = lazy (constant_fourier "Rfourier_not_lt_ge") +let coq_Rfourier_lt = lazy (constant_fourier "Rfourier_lt") +let coq_Rfourier_le = lazy (constant_fourier "Rfourier_le") +let coq_Rfourier_lt_lt = lazy (constant_fourier "Rfourier_lt_lt") +let coq_Rfourier_lt_le = lazy (constant_fourier "Rfourier_lt_le") +let coq_Rfourier_le_lt = lazy (constant_fourier "Rfourier_le_lt") +let coq_Rfourier_le_le = lazy (constant_fourier "Rfourier_le_le") +let coq_Rnot_lt_lt = lazy (constant_fourier "Rnot_lt_lt") +let coq_Rnot_le_le = lazy (constant_fourier "Rnot_le_le") +let coq_Rlt_not_le_frac_opp = lazy (constant_fourier "Rlt_not_le_frac_opp") + +(****************************************************************************** +Construction de la preuve en cas de succès de la méthode de Fourier, +i.e. on obtient une contradiction. +*) +let is_int x = (x.den)=1 +;; + +(* fraction = couple (num,den) *) +let rec rational_to_fraction x= (x.num,x.den) +;; + +(* traduction -3 -> (Ropp (Rplus R1 (Rplus R1 R1))) +*) +let int_to_real n = + let nn=abs n in + if nn=0 + then get coq_R0 + else + (let s=ref (get coq_R1) in + for i=1 to (nn-1) do s:=mkApp (get coq_Rplus,[|get coq_R1;!s|]) done; + if n<0 then mkApp (get coq_Ropp, [|!s|]) else !s) +;; +(* -1/2 -> (Rmult (Ropp R1) (Rinv (Rplus R1 R1))) +*) +let rational_to_real x = + let (n,d)=rational_to_fraction x in + mkApp (get coq_Rmult, + [|int_to_real n;mkApp(get coq_Rinv,[|int_to_real d|])|]) +;; + +(* preuve que 0 False +*) +let tac_zero_inf_false gl (n,d) = + if n=0 then (apply (get coq_Rnot_lt0)) + else + (tclTHEN (apply (get coq_Rle_not_lt)) + (tac_zero_infeq_pos gl (-n,d))) +;; + +(* preuve que 0<=(-n)*(1/d) => False +*) +let tac_zero_infeq_false gl (n,d) = + (tclTHEN (apply (get coq_Rlt_not_le_frac_opp)) + (tac_zero_inf_pos gl (-n,d))) +;; + +let create_meta () = mkMeta(Evarutil.new_meta());; + +let my_cut c gl= + let concl = pf_concl gl in + apply_type (mkProd(Anonymous,c,concl)) [create_meta()] gl +;; + +let exact = exact_check;; + +let tac_use h = match h.htype with + "Rlt" -> exact h.hname + |"Rle" -> exact h.hname + |"Rgt" -> (tclTHEN (apply (get coq_Rfourier_gt_to_lt)) + (exact h.hname)) + |"Rge" -> (tclTHEN (apply (get coq_Rfourier_ge_to_le)) + (exact h.hname)) + |"eqTLR" -> (tclTHEN (apply (get coq_Rfourier_eqLR_to_le)) + (exact h.hname)) + |"eqTRL" -> (tclTHEN (apply (get coq_Rfourier_eqRL_to_le)) + (exact h.hname)) + |_->assert false +;; + +(* +let is_ineq (h,t) = + match (kind_of_term t) with + App (f,args) -> + (match (string_of_R_constr f) with + "Rlt" -> true + | "Rgt" -> true + | "Rle" -> true + | "Rge" -> true +(* Wrong:not in Rdefinitions: *) | "eqT" -> + (match (string_of_R_constr args.(0)) with + "R" -> true + | _ -> false) + | _ ->false) + |_->false +;; +*) + +let list_of_sign s = List.map (fun (x,_,z)->(x,z)) s;; + +let mkAppL a = + let l = Array.to_list a in + mkApp(List.hd l, Array.of_list (List.tl l)) +;; + +(* Résolution d'inéquations linéaires dans R *) +let rec fourier gl= + Coqlib.check_required_library ["Coq";"fourier";"Fourier"]; + let goal = strip_outer_cast (pf_concl gl) in + let fhyp=id_of_string "new_hyp_for_fourier" in + (* si le but est une inéquation, on introduit son contraire, + et le but à prouver devient False *) + try (let tac = + match (kind_of_term goal) with + App (f,args) -> + (match (string_of_R_constr f) with + "Rlt" -> + (tclTHEN + (tclTHEN (apply (get coq_Rfourier_not_ge_lt)) + (intro_using fhyp)) + fourier) + |"Rle" -> + (tclTHEN + (tclTHEN (apply (get coq_Rfourier_not_gt_le)) + (intro_using fhyp)) + fourier) + |"Rgt" -> + (tclTHEN + (tclTHEN (apply (get coq_Rfourier_not_le_gt)) + (intro_using fhyp)) + fourier) + |"Rge" -> + (tclTHEN + (tclTHEN (apply (get coq_Rfourier_not_lt_ge)) + (intro_using fhyp)) + fourier) + |_->assert false) + |_->assert false + in tac gl) + with _ -> + (* les hypothèses *) + let hyps = List.map (fun (h,t)-> (mkVar h,t)) + (list_of_sign (pf_hyps gl)) in + let lineq =ref [] in + List.iter (fun h -> try (lineq:=(ineq1_of_constr h)@(!lineq)) + with _ -> ()) + hyps; + (* lineq = les inéquations découlant des hypothèses *) + if !lineq=[] then Util.error "No inequalities"; + let res=fourier_lineq (!lineq) in + let tac=ref tclIDTAC in + if res=[] + then Util.error "fourier failed" + (* l'algorithme de Fourier a réussi: on va en tirer une preuve Coq *) + else (match res with + [(cres,sres,lc)]-> + (* lc=coefficients multiplicateurs des inéquations + qui donnent 0 + if c<>r0 + then (lutil:=(h,c)::(!lutil)(*; + print_rational(c);print_string " "*))) + (List.combine (!lineq) lc); + (* on construit la combinaison linéaire des inéquation *) + (match (!lutil) with + (h1,c1)::lutil -> + let s=ref (h1.hstrict) in + let t1=ref (mkAppL [|get coq_Rmult; + rational_to_real c1; + h1.hleft|]) in + let t2=ref (mkAppL [|get coq_Rmult; + rational_to_real c1; + h1.hright|]) in + List.iter (fun (h,c) -> + s:=(!s)||(h.hstrict); + t1:=(mkAppL [|get coq_Rplus; + !t1; + mkAppL [|get coq_Rmult; + rational_to_real c; + h.hleft|] |]); + t2:=(mkAppL [|get coq_Rplus; + !t2; + mkAppL [|get coq_Rmult; + rational_to_real c; + h.hright|] |])) + lutil; + let ineq=mkAppL [|if (!s) then get coq_Rlt else get coq_Rle; + !t1; + !t2 |] in + let tc=rational_to_real cres in + (* puis sa preuve *) + let tac1=ref (if h1.hstrict + then (tclTHENS (apply (get coq_Rfourier_lt)) + [tac_use h1; + tac_zero_inf_pos gl + (rational_to_fraction c1)]) + else (tclTHENS (apply (get coq_Rfourier_le)) + [tac_use h1; + tac_zero_inf_pos gl + (rational_to_fraction c1)])) in + s:=h1.hstrict; + List.iter (fun (h,c)-> + (if (!s) + then (if h.hstrict + then tac1:=(tclTHENS (apply (get coq_Rfourier_lt_lt)) + [!tac1;tac_use h; + tac_zero_inf_pos gl + (rational_to_fraction c)]) + else tac1:=(tclTHENS (apply (get coq_Rfourier_lt_le)) + [!tac1;tac_use h; + tac_zero_inf_pos gl + (rational_to_fraction c)])) + else (if h.hstrict + then tac1:=(tclTHENS (apply (get coq_Rfourier_le_lt)) + [!tac1;tac_use h; + tac_zero_inf_pos gl + (rational_to_fraction c)]) + else tac1:=(tclTHENS (apply (get coq_Rfourier_le_le)) + [!tac1;tac_use h; + tac_zero_inf_pos gl + (rational_to_fraction c)]))); + s:=(!s)||(h.hstrict)) + lutil; + let tac2= if sres + then tac_zero_inf_false gl (rational_to_fraction cres) + else tac_zero_infeq_false gl (rational_to_fraction cres) + in + tac:=(tclTHENS (my_cut ineq) + [tclTHEN (change_in_concl None + (mkAppL [| get coq_not; ineq|] + )) + (tclTHEN (apply (if sres then get coq_Rnot_lt_lt + else get coq_Rnot_le_le)) + (tclTHENS (Equality.replace + (mkAppL [|get coq_Rminus;!t2;!t1|] + ) + tc) + [tac2; + (tclTHENS + (Equality.replace + (mkApp (get coq_Rinv, + [|get coq_R1|])) + (get coq_R1)) +(* en attendant Field, ça peut aider Ring de remplacer 1/1 par 1 ... *) + + [tclORELSE + (Ring.polynom []) + tclIDTAC; + (tclTHEN (apply (get coq_sym_eqT)) + (apply (get coq_Rinv_1)))] + + ) + ])); + !tac1]); + tac:=(tclTHENS (cut (get coq_False)) + [tclTHEN intro (contradiction None); + !tac]) + |_-> assert false) |_-> assert false + ); +(* ((tclTHEN !tac (tclFAIL 1 (* 1 au hasard... *))) gl) *) + (!tac gl) +(* ((tclABSTRACT None !tac) gl) *) + +;; + +(* +let fourier_tac x gl = + fourier gl +;; + +let v_fourier = add_tactic "Fourier" fourier_tac +*) + diff --git a/plugins/fourier/fourier_plugin.mllib b/plugins/fourier/fourier_plugin.mllib new file mode 100644 index 000000000..b6262f8ae --- /dev/null +++ b/plugins/fourier/fourier_plugin.mllib @@ -0,0 +1,3 @@ +Fourier +FourierR +G_fourier diff --git a/plugins/fourier/g_fourier.ml4 b/plugins/fourier/g_fourier.ml4 new file mode 100644 index 000000000..b952851fa --- /dev/null +++ b/plugins/fourier/g_fourier.ml4 @@ -0,0 +1,17 @@ +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* [ fourier ] +END -- cgit v1.2.3