aboutsummaryrefslogtreecommitdiffstats
path: root/src/lia/lia.ml
blob: dce79ee267e5f4437c0a5d99b51460291520accf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
(**************************************************************************)
(*                                                                        *)
(*     SMTCoq                                                             *)
(*     Copyright (C) 2011 - 2019                                          *)
(*                                                                        *)
(*     See file "AUTHORS" for the list of authors                         *)
(*                                                                        *)
(*   This file is distributed under the terms of the CeCILL-C licence     *)
(*                                                                        *)
(**************************************************************************)


(*** Linking SMT Terms to Micromega Terms ***)
open Util
open Structures.Micromega_plugin_Micromega

open SmtForm
open SmtAtom

(* morphism for expression over Z *)

let rec pos_of_int i =
  if i <= 1
  then XH
  else
    if i land 1 = 0
    then XO(pos_of_int (i lsr 1))
    else XI(pos_of_int (i lsr 1))

type my_tbl =
    {tbl:(hatom,int) Hashtbl.t; mutable count:int}

let get_atom_var tbl ha =
  try Hashtbl.find tbl.tbl ha
  with Not_found ->
    let v = tbl.count in
    Hashtbl.add tbl.tbl ha v;
    tbl.count <- v + 1;
    v

let create_tbl n = {tbl=Hashtbl.create n;count=1}

let rec smt_Atom_to_micromega_pos ha =
  match Atom.atom ha with
  | Auop(UO_xO, ha) ->
      XO (smt_Atom_to_micromega_pos ha)
  | Auop(UO_xI, ha) ->
      XI (smt_Atom_to_micromega_pos ha)
  | Acop CO_xH -> XH
  | _ -> raise Not_found

let smt_Atom_to_micromega_Z ha =
  match Atom.atom ha with
  | Auop(UO_Zpos, ha) ->
      Zpos (smt_Atom_to_micromega_pos ha)
  | Auop(UO_Zneg, ha) ->
      Zneg (smt_Atom_to_micromega_pos ha)
  | Acop CO_Z0 -> Z0
  | _ -> raise Not_found

let rec smt_Atom_to_micromega_pExpr tbl ha =
  match Atom.atom ha with
  | Abop (BO_Zplus, ha, hb) ->
      let a = smt_Atom_to_micromega_pExpr tbl ha in
      let b = smt_Atom_to_micromega_pExpr tbl hb in
      PEadd(a, b)
  | Abop (BO_Zmult, ha, hb) ->
      let a = smt_Atom_to_micromega_pExpr tbl ha in
      let b = smt_Atom_to_micromega_pExpr tbl hb in
      PEmul(a, b)
  | Abop (BO_Zminus, ha, hb) ->
      let a = smt_Atom_to_micromega_pExpr tbl ha in
      let b = smt_Atom_to_micromega_pExpr tbl hb in
      PEsub(a, b)
  | Auop (UO_Zopp, ha) ->
      let a = smt_Atom_to_micromega_pExpr tbl ha in
      PEopp a
  | _ ->
      try PEc (smt_Atom_to_micromega_Z ha)
      with Not_found ->
	let v = get_atom_var tbl ha in
	PEX (pos_of_int v)


(* morphism for LIA proposition (=, >, ...) *)

let smt_binop_to_micromega_formula tbl op ha hb =
  let op =
    match op with
    | BO_Zlt -> OpLt
    | BO_Zle -> OpLe
    | BO_Zge -> OpGe
    | BO_Zgt -> OpGt
    | BO_eq _ -> OpEq
    | _ -> Structures.error
	  "lia.ml: smt_binop_to_micromega_formula expecting a formula"
  in
  let lhs = smt_Atom_to_micromega_pExpr tbl ha in
  let rhs = smt_Atom_to_micromega_pExpr tbl hb in
  {flhs = lhs; fop = op; frhs = rhs }

let smt_Atom_to_micromega_formula tbl ha =
  match Atom.atom ha with
    | Abop (op,ha,hb) -> smt_binop_to_micromega_formula tbl op ha hb
    | _ -> Structures.error
	  "lia.ml: smt_Atom_to_micromega_formula was expecting an LIA formula"

(* specialized fold *)

(* morphism for general formulas *)

let binop_array g tbl op def t =
  let n = Array.length t in
  if n = 0 then
    def
  else
    let aux = ref (g tbl t.(0)) in
    for i = 1 to (n-1) do
      aux := op !aux (g tbl t.(i))
    done;
    !aux

let rec smt_Form_to_coq_micromega_formula tbl l =
  let v =
    match Form.pform l with
      | Fatom ha -> A (smt_Atom_to_micromega_formula tbl ha, Tt)
      | Fapp (Ftrue, _) -> TT
      | Fapp (Ffalse, _) -> FF
      | Fapp (Fand, l) -> binop_array smt_Form_to_coq_micromega_formula tbl (fun x y -> Cj (x,y)) TT l
      | Fapp (For, l) -> binop_array smt_Form_to_coq_micromega_formula tbl (fun x y -> D (x,y)) FF l
      | Fapp (Fxor, l) -> failwith "todo:Fxor"
      | Fapp (Fimp, l) -> binop_array smt_Form_to_coq_micromega_formula tbl (fun x y -> I (x,None,y)) TT l
      | Fapp (Fiff, l) -> failwith "todo:Fiff"
      | Fapp (Fite, l) -> failwith "todo:Fite"
      | Fapp (Fnot2 _, l) ->
        if Array.length l <> 1 then
          failwith "Lia.smt_Form_to_coq_micromega_formula: wrong number of arguments for Fnot2"
        else
          smt_Form_to_coq_micromega_formula tbl l.(0)
      | FbbT _ -> assert false
      | Fapp (Fforall _, _) -> assert false
  in
  if Form.is_pos l then v
  else N(v)

let binop_list tbl op def l =
  match l with
  | [] -> def
  | f::l -> List.fold_left (fun x y -> op x (smt_Form_to_coq_micromega_formula tbl y)) (smt_Form_to_coq_micromega_formula tbl f) l

let smt_clause_to_coq_micromega_formula tbl cl =
  binop_list tbl (fun x y -> Cj (x,y)) TT (List.map Form.neg cl)


(* backported from Coq *)
type ('option,'a,'prf,'model) prover = {
  name : string ; (* name of the prover *)
  get_option : unit ->'option ; (* find the options of the prover *)
  prover : ('option *  'a list) -> ('prf, 'model) Structures.Micromega_plugin_Certificate.res ; (* the prover itself *)
  hyps : 'prf -> Structures.Micromega_plugin_Mutils.ISet.t ; (* extract the indexes of the hypotheses really used in the proof *)
  compact : 'prf -> (int -> int) -> 'prf ; (* remap the hyp indexes according to function *)
  pp_prf : out_channel -> 'prf -> unit ;(* pretting printing of proof *)
  pp_f   : out_channel -> 'a   -> unit (* pretty printing of the formulas (polynomials)*)
}

let lia_enum  = ref true
let max_depth = max_int
let lia_proof_depth = ref max_depth
let get_lia_option () =
 (!Structures.Micromega_plugin_Certificate.use_simplex,!lia_enum,!lia_proof_depth)

let lift_pexpr_prover p l =  p (List.map (fun (e,o) -> Structures.Micromega_plugin_Micromega.denorm e , o) l)

module CacheZ = Structures.Micromega_plugin_Persistent_cache.PHashtable(struct
 type prover_option = bool * bool* int
 type t = prover_option * ((Structures.Micromega_plugin_Micromega.z Structures.Micromega_plugin_Micromega.pol * Structures.Micromega_plugin_Micromega.op1) list)
  let equal = (=)
  let hash  = Hashtbl.hash
end)

let memo_zlinear_prover = CacheZ.memo ".lia.cache" (fun ((_,ce,b),s) -> lift_pexpr_prover (Structures.Micromega_plugin_Certificate.lia ce b) s)

let xhyps_of_cone base acc prf =
  let open Structures.Micromega_plugin_Micromega in

  let rec xtract e acc =
    match e with
    | PsatzC _ | PsatzZ | PsatzSquare _ -> acc
    | PsatzIn n -> let n = (Structures.Micromega_plugin_Mutils.CoqToCaml.nat n) in
                        if n >= base
                        then  Structures.Micromega_plugin_Mutils.ISet.add (n-base) acc
                        else acc
    | PsatzMulC(_,c) -> xtract  c acc
    | PsatzAdd(e1,e2) |  PsatzMulE(e1,e2) -> xtract e1 (xtract e2 acc) in

    xtract prf acc

let hyps_of_pt pt =
  let open Structures.Micromega_plugin_Micromega in

  let rec xhyps base pt acc =
    match pt with
      | DoneProof -> acc
      | RatProof (c, pt) -> xhyps (base + 1) pt (xhyps_of_cone base acc c)
      | CutProof (c, pt) -> xhyps (base + 1) pt (xhyps_of_cone base acc c)
      | EnumProof (c1, c2, l) ->
         let s = xhyps_of_cone base (xhyps_of_cone base acc c2) c1 in
         List.fold_left (fun s x -> xhyps (base + 1) x s) s l
      | ExProof (_, pt) -> xhyps (base + 3) pt acc
  in

  xhyps 0 pt Structures.Micromega_plugin_Mutils.ISet.empty

let compact_cone prf f  =
  let open Structures.Micromega_plugin_Micromega in

  let np n = Structures.Micromega_plugin_Mutils.CamlToCoq.nat (f (Structures.Micromega_plugin_Mutils.CoqToCaml.nat n)) in

  let rec xinterp prf =
    match prf with
    | PsatzC _ | PsatzZ | PsatzSquare _ -> prf
    | PsatzIn n -> PsatzIn (np n)
    | PsatzMulC(e,c) -> PsatzMulC(e,xinterp c)
    | PsatzAdd(e1,e2) -> PsatzAdd(xinterp e1,xinterp e2)
    | PsatzMulE(e1,e2) -> PsatzMulE(xinterp e1,xinterp e2) in

    xinterp prf

let compact_pt pt f =
  let open Structures.Micromega_plugin_Micromega in
  let translate ofset x = if x < ofset then x else f (x - ofset) + ofset in
  let rec compact_pt ofset pt =
    match pt with
    | DoneProof -> DoneProof
    | RatProof (c, pt) ->
      RatProof (compact_cone c (translate ofset), compact_pt (ofset + 1) pt)
    | CutProof (c, pt) ->
      CutProof (compact_cone c (translate ofset), compact_pt (ofset + 1) pt)
    | EnumProof (c1, c2, l) ->
      EnumProof
        ( compact_cone c1 (translate ofset)
        , compact_cone c2 (translate ofset)
        , map (fun x -> compact_pt (ofset + 1) x) l )
    | ExProof (x, pt) -> ExProof (x, compact_pt (ofset + 3) pt)
  in
  compact_pt 0 pt

let pp_nat o n = Printf.fprintf o "%i" (Structures.Micromega_plugin_Mutils.CoqToCaml.nat n)

let pp_positive o x = Printf.fprintf o "%i" (Structures.Micromega_plugin_Mutils.CoqToCaml.positive x)

let pp_z o x = Printf.fprintf o "%s" (Big_int.string_of_big_int (Structures.Micromega_plugin_Mutils.CoqToCaml.z_big_int x))

let pp_list op cl elt o l =
  let rec _pp  o l =
    match l with
      | [] -> ()
      | [e] -> Printf.fprintf o "%a" elt e
      | e::l -> Printf.fprintf o "%a ,%a" elt e  _pp l in
  Printf.fprintf o "%s%a%s" op _pp l cl

let pp_pol pp_c o e =
  let open Structures.Micromega_plugin_Micromega in
  let rec pp_pol o e =
    match e with
      | Pc n -> Printf.fprintf o "Pc %a" pp_c n
      | Pinj(p,pol) -> Printf.fprintf o "Pinj(%a,%a)" pp_positive p pp_pol pol
      | PX(pol1,p,pol2) -> Printf.fprintf o "PX(%a,%a,%a)" pp_pol pol1 pp_positive p pp_pol pol2 in
  pp_pol o e

let pp_psatz pp_z o e =
  let open Structures.Micromega_plugin_Micromega in
  let rec pp_cone o e =
    match e with
      | PsatzIn n ->
         Printf.fprintf o "(In %a)%%nat" pp_nat n
      | PsatzMulC(e,c) ->
         Printf.fprintf o "( %a [*] %a)" (pp_pol pp_z) e pp_cone c
      | PsatzSquare e ->
         Printf.fprintf o "(%a^2)" (pp_pol pp_z) e
      | PsatzAdd(e1,e2) ->
         Printf.fprintf o "(%a [+] %a)" pp_cone e1 pp_cone e2
      | PsatzMulE(e1,e2) ->
         Printf.fprintf o "(%a [*] %a)" pp_cone e1 pp_cone e2
      | PsatzC p ->
         Printf.fprintf o "(%a)%%positive" pp_z p
      | PsatzZ    ->
         Printf.fprintf o "0" in
  pp_cone o e

let rec pp_proof_term o p =
  let open Structures.Micromega_plugin_Micromega in
  match p with
    | DoneProof -> Printf.fprintf o "D"
    | RatProof (cone, rst) ->
       Printf.fprintf o "R[%a,%a]" (pp_psatz pp_z) cone pp_proof_term rst
    | CutProof (cone, rst) ->
       Printf.fprintf o "C[%a,%a]" (pp_psatz pp_z) cone pp_proof_term rst
    | EnumProof (c1, c2, rst) ->
       Printf.fprintf o "EP[%a,%a,%a]" (pp_psatz pp_z) c1 (pp_psatz pp_z) c2
         (pp_list "[" "]" pp_proof_term)
         rst
    | ExProof (p, prf) ->
       Printf.fprintf o "Ex[%a,%a]" pp_positive p pp_proof_term prf

let linear_Z =   {
  name    = "lia";
 get_option = get_lia_option;
 prover  = memo_zlinear_prover ;
  hyps    = hyps_of_pt;
  compact = compact_pt;
  pp_prf  = pp_proof_term;
  pp_f    = fun o x -> pp_pol pp_z o (fst x)
}

let find_witness  p polys1 =
  let open Structures.Micromega_plugin_Certificate in
  let polys1 = List.map fst polys1 in
  match p.prover (p.get_option (), polys1) with
  | Model m -> Model m
  | Unknown -> Unknown
  | Prf prf -> Prf(prf,p)

let witness_list prover l =
  let open Structures.Micromega_plugin_Certificate in
 let rec xwitness_list l =
  match l with
   | [] -> Prf []
   | e :: l ->
      match xwitness_list l with
      | Model (m,e) -> Model (m,e)
      | Unknown     -> Unknown
      | Prf l ->
         match find_witness  prover e  with
         | Model m -> Model (m,e)
         | Unknown -> Unknown
         | Prf w ->  Prf (w::l) in
 xwitness_list l

let witness_list_tags = witness_list

let tauto_lia ff =
  let prover = linear_Z in
  let cnf_ff,_ = Structures.Micromega_plugin_Micromega.cnfZ ff in
  match witness_list_tags prover cnf_ff with
    | Structures.Micromega_plugin_Certificate.Prf l -> Some (List.map fst l)
    | _ -> None

(* call to micromega solver *)
let build_lia_certif cl =
  let tbl = create_tbl 13 in
  let f = I(smt_clause_to_coq_micromega_formula tbl cl, None, FF) in
  tauto_lia f