1 /*
2  * This file is part of the Yices SMT Solver.
3  * Copyright (C) 2017 SRI International.
4  *
5  * Yices is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Yices is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "mcsat/nra/libpoly_utils.h"
20 #include "mcsat/nra/nra_plugin_internal.h"
21 #include "mcsat/tracing.h"
22 
23 #include "terms/balanced_arith_buffers.h"
24 #include "terms/rba_buffer_terms.h"
25 #include "terms/term_manager.h"
26 
27 #include <poly/monomial.h>
28 
29 #include <gmp.h>
30 
lp_polynomial_from_power_product(nra_plugin_t * nra,pprod_t * pp,lp_integer_t * c)31 lp_polynomial_t* lp_polynomial_from_power_product(nra_plugin_t* nra, pprod_t* pp, lp_integer_t* c) {
32 
33   // Context
34   lp_polynomial_context_t* lp_ctx = nra->lp_data.lp_ctx;
35 
36   // The monomials
37   lp_monomial_t lp_monomial;
38   lp_monomial_construct(lp_ctx, &lp_monomial);
39 
40   // Set monomial coefficient to 1
41   lp_integer_t one;
42   lp_integer_construct_from_int(lp_Z, &one, 1);
43   lp_monomial_set_coefficient(lp_ctx, &lp_monomial, &one);
44   lp_integer_destruct(&one);
45 
46   // Get the product terms
47   uint32_t i = 0;
48   for (i = 0; i < pp->len; ++ i) {
49     variable_t var = variable_db_get_variable(nra->ctx->var_db, pp->prod[i].var);
50     lp_variable_t lp_var = nra_plugin_get_lp_variable(nra, var);
51     lp_monomial_push(&lp_monomial, lp_var, pp->prod[i].exp);
52   }
53 
54   lp_polynomial_t* result = lp_polynomial_new(nra->lp_data.lp_ctx);
55   lp_polynomial_add_monomial(result, &lp_monomial);
56 
57   if (c) {
58     lp_integer_assign_int(lp_Z, c, 1);
59   }
60 
61   lp_monomial_destruct(&lp_monomial);
62 
63   return result;
64 }
65 
lp_polynomial_from_polynomial(nra_plugin_t * nra,polynomial_t * p,lp_integer_t * c)66 lp_polynomial_t* lp_polynomial_from_polynomial(nra_plugin_t* nra, polynomial_t* p, lp_integer_t* c) {
67 
68   uint32_t i, j;
69   variable_t var;
70   lp_variable_t lp_var;
71 
72   lp_polynomial_t* result = lp_polynomial_new(nra->lp_data.lp_ctx);
73 
74   //
75   // we have
76   // q_1 + q_2*p_2 + ... + q_n p_n
77   //
78   // with q rationals, and p power products
79   //
80   // we get the lcm of the denominators first, and multiply it out
81   //
82 
83   // Integers to represent rationals
84   lp_integer_t a, b;
85   lp_integer_construct(&a);
86   lp_integer_construct(&b);
87 
88   // Compute the lcm
89   lp_integer_t lcm;
90   lp_integer_construct_from_int(lp_Z, &lcm, 1);
91   for (i = 0; i < p->nterms; ++ i) {
92     lp_integer_assign_yices_rational(&a, &b, &p->mono[i].coeff);
93     lp_integer_lcm_Z(&lcm, &lcm, &b);
94   }
95 
96   // Assign to c
97   if (c) {
98     lp_integer_assign(lp_Z, c, &lcm);
99   }
100 
101   // Context
102   term_table_t* terms = nra->ctx->terms;
103   variable_db_t* var_db = nra->ctx->var_db;
104   lp_polynomial_context_t* lp_ctx = nra->lp_data.lp_ctx;
105 
106   // The monomials
107   lp_monomial_t lp_monomial;
108   lp_monomial_construct(lp_ctx, &lp_monomial);
109 
110   // Add up all the monomials
111   for (i = 0; i < p->nterms; ++ i) {
112 
113     term_t product = p->mono[i].var;
114     lp_monomial_clear(lp_ctx, &lp_monomial);
115 
116     // The constant (a/b)*lcm
117     lp_integer_assign_yices_rational(&a, &b, &p->mono[i].coeff);
118     lp_integer_div_exact(lp_Z, &b, &lcm, &b);
119     lp_integer_mul(lp_Z, &a, &a, &b);
120     lp_monomial_set_coefficient(lp_ctx, &lp_monomial, &a);
121 
122     if (product == const_idx) {
123       // Constant polynomial, nothing to do
124     } else if (term_kind(terms, product) == POWER_PRODUCT) {
125       // Add all the variables
126       pprod_t* pprod = pprod_for_term(terms, product);
127       for (j = 0; j < pprod->len; ++j) {
128         var = variable_db_get_variable(var_db, pprod->prod[j].var);
129         lp_var = nra_plugin_get_lp_variable(nra, var);
130         lp_monomial_push(&lp_monomial, lp_var, pprod->prod[j].exp);
131       }
132     } else {
133       // Variable, or foreign term
134       var = variable_db_get_variable(var_db, product);
135       lp_var = nra_plugin_get_lp_variable(nra, var);
136       lp_monomial_push(&lp_monomial, lp_var, 1);
137     }
138 
139     // Add the monomial to the polynomial
140     lp_polynomial_add_monomial(result, &lp_monomial);
141   }
142 
143   // Remove temps
144   lp_monomial_destruct(&lp_monomial);
145   lp_integer_destruct(&a);
146   lp_integer_destruct(&b);
147   lp_integer_destruct(&lcm);
148 
149   return result;
150 }
151 
lp_polynomial_from_term(nra_plugin_t * nra,term_table_t * terms,term_t t,lp_integer_t * c)152 lp_polynomial_t* lp_polynomial_from_term(nra_plugin_t* nra, term_table_t* terms, term_t t, lp_integer_t* c) {
153   term_kind_t kind;
154   lp_polynomial_t* result;
155 
156   result = 0;
157 
158   if (ctx_trace_enabled(nra->ctx, "nra::terms")) {
159     ctx_trace_printf(nra->ctx, "lp_polynomial_from_term: t = ");
160     ctx_trace_term(nra->ctx, t);
161   }
162 
163   kind = term_kind(terms, t);
164   switch (kind) {
165   case ARITH_POLY:
166     result = lp_polynomial_from_polynomial(nra, poly_term_desc(terms, t), c);
167     break;
168   case ARITH_CONSTANT: {
169     // Get the constant numerator and denominator
170     lp_integer_t lp_p;
171     lp_integer_construct_from_int(lp_Z, &lp_p, 0);
172     lp_integer_assign_yices_rational(&lp_p, c, rational_term_desc(terms, t));
173     // polynomial a*x^0
174     result = lp_polynomial_alloc();
175     lp_polynomial_construct_simple(result, nra->lp_data.lp_ctx, &lp_p, 0, 0);
176     // Remove temp
177     lp_integer_destruct(&lp_p);
178     break;
179   }
180   case POWER_PRODUCT:
181     result = lp_polynomial_from_power_product(nra, pprod_term_desc(terms, t), c);
182     break;
183   default: {
184     // Constant 1
185     lp_integer_t one;
186     lp_integer_construct_from_int(lp_Z, &one, 1);
187     // The variable
188     variable_t t_var = variable_db_get_variable_if_exists(nra->ctx->var_db, t);
189     lp_variable_t lp_var = nra_plugin_get_lp_variable(nra, t_var);
190     // Polynomial 1*x^1
191     result = lp_polynomial_alloc();
192     lp_polynomial_construct_simple(result, nra->lp_data.lp_ctx, &one, lp_var, 1);
193     // Put 1 if requested
194     if (c != NULL) {
195       lp_integer_assign(lp_Z, c, &one);
196     }
197     // Remove temp
198     lp_integer_destruct(&one);
199   }
200   }
201 
202   if (ctx_trace_enabled(nra->ctx, "nra::terms")) {
203     ctx_trace_printf(nra->ctx, "lp_polynomial_from_term: result = ");
204     lp_polynomial_print(result, ctx_trace_out(nra->ctx));
205     ctx_trace_printf(nra->ctx, "\n");
206   }
207 
208   return result;
209 }
210 
lp_integer_construct_from_yices_rational(lp_integer_t * lp_p,lp_integer_t * lp_q,const rational_t * q)211 void lp_integer_construct_from_yices_rational(lp_integer_t* lp_p, lp_integer_t* lp_q, const rational_t* q) {
212   if (lp_p != NULL) {
213     rational_t q_num;
214     q_init(&q_num);
215     q_get_num(&q_num, q);
216     mpq_t q_num_mpq;
217     mpq_init(q_num_mpq);
218     q_get_mpq(&q_num, q_num_mpq);
219     lp_integer_construct_from_rational(lp_Z, lp_p, q_num_mpq);
220     mpq_clear(q_num_mpq);
221     q_clear(&q_num);
222   }
223   if (lp_q != NULL) {
224     rational_t q_den;
225     q_init(&q_den);
226     q_get_den(&q_den, q);
227     mpq_t q_den_mpq;
228     mpq_init(q_den_mpq);
229     q_get_mpq(&q_den, q_den_mpq);
230     lp_integer_construct_from_rational(lp_Z, lp_q, q_den_mpq);
231     mpq_clear(q_den_mpq);
232     q_clear(&q_den);
233   }
234 }
235 
lp_integer_assign_yices_rational(lp_integer_t * lp_p,lp_integer_t * lp_q,const rational_t * q)236 void lp_integer_assign_yices_rational(lp_integer_t* lp_p, lp_integer_t* lp_q, const rational_t* q) {
237   lp_integer_destruct(lp_p);
238   lp_integer_destruct(lp_q);
239   lp_integer_construct_from_yices_rational(lp_p, lp_q, q);
240 }
241 
rational_construct_from_lp_integer(rational_t * q,const lp_integer_t * lp_z)242 void rational_construct_from_lp_integer(rational_t* q, const lp_integer_t* lp_z) {
243   q_init(q);
244   q_set_mpz(q, lp_z);
245 }
246 
247 typedef struct {
248   nra_plugin_t* nra;
249   rba_buffer_t* b;
250   term_table_t* terms;
251 } lp_polynomial_to_yices_term_data;
252 
lp_polynomial_to_yices_traverse_f(const lp_polynomial_context_t * ctx,lp_monomial_t * m,void * void_data)253 void lp_polynomial_to_yices_traverse_f(const lp_polynomial_context_t* ctx, lp_monomial_t* m, void* void_data) {
254 
255   lp_polynomial_to_yices_term_data* data = (lp_polynomial_to_yices_term_data*) void_data;
256 
257   if (ctx_trace_enabled(data->nra->ctx, "nra::terms")) {
258     ctx_trace_printf(data->nra->ctx, "lp_polynomial_to_yices_term(");
259     lp_monomial_print(ctx, m, ctx_trace_out(data->nra->ctx));
260     ctx_trace_printf(data->nra->ctx, ")\n");
261   }
262 
263   // Constant
264   rational_t a;
265   q_init(&a);
266   q_set_mpz(&a, &m->a);
267 
268   if (m->n == 0) {
269     // Just constant
270     rba_buffer_add_const(data->b, &a);
271   } else {
272     // Actual monomial
273     pp_buffer_t pp;
274     init_pp_buffer(&pp, 0);
275     uint32_t i = 0;
276     for (i = 0; i < m->n; ++ i) {
277       lp_variable_t lp_x = m->p[i].x;
278       variable_t x = nra_plugin_get_variable_from_lp_variable(data->nra, lp_x);
279       term_t x_term = variable_db_get_term(data->nra->ctx->var_db, x);
280       pp_buffer_mul_varexp(&pp, x_term, m->p[i].d);
281     }
282     pprod_t* pprod = pprod_from_buffer(data->terms->pprods, &pp);
283     term_t pp_term = pp_is_var(pprod) ? var_of_pp(pprod) : pprod_term(data->terms, pprod);
284     rba_buffer_add_const_times_term(data->b, data->terms, &a, pp_term);
285     delete_pp_buffer(&pp);
286   }
287 
288   q_clear(&a);
289 }
290 
lp_polynomial_to_yices_term(nra_plugin_t * nra,const lp_polynomial_t * lp_p)291 term_t lp_polynomial_to_yices_term(nra_plugin_t* nra, const lp_polynomial_t* lp_p) {
292 
293   term_table_t* terms = nra->ctx->terms;
294 
295   if (ctx_trace_enabled(nra->ctx, "nra::terms")) {
296     ctx_trace_printf(nra->ctx, "lp_polynomial_to_yices_term(");
297     lp_polynomial_print(lp_p, ctx_trace_out(nra->ctx));
298     ctx_trace_printf(nra->ctx, ")\n");
299   }
300 
301   // Buffer for building
302   lp_polynomial_to_yices_term_data data;
303   data.nra   = nra;
304   data.b     = &nra->buffer;
305   data.terms = terms;
306   reset_rba_buffer(data.b);
307 
308   // Traverse and build
309   lp_polynomial_traverse(lp_p, lp_polynomial_to_yices_traverse_f, &data);
310 
311   // Make the term
312   term_t result = mk_direct_arith_term(terms, data.b);
313 
314   if (ctx_trace_enabled(nra->ctx, "nra::terms")) {
315     ctx_trace_printf(nra->ctx, "lp_polynomial_to_yices_term(");
316     lp_polynomial_print(lp_p, ctx_trace_out(nra->ctx));
317     ctx_trace_printf(nra->ctx, ") => [%d] ", result);
318     ctx_trace_term(nra->ctx, result);
319   }
320 
321   return result;
322 }
323 
324