1 /*++
2   Copyright (c) 2017 Microsoft Corporation
3 
4   Author:
5     Nikolaj Bjorner (nbjorner)
6     Lev Nachmanson (levnach)
7   --*/
8 
9 #include "math/lp/nla_order_lemmas.h"
10 #include "math/lp/nla_core.h"
11 #include "math/lp/nla_common.h"
12 #include "math/lp/factorization_factory_imp.h"
13 
14 namespace nla {
15 
16 typedef lp::lar_term term;
17 
18 // The order lemma is
19 // a > b && c > 0 => ac > bc
order_lemma()20 void order::order_lemma() {
21     TRACE("nla_solver", );
22     if (!c().m_nla_settings.run_order()) {
23         TRACE("nla_solver", tout << "not generating order lemmas\n";);
24         return;
25     }
26 
27     const auto& to_ref = c().m_to_refine;
28     unsigned r = random();
29     unsigned sz = to_ref.size();
30     for (unsigned i = 0; i < sz && !done(); ++i) {
31         lpvar j = to_ref[(i + r) % sz];
32         order_lemma_on_monic(c().emons()[j]);
33     }
34 }
35 
36 // The order lemma is
37 // a > b && c > 0 => ac > bc
38 // Consider here some binary factorizations of m=ac and
39 // try create order lemmas with either factor playing the role of c.
order_lemma_on_monic(const monic & m)40 void order::order_lemma_on_monic(const monic& m) {
41     TRACE("nla_solver_details",
42           tout << "m = " << pp_mon(c(), m););
43     for (auto ac : factorization_factory_imp(m, _())) {
44         if (ac.size() != 2)
45             continue;
46         if (ac.is_mon())
47             order_lemma_on_binomial(ac.mon());
48         else
49             order_lemma_on_factorization(m, ac);
50         if (done())
51             break;
52     }
53 }
54 // Here ac is a monic of size 2
55 // Trying to get an order lemma is
56 // a > b && c > 0 => ac > bc,
57 // with either variable of ac playing the role of c
order_lemma_on_binomial(const monic & ac)58 void order::order_lemma_on_binomial(const monic& ac) {
59     TRACE("nla_solver", tout << pp_mon_with_vars(c(), ac););
60     SASSERT(!check_monic(ac) && ac.size() == 2);
61     const rational mult_val = mul_val(ac);
62     const rational acv = var_val(ac);
63     bool gt = acv > mult_val;
64     bool k = false;
65     do {
66         order_lemma_on_binomial_sign(ac, ac.vars()[k], ac.vars()[!k], gt? 1: -1);
67         order_lemma_on_factor_binomial_explore(ac, k);
68         k = !k;
69     }
70     while (k);
71 }
72 
73 
74 /**
75 \brief
76  sign = the sign of val(xy) - val(x) * val(y) != 0
77  y <= 0 or x < a or xy >= ay
78  y <= 0 or x > a or xy <= ay
79  y >= 0 or x < a or xy <= ay
80  y >= 0 or x > a or xy >= ay
81 
82 */
order_lemma_on_binomial_sign(const monic & xy,lpvar x,lpvar y,int sign)83 void order::order_lemma_on_binomial_sign(const monic& xy, lpvar x, lpvar y, int sign) {
84     if (!c().var_is_int(x) && val(x).is_big())
85         return;
86     SASSERT(!_().mon_has_zero(xy.vars()));
87     int sy = rat_sign(val(y));
88     new_lemma lemma(c(), __FUNCTION__);
89     lemma |= ineq(y,                                   sy == 1      ? llc::LE : llc::GE, 0); // negate sy
90     lemma |= ineq(x,                                   sy*sign == 1 ? llc::GT : llc::LT , val(x));
91     lemma |= ineq(term(xy.var(), - val(x), y), sign == 1    ? llc::LE : llc::GE, 0);
92 }
93 
94 // We look for monics e = m.rvars()[k]*d and see if we can create an order lemma for m and  e
order_lemma_on_factor_binomial_explore(const monic & ac,bool k)95 void order::order_lemma_on_factor_binomial_explore(const monic& ac, bool k) {
96     TRACE("nla_solver", tout << "ac = " <<  pp_mon_with_vars(c(), ac););
97     SASSERT(ac.size() == 2);
98     lpvar c = ac.vars()[k];
99 
100     for (monic const& bd : _().emons().get_products_of(c)) {
101         if (bd.var() == ac.var())
102             continue;
103         TRACE("nla_solver", tout << "bd = " << pp_mon_with_vars(_(), bd););
104         order_lemma_on_factor_binomial_rm(ac, k, bd);
105         if (done())
106             break;
107     }
108 }
109 
110 // ac is a binomial
111 // create order lemma on monics bd where d is equivalent to ac[k]
order_lemma_on_factor_binomial_rm(const monic & ac,bool k,const monic & bd)112 void order::order_lemma_on_factor_binomial_rm(const monic& ac, bool k, const monic& bd) {
113     TRACE("nla_solver",
114           tout << "ac=" << pp_mon_with_vars(_(), ac) << "\n";
115           tout << "k=" << k << "\n";
116           tout << "bd=" << pp_mon_with_vars(_(), bd) << "\n";
117           );
118     factor d(_().m_evars.find(ac.vars()[k]).var(), factor_type::VAR);
119     factor b(false);
120     if (c().divide(bd, d, b)) {
121         order_lemma_on_binomial_ac_bd(ac, k, bd, b, d.var());
122     }
123 }
124 
125 //  ac >= bd && |c| = |d| => ac/|c| >= bd/|d|
order_lemma_on_binomial_ac_bd(const monic & ac,bool k,const monic & bd,const factor & b,lpvar d)126 void order::order_lemma_on_binomial_ac_bd(const monic& ac, bool k, const monic& bd, const factor& b, lpvar d) {
127     lpvar a = ac.vars()[!k];
128     lpvar c = ac.vars()[k];
129     TRACE("nla_solver",
130           tout << "ac = " << pp_mon(_(), ac) << "a = " << pp_var(_(), a) << "c = " << pp_var(_(), c) << "\nbd = " << pp_mon(_(), bd) << "b = " << pp_fac(_(), b) << "d = " << pp_var(_(), d) << "\n";
131           );
132     SASSERT(_().m_evars.find(c).var() == d);
133     rational acv = var_val(ac);
134     rational av = val(a);
135     rational c_sign = rrat_sign(val(c));
136     rational d_sign = rrat_sign(val(d));
137     rational bdv = var_val(bd);
138     rational bv = val(b);
139     // Notice that ac/|c| = a*c_sign , and bd/|d| = b*d_sign
140     auto av_c_s = av*c_sign; auto bv_d_s = bv*d_sign;
141     TRACE("nla_solver",
142           tout << "acv = " << acv << ", av = " << av << ", c_sign = " << c_sign << ", d_sign = " << d_sign << ", bdv = " << bdv <<
143           "\nbv = " << bv << ", av_c_s = " << av_c_s << ", bv_d_s = " << bv_d_s << "\n";);
144 
145     if (acv >= bdv && av_c_s < bv_d_s)
146         generate_mon_ol(ac, a, c_sign, c, bd, b, d_sign, d, llc::LT);
147     else if (acv <= bdv && av_c_s > bv_d_s)
148         generate_mon_ol(ac, a, c_sign, c, bd, b, d_sign, d, llc::GT);
149 
150 }
151 
152 // |c_sign| = 1, and c*c_sign > 0
153 // |d_sign| = 1, and d*d_sign > 0
154 // c and d are equivalent |c| == |d|
155 // ac > bd => ac/|c| > bd/|d| => a*c_sign > b*d_sign
156 // but the last inequality does not hold
generate_mon_ol(const monic & ac,lpvar a,const rational & c_sign,lpvar c,const monic & bd,const factor & b,const rational & d_sign,lpvar d,llc ab_cmp)157 void order::generate_mon_ol(const monic& ac,
158                            lpvar a,
159                            const rational& c_sign,
160                            lpvar c,
161                            const monic& bd,
162                            const factor& b,
163                            const rational& d_sign,
164                            lpvar d,
165                            llc ab_cmp) {
166     SASSERT(ab_cmp == llc::LT || ab_cmp == llc::GT);
167     SASSERT(ab_cmp != llc::LT || (var_val(ac) >= var_val(bd) && val(a)*c_sign < val(b)*d_sign));
168     SASSERT(ab_cmp != llc::GT || (var_val(ac) <= var_val(bd) && val(a)*c_sign > val(b)*d_sign));
169 
170     new_lemma lemma(_(), __FUNCTION__);
171     lemma |= ineq(term(c_sign, c), llc::LE, 0);
172     lemma &= c; // this explains c == +- d
173     lemma |= ineq(term(c_sign, a, -d_sign * b.rat_sign(), b.var()), negate(ab_cmp), 0);
174     lemma |= ineq(term(ac.var(), rational(-1), var(bd)), ab_cmp, 0);
175     lemma &= bd;
176     lemma &= b;
177     lemma &= d;
178 }
179 
180 
181 // a > b  && c > 0 => ac > bc
182 // a >< b && c > 0 => ac >< bc
183 // a >< b && c < 0 => ac <> bc
184 // ac[k] plays the role of c
185 
order_lemma_on_ac_and_bc(const monic & rm_ac,const factorization & ac_f,bool k,const monic & rm_bd)186 bool order::order_lemma_on_ac_and_bc(const monic& rm_ac,
187                                      const factorization& ac_f,
188                                      bool k,
189                                      const monic& rm_bd) {
190     TRACE("nla_solver",
191           tout << "rm_ac = " << pp_mon_with_vars(_(), rm_ac) << "\n";
192           tout << "rm_bd = " << pp_mon_with_vars(_(), rm_bd) << "\n";
193           tout << "ac_f[k] = ";
194           c().print_factor_with_vars(ac_f[k], tout););
195     factor b(false);
196     return
197         c().divide(rm_bd, ac_f[k], b) &&
198         order_lemma_on_ac_and_bc_and_factors(rm_ac, ac_f[!k], ac_f[k], rm_bd, b);
199 }
200 
201 
202 // Here m = ab, that is ab is binary factorization of m.
203 // We try to find a monic n = cd, such that |b| = |d|
204 // and get lemma m R n & |b| = |d| => ab/|b| R cd /|d|, where R is a relation
order_lemma_on_factorization(const monic & m,const factorization & ab)205 void order::order_lemma_on_factorization(const monic& m, const factorization& ab) {
206     bool sign = false;
207     for (factor f: ab)
208         sign ^= f.sign();
209     const rational rsign = sign_to_rat(sign);
210     const rational fv = val(var(ab[0])) * val(var(ab[1]));
211     const rational mv = rsign * var_val(m);
212     TRACE("nla_solver",
213           tout << "ab.size()=" << ab.size() << "\n";
214           tout << "we should have mv =" << mv << " = " << fv << " = fv\n";
215           tout << "m = "; _().print_monic_with_vars(m, tout); tout << "\nab ="; _().print_factorization(ab, tout););
216 
217     if (mv != fv && !c().has_real(m)) {
218         bool gt = mv > fv;
219         for (unsigned j = 0, k = 1; j < 2; j++, k--) {
220             new_lemma lemma(_(), __FUNCTION__);
221             order_lemma_on_ab(lemma, m, rsign, var(ab[k]), var(ab[j]), gt);
222             lemma &= ab;
223             lemma &= m;
224         }
225     }
226     for (unsigned j = 0, k = 1; j < 2; j++, k--) {
227         order_lemma_on_ac_explore(m, ab, j == 1);
228     }
229 }
230 
order_lemma_on_ac_explore(const monic & rm,const factorization & ac,bool k)231 void order::order_lemma_on_ac_explore(const monic& rm, const factorization& ac, bool k) {
232     const factor c = ac[k];
233     TRACE("nla_solver", tout << "c = "; _().print_factor_with_vars(c, tout); );
234     if (c.is_var()) {
235         TRACE("nla_solver", tout << "var(c) = " << var(c););
236         for (monic const& bc : _().emons().get_use_list(c.var())) {
237             if (order_lemma_on_ac_and_bc(rm, ac, k, bc))
238                 return;
239         }
240     }
241     else {
242         for (monic const& bc : _().emons().get_products_of(c.var())) {
243             if (order_lemma_on_ac_and_bc(rm, ac, k, bc))
244                 return;
245         }
246     }
247 }
248 
generate_ol_eq(const monic & ac,const factor & a,const factor & c,const monic & bc,const factor & b)249 void order::generate_ol_eq(const monic& ac,
250                         const factor& a,
251                         const factor& c,
252                         const monic& bc,
253                         const factor& b) {
254 
255     new_lemma lemma(_(), __FUNCTION__);
256     IF_VERBOSE(100,
257                verbose_stream()
258                << var_val(ac) << "(" << mul_val(ac) << "): " << ac
259                << " " << var_val(bc) << "(" << mul_val(bc) << "): " << bc << "\n"
260                << " a " << "*v" << var(a) << " " << val(a) << "\n"
261                << " b " <<  "*v" << var(b) << " " << val(b) << "\n"
262                << " c " <<  "*v" << var(c) << " " << val(c) << "\n");
263     // ac == bc
264     lemma |= ineq(c.var(), llc::EQ, 0); // c is not equal to zero
265     lemma |= ineq(term(ac.var(), -rational(1), bc.var()), llc::NE, 0);
266     lemma |= ineq(term(a.rat_sign(), a.var(), -b.rat_sign(), b.var()), llc::EQ, 0);
267     lemma &= ac;
268     lemma &= a;
269     lemma &= bc;
270     lemma &= b;
271     lemma &= c;
272 }
273 
generate_ol(const monic & ac,const factor & a,const factor & c,const monic & bc,const factor & b)274 void order::generate_ol(const monic& ac,
275                         const factor& a,
276                         const factor& c,
277                         const monic& bc,
278                         const factor& b) {
279 
280     new_lemma lemma(_(), __FUNCTION__);
281     TRACE("nla_solver", _().trace_print_ol(ac, a, c, bc, b, tout););
282     IF_VERBOSE(10, verbose_stream() << var_val(ac) << "(" << mul_val(ac) << "): " << ac
283                << " " << var_val(bc) << "(" << mul_val(bc) << "): " << bc << "\n"
284                << " a " << "*v" << var(a) << " " << val(a) << "\n"
285                << " b " << "*v" << var(b) << " " << val(b) << "\n"
286                << " c " << "*v" << var(c) << " " << val(c) << "\n");
287     // c > 0 and ac >= bc => a >= b
288     // c > 0 and ac <= bc => a <= b
289     // c < 0 and ac >= bc => a <= b
290     // c < 0 and ac <= bc => a >= b
291 
292 
293     lemma |= ineq(c.var(), val(c.var()).is_neg() ? llc::GE : llc::LE, 0);
294     lemma |= ineq(term(rational(1), ac.var(), -rational(1), bc.var()), var_val(ac) < var_val(bc) ? llc::GT : llc::LT, 0);
295     // The value of factor k is val(k) = k.rat_sign()*val(k.var()).
296     // That is why we need to use the factor signs of a and b in the term,
297     // but the constraint of the lemma is defined by val(a) and val(b).
298     lemma |= ineq(term(a.rat_sign(), a.var(),  -b.rat_sign(), b.var()),  val(a)  < val(b)  ? llc::GE : llc::LE, 0);
299 
300     lemma &= ac;
301     lemma &= a;
302     lemma &= bc;
303     lemma &= b;
304     lemma &= c;
305 }
306 
307 // We have ac = a*c and bc = b*c.
308 // Suppose ac >= bc, then ac/|c| >= bc/|c|
309 // Notice that ac/|c| = a*rat_sign(val(c)|, and similar fo bc/|c|.
310 //
order_lemma_on_ac_and_bc_and_factors(const monic & ac,const factor & a,const factor & c,const monic & bc,const factor & b)311 bool order::order_lemma_on_ac_and_bc_and_factors(const monic& ac,
312                                                  const factor& a,
313                                                  const factor& c,
314                                                  const monic& bc,
315                                                  const factor& b) {
316     SASSERT(!val(c).is_zero());
317     rational c_sign = rational(nla::rat_sign(val(c)));
318     auto av_c_s = val(a) * c_sign;
319     auto bv_c_s = val(b) * c_sign;
320     if ((var_val(ac) > var_val(bc) && av_c_s < bv_c_s) ||
321         (var_val(ac) < var_val(bc) && av_c_s > bv_c_s)) {
322         generate_ol(ac, a, c, bc, b);
323         return true;
324     }
325     else if ((var_val(ac) == var_val(bc)) && (av_c_s != bv_c_s)) {
326         generate_ol_eq(ac, a, c, bc, b);
327         return true;
328     }
329     return false;
330 }
331 /*
332    given: sign * m = ab
333    lemma b != val(b) || sign*m <= a*val(b)
334 */
order_lemma_on_ab_gt(new_lemma & lemma,const monic & m,const rational & sign,lpvar a,lpvar b)335 void order::order_lemma_on_ab_gt(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b) {
336     SASSERT(sign * var_val(m) > val(a) * val(b));
337     // negate b == val(b)
338     lemma |= ineq(b, llc::NE, val(b));
339     // ab <= val(b)a
340     lemma |= ineq(term(sign, m.var(), -val(b), a), llc::LE, 0);
341 }
342 /*
343    given: sign * m = ab
344    lemma b != val(b) || sign*m >= a*val(b)
345 */
order_lemma_on_ab_lt(new_lemma & lemma,const monic & m,const rational & sign,lpvar a,lpvar b)346 void order::order_lemma_on_ab_lt(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b) {
347     TRACE("nla_solver", tout << "sign = " << sign << ", m = "; c().print_monic(m, tout) << ", a = "; c().print_var(a, tout) <<
348           ", b = "; c().print_var(b, tout) << "\n";);
349     SASSERT(sign * var_val(m) < val(a) * val(b));
350     // negate b == val(b)
351     lemma |= ineq(b, llc::NE, val(b));
352     // ab >= val(b)a
353     lemma |= ineq(term(sign, m.var(), -val(b), a), llc::GE, 0);
354 }
355 
order_lemma_on_ab(new_lemma & lemma,const monic & m,const rational & sign,lpvar a,lpvar b,bool gt)356 void order::order_lemma_on_ab(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b, bool gt) {
357     if (gt)
358         order_lemma_on_ab_gt(lemma, m, sign, a, b);
359     else
360         order_lemma_on_ab_lt(lemma, m, sign, a, b);
361 }
362 
363 }
364