~ubuntu-branches/ubuntu/wily/coq-doc/wily

« back to all changes in this revision

Viewing changes to contrib/micromega/certificate.ml

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu, Stéphane Glondu, Samuel Mimram
  • Date: 2010-01-07 22:50:39 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100107225039-n3cq82589u0qt0s2
Tags: 8.2pl1-1
[ Stéphane Glondu ]
* New upstream release (Closes: #563669)
  - remove patches
* Packaging overhaul:
  - use git, advertise it in Vcs-* fields of debian/control
  - use debhelper 7 and dh with override
  - use source format 3.0 (quilt)
* debian/control:
  - set Maintainer to d-o-m, set Uploaders to Sam and myself
  - add Homepage field
  - bump Standards-Version to 3.8.3
* Register PDF documentation into doc-base
* Add debian/watch
* Update debian/copyright

[ Samuel Mimram ]
* Change coq-doc's description to mention that it provides documentation in
  pdf format, not postscript, closes: #543545.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(************************************************************************)
 
2
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
 
3
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
 
4
(*   \VV/  **************************************************************)
 
5
(*    //   *      This file is distributed under the terms of the       *)
 
6
(*         *       GNU Lesser General Public License Version 2.1        *)
 
7
(************************************************************************)
 
8
(*                                                                      *)
 
9
(* Micromega: A reflexive tactic using the Positivstellensatz           *)
 
10
(*                                                                      *)
 
11
(*  Frédéric Besson (Irisa/Inria) 2006-2008                             *)
 
12
(*                                                                      *)
 
13
(************************************************************************)
 
14
 
 
15
(* We take as input a list of polynomials [p1...pn] and return an unfeasibility
 
16
   certificate polynomial. *)
 
17
 
 
18
(*open Micromega.Polynomial*)
 
19
open Big_int
 
20
open Num
 
21
 
 
22
module Mc = Micromega
 
23
module Ml2C = Mutils.CamlToCoq
 
24
module C2Ml = Mutils.CoqToCaml
 
25
 
 
26
let (<+>) = add_num
 
27
let (<->) = minus_num
 
28
let (<*>) = mult_num
 
29
 
 
30
type var = Mc.positive
 
31
 
 
32
module Monomial :
 
33
sig
 
34
 type t
 
35
 val const : t
 
36
 val var : var -> t
 
37
 val find : var -> t -> int
 
38
 val mult : var -> t -> t
 
39
 val prod : t -> t -> t
 
40
 val compare : t -> t -> int
 
41
 val pp : out_channel -> t -> unit
 
42
 val fold : (var -> int -> 'a -> 'a) -> t -> 'a -> 'a
 
43
end
 
44
 =
 
45
struct
 
46
 (* A monomial is represented by a multiset of variables  *)
 
47
 module Map = Map.Make(struct type t = var let compare = Pervasives.compare end)
 
48
 open Map
 
49
 
 
50
 type t = int Map.t
 
51
 
 
52
 (* The monomial that corresponds to a constant *)
 
53
 let const = Map.empty
 
54
  
 
55
 (* The monomial 'x' *)
 
56
 let var x = Map.add x 1 Map.empty
 
57
 
 
58
 (* Get the degre of a variable in a monomial *)
 
59
 let find x m = try find x m with Not_found -> 0
 
60
  
 
61
 (* Multiply a monomial by a variable *)
 
62
 let mult x m = add x (  (find x m) + 1) m
 
63
  
 
64
 (* Product of monomials *)
 
65
 let prod m1 m2 = Map.fold (fun k d m -> add k ((find k m) + d) m) m1 m2
 
66
  
 
67
 (* Total ordering of monomials *)
 
68
 let compare m1 m2 = Map.compare Pervasives.compare m1 m2
 
69
 
 
70
 let pp o m = Map.iter (fun k v -> 
 
71
  if v = 1 then Printf.fprintf o "x%i." (C2Ml.index k)
 
72
  else     Printf.fprintf o "x%i^%i." (C2Ml.index k) v) m
 
73
 
 
74
 let fold = fold
 
75
 
 
76
end
 
77
 
 
78
 
 
79
module  Poly :
 
80
 (* A polynomial is a map of monomials *)
 
81
 (* 
 
82
    This is probably a naive implementation 
 
83
    (expected to be fast enough - Coq is probably the bottleneck)
 
84
    *The new ring contribution is using a sparse Horner representation.
 
85
 *)
 
86
sig
 
87
 type t
 
88
 val get : Monomial.t -> t -> num
 
89
 val variable : var -> t
 
90
 val add : Monomial.t -> num -> t -> t
 
91
 val constant : num -> t
 
92
 val mult : Monomial.t -> num -> t -> t
 
93
 val product : t -> t -> t
 
94
 val addition : t -> t -> t
 
95
 val uminus : t -> t
 
96
 val fold : (Monomial.t -> num -> 'a -> 'a) -> t -> 'a -> 'a
 
97
 val pp : out_channel -> t -> unit
 
98
 val compare : t -> t -> int
 
99
end =
 
100
struct
 
101
 (*normalisation bug : 0*x ... *)
 
102
 module P = Map.Make(Monomial)
 
103
 open P
 
104
 
 
105
 type t = num P.t
 
106
 
 
107
 let pp o p = P.iter (fun k v -> 
 
108
  if compare_num v (Int 0) <> 0
 
109
  then 
 
110
   if Monomial.compare Monomial.const k = 0
 
111
   then         Printf.fprintf o "%s " (string_of_num v)
 
112
   else Printf.fprintf o "%s*%a " (string_of_num v) Monomial.pp k) p  
 
113
 
 
114
 (* Get the coefficient of monomial mn *)
 
115
 let get : Monomial.t -> t -> num = 
 
116
  fun mn p -> try find mn p with Not_found -> (Int 0)
 
117
 
 
118
 
 
119
 (* The polynomial 1.x *)
 
120
 let variable : var -> t =
 
121
  fun  x ->  add (Monomial.var x) (Int 1) empty
 
122
   
 
123
 (*The constant polynomial *)
 
124
 let constant : num -> t =
 
125
  fun c -> add (Monomial.const) c empty
 
126
 
 
127
 (* The addition of a monomial *)
 
128
 
 
129
 let add : Monomial.t -> num -> t -> t =
 
130
  fun mn v p -> 
 
131
   let vl = (get mn p) <+> v in
 
132
    add mn vl p
 
133
 
 
134
 
 
135
 (** Design choice: empty is not a polynomial 
 
136
     I do not remember why .... 
 
137
 **)
 
138
 
 
139
 (* The product by a monomial *)
 
140
 let mult : Monomial.t -> num -> t -> t =
 
141
  fun mn v p -> 
 
142
   fold (fun mn' v' res -> P.add (Monomial.prod mn mn') (v<*>v') res) p empty
 
143
 
 
144
 
 
145
 let  addition : t -> t -> t =
 
146
  fun p1 p2 -> fold (fun mn v p -> add mn v p) p1 p2
 
147
   
 
148
 
 
149
 let product : t -> t -> t =
 
150
  fun p1 p2 -> 
 
151
   fold (fun mn v res -> addition (mult mn v p2) res ) p1 empty
 
152
 
 
153
 
 
154
 let uminus : t -> t =
 
155
  fun p -> map (fun v -> minus_num v) p
 
156
 
 
157
 let fold = P.fold
 
158
 
 
159
 let compare = compare compare_num
 
160
end
 
161
 
 
162
open Mutils
 
163
type 'a number_spec = {
 
164
 bigint_to_number : big_int -> 'a;
 
165
 number_to_num : 'a  -> num;
 
166
 zero : 'a;
 
167
 unit : 'a;
 
168
 mult : 'a -> 'a -> 'a;
 
169
 eqb  : 'a -> 'a -> Mc.bool
 
170
}
 
171
 
 
172
let z_spec = {
 
173
 bigint_to_number = Ml2C.bigint ;
 
174
 number_to_num = (fun x -> Big_int (C2Ml.z_big_int x));
 
175
 zero = Mc.Z0;
 
176
 unit = Mc.Zpos Mc.XH;
 
177
 mult = Mc.zmult;
 
178
 eqb  = Mc.zeq_bool
 
179
}
 
180
 
 
181
 
 
182
let q_spec = {
 
183
 bigint_to_number = (fun x -> {Mc.qnum = Ml2C.bigint x; Mc.qden = Mc.XH});
 
184
 number_to_num = C2Ml.q_to_num;
 
185
 zero = {Mc.qnum = Mc.Z0;Mc.qden = Mc.XH};
 
186
 unit = {Mc.qnum =  (Mc.Zpos Mc.XH) ; Mc.qden = Mc.XH};
 
187
 mult = Mc.qmult;
 
188
 eqb  = Mc.qeq_bool
 
189
}
 
190
 
 
191
let r_spec = z_spec
 
192
 
 
193
 
 
194
 
 
195
 
 
196
let dev_form n_spec  p =
 
197
 let rec dev_form p = 
 
198
  match p with
 
199
   | Mc.PEc z ->  Poly.constant (n_spec.number_to_num z)
 
200
   | Mc.PEX v ->  Poly.variable v
 
201
   | Mc.PEmul(p1,p2) -> 
 
202
      let p1 = dev_form p1 in
 
203
      let p2 = dev_form p2 in
 
204
       Poly.product p1 p2 
 
205
   | Mc.PEadd(p1,p2) -> Poly.addition (dev_form p1) (dev_form p2)
 
206
   | Mc.PEopp p ->  Poly.uminus (dev_form p)
 
207
   | Mc.PEsub(p1,p2) ->  Poly.addition (dev_form p1) (Poly.uminus (dev_form p2))
 
208
   | Mc.PEpow(p,n)   ->  
 
209
      let p = dev_form p in
 
210
      let n = C2Ml.n n in
 
211
      let rec pow n = 
 
212
       if n = 0 
 
213
       then Poly.constant (n_spec.number_to_num n_spec.unit)
 
214
       else Poly.product p (pow (n-1)) in
 
215
       pow n in
 
216
  dev_form p
 
217
 
 
218
 
 
219
let monomial_to_polynomial mn = 
 
220
 Monomial.fold 
 
221
  (fun v i acc -> 
 
222
   let mn = if i = 1 then Mc.PEX v else Mc.PEpow (Mc.PEX v ,Ml2C.n i) in
 
223
    if acc = Mc.PEc (Mc.Zpos Mc.XH)
 
224
    then mn 
 
225
    else Mc.PEmul(mn,acc))
 
226
  mn 
 
227
  (Mc.PEc (Mc.Zpos Mc.XH))
 
228
  
 
229
let list_to_polynomial vars l = 
 
230
 assert (List.for_all (fun x -> ceiling_num x =/ x) l);
 
231
 let var x = monomial_to_polynomial (List.nth vars x)  in 
 
232
 let rec xtopoly p i = function
 
233
  | [] -> p
 
234
  | c::l -> if c =/  (Int 0) then xtopoly p (i+1) l 
 
235
    else let c = Mc.PEc (Ml2C.bigint (numerator c)) in
 
236
    let mn = 
 
237
     if c =  Mc.PEc (Mc.Zpos Mc.XH)
 
238
     then var i
 
239
     else Mc.PEmul (c,var i) in
 
240
    let p' = if p = Mc.PEc Mc.Z0 then mn else
 
241
      Mc.PEadd (mn, p) in
 
242
     xtopoly p' (i+1) l in
 
243
  
 
244
  xtopoly (Mc.PEc Mc.Z0) 0 l
 
245
 
 
246
let rec fixpoint f x =
 
247
 let y' = f x in
 
248
  if y' = x then y'
 
249
  else fixpoint f y'
 
250
 
 
251
 
 
252
 
 
253
 
 
254
 
 
255
 
 
256
 
 
257
 
 
258
let  rec_simpl_cone n_spec e = 
 
259
 let simpl_cone = 
 
260
  Mc.simpl_cone n_spec.zero n_spec.unit n_spec.mult n_spec.eqb in
 
261
 
 
262
 let rec rec_simpl_cone  = function
 
263
 | Mc.S_Mult(t1, t2) -> 
 
264
    simpl_cone  (Mc.S_Mult (rec_simpl_cone t1, rec_simpl_cone t2))
 
265
 | Mc.S_Add(t1,t2)  -> 
 
266
    simpl_cone (Mc.S_Add (rec_simpl_cone t1, rec_simpl_cone t2))
 
267
 |  x           -> simpl_cone x in
 
268
  rec_simpl_cone e
 
269
   
 
270
   
 
271
let simplify_cone n_spec c = fixpoint (rec_simpl_cone n_spec) c
 
272
 
 
273
type cone_prod = 
 
274
  Const of cone 
 
275
  | Ideal of cone *cone 
 
276
  | Mult of cone * cone 
 
277
  | Other of cone
 
278
and cone =   Mc.zWitness
 
279
 
 
280
 
 
281
 
 
282
let factorise_linear_cone c =
 
283
 
 
284
 let rec cone_list  c l = 
 
285
  match c with
 
286
   | Mc.S_Add (x,r) -> cone_list  r (x::l)
 
287
   |  _        ->  c :: l in
 
288
  
 
289
 let factorise c1 c2 =
 
290
  match c1 , c2 with
 
291
   | Mc.S_Ideal(x,y) , Mc.S_Ideal(x',y') -> 
 
292
      if x = x' then Some (Mc.S_Ideal(x, Mc.S_Add(y,y'))) else None
 
293
   | Mc.S_Mult(x,y) , Mc.S_Mult(x',y') -> 
 
294
      if x = x' then Some (Mc.S_Mult(x, Mc.S_Add(y,y'))) else None
 
295
   |  _     -> None in
 
296
  
 
297
 let rec rebuild_cone l pending  =
 
298
  match l with
 
299
   | [] -> (match pending with
 
300
      | None -> Mc.S_Z
 
301
      | Some p -> p
 
302
     )
 
303
   | e::l -> 
 
304
      (match pending with
 
305
       | None -> rebuild_cone l (Some e) 
 
306
       | Some p -> (match factorise p e with
 
307
          | None -> Mc.S_Add(p, rebuild_cone l (Some e))
 
308
          | Some f -> rebuild_cone l (Some f) )
 
309
      ) in
 
310
 
 
311
  (rebuild_cone (List.sort Pervasives.compare (cone_list c [])) None)
 
312
 
 
313
 
 
314
 
 
315
(* The binding with Fourier might be a bit obsolete 
 
316
   -- how does it handle equalities ? *)
 
317
 
 
318
(* Certificates are elements of the cone such that P = 0  *)
 
319
 
 
320
(* To begin with, we search for certificates of the form:
 
321
   a1.p1 + ... an.pn + b1.q1 +... + bn.qn + c = 0   
 
322
   where pi >= 0 qi > 0
 
323
   ai >= 0 
 
324
   bi >= 0
 
325
   Sum bi + c >= 1
 
326
   This is a linear problem: each monomial is considered as a variable.
 
327
   Hence, we can use fourier.
 
328
 
 
329
   The variable c is at index 0
 
330
*)
 
331
 
 
332
open Mfourier
 
333
   (*module Fourier = Fourier(Vector.VList)(SysSet(Vector.VList))*)
 
334
   (*module Fourier = Fourier(Vector.VSparse)(SysSetAlt(Vector.VSparse))*)
 
335
module Fourier = Mfourier.Fourier(Vector.VSparse)(*(SysSetAlt(Vector.VMap))*)
 
336
 
 
337
module Vect = Fourier.Vect
 
338
open Fourier.Cstr
 
339
 
 
340
(* fold_left followed by a rev ! *)
 
341
 
 
342
let constrain_monomial mn l  = 
 
343
 let coeffs = List.fold_left (fun acc p -> (Poly.get mn p)::acc) [] l in
 
344
  if mn = Monomial.const
 
345
  then  
 
346
   { coeffs = Vect.from_list ((Big_int unit_big_int):: (List.rev coeffs)) ; 
 
347
     op = Eq ; 
 
348
     cst = Big_int zero_big_int  }
 
349
  else
 
350
   { coeffs = Vect.from_list ((Big_int zero_big_int):: (List.rev coeffs)) ; 
 
351
     op = Eq ; 
 
352
     cst = Big_int zero_big_int  }
 
353
 
 
354
    
 
355
let positivity l = 
 
356
 let rec xpositivity i l = 
 
357
  match l with
 
358
   | [] -> []
 
359
   | (_,Mc.Equal)::l -> xpositivity (i+1) l
 
360
   | (_,_)::l -> 
 
361
      {coeffs = Vect.update (i+1) (fun _ -> Int 1) Vect.null ; 
 
362
       op = Ge ; 
 
363
       cst = Int 0 }  :: (xpositivity (i+1) l)
 
364
 in
 
365
  xpositivity 0 l
 
366
 
 
367
 
 
368
let string_of_op = function
 
369
 | Mc.Strict -> "> 0" 
 
370
 | Mc.NonStrict -> ">= 0" 
 
371
 | Mc.Equal -> "= 0"
 
372
 | Mc.NonEqual -> "<> 0"
 
373
 
 
374
 
 
375
 
 
376
(* If the certificate includes at least one strict inequality, 
 
377
   the obtained polynomial can also be 0 *)
 
378
let build_linear_system l =
 
379
 
 
380
 (* Gather the monomials:  HINT add up of the polynomials *)
 
381
 let l' = List.map fst l in
 
382
 let monomials = 
 
383
  List.fold_left (fun acc p -> Poly.addition p acc) (Poly.constant (Int 0)) l'
 
384
 in  (* For each monomial, compute a constraint *)
 
385
 let s0 = 
 
386
  Poly.fold (fun mn _ res -> (constrain_monomial mn l')::res) monomials [] in
 
387
  (* I need at least something strictly positive *)
 
388
 let strict = {
 
389
  coeffs = Vect.from_list ((Big_int unit_big_int)::
 
390
                            (List.map (fun (x,y) -> 
 
391
                             match y with Mc.Strict -> 
 
392
                              Big_int unit_big_int 
 
393
                              | _ -> Big_int zero_big_int) l));
 
394
  op = Ge ; cst = Big_int unit_big_int } in
 
395
  (* Add the positivity constraint *)
 
396
  {coeffs = Vect.from_list ([Big_int unit_big_int]) ; 
 
397
   op = Ge ; 
 
398
   cst = Big_int zero_big_int}::(strict::(positivity l)@s0)
 
399
 
 
400
 
 
401
let big_int_to_z = Ml2C.bigint
 
402
 
 
403
(* For Q, this is a pity that the certificate has been scaled 
 
404
   -- at a lower layer, certificates are using nums... *)
 
405
let make_certificate n_spec cert li = 
 
406
 let bint_to_cst = n_spec.bigint_to_number in
 
407
  match cert with
 
408
   | [] -> None
 
409
   | e::cert' -> 
 
410
      let cst = match compare_big_int e zero_big_int with
 
411
       | 0 -> Mc.S_Z
 
412
       | 1 ->  Mc.S_Pos (bint_to_cst e) 
 
413
       | _ -> failwith "positivity error" 
 
414
      in
 
415
      let rec scalar_product cert l =
 
416
       match cert with
 
417
        | [] -> Mc.S_Z
 
418
        | c::cert -> match l with
 
419
           | [] -> failwith "make_certificate(1)"
 
420
           | i::l ->  
 
421
              let r = scalar_product cert l in
 
422
               match compare_big_int c  zero_big_int with
 
423
                | -1 -> Mc.S_Add (
 
424
                   Mc.S_Ideal (Mc.PEc ( bint_to_cst c), Mc.S_In (Ml2C.nat i)), 
 
425
                   r)
 
426
                | 0  -> r
 
427
                | _ ->  Mc.S_Add (
 
428
                   Mc.S_Mult (Mc.S_Pos (bint_to_cst c), Mc.S_In (Ml2C.nat i)),
 
429
                   r) in
 
430
       
 
431
      Some ((factorise_linear_cone 
 
432
              (simplify_cone n_spec (Mc.S_Add (cst, scalar_product cert' li)))))
 
433
 
 
434
 
 
435
exception Found of Monomial.t
 
436
 
 
437
let raw_certificate l = 
 
438
 let sys = build_linear_system l in
 
439
  try 
 
440
   match Fourier.find_point sys with
 
441
    | None -> None
 
442
    | Some cert ->  Some (rats_to_ints (Vect.to_list cert)) 
 
443
       (* should not use rats_to_ints *)
 
444
  with x -> 
 
445
   if debug 
 
446
   then (Printf.printf "raw certificate %s" (Printexc.to_string x);   
 
447
         flush stdout) ;
 
448
   None
 
449
 
 
450
 
 
451
let simple_linear_prover to_constant l =
 
452
 let (lc,li) = List.split l in
 
453
  match raw_certificate lc with
 
454
   |  None -> None (* No certificate *)
 
455
   | Some cert -> make_certificate to_constant cert li
 
456
      
 
457
      
 
458
 
 
459
let linear_prover n_spec l  =
 
460
 let li = List.combine l (interval 0 (List.length l -1)) in
 
461
 let (l1,l') = List.partition 
 
462
  (fun (x,_) -> if snd' x = Mc.NonEqual then true else false) li in
 
463
 let l' = List.map 
 
464
  (fun (c,i) -> let (Mc.Pair(x,y)) = c in 
 
465
                 match y with 
 
466
                   Mc.NonEqual -> failwith "cannot happen" 
 
467
                  |  y -> ((dev_form n_spec x, y),i)) l' in
 
468
  
 
469
  simple_linear_prover n_spec l' 
 
470
 
 
471
 
 
472
let linear_prover n_spec l  =
 
473
 try linear_prover n_spec l with
 
474
   x -> (print_string (Printexc.to_string x); None)
 
475
 
 
476
(* zprover.... *)
 
477
 
 
478
(* I need to gather the set of variables --->
 
479
   Then go for fold 
 
480
   Once I have an interval, I need a certificate : 2 other fourier elims.
 
481
   (I could probably get the certificate directly 
 
482
   as it is done in the fourier contrib.)
 
483
*)
 
484
 
 
485
let make_linear_system l =
 
486
 let l' = List.map fst l in
 
487
 let monomials = List.fold_left (fun acc p -> Poly.addition p acc) 
 
488
  (Poly.constant (Int 0)) l' in
 
489
 let monomials = Poly.fold 
 
490
  (fun mn _ l -> if mn = Monomial.const then l else mn::l) monomials [] in
 
491
  (List.map (fun (c,op) -> 
 
492
   {coeffs = Vect.from_list (List.map (fun mn ->  (Poly.get mn c)) monomials) ; 
 
493
    op = op ; 
 
494
    cst = minus_num ( (Poly.get Monomial.const c))}) l
 
495
    ,monomials)
 
496
 
 
497
 
 
498
open Interval 
 
499
let pplus x y = Mc.PEadd(x,y)
 
500
let pmult x y = Mc.PEmul(x,y)
 
501
let pconst x = Mc.PEc x
 
502
let popp x = Mc.PEopp x
 
503
 
 
504
let debug = false
 
505
 
 
506
(* keep track of enumerated vectors *)
 
507
let rec mem p x  l = 
 
508
 match l with  [] -> false | e::l -> if p x e then true else mem p x l
 
509
 
 
510
let rec remove_assoc p x l = 
 
511
 match l with [] -> [] | e::l -> if p x (fst e) then
 
512
  remove_assoc p x l else e::(remove_assoc p x l) 
 
513
 
 
514
let eq x y = Vect.compare x y = 0
 
515
 
 
516
let  remove e  l  = List.fold_left (fun l x -> if eq x e then l else x::l) [] l
 
517
 
 
518
 
 
519
(* The prover is (probably) incomplete --
 
520
   only searching for naive cutting planes *)
 
521
 
 
522
let candidates sys = 
 
523
 let ll = List.fold_right (
 
524
  fun (Mc.Pair(e,k)) r -> 
 
525
   match k with 
 
526
    | Mc.NonStrict -> (dev_form z_spec e , Ge)::r
 
527
    | Mc.Equal     ->  (dev_form z_spec e , Eq)::r 
 
528
       (* we already know the bound -- don't compute it again *)
 
529
    | _     -> failwith "Cannot happen candidates") sys [] in
 
530
 
 
531
 let (sys,var_mn) = make_linear_system ll in
 
532
 let vars = mapi (fun _ i -> Vect.set i (Int 1) Vect.null) var_mn in
 
533
  (List.fold_left (fun l cstr ->   
 
534
   let gcd = Big_int (Vect.gcd cstr.coeffs) in
 
535
    if gcd =/ (Int 1) && cstr.op = Eq 
 
536
    then l 
 
537
    else  (Vect.mul (Int 1 // gcd) cstr.coeffs)::l) [] sys) @ vars
 
538
 
 
539
 
 
540
let rec xzlinear_prover planes sys = 
 
541
 match linear_prover z_spec sys with
 
542
  | Some prf -> Some (Mc.RatProof prf)
 
543
  | None     -> (* find the candidate with the smallest range *)
 
544
     (* Grrr - linear_prover is also calling 'make_linear_system' *)
 
545
     let ll = List.fold_right (fun (Mc.Pair(e,k)) r -> match k with 
 
546
       Mc.NonEqual -> r  
 
547
      | k -> (dev_form z_spec e , 
 
548
             match k with
 
549
               Mc.NonStrict -> Ge 
 
550
              | Mc.Equal              -> Eq
 
551
              | Mc.Strict | Mc.NonEqual -> failwith "Cannot happen") :: r) sys [] in
 
552
     let (ll,var) = make_linear_system ll in
 
553
     let candidates = List.fold_left (fun  acc vect -> 
 
554
      match Fourier.optimise vect ll with
 
555
       | None -> acc
 
556
       | Some i -> 
 
557
(*        Printf.printf "%s in %s\n" (Vect.string vect) (string_of_intrvl i) ; *)
 
558
          flush stdout ; 
 
559
          (vect,i) ::acc)  [] planes in
 
560
 
 
561
     let smallest_interval = 
 
562
      match List.fold_left (fun (x1,i1) (x2,i2) -> 
 
563
       if smaller_itv i1 i2 
 
564
       then (x1,i1) else (x2,i2)) (Vect.null,Itv(None,None)) candidates 
 
565
      with
 
566
       | (x,Itv(Some i, Some j))  -> Some(i,x,j)
 
567
       | (x,Point n) ->  Some(n,x,n)
 
568
       |   x        ->   None (* This might be a cutting plane *)
 
569
      in
 
570
      match smallest_interval with
 
571
       | Some (lb,e,ub) -> 
 
572
          let (lbn,lbd) = 
 
573
           (Ml2C.bigint (sub_big_int (numerator lb)  unit_big_int),
 
574
           Ml2C.bigint (denominator lb)) in
 
575
          let (ubn,ubd) = 
 
576
           (Ml2C.bigint (add_big_int unit_big_int (numerator ub)) , 
 
577
           Ml2C.bigint (denominator ub)) in
 
578
          let expr = list_to_polynomial var (Vect.to_list e) in
 
579
           (match 
 
580
             (*x <= ub ->  x  > ub *)
 
581
             linear_prover  z_spec 
 
582
              (Mc.Pair(pplus (pmult (pconst ubd) expr) (popp (pconst  ubn)),
 
583
                      Mc.NonStrict) :: sys),
 
584
            (* lb <= x  -> lb > x *)
 
585
            linear_prover z_spec 
 
586
             (Mc.Pair( pplus  (popp (pmult  (pconst lbd) expr)) (pconst lbn) ,  
 
587
                     Mc.NonStrict)::sys) 
 
588
            with
 
589
             | Some cub , Some clb  ->   
 
590
                (match zlinear_enum  (remove e planes)   expr 
 
591
                  (ceiling_num lb)  (floor_num ub) sys 
 
592
                 with
 
593
                  | None -> None
 
594
                  | Some prf -> 
 
595
                     Some (Mc.EnumProof(Ml2C.q lb,expr,Ml2C.q ub,clb,cub,prf)))
 
596
             | _ -> None
 
597
           )
 
598
       |  _ -> None
 
599
and zlinear_enum  planes expr clb cub l = 
 
600
 if clb >/  cub
 
601
 then Some Mc.Nil
 
602
 else 
 
603
  let pexpr = pplus (popp (pconst (Ml2C.bigint (numerator clb)))) expr in
 
604
  let sys' = (Mc.Pair(pexpr, Mc.Equal))::l in
 
605
   (*let enum =  *)
 
606
   match xzlinear_prover planes sys' with
 
607
    | None -> if debug then print_string "zlp?"; None
 
608
    | Some prf -> if debug then print_string "zlp!";
 
609
    match zlinear_enum planes expr (clb +/ (Int 1)) cub l with
 
610
     | None -> None
 
611
     | Some prfl -> Some (Mc.Cons(prf,prfl))
 
612
 
 
613
let zlinear_prover sys =  
 
614
 let candidates = candidates sys in
 
615
 (*  Printf.printf "candidates %d" (List.length candidates) ; *) 
 
616
 xzlinear_prover candidates sys
 
617
 
 
618
open Sos
 
619
 
 
620
let rec scale_term t = 
 
621
 match t with
 
622
  | Zero    -> unit_big_int , Zero
 
623
  | Const n ->  (denominator n) , Const (Big_int (numerator n))
 
624
  | Var n   -> unit_big_int , Var n
 
625
  | Inv _   -> failwith "scale_term : not implemented"
 
626
  | Opp t   -> let s, t = scale_term t in s, Opp t
 
627
  | Add(t1,t2) -> let s1,y1 = scale_term t1 and s2,y2 = scale_term t2 in
 
628
    let g = gcd_big_int s1 s2 in
 
629
    let s1' = div_big_int s1 g in
 
630
    let s2' = div_big_int s2 g in
 
631
    let e = mult_big_int g (mult_big_int s1' s2') in
 
632
     if (compare_big_int e unit_big_int) = 0
 
633
     then (unit_big_int, Add (y1,y2))
 
634
     else       e, Add (Mul(Const (Big_int s2'), y1),
 
635
                       Mul (Const (Big_int s1'), y2))
 
636
  | Sub _ -> failwith "scale term: not implemented"
 
637
  | Mul(y,z) ->       let s1,y1 = scale_term y and s2,y2 = scale_term z in
 
638
                       mult_big_int s1 s2 , Mul (y1, y2)
 
639
  |  Pow(t,n) -> let s,t = scale_term t in
 
640
                  power_big_int_positive_int s  n , Pow(t,n)
 
641
  |   _ -> failwith "scale_term : not implemented"
 
642
 
 
643
let scale_term t =
 
644
 let (s,t') = scale_term t in
 
645
  s,t'
 
646
 
 
647
 
 
648
let get_index_of_ith_match f i l  =
 
649
 let rec get j res l =
 
650
  match l with
 
651
   | [] -> failwith "bad index"
 
652
   | e::l -> if f e
 
653
     then 
 
654
       (if j = i then res else get (j+1) (res+1) l )
 
655
     else get j (res+1) l in
 
656
  get 0 0 l
 
657
 
 
658
 
 
659
let rec scale_certificate pos = match pos with
 
660
 | Axiom_eq i ->  unit_big_int , Axiom_eq i
 
661
 | Axiom_le i ->  unit_big_int , Axiom_le i
 
662
 | Axiom_lt i ->   unit_big_int , Axiom_lt i
 
663
 | Monoid l   -> unit_big_int , Monoid l
 
664
 | Rational_eq n ->  (denominator n) , Rational_eq (Big_int (numerator n))
 
665
 | Rational_le n ->  (denominator n) , Rational_le (Big_int (numerator n))
 
666
 | Rational_lt n ->  (denominator n) , Rational_lt (Big_int (numerator n))
 
667
 | Square t -> let s,t' =  scale_term t in 
 
668
                mult_big_int s s , Square t'
 
669
 | Eqmul (t, y) -> let s1,y1 = scale_term t and s2,y2 = scale_certificate y in
 
670
                    mult_big_int s1 s2 , Eqmul (y1,y2)
 
671
 | Sum (y, z) -> let s1,y1 = scale_certificate y 
 
672
   and s2,y2 = scale_certificate z in
 
673
   let g = gcd_big_int s1 s2 in
 
674
   let s1' = div_big_int s1 g in
 
675
   let s2' = div_big_int s2 g in
 
676
    mult_big_int g (mult_big_int s1' s2'), 
 
677
    Sum (Product(Rational_le (Big_int s2'), y1),
 
678
        Product (Rational_le (Big_int s1'), y2))
 
679
 | Product (y, z) -> 
 
680
    let s1,y1 = scale_certificate y and s2,y2 = scale_certificate z in
 
681
     mult_big_int s1 s2 , Product (y1,y2)
 
682
 
 
683
 
 
684
open Micromega
 
685
 let rec term_to_q_expr = function
 
686
  | Const n ->  PEc (Ml2C.q n)
 
687
  | Zero   ->  PEc ( Ml2C.q (Int 0))
 
688
  | Var s   ->  PEX (Ml2C.index 
 
689
                      (int_of_string (String.sub s 1 (String.length s - 1))))
 
690
  | Mul(p1,p2) ->  PEmul(term_to_q_expr p1, term_to_q_expr p2)
 
691
  | Add(p1,p2) ->   PEadd(term_to_q_expr p1, term_to_q_expr p2)
 
692
  | Opp p ->   PEopp (term_to_q_expr p)
 
693
  | Pow(t,n) ->  PEpow (term_to_q_expr t,Ml2C.n n)
 
694
  | Sub(t1,t2) ->  PEsub (term_to_q_expr t1,  term_to_q_expr t2)
 
695
  | _ -> failwith "term_to_q_expr: not implemented"
 
696
 
 
697
let  q_cert_of_pos  pos = 
 
698
 let rec _cert_of_pos = function
 
699
   Axiom_eq i ->  Mc.S_In (Ml2C.nat i)
 
700
  | Axiom_le i ->  Mc.S_In (Ml2C.nat i)
 
701
  | Axiom_lt i ->  Mc.S_In (Ml2C.nat i)
 
702
  | Monoid l  -> Mc.S_Monoid (Ml2C.list Ml2C.nat l)
 
703
  | Rational_eq n | Rational_le n | Rational_lt n -> 
 
704
     if compare_num n (Int 0) = 0 then Mc.S_Z else
 
705
      Mc.S_Pos (Ml2C.q   n)
 
706
  | Square t -> Mc.S_Square (term_to_q_expr  t)
 
707
  | Eqmul (t, y) -> Mc.S_Ideal(term_to_q_expr t, _cert_of_pos y)
 
708
  | Sum (y, z) -> Mc.S_Add  (_cert_of_pos y, _cert_of_pos z)
 
709
  | Product (y, z) -> Mc.S_Mult (_cert_of_pos y, _cert_of_pos z) in
 
710
  simplify_cone q_spec (_cert_of_pos pos)
 
711
 
 
712
 
 
713
 let rec term_to_z_expr = function
 
714
  | Const n ->  PEc (Ml2C.bigint (big_int_of_num n))
 
715
  | Zero   ->  PEc ( Z0)
 
716
  | Var s   ->  PEX (Ml2C.index 
 
717
                      (int_of_string (String.sub s 1 (String.length s - 1))))
 
718
  | Mul(p1,p2) ->  PEmul(term_to_z_expr p1, term_to_z_expr p2)
 
719
  | Add(p1,p2) ->   PEadd(term_to_z_expr p1, term_to_z_expr p2)
 
720
  | Opp p ->   PEopp (term_to_z_expr p)
 
721
  | Pow(t,n) ->  PEpow (term_to_z_expr t,Ml2C.n n)
 
722
  | Sub(t1,t2) ->  PEsub (term_to_z_expr t1,  term_to_z_expr t2)
 
723
  | _ -> failwith "term_to_z_expr: not implemented"
 
724
 
 
725
let  z_cert_of_pos  pos = 
 
726
 let s,pos = (scale_certificate pos) in
 
727
 let rec _cert_of_pos = function
 
728
   Axiom_eq i ->  Mc.S_In (Ml2C.nat i)
 
729
  | Axiom_le i ->  Mc.S_In (Ml2C.nat i)
 
730
  | Axiom_lt i ->  Mc.S_In (Ml2C.nat i)
 
731
  | Monoid l  -> Mc.S_Monoid (Ml2C.list Ml2C.nat l)
 
732
  | Rational_eq n | Rational_le n | Rational_lt n -> 
 
733
     if compare_num n (Int 0) = 0 then Mc.S_Z else
 
734
      Mc.S_Pos (Ml2C.bigint (big_int_of_num  n))
 
735
  | Square t -> Mc.S_Square (term_to_z_expr  t)
 
736
  | Eqmul (t, y) -> Mc.S_Ideal(term_to_z_expr t, _cert_of_pos y)
 
737
  | Sum (y, z) -> Mc.S_Add  (_cert_of_pos y, _cert_of_pos z)
 
738
  | Product (y, z) -> Mc.S_Mult (_cert_of_pos y, _cert_of_pos z) in
 
739
  simplify_cone z_spec (_cert_of_pos pos)
 
740