• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SRI-CSL / yices2 / 23882467937

02 Apr 2026 03:34AM UTC coverage: 66.728% (+0.2%) from 66.539%
23882467937

Pull #611

github

web-flow
Merge 4003e85ba into 895707f23
Pull Request #611: Wrap MCSAT as a Nelson-Oppen theory solver in CDCL(T) architecture

690 of 1006 new or added lines in 15 files covered. (68.59%)

2 existing lines in 2 files now uncovered.

84087 of 126014 relevant lines covered (66.73%)

1692201.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.83
/src/context/context_simplifier.c
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
/*
20
 * SIMPLIFICATIONS AND PREPROCESSING OF ASSERTIONS
21
 *
22
 * This module implements preprocessing and simplification procedures
23
 * that do not depend on the solvers used. These procedures used to be
24
 * in context.c. Moved them to this new module created in February 2013.
25
 */
26

27
#include "context/conditional_definitions.h"
28
#include "context/context_simplifier.h"
29
#include "context/context_utils.h"
30
#include "context/internalization_codes.h"
31
#include "context/eq_learner.h"
32
#include "context/symmetry_breaking.h"
33
#include "terms/bvfactor_buffers.h"
34
#include "terms/poly_buffer_terms.h"
35
#include "terms/power_products.h"
36
#include "terms/rba_buffer_terms.h"
37
#include "terms/term_utils.h"
38

39

40
#define TRACE_SUBST  0
41
#define TRACE_EQ_ABS 0
42
#define TRACE_DL     0
43

44
#define TRACE_SYM_BREAKING 0
45

46
#if TRACE_SUBST || TRACE_EQ_ABS || TRACE_DL || TRACE_SYM_BREAKING
47

48
#include <stdio.h>
49
#include <inttypes.h>
50

51
#include "io/term_printer.h"
52
#include "terms/bv64_constants.h"
53

54
#endif
55

56

57

58
/*****************************
59
 *  FORMULA SIMPLIFICATION   *
60
 ****************************/
61

62
/*
63
 * All functions below attempt to rewrite a (boolean) term r to an
64
 * equivalent (boolean) term q. They return NULL_TERM if the
65
 * simplification fails.
66
 */
67
static term_t simplify_select(context_t *ctx, term_t r) {
×
68
  select_term_t *sel;
69
  composite_term_t *tuple;
70
  term_t t;
71

72
  sel = select_term_desc(ctx->terms, r);
×
73
  t = intern_tbl_get_root(&ctx->intern, sel->arg);
×
74
  if (term_kind(ctx->terms, t) == TUPLE_TERM) {
×
75
    // select i (tuple ... t_i ...) --> t_i
76
    tuple = tuple_term_desc(ctx->terms, t);
×
77
    return tuple->arg[sel->idx];
×
78
  }
79

80
  return NULL_TERM;
×
81
}
82

83
static term_t simplify_bit_select(context_t *ctx, term_t r) {
32,140✔
84
  select_term_t *sel;
85
  term_t t;
86

87
  sel = bit_term_desc(ctx->terms, r);
32,140✔
88
  t = intern_tbl_get_root(&ctx->intern, sel->arg);
32,140✔
89
  return extract_bit(ctx->terms, t, sel->idx);
32,140✔
90
}
91

92
static term_t simplify_arith_geq0(context_t *ctx, term_t r) {
27,815✔
93
  term_table_t *terms;
94
  composite_term_t *d;
95
  term_t t, x, y;
96

97
  terms = ctx->terms;
27,815✔
98
  t = arith_ge_arg(terms, r);
27,815✔
99
  t = intern_tbl_get_root(&ctx->intern, t);
27,815✔
100
  if (is_ite_term(terms, t)) {
27,815✔
101
    /*
102
     * (ite c x y) >= 0 --> c  if (x >= 0) and (y < 0)
103
     * (ite c x y) >= 0 --> ~c if (x < 0) and (y >= 0)
104
     */
105
    d = ite_term_desc(terms, t);
6✔
106
    x = intern_tbl_get_root(&ctx->intern, d->arg[1]);
6✔
107
    y = intern_tbl_get_root(&ctx->intern, d->arg[2]);
6✔
108

109
    // DJ: We're passing true for simplify_ite?
110
    if (arith_term_is_nonneg(terms, x, true) &&
6✔
111
        arith_term_is_negative(terms, y, true)) {
×
112
      return d->arg[0];
×
113
    }
114

115
    if (arith_term_is_negative(terms, x, true) &&
8✔
116
        arith_term_is_nonneg(terms, y, true)) {
2✔
117
      return opposite_term(d->arg[0]);
1✔
118
    }
119
  }
120

121
  return NULL_TERM;
27,814✔
122
}
123

124
static term_t simplify_arith_eq0(context_t *ctx, term_t r) {
2,271✔
125
  term_table_t *terms;
126
  composite_term_t *d;
127
  term_t t, x, y;
128

129
  terms = ctx->terms;
2,271✔
130
  t = arith_eq_arg(terms, r);
2,271✔
131
  t = intern_tbl_get_root(&ctx->intern, t);
2,271✔
132
  if (is_ite_term(terms, t)) {
2,271✔
133
    /*
134
     * (ite c 0 y) == 0 -->  c if y != 0
135
     * (ite c x 0) == 0 --> ~c if x != 0
136
     */
137
    d = ite_term_desc(terms, t);
8✔
138
    x = intern_tbl_get_root(&ctx->intern, d->arg[1]);
8✔
139
    y = intern_tbl_get_root(&ctx->intern, d->arg[2]);
8✔
140

141
    if (x == zero_term && arith_term_is_nonzero(terms, y, true)) {
8✔
142
      return d->arg[0];
1✔
143
    }
144

145
    if (y == zero_term && arith_term_is_nonzero(terms, x, true)) {
7✔
146
      return opposite_term(d->arg[0]);
×
147
    }
148
  }
149

150
  return NULL_TERM;
2,270✔
151
}
152

153

154
/*
155
 * Simplification of if-then-else: (ite c t1 t2)
156
 * - c, t1, and t2 are all root terms in the internalization table
157
 * - flatten_bool_ite does more simplifications
158
 */
159
static term_t simplify_ite(context_t *ctx, term_t c, term_t t1, term_t t2) {
77✔
160
  if (t1 == t2) return t1;                // (ite c t1 t1) --> t1
77✔
161
  if (term_is_true(ctx, c)) return t1;    // (ite true t1 t2) --> t1
77✔
162
  if (term_is_false(ctx, c)) return t2;   // (ite false t1 t2) --> t2
76✔
163

164
  return NULL_TERM;
75✔
165
}
166

167

168

169
/*
170
 * Simplification for equalities between two terms t1 and t2.
171
 * - both t1 and t2 are root terms in the internalization table
172
 * - the simplification functions don't check whether t1 = t2
173
 * - all simplification functions either a boolean term t equivalent
174
 *   to (t1 == t2) or return NULL_TERM if no simplification is found
175
 */
176

177
// t1 and t2 are arithmetic terms
178
static term_t simplify_arith_bineq(context_t *ctx, term_t t1, term_t t2) {
4,562✔
179
  term_table_t *terms;
180
  composite_term_t *d;
181
  term_t x, y;
182

183
  terms = ctx->terms;
4,562✔
184
  if (is_ite_term(terms, t1)) {
4,562✔
185
    /*
186
     * (ite c x y) == x --> c  if x != y
187
     * (ite c x y) == y --> ~c if x != y
188
     */
189
    d = ite_term_desc(terms, t1);
148✔
190
    x = intern_tbl_get_root(&ctx->intern, d->arg[1]);
148✔
191
    y = intern_tbl_get_root(&ctx->intern, d->arg[2]);
148✔
192

193
    if (x == t2 && disequal_arith_terms(terms, y, t2, true)) {
148✔
194
      return d->arg[0];
×
195
    }
196

197
    if (y == t2 && disequal_arith_terms(terms, x, t2, true)) {
148✔
198
      return opposite_term(d->arg[0]);
×
199
    }
200
  }
201

202
  if (is_ite_term(terms, t2)) {
4,562✔
203
    // symmetric case
204
    d = ite_term_desc(terms, t2);
468✔
205
    x = intern_tbl_get_root(&ctx->intern, d->arg[1]);
468✔
206
    y = intern_tbl_get_root(&ctx->intern, d->arg[2]);
468✔
207

208
    if (x == t1 && disequal_arith_terms(terms, y, t1, true)) {
468✔
209
      return d->arg[0];
1✔
210
    }
211

212
    if (y == t1 && disequal_arith_terms(terms, x, t1, true)) {
467✔
213
      return opposite_term(d->arg[0]);
1✔
214
    }
215
  }
216

217
  return NULL_TERM;
4,560✔
218
}
219

220
// t1 and t2 are boolean terms
221
term_t simplify_bool_eq(context_t *ctx, term_t t1, term_t t2) {
6,517✔
222
  if (term_is_true(ctx, t1)) return t2;  // (eq true t2) --> t2
6,517✔
223
  if (term_is_true(ctx, t2)) return t1;  // (eq t1 true) --> t1
6,419✔
224
  if (term_is_false(ctx, t1)) return opposite_term(t2); // (eq false t2) --> not t2
6,415✔
225
  if (term_is_false(ctx, t2)) return opposite_term(t1); // (eq t1 false) --> not t1
6,334✔
226

227
  return NULL_TERM;
6,331✔
228
}
229

230

231
/*
232
 * Simplification for (bveq t1 t2)
233
 * - both t1 and t2 must be root terms in the internalization table
234
 */
235
term_t simplify_bitvector_eq(context_t *ctx, term_t t1, term_t t2) {
34,062✔
236
  term_table_t *terms;
237
  term_t t;
238

239
  terms = ctx->terms;
34,062✔
240
  if (t1 == t2) {
34,062✔
241
    t = true_term;
1✔
242
  } else if (disequal_bitvector_terms(terms, t1, t2)) {
34,061✔
243
    t = false_term;
22✔
244
  } else {
245
    t = simplify_bveq(terms, t1, t2);
34,039✔
246
  }
247

248
  return t;
34,062✔
249
}
250

251

252
/*
253
 * Try arithmetic/rewriting simplifications for (t1 == t2)
254
 * - t1 and t2 must be root terms in the internalization table
255
 * - the result is stored in *r
256
 * - if r->code is REDUCED then (t1 == t2) is equivalent to (u1 == u2)
257
 *   the two terms u1 and u2 are stored in r->left and r->right.
258
 * - if r->code is REDUCED0 then (t1 == t2) is equivalent to (u1 == 0)
259
 *   u1 is stored in r->left and NULL_TERM is stored in r->right.
260
 */
261
void try_arithmetic_bveq_simplification(context_t *ctx, bveq_simp_t *r, term_t t1, term_t t2) {
14,056✔
262
  term_table_t *terms;
263
  bvpoly_buffer_t *b;
264
  uint32_t n;
265
  term_t u1, u2;
266

267
  terms = ctx->terms;
14,056✔
268

269
  r->code = BVEQ_CODE_NOCHANGE;
14,056✔
270

271
  if (is_bvpoly_term(terms, t1) || is_bvpoly_term(terms, t2)) {
14,056✔
272
    b = context_get_bvpoly_buffer(ctx);
5,993✔
273
    n = term_bitsize(terms, t1);
5,993✔
274

275
    reset_bvpoly_buffer(b, n);
5,993✔
276
    add_bvterm_to_buffer(terms, t1, b);
5,993✔
277
    sub_bvterm_from_buffer(terms, t2, b);
5,993✔
278
    normalize_bvpoly_buffer(b);
5,993✔
279

280
    if (bvpoly_buffer_is_zero(b)) {
5,993✔
281
      r->code = BVEQ_CODE_TRUE;
×
282
    } else if (bvpoly_buffer_is_constant(b)) {
5,993✔
283
      r->code = BVEQ_CODE_FALSE;
×
284
    } else if (bvpoly_buffer_is_pm_var(b, &u1)) {
5,993✔
285
      r->code = BVEQ_CODE_REDUCED0;
38✔
286
      r->left = u1;
38✔
287
      r->right = NULL_TERM;
38✔
288
    } else if (bvpoly_buffer_is_var_minus_var(b, &u1, &u2)) {
5,955✔
289
      r->code = BVEQ_CODE_REDUCED;
47✔
290
      r->left = u1;
47✔
291
      r->right = u2;
47✔
292
    }
293
  }
294
}
14,056✔
295

296

297

298
/*
299
 * SIMPLIFICATION OF EQUALITY USING FACTORING
300
 */
301

302
#if 0
303

304
/*
305
 * Print
306
 */
307
static void show_factors(bvfactor_buffer_t *b) {
308
  pprod_t *aux;
309
  bvpoly64_t *p;
310
  bvpoly_t *q;
311

312
  printf("constant: ");
313
  if (b->bitsize <= 64) {
314
    bvconst64_print(stdout, b->constant64, b->bitsize);
315
  } else {
316
    bvconst_print(stdout, b->constant.data, b->bitsize);
317
  }
318
  printf("\nproduct: ");
319
  aux = pp_buffer_getprod(&b->product);
320
  print_pprod(stdout, aux);
321
  free_pprod(aux);
322
  printf("\nexponent: ");
323
  if (b->bitsize <= 64) {
324
    p = bvpoly_buffer_getpoly64(&b->exponent);
325
    print_bvpoly64(stdout, p);
326
    free_bvpoly64(p);
327
  } else {
328
    q = bvpoly_buffer_getpoly(&b->exponent);
329
    print_bvpoly(stdout, q);
330
    free_bvpoly(q);
331
  }
332
  printf("\n");
333
}
334

335
static void show_bvfactoring(bvfactoring_t *r) {
336
  uint32_t i;
337

338
  printf("\n--- reduced 1 ---\n");
339
  for (i=0; i<r->n1; i++) {
340
    printf("reduced1[%"PRIu32"]\n", i);
341
    show_factors(r->reduced1 + i);
342
    printf("\n");
343
  }
344

345
  printf("--- reduced 2 ---\n");
346
  for (i=0; i<r->n2; i++) {
347
    printf("reduced2[%"PRIu32"]\n", i);
348
    show_factors(r->reduced2 + i);
349
    printf("\n");
350
  }
351

352
  fflush(stdout);
353
}
354

355
static void show_product(pp_buffer_t *f) {
356
  pprod_t *pp;
357

358
  pp = pp_buffer_getprod(f);
359
  print_pprod(stdout, pp);
360
  free_pprod(pp);
361

362
  fflush(stdout);
363
}
364

365
#endif
366

367
/*
368
 * Factoring buffers:
369
 * - initialize: just set code to BVFACTOR_TODO
370
 * - other fields are initialized lazily
371
 */
372
void init_bvfactoring(bvfactoring_t *r) {
6,530✔
373
  r->code = BVFACTOR_TODO;
6,530✔
374
  r->bitsize = 0;
6,530✔
375
  r->poly_buffer = NULL;
6,530✔
376
  r->pp_buffer = NULL;
6,530✔
377
}
6,530✔
378

379

380
/*
381
 * Delete buffers
382
 */
383
void delete_bvfactoring(bvfactoring_t *r) {
6,530✔
384
  uint32_t i;
385

386
  if (r->code != BVFACTOR_TODO) {
6,530✔
387
    delete_bvfactor_buffer(&r->common);
18✔
388
    for (i=0; i<r->n1; i++) {
40✔
389
      delete_bvfactor_buffer(r->reduced1+i);
22✔
390
    }
391
    for (i=0; i<r->n2; i++) {
44✔
392
      delete_bvfactor_buffer(r->reduced2+i);
26✔
393
    }
394
    r->code = BVFACTOR_TODO;
18✔
395
  }
396

397
  if (r->poly_buffer != NULL) {
6,530✔
398
    delete_bvpoly_buffer(r->poly_buffer);
15✔
399
    safe_free(r->poly_buffer);
15✔
400
    r->poly_buffer = NULL;
15✔
401
  }
402

403
  if (r->pp_buffer != NULL) {
6,530✔
404
    delete_pp_buffer(r->pp_buffer);
16✔
405
    safe_free(r->pp_buffer);
16✔
406
    r->pp_buffer = NULL;
16✔
407
  }
408
}
6,530✔
409

410

411
/*
412
 * Allocate the auxiliary buffers
413
 */
414
static bvpoly_buffer_t *factoring_get_poly_buffer(bvfactoring_t *r) {
26✔
415
  bvpoly_buffer_t *p;
416

417
  p = r->poly_buffer;
26✔
418
  if (p == NULL) {
26✔
419
    p =  (bvpoly_buffer_t *) safe_malloc(sizeof(bvpoly_buffer_t));
15✔
420
    init_bvpoly_buffer(p);
15✔
421
    r->poly_buffer = p;
15✔
422
  }
423

424
  return p;
26✔
425
}
426

427
static pp_buffer_t *factoring_get_pp_buffer(bvfactoring_t *r) {
16✔
428
  pp_buffer_t *p;
429

430
  p = r->pp_buffer;
16✔
431
  if (p == NULL) {
16✔
432
    p = (pp_buffer_t *) safe_malloc(sizeof(pp_buffer_t));
16✔
433
    init_pp_buffer(p, 4);
16✔
434
    r->pp_buffer = p;
16✔
435
  }
436

437
  return p;
16✔
438
}
439

440

441

442
/*
443
 * Prepare: allocate buffers
444
 * - n1 = number of buffers for reduced1
445
 * - n2 = number of buffers for reduced2
446
 * - bitsize = number of bits
447
 */
448
static void prepare_bvfactoring(bvfactoring_t *r, uint32_t bitsize, uint32_t n1, uint32_t n2) {
18✔
449
  uint32_t i;
450

451
  assert(0 < n1 && n1 <= MAX_BVFACTORS);
452
  assert(0 < n2 && n2 <= MAX_BVFACTORS);
453
  assert(r->code == BVFACTOR_TODO);
454

455
  r->code = BVFACTOR_FAILED; // safe default
18✔
456
  r->bitsize = bitsize;
18✔
457
  r->n1 = n1;
18✔
458
  r->n2 = n2;
18✔
459
  init_bvfactor_buffer(&r->common);
18✔
460
  for (i=0; i<n1; i++) {
36✔
461
    init_bvfactor_buffer(r->reduced1 + i);
18✔
462
  }
463
  for (i=0; i<n2; i++) {
43✔
464
    init_bvfactor_buffer(r->reduced2 + i);
25✔
465
  }
466
}
18✔
467

468

469
/*
470
 * Compute factors of t
471
 */
472
static void factoring_set_left_term(bvfactoring_t *r, term_table_t *terms, term_t t) {
18✔
473
  assert(r->n1 >= 1);
474
  factor_bvterm(terms, t, r->reduced1);
18✔
475
}
18✔
476

477
static void factoring_set_right_term(bvfactoring_t *r, term_table_t *terms, term_t t) {
11✔
478
  assert(r->n2 >= 1);
479
  factor_bvterm(terms, t, r->reduced2);
11✔
480
}
11✔
481

482
/*
483
 * Add factors of p to r->reduced1
484
 */
485
static void factoring_set_right_poly64(bvfactoring_t *r, term_table_t *terms, bvpoly64_t *p) {
4✔
486
  assert(p->nterms <= r->n2);
487
  factor_bvpoly64_monomials(terms, p, r->reduced2);
4✔
488
}
4✔
489

490
static void factoring_set_right_poly(bvfactoring_t *r, term_table_t *terms, bvpoly_t *p) {
3✔
491
  assert(p->nterms <= r->n2);
492
  factor_bvpoly_monomials(terms, p, r->reduced2);
3✔
493
}
3✔
494

495

496
/*
497
 * Try to expand:
498
 * - if a factor is of the form  c * var * 2^e and var is a small polynomial,
499
 *   we can try to expand var and see if that reveals more factors.
500
 * - return true if this works
501
 */
502

503
// extend r->reduced1 from size 1 to size n. Copy r->reduced[0] in the new elements
504
static void bvfactoring_expand_left(bvfactoring_t *r, uint32_t n) {
4✔
505
  uint32_t i;
506

507
  assert(r->n1 == 1 && n <= MAX_BVFACTORS);
508
  r->n1 = n;
4✔
509
  for (i=1; i<n; i++) {
8✔
510
    bvfactor_buffer_init_copy(r->reduced1 + i, r->reduced1);
4✔
511
  }
512
}
4✔
513

514
// extend r->reduced2 from size 1 to size n. Copy r->reduced[0] in the new elements
515
static void bvfactoring_expand_right(bvfactoring_t *r, uint32_t n) {
1✔
516
  uint32_t i;
517

518
  assert(r->n2 == 1 && n <= MAX_BVFACTORS);
519
  r->n2 = n;
1✔
520
  for (i=1; i<n; i++) {
2✔
521
    bvfactor_buffer_init_copy(r->reduced2 + i, r->reduced2);
1✔
522
  }
523
}
1✔
524

525
// try to replace t by p in r->reduced1
526
static bool try_left_replace64(bvfactoring_t *r, term_table_t *terms, term_t t, bvpoly64_t *p) {
2✔
527
  uint32_t i;
528

529
  assert(r->n1 == 1 && bvfactor_buffer_is_var(r->reduced1) && t == bvfactor_buffer_get_var(r->reduced1));
530

531
  if (p->nterms <= MAX_BVFACTORS) {
2✔
532
    bvfactor_buffer_reduce_by_var(r->reduced1, t);
2✔
533
    bvfactoring_expand_left(r, p->nterms);
2✔
534
    assert(r->n1 == p->nterms);
535
    i = 0;
2✔
536
    if (p->mono[0].var == const_idx) {
2✔
537
      bvfactor_buffer_mulconst64(r->reduced1, p->mono[i].coeff, 1);
1✔
538
      bvfactor_buffer_normalize(r->reduced1);
1✔
539
      i = 1;
1✔
540
    }
541
    while (i<r->n1) {
5✔
542
      factor_mul_bvterm64(terms, p->mono[i].coeff, p->mono[i].var, r->reduced1 + i);
3✔
543
      i ++;
3✔
544
    }
545
    return true;
2✔
546
  }
547

548
  return false;
×
549
}
550

551
static bool try_left_replace(bvfactoring_t *r, term_table_t *terms, term_t t, bvpoly_t *p) {
2✔
552
  uint32_t i;
553

554
  assert(r->n1 == 1 && bvfactor_buffer_is_var(r->reduced1) && t == bvfactor_buffer_get_var(r->reduced1));
555

556
  if (p->nterms <= MAX_BVFACTORS) {
2✔
557
    bvfactor_buffer_reduce_by_var(r->reduced1, t);
2✔
558
    bvfactoring_expand_left(r, p->nterms);
2✔
559
    assert(r->n1 == p->nterms);
560
    i = 0;
2✔
561
    if (p->mono[0].var == const_idx) {
2✔
562
      bvfactor_buffer_mulconst(r->reduced1, p->mono[i].coeff, 1);
1✔
563
      bvfactor_buffer_normalize(r->reduced1);
1✔
564
      i = 1;
1✔
565
    }
566
    while (i<r->n1) {
5✔
567
      factor_mul_bvterm(terms, p->mono[i].coeff, p->mono[i].var, r->reduced1 + i);
3✔
568
      i ++;
3✔
569
    }
570
    return true;
2✔
571
  }
572

573
  return false;
×
574
}
575

576
// try to replace t by p in r->reduced2
577
static bool try_right_replace64(bvfactoring_t *r, term_table_t *terms, term_t t, bvpoly64_t *p) {
1✔
578
  uint32_t i;
579

580
  assert(r->n2 == 1 && bvfactor_buffer_is_var(r->reduced2) && t == bvfactor_buffer_get_var(r->reduced2));
581

582
  if (p->nterms <= MAX_BVFACTORS) {
1✔
583
    bvfactor_buffer_reduce_by_var(r->reduced2, t);
1✔
584
    bvfactoring_expand_right(r, p->nterms);
1✔
585
    assert(r->n2 == p->nterms);
586
    i = 0;
1✔
587
    if (p->mono[0].var == const_idx) {
1✔
588
      bvfactor_buffer_mulconst64(r->reduced2, p->mono[i].coeff, 1);
×
589
      bvfactor_buffer_normalize(r->reduced2);
×
590
      i = 1;
×
591
    }
592
    while (i<r->n2) {
3✔
593
      factor_mul_bvterm64(terms, p->mono[i].coeff, p->mono[i].var, r->reduced2 + i);
2✔
594
      i ++;
2✔
595
    }
596
    return true;
1✔
597
  }
598

599
  return false;
×
600
}
601

602
static bool try_right_replace(bvfactoring_t *r, term_table_t *terms, term_t t, bvpoly_t *p) {
×
603
  uint32_t i;
604

605
  assert(r->n2 == 1 && bvfactor_buffer_is_var(r->reduced2) && t == bvfactor_buffer_get_var(r->reduced2));
606

607
  if (p->nterms <= MAX_BVFACTORS) {
×
608
    bvfactor_buffer_reduce_by_var(r->reduced2, t);
×
609
    bvfactoring_expand_right(r, p->nterms);
×
610
    assert(r->n2 == p->nterms);
611
    i = 0;
×
612
    if (p->mono[0].var == const_idx) {
×
613
      bvfactor_buffer_mulconst(r->reduced2, p->mono[i].coeff, 1);
×
614
      bvfactor_buffer_normalize(r->reduced2);
×
615
      i = 1;
×
616
    }
617
    while (i<r->n2) {
×
618
      factor_mul_bvterm(terms, p->mono[i].coeff, p->mono[i].var, r->reduced2 + i);
×
619
      i ++;
×
620
    }
621
    return true;
×
622
  }
623

624
  return false;
×
625
}
626

627

628
static bool try_left_expansion(bvfactoring_t *r, term_table_t *terms) {
16✔
629
  term_t t;
630
  term_kind_t kind;
631

632
  if (r->n1 == 1 && bvfactor_buffer_is_var(r->reduced1)) {
16✔
633
    t = bvfactor_buffer_get_var(r->reduced1);
10✔
634
    kind = term_kind(terms, t);
10✔
635
    if (kind == BV64_POLY) {
10✔
636
      return try_left_replace64(r, terms, t, bvpoly64_term_desc(terms, t));
2✔
637
    } else if (kind == BV_POLY) {
8✔
638
      return try_left_replace(r, terms, t, bvpoly_term_desc(terms, t));
2✔
639
    }
640
  }
641

642
  return false;
12✔
643
}
644

645
static bool try_right_expansion(bvfactoring_t *r, term_table_t *terms) {
14✔
646
  term_t t;
647
  term_kind_t kind;
648

649
  if (r->n2 == 1 && bvfactor_buffer_is_var(r->reduced2)) {
14✔
650
    t = bvfactor_buffer_get_var(r->reduced2);
4✔
651
    kind = term_kind(terms, t);
4✔
652
    if (kind == BV64_POLY) {
4✔
653
      return try_right_replace64(r, terms, t, bvpoly64_term_desc(terms, t));
1✔
654
    } else if (kind == BV_POLY) {
3✔
655
      return try_right_replace(r, terms, t, bvpoly_term_desc(terms, t));
×
656
    }
657
  }
658

659
  return false;
13✔
660
}
661

662

663

664
/*
665
 * Check whether both reduced parts of r are linear
666
 * - ignore exponents
667
 */
668
static bool linear_reduced_factoring(bvfactoring_t *r) {
21✔
669
  uint32_t i;
670

671
  for (i=0; i<r->n1; i++) {
41✔
672
    if (! bvfactor_buffer_is_linear(r->reduced1 + i)) {
25✔
673
      return false;
5✔
674
    }
675
  }
676

677
  for (i=0; i<r->n2; i++) {
38✔
678
    if (! bvfactor_buffer_is_linear(r->reduced2 + i)) {
24✔
679
      return false;
2✔
680
    }
681
  }
682

683
  return true;
14✔
684
}
685

686
/*
687
 * Check whether both reduced parts of r have the same exponent
688
 */
689
static bool factoring_has_unique_exponent(bvfactoring_t *r) {
14✔
690
  uint32_t i;
691
  bvfactor_buffer_t *f0;
692

693
  assert(r->n1 > 0 && r->n2 > 0);
694
  f0 = r->reduced1;
14✔
695

696
  for (i=1; i<r->n1; i++) {
18✔
697
    if (! bvfactor_buffer_equal_exponents(f0, r->reduced1 + i)) {
4✔
698
      return false;
×
699
    }
700
  }
701

702
  for (i=0; i<r->n2; i++) {
25✔
703
    if (! bvfactor_buffer_equal_exponents(f0, r->reduced2 + i)) {
17✔
704
      return false;
6✔
705
    }
706
  }
707

708
  return true;
8✔
709
}
710

711

712

713
/*
714
 * Add factor f to buffer b:
715
 * - ignore the exponent of f
716
 * - f must be linear
717
 */
718
static void bvpoly_buffer_add_factor64(bvpoly_buffer_t *b, term_table_t *terms, bvfactor_buffer_t *f) {
7✔
719
  term_t t;
720

721
  assert(bvfactor_buffer_is_linear(f));
722
  assert(b->bitsize == f->bitsize && f->bitsize <= 64);
723

724
  if (bvfactor_buffer_product_is_one(f)) {
7✔
725
    bvpoly_buffer_add_const64(b, f->constant64);
2✔
726
  } else {
727
    t = bvfactor_buffer_get_var(f);
5✔
728
    addmul_bvterm64_to_buffer(terms, t, f->constant64, b);
5✔
729
  }
730
}
7✔
731

732
static void bvpoly_buffer_add_factor(bvpoly_buffer_t *b, term_table_t *terms, bvfactor_buffer_t *f) {
3✔
733
  term_t t;
734

735
  assert(bvfactor_buffer_is_linear(f));
736
  assert(b->bitsize == f->bitsize && f->bitsize > 64);
737

738
  if (bvfactor_buffer_product_is_one(f)) {
3✔
739
    bvpoly_buffer_add_constant(b, f->constant.data);
1✔
740
  } else {
741
    t = bvfactor_buffer_get_var(f);
2✔
742
    addmul_bvterm_to_buffer(terms, t, f->constant.data, b);
2✔
743
  }
744
}
3✔
745

746

747
/*
748
 * Subtract f from b
749
 */
750
static void bvpoly_buffer_sub_factor64(bvpoly_buffer_t *b, term_table_t *terms, bvfactor_buffer_t *f) {
8✔
751
  term_t t;
752

753
  assert(bvfactor_buffer_is_linear(f));
754
  assert(b->bitsize == f->bitsize && f->bitsize <= 64);
755

756
  if (bvfactor_buffer_product_is_one(f)) {
8✔
757
    bvpoly_buffer_sub_const64(b, f->constant64);
×
758
  } else {
759
    t = bvfactor_buffer_get_var(f);
8✔
760
    submul_bvterm64_from_buffer(terms, t, f->constant64, b);
8✔
761
  }
762
}
8✔
763

764
static void bvpoly_buffer_sub_factor(bvpoly_buffer_t *b, term_table_t *terms, bvfactor_buffer_t *f) {
3✔
765
  term_t t;
766

767
  assert(bvfactor_buffer_is_linear(f));
768
  assert(b->bitsize == f->bitsize && f->bitsize > 64);
769

770
  if (bvfactor_buffer_product_is_one(f)) {
3✔
771
    bvpoly_buffer_sub_constant(b, f->constant.data);
1✔
772
  } else {
773
    t = bvfactor_buffer_get_var(f);
2✔
774
    submul_bvterm_from_buffer(terms, t, f->constant.data, b);
2✔
775
  }
776
}
3✔
777

778

779
/*
780
 * Check whether the reduced factors are linear and equal
781
 */
782
static bool factoring_equal_linear_factors(bvfactoring_t *r, term_table_t *terms) {
8✔
783
  bvpoly_buffer_t *b;
784
  uint32_t i;
785

786
  b = factoring_get_poly_buffer(r);
8✔
787
  reset_bvpoly_buffer(b, r->bitsize);
8✔
788

789
  if (r->bitsize <= 64) {
8✔
790
    for (i=0; i<r->n1; i++) {
13✔
791
      bvpoly_buffer_add_factor64(b, terms, r->reduced1 + i);
7✔
792
    }
793
    for (i=0; i<r->n2; i++) {
14✔
794
      bvpoly_buffer_sub_factor64(b, terms, r->reduced2 + i);
8✔
795
    }
796
  } else {
797
    for (i=0; i<r->n1; i++) {
5✔
798
      bvpoly_buffer_add_factor(b, terms, r->reduced1 + i);
3✔
799
    }
800
    for (i=0; i<r->n2; i++) {
5✔
801
      bvpoly_buffer_sub_factor(b, terms, r->reduced2 + i);
3✔
802
    }
803
  }
804

805
  normalize_bvpoly_buffer(b);
8✔
806
  return bvpoly_buffer_is_zero(b);
8✔
807
}
808

809

810

811
/*
812
 * Prepate equality factoring: both t1 and t2 are products
813
 */
814
static void build_prod_prod_factoring(bvfactoring_t *r, term_table_t *terms, term_t t1, term_t t2) {
11✔
815
  uint32_t n;
816

817
  n = term_bitsize(terms, t1);
11✔
818
  assert(n == term_bitsize(terms, t2));
819

820
  prepare_bvfactoring(r, n, 1, 1);
11✔
821
  factoring_set_left_term(r, terms, t1);
11✔
822
  factoring_set_right_term(r, terms, t2);
11✔
823
}
11✔
824

825

826
/*
827
 * Prepare factoring: t1 + polynomial
828
 * - fails if p is too large
829
 */
830
static bool build_prod_poly64_factoring(bvfactoring_t *r, term_table_t *terms, term_t t1, bvpoly64_t *p) {
4✔
831
  uint32_t n;
832

833
  n = p->bitsize;
4✔
834
  assert(n == term_bitsize(terms, t1));
835
  if (p->nterms > 0 && p->nterms <= MAX_BVFACTORS) {
4✔
836
    prepare_bvfactoring(r, n, 1, p->nterms);
4✔
837
    factoring_set_left_term(r, terms, t1);
4✔
838
    factoring_set_right_poly64(r, terms, p);
4✔
839
    return true;
4✔
840
  }
841

842
  return false;
×
843
}
844

845
static bool build_prod_poly_factoring(bvfactoring_t *r, term_table_t *terms, term_t t1, bvpoly_t *p) {
3✔
846
  uint32_t n;
847

848
  n = p->bitsize;
3✔
849
  assert(n == term_bitsize(terms, t1));
850
  if (p->nterms > 0 && p->nterms <= MAX_BVFACTORS) {
3✔
851
    prepare_bvfactoring(r, n, 1, p->nterms);
3✔
852
    factoring_set_left_term(r, terms, t1);
3✔
853
    factoring_set_right_poly(r, terms, p);
3✔
854
    return true;
3✔
855
  }
856

857
  return false;
×
858
}
859

860
static bool try_term_poly_factoring(bvfactoring_t *r, term_table_t *terms, term_t t1, term_t t2) {
159✔
861
  switch (term_kind(terms, t2)) {
159✔
862
  case BV64_POLY:
4✔
863
    return build_prod_poly64_factoring(r, terms, t1, bvpoly64_term_desc(terms, t2));
4✔
864

865
  case BV_POLY:
3✔
866
    return build_prod_poly_factoring(r, terms, t1, bvpoly_term_desc(terms, t2));
3✔
867

868
  default:
152✔
869
    return false;
152✔
870
  }
871
}
872

873

874
/*
875
 * Reduce and store the common factors in p
876
 */
877
static void reduce_bvfactoring(bvfactoring_t *r, pp_buffer_t *p) {
21✔
878
  uint32_t i;
879

880
  pp_buffer_reset(p);
21✔
881
  bvfactor_buffer_array_common_factors(p, r->reduced1, r->n1, r->reduced2, r->n2);
21✔
882
  for (i=0; i<r->n1; i++) {
46✔
883
    bvfactor_buffer_reduce(r->reduced1 + i, p);
25✔
884
  }
885
  for (i=0; i<r->n2; i++) {
52✔
886
    bvfactor_buffer_reduce(r->reduced2 + i, p);
31✔
887
  }
888
}
21✔
889

890

891
/*
892
 * Compute the common factors of r->reduced1 and r->reduced2
893
 */
894
static void try_common_factors(bvfactoring_t *r, term_table_t *terms) {
16✔
895
  pp_buffer_t *common;
896

897
  common = factoring_get_pp_buffer(r);
16✔
898
  reduce_bvfactoring(r, common);
16✔
899
  r->code = BVFACTOR_FOUND;
16✔
900

901
#if 0
902
  printf("--- Common factors ---\n");
903
  show_product(common);
904
  printf("\n");
905
  show_bvfactoring(r);
906
  printf("\n");
907
#endif
908

909
  if (linear_reduced_factoring(r) && factoring_has_unique_exponent(r)
16✔
910
      && factoring_equal_linear_factors(r, terms)) {
6✔
911
    //    printf("Linear equal\n\n");
912
    r->code = BVFACTOR_EQUAL;
×
913
    return;
×
914
  }
915

916
  if (try_left_expansion(r, terms)) {
16✔
917
    //    printf("Left expansion\n");
918
    //    show_bvfactoring(r);
919

920
    reduce_bvfactoring(r, common);
4✔
921

922
#if 0
923
    printf("--- Common factors ---\n");
924
    show_product(common);
925
    printf("\n");
926
    show_bvfactoring(r);
927
    printf("\n");
928
#endif
929

930
    if (linear_reduced_factoring(r) && factoring_has_unique_exponent(r)
4✔
931
        && factoring_equal_linear_factors(r, terms)) {
2✔
932
      //      printf("Linear equal after left expansion\n\n");
933
      r->code = BVFACTOR_EQUAL;
2✔
934
      return;
2✔
935
    }
936
  }
937

938
  if (try_right_expansion(r, terms)) {
14✔
939
    //    printf("Right expansion\n");
940
    //    show_bvfactoring(r);
941

942
    reduce_bvfactoring(r, common);
1✔
943

944
#if 0
945
    printf("--- Common factors ---\n");
946
    show_product(common);
947
    printf("\n");
948
    show_bvfactoring(r);
949
    printf("\n");
950
#endif
951

952
    if (linear_reduced_factoring(r) && factoring_has_unique_exponent(r)
1✔
953
        && factoring_equal_linear_factors(r, terms)) {
×
954
      //      printf("Linear equal after right expansion\n\n");
955
      r->code = BVFACTOR_EQUAL;
×
956
      return;
×
957
    }
958
  }
959
}
960

961

962
#if 0
963
/*
964
 * For testing: convert the left/righ part of r to terms
965
 */
966
static void test_factor_to_terms(context_t *ctx, bvfactoring_t *r) {
967
  bvpoly_buffer_t *b;
968
  term_t left, right;
969

970
  b = factoring_get_poly_buffer(r);
971

972
  if (r->n1 > 0) {
973
    printf("Test: convert reduced1 to term\n");
974
    if (r->n1 == 1) {
975
      left = bvfactor_buffer_to_term(ctx->terms, b, r->reduced1);
976
    } else {
977
      left = bvfactor_buffer_array_to_term(ctx->terms, b, r->reduced1, r->n1);
978
    }
979
    print_term_full(stdout, ctx->terms, left);
980
    printf("\n\n");
981
  }
982

983
  if (r->n2 > 0) {
984
    printf("Test: convert reduced2 to term\n");
985
    if (r->n2 == 1) {
986
      right = bvfactor_buffer_to_term(ctx->terms, b, r->reduced2);
987
    } else {
988
      right = bvfactor_buffer_array_to_term(ctx->terms, b, r->reduced2, r->n2);
989
    }
990
    print_term_full(stdout, ctx->terms, right);
991
    printf("\n\n");
992
  }
993
}
994

995
#endif
996

997
/*
998
 * Try factoring of t1 and t2
999
 */
1000
void try_bitvector_factoring(context_t *ctx, bvfactoring_t *r, term_t t1, term_t t2) {
6,530✔
1001
  term_table_t *terms;
1002
  bool t1_is_prod, t2_is_prod;
1003

1004
  terms = ctx->terms;
6,530✔
1005
  t1_is_prod = term_is_bvprod(terms, t1);
6,530✔
1006
  t2_is_prod = term_is_bvprod(terms, t2);
6,530✔
1007

1008
  if (t1_is_prod && t2_is_prod) {
6,530✔
1009
    build_prod_prod_factoring(r, terms, t1, t2);
11✔
1010
    if (bvfactor_buffer_equal(r->reduced1, r->reduced2)) {
11✔
1011
#if 0
1012
      show_bvfactoring(r);
1013
      printf("\n");
1014
      printf("Simple equal\n\n");
1015
#endif
1016

1017
      r->code = BVFACTOR_EQUAL;
2✔
1018
      return;
2✔
1019
    }
1020
    try_common_factors(r, terms);
9✔
1021

1022
  } else if (t1_is_prod && try_term_poly_factoring(r, terms, t1, t2)) {
6,519✔
1023
    try_common_factors(r, terms);
3✔
1024

1025
  } else if (t2_is_prod && try_term_poly_factoring(r, terms, t2, t1)) {
6,516✔
1026
    try_common_factors(r, terms);
4✔
1027
  }
1028

1029
}
1030

1031

1032
/*
1033
 * Check whether t1 and t2 have the same factor decomposition
1034
 */
1035
bool equal_bitvector_factors(context_t *ctx, term_t t1, term_t t2) {
4,778✔
1036
  bvfactoring_t *factoring;
1037
  bool eq;
1038

1039
  factoring = objstack_alloc(&ctx->ostack, sizeof(bvfactoring_t),
4,778✔
1040
                             (cleaner_t) delete_bvfactoring);
1041
  init_bvfactoring(factoring);
4,778✔
1042
  try_bitvector_factoring(ctx, factoring, t1, t2);
4,778✔
1043
  eq = factoring->code == BVFACTOR_EQUAL;
4,778✔
1044
  //  delete_bvfactoring(&factoring);
1045
  objstack_pop(&ctx->ostack);
4,778✔
1046

1047
  return eq;
4,778✔
1048
}
1049

1050

1051
/*
1052
 * Convert the left/right parts of r to terms
1053
 * - r must contain a valid factoring
1054
 */
1055
static term_t reduced_array_to_term(term_table_t *terms, bvfactoring_t *r, bvfactor_buffer_t *f, uint32_t n) {
18✔
1056
  bvpoly_buffer_t *aux;
1057

1058
  aux = factoring_get_poly_buffer(r);
18✔
1059
  if (n == 1) {
18✔
1060
    return bvfactor_buffer_to_term(terms, aux, f);
12✔
1061
  } else {
1062
    return bvfactor_buffer_array_to_term(terms, aux, f, n);
6✔
1063
  }
1064
}
1065

1066
term_t bitvector_factoring_left_term(context_t *ctx, bvfactoring_t *r) {
9✔
1067
  assert(r->code == BVFACTOR_FOUND);
1068
  assert(r->n1 > 0);
1069
  return reduced_array_to_term(ctx->terms, r, r->reduced1, r->n1);
9✔
1070
}
1071

1072
term_t bitvector_factoring_right_term(context_t *ctx, bvfactoring_t *r) {
9✔
1073
  assert(r->code == BVFACTOR_FOUND);
1074
  assert(r->n2 > 0);
1075
  return reduced_array_to_term(ctx->terms, r, r->reduced2, r->n2);
9✔
1076
}
1077

1078

1079

1080

1081

1082
/**************************
1083
 *  VARIABLE ELIMINATION  *
1084
 *************************/
1085

1086
/*
1087
 * If variable elimination is enabled, some top-level equalities (eq x
1088
 * <term>) are converted into substitutions [x := term] and variable x
1089
 * is eliminated. This is done in three phases:
1090
 *
1091
 * 1) Cheap substitutions (X := constant or X := variable) are performed first.
1092
 *    Other possible substitutions (X := <term>) are stored into vector subst_eqs.
1093
 *
1094
 * 2) After flattening, the terms in subst_eqs are scanned and converted to
1095
 *    potential substitutions [X --> <term>] whenever possible. Terms in subst_eqs
1096
 *    that are no longer possible substitutions are copied into top_eqs.
1097
 *
1098
 * 3) Substitution cycles are removed. Every substitution that does not cause
1099
 *    a cycle is stored in intern_table.
1100
 *
1101
 * NOTE: it's too expensive to check for cycles in every candidate substitution
1102
 * (i.e., we can't call intern_tbl_valid_subst in phase 1).
1103
 */
1104

1105

1106
/*
1107
 * VARIABLE ELIMINATION: PHASE 1
1108
 */
1109

1110
/*
1111
 * Process a candidate substitution [t1 := t2]
1112
 * - e is a term equivalent to (eq t1 t2) and e has been asserted true
1113
 * - both t1 and t2 are roots in the internalization table
1114
 * - t1 is free and t2 is not
1115
 * - if t2 is constant, perform the substitution now
1116
 * - otherwise store e into subst_eqs for Phase 2 processing
1117
 */
1118
static void process_candidate_subst(context_t *ctx, term_t t1, term_t t2, term_t e) {
6,671✔
1119
  intern_tbl_t *intern;
1120

1121
  assert(term_is_true(ctx, e));
1122

1123
  intern = &ctx->intern;
6,671✔
1124
  if (is_constant_term(ctx->terms, t2)) {
6,671✔
1125
    if (intern_tbl_valid_const_subst(intern, t1, t2)) {
1,104✔
1126
#if TRACE_SUBST
1127
      printf("Eager substitution: ");
1128
      print_term_desc(stdout, ctx->terms, t1);
1129
      printf(" := ");;
1130
      print_term_desc(stdout, ctx->terms, 2);
1131
      printf("\n");
1132
      fflush(stdout);
1133
#endif
1134
      intern_tbl_add_subst(intern, t1, t2);
1,104✔
1135
    } else {
1136
      // unsat by type incompatibility
1137
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1138
    }
1139
  } else if (intern_tbl_sound_subst(intern, t1, t2)) {
5,567✔
1140
    ivector_push(&ctx->subst_eqs, e);
5,564✔
1141
  } else {
1142
    // can't substitute
1143
    ivector_push(&ctx->top_eqs, e);
3✔
1144
  }
1145
}
6,671✔
1146

1147

1148
/*
1149
 * Attempt to turn (eq t1 t2) into a variable substitution
1150
 * - both t1 and t2 are root terms in the internalization table
1151
 *   (and t1 and t2 are not boolean so they have positive polarity)
1152
 * - e is a term equivalent to (eq t1 t2)
1153
 * - if both t1 and t2 are free merge their classes in the internalization table
1154
 * - if one is free and the other is a constant perform the substitution now
1155
 * - if one is free and the other is not a constant store e in subst_eqs for Phase 2
1156
 * - otherwise, add e to the top_eqs
1157
 */
1158
static void try_substitution(context_t *ctx, term_t t1, term_t t2, term_t e) {
16,603✔
1159
  intern_tbl_t *intern;
1160
  bool free1, free2;
1161

1162
  assert(is_pos_term(t1) && is_pos_term(t2) && term_is_true(ctx, e));
1163

1164
  /*
1165
   * In supplementary-MCSAT mode, keep equalities explicit so they can be
1166
   * routed to the MCSAT satellite as tracked atoms/constraints.
1167
   */
1168
  if (ctx->mcsat_supplement_active) {
16,603✔
1169
    ivector_push(&ctx->top_eqs, e);
7✔
1170
    return;
7✔
1171
  }
1172

1173
  if (context_var_elim_enabled(ctx)) {
16,596✔
1174
    intern = &ctx->intern;
11,762✔
1175

1176
    free1 = intern_tbl_root_is_free(intern, t1);
11,762✔
1177
    free2 = intern_tbl_root_is_free(intern, t2);
11,762✔
1178

1179
    if (free1 && free2) {
11,762✔
1180
      intern_tbl_merge_classes(intern, t1, t2);
536✔
1181
      return;
536✔
1182
    }
1183

1184
    if (free1) {
11,226✔
1185
      process_candidate_subst(ctx, t1, t2, e);
5,730✔
1186
      return;
5,730✔
1187
    }
1188

1189
    if (free2) {
5,496✔
1190
      process_candidate_subst(ctx, t2, t1, e);
941✔
1191
      return;
941✔
1192
    }
1193
  }
1194

1195
  // no substitution: record e as a top-equality
1196
  ivector_push(&ctx->top_eqs, e);
9,389✔
1197
}
1198

1199

1200
/*
1201
 * Attempt to turn (eq t1 t2) into a variable substitution
1202
 * - both t1 and t2 are boolean root terms in the internalization table
1203
 * - e is a term equivalent to (eq t1 t2)
1204
 * - neither t1 nor t2 are constant
1205
 */
1206
static void try_bool_substitution(context_t *ctx, term_t t1, term_t t2, term_t e) {
3,613✔
1207
  intern_tbl_t *intern;
1208
  bool free1, free2;
1209

1210
  assert(term_is_true(ctx, e));
1211

1212
  /*
1213
   * In supplementary-MCSAT mode, keep boolean equalities explicit.
1214
   */
1215
  if (ctx->mcsat_supplement_active) {
3,613✔
NEW
1216
    ivector_push(&ctx->top_formulas, e);
×
NEW
1217
    return;
×
1218
  }
1219

1220
  if (context_var_elim_enabled(ctx)) {
3,613✔
1221
    intern = &ctx->intern;
1,759✔
1222

1223
    free1 = intern_tbl_root_is_free(intern, t1);
1,759✔
1224
    free2 = intern_tbl_root_is_free(intern, t2);
1,759✔
1225

1226
    if (free1 && free2) {
1,759✔
1227
      /*
1228
       * Both t1 and t2 are free
1229
       */
1230
      intern_tbl_merge_classes(intern, t1, t2);
39✔
1231
      return;
39✔
1232
    }
1233

1234
    if (free1 || free2) {
1,720✔
1235
      /*
1236
       * Only one is free: save e in subst_eqs for future processing
1237
       */
1238
      ivector_push(&ctx->subst_eqs, e);
842✔
1239
      return;
842✔
1240
    }
1241
  }
1242

1243
  // no substitution
1244
  //  ivector_push(&ctx->top_eqs, e);
1245
  ivector_push(&ctx->top_formulas, e);
2,732✔
1246
}
1247

1248

1249

1250
/*
1251
 * VARIABLE ELIMINATION: PHASE 2
1252
 */
1253

1254
/*
1255
 * Check whether x is already mapped in the candidate substitution
1256
 * - if not, store [x := t] as a candidate
1257
 * - otherwise, add e to the top_eqs vector
1258
 */
1259
static void try_pseudo_subst(context_t *ctx, pseudo_subst_t *subst, term_t x, term_t t, term_t e) {
6,374✔
1260
  subst_triple_t *s;
1261

1262
  assert(is_pos_term(x) && intern_tbl_root_is_free(&ctx->intern, x) && term_is_true(ctx, e));
1263

1264
  s = pseudo_subst_get(subst, x);
6,374✔
1265
  assert(s->var == x);
1266
  if (s->map == NULL_TERM) {
6,374✔
1267
    // x := t is a candidate
1268
    assert(s->eq == NULL_TERM);
1269
    s->map = t;
6,082✔
1270
    s->eq = e;
6,082✔
1271

1272
#if TRACE_SUBST
1273
    printf("Add subst candidate ");
1274
    print_term_desc(stdout, ctx->terms, x);
1275
    printf(" := ");;
1276
    print_term_desc(stdout, ctx->terms, t);
1277
    printf(" by assertion ");
1278
    print_term_desc(stdout, ctx->terms, e);
1279
    printf("\n");
1280
    fflush(stdout);
1281
#endif
1282

1283
  } else {
1284
    ivector_push(&ctx->top_eqs, e);
292✔
1285
  }
1286
}
6,374✔
1287

1288
/*
1289
 * Check whether (eq t1 t2) can still be turned into a substitution (X := term)
1290
 * - if so add the candidate substitution [X --> term] to subst
1291
 * - otherwise, move e to the top-level equalities
1292
 * - both t1 and t2 are root terms in the internalization table
1293
 * - e is equivalent to (eq t1 t2))
1294
 * - t1 and t2 are not boolean terms
1295
 */
1296
static void check_candidate_subst(context_t *ctx, pseudo_subst_t *subst, term_t t1, term_t t2, term_t e) {
5,564✔
1297
  assert(is_pos_term(t1) && is_pos_term(t2) && term_is_true(ctx, e));
1298

1299
  if (intern_tbl_root_is_free(&ctx->intern, t1)) {
5,564✔
1300
    try_pseudo_subst(ctx, subst, t1, t2, e);
4,619✔
1301
  } else if (intern_tbl_root_is_free(&ctx->intern, t2)) {
945✔
1302
    try_pseudo_subst(ctx, subst, t2, t1, e);
923✔
1303
  } else {
1304
    ivector_push(&ctx->top_eqs, e);
22✔
1305
  }
1306
}
5,564✔
1307

1308

1309

1310
/*
1311
 * Same thing for an equality between booleans terms
1312
 */
1313
static void check_candidate_bool_subst(context_t *ctx, pseudo_subst_t *subst, term_t t1, term_t t2, term_t e) {
842✔
1314
  assert(is_boolean_term(ctx->terms, t1) && is_boolean_term(ctx->terms, t2) && term_is_true(ctx, e));
1315

1316
  if (intern_tbl_root_is_free(&ctx->intern, t1)) {
842✔
1317
    // if t1 is (not u1), rewrite to (u1 == not t2)
1318
    t2 ^= polarity_of(t1);
825✔
1319
    t1 = unsigned_term(t1);
825✔
1320
    try_pseudo_subst(ctx, subst, t1, t2, e);
825✔
1321
  } else if (intern_tbl_root_is_free(&ctx->intern, t2)) {
17✔
1322
    // fix polarities too
1323
    t1 ^= polarity_of(t2);
7✔
1324
    t2 = unsigned_term(t2);
7✔
1325
    try_pseudo_subst(ctx, subst, t2, t1, e);
7✔
1326
  } else {
1327
    ivector_push(&ctx->top_eqs, e);
10✔
1328
  }
1329
}
842✔
1330

1331

1332
/*
1333
 * Process all elements in subst_eqs:
1334
 * - turn them into substitution candidates or move them to top_eqs
1335
 */
1336
static void process_subst_eqs(context_t *ctx, pseudo_subst_t *subst) {
2,804✔
1337
  term_table_t *terms;
1338
  ivector_t *subst_eqs;
1339
  composite_term_t *eq;
1340
  term_t e, t1, t2;
1341
  uint32_t i, n;
1342

1343
  terms = ctx->terms;
2,804✔
1344
  subst_eqs = &ctx->subst_eqs;
2,804✔
1345

1346
  n = subst_eqs->size;
2,804✔
1347
  for (i=0; i<n; i++) {
9,210✔
1348
    e = subst_eqs->data[i];
6,406✔
1349
    assert(term_is_true(ctx, e));
1350

1351
    switch (term_kind(terms, e)) {
6,406✔
1352
    case EQ_TERM:
6,406✔
1353
    case ARITH_BINEQ_ATOM:
1354
    case BV_EQ_ATOM:
1355
      eq = composite_term_desc(terms, e);
6,406✔
1356
      assert(eq->arity == 2);
1357
      t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
6,406✔
1358
      t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
6,406✔
1359

1360
      if (is_boolean_term(terms, t1)) {
6,406✔
1361
        /*
1362
         * e was asserted true
1363
         * it's either (eq t1 t2) or (not (eq t1 t2))
1364
         * in the latter case, we use the equivalence
1365
         *  (not (eq t1 t2)) <--> (eq t1 (not t2))
1366
         * i.e., we flip t2's polarity if e has negative polarity
1367
         */
1368
        t2 ^= polarity_of(e);
842✔
1369
        check_candidate_bool_subst(ctx, subst, t1, t2, e);
842✔
1370
      } else {
1371
        /*
1372
         * e is (eq t1 t2) for two non-boolean terms t1 and t2
1373
         */
1374
        assert(is_pos_term(e));
1375
        check_candidate_subst(ctx, subst, t1, t2, e);
5,564✔
1376
      }
1377
      break;
6,406✔
1378

1379
    default:
×
1380
      assert(false);
1381
      break;
×
1382
    }
1383
  }
1384
}
2,804✔
1385

1386

1387
/*
1388
 * VARIABLE ELIMINATION PHASE 3: CYCLE REMOVAL
1389
 */
1390

1391
/*
1392
 * We use a depth-first search in the dependency graph:
1393
 * - vertices are terms,
1394
 * - edges are of two forms:
1395
 *    t --> u if u is a child subterm of t
1396
 *    x := t  if x is a variable and t is the substitution candidate for x
1397
 *
1398
 * By construction, the graph restricted to edges t --> u (without the
1399
 * substitution edges) is a DAG. So we can remove cycles by removing some
1400
 * substitution edges x := t.
1401
 */
1402

1403
/*
1404
 * Substitution candidate for term t:
1405
 * - return NULL_TERM if there's no candidate
1406
 */
1407
static term_t subst_candidate(context_t *ctx, term_t t) {
15,379✔
1408
  subst_triple_t *s;
1409

1410
  assert(ctx->subst != NULL);
1411
  s = pseudo_subst_find(ctx->subst, t);
15,379✔
1412
  if (s == NULL) {
15,379✔
1413
    return NULL_TERM;
9,297✔
1414
  } else {
1415
    assert(s->var == t);
1416
    return s->map;
6,082✔
1417
  }
1418
}
1419

1420

1421
/*
1422
 * Remove substitution candidate for t
1423
 */
1424
static void remove_subst_candidate(context_t *ctx, term_t t) {
206✔
1425
  subst_triple_t *s;
1426

1427
  assert(ctx->subst != NULL);
1428
  s = pseudo_subst_find(ctx->subst, t);
206✔
1429
  assert(s != NULL && s->var == t && s->map != NULL_TERM);
1430

1431
#if TRACE_SUBST
1432
  printf("Removing subst candidate ");
1433
  print_term_desc(stdout, ctx->terms, t);
1434
  printf(" := ");;
1435
  print_term_desc(stdout, ctx->terms, s->map);
1436
  printf("\n");
1437
  fflush(stdout);
1438
#endif
1439

1440
  s->map = NULL_TERM;
206✔
1441
}
206✔
1442

1443

1444
/*
1445
 * Visit t: return true if t is on a cycle.
1446
 */
1447
static bool visit(context_t *ctx, term_t t);
1448

1449
static bool visit_composite(context_t *ctx, composite_term_t *c) {
34,889✔
1450
  uint32_t i, n;
1451

1452
  n = c->arity;
34,889✔
1453
  for (i=0; i<n; i++) {
726,324✔
1454
    if (visit(ctx, c->arg[i])) {
691,663✔
1455
      return true;
228✔
1456
    }
1457
  }
1458

1459
  return false;
34,661✔
1460
}
1461

1462
static bool visit_pprod(context_t *ctx, pprod_t *p) {
13✔
1463
  uint32_t i, n;
1464

1465
  n = p->len;
13✔
1466
  for (i=0; i<n; i++) {
33✔
1467
    if (visit(ctx, p->prod[i].var)) {
23✔
1468
      return true;
3✔
1469
    }
1470
  }
1471

1472
  return false;
10✔
1473
}
1474

1475
static bool visit_arith_poly(context_t *ctx, polynomial_t *p) {
783✔
1476
  monomial_t *m;
1477
  uint32_t i, n;
1478

1479
  m = p->mono;
783✔
1480
  n = p->nterms;
783✔
1481
  assert(n > 0);
1482
  // skip constant marker
1483
  if (m[0].var == const_idx) {
783✔
1484
    m++;
459✔
1485
    n--;
459✔
1486
  }
1487

1488
  for (i=0; i<n; i++) {
2,448✔
1489
    if (visit(ctx, m[i].var)) {
1,665✔
1490
      return true;
×
1491
    }
1492
  }
1493

1494
  return false;
783✔
1495
}
1496

1497
static bool visit_bv_poly(context_t *ctx, bvpoly_t *p) {
25✔
1498
  bvmono_t *m;
1499
  uint32_t i, n;
1500

1501
  m = p->mono;
25✔
1502
  n = p->nterms;
25✔
1503
  assert(n > 0);
1504
  // skip constant marker
1505
  if (m[0].var == const_idx) {
25✔
1506
    m++;
5✔
1507
    n--;
5✔
1508
  }
1509

1510
  for (i=0; i<n; i++) {
63✔
1511
    if (visit(ctx, m[i].var)) {
39✔
1512
      return true;
1✔
1513
    }
1514
  }
1515

1516
  return false;
24✔
1517
}
1518

1519

1520
static bool visit_bv64_poly(context_t *ctx, bvpoly64_t *p) {
239✔
1521
  bvmono64_t *m;
1522
  uint32_t i, n;
1523

1524
  m = p->mono;
239✔
1525
  n = p->nterms;
239✔
1526
  assert(n > 0);
1527
  // skip constant marker
1528
  if (m[0].var == const_idx) {
239✔
1529
    m++;
170✔
1530
    n--;
170✔
1531
  }
1532

1533
  for (i=0; i<n; i++) {
527✔
1534
    if (visit(ctx, m[i].var)) {
291✔
1535
      return true;
3✔
1536
    }
1537
  }
1538

1539
  return false;
236✔
1540
}
1541

1542

1543
static bool visit(context_t *ctx, term_t t) {
1,178,625✔
1544
  term_table_t *terms;
1545
  term_t r;
1546
  int32_t i;
1547
  bool result;
1548
  uint8_t color;
1549

1550
  assert(ctx->marks != NULL);
1551
  i = index_of(t);
1,178,625✔
1552
  color = mark_vector_get_mark(ctx->marks, i);
1,178,625✔
1553

1554
  if (color == WHITE) {
1,178,625✔
1555
    /*
1556
     * i not visited yet
1557
     */
1558
    terms = ctx->terms;
535,340✔
1559
    mark_vector_add_mark(ctx->marks, i, GREY);
535,340✔
1560

1561
    switch (kind_for_idx(terms, i)) {
535,340✔
1562
    case CONSTANT_TERM:
9,712✔
1563
    case ARITH_CONSTANT:
1564
    case BV64_CONSTANT:
1565
    case BV_CONSTANT:
1566
    case VARIABLE:
1567
      result = false;
9,712✔
1568
      break;
9,712✔
1569

1570
    case UNINTERPRETED_TERM:
23,543✔
1571
      r = intern_tbl_get_root(&ctx->intern, t);
23,543✔
1572
      if (r != t) {
23,543✔
1573
        result = visit(ctx, r);
8,164✔
1574
      } else {
1575
        r = subst_candidate(ctx, pos_term(i));
15,379✔
1576
        if (r != NULL_TERM && visit(ctx, r)) {
15,379✔
1577
          /*
1578
           * There's a cycle u --> ... --> t := r --> ... --> u
1579
           * remove the substitution t := r to break the cycle
1580
           */
1581
          remove_subst_candidate(ctx, pos_term(i));
206✔
1582
        }
1583
        result = false;
15,379✔
1584
      }
1585
      break;
23,543✔
1586

1587
    case ARITH_EQ_ATOM:
727✔
1588
    case ARITH_GE_ATOM:
1589
    case ARITH_IS_INT_ATOM:
1590
    case ARITH_FLOOR:
1591
    case ARITH_CEIL:
1592
    case ARITH_ABS:
1593
      result = visit(ctx, integer_value_for_idx(terms, i));
727✔
1594
      break;
727✔
1595

1596
    case ITE_TERM:
34,889✔
1597
    case ITE_SPECIAL:
1598
    case APP_TERM:
1599
    case UPDATE_TERM:
1600
    case TUPLE_TERM:
1601
    case EQ_TERM:
1602
    case DISTINCT_TERM:
1603
    case FORALL_TERM:
1604
    case LAMBDA_TERM:
1605
    case OR_TERM:
1606
    case XOR_TERM:
1607
    case ARITH_BINEQ_ATOM:
1608
    case ARITH_RDIV:
1609
    case ARITH_IDIV:
1610
    case ARITH_MOD:
1611
    case ARITH_DIVIDES_ATOM:
1612
    case BV_ARRAY:
1613
    case BV_DIV:
1614
    case BV_REM:
1615
    case BV_SDIV:
1616
    case BV_SREM:
1617
    case BV_SMOD:
1618
    case BV_SHL:
1619
    case BV_LSHR:
1620
    case BV_ASHR:
1621
    case BV_EQ_ATOM:
1622
    case BV_GE_ATOM:
1623
    case BV_SGE_ATOM:
1624
      result = visit_composite(ctx, composite_for_idx(terms, i));
34,889✔
1625
      break;
34,889✔
1626

1627
    case SELECT_TERM:
465,409✔
1628
    case BIT_TERM:
1629
      result = visit(ctx, select_for_idx(terms, i)->arg);
465,409✔
1630
      break;
465,409✔
1631

1632
    case POWER_PRODUCT:
13✔
1633
      result = visit_pprod(ctx, pprod_for_idx(terms, i));
13✔
1634
      break;
13✔
1635

1636
    case ARITH_POLY:
783✔
1637
      result = visit_arith_poly(ctx, polynomial_for_idx(terms, i));
783✔
1638
      break;
783✔
1639

1640
    case BV64_POLY:
239✔
1641
      result = visit_bv64_poly(ctx, bvpoly64_for_idx(terms, i));
239✔
1642
      break;
239✔
1643

1644
    case BV_POLY:
25✔
1645
      result = visit_bv_poly(ctx, bvpoly_for_idx(terms, i));
25✔
1646
      break;
25✔
1647

1648
    case UNUSED_TERM:
×
1649
    case RESERVED_TERM:
1650
    default:
1651
      assert(false);
1652
      longjmp(ctx->env, INTERNAL_ERROR);
×
1653
      break;
1654
    }
1655

1656
    if (result) {
535,340✔
1657
      /*
1658
       * t is on a cycle of grey terms:
1659
       *  v --> .. x := u --> ... --> t --> ... --> v
1660
       * all terms on the cycle must be cleared except v
1661
       */
1662
      mark_vector_add_mark(ctx->marks, i, WHITE);
242✔
1663
    } else {
1664
      // no cycle containing t: mark i black
1665
      mark_vector_add_mark(ctx->marks, i, BLACK);
535,098✔
1666
    }
1667

1668
  } else {
1669
    /*
1670
     * i already visited before
1671
     * - if it's black there's no cycle
1672
     * - if it's grey, we've just detected a cycle
1673
     */
1674
    assert(color == GREY || color == BLACK);
1675
    result = (color == GREY);
643,285✔
1676
  }
1677

1678
  return result;
1,178,625✔
1679
}
1680

1681

1682
/*
1683
 * Iterator for remove cycle:
1684
 * - s is a triple [x, t, e] for a candidate substitution x := t
1685
 */
1686
static void visit_subst_candidate(context_t *ctx, subst_triple_t *s) {
6,082✔
1687
  term_t x;
1688

1689
  x = s->var;
6,082✔
1690
  assert(intern_tbl_is_root(&ctx->intern, x) && intern_tbl_root_is_free(&ctx->intern, x));
1691
  if (mark_vector_get_mark(ctx->marks, index_of(x)) == WHITE) {
6,082✔
1692
    (void) visit(ctx, x);
4,562✔
1693
  }
1694
}
6,082✔
1695

1696

1697
/*
1698
 * Remove cycles in the candidate substitutions
1699
 */
1700
static void remove_subst_cycles(context_t *ctx) {
2,804✔
1701
  pseudo_subst_iterate(ctx->subst, ctx, (pseudo_subst_iterator_t) visit_subst_candidate);
2,804✔
1702
}
2,804✔
1703

1704

1705
/*
1706
 * Iterator for finalize subst:
1707
 * - s is a triple [x, t, e]
1708
 * - if t is NULL_TERM, that's no longer a good substitution: add e to top_eqs
1709
 * - otherwise add x := t as a substitution in the internalization table
1710
 */
1711
static void finalize_subst_triple(context_t *ctx, subst_triple_t *s) {
6,082✔
1712
  assert(s->eq != NULL_TERM && term_is_true(ctx, s->eq));
1713

1714
  if (s->map != NULL_TERM) {
6,082✔
1715
    intern_tbl_add_subst(&ctx->intern, s->var, s->map);
5,876✔
1716
  } else {
1717
    ivector_push(&ctx->top_eqs, s->eq);
206✔
1718
  }
1719
}
6,082✔
1720

1721

1722
/*
1723
 * Finalize all candidate substitutions
1724
 */
1725
static void finalize_subst_candidates(context_t *ctx) {
2,804✔
1726
  pseudo_subst_iterate(ctx->subst, ctx, (pseudo_subst_iterator_t) finalize_subst_triple);
2,804✔
1727
}
2,804✔
1728

1729

1730

1731

1732

1733

1734

1735
/***************************
1736
 *  ASSERTION FLATTENING   *
1737
 **************************/
1738

1739
/*
1740
 * Assertions are processed by performing top-down boolean propagation
1741
 * and collecting all subterms that can't be flattened into four vectors:
1742
 *
1743
 * 1) ctx->top_eqs = top-level equalities.
1744
 *    Every t in top_eqs is (eq t1 t2) (or a variant) asserted true.
1745
 *    t is mapped to true in the internalization table.
1746
 *
1747
 * 2) ctx->top_atoms = top-level atoms.
1748
 *    Every t in top_atoms is an atom or the negation of an atom (that
1749
 *    can't go into top_eqs).
1750
 *    t is mapped to true in the internalization table.
1751
 *
1752
 * 3) ctx->top_formulas = non-atomic terms.
1753
 *    Every t in top_formulas is either an (OR ...) or (ITE ...) or (XOR ...) or (IFF ..)
1754
 *    or the negation of such a term.
1755
 *    t is mapped to true in the internalization table.
1756
 *
1757
 * 4) ctx->top_interns = already internalized terms.
1758
 *    Every t in top_interns is a term that's been internalized before
1759
 *    and is mapped to a literal l or an egraph occurrence g in
1760
 *    the internalization table.
1761
 *    l or g must be asserted true in later stages.
1762
 *
1763
 * Flattening is done breadth-first:
1764
 * - the subterms to process are stored into ctx->queue.
1765
 * - each subterm in that queue is a boolean term that's asserted true
1766
 */
1767

1768

1769
/*
1770
 * Each function below processes an assertion of the form (r == tt)
1771
 * where r is a boolean term (with positive polarity) and tt is either
1772
 * true or false. The term r is a root in the internalization table
1773
 * and r is not internalized yet.
1774
 *
1775
 * Processing:
1776
 * - try to simplify (r == tt) to a boolean term q. If that works
1777
 *   add q to the internal queue.
1778
 * - check for boolean propagation from (r == tt) to r's children.
1779
 *   Example: (or t_1 ... t_n) == false ---> (t_1 == false), etc.
1780
 * - if (r == tt) can be rewritten to an equality (t1 == t2), check
1781
 *   whether we can eliminate t1 or t2 by substitution.
1782
 * - otherwise, add r or (not r) to one of top_eqs, top_atoms, or top_formulas.
1783
 */
1784

1785
/*
1786
 * Atoms, except equalities
1787
 */
1788
// r is (p t_1 ... t_n)
1789
static void flatten_bool_app(context_t *ctx, term_t r, bool tt) {
252✔
1790
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
252✔
1791
}
252✔
1792

1793
// r is (distinct t1 .... t_n)
1794
static void flatten_distinct(context_t *ctx, term_t r, bool tt) {
172✔
1795
  if (tt) {
172✔
1796
    ivector_push(&ctx->top_atoms, r);
163✔
1797
  } else {
1798
    // not (distinct ...) expands to an or
1799
    ivector_push(&ctx->top_formulas, not(r));
9✔
1800
  }
1801
}
172✔
1802

1803
// r is (select i t) for a tuple t
1804
static void flatten_select(context_t *ctx, term_t r, bool tt) {
×
1805
  term_t t;
1806

1807
  t = simplify_select(ctx, r);
×
1808
  if (t != NULL_TERM) {
×
1809
    int_queue_push(&ctx->queue, signed_term(t, tt));
×
1810
  } else {
1811
    ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
1812
  }
1813
}
×
1814

1815
// r is (bit i t) for a bitvector term t
1816
static void flatten_bit_select(context_t *ctx, term_t r, bool tt) {
32,140✔
1817
  term_t t;
1818

1819
  t = simplify_bit_select(ctx, r);
32,140✔
1820
  if (t != NULL_TERM) {
32,140✔
1821
    int_queue_push(&ctx->queue, signed_term(t, tt));
198✔
1822
  } else {
1823
    ivector_push(&ctx->top_atoms, signed_term(r, tt));
31,942✔
1824
  }
1825
}
32,140✔
1826

1827
// r is (t >= 0) for an arithmetic term t
1828
static void flatten_arith_geq0(context_t *ctx, term_t r, bool tt) {
27,815✔
1829
  term_t t;
1830

1831
  t = simplify_arith_geq0(ctx, r);
27,815✔
1832
  if (t != NULL_TERM) {
27,815✔
1833
    int_queue_push(&ctx->queue, signed_term(t, tt));
1✔
1834
  } else {
1835
    ivector_push(&ctx->top_atoms, signed_term(r, tt));
27,814✔
1836
  }
1837
}
27,815✔
1838

1839
// r is (is-int t)
1840
static void flatten_arith_is_int(context_t *ctx, term_t r, bool tt) {
×
1841
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
1842
}
×
1843

1844
// r is (divides t1 t2)
1845
static void flatten_arith_divides(context_t *ctx, term_t r, bool tt) {
×
1846
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
1847
}
×
1848

1849
// r is (bvge t1 t2) for two bitvector terms t1 and t2
1850
static void flatten_bvge(context_t *ctx, term_t r, bool tt) {
1,478✔
1851
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
1,478✔
1852
}
1,478✔
1853

1854
// r is (bvsge t1 t2) for two bitvector terms t1 and t2
1855
static void flatten_bvsge(context_t *ctx, term_t r, bool tt) {
455✔
1856
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
455✔
1857
}
455✔
1858

1859

1860
/*
1861
 * Equalities
1862
 */
1863
// r is (t == 0) for an arithmetic term t
1864
static void flatten_arith_eq0(context_t *ctx, term_t r, bool tt) {
2,271✔
1865
  term_t t;
1866

1867
  t = simplify_arith_eq0(ctx, r);
2,271✔
1868
  if (t != NULL_TERM) {
2,271✔
1869
    int_queue_push(&ctx->queue, signed_term(t, tt));
1✔
1870
  } else if (tt) {
2,270✔
1871
    ivector_push(&ctx->top_eqs, r);
960✔
1872
  } else {
1873
    ivector_push(&ctx->top_atoms, opposite_term(r));
1,310✔
1874
  }
1875
}
2,271✔
1876

1877
// r is (t1 == t2) for two arithmetic terms t1 and t2
1878
static void flatten_arith_eq(context_t *ctx, term_t r, bool tt) {
4,567✔
1879
  composite_term_t *eq;
1880
  term_t t1, t2, t;
1881

1882
  eq = arith_bineq_atom_desc(ctx->terms, r);
4,567✔
1883
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
4,567✔
1884
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
4,567✔
1885

1886
  if (t1 == t2) {
4,567✔
1887
    if (!tt) {
5✔
1888
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1889
    }
1890
    return; // redundant
5✔
1891
  }
1892

1893
  t = simplify_arith_bineq(ctx, t1, t2);
4,562✔
1894
  if (t != NULL_TERM) {
4,562✔
1895
    int_queue_push(&ctx->queue, signed_term(t, tt));
2✔
1896
  } else if (tt) {
4,560✔
1897
    try_substitution(ctx, t1, t2, r);
2,342✔
1898
  } else {
1899
    ivector_push(&ctx->top_atoms, opposite_term(r));
2,218✔
1900
  }
1901
}
1902

1903
// r is (eq t1 t2): t1 and t2 are either boolean or tuples or uninterpreted
1904
static void flatten_eq(context_t *ctx, term_t r, bool tt) {
6,315✔
1905
  term_table_t *terms;
1906
  composite_term_t *eq;
1907
  term_t t1, t2, t;
1908

1909
  terms = ctx->terms;
6,315✔
1910
  eq = eq_term_desc(terms, r);
6,315✔
1911
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
6,315✔
1912
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
6,315✔
1913

1914
  if (is_boolean_term(terms, t1)) {
6,315✔
1915
    /*
1916
     * Boolean equality
1917
     */
1918
    assert(is_boolean_term(terms, t2));
1919

1920
    t = simplify_bool_eq(ctx, t1, t2);
3,782✔
1921
    if (t != NULL_TERM) {
3,782✔
1922
      int_queue_push(&ctx->queue, signed_term(t, tt));
169✔
1923
    } else {
1924
      // not (eq t1 t2) --> (eq t1 (not t2))
1925
      if (! tt) {
3,613✔
1926
        r = opposite_term(r);
77✔
1927
        t2 = opposite_term(t2);
77✔
1928
      }
1929

1930
      if (index_of(t1) == index_of(t2)) {
3,613✔
1931
        // either (eq t1 t1) or (eq t1 (not t1))
1932
        if (t1 == t2) return;
×
1933
        assert(opposite_bool_terms(t1, t2));
1934
        longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1935
      }
1936

1937
      try_bool_substitution(ctx, t1, t2, r);
3,613✔
1938
    }
1939

1940
  } else {
1941
    /*
1942
     * Non-boolean
1943
     */
1944
    if (t1 == t2) {
2,533✔
1945
      if (! tt) {
×
1946
        longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1947
      }
1948
      return;
×
1949
    }
1950

1951
    if (tt) {
2,533✔
1952
      try_substitution(ctx, t1, t2, r);
1,467✔
1953
    } else {
1954
      ivector_push(&ctx->top_atoms, opposite_term(r));
1,066✔
1955
    }
1956
  }
1957
}
1958

1959
// r is (bveq t1 t2) for two bitvector terms t1 and t2
1960
static void flatten_bveq(context_t *ctx, term_t r, bool tt) {
19,895✔
1961
  term_table_t *terms;
1962
  composite_term_t *eq;
1963
  ivector_t *v;
1964
  term_t t1, t2, t;
1965

1966
  terms = ctx->terms;
19,895✔
1967
  eq = bveq_atom_desc(terms, r);
19,895✔
1968
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
19,895✔
1969
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
19,895✔
1970

1971
  /*
1972
   * First check whether (eq t1 t2) is equivalent to
1973
   * a Boolean term t
1974
   */
1975
  t = simplify_bitvector_eq(ctx, t1, t2);
19,895✔
1976
  if (t != NULL_TERM) {
19,895✔
1977
    t = signed_term(t, tt);
66✔
1978
    if (t == false_term) {
66✔
1979
      longjmp(ctx->env, TRIVIALLY_UNSAT);
1✔
1980
    } else if (t != true_term) {
65✔
1981
      int_queue_push(&ctx->queue, t);
53✔
1982
    }
1983

1984
  } else if (tt) {
19,829✔
1985
    /*
1986
     * try to flatten into a conjunction of terms
1987
     */
1988
    v = &ctx->aux_vector;
18,037✔
1989
    assert(v->size == 0);
1990
    if (bveq_flattens(ctx->terms, t1, t2, v)) {
18,037✔
1991
      /*
1992
       * (bveq t1 t2) is equivalent to (and v[0] ... v[k-1])
1993
       * (bveq t1 t2) is asserted true
1994
       */
1995
      int_queue_push_array(&ctx->queue, v->data, v->size);
5,298✔
1996
    } else {
1997
      /*
1998
       * Did not flatten
1999
       */
2000
      try_substitution(ctx, t1, t2, r);
12,739✔
2001
    }
2002

2003
    ivector_reset(v);
18,037✔
2004

2005
  } else {
2006
    ivector_push(&ctx->top_atoms, opposite_term(r));
1,792✔
2007
  }
2008
}
19,894✔
2009

2010

2011
#if 0
2012
/*
2013
 * Display the results of factoring r
2014
 */
2015
static void show_common_factors(context_t *ctx, term_t r, ivector_t *v) {
2016
  yices_pp_t printer;
2017
  uint32_t i, n;
2018

2019
  n = v->size;
2020
  if (n > 0) {
2021
    printf("--- common factors of r = %"PRId32" ---\n", r);
2022
    init_yices_pp(&printer, stdout, NULL, PP_VMODE, 0);
2023
    pp_term_full(&printer, ctx->terms, r);
2024
    flush_yices_pp(&printer);
2025

2026
    for (i=0; i<n; i++) {
2027
      printf("factor[%"PRIu32"]: ", i);
2028
      pp_term_full(&printer, ctx->terms, v->data[i]);
2029
      flush_yices_pp(&printer);
2030
    }
2031

2032
    delete_yices_pp(&printer, true);
2033
  }
2034
}
2035

2036
#endif
2037

2038
/*
2039
 * Search for common factors of an or
2040
 * - push them in the queue for further flattening
2041
 */
2042
static void push_common_factors(context_t *ctx, term_t r) {
×
2043
  ivector_t *v;
2044
  uint32_t i, n;
2045

2046
  v = &ctx->aux_vector;
×
2047
  context_factor_disjunction(ctx, r, v);
×
2048

2049
#if 0
2050
  show_common_factors(ctx, r, v);
2051
#endif
2052

2053
  n = v->size;
×
2054
  for (i=0; i<n; i++) {
×
2055
    int_queue_push(&ctx->queue, v->data[i]);
×
2056
  }
2057
  ivector_reset(v);
×
2058
}
×
2059

2060
/*
2061
 * Non-atomic terms
2062
 */
2063
// r is (or t1 ... t_n)
2064
static void flatten_or(context_t *ctx, term_t r, bool tt) {
60,158✔
2065
  composite_term_t *d;
2066
  uint32_t i, n;
2067

2068
  if (tt) {
60,158✔
2069
    ivector_push(&ctx->top_formulas, r);
42,486✔
2070
    if (context_or_factoring_enabled(ctx)) {
42,486✔
2071
      push_common_factors(ctx, r);
×
2072
    }
2073
  } else {
2074
    d = or_term_desc(ctx->terms, r);
17,672✔
2075
    n = d->arity;
17,672✔
2076
    for (i=0; i<n; i++) {
100,267✔
2077
      int_queue_push(&ctx->queue, opposite_term(d->arg[i]));
82,595✔
2078
    }
2079
  }
2080
}
60,158✔
2081

2082
// r is (xor t1 ... t_n)
2083
static void flatten_xor(context_t *ctx, term_t r, bool tt) {
7✔
2084
  ivector_push(&ctx->top_formulas, signed_term(r, tt));
7✔
2085
}
7✔
2086

2087
// r is (ite c t1 t2) where t1 and t2 are boolean terms
2088
static void flatten_bool_ite(context_t *ctx, term_t r, bool tt) {
77✔
2089
  term_table_t *terms;
2090
  composite_term_t *d;
2091
  term_t c, t1, t2, t;
2092

2093
  terms = ctx->terms;
77✔
2094
  d = ite_term_desc(terms, r);
77✔
2095
  c = intern_tbl_get_root(&ctx->intern, d->arg[0]);
77✔
2096
  t1 = intern_tbl_get_root(&ctx->intern, d->arg[1]);
77✔
2097
  t2 = intern_tbl_get_root(&ctx->intern, d->arg[2]);
77✔
2098

2099
  t = simplify_ite(ctx, c, t1, t2);
77✔
2100
  if (t != NULL_TERM) {
77✔
2101
    int_queue_push(&ctx->queue, signed_term(t, tt));
2✔
2102
  } else {
2103

2104
    if (tt) {
75✔
2105
      if (c == t2 || term_is_false(ctx, t2)) {
58✔
2106
        // assert (ite c a false) --> assert c and a
2107
        // assert (ite c a c)     --> assert c and a
2108
        int_queue_push(&ctx->queue, c);
1✔
2109
        int_queue_push(&ctx->queue, t1);
1✔
2110
        return;
1✔
2111
      }
2112

2113
      if (opposite_bool_terms(c, t1) || term_is_false(ctx, t1)) {
57✔
2114
        // assert (ite c false b)   --> assert (not c) and b
2115
        // assert (ite c (not c) b) --> assert (not c) and b
2116
        int_queue_push(&ctx->queue, opposite_term(c));
1✔
2117
        int_queue_push(&ctx->queue, t2);
1✔
2118
        return;
1✔
2119
      }
2120

2121
    } else {
2122
      if (opposite_bool_terms(c, t2) || term_is_true(ctx, t2)) {
17✔
2123
        // assert not (ite c a true)    --> assert c and (not a)
2124
        // assert not (ite c a (not c)) --> assert c and (not a)
2125
        int_queue_push(&ctx->queue, c);
1✔
2126
        int_queue_push(&ctx->queue, opposite_term(t1));
1✔
2127
        return;
1✔
2128
      }
2129

2130
      if (c == t1 || term_is_true(ctx, t1)) {
16✔
2131
        // assert not (ite c true b) --> assert (not c) and (not b)
2132
        // assert not (ite c c b)    --> assert (not c) and (not b)
2133
        int_queue_push(&ctx->queue, opposite_term(c));
1✔
2134
        int_queue_push(&ctx->queue, opposite_term(t2));
1✔
2135
        return;
1✔
2136
      }
2137
    }
2138

2139
    // no flattening found
2140
    ivector_push(&ctx->top_formulas, signed_term(r, tt));
71✔
2141
  }
2142
}
2143

2144

2145
/*
2146
 * Simplify and flatten assertion f.
2147
 *
2148
 * Raise an exception via longjmp if there's an error or if a
2149
 * contradiction is detected.
2150
 */
2151
void flatten_assertion(context_t *ctx, term_t f) {
123,600✔
2152
  intern_tbl_t *intern;
2153
  int_queue_t *queue;
2154
  term_table_t *terms;
2155
  term_t t, r;
2156
  int32_t x;
2157
  bool tt;
2158
  int32_t exception;
2159

2160
  queue = &ctx->queue;
123,600✔
2161
  intern = &ctx->intern;
123,600✔
2162
  terms = ctx->terms;
123,600✔
2163

2164
  assert(int_queue_is_empty(queue));
2165
  int_queue_push(queue, f);
123,600✔
2166

2167
  do {
2168
    t = int_queue_pop(queue);           // assert t
221,505✔
2169

2170
    /*
2171
     * Convert (assert t) to (assert r == tt)
2172
     * where r is positive (equal to t or not t)
2173
     * and polarity is either true or false
2174
     */
2175
    r = intern_tbl_get_root(intern, t); // r == t by substitution
221,505✔
2176
    tt = is_pos_term(r);
221,505✔
2177
    r = unsigned_term(r);
221,505✔
2178

2179
    assert(is_pos_term(r) && intern_tbl_is_root(intern, r));
2180

2181
    if (intern_tbl_root_is_mapped(intern, r)) {
221,505✔
2182
      /*
2183
       * r already mapped to something
2184
       * check for trivial unsat
2185
       * then add r or (not r) to top_intern
2186
       */
2187
      x = intern_tbl_map_of_root(intern, r);
65,296✔
2188
      if (x == bool2code(! tt)) {
65,296✔
2189
        exception = TRIVIALLY_UNSAT;
352✔
2190
        goto abort;
352✔
2191
      }
2192

2193
      if (x != bool2code(tt)) {
64,944✔
2194
        ivector_push(&ctx->top_interns, signed_term(r, tt));
738✔
2195
      }
2196

2197
    } else {
2198
      /*
2199
       * r not seen before: record r = tt then explore r
2200
       */
2201
      switch (term_kind(terms, r)) {
156,209✔
2202
      case UNUSED_TERM:
×
2203
      case RESERVED_TERM:
2204
      case CONSTANT_TERM:
2205
        /*
2206
         * NOTE: the constant boolean terms are true and false, which
2207
         * should always be internalized to true_literal or false_literal.
2208
         * That's why we don't have a separate 'CONSTANT_TERM' case.
2209
         */
2210
        exception = INTERNAL_ERROR;
×
2211
        goto abort;
×
2212

2213
      case ARITH_CONSTANT:
×
2214
      case BV64_CONSTANT:
2215
      case BV_CONSTANT:
2216
      case ARITH_FLOOR:
2217
      case ARITH_CEIL:
2218
      case ARITH_ABS:
2219
      case UPDATE_TERM:
2220
      case TUPLE_TERM:
2221
      case LAMBDA_TERM:
2222
      case ARITH_RDIV:
2223
      case ARITH_IDIV:
2224
      case ARITH_MOD:
2225
      case BV_ARRAY:
2226
      case BV_DIV:
2227
      case BV_REM:
2228
      case BV_SDIV:
2229
      case BV_SREM:
2230
      case BV_SMOD:
2231
      case BV_SHL:
2232
      case BV_LSHR:
2233
      case BV_ASHR:
2234
      case POWER_PRODUCT:
2235
      case ARITH_POLY:
2236
      case BV64_POLY:
2237
      case BV_POLY:
2238
        exception = TYPE_ERROR;
×
2239
        goto abort;
×
2240

2241
      case VARIABLE:
×
2242
        exception = FREE_VARIABLE_IN_FORMULA;
×
2243
        goto abort;
×
2244

2245
      case UNINTERPRETED_TERM:
605✔
2246
        assert(intern_tbl_root_is_free(intern, r));
2247
        if (context_var_elim_enabled(ctx)) {
605✔
2248
          intern_tbl_add_subst(intern, r, bool2term(tt));
163✔
2249
        } else {
2250
          intern_tbl_map_root(intern, r, bool2code(tt));
442✔
2251
        }
2252
        break;
605✔
2253

2254
      case ARITH_EQ_ATOM:
2,271✔
2255
        intern_tbl_map_root(intern, r, bool2code(tt));
2,271✔
2256
        flatten_arith_eq0(ctx, r, tt);
2,271✔
2257
        break;
2,271✔
2258

2259
      case ARITH_GE_ATOM:
27,815✔
2260
        intern_tbl_map_root(intern, r, bool2code(tt));
27,815✔
2261
        flatten_arith_geq0(ctx, r, tt);
27,815✔
2262
        break;
27,815✔
2263

2264
      case ARITH_ROOT_ATOM:
×
NEW
2265
        if (context_mcsat_supplement_active(ctx)) {
×
NEW
2266
          intern_tbl_map_root(intern, r, bool2code(tt));
×
NEW
2267
          ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
2268
        } else {
NEW
2269
          exception = FORMULA_NOT_LINEAR;
×
NEW
2270
          goto abort;
×
2271
        }
NEW
2272
        break;
×
2273

2274
      case ARITH_IS_INT_ATOM:
×
2275
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2276
        flatten_arith_is_int(ctx, r, tt);
×
2277
        break;
×
2278

2279
      case ITE_TERM:
77✔
2280
      case ITE_SPECIAL:
2281
        intern_tbl_map_root(intern, r, bool2code(tt));
77✔
2282
        flatten_bool_ite(ctx, r, tt);
77✔
2283
        break;
77✔
2284

2285
      case APP_TERM:
252✔
2286
        intern_tbl_map_root(intern, r, bool2code(tt));
252✔
2287
        flatten_bool_app(ctx, r, tt);
252✔
2288
        break;
252✔
2289

2290
      case EQ_TERM:
6,315✔
2291
        intern_tbl_map_root(intern, r, bool2code(tt));
6,315✔
2292
        flatten_eq(ctx, r, tt);
6,315✔
2293
        break;
6,315✔
2294

2295
      case DISTINCT_TERM:
172✔
2296
        intern_tbl_map_root(intern, r, bool2code(tt));
172✔
2297
        flatten_distinct(ctx, r, tt);
172✔
2298
        break;
172✔
2299

2300
      case FORALL_TERM:
×
2301
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2302
        ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
2303
        break;
×
2304

2305
      case OR_TERM:
60,158✔
2306
        intern_tbl_map_root(intern, r, bool2code(tt));
60,158✔
2307
        flatten_or(ctx, r, tt);
60,158✔
2308
        break;
60,158✔
2309

2310
      case XOR_TERM:
7✔
2311
        intern_tbl_map_root(intern, r, bool2code(tt));
7✔
2312
        flatten_xor(ctx, r, tt);
7✔
2313
        break;
7✔
2314

2315
      case ARITH_BINEQ_ATOM:
4,567✔
2316
        intern_tbl_map_root(intern, r, bool2code(tt));
4,567✔
2317
        flatten_arith_eq(ctx, r, tt);
4,567✔
2318
        break;
4,567✔
2319

2320
      case ARITH_DIVIDES_ATOM:
×
2321
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2322
        flatten_arith_divides(ctx, r, tt);
×
2323
        break;
×
2324

2325
      case BV_EQ_ATOM:
19,895✔
2326
        intern_tbl_map_root(intern, r, bool2code(tt));
19,895✔
2327
        flatten_bveq(ctx, r, tt);
19,895✔
2328
        break;
19,894✔
2329

2330
      case BV_GE_ATOM:
1,478✔
2331
        intern_tbl_map_root(intern, r, bool2code(tt));
1,478✔
2332
        flatten_bvge(ctx, r, tt);
1,478✔
2333
        break;
1,478✔
2334

2335
      case BV_SGE_ATOM:
455✔
2336
        intern_tbl_map_root(intern, r, bool2code(tt));
455✔
2337
        flatten_bvsge(ctx, r, tt);
455✔
2338
        break;
455✔
2339

2340
      case SELECT_TERM:
×
2341
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2342
        flatten_select(ctx, r, tt);
×
2343
        break;
×
2344

2345
      case BIT_TERM:
32,140✔
2346
        intern_tbl_map_root(intern, r, bool2code(tt));
32,140✔
2347
        flatten_bit_select(ctx, r, tt);
32,140✔
2348
        break;
32,140✔
2349

2350
      case ARITH_FF_EQ_ATOM:
2✔
2351
      case ARITH_FF_BINEQ_ATOM:
2352
        if (context_mcsat_supplement_active(ctx)) {
2✔
2353
          intern_tbl_map_root(intern, r, bool2code(tt));
2✔
2354
          ivector_push(&ctx->top_atoms, signed_term(r, tt));
2✔
2355
        } else {
NEW
2356
          exception = CONTEXT_UNSUPPORTED_THEORY;
×
NEW
2357
          goto abort;
×
2358
        }
2359
        break;
2✔
2360

NEW
2361
      case ARITH_FF_POLY:
×
2362
      case ARITH_FF_CONSTANT:
2363
        exception = CONTEXT_UNSUPPORTED_THEORY;
×
2364
        goto abort;
×
2365
      }
2366
    }
2367

2368
  } while (! int_queue_is_empty(queue));
221,152✔
2369

2370
  return;
123,247✔
2371

2372
 abort:
352✔
2373
  assert(exception != 0);
2374
  longjmp(ctx->env, exception);
352✔
2375
}
2376

2377

2378

2379

2380
/*
2381
 * Process all candidate substitutions after flattening
2382
 * - the candidate substitutions are in ctx->subst_eqs
2383
 * - each element in ctx->subst_eqs is a boolean term e
2384
 *   such that e is true or false (by flattening)
2385
 *         and e is equivalent to an equality (t1 == t2)
2386
 *   where one of t1 and t2 is a variable.
2387
 */
2388
void context_process_candidate_subst(context_t *ctx) {
2,804✔
2389
  pseudo_subst_t *subst;
2390
  mark_vector_t *marks;
2391

2392
  subst = context_get_subst(ctx);
2,804✔
2393
  marks = context_get_marks(ctx);
2,804✔
2394
  process_subst_eqs(ctx, subst);
2,804✔
2395
  remove_subst_cycles(ctx);
2,804✔
2396
  finalize_subst_candidates(ctx);
2,804✔
2397

2398
  // cleanup
2399
  ivector_reset(&ctx->subst_eqs);
2,804✔
2400
  reset_pseudo_subst(subst);
2,804✔
2401
  reset_mark_vector(marks);
2,804✔
2402
}
2,804✔
2403

2404

2405

2406

2407
/**************************
2408
 *  AUXILIARY EQUALITIES  *
2409
 *************************/
2410

2411
/*
2412
 * Process an auxiliary equality eq
2413
 * - eq must be an equality term (i.e.,
2414
 *   either EQ_TERM, ARITH_EQ_ATOM, ARITH_BINEQ_ATOM, BVEQ_ATOM)
2415
 */
2416
static void process_aux_eq(context_t *ctx, term_t eq) {
57✔
2417
  composite_term_t *d;
2418
  term_t t1, t2;
2419
  int32_t code;
2420

2421
  assert(intern_tbl_is_root(&ctx->intern, eq));
2422

2423
  if (intern_tbl_root_is_mapped(&ctx->intern, eq)) {
57✔
2424
    // eq is already internalized
2425
    code = intern_tbl_map_of_root(&ctx->intern, eq);
1✔
2426
    if (code == bool2code(false)) {
1✔
2427
      // contradiction
2428
      longjmp(ctx->env, TRIVIALLY_UNSAT);
1✔
2429
    } else if (code != bool2code(true)) {
×
2430
      ivector_push(&ctx->top_interns, eq);
×
2431
    }
2432
  } else {
2433
    // map e to true and try to process it as a substitution
2434
    intern_tbl_map_root(&ctx->intern, eq, bool2code(true));
56✔
2435

2436
    switch (term_kind(ctx->terms, eq)) {
56✔
2437
    case EQ_TERM:
55✔
2438
    case ARITH_BINEQ_ATOM:
2439
    case BV_EQ_ATOM:
2440
      // process e as a substitution if possible
2441
      d = composite_term_desc(ctx->terms, eq);
55✔
2442
      assert(d->arity == 2);
2443
      t1 = intern_tbl_get_root(&ctx->intern, d->arg[0]);
55✔
2444
      t2 = intern_tbl_get_root(&ctx->intern, d->arg[1]);
55✔
2445
      if (is_boolean_term(ctx->terms, t1)) {
55✔
2446
        try_bool_substitution(ctx, t1, t2, eq);
×
2447
      } else {
2448
        try_substitution(ctx, t1, t2, eq);
55✔
2449
      }
2450
      break;
55✔
2451

2452
    case ARITH_EQ_ATOM:
1✔
2453
      ivector_push(&ctx->top_eqs, eq);
1✔
2454
      break;
1✔
2455

2456
    default:
×
2457
      assert(false);
2458
      break;
×
2459
    }
2460
  }
2461
}
56✔
2462

2463

2464
/*
2465
 * Process the auxiliary equalities:
2466
 * - if substitution is not enabled, then all aux equalities are added to top_eqs
2467
 * - otherwise, cheap substitutions are performed and candidate substitutions
2468
 *   are added to subst_eqs.
2469
 *
2470
 * This function raises an exception via longjmp if a contradiction is detected.
2471
 */
2472
void process_aux_eqs(context_t *ctx) {
8✔
2473
  uint32_t i, n;
2474
  ivector_t *aux_eqs;
2475

2476
  aux_eqs = &ctx->aux_eqs;
8✔
2477
  n = aux_eqs->size;
8✔
2478
  for (i=0; i<n; i++) {
64✔
2479
    process_aux_eq(ctx, aux_eqs->data[i]);
57✔
2480
  }
2481

2482
  // cleanup
2483
  ivector_reset(&ctx->aux_eqs);
7✔
2484
}
7✔
2485

2486

2487

2488
/*******************
2489
 *  LEARNED ATOMS  *
2490
 ******************/
2491

2492
/*
2493
 * Process all terms in ctx->aux_atoms:
2494
 */
2495
void process_aux_atoms(context_t *ctx) {
3✔
2496
  ivector_t *v;
2497
  uint32_t i, n;
2498
  term_t t, r;
2499
  int32_t code;
2500

2501
  v = &ctx->aux_atoms;
3✔
2502
  n = v->size;
3✔
2503
  for (i=0; i<n; i++) {
529✔
2504
    t = v->data[i];
526✔
2505
    r = intern_tbl_get_root(&ctx->intern, t);
526✔
2506

2507
    if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
526✔
2508
      // already internalized
2509
      code = intern_tbl_map_of_root(&ctx->intern, r);
2✔
2510
      if (code == bool2code(false)) {
2✔
2511
        // contradiction
2512
        longjmp(ctx->env, TRIVIALLY_UNSAT);
×
2513
      } else if (code != bool2code(true)) {
2✔
2514
        ivector_push(&ctx->top_interns, r);
2✔
2515
      }
2516
    } else {
2517
      // not mapped
2518
      intern_tbl_map_root(&ctx->intern, r, bool2code(true));
524✔
2519
      ivector_push(&ctx->top_atoms, r);
524✔
2520
    }
2521
  }
2522

2523
  ivector_reset(v);
3✔
2524
}
3✔
2525

2526

2527

2528

2529
/********************************
2530
 *  FLATTENING OF DISJUNCTIONS  *
2531
 *******************************/
2532

2533
/*
2534
 * This does two things:
2535
 * 1) rewrite nested OR terms to flat OR terms
2536
 * 2) replace arithmetic disequality by disjunctions of strict inequalities
2537
 *    (i.e., rewrite (x != 0) to (or (x < 0) (x > 0))
2538
 */
2539

2540
/*
2541
 * Build the atom (t < 0)
2542
 */
2543
static term_t lt0_atom(context_t *ctx, term_t t) {
2,573✔
2544
  rba_buffer_t *b;
2545

2546
  assert(is_pos_term(t) && is_arithmetic_term(ctx->terms, t));
2547

2548
  b = ctx->arith_buffer;
2,573✔
2549
  assert(b != NULL && rba_buffer_is_zero(b));
2550

2551
  rba_buffer_add_term(b, ctx->terms, t);
2,573✔
2552
  return mk_direct_arith_lt0(ctx->terms, b, true);
2,573✔
2553
}
2554

2555
/*
2556
 * Build a term equivalent to (t > 0)
2557
 */
2558
static term_t gt0_atom(context_t *ctx, term_t t) {
2,573✔
2559
  rba_buffer_t *b;
2560

2561
  assert(is_pos_term(t) && is_arithmetic_term(ctx->terms, t));
2562

2563
  b = ctx->arith_buffer;
2,573✔
2564
  assert(b != NULL && rba_buffer_is_zero(b));
2565

2566
  rba_buffer_add_term(b, ctx->terms, t);
2,573✔
2567
  return mk_direct_arith_gt0(ctx->terms, b, true);
2,573✔
2568
}
2569

2570

2571
/*
2572
 * Build a term equivalent to (t < u)
2573
 */
2574
static term_t lt_atom(context_t *ctx, term_t t, term_t u) {
6,856✔
2575
  rba_buffer_t *b;
2576

2577
  assert(is_pos_term(t) && is_arithmetic_term(ctx->terms, t));
2578
  assert(is_pos_term(u) && is_arithmetic_term(ctx->terms, u));
2579

2580
  // build atom (t - u < 0)
2581
  b = ctx->arith_buffer;
6,856✔
2582
  assert(b != NULL && rba_buffer_is_zero(b));
2583
  rba_buffer_add_term(b, ctx->terms, t);
6,856✔
2584
  rba_buffer_sub_term(b, ctx->terms, u);
6,856✔
2585
  return mk_direct_arith_lt0(ctx->terms, b, true);
6,856✔
2586
}
2587

2588

2589
/*
2590
 * We use a breadth-first approach:
2591
 * - ctx->queue contains all terms to process
2592
 * - v contains the terms that can't be flattened
2593
 * - ctx->small_cache contains all the terms that have been visited
2594
 *   (including all terms in v and in ctx->queue).
2595
 *
2596
 * The term we're building is (or <elements in v> <elements in the queue>)
2597
 */
2598

2599
/*
2600
 * Push t into ctx->queue if it's not been visited yet
2601
 */
2602
static void flatten_or_push_term(context_t *ctx, term_t t) {
125,795✔
2603
  assert(is_boolean_term(ctx->terms, t));
2604

2605
  if (int_hset_add(ctx->small_cache, t)) {
125,795✔
2606
    int_queue_push(&ctx->queue, t);
125,507✔
2607
  }
2608
}
125,795✔
2609

2610
/*
2611
 * Add t to v if it's not been visited yet
2612
 */
2613
static void flatten_or_add_term(context_t *ctx, ivector_t *v, term_t t) {
12,002✔
2614
  assert(is_boolean_term(ctx->terms, t));
2615

2616
  if (int_hset_add(ctx->small_cache, t)) {
12,002✔
2617
    ivector_push(v, t);
12,002✔
2618
  }
2619
}
12,002✔
2620

2621
/*
2622
 * Process all elements in ctx->queue.
2623
 *
2624
 * For every term t in the queue:
2625
 * - if t is already internalized, keep t and add it to v
2626
 * - if t is (or t1 ... t_n), add t1 ... t_n to the queue
2627
 * - if flattening of disequalities is enabled, and t is (NOT (x == 0)) then
2628
 *   we rewrite (NOT (x == 0)) to (OR (< x 0) (> x 0))
2629
 * - otherwise store t into v
2630
 */
2631
static void flatten_or_process_queue(context_t *ctx, ivector_t *v) {
27,715✔
2632
  term_table_t *terms;
2633
  composite_term_t *or;
2634
  composite_term_t *eq;
2635
  uint32_t i, n;
2636
  term_kind_t kind;
2637
  term_t t, x, y;
2638

2639
  terms = ctx->terms;
27,715✔
2640

2641
  while (! int_queue_is_empty(&ctx->queue)) {
153,222✔
2642
    t = int_queue_pop(&ctx->queue);
125,507✔
2643

2644
    // apply substitutions
2645
    t = intern_tbl_get_root(&ctx->intern, t);
125,507✔
2646

2647
    if (intern_tbl_root_is_mapped(&ctx->intern, t)) {
125,507✔
2648
      // t is already internalized: keep it as is
2649
      ivector_push(v, t);
62,077✔
2650
    } else {
2651
      kind = term_kind(terms, t);
63,430✔
2652
      if (is_pos_term(t) && kind == OR_TERM) {
85,508✔
2653
        // add t's children to the queue
2654
        or = or_term_desc(terms, t);
22,078✔
2655
        n = or->arity;
22,078✔
2656
        for (i=0; i<n; i++) {
68,050✔
2657
          flatten_or_push_term(ctx, or->arg[i]);
45,972✔
2658
        }
2659
      } else if (is_neg_term(t) && context_flatten_diseq_enabled(ctx)) {
41,352✔
2660
        switch (kind) {
26,406✔
2661
        case ARITH_EQ_ATOM:
2,608✔
2662
          /*
2663
           * t is (not (eq x 0)): rewrite to (or (x < 0) (x > 0))
2664
           *
2665
           * Exception: keep it as an equality if x is an if-then-else term
2666
           */
2667
          x = intern_tbl_get_root(&ctx->intern, arith_eq_arg(terms, t));
2,608✔
2668
          if (is_ite_term(terms, x)) {
2,608✔
2669
            ivector_push(v, t);
35✔
2670
          } else {
2671
            flatten_or_add_term(ctx, v, lt0_atom(ctx, x));
2,573✔
2672
            flatten_or_add_term(ctx, v, gt0_atom(ctx, x));
2,573✔
2673
          }
2674
          break;
2,608✔
2675

2676
        case ARITH_BINEQ_ATOM:
5,348✔
2677
          /*
2678
           * t is (not (eq x y)): rewrite to (or (x < y) (y < x))
2679
           *
2680
           * Exception 1: if x or y is an if-then-else term, then it's
2681
           * better to keep (eq x y) because the if-lifting
2682
           * simplifications are more likely to work on
2683
           *    (ite c a b) = y
2684
           * than (ite c a b) >= y AND (ite c a b) <= y
2685
           *
2686
           * Exception 2: if there's an egraph, then it's better
2687
           * to keep (eq x y) as is. It will be converted to an
2688
           * egraph equality.
2689
           */
2690
          eq = arith_bineq_atom_desc(terms, t);
5,348✔
2691
          x = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
5,348✔
2692
          y = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
5,348✔
2693
          if (context_has_egraph(ctx) || is_ite_term(terms, x) || is_ite_term(terms, y)) {
5,348✔
2694
            ivector_push(v, t);
1,920✔
2695
          } else {
2696
            flatten_or_add_term(ctx, v, lt_atom(ctx, x, y));
3,428✔
2697
            flatten_or_add_term(ctx, v, lt_atom(ctx, y, x));
3,428✔
2698
          }
2699
          break;
5,348✔
2700

2701
        default:
18,450✔
2702
          // can't flatten
2703
          ivector_push(v, t);
18,450✔
2704
          break;
18,450✔
2705
        }
2706

2707
      } else {
2708
        // can't flatten
2709
        ivector_push(v, t);
14,946✔
2710
      }
2711
    }
2712
  }
2713
}
27,715✔
2714

2715
/*
2716
 * Flatten a top-level (or t1 .... tp)
2717
 * - initialize the small_cache, then calls the recursive function
2718
 * - the result is stored in v
2719
 */
2720
void flatten_or_term(context_t *ctx, ivector_t *v, composite_term_t *or) {
27,715✔
2721
  uint32_t i, n;
2722

2723
  assert(v->size == 0 && int_queue_is_empty(&ctx->queue));
2724

2725
  (void) context_get_small_cache(ctx); // initialize the cache
27,715✔
2726
  if (context_flatten_diseq_enabled(ctx)) {
27,715✔
2727
    (void) context_get_arith_buffer(ctx);  // allocate the internal buffer
27,715✔
2728
  }
2729

2730
  n = or->arity;
27,715✔
2731
  for (i=0; i<n; i++) {
107,538✔
2732
    flatten_or_push_term(ctx, or->arg[i]);
79,823✔
2733
  }
2734

2735
  flatten_or_process_queue(ctx, v);
27,715✔
2736

2737
  //  context_delete_small_cache(ctx);
2738
  context_reset_small_cache(ctx);
27,715✔
2739
}
27,715✔
2740

2741

2742

2743

2744
/************************
2745
 *  EQUALITY LEARNING   *
2746
 ***********************/
2747

2748
/*
2749
 * Add implied equalities defined by the partition p to the aux_eqs vector
2750
 */
2751
static void add_implied_equalities(context_t *ctx, epartition_t *p) {
51✔
2752
  uint32_t i, n;
2753
  term_t *q, x, y;
2754

2755
  n = p->nclasses;
51✔
2756
  q = p->data;
51✔
2757
  for (i=0; i<n; i++) {
102✔
2758
    x = *q++;
51✔
2759
    assert(x >= 0);
2760
    y = *q ++;
51✔
2761
    while (y >= 0) {
102✔
2762
      add_aux_eq(ctx, x, y);
51✔
2763
      y = *q ++;
51✔
2764
    }
2765
  }
2766
}
51✔
2767

2768

2769
/*
2770
 * Attempt to learn global equalities implied
2771
 * by the formulas stored in ctx->top_formulas.
2772
 * Any such equality is added to ctx->aux_eqs
2773
 */
2774
void analyze_uf(context_t *ctx) {
64✔
2775
  ivector_t *v;
2776
  uint32_t i, n;
2777
  eq_learner_t *eql;
2778
  epartition_t *p;
2779

2780
  eql = objstack_alloc(&ctx->ostack, sizeof(eq_learner_t), (cleaner_t) delete_eq_learner);
64✔
2781
  init_eq_learner(eql, ctx->terms);
64✔
2782
  v = &ctx->top_formulas;
64✔
2783
  n = v->size;
64✔
2784

2785
  for (i=0; i<n; i++) {
1,743✔
2786
    p = eq_learner_process(eql, v->data[i]);
1,679✔
2787
    if (p->nclasses > 0) {
1,679✔
2788
      add_implied_equalities(ctx, p);
51✔
2789
    }
2790
  }
2791

2792
  //  delete_eq_learner(&eql);
2793
  objstack_pop(&ctx->ostack);
64✔
2794
}
64✔
2795

2796

2797

2798

2799
/*************************************************
2800
 *  ANALYSIS FOR THE DIFFERENCE LOGIC FRAGMENTS  *
2801
 ************************************************/
2802

2803
/*
2804
 * Buffer to store a difference logic term.
2805
 *
2806
 * The difference logic fragment contains terms of the following forms:
2807
 *   a + x - y
2808
 *   a + x
2809
 *   a - y
2810
 *   a
2811
 * where x and y are arithmetic variables and a is a constant (possibly a = 0).
2812
 *
2813
 * In IDL, x and y must be integer variables and a must be an integer constant.
2814
 * In RDL, x and y must be real variables.
2815
 *
2816
 * To encode the four types of terms, we use zero_term when x or y is missing:
2817
 *  a + x  -->  a + x - zero_term
2818
 *  a - y  -->  a + zero_term - y
2819
 *  a      -->  a + zero_term - zero_term
2820
 */
2821
typedef struct dl_term_s {
2822
  term_t x;
2823
  term_t y;
2824
  rational_t a;
2825
} dl_term_t;
2826

2827

2828
/*
2829
 * Initialization and cleanup
2830
 */
2831
static void init_dl_term(dl_term_t *triple) {
6,431✔
2832
  triple->x = zero_term;
6,431✔
2833
  triple->y = zero_term;
6,431✔
2834
  q_init(&triple->a);
6,431✔
2835
}
6,431✔
2836

2837
static void delete_dl_term(dl_term_t *triple) {
6,431✔
2838
  q_clear(&triple->a);
6,431✔
2839
}
6,431✔
2840

2841

2842
/*
2843
 * Check whether the triple is in IDL or RDL.
2844
 */
2845
static bool check_dl_fragment(context_t *ctx, dl_term_t *triple, bool idl) {
6,431✔
2846
  assert(is_arithmetic_term(ctx->terms, triple->x) && is_pos_term(triple->x) && intern_tbl_is_root(&ctx->intern, triple->x));
2847
  assert(is_arithmetic_term(ctx->terms, triple->y) && is_pos_term(triple->y) && intern_tbl_is_root(&ctx->intern, triple->y));
2848

2849
  return (triple->x == zero_term || is_integer_root(ctx, triple->x) == idl)
6,412✔
2850
    && (triple->y == zero_term || is_integer_root(ctx, triple->y) == idl)
6,431✔
2851
    && (!idl || q_is_integer(&triple->a));
12,862✔
2852
}
2853

2854

2855
/*
2856
 * Check whether aux contains a difference logic term. If so store the term in *triple.
2857
 * All terms of aux must be roots in ctx->interm.
2858
 *
2859
 * Return true if aux is in the difference logic fragment, false otherwise.
2860
 */
2861
static bool dl_convert_poly_buffer(context_t *ctx, dl_term_t *triple, poly_buffer_t *aux) {
6,431✔
2862
  uint32_t n;
2863
  monomial_t *q;
2864

2865
  n = poly_buffer_nterms(aux);
6,431✔
2866
  if (n > 3) return false;
6,431✔
2867
  if (n == 0) return true;
6,431✔
2868

2869
  q = poly_buffer_mono(aux);
6,424✔
2870

2871
  // constant
2872
  q_clear(&triple->a);
6,424✔
2873
  if (q[0].var == const_idx) {
6,424✔
2874
    q_set(&triple->a, &q[0].coeff);
5,261✔
2875
    q ++;
5,261✔
2876
    n --;
5,261✔
2877
  }
2878

2879
  // deal with the non-constant terms
2880
  if (n == 2 && q_opposite(&q[0].coeff, &q[1].coeff)) {
6,424✔
2881
    if (q_is_one(&q[0].coeff)) {
6,408✔
2882
      // a_0 + x_1 - x_2
2883
      triple->x = q[0].var; // x_1
759✔
2884
      triple->y = q[1].var; // x_2
759✔
2885
      return true;
759✔
2886
    }
2887

2888
    if (q_is_one(&q[1].coeff)) {
5,649✔
2889
      // a_0 - x_1 + x_2
2890
      triple->x = q[1].var; // x_2
5,649✔
2891
      triple->y = q[0].var; // x_1
5,649✔
2892
      return true;
5,649✔
2893
    }
2894

2895
  } else if (n == 1) {
16✔
2896
    if (q_is_one(&q[0].coeff)) {
4✔
2897
      // a_0 + x_1
2898
      triple->x = q[0].var; // x_1
4✔
2899
      triple->y = zero_term;
4✔
2900
      return true;
4✔
2901
    }
2902

2903
    if (q_is_minus_one(&q[0].coeff)) {
×
2904
      // a_0 - x_1
2905
      triple->x = zero_term;
×
2906
      triple->y = q[0].var; // x_1
×
2907
      return true;
×
2908
    }
2909

2910
  } else if (n == 0) {
12✔
2911
    triple->x = zero_term;
12✔
2912
    triple->y = zero_term;
12✔
2913
    return true;
12✔
2914
  }
2915

2916
  return false;
×
2917
}
2918

2919

2920
/*
2921
 * Apply substitutions then check whether p can be converted to a dl term.
2922
 * If so store the result in tiple and return true. Otherwise return false;
2923
 */
2924
static bool dl_convert_poly(context_t *ctx, dl_term_t *triple, polynomial_t *p) {
5,670✔
2925
  poly_buffer_t *aux;
2926
  monomial_t *mono;
2927
  term_table_t *terms;
2928
  uint32_t i, n;
2929
  term_t t;
2930

2931
  aux = context_get_poly_buffer(ctx);
5,670✔
2932
  reset_poly_buffer(aux);
5,670✔
2933

2934
  assert(poly_buffer_is_zero(aux));
2935

2936
  n = p->nterms;
5,670✔
2937
  mono = p->mono;
5,670✔
2938

2939
  /*
2940
   * p is of the form a0 + a_1 t_1 + ... + a_n t_n
2941
   * We replace t_i by its root in S(t_i) in the intern table.
2942
   * The result a0 + a_1 S(t_1) + ... + a_n S(t_n) is stored in buffer aux..
2943
   * Then we check whether aux is a difference logic polynomial.
2944
   */
2945
  assert(n > 0); // because zero polynomial is converted to 0 constant
2946

2947
  // deal with the constant first
2948
  if (mono[0].var == const_idx) {
5,670✔
2949
    poly_buffer_add_const(aux, &mono[0].coeff);
5,263✔
2950
    n --;
5,263✔
2951
    mono ++;
5,263✔
2952
  }
2953

2954
  terms = ctx->terms;
5,670✔
2955
  for (i=0; i<n; i++) {
17,010✔
2956
    t = intern_tbl_get_root(&ctx->intern, mono[i].var);
11,340✔
2957
    poly_buffer_addmul_term(terms, aux, t, &mono[i].coeff);
11,340✔
2958
  }
2959

2960
  normalize_poly_buffer(aux);
5,670✔
2961

2962
  /*
2963
   * The QF_RDL theory, as defined by SMT-LIB, allows constraints of
2964
   * the form (<= (- (* a x) (* a y)) b) where a and b are integer
2965
   * constants. We allow rationals here and we also allow
2966
   * constraints like that for QF_IDL (provided b/a is an integer).
2967
   */
2968
  if (! poly_buffer_is_zero(aux)) {
5,670✔
2969
    (void) poly_buffer_make_monic(aux);
5,665✔
2970
  }
2971

2972
  return dl_convert_poly_buffer(ctx, triple, aux);
5,670✔
2973
}
2974

2975

2976
/*
2977
 * Check whether (x - y) is a difference logic term. If so, store the result in triple
2978
 * and return true. Otherwise return false.
2979
 */
2980
static bool dl_convert_diff(context_t *ctx, dl_term_t *triple, term_t x, term_t y) {
761✔
2981
  term_table_t *terms;
2982
  poly_buffer_t *aux;
2983

2984
  assert(is_arithmetic_term(ctx->terms, x) && is_pos_term(x) &&
2985
         is_arithmetic_term(ctx->terms, y) && is_pos_term(y));
2986

2987
  aux = context_get_poly_buffer(ctx);
761✔
2988
  reset_poly_buffer(aux);
761✔
2989
  assert(poly_buffer_is_zero(aux));
2990

2991
  // build polynomial (x - y) after applying substitutions
2992
  terms = ctx->terms;
761✔
2993
  poly_buffer_add_term(terms, aux, intern_tbl_get_root(&ctx->intern, x));
761✔
2994
  poly_buffer_sub_term(terms, aux, intern_tbl_get_root(&ctx->intern, y));
761✔
2995
  normalize_poly_buffer(aux);
761✔
2996

2997
  return dl_convert_poly_buffer(ctx, triple, aux);
761✔
2998
}
2999

3000

3001
/*
3002
 * Check whether term t is a difference logic term. If so convert t to a dl_term
3003
 * and store that in triple.
3004
 * Return true if the conversion succeeds, false otherwise.
3005
 */
3006
static bool dl_convert_term(context_t *ctx, dl_term_t *triple, term_t t) {
5,670✔
3007
  term_table_t *terms;
3008

3009
  assert(is_arithmetic_term(ctx->terms, t));
3010

3011
  terms = ctx->terms;
5,670✔
3012

3013
  // apply substitution
3014
  t = intern_tbl_get_root(&ctx->intern, t);
5,670✔
3015

3016
  assert(is_arithmetic_term(terms, t) && is_pos_term(t)
3017
         && intern_tbl_is_root(&ctx->intern, t));
3018

3019
  switch (term_kind(terms, t)) {
5,670✔
3020
  case ARITH_CONSTANT:
×
3021
    triple->x = zero_term;
×
3022
    triple->y = zero_term;
×
3023
    q_set(&triple->a, rational_term_desc(terms, t));
×
3024
    return true;
×
3025

3026
  case UNINTERPRETED_TERM:
×
3027
    return dl_convert_diff(ctx, triple, t, zero_term);
×
3028

3029
  case ARITH_POLY:
5,670✔
3030
    return dl_convert_poly(ctx, triple, poly_term_desc(terms, t));
5,670✔
3031

3032
  default:
×
3033
    // TODO: we could accept if-then-else here?
3034
    return false;
×
3035
  }
3036
}
3037

3038

3039

3040
/*
3041
 * Increment the number of variables if t has not been seen before
3042
 */
3043
static void count_dl_var(context_t *ctx, term_t t) {
19✔
3044
  bool new;
3045

3046
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t));
3047

3048
  (void) int_rat_hmap_get(ctx->edge_map, t, &new);
19✔
3049
  ctx->dl_profile->num_vars += new;
19✔
3050
}
19✔
3051

3052
/*
3053
 * Update: edge of weight a from source t
3054
 * - in the edge_map, we assign to term t the max weight of all potential
3055
 *   edges of source t. The weight is an absolute value.
3056
 */
3057
static void count_dl_var_and_edge(context_t *ctx, term_t t, rational_t *a) {
12,824✔
3058
  int_rat_hmap_rec_t *d;
3059
  bool new;
3060

3061
  assert(q_is_nonneg(a));
3062
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t));
3063

3064
  d = int_rat_hmap_get(ctx->edge_map, t, &new);
12,824✔
3065
  ctx->dl_profile->num_vars += new;
12,824✔
3066
  if (q_gt(a, &d->value)) {
12,824✔
3067
    // increase bound on edges of source t
3068
    q_set(&d->value, a);
1,750✔
3069
  }
3070
}
12,824✔
3071

3072

3073
/*
3074
 * Update the difference logic statistics for atom x - y <= a
3075
 * - this corresponds to an edge x --> y of absolute weight a >= 0
3076
 * - if the atom is true, the dl solver will add an edge from x to y of weight a
3077
 * - if the atom if false, the dl solver will and an edge from y to x of weight
3078
 *    (or - a - 1 in IDL case)
3079
 */
3080
static void update_dl_stats(context_t *ctx, term_t x, term_t y, rational_t *a, bool idl) {
3,867✔
3081
  if (x == y) {
3,867✔
3082
    /*
3083
     * The atom simplifies to true or false but we must count x as a variable,
3084
     * because the diff logic solver will still create a variable for x.
3085
     */
3086
    count_dl_var(ctx, x);
9✔
3087
  } else {
3088
    /*
3089
     * We use the absolute value as an upper bound:
3090
     *  x --> y with weight = |a|
3091
     *  y --> x with weight = |a| or |a|+1 if idl
3092
     */
3093
    if (q_is_neg(a)) q_neg(a);
3,858✔
3094
    count_dl_var_and_edge(ctx, x, a);
3,858✔
3095
    if (idl) q_add_one(a);
3,858✔
3096
    count_dl_var_and_edge(ctx, y, a);
3,858✔
3097
    ctx->dl_profile->num_atoms ++;
3,858✔
3098
  }
3099
}
3,867✔
3100

3101

3102
/*
3103
 * Same thing for (x - y == a): the max weight is |a| + 1 for both x and y
3104
 */
3105
static void update_dleq_stats(context_t *ctx, term_t x, term_t y, rational_t *a, bool idl) {
2,564✔
3106
  if (x == y) {
2,564✔
3107
    count_dl_var(ctx, x);
10✔
3108
  } else {
3109
    if (q_is_neg(a)) q_neg(a);
2,554✔
3110
    if (idl) q_add_one(a);
2,554✔
3111
    count_dl_var_and_edge(ctx, x, a);
2,554✔
3112
    count_dl_var_and_edge(ctx, y, a);
2,554✔
3113
    ctx->dl_profile->num_eqs ++;
2,554✔
3114
    ctx->dl_profile->num_atoms ++;
2,554✔
3115
  }
3116
}
2,564✔
3117

3118
/*
3119
 * Check atom (t == 0) and update statistics
3120
 * - idl = true to check for IDL, false for RDL
3121
 */
3122
static bool check_dl_eq0_atom(context_t *ctx, term_t t, bool idl) {
1,803✔
3123
  dl_term_t *triple;
3124
  bool result;
3125

3126
  triple = objstack_alloc(&ctx->ostack, sizeof(dl_term_t), (cleaner_t) delete_dl_term);
1,803✔
3127
  init_dl_term(triple);
1,803✔
3128
  result = dl_convert_term(ctx, triple, t) && check_dl_fragment(ctx, triple, idl);
1,803✔
3129
  if (result) {
1,803✔
3130
    // a + x - y = 0 <--> (y - x = a)
3131
    update_dleq_stats(ctx, triple->y, triple->x, &triple->a, idl);
1,803✔
3132
  }
3133
  //  delete_dl_term(&triple);
3134
  objstack_pop(&ctx->ostack);
1,803✔
3135

3136
  return result;
1,803✔
3137
}
3138

3139
/*
3140
 * Check atom (t >= 0) and update statistics
3141
 */
3142
static bool check_dl_geq0_atom(context_t *ctx, term_t t, bool idl) {
3,867✔
3143
  dl_term_t *triple;
3144
  bool result;
3145

3146
  triple = objstack_alloc(&ctx->ostack, sizeof(dl_term_t), (cleaner_t) delete_dl_term);
3,867✔
3147
  init_dl_term(triple);
3,867✔
3148
  result = dl_convert_term(ctx, triple, t) && check_dl_fragment(ctx, triple, idl);
3,867✔
3149
  if (result) {
3,867✔
3150
    // a + x - y >= 0 <--> (y - x <= -a)
3151
    q_neg(&triple->a);
3,867✔
3152
    update_dl_stats(ctx, triple->y, triple->x, &triple->a, idl);
3,867✔
3153
  }
3154
  //  delete_dl_term(triple);
3155
  objstack_pop(&ctx->ostack);
3,867✔
3156

3157
  return result;
3,867✔
3158
}
3159

3160
/*
3161
 * Check atom (t1 == t2) and update statistics
3162
 */
3163
static bool check_dl_eq_atom(context_t *ctx, term_t t1, term_t t2, bool idl) {
761✔
3164
  dl_term_t *triple;
3165
  bool result;
3166

3167
  triple = objstack_alloc(&ctx->ostack, sizeof(dl_term_t), (cleaner_t) delete_dl_term);
761✔
3168
  init_dl_term(triple);
761✔
3169
  result = dl_convert_diff(ctx, triple, t1, t2) && check_dl_fragment(ctx, triple, idl);
761✔
3170
  if (result) {
761✔
3171
    // a + x - y = 0 <--> (y - x = a)
3172
    update_dleq_stats(ctx, triple->y, triple->x, &triple->a, idl);
761✔
3173
  }
3174
  //  delete_dl_term(triple);
3175
  objstack_pop(&ctx->ostack);
761✔
3176

3177
  return result;
761✔
3178
}
3179

3180

3181
/*
3182
 * Check atom (distinct a[0] .... a[n-1]) and update statistics
3183
 */
3184
static bool check_dl_distinct_atom(context_t *ctx, term_t *a, uint32_t n, bool idl) {
×
3185
  uint32_t i, j;
3186

3187
  assert(n > 2);
3188

3189
  for (i=0; i<n-1; i++) {
×
3190
    for (j=i+1; j<n; j++) {
×
3191
      if (! check_dl_eq_atom(ctx, a[i], a[j], idl)) {
×
3192
        return false;
×
3193
      }
3194
    }
3195
  }
3196

3197
  return true;
×
3198
}
3199

3200

3201
/*
3202
 * Analyze all arithmetic atoms in term t and fill ctx->dl_profile
3203
 * - if idl is true, this checks for integer difference logic
3204
 *   otherwise, checks for real difference logic
3205
 * - cache must be initialized and contain all the terms already visited
3206
 */
3207
static void analyze_dl(context_t *ctx, term_t t, bool idl) {
20,256✔
3208
  term_table_t *terms;
3209
  composite_term_t *cmp;
3210
  uint32_t i, n;
3211
  int32_t idx;
3212
  term_t r;
3213
  int32_t code;
3214

3215
  assert(is_boolean_term(ctx->terms, t));
3216

3217
  idx = index_of(t); // remove negation
20,256✔
3218

3219
  if (int_bvset_add_check(ctx->cache, idx)) {
20,256✔
3220
    /*
3221
     * idx not visited yet
3222
     */
3223
    terms = ctx->terms;
11,773✔
3224
    switch (kind_for_idx(terms, idx)) {
11,773✔
3225
    case CONSTANT_TERM:
6✔
3226
      assert(idx == bool_const);
3227
      break;
6✔
3228

3229
    case UNINTERPRETED_TERM:
728✔
3230
      // follow the substitutions if any
3231
      r = intern_tbl_get_root(&ctx->intern, pos_term(idx));
728✔
3232
      if (r != pos_term(idx)) {
728✔
3233
        analyze_dl(ctx,  r, idl);
57✔
3234
      }
3235
      break;
728✔
3236

3237
    case ITE_TERM:
4,398✔
3238
    case ITE_SPECIAL:
3239
    case OR_TERM:
3240
    case XOR_TERM:
3241
      cmp = composite_for_idx(terms, idx);
4,398✔
3242
      n = cmp->arity;
4,398✔
3243
      for (i=0; i<n; i++) {
18,512✔
3244
        analyze_dl(ctx, cmp->arg[i], idl);
14,114✔
3245
      }
3246
      break;
4,398✔
3247

3248
    case EQ_TERM:
210✔
3249
      cmp = composite_for_idx(terms, idx);
210✔
3250
      assert(cmp->arity == 2);
3251
      if (is_boolean_term(terms, cmp->arg[0])) {
210✔
3252
        // boolean equality
3253
        analyze_dl(ctx, cmp->arg[0], idl);
210✔
3254
        analyze_dl(ctx, cmp->arg[1], idl);
210✔
3255
      } else {
3256
        goto abort;
×
3257
      }
3258
      break;
210✔
3259

3260
    case DISTINCT_TERM:
×
3261
      cmp = composite_for_idx(terms, idx);
×
3262
      if (! check_dl_distinct_atom(ctx, cmp->arg, cmp->arity, idl)) {
×
3263
        goto abort;
×
3264
      }
3265
      break;
×
3266

3267
    case ARITH_EQ_ATOM:
1,803✔
3268
      // term (x == 0): check whether x is a difference logic term
3269
      if (! check_dl_eq0_atom(ctx, integer_value_for_idx(terms, idx), idl)) {
1,803✔
3270
        goto abort;
×
3271
      }
3272
      break;
1,803✔
3273

3274
    case ARITH_GE_ATOM:
3,867✔
3275
      // term (x >= 0): check whether x is a difference logic term
3276
      if (! check_dl_geq0_atom(ctx, integer_value_for_idx(terms, idx), idl)) {
3,867✔
3277
        goto abort;
×
3278
      }
3279
      break;
3,867✔
3280

3281
    case ARITH_BINEQ_ATOM:
761✔
3282
      // term (x == y): check whether x - y is a difference logic term
3283
      cmp = composite_for_idx(terms, idx);
761✔
3284
      assert(cmp->arity == 2);
3285
      if (! check_dl_eq_atom(ctx, cmp->arg[0], cmp->arg[1], idl)) {
761✔
3286
        goto abort;
×
3287
      }
3288
      break;
761✔
3289

3290
    default:
×
3291
      goto abort;
×
3292
    }
3293
  }
3294

3295
  return;
20,256✔
3296

3297
 abort:
×
3298
  code = idl ? FORMULA_NOT_IDL : FORMULA_NOT_RDL;
×
3299
  longjmp(ctx->env, code);
×
3300
}
3301

3302

3303
/*
3304
 * Check all terms in vector v
3305
 */
3306
static void analyze_diff_logic_vector(context_t *ctx, ivector_t *v, bool idl) {
105✔
3307
  uint32_t i, n;
3308

3309
  n = v->size;
105✔
3310
  for (i=0; i<n; i++) {
5,770✔
3311
    analyze_dl(ctx, v->data[i], idl);
5,665✔
3312
  }
3313
}
105✔
3314

3315

3316
/*
3317
 * Check difference logic after flattening:
3318
 * - check whether all formulas in top_eqs, top_atoms, and top_formulas
3319
 *   are in the difference logic fragment. If so, compute the benchmark
3320
 *   profile (i.e., statistics on number of variables + atoms)
3321
 * - if idl is true, all variables must be integer (i.e., the formula is
3322
 *   in the IDL fragment), otherwise all variables must be real (i.e., the
3323
 *   formula is in the RDL fragment).
3324
 *
3325
 * - if all assertions are in IDL or RDL.
3326
 *   the statistics are stored in ctx->dl_profile.
3327
 * - raise an exception (either FORMULA_NOT_IDL or FORMULA_NOT_RDL) otherwise.
3328
 *
3329
 * This function is used to decide whether to use simplex or a
3330
 * specialized solver when the architecture is CTX_AUTO_IDL or
3331
 * CTX_AUTO_RDL.  Because this function is called before the actual
3332
 * arithmetic solver is created, we assume that no arithmetic term is
3333
 * internalized, and that top_interns is empty.
3334
 */
3335
void analyze_diff_logic(context_t *ctx, bool idl) {
35✔
3336
  dl_data_t *stats;
3337
  int_rat_hmap_t *edges;
3338

3339
  assert(ctx->dl_profile == NULL && ctx->edge_map == NULL);
3340

3341
  // allocate and initialize dl_profile, edge_map, and cache
3342
  stats = context_get_dl_profile(ctx);
35✔
3343
  edges = context_get_edge_map(ctx);
35✔
3344
  (void) context_get_cache(ctx);
35✔
3345

3346
  analyze_diff_logic_vector(ctx, &ctx->top_eqs, idl);
35✔
3347
  analyze_diff_logic_vector(ctx, &ctx->top_atoms, idl);
35✔
3348
  analyze_diff_logic_vector(ctx, &ctx->top_formulas, idl);
35✔
3349

3350
  // compute the bound on path length
3351
  int_rat_hmap_sum(edges, &stats->path_bound);
35✔
3352

3353
#if (TRACE || TRACE_DL)
3354
  printf("==== Difference logic ====\n");
3355
  if (idl) {
3356
    printf("---> IDL\n");
3357
  } else {
3358
    printf("---> RDL\n");
3359
  }
3360
  printf("---> %"PRIu32" variables\n", stats->num_vars);
3361
  printf("---> %"PRIu32" atoms\n", stats->num_atoms);
3362
  printf("---> %"PRIu32" equalities\n", stats->num_eqs);
3363
  printf("---> path bound = ");
3364
  q_print(stdout, &stats->path_bound);
3365
  printf("\n");
3366
#endif
3367

3368
  context_free_cache(ctx);
35✔
3369
  context_free_edge_map(ctx);
35✔
3370
}
35✔
3371

3372

3373

3374
/*******************
3375
 *  CONDITIONALS   *
3376
 ******************/
3377

3378
/*
3379
 * Allocate a conditional descriptor from the store
3380
 */
3381
static conditional_t *new_conditional(context_t *ctx) {
5,261✔
3382
  conditional_t *d;
3383

3384
  d = objstore_alloc(&ctx->cstore);
5,261✔
3385
  init_conditional(d, ctx->terms);
5,261✔
3386
  return d;
5,261✔
3387
}
3388

3389
/*
3390
 * Free conditional descriptor d
3391
 */
3392
void context_free_conditional(context_t *ctx, conditional_t *d) {
5,261✔
3393
  delete_conditional(d);
5,261✔
3394
  objstore_free(&ctx->cstore, d);
5,261✔
3395
}
5,261✔
3396

3397
/*
3398
 * Attempt to convert an if-then-else term to a conditional
3399
 * - return NULL if the conversion fails
3400
 * - return a conditional descriptor otherwise
3401
 * - if NON-NULL, the result must be freed when no-longer used
3402
 *   by calling context_free_conditional
3403
 */
3404
conditional_t *context_make_conditional(context_t *ctx, composite_term_t *ite) {
5,261✔
3405
  conditional_t *d;
3406

3407
  assert(ite->arity == 3);
3408

3409
  d = new_conditional(ctx);
5,261✔
3410
  convert_ite_to_conditional(d, ite->arg[0], ite->arg[1], ite->arg[2]);
5,261✔
3411
  if (d->nconds <= 1) {
5,261✔
3412
    context_free_conditional(ctx, d);
4,997✔
3413
    d = NULL;
4,997✔
3414
  }
3415

3416
  return d;
5,261✔
3417
}
3418

3419

3420
/*
3421
 * Check whether conditional_t *d can be simplified
3422
 * - d is of the form
3423
 *    COND c1 --> a1
3424
 *         c2 --> a2
3425
 *         ...
3426
 *         else --> b
3427
 *    END
3428
 *   where c_1 ... c_n are pairwise disjoint
3429
 *
3430
 * - if one of c_i is true, the function returns a_i
3431
 * - if all c_i's are false, the function returns d
3432
 * - in all other cases, the function returns NULL_TERM
3433
 */
3434
term_t simplify_conditional(context_t *ctx, conditional_t *d) {
264✔
3435
  uint32_t i, n;
3436
  bool all_false;
3437
  term_t r, result;
3438

3439
  n = d->nconds;
264✔
3440
  all_false = true;
264✔
3441
  result = NULL_TERM;
264✔
3442

3443
  for (i=0; i<n; i++) {
855✔
3444
    r = intern_tbl_get_root(&ctx->intern, d->pair[i].cond);
609✔
3445
    if (term_is_true(ctx, r)) {
609✔
3446
      result = d->pair[i].val;
18✔
3447
      goto done;
18✔
3448
    }
3449
    all_false &= term_is_false(ctx, r);
591✔
3450
  }
3451

3452
  if (all_false) {
246✔
3453
    result = d->defval;
1✔
3454
  }
3455

3456
 done:
245✔
3457
  return result;
264✔
3458
}
3459

3460

3461
#if 0
3462

3463
/*
3464
 * FOR TESTING ONLY
3465
 */
3466

3467
/*
3468
 * Print result of conversion of t to a conditional structure
3469
 */
3470
static void print_conditional_conversion(conditional_t *d, term_t t) {
3471
  yices_pp_t pp;
3472
  pp_area_t area;
3473
  uint32_t i, n;
3474

3475
  area.width = 400;
3476
  area.height = 300;
3477
  area.offset = 0;
3478
  area.stretch = false;
3479
  area.truncate = true;
3480
  init_default_yices_pp(&pp, stdout, &area);
3481

3482
  pp_open_block(&pp, PP_OPEN);
3483
  pp_string(&pp, "Conversion to conditional for term");
3484
  pp_term_full(&pp, d->terms, t);
3485
  pp_close_block(&pp, false);
3486
  flush_yices_pp(&pp);
3487

3488
  pp_string(&pp, "result:");
3489
  flush_yices_pp(&pp);
3490

3491
  n = d->nconds;
3492
  for (i=0; i<n; i++) {
3493
    pp_open_block(&pp, PP_OPEN_ITE);
3494
    pp_term_full(&pp, d->terms, d->pair[i].cond);
3495
    pp_term_full(&pp, d->terms, d->pair[i].val);
3496
    pp_close_block(&pp, true);
3497
  }
3498

3499
  pp_open_block(&pp, PP_OPEN_PAR);
3500
  pp_string(&pp, "else");
3501
  pp_term_full(&pp, d->terms, d->defval);
3502
  pp_close_block(&pp, true);
3503

3504
  delete_yices_pp(&pp, true);
3505
}
3506

3507
/*
3508
 * Try to flatten an ite term t into a conditional
3509
 * - if that works print the result
3510
 */
3511
void context_test_conditional_for_ite(context_t *ctx, composite_term_t *ite, term_t t) {
3512
  conditional_t condi;
3513

3514
  init_conditional(&condi, ctx->terms);
3515
  convert_ite_to_conditional(&condi, ite->arg[0], ite->arg[1], ite->arg[2]);
3516

3517
  if (condi.nconds > 1) {
3518
    print_conditional_conversion(&condi, t);
3519
  }
3520

3521
  delete_conditional(&condi);
3522
}
3523

3524

3525
#endif
3526

3527

3528
/****************************************************
3529
 *  SIMPLIFICATIONS FOR SPECIAL IF-THEN-ELSE TERMS  *
3530
 ***************************************************/
3531

3532
/*
3533
 * If t is (ite c a b), we can try to rewrite (= t k) into a conjunction
3534
 * of terms using the two rules:
3535
 *   (= (ite c a b) k) --> c and (= a k)        if k != b holds
3536
 *   (= (ite c a b) k) --> (not c) and (= b k)  if k != a holds
3537
 *
3538
 * This works best for the NEC benchmarks in SMT LIB, where many terms
3539
 * are deeply nested if-then-else terms with constant leaves.
3540
 *
3541
 * The function below does that: it rewrites (eq t k) to (and c_0 ... c_n (eq t' k))
3542
 * - the boolean terms c_0 ... c_n are added to vector v
3543
 * - the term t' is returned
3544
 * So the simplification worked it the returned term t' is different from t
3545
 * (and then v->size is not 0).
3546
 */
3547
term_t flatten_ite_equality(context_t *ctx, ivector_t *v, term_t t, term_t k) {
113,638✔
3548
  term_table_t *terms;
3549
  composite_term_t *ite;
3550

3551
  terms = ctx->terms;
113,638✔
3552
  assert(is_pos_term(t) && good_term(terms, t));
3553

3554
  while (is_ite_term(terms, t)) {
838,926✔
3555
    // t is (ite c a b)
3556
    ite = ite_term_desc(terms, t);
769,852✔
3557
    assert(ite->arity == 3);
3558

3559
    if (disequal_terms(terms, k, ite->arg[1], true)) {
769,852✔
3560
      // (t == k) is (not c) and (t == b)
3561
      ivector_push(v, opposite_term(ite->arg[0]));
709,356✔
3562
      t = intern_tbl_get_root(&ctx->intern, ite->arg[2]);
709,356✔
3563

3564
    } else if (disequal_terms(terms, k, ite->arg[2], true)) {
60,496✔
3565
      // (t == k) is c and (t == a)
3566
      ivector_push(v, ite->arg[0]);
15,932✔
3567
      t = intern_tbl_get_root(&ctx->intern, ite->arg[1]);
15,932✔
3568

3569
    } else {
3570
      // no more flattening possible
3571
      break;
44,564✔
3572
    }
3573
  }
3574

3575
  return t;
113,638✔
3576
}
3577

3578

3579

3580

3581

3582

3583

3584
/***********************
3585
 *  SYMMETRY BREAKING  *
3586
 **********************/
3587

3588
#if TRACE_SYM_BREAKING
3589

3590
static void show_constant_set(yices_pp_t *pp, term_table_t *terms, rng_record_t *r) {
3591
  uint32_t i, n;
3592

3593
  n = r->num_constants;
3594
  pp_open_block(pp, PP_OPEN);
3595
  for (i=0; i<n; i++) {
3596
    pp_term(pp, terms, r->cst[i]);
3597
  }
3598
  pp_close_block(pp, false);
3599
}
3600

3601
static void pp_constraints(yices_pp_t *pp, sym_breaker_t *breaker, rng_record_t *r) {
3602
  uint32_t i, j, n;
3603

3604
  n = r->num_terms;
3605
  for (i=0; i<n; i++) {
3606
    j = r->idx[i];
3607
    pp_open_block(pp, PP_OPEN);
3608
    pp_string(pp, "Formula ");
3609
    pp_uint32(pp, j);
3610
    pp_close_block(pp, false);
3611
    flush_yices_pp(pp);
3612

3613
    pp_term_full(pp, breaker->terms, breaker->ctx->top_formulas.data[j]);
3614
    flush_yices_pp(pp);
3615

3616
    pp_open_block(pp, PP_OPEN);
3617
    pp_string(pp, "constraint on term ");
3618
    pp_term_full(pp, breaker->terms, r->trm[i]);
3619
    pp_close_block(pp, false);
3620
    flush_yices_pp(pp);
3621
    flush_yices_pp(pp);
3622
  }
3623
}
3624

3625
static void show_range_constraints(sym_breaker_t *breaker) {
3626
  yices_pp_t pp;
3627
  pp_area_t area;
3628
  rng_record_t **v;
3629
  uint32_t i, n;
3630

3631
  area.width = 150;
3632
  area.height = 30;
3633
  area.offset = 0;
3634
  area.stretch = false;
3635
  area.truncate = true;
3636
  init_default_yices_pp(&pp, stdout, &area);
3637

3638
  v = breaker->sorted_constraints;
3639
  n = breaker->num_constraints;
3640
  for (i=0; i<n; i++) {
3641
    pp_open_block(&pp, PP_OPEN);
3642
    pp_string(&pp, "Range constraints for set: ");
3643
    show_constant_set(&pp, breaker->terms, v[i]);
3644
    pp_close_block(&pp, false);
3645
    flush_yices_pp(&pp);
3646
    flush_yices_pp(&pp);
3647
    pp_constraints(&pp, breaker, v[i]);
3648
  }
3649

3650
  delete_yices_pp(&pp, true);
3651
}
3652

3653
static void print_constant_set(sym_breaker_t *breaker, rng_record_t *r) {
3654
  uint32_t i, n;
3655

3656
  n = r->num_constants;
3657
  for (i=0; i<n; i++) {
3658
    fputc(' ', stdout);
3659
    print_term(stdout, breaker->terms, r->cst[i]);
3660
  }
3661
}
3662

3663
static void print_candidates(sym_breaker_t *breaker, sym_breaker_sets_t *sets) {
3664
  uint32_t i, n;
3665

3666
  printf("--- Candidates ---\n");
3667
  n = sets->num_candidates;
3668
  for (i=0; i<n; i++) {
3669
    printf("   ");
3670
    print_term_full(stdout, breaker->terms, sets->candidates[i]);
3671
    printf("\n");
3672
  }
3673
}
3674

3675
#endif
3676

3677

3678
/*
3679
 * Break symmetries
3680
 */
3681
void break_uf_symmetries(context_t *ctx) {
30✔
3682
  sym_breaker_t *breaker;
3683
  sym_breaker_sets_t *sets;
3684
  rng_record_t **v;
3685
  uint32_t i, j, n;
3686

3687
  breaker = objstack_alloc(&ctx->ostack, sizeof(sym_breaker_t), (cleaner_t) delete_sym_breaker);
30✔
3688
  init_sym_breaker(breaker, ctx);
30✔
3689
  collect_range_constraints(breaker);
30✔
3690

3691
#if TRACE_SYM_BREAKING
3692
  show_range_constraints(breaker);
3693
#endif
3694

3695
  v = breaker->sorted_constraints;
30✔
3696
  n = breaker->num_constraints;
30✔
3697
  if (n > 0) {
30✔
3698
    // test of symmetry breaking
3699
    sets = &breaker->sets;
11✔
3700
    for (i=0; i<n; i++) {
61✔
3701
      if (check_assertion_invariance(breaker, v[i])) {
50✔
3702
#if TRACE_SYM_BREAKING
3703
        printf("Breaking symmetries using set[%"PRIu32"]:", i);
3704
        print_constant_set(breaker, v[i]);
3705
        printf("\n");
3706
#endif
3707
        breaker_sets_copy_record(sets, v[i]);
9✔
3708
        for (j=i+1; j<n; j++) {
44✔
3709
          if (range_record_subset(v[j], v[i])) {
35✔
3710
#if TRACE_SYM_BREAKING
3711
            printf("Adding set[%"PRIu32"]:", j);
3712
            print_constant_set(breaker, v[j]);
3713
            printf("\n");
3714
#endif
3715
            breaker_sets_add_record(sets, v[j]);
34✔
3716
          }
3717
        }
3718
#if TRACE_SYM_BREAKING
3719
        print_candidates(breaker, sets);
3720
        printf("\n");
3721
#endif
3722
        break_symmetries(breaker, sets);
9✔
3723
      } else {
3724
#if TRACE_SYM_BREAKING
3725
        printf("Set[%"PRIu32"]:", i);
3726
        print_constant_set(breaker, v[i]);
3727
        printf(" not symmetrical\n\n");
3728
#endif
3729
      }
3730
    }
3731

3732
  } else {
3733
#if TRACE_SYM_BREAKING
3734
    printf("\n*** NO SYMMETRY CANDIDATES ***\n\n");
3735
#endif
3736
  }
3737

3738
  //  delete_sym_breaker(breaker);
3739
  objstack_pop(&ctx->ostack);
30✔
3740
}
30✔
3741

3742

3743

3744

3745
/******************************
3746
 *  CONDITIONAL DEFINITIONS   *
3747
 *****************************/
3748

3749
void process_conditional_definitions(context_t *ctx) {
52✔
3750
  cond_def_collector_t *collect;
3751
  ivector_t *v;
3752
  uint32_t i, n;
3753

3754
  v = &ctx->top_formulas;
52✔
3755
  n = v->size;
52✔
3756
  if (n > 0) {
52✔
3757
    collect = objstack_alloc(&ctx->ostack, sizeof(cond_def_collector_t),
44✔
3758
                             (cleaner_t) delete_cond_def_collector);
3759
    init_cond_def_collector(collect, ctx);
44✔
3760
    for (i=0; i<n; i++) {
3,517✔
3761
      extract_conditional_definitions(collect, v->data[i]);
3,473✔
3762
    }
3763
    analyze_conditional_definitions(collect);
44✔
3764
    //    delete_cond_def_collector(&collect);
3765
    objstack_pop(&ctx->ostack);
44✔
3766
  }
3767
}
52✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc