(************************************************************************)
(* * 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) *)
(************************************************************************)
open Util
open Num
open Polynomial
open Vect
let debug = false
let compare_float (p : float) q = Pervasives.compare p q
(** Implementation of intervals *)
open Itv
type vector = Vect.t
(** 'cstr' is the type of constraints.
{coeffs = v ; bound = (l,r) } models the constraints l <= v <= r
**)
module ISet = Set.Make(Int)
module System = Hashtbl.Make(Vect)
type proof =
| Assum of int
| Elim of var * proof * proof
| And of proof * proof
type system = {
sys : cstr_info ref System.t ;
vars : ISet.t
}
and cstr_info = {
bound : interval ;
prf : proof ;
pos : int ;
neg : int ;
}
(** A system of constraints has the form [\{sys = s ; vars = v\}].
[s] is a hashtable mapping a normalised vector to a [cstr_info] record where
- [bound] is an interval
- [prf_idx] is the set of hypothesis indexes (i.e. constraints in the initial system) used to obtain the current constraint.
In the initial system, each constraint is given an unique singleton proof_idx.
When a new constraint c is computed by a function f(c1,...,cn), its proof_idx is ISet.fold union (List.map (fun x -> x.proof_idx) [c1;...;cn]
- [pos] is the number of positive values of the vector
- [neg] is the number of negative values of the vector
( [neg] + [pos] is therefore the length of the vector)
[v] is an upper-bound of the set of variables which appear in [s].
*)
(** To be thrown when a system has no solution *)
exception SystemContradiction of proof
(** Pretty printing *)
let rec pp_proof o prf =
match prf with
| Assum i -> Printf.fprintf o "H%i" i
| Elim(v, prf1,prf2) -> Printf.fprintf o "E(%i,%a,%a)" v pp_proof prf1 pp_proof prf2
| And(prf1,prf2) -> Printf.fprintf o "A(%a,%a)" pp_proof prf1 pp_proof prf2
let pp_cstr o (vect,bnd) =
let (l,r) = bnd in
(match l with
| None -> ()
| Some n -> Printf.fprintf o "%s <= " (string_of_num n))
;
Vect.pp o vect ;
(match r with
| None -> output_string o"\n"
| Some n -> Printf.fprintf o "<=%s\n" (string_of_num n))
let pp_system o sys=
System.iter (fun vect ibnd ->
pp_cstr o (vect,(!ibnd).bound)) sys
(** [merge_cstr_info] takes:
- the intersection of bounds and
- the union of proofs
- [pos] and [neg] fields should be identical *)
let merge_cstr_info i1 i2 =
let { pos = p1 ; neg = n1 ; bound = i1 ; prf = prf1 } = i1
and { pos = p2 ; neg = n2 ; bound = i2 ; prf = prf2 } = i2 in
assert (Int.equal p1 p2 && Int.equal n1 n2) ;
match inter i1 i2 with
| None -> None (* Could directly raise a system contradiction exception *)
| Some bnd ->
Some { pos = p1 ; neg = n1 ; bound = bnd ; prf = And(prf1,prf2) }
(** [xadd_cstr vect cstr_info] loads an constraint into the system.
The constraint is neither redundant nor contradictory.
@raise SystemContradiction if [cstr_info] returns [None]
*)
let xadd_cstr vect cstr_info sys =
try
let info = System.find sys vect in
match merge_cstr_info cstr_info !info with
| None -> raise (SystemContradiction (And(cstr_info.prf, (!info).prf)))
| Some info' -> info := info'
with
| Not_found -> System.replace sys vect (ref cstr_info)
exception TimeOut
let xadd_cstr vect cstr_info sys =
if debug && Int.equal (System.length sys mod 1000) 0 then (print_string "*" ; flush stdout) ;
if System.length sys < !max_nb_cstr
then xadd_cstr vect cstr_info sys
else raise TimeOut
type cstr_ext =
| Contradiction (** The constraint is contradictory.
Typically, a [SystemContradiction] exception will be raised. *)
| Redundant (** The constrain is redundant.
Typically, the constraint will be dropped *)
| Cstr of vector * cstr_info (** Taken alone, the constraint is neither contradictory nor redundant.
Typically, it will be added to the constraint system. *)
(** [normalise_cstr] : vector -> cstr_info -> cstr_ext *)
let normalise_cstr vect cinfo =
match norm_itv cinfo.bound with
| None -> Contradiction
| Some (l,r) ->
match Vect.choose vect with
| None -> if Itv.in_bound (l,r) (Int 0) then Redundant else Contradiction
| Some (_,n,_) -> Cstr(Vect.div n vect,
let divn x = x // n in
if Int.equal (sign_num n) 1
then{cinfo with bound = (Option.map divn l , Option.map divn r) }
else {cinfo with pos = cinfo.neg ; neg = cinfo.pos ; bound = (Option.map divn r , Option.map divn l)})
(** For compatibility, there is an external representation of constraints *)
let count v =
Vect.fold (fun (n,p) _ vl ->
let sg = sign_num vl in
assert (sg <> 0) ;
if Int.equal sg 1 then (n,p+1)else (n+1, p)) (0,0) v
let norm_cstr {coeffs = v ; op = o ; cst = c} idx =
let (n,p) = count v in
normalise_cstr v {pos = p ; neg = n ; bound =
(match o with
| Eq -> Some c , Some c
| Ge -> Some c , None
| Gt -> raise Polynomial.Strict
) ;
prf = Assum idx }
(** [load_system l] takes a list of constraints of type [cstr_compat]
@return a system of constraints
@raise SystemContradiction if a contradiction is found
*)
let load_system l =
let sys = System.create 1000 in
let li = List.mapi (fun i e -> (e,i)) l in
let vars = List.fold_left (fun vrs (cstr,i) ->
match norm_cstr cstr i with
| Contradiction -> raise (SystemContradiction (Assum i))
| Redundant -> vrs
| Cstr(vect,info) ->
xadd_cstr vect info sys ;
Vect.fold (fun s v _ -> ISet.add v s) vrs cstr.coeffs) ISet.empty li in
{sys = sys ;vars = vars}
let system_list sys =
let { sys = s ; vars = v } = sys in
System.fold (fun k bi l -> (k, !bi)::l) s []
(** [add (v1,c1) (v2,c2) ]
precondition: (c1 <>/ Int 0 && c2 <>/ Int 0)
@return a pair [(v,ln)] such that
[v] is the sum of vector [v1] divided by [c1] and vector [v2] divided by [c2]
Note that the resulting vector is not normalised.
*)
let add (v1,c1) (v2,c2) =
assert (c1 <>/ Int 0 && c2 <>/ Int 0) ;
let res = mul_add (Int 1 // c1) v1 (Int 1 // c2) v2 in
(res, count res)
let add (v1,c1) (v2,c2) =
let res = add (v1,c1) (v2,c2) in
(* Printf.printf "add(%a,%s,%a,%s) -> %a\n" pp_vect v1 (string_of_num c1) pp_vect v2 (string_of_num c2) pp_vect (fst res) ;*)
res
(** To perform Fourier elimination, constraints are categorised depending on the sign of the variable to eliminate. *)
(** [split x vect info (l,m,r)]
@param v is the variable to eliminate
@param l contains constraints such that (e + a*x) // a >= c / a
@param r contains constraints such that (e + a*x) // - a >= c / -a
@param m contains constraints which do not mention [x]
*)
let split x (vect: vector) info (l,m,r) =
match get x vect with
| Int 0 -> (* The constraint does not mention [x], store it in m *)
(l,(vect,info)::m,r)
| vl -> (* otherwise *)
let cons_bound lst bd =
match bd with
| None -> lst
| Some bnd -> (vl,vect,{info with bound = Some bnd,None})::lst in
let lb,rb = info.bound in
if Int.equal (sign_num vl) 1
then (cons_bound l lb,m,cons_bound r rb)
else (* sign_num vl = -1 *)
(cons_bound l rb,m,cons_bound r lb)
(** [project vr sys] projects system [sys] over the set of variables [ISet.remove vr sys.vars ].
This is a one step Fourier elimination.
*)
let project vr sys =
let (l,m,r) = System.fold (fun vect rf l_m_r -> split vr vect !rf l_m_r) sys.sys ([],[],[]) in
let new_sys = System.create (System.length sys.sys) in
(* Constraints in [m] belong to the projection - for those [vr] is already projected out *)
List.iter (fun (vect,info) -> System.replace new_sys vect (ref info) ) m ;
let elim (v1,vect1,info1) (v2,vect2,info2) =
let {neg = n1 ; pos = p1 ; bound = bound1 ; prf = prf1} = info1
and {neg = n2 ; pos = p2 ; bound = bound2 ; prf = prf2} = info2 in
let bnd1 = Option.get (fst bound1)
and bnd2 = Option.get (fst bound2) in
let bound = (bnd1 // v1) +/ (bnd2 // minus_num v2) in
let vres,(n,p) = add (vect1,v1) (vect2,minus_num v2) in
(vres,{neg = n ; pos = p ; bound = (Some bound, None); prf = Elim(vr,info1.prf,info2.prf)}) in
List.iter(fun l_elem -> List.iter (fun r_elem ->
let (vect,info) = elim l_elem r_elem in
match normalise_cstr vect info with
| Redundant -> ()
| Contradiction -> raise (SystemContradiction info.prf)
| Cstr(vect,info) -> xadd_cstr vect info new_sys) r ) l;
{sys = new_sys ; vars = ISet.remove vr sys.vars}
(** [project_using_eq] performs elimination by pivoting using an equation.
This is the counter_part of the [elim] sub-function of [!project].
@param vr is the variable to be used as pivot
@param c is the coefficient of variable [vr] in vector [vect]
@param len is the length of the equation
@param bound is the bound of the equation
@param prf is the proof of the equation
*)
let project_using_eq vr c vect bound prf (vect',info') =
match get vr vect' with
| Int 0 -> (vect',info')
| c2 ->
let c1 = if c2 >=/ Int 0 then minus_num c else c in
let c2 = abs_num c2 in
let (vres,(n,p)) = add (vect,c1) (vect', c2) in
let cst = bound // c1 in
let bndres =
let f x = cst +/ x // c2 in
let (l,r) = info'.bound in
(Option.map f l , Option.map f r) in
(vres,{neg = n ; pos = p ; bound = bndres ; prf = Elim(vr,prf,info'.prf)})
let elim_var_using_eq vr vect cst prf sys =
let c = get vr vect in
let elim_var = project_using_eq vr c vect cst prf in
let new_sys = System.create (System.length sys.sys) in
System.iter(fun vect iref ->
let (vect',info') = elim_var (vect,!iref) in
match normalise_cstr vect' info' with
| Redundant -> ()
| Contradiction -> raise (SystemContradiction info'.prf)
| Cstr(vect,info') -> xadd_cstr vect info' new_sys) sys.sys ;
{sys = new_sys ; vars = ISet.remove vr sys.vars}
(** [size sys] computes the number of entries in the system of constraints *)
let size sys = System.fold (fun v iref s -> s + (!iref).neg + (!iref).pos) sys 0
module IMap = CMap.Make(Int)
(** [eval_vect map vect] evaluates vector [vect] using the values of [map].
If [map] binds all the variables of [vect], we get
[eval_vect map [(x1,v1);...;(xn,vn)] = (IMap.find x1 map * v1) + ... + (IMap.find xn map) * vn , []]
The function returns as second argument, a sub-vector consisting in the variables that are not in [map]. *)
let eval_vect map vect =
Vect.fold (fun (sum,rst) v vl ->
try
let val_v = IMap.find v map in
(sum +/ (val_v */ vl), rst)
with
Not_found -> (sum, Vect.set v vl rst)) (Int 0,Vect.null) vect
(** [restrict_bound n sum itv] returns the interval of [x]
given that (fst itv) <= x * n + sum <= (snd itv) *)
let restrict_bound n sum (itv:interval) =
let f x = (x -/ sum) // n in
let l,r = itv in
match sign_num n with
| 0 -> if in_bound itv sum
then (None,None) (* redundant *)
else failwith "SystemContradiction"
| 1 -> Option.map f l , Option.map f r
| _ -> Option.map f r , Option.map f l
(** [bound_of_variable map v sys] computes the interval of [v] in
[sys] given a mapping [map] binding all the other variables *)
let bound_of_variable map v sys =
System.fold (fun vect iref bnd ->
let sum,rst = eval_vect map vect in
let vl = Vect.get v rst in
match inter bnd (restrict_bound vl sum (!iref).bound) with
| None ->
Printf.fprintf stdout "bound_of_variable: eval_vecr %a = %s,%a\n"
Vect.pp vect (Num.string_of_num sum) Vect.pp rst ;
Printf.fprintf stdout "current interval: %a\n" Itv.pp (!iref).bound;
failwith "bound_of_variable: impossible"
| Some itv -> itv) sys (None,None)
(** [pick_small_value bnd] picks a value being closed to zero within the interval *)
let pick_small_value bnd =
match bnd with
| None , None -> Int 0
| None , Some i -> if (Int 0) <=/ (floor_num i) then Int 0 else floor_num i
| Some i,None -> if i <=/ (Int 0) then Int 0 else ceiling_num i
| Some i,Some j ->
if i <=/ Int 0 && Int 0 <=/ j
then Int 0
else if ceiling_num i <=/ floor_num j
then ceiling_num i (* why not *) else i
(** [solution s1 sys_l = Some(sn,\[(vn-1,sn-1);...; (v1,s1)\]\@sys_l)]
then [sn] is a system which contains only [black_v] -- if it existed in [s1]
and [sn+1] is obtained by projecting [vn] out of [sn]
@raise SystemContradiction if system [s] has no solution
*)
let solve_sys black_v choose_eq choose_variable sys sys_l =
let rec solve_sys sys sys_l =
if debug then Printf.printf "S #%i size %i\n" (System.length sys.sys) (size sys.sys);
if debug then Printf.printf "solve_sys :\n %a" pp_system sys.sys ;
let eqs = choose_eq sys in
try
let (v,vect,cst,ln) = fst (List.find (fun ((v,_,_,_),_) -> v <> black_v) eqs) in
if debug then
(Printf.printf "\nE %a = %s variable %i\n" Vect.pp vect (string_of_num cst) v ;
flush stdout);
let sys' = elim_var_using_eq v vect cst ln sys in
solve_sys sys' ((v,sys)::sys_l)
with Not_found ->
let vars = choose_variable sys in
try
let (v,est) = (List.find (fun (v,_) -> v <> black_v) vars) in
if debug then (Printf.printf "\nV : %i estimate %f\n" v est ; flush stdout) ;
let sys' = project v sys in
solve_sys sys' ((v,sys)::sys_l)
with Not_found -> (* we are done *) Inl (sys,sys_l) in
solve_sys sys sys_l
let solve black_v choose_eq choose_variable cstrs =
try
let sys = load_system cstrs in
if debug then Printf.printf "solve :\n %a" pp_system sys.sys ;
solve_sys black_v choose_eq choose_variable sys []
with SystemContradiction prf -> Inr prf
(** The purpose of module [EstimateElimVar] is to try to estimate the cost of eliminating a variable.
The output is an ordered list of (variable,cost).
*)
module EstimateElimVar =
struct
type sys_list = (vector * cstr_info) list
let abstract_partition (v:int) (l: sys_list) =
let rec xpart (l:sys_list) (ltl:sys_list) (n:int list) (z:int) (p:int list) =
match l with
| [] -> (ltl, n,z,p)
| (l1,info) ::rl ->
match Vect.choose l1 with
| None -> xpart rl ((Vect.null,info)::ltl) n (info.neg+info.pos+z) p
| Some(vr, vl, rl1) ->
if Int.equal v vr
then
let cons_bound lst bd =
match bd with
| None -> lst
| Some bnd -> info.neg+info.pos::lst in
let lb,rb = info.bound in
if Int.equal (sign_num vl) 1
then xpart rl ((rl1,info)::ltl) (cons_bound n lb) z (cons_bound p rb)
else xpart rl ((rl1,info)::ltl) (cons_bound n rb) z (cons_bound p lb)
else
(* the variable is greater *)
xpart rl ((l1,info)::ltl) n (info.neg+info.pos+z) p
in
let (sys',n,z,p) = xpart l [] [] 0 [] in
let ln = float_of_int (List.length n) in
let sn = float_of_int (List.fold_left (+) 0 n) in
let lp = float_of_int (List.length p) in
let sp = float_of_int (List.fold_left (+) 0 p) in
(sys', float_of_int z +. lp *. sn +. ln *. sp -. lp*.ln)
let choose_variable sys =
let {sys = s ; vars = v} = sys in
let sl = system_list sys in
let evals = fst
(ISet.fold (fun v (eval,s) -> let ts,vl = abstract_partition v s in
((v,vl)::eval, ts)) v ([],sl)) in
List.sort (fun x y -> compare_float (snd x) (snd y) ) evals
end
open EstimateElimVar
(** The module [EstimateElimEq] is similar to [EstimateElimVar] but it orders equations.
*)
module EstimateElimEq =
struct
let itv_point bnd =
match bnd with
|(Some a, Some b) -> a =/ b
| _ -> false
let rec unroll_until v l =
match Vect.choose l with
| None -> (false,Vect.null)
| Some(i,_,rl) -> if Int.equal i v
then (true,rl)
else if i < v then unroll_until v rl else (false,l)
let rec choose_simple_equation eqs =
match eqs with
| [] -> None
| (vect,a,prf,ln)::eqs ->
match Vect.choose vect with
| Some(i,v,rst) -> if Vect.is_null rst
then Some (i,vect,a,prf,ln)
else choose_simple_equation eqs
| _ -> choose_simple_equation eqs
let choose_primal_equation eqs (sys_l: (Vect.t *cstr_info) list) =
(* Counts the number of equations referring to variable [v] --
It looks like nb_cst is dead...
*)
let is_primal_equation_var v =
List.fold_left (fun nb_eq (vect,info) ->
if fst (unroll_until v vect)
then if itv_point info.bound then nb_eq + 1 else nb_eq
else nb_eq) 0 sys_l in
let rec find_var vect =
match Vect.choose vect with
| None -> None
| Some(i,_,vect) ->
let nb_eq = is_primal_equation_var i in
if Int.equal nb_eq 2
then Some i else find_var vect in
let rec find_eq_var eqs =
match eqs with
| [] -> None
| (vect,a,prf,ln)::l ->
match find_var vect with
| None -> find_eq_var l
| Some r -> Some (r,vect,a,prf,ln)
in
match choose_simple_equation eqs with
| None -> find_eq_var eqs
| Some res -> Some res
let choose_equality_var sys =
let sys_l = system_list sys in
let equalities = List.fold_left
(fun l (vect,info) ->
match info.bound with
| Some a , Some b ->
if a =/ b then (* This an equation *)
(vect,a,info.prf,info.neg+info.pos)::l else l
| _ -> l
) [] sys_l in
let rec estimate_cost v ct sysl acc tlsys =
match sysl with
| [] -> (acc,tlsys)
| (l,info)::rsys ->
let ln = info.pos + info.neg in
let (b,l) = unroll_until v l in
match b with
| true ->
if itv_point info.bound
then estimate_cost v ct rsys (acc+ln) ((l,info)::tlsys) (* this is free *)
else estimate_cost v ct rsys (acc+ln+ct) ((l,info)::tlsys) (* should be more ? *)
| false -> estimate_cost v ct rsys (acc+ln) ((l,info)::tlsys) in
match choose_primal_equation equalities sys_l with
| None ->
let cost_eq eq const prf ln acc_costs =
let rec cost_eq eqr sysl costs =
match Vect.choose eqr with
| None -> costs
| Some(v,_,eqr) -> let (cst,tlsys) = estimate_cost v (ln-1) sysl 0 [] in
cost_eq eqr tlsys (((v,eq,const,prf),cst)::costs) in
cost_eq eq sys_l acc_costs in
let all_costs = List.fold_left (fun all_costs (vect,const,prf,ln) -> cost_eq vect const prf ln all_costs) [] equalities in
(* pp_list (fun o ((v,eq,_,_),cst) -> Printf.fprintf o "((%i,%a),%i)\n" v pp_vect eq cst) stdout all_costs ; *)
List.sort (fun x y -> Int.compare (snd x) (snd y) ) all_costs
| Some (v,vect, const,prf,_) -> [(v,vect,const,prf),0]
end
open EstimateElimEq
module Fourier =
struct
let optimise vect l =
(* We add a dummy (fresh) variable for vector *)
let fresh =
List.fold_left (fun fr c -> Pervasives.max fr (Vect.fresh c.coeffs)) 0 l in
let cstr = {
coeffs = Vect.set fresh (Int (-1)) vect ;
op = Eq ;
cst = (Int 0)} in
match solve fresh choose_equality_var choose_variable (cstr::l) with
| Inr prf -> None (* This is an unsatisfiability proof *)
| Inl (s,_) ->
try
Some (bound_of_variable IMap.empty fresh s.sys)
with x when CErrors.noncritical x ->
Printf.printf "optimise Exception : %s" (Printexc.to_string x);
None
let find_point cstrs =
match solve max_int choose_equality_var choose_variable cstrs with
| Inr prf -> Inr prf
| Inl (_,l) ->
let rec rebuild_solution l map =
match l with
| [] -> map
| (v,e)::l ->
let itv = bound_of_variable map v e.sys in
let map = IMap.add v (pick_small_value itv) map in
rebuild_solution l map
in
let map = rebuild_solution l IMap.empty in
let vect = IMap.fold (fun v i vect -> Vect.set v i vect) map Vect.null in
if debug then Printf.printf "SOLUTION %a" Vect.pp vect ;
let res = Inl vect in
res
end
module Proof =
struct
(** A proof term in the sense of a ZMicromega.RatProof is a positive combination of the hypotheses which leads to a contradiction.
The proofs constructed by Fourier elimination are more like execution traces:
- certain facts are recorded but are useless
- certain inferences are implicit.
The following code implements proof reconstruction.
*)
let add x y = fst (add x y)
let forall_pairs f l1 l2 =
List.fold_left (fun acc e1 ->
List.fold_left (fun acc e2 ->
match f e1 e2 with
| None -> acc
| Some v -> v::acc) acc l2) [] l1
let add_op x y =
match x , y with
| Eq , Eq -> Eq
| _ -> Ge
let pivot v (p1,c1) (p2,c2) =
let {coeffs = v1 ; op = op1 ; cst = n1} = c1
and {coeffs = v2 ; op = op2 ; cst = n2} = c2 in
match Vect.get v v1 , Vect.get v v2 with
| Int 0 , _ | _ , Int 0 -> None
| a , b ->
if Int.equal ((sign_num a) * (sign_num b)) (-1)
then
Some (add (p1,abs_num a) (p2,abs_num b) ,
{coeffs = add (v1,abs_num a) (v2,abs_num b) ;
op = add_op op1 op2 ;
cst = n1 // (abs_num a) +/ n2 // (abs_num b) })
else if op1 == Eq
then Some (add (p1,minus_num (a // b)) (p2,Int 1),
{coeffs = add (v1,minus_num (a// b)) (v2 ,Int 1) ;
op = add_op op1 op2;
cst = n1 // (minus_num (a// b)) +/ n2 // (Int 1)})
else if op2 == Eq
then
Some (add (p2,minus_num (b // a)) (p1,Int 1),
{coeffs = add (v2,minus_num (b// a)) (v1 ,Int 1) ;
op = add_op op1 op2;
cst = n2 // (minus_num (b// a)) +/ n1 // (Int 1)})
else None (* op2 could be Eq ... this might happen *)
let normalise_proofs l =
List.fold_left (fun acc (prf,cstr) ->
match acc with
| Inr _ -> acc (* I already found a contradiction *)
| Inl acc ->
match norm_cstr cstr 0 with
| Redundant -> Inl acc
| Contradiction -> Inr (prf,cstr)
| Cstr(v,info) -> Inl ((prf,cstr,v,info)::acc)) (Inl []) l
type oproof = (vector * cstr * num) option
let merge_proof (oleft:oproof) (prf,cstr,v,info) (oright:oproof) =
let (l,r) = info.bound in
let keep p ob bd =
match ob , bd with
| None , None -> None
| None , Some b -> Some(prf,cstr,b)
| Some _ , None -> ob
| Some(prfl,cstrl,bl) , Some b -> if p bl b then Some(prf,cstr, b) else ob in
let oleft = keep (<=/) oleft l in
let oright = keep (>=/) oright r in
(* Now, there might be a contradiction *)
match oleft , oright with
| None , _ | _ , None -> Inl (oleft,oright)
| Some(prfl,cstrl,l) , Some(prfr,cstrr,r) ->
if l <=/ r
then Inl (oleft,oright)
else (* There is a contradiction - it should show up by scaling up the vectors - any pivot should do*)
match Vect.choose cstrr.coeffs with
| None -> Inr (add (prfl,Int 1) (prfr,Int 1), cstrr) (* this is wrong *)
| Some(v,_,_) ->
match pivot v (prfl,cstrl) (prfr,cstrr) with
| None -> failwith "merge_proof : pivot is not possible"
| Some x -> Inr x
let mk_proof hyps prf =
(* I am keeping list - I might have a proof for the left bound and a proof for the right bound.
If I perform aggressive elimination of redundancies, I expect the list to be of length at most 2.
For each proof list, all the vectors should be of the form a.v for different constants a.
*)
let rec mk_proof prf =
match prf with
| Assum i -> [ (Vect.set i (Int 1) Vect.null , List.nth hyps i) ]
| Elim(v,prf1,prf2) ->
let prfsl = mk_proof prf1
and prfsr = mk_proof prf2 in
(* I take only the pairs for which the elimination is meaningful *)
forall_pairs (pivot v) prfsl prfsr
| And(prf1,prf2) ->
let prfsl1 = mk_proof prf1
and prfsl2 = mk_proof prf2 in
(* detect trivial redundancies and contradictions *)
match normalise_proofs (prfsl1@prfsl2) with
| Inr x -> [x] (* This is a contradiction - this should be the end of the proof *)
| Inl l -> (* All the vectors are the same *)
let prfs =
List.fold_left (fun acc e ->
match acc with
| Inr _ -> acc (* I have a contradiction *)
| Inl (oleft,oright) -> merge_proof oleft e oright) (Inl(None,None)) l in
match prfs with
| Inr x -> [x]
| Inl (oleft,oright) ->
match oleft , oright with
| None , None -> []
| None , Some(prf,cstr,_) | Some(prf,cstr,_) , None -> [prf,cstr]
| Some(prf1,cstr1,_) , Some(prf2,cstr2,_) -> [prf1,cstr1;prf2,cstr2] in
mk_proof prf
end
¤ Dauer der Verarbeitung: 0.9 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.
|