2 \subsection{Implementation}
11 \subsubsection{Type definitions}
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
};;
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
;;
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'
)
48 let lt_lists lt_fun l l'
=
49 let rec iter = function
51 if lt_fun e e'
then true
52 else if lt_fun e' e
then 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'
)
61 let rec lt_expr e e'
= match e
, e'
with
62 | FORM f
, FORM f'
-> lt_forme f f'
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'
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'
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
;;
84 \subsubsection{Expression simplification}
86 let expr_is_form = function
90 let rec form_of_expr = function
92 | NAE
{nae_operator
= _
; nae_args
= el
} as e
->
93 ignore
(List.map
form_of_expr el
);
95 | e
-> raise
(Non_linear e
);;
97 let modularify_forme f m
=
98 let fm = (forme_of_terme_list
100 (fun t
-> let c = terme_get_coef t
in
101 if (mod_num
c m
=/ zero
) then
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
=
111 then FORM
(forme_of_num
(quo_num
(get_const f
) d
))
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
)}
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
)}]}
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
->
132 | "+" -> NAE
{nae_operator
= "+";
133 nae_args
= sort_args (List.map
134 negate_formified_expression
137 begin match args
with
138 | [] -> invalid_arg
"Gen_syst.negate_formified_expression"
140 | h
::t
-> NAE
{nae_operator
= "+";
142 (negate_formified_expression h
)::t
}
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
= "*";
151 ((negate_formified_expression h
)::t
)}
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
= "/";
159 (negate_formified_expression h
)::t
}
161 | _
-> NAE
{nae_operator
= "-";
165 let rec flatten_mult_args = function
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
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
185 let mult_formified_expressions el
=
186 match List.partition
expr_is_form
187 (powerify_mults (sort_args (flatten_mult_args el
))) with
189 begin match List.partition forme_is_num
190 (List.map
form_of_expr fe
) with
193 (List.fold_right mult_num
194 (List.map get_const l
) un
))
196 FORM
(List.fold_left mult_forme f
197 (List.map get_const l
))
199 NAE
{nae_operator
= "*";
202 ((FORM
(List.fold_left mult_forme h
203 (List.map get_const l
)))
204 ::(List.map
(fun f
-> FORM f
) t
))}
207 | [], nfe
-> NAE
{nae_operator
= "*";
208 nae_args
= sort_args nfe
}
210 begin match List.partition forme_is_num
211 (List.map
form_of_expr fe
) with
213 let n = (List.fold_right mult_num
214 (List.map get_const l
) un
) in
215 NAE
{nae_operator
= "*";
217 if n =/ un
then sort_args nfe
218 else if n =/ moins_un
then
221 sort_args ((negate_formified_expression h
)::t
)
224 "Gen_syst.mult_formified_expressions"
226 else sort_args ((FORM
(forme_of_num
n))::nfe
)}
228 NAE
{nae_operator
= "*";
230 sort_args ((FORM
(List.fold_left mult_forme f
231 (List.map get_const l
)))
234 NAE
{nae_operator
= "*";
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
)}
241 let div_formified_expressions = function
243 begin match List.partition
244 (fun e
-> expr_is_form e
245 && forme_is_num
(form_of_expr e
)) (e'
::r
) with
248 then FORM
(List.fold_left div_forme
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
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
)}
264 then NAE
{nae_operator
= "/";
266 (FORM
(List.fold_left div_forme
270 (form_of_expr e
)) ne
)))
272 else let n = List.fold_left mult_num un
273 (List.map
(fun e
-> get_const
274 (form_of_expr e
)) ne
) in
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
)
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'
))
290 if (get_const
(form_of_expr e'
)) = zero
291 then FORM
(forme_of_num un
)
293 if (get_const
(form_of_expr e'
)) = un
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
)
311 and new_var
() = Util.Name.gen
"s" in
312 let rec make_term_list tl defs el
=
315 List.iter (fun (v
, e'
) ->
316 if eq_expr e e'
then name := v
) defs
;
319 List.iter (fun (v
, e'
) ->
320 if eq_expr (negate_formified_expression e
) e'
321 then name := v
) defs
;
325 make_term_list ((make_terme
!name c)::tl
)
328 make_term_list ((make_terme
!name (minus_num
c))::tl
) defs t
330 make_term_list ((make_terme
!name c)::tl
) defs t
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
=
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
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
351 let add_formified_expressions el
=
352 match List.partition
expr_is_form (flatten_sums el
) with
354 FORM
(List.fold_right
356 (List.map
form_of_expr fe
)
359 begin match sum_exprs nfe
with
360 | [] -> FORM
(forme_of_num zero
)
362 | s
-> NAE
{nae_operator
= "+";
363 nae_args
= sort_args s
}
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
372 if forme_is_num
f && (get_const
f) =/ zero
374 else NAE
{nae_operator
= "+";
375 nae_args
= sort_args [FORM
f; e
]}
377 NAE
{nae_operator
= "+";
379 if forme_is_num
f && (get_const
f) =/ zero
381 else sort_args ((FORM
f)::s
)}
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
= "*";
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
)
397 let choose = function
400 | (e
,_
)::_
-> Some e
in
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
406 | Some factor
-> begin
408 | NAE
{nae_operator
= "*"; nae_args
= el
}
409 when generic_mem
eq_expr factor el
->
412 generic_remove_first
eq_expr factor el
414 | [] -> Some
(FORM
(forme_of_num un
)), None
415 | [e
] -> Some e
, None
416 | l
-> Some
(mult_formified_expressions
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
427 | (Some h
, None
)::t
->
428 let t1,t2
= split_and_remove_options t
in
430 | (Some h1
, Some h2
)::t
->
431 let t1,t2
= split_and_remove_options t
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
440 ((mult_formified_expressions
441 (sort_args [factor
;e
]))::l
))
442 | l
, [] -> mult_formified_expressions
444 add_formified_expressions
446 | l
, l'
-> add_formified_expressions
448 ((mult_formified_expressions
451 add_formified_expressions
452 (sort_args l
)]))::l'
))
458 formify\_expr is the main simplification function. It computes all
459 the available linear forms.
461 let rec formify_step formify_args
= function
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
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'
))
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
485 | "+" -> factorize (add_formified_expressions (sort_args fargs))
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
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;;
506 \subsubsection{Constructors}
508 let expr_of_forme f = FORM
f;;
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
= "+";
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
= "*";
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
))});;
547 formify_top_expr (DIV
{div_expr = e1
; divisor
= 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 ' '
;
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
];;
566 \texttt{gen\_syst\_to\_ineq\_list}.
568 let linearize_expr defs
e =
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
->
577 let mf, mdefs
= make_forme defs me
in
578 let mm = MOD
{mod_expr = mf; modulus
= FORM
f} in
581 (fun (v
, e) -> if eq_expr mm e then name := v
) defs
;
582 if !name = "" then begin
585 if eq_expr (negate_formified_expression mm) e
586 then name := v
) defs
;
587 if !name = "" then begin
589 FORM
(forme_of_string
!name), ((!name, mm)::mdefs
)
591 FORM
(minus_forme
(forme_of_string
!name)), mdefs
593 FORM
(forme_of_string
!name), mdefs
595 else raise
(Non_linear exp
)
596 | DIV
{div_expr = de
; divisor
= FORM
f} as exp
->
600 let df, mdefs
= make_forme defs de
in
601 let dd = DIV
{div_expr = df; divisor
= FORM
f} in
604 (fun (v
, e) -> if eq_expr dd e then name := v
) defs
;
605 if !name = "" then begin
608 if eq_expr (negate_formified_expression dd) e
609 then name := v
) defs
;
610 if !name = "" then begin
612 FORM
(forme_of_string
!name), ((!name, dd)::mdefs
)
614 FORM
(minus_forme
(forme_of_string
!name)), mdefs
616 FORM
(forme_of_string
!name), mdefs
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
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
)
632 let linearize_ineq defs = function
634 let e'
, defs'
= linearize_expr defs e in
637 let e'
, defs'
= linearize_expr defs e in
641 | NAE
{nae_operator
= "+";
643 NAE
{nae_operator
= "-";
644 nae_args
= [MOD
{mod_expr = me
;
645 modulus
= FORM
f}]}]}
646 when forme_is_var v
->
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
657 let ineq_list_of_gen_syst s
=
658 let s'
, defs = List.fold_left
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
)
670 (fun (v
, e) -> match e with
673 (FORM
(forme_of_string
(Util.Name.gen
"div"))),
674 (FORM
(forme_of_string v
))
676 (NAE
{nae_operator
= "+";
678 [NAE
{nae_operator
= "*";
679 nae_args
= [m
.modulus
; q]};
681 negate_formified_expression
685 (NAE
{nae_operator
= "-";
686 nae_args
= [m
.modulus
; r
]}))]
689 (FORM
(forme_of_string v
)),
690 (FORM
(forme_of_string
(Util.Name.gen
"mod")))
692 (NAE
{nae_operator
= "+";
694 [NAE
{nae_operator
= "*";
695 nae_args
= [d
.divisor
; q]};
697 negate_formified_expression
701 (NAE
{nae_operator
= "-";
702 nae_args
= [d
.divisor
; r
]}))]
703 | e -> raise
(Non_linear
e))
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)))
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
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
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
740 let ineq_is_ge = function
744 let ineq_is_gt = function
748 let gen_ineq_of_ineq {in_forme
= f; in_signe
= s; in_biais
= n} =
752 (expr_of_forme (forme_of_num
n))
753 | SUP
-> make_ineq_ge
755 (expr_of_forme (forme_of_num
n))
756 | INF
-> make_ineq_le
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'
)
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 =
780 (fun {in_forme
= f; in_signe
= c; in_biais
= n} ->
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))
786 (systeme_to_ineq_list
s);;
789 \subsubsection{Variable manipulation}
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
;
801 (fun e -> map_forme_expr f e)
804 let map_expr f e = formify_expr (map_forme_expr f e);;
806 let rec fold_expr f n = function
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
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))
822 let expr_of_ineq = function
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))
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);;
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
851 | i::s -> let avec,sans
= split_gen_syst l
s
852 in if (intersect
(list_var_ineq i) l
) = []
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
865 | i::s -> let avec,sans
= strict_split_gen_syst l
s
866 in if (subtract
(list_var_ineq i) l
) = []
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
878 let ineq_is_constant_def = function
879 | Eq
(FORM
f) -> (List.length
(liste_var_forme
f)) = 1
882 let replace_constant_def iv
i s = match i with
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
891 (List.length
(liste_var_forme
f) = 2)
892 && (get_const
f =/ zero
)
895 let replace_scale iv tv p
i s = match i with
897 let v, v'
= match liste_var_forme
f with
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
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
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
920 let replace_def keep vl pl
i s = match i with
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
)
936 let rec remove_tautologies = function
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
)
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) ]
955 let rec remove_duplicates = function
957 | h
::t
-> h
::(remove_duplicates
958 (generic_subtract
eq_ineq t
[h
]));;
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
968 let with_vars, iv_only
= separate s in
969 if intersect
vars (list_var_ineq i) = [] then
970 with_vars, (i::iv_only
)
972 (i::with_vars), iv_only
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
)
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
993 Removing intermediate variable definition (any kind, not only
994 linear) for which the defined variable only appears in other such
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
} ->
1006 let fe, nfe
= List.partition
expr_is_form el
in
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)
1016 not
(List.mem
v (list_var_expr
1017 (NAE
{nae_operator
="+";
1019 (intersect iv
(get_unit_vars f))
1021 | _, _ -> failwith
"Gen_syst.is_iv_def"
1026 let remove_iv_defs iv
s =
1028 and modif
= ref true
1029 in let rec rem_defs before
= function
1032 match is_iv_def iv
i with
1033 | [] -> rem_defs (i::before
) l
1036 (fun v -> not
(List.mem
v
1037 (list_var_syst (before
@l
)))) vl
1041 end else rem_defs (i::before
) l
1047 syst := rem_defs [] !syst
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
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 []
1066 in let register i (s, keep
) =
1067 if keep
then used_ineqs
:= i::(!used_ineqs
);
1072 let rec scan before after
=
1074 then match after
with
1078 then register h
(replace h
(before
@t
))
1079 else scan (h
::before
) t
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 []
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
) =
1099 used_ineqs
:= used
@(!used_ineqs
);
1102 while !modif3
or !modif2
or !modif1 do
1104 while !modif2
or !modif1 do
1108 (stage ineq_is_constant_def (replace_constant_def iv
) !syst);
1110 (stage ineq_is_scale (replace_scale iv tv p
) !syst)
1113 (stage (ineq_is_def iv
(tv
@p
)) (replace_def false iv
(tv
@p
)) !syst)
1116 (stage (ineq_is_def tv p
) (replace_def true tv p
) !syst);
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;;
1128 \subsubsection{Printers}
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
1147 pp_open_hovbox
(!current_formatter
) 2;
1148 pp_print_string
(!current_formatter
) "(";
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"
1158 pp_print_string
(!current_formatter
) nae
.nae_operator
;
1159 pp_print_cut
(!current_formatter
) ();
1165 pp_print_cut
(!current_formatter
) ();
1166 pp_print_string
(!current_formatter
) nae
.nae_operator
;
1167 pp_print_cut
(!current_formatter
) ();
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"
1182 pp_print_space
(!current_formatter
) ();
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
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
) "(";
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
) "(";
1227 pp_print_string
(!current_formatter
) ")";
1228 pp_close_box
(!current_formatter
) ();;
1230 let print_form_ineq f comp
=
1231 let neg_comp = function
1235 | _ -> assert false in
1236 let const = get_const
f in
1237 if eq_num
const zero
then
1239 if (signature
f) < 0 then
1240 minus_forme
f, neg_comp comp
1245 (fun t
-> gt_num
(terme_get_coef t
) zero
)
1246 (forme_to_terme_list
f'
)
1250 pp_print_space
(!current_formatter
) ();
1251 pp_print_string
(!current_formatter
) comp'
;
1252 pp_print_space
(!current_formatter
) ();
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
) ();
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
))
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
) ();
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)
1282 let print_gen_ineq i =
1283 pp_open_hovbox
(!current_formatter
) 2;
1285 | Eq
(FORM
f) -> print_form_ineq f "="
1286 | Large
(FORM
f) -> print_form_ineq f ">="
1287 | Strict
(FORM
f) -> print_form_ineq f ">"
1290 pp_print_space
(!current_formatter
) ();
1291 pp_print_string
(!current_formatter
) "= 0"
1294 pp_print_space
(!current_formatter
) ();
1295 pp_print_string
(!current_formatter
) ">= 0"
1298 pp_print_space
(!current_formatter
) ();
1299 pp_print_string
(!current_formatter
) "> 0"
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
1309 | h
::[] -> print_gen_ineq h
1310 | h
::t
-> print_gen_ineq h
;
1312 pp_print_string
(!current_formatter
) ",";
1313 pp_print_space
(!current_formatter
) ();
1316 pp_print_cut
(!current_formatter
) ();
1317 pp_print_string
(!current_formatter
) "}";
1318 pp_close_box
(!current_formatter
) ();;