1 (* Copyright (C) 2002, HELM Team.
3 * This file is part of HELM, an Hypertextual, Electronic
4 * Library of Mathematics, developed at the Computer Science
5 * Department, University of Bologna, Italy.
7 * HELM is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * HELM is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with HELM; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
28 (* La tactique Fourier ne fonctionne de manière sûre que si les coefficients
29 des inéquations et équations sont entiers. En attendant la tactique Field.
32 (*open Term // in coq/kernel
39 (******************************************************************************
40 Operations on linear combinations.
42 Opérations sur les combinaisons linéaires affines.
43 La partie homogène d'une combinaison linéaire est en fait une table de hash
44 qui donne le coefficient d'un terme du calcul des constructions,
45 qui est zéro si le terme n'y est pas.
51 The type for linear combinations
53 type flin = {fhom:(Cic.term , rational)Hashtbl.t;fcste:rational}
59 let flin_zero () = {fhom = Hashtbl.create 50;fcste=r0}
65 @return the rational associated with x (coefficient)
69 (Hashtbl.find f.fhom x)
75 Adds c to the coefficient of x
82 let cx = flin_coef f x in
83 Hashtbl.remove f.fhom x;
84 Hashtbl.add f.fhom x (rplus cx c);
93 let flin_add_cste f c =
95 fcste=rplus f.fcste c}
99 @return a empty flin with r1 in fcste
101 let flin_one () = flin_add_cste (flin_zero()) r1;;
106 let flin_plus f1 f2 =
107 let f3 = flin_zero() in
108 Hashtbl.iter (fun x c -> let _=flin_add f3 x c in ()) f1.fhom;
109 Hashtbl.iter (fun x c -> let _=flin_add f3 x c in ()) f2.fhom;
110 flin_add_cste (flin_add_cste f3 f1.fcste) f2.fcste;
116 let flin_minus f1 f2 =
117 let f3 = flin_zero() in
118 Hashtbl.iter (fun x c -> let _=flin_add f3 x c in ()) f1.fhom;
119 Hashtbl.iter (fun x c -> let _=flin_add f3 x (rop c) in ()) f2.fhom;
120 flin_add_cste (flin_add_cste f3 f1.fcste) (rop f2.fcste);
127 let f2 = flin_zero() in
128 Hashtbl.iter (fun x c -> let _=flin_add f2 x (rmult a c) in ()) f.fhom;
129 flin_add_cste f2 (rmult a f.fcste);
133 (*****************************************************************************)
137 no idea about helm parser ??????????????????????????????
139 let parse_ast = Pcoq.parse_string Pcoq.Constr.constr;;
140 let parse s = Astterm.interp_constr Evd.empty (Global.env()) (parse_ast s);;
141 let pf_parse_constr gl s =
142 Astterm.interp_constr Evd.empty (pf_env gl) (parse_ast s);;
148 @return proiection on string of t
150 let rec string_of_term t =
152 Cic.Cast (t1,t2) -> string_of_term t1
153 |Cic.Const (u,boh) -> UriManager.string_of_uri u
154 |Cic.Var (u) -> UriManager.string_of_uri u
155 | _ -> "not_of_constant"
159 let string_of_constr = string_of_term
165 @raise Failure if conversion is impossible
166 @return rational proiection of t
168 let rec rational_of_term t =
169 (* fun to apply f to the first and second rational-term of l *)
170 let rat_of_binop f l =
171 let a = List.hd l and
172 b = List.hd(List.tl l) in
173 f (rational_of_term a) (rational_of_term b)
175 (* as before, but f is unary *)
176 let rat_of_unop f l =
177 f (rational_of_term (List.hd l))
180 | Cic.Cast (t1,t2) -> (rational_of_term t1)
181 | Cic.Appl (t1::next) ->
184 (match (UriManager.string_of_uri u) with
185 "cic:/Coq/Reals/Rdefinitions/Ropp.con" ->
187 |"cic:/Coq/Reals/Rdefinitions/Rinv.con" ->
188 rat_of_unop rinv next
189 |"cic:/Coq/Reals/Rdefinitions/Rmult.con" ->
190 rat_of_binop rmult next
191 |"cic:/Coq/Reals/Rdefinitions/Rdiv.con" ->
192 rat_of_binop rdiv next
193 |"cic:/Coq/Reals/Rdefinitions/Rplus.con" ->
194 rat_of_binop rplus next
195 |"cic:/Coq/Reals/Rdefinitions/Rminus.con" ->
196 rat_of_binop rminus next
197 | _ -> failwith "not a rational")
198 | _ -> failwith "not a rational")
199 | Cic.Const (u,boh) ->
200 (match (UriManager.string_of_uri u) with
201 "cic:/Coq/Reals/Rdefinitions/R1.con" -> r1
202 |"cic:/Coq/Reals/Rdefinitions/R0.con" -> r0
203 | _ -> failwith "not a rational")
204 | _ -> failwith "not a rational"
208 let rational_of_const = rational_of_term;;
212 let rec flin_of_term t =
213 let fl_of_binop f l =
214 let a = List.hd l and
215 b = List.hd(List.tl l) in
216 f (flin_of_term a) (flin_of_term b)
220 | Cic.Cast (t1,t2) -> (flin_of_term t1)
221 | Cic.Appl (t1::next) ->
226 match (UriManager.string_of_uri u) with
227 "cic:/Coq/Reals/Rdefinitions/Ropp.con" ->
228 flin_emult (rop r1) (flin_of_term (List.hd next))
229 |"cic:/Coq/Reals/Rdefinitions/Rplus.con"->
230 fl_of_binop flin_plus next
231 |"cic:/Coq/Reals/Rdefinitions/Rminus.con"->
232 fl_of_binop flin_minus next
233 |"cic:/Coq/Reals/Rdefinitions/Rmult.con"->
235 let arg1 = (List.hd next) and
236 arg2 = (List.hd(List.tl next))
240 let a = rational_of_term arg1 in
243 let b = (rational_of_term arg2) in
244 (flin_add_cste (flin_zero()) (rmult a b))
247 _ -> (flin_add (flin_zero()) arg2 a)
250 _-> (flin_add (flin_zero()) arg1 (rational_of_term arg2 ))
252 |"cic:/Coq/Reals/Rdefinitions/Rinv.con"->
253 let a=(rational_of_term (List.hd next)) in
254 flin_add_cste (flin_zero()) (rinv a)
255 |"cic:/Coq/Reals/Rdefinitions/Rdiv.con"->
257 let b=(rational_of_term (List.hd(List.tl next))) in
260 let a = (rational_of_term (List.hd next)) in
261 (flin_add_cste (flin_zero()) (rdiv a b))
264 _-> (flin_add (flin_zero()) (List.hd next) (rinv b))
270 | Cic.Const (u,boh) ->
272 match (UriManager.string_of_uri u) with
273 "cic:/Coq/Reals/Rdefinitions/R1.con" -> flin_one ()
274 |"cic:/Coq/Reals/Rdefinitions/R0.con" -> flin_zero ()
278 with _ -> flin_add (flin_zero()) t r1
282 let flin_of_constr = flin_of_term;;
286 Translates a flin to (c,x) list
288 @return something like (c1,x1)::(c2,x2)::...::(cn,xn)
290 let flin_to_alist f =
292 Hashtbl.iter (fun x c -> res:=(c,x)::(!res)) f;
296 (* Représentation des hypothèses qui sont des inéquations ou des équations.
300 The structure for ineq
302 type hineq={hname:Cic.term; (* le nom de l'hypothèse *)
303 htype:string; (* Rlt, Rgt, Rle, Rge, eqTLR ou eqTRL *)
310 (* Transforme une hypothese h:t en inéquation flin<0 ou flin<=0
313 let ineq1_of_term (h,t) =
315 Cic.Appl (t1::next) ->
316 let arg1= List.hd next in
317 let arg2= List.hd(List.tl next) in
320 (match UriManager.string_of_uri u with
321 "cic:/Coq/Reals/Rdefinitions/Rlt.con" -> [{hname=h;
325 hflin= flin_minus (flin_of_term arg1)
328 |"cic:/Coq/Reals/Rdefinitions/Rgt.con" -> [{hname=h;
332 hflin= flin_minus (flin_of_term arg2)
335 |"cic:/Coq/Reals/Rdefinitions/Rle.con" -> [{hname=h;
339 hflin= flin_minus (flin_of_term arg1)
342 |"cic:/Coq/Reals/Rdefinitions/Rge.con" -> [{hname=h;
346 hflin= flin_minus (flin_of_term arg2)
350 | Cic.MutInd (u,i,o) ->
351 (match UriManager.string_of_uri u with
352 "cic:/Coq/Init/Logic_Type/eqT.con" ->
355 let arg2= List.hd(List.tl (List.tl next)) in
358 (match UriManager.string_of_uri u with
359 "cic:/Coq/Reals/Rdefinitions/R.con"->
364 hflin= flin_minus (flin_of_term arg1)
371 hflin= flin_minus (flin_of_term arg2)
381 let ineq1_of_constr = ineq1_of_term;;
384 (* Applique la méthode de Fourier à une liste d'hypothèses (type hineq)
387 let fourier_lineq lineq1 =
389 let hvar=Hashtbl.create 50 in (* la table des variables des inéquations *)
391 Hashtbl.iter (fun x c ->
392 try (Hashtbl.find hvar x;())
393 with _-> nvar:=(!nvar)+1;
394 Hashtbl.add hvar x (!nvar))
397 let sys= List.map (fun h->
398 let v=Array.create ((!nvar)+1) r0 in
399 Hashtbl.iter (fun x c -> v.(Hashtbl.find hvar x)<-c)
401 ((Array.to_list v)@[rop h.hflin.fcste],h.hstrict))
406 (******************************************************************************
407 Construction de la preuve en cas de succès de la méthode de Fourier,
408 i.e. on obtient une contradiction.
411 let is_int x = (x.den)=1
414 (* fraction = couple (num,den) *)
415 let rec rational_to_fraction x= (x.num,x.den)
418 (* traduction -3 -> (Ropp (Rplus R1 (Rplus R1 R1)))
426 for i=1 to (nn-1) do s:="(Rplus R1 "^(!s)^")"; done;);
427 if n<0 then s:="(Ropp "^(!s)^")";
431 (* -1/2 -> (Rmult (Ropp R1) (Rinv (Rplus R1 R1)))
433 let rational_to_real x =
434 let (n,d)=rational_to_fraction x in
435 ("(Rmult "^(int_to_real n)^" (Rinv "^(int_to_real d)^"))")
438 (* preuve que 0<n*1/d
440 (*let tac_zero_inf_pos gl (n,d) =
441 let cste = pf_parse_constr gl in
442 let tacn=ref (apply (cste "Rlt_zero_1")) in
443 let tacd=ref (apply (cste "Rlt_zero_1")) in
445 tacn:=(tclTHEN (apply (cste "Rlt_zero_pos_plus1")) !tacn); done;
447 tacd:=(tclTHEN (apply (cste "Rlt_zero_pos_plus1")) !tacd); done;
448 (tclTHENS (apply (cste "Rlt_mult_inv_pos")) [!tacn;!tacd])
451 (* preuve que 0<=n*1/d
453 (*let tac_zero_infeq_pos gl (n,d)=
454 let cste = pf_parse_constr gl in
456 then (apply (cste "Rle_zero_zero"))
457 else (apply (cste "Rle_zero_1"))) in
458 let tacd=ref (apply (cste "Rlt_zero_1")) in
460 tacn:=(tclTHEN (apply (cste "Rle_zero_pos_plus1")) !tacn); done;
462 tacd:=(tclTHEN (apply (cste "Rlt_zero_pos_plus1")) !tacd); done;
463 (tclTHENS (apply (cste "Rle_mult_inv_pos")) [!tacn;!tacd])
466 (* preuve que 0<(-n)*(1/d) => False
468 (*let tac_zero_inf_false gl (n,d) =
469 let cste = pf_parse_constr gl in
470 if n=0 then (apply (cste "Rnot_lt0"))
472 (tclTHEN (apply (cste "Rle_not_lt"))
473 (tac_zero_infeq_pos gl (-n,d)))
476 (* preuve que 0<=(-n)*(1/d) => False
478 (*let tac_zero_infeq_false gl (n,d) =
479 let cste = pf_parse_constr gl in
480 (tclTHEN (apply (cste "Rlt_not_le"))
481 (tac_zero_inf_pos gl (-n,d)))
484 let create_meta () = mkMeta(new_meta());;
487 let concl = pf_concl gl in
488 apply_type (mkProd(Anonymous,c,concl)) [create_meta()] gl
490 let exact = exact_check;;
492 let tac_use h = match h.htype with
493 "Rlt" -> exact h.hname
494 |"Rle" -> exact h.hname
495 |"Rgt" -> (tclTHEN (apply (parse "Rfourier_gt_to_lt"))
497 |"Rge" -> (tclTHEN (apply (parse "Rfourier_ge_to_le"))
499 |"eqTLR" -> (tclTHEN (apply (parse "Rfourier_eqLR_to_le"))
501 |"eqTRL" -> (tclTHEN (apply (parse "Rfourier_eqRL_to_le"))
507 match (kind_of_term t) with
509 (match (string_of_constr f) with
510 "Coq.Reals.Rdefinitions.Rlt" -> true
511 |"Coq.Reals.Rdefinitions.Rgt" -> true
512 |"Coq.Reals.Rdefinitions.Rle" -> true
513 |"Coq.Reals.Rdefinitions.Rge" -> true
514 |"Coq.Init.Logic_Type.eqT" -> (match (string_of_constr args.(0)) with
515 "Coq.Reals.Rdefinitions.R"->true
521 let list_of_sign s = List.map (fun (x,_,z)->(x,z)) s;;
524 let l = Array.to_list a in
525 mkApp(List.hd l, Array.of_list (List.tl l))
528 (* Résolution d'inéquations linéaires dans R *)
532 let parse = pf_parse_constr gl in
533 let goal = strip_outer_cast (pf_concl gl) in
534 let fhyp=id_of_string "new_hyp_for_fourier" in
535 (* si le but est une inéquation, on introduit son contraire,
536 et le but à prouver devient False *)
538 match (kind_of_term goal) with
540 (match (string_of_constr f) with
541 "Coq.Reals.Rdefinitions.Rlt" ->
543 (tclTHEN (apply (parse "Rfourier_not_ge_lt"))
546 |"Coq.Reals.Rdefinitions.Rle" ->
548 (tclTHEN (apply (parse "Rfourier_not_gt_le"))
551 |"Coq.Reals.Rdefinitions.Rgt" ->
553 (tclTHEN (apply (parse "Rfourier_not_le_gt"))
556 |"Coq.Reals.Rdefinitions.Rge" ->
558 (tclTHEN (apply (parse "Rfourier_not_lt_ge"))
569 let hyps = List.map (fun (h,t)-> (mkVar h,(body_of_type t)))
570 (list_of_sign (pf_hyps gl)) in
572 List.iter (fun h -> try (lineq:=(ineq1_of_constr h)@(!lineq))
577 (* lineq = les inéquations découlant des hypothèses *)
581 let res=fourier_lineq (!lineq) in
582 let tac=ref tclIDTAC in
584 then (print_string "Tactic Fourier fails.\n";
588 (* l'algorithme de Fourier a réussi: on va en tirer une preuve Coq *)
594 (* lc=coefficients multiplicateurs des inéquations
595 qui donnent 0<cres ou 0<=cres selon sres *)
596 (*print_string "Fourier's method can prove the goal...";flush stdout;*)
604 then (lutil:=(h,c)::(!lutil)(*;
605 print_rational(c);print_string " "*)))
606 (List.combine (!lineq) lc);
609 (* on construit la combinaison linéaire des inéquation *)
614 let s=ref (h1.hstrict) in
615 let t1=ref (mkAppL [|parse "Rmult";
616 parse (rational_to_real c1);
618 let t2=ref (mkAppL [|parse "Rmult";
619 parse (rational_to_real c1);
621 List.iter (fun (h,c) ->
622 s:=(!s)||(h.hstrict);
623 t1:=(mkAppL [|parse "Rplus";
625 mkAppL [|parse "Rmult";
626 parse (rational_to_real c);
628 t2:=(mkAppL [|parse "Rplus";
630 mkAppL [|parse "Rmult";
631 parse (rational_to_real c);
634 let ineq=mkAppL [|parse (if (!s) then "Rlt" else "Rle");
637 let tc=parse (rational_to_real cres) in
641 let tac1=ref (if h1.hstrict
642 then (tclTHENS (apply (parse "Rfourier_lt"))
645 (rational_to_fraction c1)])
646 else (tclTHENS (apply (parse "Rfourier_le"))
649 (rational_to_fraction c1)])) in
651 List.iter (fun (h,c)->
654 then tac1:=(tclTHENS (apply (parse "Rfourier_lt_lt"))
657 (rational_to_fraction c)])
658 else tac1:=(tclTHENS (apply (parse "Rfourier_lt_le"))
661 (rational_to_fraction c)]))
663 then tac1:=(tclTHENS (apply (parse "Rfourier_le_lt"))
666 (rational_to_fraction c)])
667 else tac1:=(tclTHENS (apply (parse "Rfourier_le_le"))
670 (rational_to_fraction c)])));
671 s:=(!s)||(h.hstrict))
674 then tac_zero_inf_false gl (rational_to_fraction cres)
675 else tac_zero_infeq_false gl (rational_to_fraction cres)
677 tac:=(tclTHENS (my_cut ineq)
678 [tclTHEN (change_in_concl
679 (mkAppL [| parse "not"; ineq|]
681 (tclTHEN (apply (if sres then parse "Rnot_lt_lt"
682 else parse "Rnot_le_le"))
683 (tclTHENS (Equality.replace
684 (mkAppL [|parse "Rminus";!t2;!t1|]
688 (tclTHENS (Equality.replace (parse "(Rinv R1)")
691 (* en attendant Field, ça peut aider Ring de remplacer 1/1 par 1 ... *)
696 (tclTHEN (apply (parse "sym_eqT"))
697 (apply (parse "Rinv_R1")))]
702 tac:=(tclTHENS (cut (parse "False"))
703 [tclTHEN intro contradiction;
705 |_-> assert false) |_-> assert false
707 ((tclTHEN !tac (tclFAIL 1 (* 1 au hasard... *) )) gl)
709 ((tclABSTRACT None !tac) gl)
713 let fourier_tac x gl =
717 let v_fourier = add_tactic "Fourier" fourier_tac
720 (*open CicReduction*)
721 (*open PrimitiveTactics*)
722 (*open ProofEngineTypes*)
723 let fourier_tac ~status:(proof,goal) = (proof,[goal]) ;;