sort generating system before printing
[sppoc.git] / Formel / gen_syst.ml
blob5e38253dab19dea81fbc8c6f26e6a3ebf9b50cc6
1 (*TeX
2 \subsection{Implementation}
3 *)
4 open Forme;;
5 open Systeme;;
6 open Num;;
7 open Util.Nums;;
8 open Util.Lists;;
10 (*TeX
11 \subsubsection{Type definitions}
13 type expr =
14 | FORM of forme
15 | MOD of modulo
16 | DIV of division
17 | NAE of non_aff_expr
18 and non_aff_expr = {nae_operator : string; nae_args : expr list}
19 and modulo = {mod_expr : expr; modulus : expr}
20 and division = {div_expr : expr; divisor : expr};;
22 type gen_ineq =
23 | Strict of expr (* expr > 0 *)
24 | Large of expr (* expr >= 0 *)
25 | Eq of expr (* expr = 0 *)
28 type gen_syst = gen_ineq list;;
30 exception Non_linear of expr;;
32 (*TeX
33 Comparison functions.
35 let rec eq_expr e e' = match e, e' with
36 | FORM f, FORM f' -> eq_forme f f'
37 | MOD {mod_expr = me; modulus = m},
38 MOD {mod_expr = me'; modulus = m'} ->
39 eq_expr m m' && eq_expr me me'
40 | DIV {div_expr = de; divisor = d},
41 DIV {div_expr = de'; divisor = d'} ->
42 eq_expr d d' && eq_expr de de'
43 | NAE {nae_operator = op; nae_args = a},
44 NAE {nae_operator = op'; nae_args = a'} ->
45 op = op' && (eq_lists eq_expr a a')
46 | _ -> false;;
48 let lt_lists lt_fun l l' =
49 let rec iter = function
50 | (e, e')::t ->
51 if lt_fun e e' then true
52 else if lt_fun e' e then false
53 else iter t
54 | [] -> false
56 if (List.length l) < (List.length l') then true
57 else if (List.length l) = (List.length l') then
58 iter (List.combine l l')
59 else false;;
61 let rec lt_expr e e' = match e, e' with
62 | FORM f, FORM f' -> lt_forme f f'
63 | FORM _, _ -> true
64 | _, FORM _ -> false
65 | MOD {mod_expr = me; modulus = m},
66 MOD {mod_expr = me'; modulus = m'} ->
67 lt_expr m m' || eq_expr m m' && lt_expr me me'
68 | MOD _ , _ -> true
69 | _, MOD _ -> false
70 | DIV {div_expr = de; divisor = d},
71 DIV {div_expr = de'; divisor = d'} ->
72 lt_expr d d' || eq_expr d d' && eq_expr de de'
73 | DIV _, _ -> true
74 | _, DIV _ -> false
75 | NAE {nae_operator = op; nae_args = a},
76 NAE {nae_operator = op'; nae_args = a'} ->
77 op < op' || op = op' && (lt_lists lt_expr a a');;
79 let leq_expr e e' = lt_expr e e' || eq_expr e e';;
81 let sort_args l = Sort.list leq_expr l;;
83 (*TeX
84 \subsubsection{Expression simplification}
86 let expr_is_form = function
87 | FORM _ -> true
88 | _ -> false;;
90 let rec form_of_expr = function
91 | FORM f -> f
92 | NAE {nae_operator = _; nae_args = el} as e ->
93 ignore (List.map form_of_expr el);
94 raise (Non_linear e)
95 | e -> raise (Non_linear e);;
97 let modularify_forme f m =
98 let fm = (forme_of_terme_list
99 (List.map
100 (fun t -> let c = terme_get_coef t in
101 if (mod_num c m =/ zero) then
102 terme_of_num zero
103 else t)
104 (forme_to_terme_list f))) in
105 if forme_is_num fm then
106 FORM (forme_of_num (mod_num (get_const fm) m))
107 else MOD {mod_expr = FORM fm; modulus = FORM (forme_of_num m)};;
109 let divide_forme f d =
110 if forme_is_num f
111 then FORM (forme_of_num (quo_num (get_const f) d))
112 else
113 begin match List.partition
114 (fun t -> mod_num (terme_get_coef t) d =/ zero)
115 (forme_to_terme_list f) with
116 | dt, [] -> FORM ((forme_of_terme_list dt) /| d)
117 | [], ndt -> DIV {div_expr = FORM (forme_of_terme_list ndt);
118 divisor = FORM (forme_of_num d)}
119 | dt, ndt ->
120 NAE {nae_operator = "+";
121 nae_args = [FORM ((forme_of_terme_list dt) /| d);
122 DIV {div_expr = FORM (forme_of_terme_list ndt);
123 divisor = FORM (forme_of_num d)}]}
124 end;;
126 let rec negate_formified_expression = function
127 | FORM f -> FORM (minus_forme f)
128 | MOD m -> NAE {nae_operator = "-"; nae_args = [MOD m]}
129 | DIV d -> NAE {nae_operator = "-"; nae_args = [DIV d]}
130 | NAE {nae_operator = op; nae_args = args} as nae ->
131 begin match op with
132 | "+" -> NAE {nae_operator = "+";
133 nae_args = sort_args (List.map
134 negate_formified_expression
135 args)}
136 | "-" ->
137 begin match args with
138 | [] -> invalid_arg "Gen_syst.negate_formified_expression"
139 | [e] -> e
140 | h::t -> NAE {nae_operator = "+";
141 nae_args =
142 (negate_formified_expression h)::t}
144 | "*" ->
145 begin match args with
146 | [] -> invalid_arg "Gen_syst.negate_formified_expression"
147 | [e] -> negate_formified_expression e
148 | h::t -> NAE {nae_operator = "*";
149 nae_args =
150 sort_args
151 ((negate_formified_expression h)::t)}
153 | "/" ->
154 begin match args with
155 | [] -> invalid_arg "Gen_syst.negate_formified_expression"
156 | [e] -> negate_formified_expression e
157 | h::t -> NAE {nae_operator = "/";
158 nae_args =
159 (negate_formified_expression h)::t}
161 | _ -> NAE {nae_operator = "-";
162 nae_args = [nae]}
163 end;;
165 let rec flatten_mult_args = function
166 | [] -> []
167 | NAE {nae_operator = "*"; nae_args = el}::t ->
168 el@(flatten_mult_args t)
169 | h::t -> h::(flatten_mult_args t);;
171 let powerify_mults = function
172 | [] -> []
173 | h::t ->
174 let make_power e n =
175 if n = 1 then e
176 else NAE {nae_operator = "**";
177 nae_args = [e; FORM (forme_of_num
178 (Num.num_of_int n))]} in
179 let rec build_freq e n = function
180 | e'::r when eq_expr e e' -> build_freq e (succ n) r
181 | e'::r -> (make_power e n)::(build_freq e' 1 r)
182 | [] -> [make_power e n] in
183 build_freq h 1 t;;
185 let mult_formified_expressions el =
186 match List.partition expr_is_form
187 (powerify_mults (sort_args (flatten_mult_args el))) with
188 | fe, [] ->
189 begin match List.partition forme_is_num
190 (List.map form_of_expr fe) with
191 | l, [] ->
192 FORM (forme_of_num
193 (List.fold_right mult_num
194 (List.map get_const l) un))
195 | l, [f] ->
196 FORM (List.fold_left mult_forme f
197 (List.map get_const l))
198 | l, h::t ->
199 NAE {nae_operator = "*";
200 nae_args =
201 sort_args
202 ((FORM (List.fold_left mult_forme h
203 (List.map get_const l)))
204 ::(List.map (fun f -> FORM f) t))}
206 | [], [nf] -> nf
207 | [], nfe -> NAE {nae_operator = "*";
208 nae_args = sort_args nfe}
209 | fe, nfe ->
210 begin match List.partition forme_is_num
211 (List.map form_of_expr fe) with
212 | l, [] ->
213 let n = (List.fold_right mult_num
214 (List.map get_const l) un) in
215 NAE {nae_operator = "*";
216 nae_args =
217 if n =/ un then sort_args nfe
218 else if n =/ moins_un then
219 begin match nfe with
220 | h::t ->
221 sort_args ((negate_formified_expression h)::t)
222 | _ ->
223 failwith
224 "Gen_syst.mult_formified_expressions"
226 else sort_args ((FORM (forme_of_num n))::nfe)}
227 | l, [f] ->
228 NAE {nae_operator = "*";
229 nae_args =
230 sort_args ((FORM (List.fold_left mult_forme f
231 (List.map get_const l)))
232 ::nfe)}
233 | l, h::t ->
234 NAE {nae_operator = "*";
235 nae_args =
236 sort_args (((FORM (List.fold_left mult_forme h
237 (List.map get_const l)))
238 ::(List.map (fun f -> FORM f) t))@nfe)}
239 end;;
241 let div_formified_expressions = function
242 | e::e'::r as el ->
243 begin match List.partition
244 (fun e -> expr_is_form e
245 && forme_is_num (form_of_expr e)) (e'::r) with
246 | ne, [] ->
247 if expr_is_form e
248 then FORM (List.fold_left div_forme
249 (form_of_expr e)
250 (List.map (fun e -> get_const
251 (form_of_expr e)) ne))
252 else let n = List.fold_left mult_num un
253 (List.map (fun e -> get_const
254 (form_of_expr e)) ne) in
255 if n =/ un then e
256 else if n =/ moins_un
257 then negate_formified_expression e
258 else NAE {nae_operator = "*";
259 nae_args = (sort_args [FORM (forme_of_num (un // n)); e])}
260 | [], nne -> NAE {nae_operator = "/";
261 nae_args = e::(sort_args nne)}
262 | ne, nne ->
263 if expr_is_form e
264 then NAE {nae_operator = "/";
265 nae_args =
266 (FORM (List.fold_left div_forme
267 (form_of_expr e)
268 (List.map
269 (fun e -> get_const
270 (form_of_expr e)) ne)))
271 ::(sort_args nne)}
272 else let n = List.fold_left mult_num un
273 (List.map (fun e -> get_const
274 (form_of_expr e)) ne) in
275 if n =/ un
276 then NAE {nae_operator = "/";
277 nae_args = e::(sort_args nne)}
278 else if n =/ moins_un
279 then NAE {nae_operator = "/";
280 nae_args = (negate_formified_expression e)
281 ::(sort_args nne)}
282 else NAE {nae_operator = "/";
283 nae_args = e::(sort_args ((FORM (forme_of_num n))::nne))}
285 | _ -> invalid_arg "Gen_syst.div_formified_expressions";;
287 let power_formified_expressions e e' =
288 if (expr_is_form e') && (forme_is_num (form_of_expr e'))
289 then
290 if (get_const (form_of_expr e')) = zero
291 then FORM (forme_of_num un)
292 else
293 if (get_const (form_of_expr e')) = un
294 then e
295 else
296 if (expr_is_form e) && (forme_is_num (form_of_expr e))
297 then FORM (forme_of_num (power_num
298 (get_const (form_of_expr e))
299 (get_const (form_of_expr e'))))
300 else NAE {nae_operator = "**"; nae_args = [e; e']}
301 else NAE {nae_operator = "**"; nae_args = [e; e']};;
303 let rec flatten_sums = function
304 | (NAE {nae_operator = "+";
305 nae_args = el})::t -> (flatten_sums el)@(flatten_sums t)
306 | e::t -> e::(flatten_sums t)
307 | [] -> []
309 let sum_exprs el =
310 let name = ref ""
311 and new_var () = Util.Name.gen "s" in
312 let rec make_term_list tl defs el =
313 let check e c t =
314 name := "";
315 List.iter (fun (v, e') ->
316 if eq_expr e e' then name := v) defs;
317 if !name = ""
318 then begin
319 List.iter (fun (v, e') ->
320 if eq_expr (negate_formified_expression e) e'
321 then name := v) defs;
322 if !name = ""
323 then begin
324 name := new_var ();
325 make_term_list ((make_terme !name c)::tl)
326 ((!name, e)::defs) t
327 end else
328 make_term_list ((make_terme !name (minus_num c))::tl) defs t
329 end else
330 make_term_list ((make_terme !name c)::tl) defs t
331 in match el with
332 | [] -> (forme_to_terme_list (forme_of_terme_list tl)), defs
333 | (NAE {nae_operator = "*";
334 nae_args = [FORM f; e]})::t when forme_is_num f ->
335 check e (get_const f) t
336 | h::t -> check h un t
337 and rebuild defs tl =
338 List.map (fun t ->
339 let c, v = (terme_get_coef t), (terme_get_var t)
340 in if c =/ un then List.assoc v defs
341 else if c =/ moins_un
342 then (negate_formified_expression
343 (List.assoc v defs))
344 else mult_formified_expressions
345 [FORM (forme_of_num c);
346 List.assoc v defs]) tl
348 let tl, defs = make_term_list [] [] el in
349 rebuild defs tl;;
351 let add_formified_expressions el =
352 match List.partition expr_is_form (flatten_sums el) with
353 | fe, [] ->
354 FORM (List.fold_right
355 add_forme
356 (List.map form_of_expr fe)
357 (forme_of_num zero))
358 | [], nfe ->
359 begin match sum_exprs nfe with
360 | [] -> FORM (forme_of_num zero)
361 | [e] -> e
362 | s -> NAE {nae_operator = "+";
363 nae_args = sort_args s}
365 | fe, nfe ->
366 let f = List.fold_right add_forme
367 (List.map form_of_expr fe)
368 (forme_of_num zero) in
369 begin match sum_exprs nfe with
370 | [] -> FORM f
371 | [e] ->
372 if forme_is_num f && (get_const f) =/ zero
373 then e
374 else NAE {nae_operator = "+";
375 nae_args = sort_args [FORM f; e]}
376 | s ->
377 NAE {nae_operator = "+";
378 nae_args =
379 if forme_is_num f && (get_const f) =/ zero
380 then sort_args s
381 else sort_args ((FORM f)::s)}
382 end;;
384 let factorize = function
385 | NAE {nae_operator = "+";
386 nae_args = el} as sumexpr -> begin
387 let build_sub_exprs = function
388 | NAE {nae_operator = "*";
389 nae_args = l} -> l
390 | e -> [e] in
391 let sub_exprs = Sort.list leq_expr
392 (List.flatten (List.map build_sub_exprs el)) in
393 let rec build_freq e n = function
394 | e'::r when eq_expr e e' -> build_freq e (succ n) r
395 | e'::r -> (e,n)::(build_freq e' 1 r)
396 | [] -> [(e,n)] in
397 let choose = function
398 | [] -> None
399 | (_,1)::_ -> None
400 | (e,_)::_ -> Some e in
401 match choose
402 (Sort.list
403 (fun (e,n) (e',n') -> n > n' || (n = n' && (lt_expr e' e)))
404 (build_freq (List.hd sub_exprs) 0 sub_exprs)) with
405 | None -> sumexpr
406 | Some factor -> begin
407 let fact = function
408 | NAE {nae_operator = "*"; nae_args = el}
409 when generic_mem eq_expr factor el ->
410 begin
411 match
412 generic_remove_first eq_expr factor el
413 with
414 | [] -> Some (FORM (forme_of_num un)), None
415 | [e] -> Some e, None
416 | l -> Some (mult_formified_expressions
417 (sort_args l)), None
419 | e when eq_expr factor e ->
420 Some (FORM (forme_of_num un)), None
421 | e -> None, Some e in
422 let rec split_and_remove_options = function
423 | (None, None)::t -> assert false
424 | (None, Some h)::t ->
425 let t1,t2 = split_and_remove_options t in
426 t1, (h::t2)
427 | (Some h, None)::t ->
428 let t1,t2 = split_and_remove_options t in
429 (h::t1), t2
430 | (Some h1, Some h2)::t ->
431 let t1,t2 = split_and_remove_options t in
432 (h1::t1), (h2::t2)
433 | [] -> [], [] in
434 match split_and_remove_options (List.map fact el) with
435 | [], _ -> assert false
436 | [e], [] -> mult_formified_expressions
437 (sort_args [factor;e])
438 | [e], l -> add_formified_expressions
439 (sort_args
440 ((mult_formified_expressions
441 (sort_args [factor;e]))::l))
442 | l, [] -> mult_formified_expressions
443 (sort_args [factor;
444 add_formified_expressions
445 (sort_args l)])
446 | l, l' -> add_formified_expressions
447 (sort_args
448 ((mult_formified_expressions
449 (sort_args
450 [factor;
451 add_formified_expressions
452 (sort_args l)]))::l'))
455 | e -> e;;
457 (*TeX
458 formify\_expr is the main simplification function. It computes all
459 the available linear forms.
461 let rec formify_step formify_args = function
462 | FORM f -> FORM f
463 | MOD {mod_expr = e; modulus = m} ->
464 let e' = formify_args e
465 and m' = formify_args m in
466 if (expr_is_form e') && (expr_is_form m')
467 && (forme_is_num (form_of_expr m'))
468 then modularify_forme
469 (form_of_expr e')
470 (get_const (form_of_expr m'))
471 else MOD {mod_expr = e'; modulus = m'}
472 | DIV {div_expr = e; divisor = d} ->
473 let e' = formify_args e
474 and d' = formify_args d in
475 if (expr_is_form e') && (expr_is_form d')
476 && (forme_is_num (form_of_expr d'))
477 then divide_forme
478 (form_of_expr e')
479 (get_const (form_of_expr d'))
480 else DIV {div_expr = e'; divisor = d'}
481 | NAE nae -> formify_nae formify_args nae
482 and formify_nae formify_args {nae_operator = op; nae_args = args} =
483 let fargs = List.map formify_args args in
484 match op with
485 | "+" -> factorize (add_formified_expressions (sort_args fargs))
486 | "-" ->
487 begin match fargs with
488 | [] -> invalid_arg "Gen_syst.formify_nae"
489 | [e] -> negate_formified_expression e
490 | h::t -> add_formified_expressions
491 (h::(List.map negate_formified_expression t))
493 | "*" -> mult_formified_expressions (sort_args fargs)
494 | "/" -> div_formified_expressions fargs
495 | "**" ->
496 begin match fargs with
497 | [e;e'] -> power_formified_expressions e e'
498 | _ -> invalid_arg "Gen_syst.formify_nae"
500 | op -> NAE {nae_operator = op; nae_args = fargs};;
502 let rec formify_expr e = formify_step formify_expr e;;
503 let formify_top_expr e = formify_step (fun exp -> exp) e;;
505 (*TeX
506 \subsubsection{Constructors}
508 let expr_of_forme f = FORM f;;
510 let add_expr e1 e2 =
511 formify_top_expr (NAE {nae_operator = "+";
512 nae_args = [e1; e2]});;
514 let add_expr_list el =
515 formify_top_expr (NAE {nae_operator = "+";
516 nae_args = el});;
518 let sub_expr e1 e2 =
519 formify_top_expr (NAE {nae_operator = "-";
520 nae_args = [e1; e2]});;
522 let sub_expr_list el =
523 if List.length el = 0 then invalid_arg "Gen_syst.sub_expr_list";
524 formify_top_expr (NAE {nae_operator = "-";
525 nae_args = (List.hd el)::(sort_args (List.tl el))});;
527 let minus_expr e = negate_formified_expression e;;
529 let mult_expr e1 e2 =
530 formify_top_expr (NAE {nae_operator = "*";
531 nae_args = [e1; e2]});;
533 let mult_expr_list el =
534 formify_top_expr (NAE {nae_operator = "*";
535 nae_args = el});;
537 let div_expr e1 e2 =
538 formify_top_expr (NAE {nae_operator = "/";
539 nae_args = [e1; e2]});;
541 let div_expr_list el =
542 if List.length el < 2 then invalid_arg "Gen_syst.div_expr_list";
543 formify_top_expr (NAE {nae_operator = "/";
544 nae_args = (List.hd el)::(sort_args (List.tl el))});;
546 let quo_expr e1 e2 =
547 formify_top_expr (DIV {div_expr = e1; divisor = e2});;
549 let mod_expr e1 e2 =
550 formify_top_expr (MOD {mod_expr = e1; modulus = e2});;
552 let gen_expr op args =
553 formify_top_expr (NAE {nae_operator = Util.Strings.remove op ' ';
554 nae_args = args});;
556 (*TeX
557 General destructor.
559 let destructor = function
560 | NAE {nae_operator = op; nae_args = args} -> op, args
561 | FORM f -> "", [(expr_of_forme f)]
562 | DIV {div_expr = n; divisor = d} -> "div", [n;d]
563 | MOD {mod_expr = n; modulus = d} -> "mod", [n;d];;
565 (*TeX
566 \texttt{gen\_syst\_to\_ineq\_list}.
568 let linearize_expr defs e =
569 let name = ref ""
570 and new_var () = Util.Name.gen "e" in
571 let rec make_forme defs = function
572 | FORM f -> (FORM f), defs
573 | MOD {mod_expr = me; modulus = FORM f} as exp ->
574 if forme_is_num f
575 then
576 begin
577 let mf, mdefs = make_forme defs me in
578 let mm = MOD {mod_expr = mf; modulus = FORM f} in
579 name := "";
580 List.iter
581 (fun (v, e) -> if eq_expr mm e then name := v) defs;
582 if !name = "" then begin
583 List.iter
584 (fun (v, e) ->
585 if eq_expr (negate_formified_expression mm) e
586 then name := v) defs;
587 if !name = "" then begin
588 name := new_var ();
589 FORM (forme_of_string !name), ((!name, mm)::mdefs)
590 end else
591 FORM (minus_forme (forme_of_string !name)), mdefs
592 end else
593 FORM (forme_of_string !name), mdefs
594 end
595 else raise (Non_linear exp)
596 | DIV {div_expr = de; divisor = FORM f} as exp ->
597 if forme_is_num f
598 then
599 begin
600 let df, mdefs = make_forme defs de in
601 let dd = DIV {div_expr = df; divisor = FORM f} in
602 name := "";
603 List.iter
604 (fun (v, e) -> if eq_expr dd e then name := v) defs;
605 if !name = "" then begin
606 List.iter
607 (fun (v, e) ->
608 if eq_expr (negate_formified_expression dd) e
609 then name := v) defs;
610 if !name = "" then begin
611 name := new_var ();
612 FORM (forme_of_string !name), ((!name, dd)::mdefs)
613 end else
614 FORM (minus_forme (forme_of_string !name)), mdefs
615 end else
616 FORM (forme_of_string !name), mdefs
617 end
618 else raise (Non_linear exp)
619 | NAE {nae_operator = op; nae_args = el} as exp ->
620 let defs', el' = List.fold_right
621 (fun e (defs, el') ->
622 let e', defs' = make_forme defs e in
623 defs', (e'::el'))
624 el (defs, [])
625 in let f = formify_expr (NAE {nae_operator = op; nae_args = el'})
627 (FORM (form_of_expr f)), defs'
628 | exp -> raise (Non_linear exp)
630 make_forme defs e;;
632 let linearize_ineq defs = function
633 | Large e ->
634 let e', defs' = linearize_expr defs e in
635 (Large e'), defs'
636 | Strict e ->
637 let e', defs' = linearize_expr defs e in
638 (Strict e'), defs'
639 | Eq e -> begin
640 match e with
641 | NAE {nae_operator = "+";
642 nae_args = [FORM v;
643 NAE {nae_operator = "-";
644 nae_args = [MOD {mod_expr = me;
645 modulus = FORM f}]}]}
646 when forme_is_var v ->
647 if forme_is_num f
648 then
649 let mf, mdefs = linearize_expr defs me in
650 let mm = MOD {mod_expr = mf; modulus = FORM f} in
651 Eq (FORM (forme_of_num zero)), ((forme_to_var v, mm)::mdefs)
652 else raise (Non_linear (MOD {mod_expr = me; modulus = FORM f}))
653 | _ -> let e', defs' = linearize_expr defs e in
654 (Eq e'), defs'
655 end;;
657 let ineq_list_of_gen_syst s =
658 let s', defs = List.fold_left
659 (fun (il, d) i ->
660 let i', d' = linearize_ineq d i in
661 (i'::il), d') ([], []) s
663 List.map (fun i -> match i with
664 | Eq e -> make_ineq (form_of_expr e) EQ zero
665 | Large e -> make_ineq (form_of_expr e) SUP zero
666 | Strict e -> make_ineq (form_of_expr e) SUP un)
667 (s'@
668 (List.flatten
669 (List.map
670 (fun (v, e) -> match e with
671 | MOD m ->
672 let q, r =
673 (FORM (forme_of_string (Util.Name.gen "div"))),
674 (FORM (forme_of_string v))
675 in [Eq (formify_expr
676 (NAE {nae_operator = "+";
677 nae_args =
678 [NAE {nae_operator = "*";
679 nae_args = [m.modulus; q]};
681 negate_formified_expression
682 m.mod_expr]}));
683 Large r;
684 Strict (formify_expr
685 (NAE {nae_operator = "-";
686 nae_args = [m.modulus; r]}))]
687 | DIV d ->
688 let q, r =
689 (FORM (forme_of_string v)),
690 (FORM (forme_of_string (Util.Name.gen "mod")))
691 in [Eq (formify_expr
692 (NAE {nae_operator = "+";
693 nae_args =
694 [NAE {nae_operator = "*";
695 nae_args = [d.divisor; q]};
697 negate_formified_expression
698 d.div_expr]}));
699 Large r;
700 Strict (formify_expr
701 (NAE {nae_operator = "-";
702 nae_args = [d.divisor; r]}))]
703 | e -> raise (Non_linear e))
704 defs)));;
706 (*TeX
707 Normalisation d'une inéquation.
709 let norm_ineq = function
710 | Eq (FORM f) -> Eq (FORM (div_forme f (pgcd_forme f)))
711 | Strict (FORM f) -> Strict (FORM (div_forme f (pgcd_forme f)))
712 | Large (FORM f) -> Large (FORM (div_forme f (pgcd_forme f)))
713 | i -> i;;
715 let make_ineq_eq e1 e2 = norm_ineq (Eq (sub_expr e1 e2));;
716 let make_ineq_le e1 e2 = norm_ineq (Large (sub_expr e2 e1));;
717 let make_ineq_lt e1 e2 = norm_ineq (Strict (sub_expr e2 e1));;
718 let make_ineq_ge e1 e2 = norm_ineq (Large (sub_expr e1 e2));;
719 let make_ineq_gt e1 e2 = norm_ineq (Strict (sub_expr e1 e2));;
721 let ineq_e_of_t i = match norm_ineq i with
722 | Eq e -> Eq e
723 | Large e -> Large e
724 | Strict e -> norm_ineq (Large (sub_expr e (FORM (forme_of_num un))));;
726 let ineq_t_of_e i = match norm_ineq i with
727 | Eq e -> Eq e
728 | Large e -> norm_ineq (Strict (add_expr e (FORM (forme_of_num un))))
729 | Strict e -> Strict e;;
731 let not_ineq = function
732 | Eq e -> invalid_arg "Gen_syst.not_ineq"
733 | Large e -> Strict (minus_expr e)
734 | Strict e -> Large (minus_expr e);;
736 let ineq_is_eq = function
737 | Eq _ -> true
738 | _ -> false;;
740 let ineq_is_ge = function
741 | Large _ -> true
742 | _ -> false;;
744 let ineq_is_gt = function
745 | Strict _ -> true
746 | _ -> false;;
748 let gen_ineq_of_ineq {in_forme = f; in_signe = s; in_biais = n} =
749 match s with
750 | EQ -> make_ineq_eq
751 (expr_of_forme f)
752 (expr_of_forme (forme_of_num n))
753 | SUP -> make_ineq_ge
754 (expr_of_forme f)
755 (expr_of_forme (forme_of_num n))
756 | INF -> make_ineq_le
757 (expr_of_forme f)
758 (expr_of_forme (forme_of_num n));;
760 let ineq_of_gen_ineq = function
761 | Eq e -> make_ineq (form_of_expr e) EQ zero
762 | Large e -> make_ineq (form_of_expr e) SUP zero
763 | Strict e -> make_ineq (form_of_expr e) SUP un;;
765 let norm_syst s = (* Sort.list (>=) *) s;;
767 let eq_ineq i i' = match i, i' with
768 | Strict e, Strict e' -> eq_expr e e'
769 | Large e, Large e' -> eq_expr e e'
770 | Eq e, Eq e' -> eq_expr e e'
771 or eq_expr (negate_formified_expression e) e'
772 or eq_expr e (negate_formified_expression e')
773 | _ -> false;;
775 let systeme_of_gen_syst s =
776 systeme_of_ineq_list (ineq_list_of_gen_syst s);;
778 let gen_syst_of_systeme s =
779 List.map
780 (fun {in_forme = f; in_signe = c; in_biais = n} ->
781 begin match c with
782 | EQ -> make_ineq_eq (FORM f) (FORM (forme_of_num n))
783 | SUP -> make_ineq_ge (FORM f) (FORM (forme_of_num n))
784 | INF -> make_ineq_le (FORM f) (FORM (forme_of_num n))
785 end)
786 (systeme_to_ineq_list s);;
788 (*TeX
789 \subsubsection{Variable manipulation}
791 Itérateurs.
793 let rec map_forme_expr f = function
794 | FORM e -> FORM (f e)
795 | MOD m -> MOD {mod_expr = map_forme_expr f m.mod_expr;
796 modulus = map_forme_expr f m.modulus}
797 | DIV d -> DIV {div_expr = map_forme_expr f d.div_expr;
798 divisor = map_forme_expr f d.divisor}
799 | NAE nae -> NAE {nae_operator = nae.nae_operator;
800 nae_args = List.map
801 (fun e -> map_forme_expr f e)
802 nae.nae_args};;
804 let map_expr f e = formify_expr (map_forme_expr f e);;
806 let rec fold_expr f n = function
807 | FORM e -> f n e
808 | MOD m -> fold_expr f (fold_expr f n m.mod_expr) m.modulus
809 | DIV d -> fold_expr f (fold_expr f n d.div_expr) d.divisor
810 | NAE nae -> List.fold_left
811 (fun n' e -> fold_expr f n' e) n nae.nae_args;;
813 let apply_ineq f = function
814 | Eq e -> Eq (f e)
815 | Large e -> Large (f e)
816 | Strict e -> Strict (f e);;
818 let list_var_expr e =
819 fold_expr (fun l f -> fusionne l (liste_var_forme f))
820 [] e;;
822 let expr_of_ineq = function
823 | Eq e -> e
824 | Large e -> e
825 | Strict e -> e;;
827 let list_var_ineq i = list_var_expr (expr_of_ineq i);;
829 let list_var_syst s =
830 List.fold_left (fun l i -> fusionne l (list_var_ineq i))
831 [] s;;
833 (*TeX
834 Substitutions.
836 let subst_expr e sfl = map_expr (fun f -> subst_forme f sfl) e;;
838 let subst_ineq i sfl =
839 norm_ineq (apply_ineq (fun e -> subst_expr e sfl) i);;
841 let subst_syst s sfl =
842 norm_syst (List.map (fun i -> subst_ineq i sfl) s);;
844 (*TeX
845 Séparation en deux sous-systèmes d'un système avec d'une part les
846 inéquations qui font référence à au moins une des variables de la
847 liste passée en argument et les autres d'autre part.
849 let rec split_gen_syst l = function
850 [] -> [],[]
851 | i::s -> let avec,sans = split_gen_syst l s
852 in if (intersect (list_var_ineq i) l) = []
853 then avec, (i::sans)
854 else (i::avec), sans
857 (*TeX
858 Séparation en deux sous-systèmes d'un système avec d'une part les
859 inéquations qui font référence uniquement aux variables de la
860 liste passée en argument et les autres d'autre part.
863 let rec strict_split_gen_syst l = function
864 [] -> [],[]
865 | i::s -> let avec,sans = strict_split_gen_syst l s
866 in if (subtract (list_var_ineq i) l) = []
867 then (i::avec), sans
868 else avec, (i::sans)
871 (*TeX
872 Structure tests and corresponding simplifications. A replacement
873 function returns the simplified system and a boolean indicating if
874 the inequation used for the simplification should be kept in the
875 system or not. This inequation is not included in the system to be
876 simplified.
878 let ineq_is_constant_def = function
879 | Eq (FORM f) -> (List.length (liste_var_forme f)) = 1
880 | _ -> false;;
882 let replace_constant_def iv i s = match i with
883 | Eq (FORM f) ->
884 let v = List.hd (liste_var_forme f) in
885 let c = (minus_num (get_const f)) // (get_coef v f) in
886 (subst_syst s [v, forme_of_num c]), not (List.mem v iv)
887 | _ -> invalid_arg "Gen_syst.replace_constant_def";;
889 let ineq_is_scale = function
890 | Eq (FORM f) ->
891 (List.length (liste_var_forme f) = 2)
892 && (get_const f =/ zero)
893 | _ -> false;;
895 let replace_scale iv tv p i s = match i with
896 | Eq (FORM f) ->
897 let v, v' = match liste_var_forme f with
898 | [v1; v2] ->
899 if List.mem v1 iv then v1, v2
900 else if List.mem v2 iv then v2, v1
901 else if List.mem v1 p && List.mem v2 tv then v2, v1
902 else v1, v2
903 | _ -> invalid_arg "Gen_syst.replace_scale"
904 in let sf = div_forme
905 (((forme_of_string v') *| (get_coef v' f))
906 +| (forme_of_num (get_const f)))
907 (minus_num (get_coef v f))
908 in (subst_syst s [v, sf]), not (List.mem v iv)
909 | _ -> invalid_arg "Gen_syst.replace_scale";;
911 let ineq_is_def vl pl = function
912 | Eq (FORM f) ->
913 let symbs = liste_var_forme f in
914 let vars, os = List.partition (fun s -> List.mem s vl) symbs in
915 let params, others = List.partition (fun s -> List.mem s pl) os
917 List.length vars = 1 && List.length others = 0
918 | _ -> false;;
920 let replace_def keep vl pl i s = match i with
921 | Eq (FORM f) ->
922 let v = List.find
923 (fun v -> List.mem v vl)
924 (liste_var_forme f) in
925 let c = get_coef v f in
926 let sf = (forme_of_string v) -| (f /| c)
927 in (subst_syst s [v, sf]), keep
928 | _ -> invalid_arg "Gen_syst.replace_def";;
930 let ineq_is_tautology = function
931 | Eq (FORM f) -> (forme_is_num f) && (get_const f =/ zero)
932 | Large (FORM f) -> (forme_is_num f) && (get_const f >=/ zero)
933 | Strict (FORM f) -> (forme_is_num f) && (get_const f >/ zero)
934 | _ -> false;;
936 let rec remove_tautologies = function
937 | [] -> []
938 | h::t ->
939 if ineq_is_tautology h
940 then remove_tautologies t
941 else h::(remove_tautologies t);;
943 let ineq_is_antilogy = function
944 | Eq (FORM f) -> (forme_is_num f) && (get_const f <>/ zero)
945 | Large (FORM f) -> (forme_is_num f) && (get_const f </ zero)
946 | Strict (FORM f) -> (forme_is_num f) && (get_const f >=/ zero)
947 | _ -> false;;
949 let handle_antilogies system =
950 let form = Forme.forme_of_num ( Num.minus_num one ) in
951 if List.exists ineq_is_antilogy system then [ Eq (FORM form) ]
952 else system
955 let rec remove_duplicates = function
956 | [] -> []
957 | h::t -> h::(remove_duplicates
958 (generic_subtract eq_ineq t [h]));;
960 (*TeX
961 Removing of the inequalities with only intermediate variables that
962 do not appear in any inequality with true variables or parameters.
964 let remove_iv_only tv iv p s =
965 let vars = fusionne (Sort.list (<=) tv) (Sort.list (<=) p) in
966 let rec separate = function
967 | i::s ->
968 let with_vars, iv_only = separate s in
969 if intersect vars (list_var_ineq i) = [] then
970 with_vars, (i::iv_only)
971 else
972 (i::with_vars), iv_only
973 | [] -> [], [] in
974 let with_vars, iv_only = separate s in
975 let keep_vars = ref (list_var_syst with_vars)
976 and keep_ineq = ref with_vars in
977 let rec trim = function
978 | (i::to_scan , useless) ->
979 let ineq_vars = list_var_ineq i in
980 if (ineq_vars <> []) && (intersect !keep_vars ineq_vars = []) then
981 trim (to_scan , i::useless)
982 else
983 begin
984 keep_ineq := i::!keep_ineq ;
985 keep_vars := list_var_syst !keep_ineq ;
986 trim (to_scan@useless , []) ;
988 | ([] , useless ) -> ([] , useless) in
989 let _ = trim (iv_only , []) in
990 !keep_ineq;;
992 (*TeX
993 Removing intermediate variable definition (any kind, not only
994 linear) for which the defined variable only appears in other such
995 definitions.
997 let is_iv_def iv ineq =
998 let get_unit_vars f =
999 List.filter (fun v ->
1000 abs_num (Forme.get_coef v f) =/ un)
1001 (liste_var_forme f) in
1002 if ineq_is_eq ineq then
1003 match expr_of_ineq ineq with
1004 | NAE {nae_operator="+"; nae_args=el} ->
1005 begin
1006 let fe, nfe = List.partition expr_is_form el in
1007 match fe, nfe with
1008 (* Attention, il ne faut prendre que les variables avec un
1009 coefficient de 1 ou -1, sinon ce n'est pas une definition
1010 mais une contrainte : nous sommes en nombres ENTIERS
1012 | [FORM f], [] -> intersect iv (get_unit_vars f)
1013 | [FORM f], _ ->
1014 List.filter
1015 (fun v ->
1016 not (List.mem v (list_var_expr
1017 (NAE {nae_operator="+";
1018 nae_args=nfe}))))
1019 (intersect iv (get_unit_vars f))
1020 | [], _ -> []
1021 | _, _ -> failwith "Gen_syst.is_iv_def"
1023 | _ -> []
1024 else [];;
1026 let remove_iv_defs iv s =
1027 let syst = ref s
1028 and modif = ref true
1029 in let rec rem_defs before = function
1030 | i::l ->
1031 begin
1032 match is_iv_def iv i with
1033 | [] -> rem_defs (i::before) l
1034 | vl ->
1035 if List.exists
1036 (fun v -> not (List.mem v
1037 (list_var_syst (before@l)))) vl
1038 then begin
1039 modif := true;
1040 rem_defs before l
1041 end else rem_defs (i::before) l
1043 | [] -> before
1045 while !modif do
1046 modif := false;
1047 syst := rem_defs [] !syst
1048 done;
1049 !syst;;
1051 (*TeX
1052 If an equality is a negation, take the opposite.
1054 let neg_trim = function
1055 | Eq (NAE {nae_operator="-"; nae_args=[e]}) -> Eq e
1056 | i -> i;;
1058 (*TeX
1059 Simplification engine.
1061 let stage test replace s =
1062 let modif = ref true
1063 and global_mod = ref false
1064 and used_ineqs = ref []
1065 and syst = ref s
1066 in let register i (s, keep) =
1067 if keep then used_ineqs := i::(!used_ineqs);
1068 modif := true;
1069 global_mod := true;
1070 syst := norm_syst s
1072 let rec scan before after =
1073 if not !modif
1074 then match after with
1075 | [] -> ()
1076 | h::t ->
1077 if test h
1078 then register h (replace h (before@t))
1079 else scan (h::before) t
1081 while !modif do
1082 modif := false;
1083 scan [] !syst
1084 done;
1085 !global_mod, !used_ineqs, !syst;;
1087 let simplify_interne tv iv p s =
1088 let modif1 = ref true
1089 and modif2 = ref true
1090 and modif3 = ref true
1091 and used_ineqs = ref []
1092 and syst = ref s
1093 in let trim () =
1094 syst := List.map neg_trim !syst;
1095 syst := remove_iv_defs iv
1096 (remove_iv_only tv iv p (remove_duplicates !syst))
1097 in let register modifn (modified, used, new_syst) =
1098 modifn := modified;
1099 used_ineqs := used@(!used_ineqs);
1100 syst := new_syst
1102 while !modif3 or !modif2 or !modif1 do
1103 modif3 := false;
1104 while !modif2 or !modif1 do
1105 modif2 := false;
1106 while !modif1 do
1107 register modif1
1108 (stage ineq_is_constant_def (replace_constant_def iv) !syst);
1109 register modif1
1110 (stage ineq_is_scale (replace_scale iv tv p) !syst)
1111 done;
1112 register modif2
1113 (stage (ineq_is_def iv (tv@p)) (replace_def false iv (tv@p)) !syst)
1114 done;
1115 register modif3
1116 (stage (ineq_is_def tv p) (replace_def true tv p) !syst);
1117 trim ();
1118 done;
1119 let simple = remove_tautologies (remove_duplicates !syst) in
1120 handle_antilogies (!used_ineqs@simple);;
1122 let simplify tv p s =
1123 simplify_interne tv (subtract (list_var_syst s) (tv@p)) p s;;
1124 let simplify_vars tv s =
1125 simplify_interne tv (subtract (list_var_syst s) tv) [] s;;
1127 (*TeX
1128 \subsubsection{Printers}
1130 open Format;;
1131 open Formatters;;
1133 let rec print_expr = function
1134 | FORM f -> print_forme f
1135 | MOD m -> print_modulo m
1136 | DIV d -> print_division d
1137 | NAE nae -> print_non_aff_expr nae
1138 and print_expr_rec = function
1139 | FORM f -> print_forme_rec f
1140 | MOD m -> print_modulo_rec m
1141 | DIV d -> print_division_rec d
1142 | NAE nae -> print_non_aff_expr_rec nae
1143 and print_forme_rec f =
1144 if List.length (forme_to_terme_list f) = 1 then
1145 print_forme f
1146 else begin
1147 pp_open_hovbox (!current_formatter) 2;
1148 pp_print_string (!current_formatter) "(";
1149 print_forme f;
1150 pp_print_string (!current_formatter) ")";
1151 pp_close_box (!current_formatter) ()
1153 and print_non_aff_infix_expr nae =
1154 pp_open_hvbox (!current_formatter) 2;
1155 begin match nae.nae_args with
1156 | [] -> invalid_arg "Gen_syst.print_non_aff_infix_expr"
1157 | [e] ->
1158 pp_print_string (!current_formatter) nae.nae_operator;
1159 pp_print_cut (!current_formatter) ();
1160 print_expr_rec e;
1161 | e::t ->
1162 print_expr_rec e;
1163 List.iter
1164 (fun e ->
1165 pp_print_cut (!current_formatter) ();
1166 pp_print_string (!current_formatter) nae.nae_operator;
1167 pp_print_cut (!current_formatter) ();
1168 print_expr_rec e)
1170 end;
1171 pp_close_box (!current_formatter) ()
1172 and print_non_aff_prefix_expr nae =
1173 pp_open_hvbox (!current_formatter) 2;
1174 pp_print_string (!current_formatter) nae.nae_operator;
1175 pp_print_space (!current_formatter) ();
1176 begin match nae.nae_args with
1177 | [] -> invalid_arg "Gen_syst.print_non_aff_prefix_expr"
1178 | e::t ->
1179 print_expr e;
1180 List.iter
1181 (fun e ->
1182 pp_print_space (!current_formatter) ();
1183 print_expr_rec e)
1185 end;
1186 pp_close_box (!current_formatter) ()
1187 and print_non_aff_expr nae =
1188 if (String.uppercase nae.nae_operator) <>
1189 (String.lowercase nae.nae_operator)
1190 then print_non_aff_prefix_expr nae
1191 else print_non_aff_infix_expr nae
1192 and print_non_aff_expr_rec nae =
1193 if nae.nae_operator = "**" then print_non_aff_expr nae
1194 else begin
1195 pp_open_hvbox (!current_formatter) 1;
1196 pp_print_string (!current_formatter) "(";
1197 print_non_aff_expr nae;
1198 pp_print_string (!current_formatter) ")";
1199 pp_close_box (!current_formatter) ()
1201 and print_modulo m =
1202 pp_open_hovbox (!current_formatter) 2;
1203 print_expr_rec m.mod_expr;
1204 pp_print_space (!current_formatter) ();
1205 pp_print_string (!current_formatter) "mod";
1206 pp_print_space (!current_formatter) ();
1207 print_expr_rec m.modulus;
1208 pp_close_box (!current_formatter) ()
1209 and print_modulo_rec m =
1210 pp_open_hovbox (!current_formatter) 1;
1211 pp_print_string (!current_formatter) "(";
1212 print_modulo m;
1213 pp_print_string (!current_formatter) ")";
1214 pp_close_box (!current_formatter) ()
1215 and print_division d =
1216 pp_open_hovbox (!current_formatter) 2;
1217 print_expr_rec d.div_expr;
1218 pp_print_space (!current_formatter) ();
1219 pp_print_string (!current_formatter) "div";
1220 pp_print_space (!current_formatter) ();
1221 print_expr_rec d.divisor;
1222 pp_close_box (!current_formatter) ()
1223 and print_division_rec d =
1224 pp_open_hovbox (!current_formatter) 1;
1225 pp_print_string (!current_formatter) "(";
1226 print_division d;
1227 pp_print_string (!current_formatter) ")";
1228 pp_close_box (!current_formatter) ();;
1230 let print_form_ineq f comp =
1231 let neg_comp = function
1232 | "=" -> "="
1233 | ">=" -> "<="
1234 | ">" -> "<"
1235 | _ -> assert false in
1236 let const = get_const f in
1237 if eq_num const zero then
1238 let f', comp' =
1239 if (signature f) < 0 then
1240 minus_forme f, neg_comp comp
1241 else f, comp
1242 in begin
1243 match
1244 List.partition
1245 (fun t -> gt_num (terme_get_coef t) zero)
1246 (forme_to_terme_list f')
1247 with
1248 | lp, [] ->
1249 print_forme f';
1250 pp_print_space (!current_formatter) ();
1251 pp_print_string (!current_formatter) comp';
1252 pp_print_space (!current_formatter) ();
1253 print_num zero
1254 | [], ln ->
1255 print_forme (minus_forme f');
1256 pp_print_space (!current_formatter) ();
1257 pp_print_string (!current_formatter) (neg_comp comp');
1258 pp_print_space (!current_formatter) ();
1259 print_num zero
1260 | lp, ln ->
1261 print_forme (forme_of_terme_list lp);
1262 pp_print_space (!current_formatter) ();
1263 pp_print_string (!current_formatter) comp';
1264 pp_print_space (!current_formatter) ();
1265 print_forme (minus_forme (forme_of_terme_list ln))
1266 end else
1267 let f' = sub_forme f (forme_of_num const) in
1268 if signature f' < 0 then begin
1269 print_forme (minus_forme f');
1270 pp_print_space (!current_formatter) ();
1271 pp_print_string (!current_formatter) (neg_comp comp);
1272 pp_print_space (!current_formatter) ();
1273 print_num const
1274 end else begin
1275 print_forme f';
1276 pp_print_space (!current_formatter) ();
1277 pp_print_string (!current_formatter) comp;
1278 pp_print_space (!current_formatter) ();
1279 print_num (minus_num const)
1280 end;;
1282 let print_gen_ineq i =
1283 pp_open_hovbox (!current_formatter) 2;
1284 begin match i with
1285 | Eq (FORM f) -> print_form_ineq f "="
1286 | Large (FORM f) -> print_form_ineq f ">="
1287 | Strict (FORM f) -> print_form_ineq f ">"
1288 | Eq e ->
1289 print_expr e;
1290 pp_print_space (!current_formatter) ();
1291 pp_print_string (!current_formatter) "= 0"
1292 | Large e ->
1293 print_expr e;
1294 pp_print_space (!current_formatter) ();
1295 pp_print_string (!current_formatter) ">= 0"
1296 | Strict e ->
1297 print_expr e;
1298 pp_print_space (!current_formatter) ();
1299 pp_print_string (!current_formatter) "> 0"
1300 end;
1301 pp_close_box (!current_formatter) ();;
1303 let print_gen_syst s =
1304 pp_open_hovbox (!current_formatter) 1;
1305 pp_print_string (!current_formatter) "{";
1306 let ss = List.sort compare s in
1307 begin match ss with
1308 | [] -> ()
1309 | h::[] -> print_gen_ineq h
1310 | h::t -> print_gen_ineq h;
1311 List.iter (fun i ->
1312 pp_print_string (!current_formatter) ",";
1313 pp_print_space (!current_formatter) ();
1314 print_gen_ineq i) t
1315 end;
1316 pp_print_cut (!current_formatter) ();
1317 pp_print_string (!current_formatter) "}";
1318 pp_close_box (!current_formatter) ();;