(************************************************************************)
(* * The Coq Proof Assistant / The Coq Development Team *)
(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
(* <O___,, * (see CREDITS file for the list of authors) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
(* *)
(* Micromega: A reflexive tactic using the Positivstellensatz *)
(* *)
(* Frédéric Besson (Irisa/Inria) 2006-20018 *)
(* *)
(************************************************************************)
open Num
module Utils = Mutils
open Utils
module Mc = Micromega
let max_nb_cstr = ref max_int
type var = int
let debug = false
let (<+>) = add_num
let (<*>) = mult_num
module Monomial :
sig
type t
val const : t
val is_const : t -> bool
val var : var -> t
val is_var : t -> bool
val get_var : t -> var option
val prod : t -> t -> t
val exp : t -> int -> t
val div : t -> t -> t * int
val compare : t -> t -> int
val pp : out_channel -> t -> unit
val fold : (var -> int -> 'a -> 'a) -> t -> 'a -> 'a
val sqrt : t -> t option
val variables : t -> ISet.t
end
= struct
(* A monomial is represented by a multiset of variables *)
module Map = Map.Make(Int)
open Map
type t = int Map.t
let is_singleton m =
try
let (k,v) = choose m in
let (l,e,r) = split k m in
if is_empty l && is_empty r
then Some(k,v) else None
with Not_found -> None
let pp o m =
let pp_elt o (k,v)=
if v = 1 then Printf.fprintf o "x%i" k
else Printf.fprintf o "x%i^%i" k v in
let rec pp_list o l =
match l with
[] -> ()
| [e] -> pp_elt o e
| e::l -> Printf.fprintf o "%a*%a" pp_elt e pp_list l in
pp_list o (Map.bindings m)
(* The monomial that corresponds to a constant *)
let const = Map.empty
let sum_degree m = Map.fold (fun _ n s -> s + n) m 0
(* Total ordering of monomials *)
let compare: t -> t -> int =
fun m1 m2 ->
let s1 = sum_degree m1
and s2 = sum_degree m2 in
if Int.equal s1 s2 then Map.compare Int.compare m1 m2
else Int.compare s1 s2
let is_const m = (m = Map.empty)
(* The monomial 'x' *)
let var x = Map.add x 1 Map.empty
let is_var m =
match is_singleton m with
| None -> false
| Some (_,i) -> i = 1
let get_var m =
match is_singleton m with
| None -> None
| Some (k,i) -> if i = 1 then Some k else None
let sqrt m =
if is_const m then None
else
try
Some (Map.fold (fun v i acc ->
let i' = i / 2 in
if i mod 2 = 0
then add v i' acc
else raise Not_found) m const)
with Not_found -> None
(* Get the degre of a variable in a monomial *)
let find x m = try find x m with Not_found -> 0
(* Product of monomials *)
let prod m1 m2 = Map.fold (fun k d m -> add k ((find k m) + d) m) m1 m2
let exp m n =
let rec exp acc n =
if n = 0 then acc
else exp (prod acc m) (n - 1) in
exp const n
(* [div m1 m2 = mr,n] such that mr * (m2)^n = m1 *)
let div m1 m2 =
let n = fold (fun x i n -> let i' = find x m1 in
let nx = i' / i in
min n nx) m2 max_int in
let mr = fold (fun x i' m ->
let i = find x m2 in
let ir = i' - i * n in
if ir = 0 then m
else add x ir m) m1 empty in
(mr,n)
let variables m = fold (fun v i acc -> ISet.add v acc) m ISet.empty
let fold = fold
end
module MonMap =
struct
include Map.Make(Monomial)
let union f = merge
(fun x v1 v2 ->
match v1 , v2 with
| None , None -> None
| Some v , None | None , Some v -> Some v
| Some v1 , Some v2 -> f x v1 v2)
end
let pp_mon o (m, i) =
if Monomial.is_const m
then if eq_num (Int 0) i then ()
else Printf.fprintf o "%s" (string_of_num i)
else
match i with
| Int 1 -> Monomial.pp o m
| Int -1 -> Printf.fprintf o "-%a" Monomial.pp m
| Int 0 -> ()
| _ -> Printf.fprintf o "%s*%a" (string_of_num i) Monomial.pp m
module Poly :
(* A polynomial is a map of monomials *)
(*
This is probably a naive implementation
(expected to be fast enough - Coq is probably the bottleneck)
*The new ring contribution is using a sparse Horner representation.
*)
sig
type t
val pp : out_channel -> t -> unit
val get : Monomial.t -> t -> num
val variable : var -> t
val add : Monomial.t -> num -> t -> t
val constant : num -> t
val product : t -> t -> t
val addition : t -> t -> t
val uminus : t -> t
val fold : (Monomial.t -> num -> 'a -> 'a) -> t -> 'a -> 'a
val factorise : var -> t -> t * t
end = struct
(*normalisation bug : 0*x ... *)
module P = Map.Make(Monomial)
open P
type t = num P.t
let pp o p = P.iter (fun mn i -> Printf.fprintf o "%a + " pp_mon (mn, i)) p
(* Get the coefficient of monomial mn *)
let get : Monomial.t -> t -> num =
fun mn p -> try find mn p with Not_found -> (Int 0)
(* The polynomial 1.x *)
let variable : var -> t =
fun x -> add (Monomial.var x) (Int 1) empty
(*The constant polynomial *)
let constant : num -> t =
fun c -> add (Monomial.const) c empty
(* The addition of a monomial *)
let add : Monomial.t -> num -> t -> t =
fun mn v p ->
if sign_num v = 0 then p
else
let vl = (get mn p) <+> v in
if sign_num vl = 0 then
remove mn p
else add mn vl p
(** Design choice: empty is not a polynomial
I do not remember why ....
**)
(* The product by a monomial *)
let mult : Monomial.t -> num -> t -> t =
fun mn v p ->
if sign_num v = 0
then constant (Int 0)
else
fold (fun mn' v' res -> P.add (Monomial.prod mn mn') (v<*>v') res) p empty
let addition : t -> t -> t =
fun p1 p2 -> fold (fun mn v p -> add mn v p) p1 p2
let product : t -> t -> t =
fun p1 p2 ->
fold (fun mn v res -> addition (mult mn v p2) res ) p1 empty
let uminus : t -> t =
fun p -> map (fun v -> minus_num v) p
let fold = P.fold
let factorise x p =
let x = Monomial.var x in
P.fold (fun m v (px,cx) ->
let (m1,i) = Monomial.div m x in
if i = 0
then (px, add m v cx)
else
let mx = Monomial.prod m1 (Monomial.exp x (i-1)) in
(add mx v px,cx) ) p (constant (Int 0) , constant (Int 0))
end
type vector = Vect.t
type cstr = {coeffs : vector ; op : op ; cst : num}
and op = |Eq | Ge | Gt
exception Strict
let is_strict c = Pervasives.(=) c.op Gt
let eval_op = function
| Eq -> (=/)
| Ge -> (>=/)
| Gt -> (>/)
let string_of_op = function Eq -> "=" | Ge -> ">=" | Gt -> ">"
let output_cstr o { coeffs ; op ; cst } =
Printf.fprintf o "%a %s %s" Vect.pp coeffs (string_of_op op) (string_of_num cst)
let opMult o1 o2 =
match o1, o2 with
| Eq , _ | _ , Eq -> Eq
| Ge , _ | _ , Ge -> Ge
| Gt , Gt -> Gt
let opAdd o1 o2 =
match o1, o2 with
| Eq , x | x , Eq -> x
| Gt , x | x , Gt -> Gt
| Ge , Ge -> Ge
module LinPoly = struct
(** A linear polynomial a0 + a1.x1 + ... + an.xn
By convention, the constant a0 is the coefficient of the variable 0.
*)
type t = Vect.t
module MonT = struct
module MonoMap = Map.Make(Monomial)
module IntMap = Map.Make(Int)
(** A hash table might be preferable but requires a hash function. *)
let (index_of_monomial : int MonoMap.t ref) = ref (MonoMap.empty)
let (monomial_of_index : Monomial.t IntMap.t ref) = ref (IntMap.empty)
let fresh = ref 0
let clear () =
index_of_monomial := MonoMap.empty;
monomial_of_index := IntMap.empty ;
fresh := 0
let register m =
try
MonoMap.find m !index_of_monomial
with Not_found ->
begin
let res = !fresh in
index_of_monomial := MonoMap.add m res !index_of_monomial ;
monomial_of_index := IntMap.add res m !monomial_of_index ;
incr fresh ; res
end
let retrieve i = IntMap.find i !monomial_of_index
let _ = register Monomial.const
end
let var v = Vect.set (MonT.register (Monomial.var v)) (Int 1) Vect.null
let of_monomial m =
let v = MonT.register m in
Vect.set v (Int 1) Vect.null
let linpol_of_pol p =
Poly.fold
(fun mon num vct ->
let vr = MonT.register mon in
Vect.set vr num vct) p Vect.null
let pol_of_linpol v =
Vect.fold (fun p vr n -> Poly.add (MonT.retrieve vr) n p) (Poly.constant (Int 0)) v
let coq_poly_of_linpol cst p =
let pol_of_mon m =
Monomial.fold (fun x v p -> Mc.PEmul(Mc.PEpow(Mc.PEX(CamlToCoq.positive x),CamlToCoq.n v),p)) m (Mc.PEc (cst (Int 1))) in
Vect.fold (fun acc x v ->
let mn = MonT.retrieve x in
Mc.PEadd(Mc.PEmul(Mc.PEc (cst v), pol_of_mon mn),acc)) (Mc.PEc (cst (Int 0))) p
let pp_var o vr =
try
Monomial.pp o (MonT.retrieve vr) (* this is a non-linear variable *)
with Not_found -> Printf.fprintf o "v%i" vr
let pp o p = Vect.pp_gen pp_var o p
let constant c =
if sign_num c = 0
then Vect.null
else Vect.set 0 c Vect.null
let is_linear p =
Vect.for_all (fun v _ ->
let mn = (MonT.retrieve v) in
Monomial.is_var mn || Monomial.is_const mn) p
let is_variable p =
let ((x,v),r) = Vect.decomp_fst p in
if Vect.is_null r && v >/ Int 0
then Monomial.get_var (MonT.retrieve x)
else None
let factorise x p =
let (px,cx) = Poly.factorise x (pol_of_linpol p) in
(linpol_of_pol px, linpol_of_pol cx)
let is_linear_for x p =
let (a,b) = factorise x p in
Vect.is_constant a
let search_all_linear p l =
Vect.fold (fun acc x v ->
if p v
then
let x' = MonT.retrieve x in
match Monomial.get_var x' with
| None -> acc
| Some x ->
if is_linear_for x l
then x::acc
else acc
else acc) [] l
let min_list (l:int list) =
match l with
| [] -> None
| e::l -> Some (List.fold_left Pervasives.min e l)
let search_linear p l =
min_list (search_all_linear p l)
let product p1 p2 =
linpol_of_pol (Poly.product (pol_of_linpol p1) (pol_of_linpol p2))
let addition p1 p2 = Vect.add p1 p2
let of_vect v =
Vect.fold (fun acc v vl -> addition (product (var v) (constant vl)) acc) Vect.null v
let variables p = Vect.fold
(fun acc v _ ->
ISet.union (Monomial.variables (MonT.retrieve v)) acc) ISet.empty p
let pp_goal typ o l =
let vars = List.fold_left (fun acc p -> ISet.union acc (variables (fst p))) ISet.empty l in
let pp_vars o i = ISet.iter (fun v -> Printf.fprintf o "(x%i : %s) " v typ) vars in
Printf.fprintf o "forall %a\n" pp_vars vars ;
List.iteri (fun i (p,op) -> Printf.fprintf o "(H%i : %a %s 0)\n" i pp p (string_of_op op)) l;
Printf.fprintf o ", False\n"
let collect_square p =
Vect.fold (fun acc v _ ->
let m = (MonT.retrieve v) in
match Monomial.sqrt m with
| None -> acc
| Some s -> MonMap.add s m acc
) MonMap.empty p
end
module ProofFormat = struct
open Big_int
type prf_rule =
| Annot of string * prf_rule
| Hyp of int
| Def of int
| Cst of Num.num
| Zero
| Square of Vect.t
| MulC of Vect.t * prf_rule
| Gcd of Big_int.big_int * prf_rule
| MulPrf of prf_rule * prf_rule
| AddPrf of prf_rule * prf_rule
| CutPrf of prf_rule
type proof =
| Done
| Step of int * prf_rule * proof
| Enum of int * prf_rule * Vect.t * prf_rule * proof list
let rec output_prf_rule o = function
| Annot(s,p) -> Printf.fprintf o "(%a)@%s" output_prf_rule p s
| Hyp i -> Printf.fprintf o "Hyp %i" i
| Def i -> Printf.fprintf o "Def %i" i
| Cst c -> Printf.fprintf o "Cst %s" (string_of_num c)
| Zero -> Printf.fprintf o "Zero"
| Square s -> Printf.fprintf o "(%a)^2" Poly.pp (LinPoly.pol_of_linpol s)
| MulC(p,pr) -> Printf.fprintf o "(%a) * (%a)" Poly.pp (LinPoly.pol_of_linpol p) output_prf_rule pr
| MulPrf(p1,p2) -> Printf.fprintf o "(%a) * (%a)" output_prf_rule p1 output_prf_rule p2
| AddPrf(p1,p2) -> Printf.fprintf o "%a + %a" output_prf_rule p1 output_prf_rule p2
| CutPrf(p) -> Printf.fprintf o "[%a]" output_prf_rule p
| Gcd(c,p) -> Printf.fprintf o "(%a)/%s" output_prf_rule p (string_of_big_int c)
let rec output_proof o = function
| Done -> Printf.fprintf o "."
| Step(i,p,pf) -> Printf.fprintf o "%i:= %a ; %a" i output_prf_rule p output_proof pf
| Enum(i,p1,v,p2,pl) -> Printf.fprintf o "%i{%a<=%a<=%a}%a" i
output_prf_rule p1 Vect.pp v output_prf_rule p2
(pp_list ";" output_proof) pl
let rec pr_size = function
| Annot(_,p) -> pr_size p
| Zero| Square _ -> Int 0
| Hyp _ -> Int 1
| Def _ -> Int 1
| Cst n -> n
| Gcd(i, p) -> pr_size p // (Big_int i)
| MulPrf(p1,p2) | AddPrf(p1,p2) -> pr_size p1 +/ pr_size p2
| CutPrf p -> pr_size p
| MulC(v, p) -> pr_size p
let rec pr_rule_max_id = function
| Annot(_,p) -> pr_rule_max_id p
| Hyp i | Def i -> i
| Cst _ | Zero | Square _ -> -1
| MulC(_,p) | CutPrf p | Gcd(_,p) -> pr_rule_max_id p
| MulPrf(p1,p2)| AddPrf(p1,p2) -> max (pr_rule_max_id p1) (pr_rule_max_id p2)
let rec proof_max_id = function
| Done -> -1
| Step(i,pr,prf) -> max i (max (pr_rule_max_id pr) (proof_max_id prf))
| Enum(i,p1,_,p2,l) ->
let m = max (pr_rule_max_id p1) (pr_rule_max_id p2) in
List.fold_left (fun i prf -> max i (proof_max_id prf)) (max i m) l
let rec pr_rule_def_cut id = function
| Annot(_,p) -> pr_rule_def_cut id p
| MulC(p,prf) ->
let (bds,id',prf') = pr_rule_def_cut id prf in
(bds, id', MulC(p,prf'))
| MulPrf(p1,p2) ->
let (bds1,id,p1) = pr_rule_def_cut id p1 in
let (bds2,id,p2) = pr_rule_def_cut id p2 in
(bds2@bds1,id,MulPrf(p1,p2))
| AddPrf(p1,p2) ->
let (bds1,id,p1) = pr_rule_def_cut id p1 in
let (bds2,id,p2) = pr_rule_def_cut id p2 in
(bds2@bds1,id,AddPrf(p1,p2))
| CutPrf p ->
let (bds,id,p) = pr_rule_def_cut id p in
((id,p)::bds,id+1,Def id)
| Gcd(c,p) ->
let (bds,id,p) = pr_rule_def_cut id p in
((id,p)::bds,id+1,Def id)
| Square _|Cst _|Def _|Hyp _|Zero as x -> ([],id,x)
(* Do not define top-level cuts *)
let pr_rule_def_cut id = function
| CutPrf p ->
let (bds,ids,p') = pr_rule_def_cut id p in
bds,ids, CutPrf p'
| p -> pr_rule_def_cut id p
let rec implicit_cut p =
match p with
| CutPrf p -> implicit_cut p
| _ -> p
let rec pr_rule_collect_hyps pr =
match pr with
| Annot(_,pr) -> pr_rule_collect_hyps pr
| Hyp i | Def i -> ISet.add i ISet.empty
| Cst _ | Zero | Square _ -> ISet.empty
| MulC(_,pr) | Gcd(_,pr)| CutPrf pr -> pr_rule_collect_hyps pr
| MulPrf(p1,p2) | AddPrf(p1,p2) -> ISet.union (pr_rule_collect_hyps p1) (pr_rule_collect_hyps p2)
let simplify_proof p =
let rec simplify_proof p =
match p with
| Done -> (Done, ISet.empty)
| Step(i,pr,Done) -> (p, ISet.add i (pr_rule_collect_hyps pr))
| Step(i,pr,prf) ->
let (prf',hyps) = simplify_proof prf in
if not (ISet.mem i hyps)
then (prf',hyps)
else
(Step(i,pr,prf'), ISet.add i (ISet.union (pr_rule_collect_hyps pr) hyps))
| Enum(i,p1,v,p2,pl) ->
let (pl,hl) = List.split (List.map simplify_proof pl) in
let hyps = List.fold_left ISet.union ISet.empty hl in
(Enum(i,p1,v,p2,pl),ISet.add i (ISet.union (ISet.union (pr_rule_collect_hyps p1) (pr_rule_collect_hyps p2)) hyps)) in
fst (simplify_proof p)
let rec normalise_proof id prf =
match prf with
| Done -> (id,Done)
| Step(i,Gcd(c,p),Done) -> normalise_proof id (Step(i,p,Done))
| Step(i,p,prf) ->
let bds,id,p' = pr_rule_def_cut id p in
let (id,prf) = normalise_proof id prf in
let prf = List.fold_left (fun acc (i,p) -> Step(i, CutPrf p,acc))
(Step(i,p',prf)) bds in
(id,prf)
| Enum(i,p1,v,p2,pl) ->
(* Why do I have top-level cuts ? *)
(* let p1 = implicit_cut p1 in
let p2 = implicit_cut p2 in
let (ids,prfs) = List.split (List.map (normalise_proof id) pl) in
(List.fold_left max 0 ids ,
Enum(i,p1,v,p2,prfs))
*)
let bds1,id,p1' = pr_rule_def_cut id (implicit_cut p1) in
let bds2,id,p2' = pr_rule_def_cut id (implicit_cut p2) in
let (ids,prfs) = List.split (List.map (normalise_proof id) pl) in
(List.fold_left max 0 ids ,
List.fold_left (fun acc (i,p) -> Step(i, CutPrf p,acc))
(Enum(i,p1',v,p2',prfs)) (bds2@bds1))
let normalise_proof id prf =
let prf = simplify_proof prf in
let res = normalise_proof id prf in
if debug then Printf.printf "normalise_proof %a -> %a" output_proof prf output_proof (snd res) ;
res
module OrdPrfRule =
struct
type t = prf_rule
let id_of_constr = function
| Annot _ -> 0
| Hyp _ -> 1
| Def _ -> 2
| Cst _ -> 3
| Zero -> 4
| Square _ -> 5
| MulC _ -> 6
| Gcd _ -> 7
| MulPrf _ -> 8
| AddPrf _ -> 9
| CutPrf _ -> 10
let cmp_pair c1 c2 (x1,x2) (y1,y2) =
match c1 x1 y1 with
| 0 -> c2 x2 y2
| i -> i
let rec compare p1 p2 =
match p1, p2 with
| Annot(s1,p1) , Annot(s2,p2) -> if s1 = s2 then compare p1 p2
else Pervasives.compare s1 s2
| Hyp i , Hyp j -> Pervasives.compare i j
| Def i , Def j -> Pervasives.compare i j
| Cst n , Cst m -> Num.compare_num n m
| Zero , Zero -> 0
| Square v1 , Square v2 -> Vect.compare v1 v2
| MulC(v1,p1) , MulC(v2,p2) -> cmp_pair Vect.compare compare (v1,p1) (v2,p2)
| Gcd(b1,p1) , Gcd(b2,p2) -> cmp_pair Big_int.compare_big_int compare (b1,p1) (b2,p2)
| MulPrf(p1,q1) , MulPrf(p2,q2) -> cmp_pair compare compare (p1,q1) (p2,q2)
| AddPrf(p1,q1) , MulPrf(p2,q2) -> cmp_pair compare compare (p1,q1) (p2,q2)
| CutPrf p , CutPrf p' -> compare p p'
| _ , _ -> Pervasives.compare (id_of_constr p1) (id_of_constr p2)
end
let add_proof x y =
match x, y with
| Zero , p | p , Zero -> p
| _ -> AddPrf(x,y)
let rec mul_cst_proof c p =
match p with
| Annot(s,p) -> Annot(s,mul_cst_proof c p)
| MulC(v,p') -> MulC(Vect.mul c v,p')
| _ ->
match sign_num c with
| 0 -> Zero (* This is likely to be a bug *)
| -1 -> MulC(LinPoly.constant c, p) (* [p] should represent an equality *)
| 1 ->
if eq_num (Int 1) c
then p
else MulPrf(Cst c,p)
| _ -> assert false
let sMulC v p =
let (c,v') = Vect.decomp_cst v in
if Vect.is_null v' then mul_cst_proof c p
else MulC(v,p)
let mul_proof p1 p2 =
match p1 , p2 with
| Zero , _ | _ , Zero -> Zero
| Cst c , p | p , Cst c -> mul_cst_proof c p
| _ , _ ->
MulPrf(p1,p2)
module PrfRuleMap = Map.Make(OrdPrfRule)
let prf_rule_of_map m =
PrfRuleMap.fold (fun k v acc -> add_proof (sMulC v k) acc) m Zero
let rec dev_prf_rule p =
match p with
| Annot(s,p) -> dev_prf_rule p
| Hyp _ | Def _ | Cst _ | Zero | Square _ -> PrfRuleMap.singleton p (LinPoly.constant (Int 1))
| MulC(v,p) -> PrfRuleMap.map (fun v1 -> LinPoly.product v v1) (dev_prf_rule p)
| AddPrf(p1,p2) -> PrfRuleMap.merge (fun k o1 o2 ->
match o1 , o2 with
| None , None -> None
| None , Some v | Some v, None -> Some v
| Some v1 , Some v2 -> Some (LinPoly.addition v1 v2)) (dev_prf_rule p1) (dev_prf_rule p2)
| MulPrf(p1, p2) ->
begin
let p1' = dev_prf_rule p1 in
let p2' = dev_prf_rule p2 in
let p1'' = prf_rule_of_map p1' in
let p2'' = prf_rule_of_map p2' in
match p1'' with
| Cst c -> PrfRuleMap.map (fun v1 -> Vect.mul c v1) p2'
| _ -> PrfRuleMap.singleton (MulPrf(p1'',p2'')) (LinPoly.constant (Int 1))
end
| _ -> PrfRuleMap.singleton p (LinPoly.constant (Int 1))
let simplify_prf_rule p =
prf_rule_of_map (dev_prf_rule p)
(*
let mul_proof p1 p2 =
let res = mul_proof p1 p2 in
Printf.printf "mul_proof %a %a = %a\n"
output_prf_rule p1 output_prf_rule p2 output_prf_rule res; res
let add_proof p1 p2 =
let res = add_proof p1 p2 in
Printf.printf "add_proof %a %a = %a\n"
output_prf_rule p1 output_prf_rule p2 output_prf_rule res; res
let sMulC v p =
let res = sMulC v p in
Printf.printf "sMulC %a %a = %a\n" Vect.pp v output_prf_rule p output_prf_rule res ;
res
let mul_cst_proof c p =
let res = mul_cst_proof c p in
Printf.printf "mul_cst_proof %s %a = %a\n" (Num.string_of_num c) output_prf_rule p output_prf_rule res ;
res
*)
let proof_of_farkas env vect =
Vect.fold (fun prf x n ->
add_proof (mul_cst_proof n (IMap.find x env)) prf) Zero vect
module Env = struct
let rec string_of_int_list l =
match l with
| [] -> ""
| i::l -> Printf.sprintf "%i,%s" i (string_of_int_list l)
let id_of_hyp hyp l =
let rec xid_of_hyp i l' =
match l' with
| [] -> failwith (Printf.sprintf "id_of_hyp %i %s" hyp (string_of_int_list l))
| hyp'::l' -> if Pervasives.(=) hyp hyp' then i else xid_of_hyp (i+1) l' in
xid_of_hyp 0 l
end
let cmpl_prf_rule norm (cst:num-> 'a) env prf =
let rec cmpl =
function
| Annot(s,p) -> cmpl p
| Hyp i | Def i -> Mc.PsatzIn (CamlToCoq.nat (Env.id_of_hyp i env))
| Cst i -> Mc.PsatzC (cst i)
| Zero -> Mc.PsatzZ
| MulPrf(p1,p2) -> Mc.PsatzMulE(cmpl p1, cmpl p2)
| AddPrf(p1,p2) -> Mc.PsatzAdd(cmpl p1 , cmpl p2)
| MulC(lp,p) -> let lp = norm (LinPoly.coq_poly_of_linpol cst lp) in
Mc.PsatzMulC(lp,cmpl p)
| Square lp -> Mc.PsatzSquare (norm (LinPoly.coq_poly_of_linpol cst lp))
| _ -> failwith "Cuts should already be compiled" in
cmpl prf
let cmpl_prf_rule_z env r = cmpl_prf_rule Mc.normZ (fun x -> CamlToCoq.bigint (numerator x)) env r
let rec cmpl_proof env = function
| Done -> Mc.DoneProof
| Step(i,p,prf) ->
begin
match p with
| CutPrf p' ->
Mc.CutProof(cmpl_prf_rule_z env p', cmpl_proof (i::env) prf)
| _ -> Mc.RatProof(cmpl_prf_rule_z env p,cmpl_proof (i::env) prf)
end
| Enum(i,p1,_,p2,l) ->
Mc.EnumProof(cmpl_prf_rule_z env p1,cmpl_prf_rule_z env p2,List.map (cmpl_proof (i::env)) l)
let compile_proof env prf =
let id = 1 + proof_max_id prf in
let _,prf = normalise_proof id prf in
cmpl_proof env prf
let rec eval_prf_rule env = function
| Annot(s,p) -> eval_prf_rule env p
| Hyp i | Def i -> env i
| Cst n -> (Vect.set 0 n Vect.null,
match Num.compare_num n (Int 0) with
| 0 -> Ge
| 1 -> Gt
| _ -> failwith "eval_prf_rule : negative constant"
)
| Zero -> (Vect.null, Ge)
| Square v -> (LinPoly.product v v,Ge)
| MulC(v, p) ->
let (p1,o) = eval_prf_rule env p in
begin match o with
| Eq -> (LinPoly.product v p1,Eq)
| _ ->
Printf.fprintf stdout "MulC(%a,%a) invalid 2d arg %a %s" Vect.pp v output_prf_rule p Vect.pp p1 (string_of_op o);
failwith "eval_prf_rule : not an equality"
end
| Gcd(g,p) -> let (v,op) = eval_prf_rule env p in
(Vect.div (Big_int g) v, op)
| MulPrf(p1,p2) ->
let (v1,o1) = eval_prf_rule env p1 in
let (v2,o2) = eval_prf_rule env p2 in
(LinPoly.product v1 v2, opMult o1 o2)
| AddPrf(p1,p2) ->
let (v1,o1) = eval_prf_rule env p1 in
let (v2,o2) = eval_prf_rule env p2 in
(LinPoly.addition v1 v2, opAdd o1 o2)
| CutPrf p -> eval_prf_rule env p
let is_unsat (p,o) =
let (c,r) = Vect.decomp_cst p in
if Vect.is_null r
then not (eval_op o c (Int 0))
else false
let rec eval_proof env p =
match p with
| Done -> failwith "Proof is not finished"
| Step(i, prf, rst) ->
let (p,o) = eval_prf_rule (fun i -> IMap.find i env) prf in
if is_unsat (p,o) then true
else
if Pervasives.(=) rst Done
then
begin
Printf.fprintf stdout "Last inference %a %s\n" LinPoly.pp p (string_of_op o);
false
end
else eval_proof (IMap.add i (p,o) env) rst
| Enum(i,r1,v,r2,l) -> let _ = eval_prf_rule (fun i -> IMap.find i env) r1 in
let _ = eval_prf_rule (fun i -> IMap.find i env) r2 in
(* Should check bounds *)
failwith "Not implemented"
end
module WithProof = struct
type t = ((LinPoly.t * op) * ProofFormat.prf_rule)
let annot s (p,prf) = (p, ProofFormat.Annot(s,prf))
let output o ((lp,op),prf) =
Printf.fprintf o "%a %s 0 by %a\n" LinPoly.pp lp (string_of_op op) ProofFormat.output_prf_rule prf
let output_sys o l =
List.iter (Printf.fprintf o "%a\n" output) l
exception InvalidProof
let zero = ((Vect.null,Eq), ProofFormat.Zero)
let const n = ((LinPoly.constant n,Ge), ProofFormat.Cst n)
let of_cstr (c,prf) =
(Vect.set 0 (Num.minus_num (c.cst)) c.coeffs,c.op), prf
let product : t -> t -> t = fun ((p1,o1),prf1) ((p2,o2),prf2) ->
((LinPoly.product p1 p2 , opMult o1 o2), ProofFormat.mul_proof prf1 prf2)
let addition : t -> t -> t = fun ((p1,o1),prf1) ((p2,o2),prf2) ->
((Vect.add p1 p2, opAdd o1 o2), ProofFormat.add_proof prf1 prf2)
let mult p ((p1,o1),prf1) =
match o1 with
| Eq -> ((LinPoly.product p p1,o1), ProofFormat.sMulC p prf1)
| Gt| Ge -> let (n,r) = Vect.decomp_cst p in
if Vect.is_null r && n >/ Int 0
then ((LinPoly.product p p1, o1), ProofFormat.mul_cst_proof n prf1)
else raise InvalidProof
let cutting_plane ((p,o),prf) =
let (c,p') = Vect.decomp_cst p in
let g = (Vect.gcd p') in
if (Big_int.eq_big_int Big_int.unit_big_int g) || c =/ Int 0 ||
not (Big_int.eq_big_int (denominator c) Big_int.unit_big_int)
then None (* Nothing to do *)
else
let c1 = c // (Big_int g) in
let c1' = Num.floor_num c1 in
if c1 =/ c1'
then None
else
match o with
| Eq -> Some ((Vect.set 0 (Int (-1)) Vect.null,Eq), ProofFormat.Gcd(g,prf))
| Gt -> failwith "cutting_plane ignore strict constraints"
| Ge ->
(* This is a non-trivial common divisor *)
Some ((Vect.set 0 c1' (Vect.div (Big_int g) p),o),ProofFormat.Gcd(g, prf))
let construct_sign p =
let (c,p') = Vect.decomp_cst p in
if Vect.is_null p'
then
Some (begin match sign_num c with
| 0 -> (true, Eq, ProofFormat.Zero)
| 1 -> (true,Gt, ProofFormat.Cst c)
| _ (*-1*) -> (false,Gt, ProofFormat.Cst (minus_num c))
end)
else None
let get_sign l p =
match construct_sign p with
| None -> begin
try
let ((p',o),prf) =
List.find (fun ((p',o),prf) -> Vect.equal p p') l in
Some (true,o,prf)
with Not_found ->
let p = Vect.uminus p in
try
let ((p',o),prf) = List.find (fun ((p',o),prf) -> Vect.equal p p') l in
Some (false,o,prf)
with Not_found -> None
end
| Some s -> Some s
let mult_sign : bool -> t -> t = fun b ((p,o),prf) ->
if b then ((p,o),prf)
else ((Vect.uminus p,o),prf)
let rec linear_pivot sys ((lp1,op1), prf1) x ((lp2,op2), prf2) =
(* lp1 = a1.x + b1 *)
let (a1,b1) = LinPoly.factorise x lp1 in
(* lp2 = a2.x + b2 *)
let (a2,b2) = LinPoly.factorise x lp2 in
if Vect.is_null a2
then (* We are done *)
Some ((lp2,op2),prf2)
else
match op1,op2 with
| Eq , (Ge|Gt) -> begin
match get_sign sys a1 with
| None -> None (* Impossible to pivot without sign information *)
| Some(b,o,prf) ->
let sa1 = mult_sign b ((a1,o),prf) in
let sa2 = if b then (Vect.uminus a2) else a2 in
let ((lp2,op2),prf2) =
addition (product sa1 ((lp2,op2),prf2))
(mult sa2 ((lp1,op1),prf1)) in
linear_pivot sys ((lp1,op1),prf1) x ((lp2,op2),prf2)
end
| Eq , Eq ->
let ((lp2,op2),prf2) = addition (mult a1 ((lp2,op2),prf2))
(mult (Vect.uminus a2) ((lp1,op1),prf1)) in
linear_pivot sys ((lp1,op1),prf1) x ((lp2,op2),prf2)
| (Ge | Gt) , (Ge| Gt) -> begin
match get_sign sys a1 , get_sign sys a2 with
| Some(b1,o1,p1) , Some(b2,o2,p2) ->
if b1 <> b2
then
let ((lp2,op2),prf2) =
addition (product (mult_sign b1 ((a1,o1), p1)) ((lp2,op2),prf2))
(product (mult_sign b2 ((a2,o2), p2)) ((lp1,op1),prf1)) in
linear_pivot sys ((lp1,op1),prf1) x ((lp2,op2),prf2)
else None
| _ -> None
end
| (Ge|Gt) , Eq -> failwith "pivot: equality as second argument"
let linear_pivot sys ((lp1,op1), prf1) x ((lp2,op2), prf2) =
match linear_pivot sys ((lp1,op1), prf1) x ((lp2,op2), prf2) with
| None -> None
| Some (c,p) -> Some(c, ProofFormat.simplify_prf_rule p)
let is_substitution strict ((p,o),prf) =
let pred v = if strict then v =/ Int 1 || v =/ Int (-1) else true in
match o with
| Eq -> LinPoly.search_linear pred p
| _ -> None
let subst1 sys0 =
let (oeq,sys') = extract (is_substitution true) sys0 in
match oeq with
| None -> sys0
| Some(v,pc) ->
match simplify (linear_pivot sys0 pc v) sys' with
| None -> sys0
| Some sys' -> sys'
let subst sys0 =
let elim sys =
let (oeq,sys') = extract (is_substitution true) sys in
match oeq with
| None -> None
| Some(v,pc) -> simplify (linear_pivot sys0 pc v) sys' in
iterate_until_stable elim sys0
let saturate_subst b sys0 =
let select = is_substitution b in
let gen (v,pc) ((c,op),prf) =
if ISet.mem v (LinPoly.variables c)
then linear_pivot sys0 pc v ((c,op),prf)
else None
in
saturate select gen sys0
end
(* Local Variables: *)
(* coding: utf-8 *)
(* End: *)
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|