let rec zsolve (a, b) =
fresh := [];
if Term.eq a b then [] else
if Term.is_var a && Term.is_var b then
[Term.orient(a, b)]
else
let a_sub_b = mk_sub a b in
let q = constant_of a_sub_b
and ml = nonconstant_monomials_of a_sub_b in
match ml with
| [] ->
if Q.is_zero q then [] else raise(Exc.Inconsistent)
| [m] ->
let p = coefficient_of_mono m
and x = variable_of_mono m in
let q_div_p = Q.div q p in
if Q.is_integer q_div_p then
[(x, mk_num (Q.minus q_div_p))]
else
raise Exc.Inconsistent
| _ ->
let (cl, xl) = vectorize ml in
(match Euclid.solve cl (Q.minus q) with
| None ->
raise Exc.Inconsistent
| Some(d, pl) ->
let gl = general cl (d, pl) in
combine xl gl)
and vectorize ml =
let rec loop (ql, xl) = function
| [] ->
(ql, xl)
| m :: ml ->
let q = coefficient_of_mono m
and x = variable_of_mono m in
loop (q :: ql, x :: xl) ml
in
loop ([], []) ml
and combine xl bl =
List.combine xl bl
and general al (d, pl) =
let rec loop al zl =
match al, zl with
| [_], [_] -> zl
| a0 :: ((a1 :: al'') as al'), z0 :: z1 :: zl'' ->
let k = mk_fresh () in
let e0 = mk_add z0 (mk_multq (Q.div a1 d) k) in
let e1 = mk_add z1 (mk_multq (Q.div (Q.minus a0) d) k) in
let sl' = loop al' (e1 :: zl'') in
e0 :: sl'
| _ -> assert false
in
loop al (List.map mk_num pl)