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