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

SRI-CSL / yices2 / 9226448713

24 May 2024 03:34PM UTC coverage: 65.988% (+0.3%) from 65.728%
9226448713

Pull #513

github

web-flow
Merge da66d3d5d into f06761440
Pull Request #513: Finite Field support

2396 of 3347 new or added lines in 66 files covered. (71.59%)

18 existing lines in 12 files now uncovered.

81769 of 123915 relevant lines covered (65.99%)

1493770.28 hits per line

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

88.3
/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) {
33,128✔
84
  select_term_t *sel;
85
  term_t t;
86

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

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

97
  terms = ctx->terms;
6,489✔
98
  t = arith_ge_arg(terms, r);
6,489✔
99
  t = intern_tbl_get_root(&ctx->intern, t);
6,489✔
100
  if (is_ite_term(terms, t)) {
6,489✔
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;
6,488✔
122
}
123

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

129
  terms = ctx->terms;
2,210✔
130
  t = arith_eq_arg(terms, r);
2,210✔
131
  t = intern_tbl_get_root(&ctx->intern, t);
2,210✔
132
  if (is_ite_term(terms, t)) {
2,210✔
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,209✔
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,295✔
179
  term_table_t *terms;
180
  composite_term_t *d;
181
  term_t x, y;
182

183
  terms = ctx->terms;
4,295✔
184
  if (is_ite_term(terms, t1)) {
4,295✔
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,295✔
203
    // symmetric case
204
    d = ite_term_desc(terms, t2);
464✔
205
    x = intern_tbl_get_root(&ctx->intern, d->arg[1]);
464✔
206
    y = intern_tbl_get_root(&ctx->intern, d->arg[2]);
464✔
207

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

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

217
  return NULL_TERM;
4,293✔
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,515✔
222
  if (term_is_true(ctx, t1)) return t2;  // (eq true t2) --> t2
6,515✔
223
  if (term_is_true(ctx, t2)) return t1;  // (eq t1 true) --> t1
6,417✔
224
  if (term_is_false(ctx, t1)) return opposite_term(t2); // (eq false t2) --> not t2
6,413✔
225
  if (term_is_false(ctx, t2)) return opposite_term(t1); // (eq t1 false) --> not t1
6,332✔
226

227
  return NULL_TERM;
6,329✔
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) {
37,436✔
236
  term_table_t *terms;
237
  term_t t;
238

239
  terms = ctx->terms;
37,436✔
240
  if (t1 == t2) {
37,436✔
241
    t = true_term;
1✔
242
  } else if (disequal_bitvector_terms(terms, t1, t2)) {
37,435✔
243
    t = false_term;
24✔
244
  } else {
245
    t = simplify_bveq(terms, t1, t2);
37,411✔
246
  }
247

248
  return t;
37,436✔
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) {
15,128✔
262
  term_table_t *terms;
263
  bvpoly_buffer_t *b;
264
  uint32_t n;
265
  term_t u1, u2;
266

267
  terms = ctx->terms;
15,128✔
268

269
  r->code = BVEQ_CODE_NOCHANGE;
15,128✔
270

271
  if (is_bvpoly_term(terms, t1) || is_bvpoly_term(terms, t2)) {
15,128✔
272
    b = context_get_bvpoly_buffer(ctx);
6,008✔
273
    n = term_bitsize(terms, t1);
6,008✔
274

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

280
    if (bvpoly_buffer_is_zero(b)) {
6,008✔
281
      r->code = BVEQ_CODE_TRUE;
×
282
    } else if (bvpoly_buffer_is_constant(b)) {
6,008✔
283
      r->code = BVEQ_CODE_FALSE;
×
284
    } else if (bvpoly_buffer_is_pm_var(b, &u1)) {
6,008✔
285
      r->code = BVEQ_CODE_REDUCED0;
41✔
286
      r->left = u1;
41✔
287
      r->right = NULL_TERM;
41✔
288
    } else if (bvpoly_buffer_is_var_minus_var(b, &u1, &u2)) {
5,967✔
289
      r->code = BVEQ_CODE_REDUCED;
46✔
290
      r->left = u1;
46✔
291
      r->right = u2;
46✔
292
    }
293
  }
294
}
15,128✔
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) {
7,420✔
373
  r->code = BVFACTOR_TODO;
7,420✔
374
  r->bitsize = 0;
7,420✔
375
  r->poly_buffer = NULL;
7,420✔
376
  r->pp_buffer = NULL;
7,420✔
377
}
7,420✔
378

379

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

386
  if (r->code != BVFACTOR_TODO) {
7,420✔
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) {
7,420✔
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) {
7,420✔
404
    delete_pp_buffer(r->pp_buffer);
16✔
405
    safe_free(r->pp_buffer);
16✔
406
    r->pp_buffer = NULL;
16✔
407
  }
408
}
7,420✔
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) {
7,420✔
1001
  term_table_t *terms;
1002
  bool t1_is_prod, t2_is_prod;
1003

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

1008
  if (t1_is_prod && t2_is_prod) {
7,420✔
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)) {
7,409✔
1023
    try_common_factors(r, terms);
3✔
1024

1025
  } else if (t2_is_prod && try_term_poly_factoring(r, terms, t2, t1)) {
7,406✔
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,950✔
1036
  bvfactoring_t *factoring;
1037
  bool eq;
1038

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

1047
  return eq;
4,950✔
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) {
7,772✔
1119
  intern_tbl_t *intern;
1120

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

1123
  intern = &ctx->intern;
7,772✔
1124
  if (is_constant_term(ctx->terms, t2)) {
7,772✔
1125
    if (intern_tbl_valid_const_subst(intern, t1, t2)) {
916✔
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);
916✔
1135
    } else {
1136
      // unsat by type incompatibility
1137
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1138
    }
1139
  } else if (intern_tbl_sound_subst(intern, t1, t2)) {
6,856✔
1140
    ivector_push(&ctx->subst_eqs, e);
6,853✔
1141
  } else {
1142
    // can't substitute
1143
    ivector_push(&ctx->top_eqs, e);
3✔
1144
  }
1145
}
7,772✔
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) {
17,873✔
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
  if (context_var_elim_enabled(ctx)) {
17,873✔
1165
    intern = &ctx->intern;
13,039✔
1166

1167
    free1 = intern_tbl_root_is_free(intern, t1);
13,039✔
1168
    free2 = intern_tbl_root_is_free(intern, t2);
13,039✔
1169

1170
    if (free1 && free2) {
13,039✔
1171
      intern_tbl_merge_classes(intern, t1, t2);
541✔
1172
      return;
541✔
1173
    }
1174

1175
    if (free1) {
12,498✔
1176
      process_candidate_subst(ctx, t1, t2, e);
5,924✔
1177
      return;
5,924✔
1178
    }
1179

1180
    if (free2) {
6,574✔
1181
      process_candidate_subst(ctx, t2, t1, e);
1,848✔
1182
      return;
1,848✔
1183
    }
1184
  }
1185

1186
  // no substitution: record e as a top-equality
1187
  ivector_push(&ctx->top_eqs, e);
9,560✔
1188
}
1189

1190

1191
/*
1192
 * Attempt to turn (eq t1 t2) into a variable substitution
1193
 * - both t1 and t2 are boolean root terms in the internalization table
1194
 * - e is a term equivalent to (eq t1 t2)
1195
 * - neither t1 nor t2 are constant
1196
 */
1197
static void try_bool_substitution(context_t *ctx, term_t t1, term_t t2, term_t e) {
3,611✔
1198
  intern_tbl_t *intern;
1199
  bool free1, free2;
1200

1201
  assert(term_is_true(ctx, e));
1202

1203
  if (context_var_elim_enabled(ctx)) {
3,611✔
1204
    intern = &ctx->intern;
1,757✔
1205

1206
    free1 = intern_tbl_root_is_free(intern, t1);
1,757✔
1207
    free2 = intern_tbl_root_is_free(intern, t2);
1,757✔
1208

1209
    if (free1 && free2) {
1,757✔
1210
      /*
1211
       * Both t1 and t2 are free
1212
       */
1213
      intern_tbl_merge_classes(intern, t1, t2);
39✔
1214
      return;
39✔
1215
    }
1216

1217
    if (free1 || free2) {
1,718✔
1218
      /*
1219
       * Only one is free: save e in subst_eqs for future processing
1220
       */
1221
      ivector_push(&ctx->subst_eqs, e);
841✔
1222
      return;
841✔
1223
    }
1224
  }
1225

1226
  // no substitution
1227
  //  ivector_push(&ctx->top_eqs, e);
1228
  ivector_push(&ctx->top_formulas, e);
2,731✔
1229
}
1230

1231

1232

1233
/*
1234
 * VARIABLE ELIMINATION: PHASE 2
1235
 */
1236

1237
/*
1238
 * Check whether x is already mapped in the candidate substitution
1239
 * - if not, store [x := t] as a candidate
1240
 * - otherwise, add e to the top_eqs vector
1241
 */
1242
static void try_pseudo_subst(context_t *ctx, pseudo_subst_t *subst, term_t x, term_t t, term_t e) {
7,662✔
1243
  subst_triple_t *s;
1244

1245
  assert(is_pos_term(x) && intern_tbl_root_is_free(&ctx->intern, x) && term_is_true(ctx, e));
1246

1247
  s = pseudo_subst_get(subst, x);
7,662✔
1248
  assert(s->var == x);
1249
  if (s->map == NULL_TERM) {
7,662✔
1250
    // x := t is a candidate
1251
    assert(s->eq == NULL_TERM);
1252
    s->map = t;
7,370✔
1253
    s->eq = e;
7,370✔
1254

1255
#if TRACE_SUBST
1256
    printf("Add subst candidate ");
1257
    print_term_desc(stdout, ctx->terms, x);
1258
    printf(" := ");;
1259
    print_term_desc(stdout, ctx->terms, t);
1260
    printf(" by assertion ");
1261
    print_term_desc(stdout, ctx->terms, e);
1262
    printf("\n");
1263
    fflush(stdout);
1264
#endif
1265

1266
  } else {
1267
    ivector_push(&ctx->top_eqs, e);
292✔
1268
  }
1269
}
7,662✔
1270

1271
/*
1272
 * Check whether (eq t1 t2) can still be turned into a substitution (X := term)
1273
 * - if so add the candidate substitution [X --> term] to subst
1274
 * - otherwise, move e to the top-level equalities
1275
 * - both t1 and t2 are root terms in the internalization table
1276
 * - e is equivalent to (eq t1 t2))
1277
 * - t1 and t2 are not boolean terms
1278
 */
1279
static void check_candidate_subst(context_t *ctx, pseudo_subst_t *subst, term_t t1, term_t t2, term_t e) {
6,853✔
1280
  assert(is_pos_term(t1) && is_pos_term(t2) && term_is_true(ctx, e));
1281

1282
  if (intern_tbl_root_is_free(&ctx->intern, t1)) {
6,853✔
1283
    try_pseudo_subst(ctx, subst, t1, t2, e);
4,995✔
1284
  } else if (intern_tbl_root_is_free(&ctx->intern, t2)) {
1,858✔
1285
    try_pseudo_subst(ctx, subst, t2, t1, e);
1,836✔
1286
  } else {
1287
    ivector_push(&ctx->top_eqs, e);
22✔
1288
  }
1289
}
6,853✔
1290

1291

1292

1293
/*
1294
 * Same thing for an equality between booleans terms
1295
 */
1296
static void check_candidate_bool_subst(context_t *ctx, pseudo_subst_t *subst, term_t t1, term_t t2, term_t e) {
841✔
1297
  assert(is_boolean_term(ctx->terms, t1) && is_boolean_term(ctx->terms, t2) && term_is_true(ctx, e));
1298

1299
  if (intern_tbl_root_is_free(&ctx->intern, t1)) {
841✔
1300
    // if t1 is (not u1), rewrite to (u1 == not t2)
1301
    t2 ^= polarity_of(t1);
824✔
1302
    t1 = unsigned_term(t1);
824✔
1303
    try_pseudo_subst(ctx, subst, t1, t2, e);
824✔
1304
  } else if (intern_tbl_root_is_free(&ctx->intern, t2)) {
17✔
1305
    // fix polarities too
1306
    t1 ^= polarity_of(t2);
7✔
1307
    t2 = unsigned_term(t2);
7✔
1308
    try_pseudo_subst(ctx, subst, t2, t1, e);
7✔
1309
  } else {
1310
    ivector_push(&ctx->top_eqs, e);
10✔
1311
  }
1312
}
841✔
1313

1314

1315
/*
1316
 * Process all elements in subst_eqs:
1317
 * - turn them into substitution candidates or move them to top_eqs
1318
 */
1319
static void process_subst_eqs(context_t *ctx, pseudo_subst_t *subst) {
4,092✔
1320
  term_table_t *terms;
1321
  ivector_t *subst_eqs;
1322
  composite_term_t *eq;
1323
  term_t e, t1, t2;
1324
  uint32_t i, n;
1325

1326
  terms = ctx->terms;
4,092✔
1327
  subst_eqs = &ctx->subst_eqs;
4,092✔
1328

1329
  n = subst_eqs->size;
4,092✔
1330
  for (i=0; i<n; i++) {
11,786✔
1331
    e = subst_eqs->data[i];
7,694✔
1332
    assert(term_is_true(ctx, e));
1333

1334
    switch (term_kind(terms, e)) {
7,694✔
1335
    case EQ_TERM:
7,694✔
1336
    case ARITH_BINEQ_ATOM:
1337
    case BV_EQ_ATOM:
1338
      eq = composite_term_desc(terms, e);
7,694✔
1339
      assert(eq->arity == 2);
1340
      t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
7,694✔
1341
      t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
7,694✔
1342

1343
      if (is_boolean_term(terms, t1)) {
7,694✔
1344
        /*
1345
         * e was asserted true
1346
         * it's either (eq t1 t2) or (not (eq t1 t2))
1347
         * in the latter case, we use the equivalence
1348
         *  (not (eq t1 t2)) <--> (eq t1 (not t2))
1349
         * i.e., we flip t2's polarity if e has negative polarity
1350
         */
1351
        t2 ^= polarity_of(e);
841✔
1352
        check_candidate_bool_subst(ctx, subst, t1, t2, e);
841✔
1353
      } else {
1354
        /*
1355
         * e is (eq t1 t2) for two non-boolean terms t1 and t2
1356
         */
1357
        assert(is_pos_term(e));
1358
        check_candidate_subst(ctx, subst, t1, t2, e);
6,853✔
1359
      }
1360
      break;
7,694✔
1361

1362
    default:
×
1363
      assert(false);
1364
      break;
×
1365
    }
1366
  }
1367
}
4,092✔
1368

1369

1370
/*
1371
 * VARIABLE ELIMINATION PHASE 3: CYCLE REMOVAL
1372
 */
1373

1374
/*
1375
 * We use a depth-first search in the dependency graph:
1376
 * - vertices are terms,
1377
 * - edges are of two forms:
1378
 *    t --> u if u is a child subterm of t
1379
 *    x := t  if x is a variable and t is the substitution candidate for x
1380
 *
1381
 * By construction, the graph restricted to edges t --> u (without the
1382
 * substitution edges) is a DAG. So we can remove cycles by removing some
1383
 * substitution edges x := t.
1384
 */
1385

1386
/*
1387
 * Substitution candidate for term t:
1388
 * - return NULL_TERM if there's no candidate
1389
 */
1390
static term_t subst_candidate(context_t *ctx, term_t t) {
18,420✔
1391
  subst_triple_t *s;
1392

1393
  assert(ctx->subst != NULL);
1394
  s = pseudo_subst_find(ctx->subst, t);
18,420✔
1395
  if (s == NULL) {
18,420✔
1396
    return NULL_TERM;
11,050✔
1397
  } else {
1398
    assert(s->var == t);
1399
    return s->map;
7,370✔
1400
  }
1401
}
1402

1403

1404
/*
1405
 * Remove substitution candidate for t
1406
 */
1407
static void remove_subst_candidate(context_t *ctx, term_t t) {
207✔
1408
  subst_triple_t *s;
1409

1410
  assert(ctx->subst != NULL);
1411
  s = pseudo_subst_find(ctx->subst, t);
207✔
1412
  assert(s != NULL && s->var == t && s->map != NULL_TERM);
1413

1414
#if TRACE_SUBST
1415
  printf("Removing subst candidate ");
1416
  print_term_desc(stdout, ctx->terms, t);
1417
  printf(" := ");;
1418
  print_term_desc(stdout, ctx->terms, s->map);
1419
  printf("\n");
1420
  fflush(stdout);
1421
#endif
1422

1423
  s->map = NULL_TERM;
207✔
1424
}
207✔
1425

1426

1427
/*
1428
 * Visit t: return true if t is on a cycle.
1429
 */
1430
static bool visit(context_t *ctx, term_t t);
1431

1432
static bool visit_composite(context_t *ctx, composite_term_t *c) {
37,147✔
1433
  uint32_t i, n;
1434

1435
  n = c->arity;
37,147✔
1436
  for (i=0; i<n; i++) {
734,387✔
1437
    if (visit(ctx, c->arg[i])) {
697,472✔
1438
      return true;
232✔
1439
    }
1440
  }
1441

1442
  return false;
36,915✔
1443
}
1444

1445
static bool visit_pprod(context_t *ctx, pprod_t *p) {
13✔
1446
  uint32_t i, n;
1447

1448
  n = p->len;
13✔
1449
  for (i=0; i<n; i++) {
33✔
1450
    if (visit(ctx, p->prod[i].var)) {
23✔
1451
      return true;
3✔
1452
    }
1453
  }
1454

1455
  return false;
10✔
1456
}
1457

1458
static bool visit_arith_poly(context_t *ctx, polynomial_t *p) {
783✔
1459
  monomial_t *m;
1460
  uint32_t i, n;
1461

1462
  m = p->mono;
783✔
1463
  n = p->nterms;
783✔
1464
  assert(n > 0);
1465
  // skip constant marker
1466
  if (m[0].var == const_idx) {
783✔
1467
    m++;
459✔
1468
    n--;
459✔
1469
  }
1470

1471
  for (i=0; i<n; i++) {
2,448✔
1472
    if (visit(ctx, m[i].var)) {
1,665✔
1473
      return true;
×
1474
    }
1475
  }
1476

1477
  return false;
783✔
1478
}
1479

1480
static bool visit_bv_poly(context_t *ctx, bvpoly_t *p) {
25✔
1481
  bvmono_t *m;
1482
  uint32_t i, n;
1483

1484
  m = p->mono;
25✔
1485
  n = p->nterms;
25✔
1486
  assert(n > 0);
1487
  // skip constant marker
1488
  if (m[0].var == const_idx) {
25✔
1489
    m++;
5✔
1490
    n--;
5✔
1491
  }
1492

1493
  for (i=0; i<n; i++) {
63✔
1494
    if (visit(ctx, m[i].var)) {
39✔
1495
      return true;
1✔
1496
    }
1497
  }
1498

1499
  return false;
24✔
1500
}
1501

1502

1503
static bool visit_bv64_poly(context_t *ctx, bvpoly64_t *p) {
229✔
1504
  bvmono64_t *m;
1505
  uint32_t i, n;
1506

1507
  m = p->mono;
229✔
1508
  n = p->nterms;
229✔
1509
  assert(n > 0);
1510
  // skip constant marker
1511
  if (m[0].var == const_idx) {
229✔
1512
    m++;
167✔
1513
    n--;
167✔
1514
  }
1515

1516
  for (i=0; i<n; i++) {
502✔
1517
    if (visit(ctx, m[i].var)) {
276✔
1518
      return true;
3✔
1519
    }
1520
  }
1521

1522
  return false;
226✔
1523
}
1524

1525

1526
static bool visit(context_t *ctx, term_t t) {
1,189,959✔
1527
  term_table_t *terms;
1528
  term_t r;
1529
  int32_t i;
1530
  bool result;
1531
  uint8_t color;
1532

1533
  assert(ctx->marks != NULL);
1534
  i = index_of(t);
1,189,959✔
1535
  color = mark_vector_get_mark(ctx->marks, i);
1,189,959✔
1536

1537
  if (color == WHITE) {
1,189,959✔
1538
    /*
1539
     * i not visited yet
1540
     */
1541
    terms = ctx->terms;
544,080✔
1542
    mark_vector_add_mark(ctx->marks, i, GREY);
544,080✔
1543

1544
    switch (kind_for_idx(terms, i)) {
544,080✔
1545
    case CONSTANT_TERM:
10,199✔
1546
    case ARITH_CONSTANT:
1547
    case BV64_CONSTANT:
1548
    case BV_CONSTANT:
1549
    case VARIABLE:
1550
      result = false;
10,199✔
1551
      break;
10,199✔
1552

1553
    case UNINTERPRETED_TERM:
26,583✔
1554
      r = intern_tbl_get_root(&ctx->intern, t);
26,583✔
1555
      if (r != t) {
26,583✔
1556
        result = visit(ctx, r);
8,163✔
1557
      } else {
1558
        r = subst_candidate(ctx, pos_term(i));
18,420✔
1559
        if (r != NULL_TERM && visit(ctx, r)) {
18,420✔
1560
          /*
1561
           * There's a cycle u --> ... --> t := r --> ... --> u
1562
           * remove the substitution t := r to break the cycle
1563
           */
1564
          remove_subst_candidate(ctx, pos_term(i));
207✔
1565
        }
1566
        result = false;
18,420✔
1567
      }
1568
      break;
26,583✔
1569

1570
    case ARITH_EQ_ATOM:
727✔
1571
    case ARITH_GE_ATOM:
1572
    case ARITH_IS_INT_ATOM:
1573
    case ARITH_FLOOR:
1574
    case ARITH_CEIL:
1575
    case ARITH_ABS:
1576
      result = visit(ctx, integer_value_for_idx(terms, i));
727✔
1577
      break;
727✔
1578

1579
    case ITE_TERM:
37,147✔
1580
    case ITE_SPECIAL:
1581
    case APP_TERM:
1582
    case UPDATE_TERM:
1583
    case TUPLE_TERM:
1584
    case EQ_TERM:
1585
    case DISTINCT_TERM:
1586
    case FORALL_TERM:
1587
    case LAMBDA_TERM:
1588
    case OR_TERM:
1589
    case XOR_TERM:
1590
    case ARITH_BINEQ_ATOM:
1591
    case ARITH_RDIV:
1592
    case ARITH_IDIV:
1593
    case ARITH_MOD:
1594
    case ARITH_DIVIDES_ATOM:
1595
    case BV_ARRAY:
1596
    case BV_DIV:
1597
    case BV_REM:
1598
    case BV_SDIV:
1599
    case BV_SREM:
1600
    case BV_SMOD:
1601
    case BV_SHL:
1602
    case BV_LSHR:
1603
    case BV_ASHR:
1604
    case BV_EQ_ATOM:
1605
    case BV_GE_ATOM:
1606
    case BV_SGE_ATOM:
1607
      result = visit_composite(ctx, composite_for_idx(terms, i));
37,147✔
1608
      break;
37,147✔
1609

1610
    case SELECT_TERM:
468,374✔
1611
    case BIT_TERM:
1612
      result = visit(ctx, select_for_idx(terms, i)->arg);
468,374✔
1613
      break;
468,374✔
1614

1615
    case POWER_PRODUCT:
13✔
1616
      result = visit_pprod(ctx, pprod_for_idx(terms, i));
13✔
1617
      break;
13✔
1618

1619
    case ARITH_POLY:
783✔
1620
      result = visit_arith_poly(ctx, polynomial_for_idx(terms, i));
783✔
1621
      break;
783✔
1622

1623
    case BV64_POLY:
229✔
1624
      result = visit_bv64_poly(ctx, bvpoly64_for_idx(terms, i));
229✔
1625
      break;
229✔
1626

1627
    case BV_POLY:
25✔
1628
      result = visit_bv_poly(ctx, bvpoly_for_idx(terms, i));
25✔
1629
      break;
25✔
1630

1631
    case UNUSED_TERM:
×
1632
    case RESERVED_TERM:
1633
    default:
1634
      assert(false);
1635
      longjmp(ctx->env, INTERNAL_ERROR);
×
1636
      break;
1637
    }
1638

1639
    if (result) {
544,080✔
1640
      /*
1641
       * t is on a cycle of grey terms:
1642
       *  v --> .. x := u --> ... --> t --> ... --> v
1643
       * all terms on the cycle must be cleared except v
1644
       */
1645
      mark_vector_add_mark(ctx->marks, i, WHITE);
246✔
1646
    } else {
1647
      // no cycle containing t: mark i black
1648
      mark_vector_add_mark(ctx->marks, i, BLACK);
543,834✔
1649
    }
1650

1651
  } else {
1652
    /*
1653
     * i already visited before
1654
     * - if it's black there's no cycle
1655
     * - if it's grey, we've just detected a cycle
1656
     */
1657
    assert(color == GREY || color == BLACK);
1658
    result = (color == GREY);
645,879✔
1659
  }
1660

1661
  return result;
1,189,959✔
1662
}
1663

1664

1665
/*
1666
 * Iterator for remove cycle:
1667
 * - s is a triple [x, t, e] for a candidate substitution x := t
1668
 */
1669
static void visit_subst_candidate(context_t *ctx, subst_triple_t *s) {
7,370✔
1670
  term_t x;
1671

1672
  x = s->var;
7,370✔
1673
  assert(intern_tbl_is_root(&ctx->intern, x) && intern_tbl_root_is_free(&ctx->intern, x));
1674
  if (mark_vector_get_mark(ctx->marks, index_of(x)) == WHITE) {
7,370✔
1675
    (void) visit(ctx, x);
5,850✔
1676
  }
1677
}
7,370✔
1678

1679

1680
/*
1681
 * Remove cycles in the candidate substitutions
1682
 */
1683
static void remove_subst_cycles(context_t *ctx) {
4,092✔
1684
  pseudo_subst_iterate(ctx->subst, ctx, (pseudo_subst_iterator_t) visit_subst_candidate);
4,092✔
1685
}
4,092✔
1686

1687

1688
/*
1689
 * Iterator for finalize subst:
1690
 * - s is a triple [x, t, e]
1691
 * - if t is NULL_TERM, that's no longer a good substitution: add e to top_eqs
1692
 * - otherwise add x := t as a substitution in the internalization table
1693
 */
1694
static void finalize_subst_triple(context_t *ctx, subst_triple_t *s) {
7,370✔
1695
  assert(s->eq != NULL_TERM && term_is_true(ctx, s->eq));
1696

1697
  if (s->map != NULL_TERM) {
7,370✔
1698
    intern_tbl_add_subst(&ctx->intern, s->var, s->map);
7,163✔
1699
  } else {
1700
    ivector_push(&ctx->top_eqs, s->eq);
207✔
1701
  }
1702
}
7,370✔
1703

1704

1705
/*
1706
 * Finalize all candidate substitutions
1707
 */
1708
static void finalize_subst_candidates(context_t *ctx) {
4,092✔
1709
  pseudo_subst_iterate(ctx->subst, ctx, (pseudo_subst_iterator_t) finalize_subst_triple);
4,092✔
1710
}
4,092✔
1711

1712

1713

1714

1715

1716

1717

1718
/***************************
1719
 *  ASSERTION FLATTENING   *
1720
 **************************/
1721

1722
/*
1723
 * Assertions are processed by performing top-down boolean propagation
1724
 * and collecting all subterms that can't be flattened into four vectors:
1725
 *
1726
 * 1) ctx->top_eqs = top-level equalities.
1727
 *    Every t in top_eqs is (eq t1 t2) (or a variant) asserted true.
1728
 *    t is mapped to true in the internalization table.
1729
 *
1730
 * 2) ctx->top_atoms = top-level atoms.
1731
 *    Every t in top_atoms is an atom or the negation of an atom (that
1732
 *    can't go into top_eqs).
1733
 *    t is mapped to true in the internalization table.
1734
 *
1735
 * 3) ctx->top_formulas = non-atomic terms.
1736
 *    Every t in top_formulas is either an (OR ...) or (ITE ...) or (XOR ...) or (IFF ..)
1737
 *    or the negation of such a term.
1738
 *    t is mapped to true in the internalization table.
1739
 *
1740
 * 4) ctx->top_interns = already internalized terms.
1741
 *    Every t in top_interns is a term that's been internalized before
1742
 *    and is mapped to a literal l or an egraph occurrence g in
1743
 *    the internalization table.
1744
 *    l or g must be asserted true in later stages.
1745
 *
1746
 * Flattening is done breadth-first:
1747
 * - the subterms to process are stored into ctx->queue.
1748
 * - each subterm in that queue is a boolean term that's asserted true
1749
 */
1750

1751

1752
/*
1753
 * Each function below processes an assertion of the form (r == tt)
1754
 * where r is a boolean term (with positive polarity) and tt is either
1755
 * true or false. The term r is a root in the internalization table
1756
 * and r is not internalized yet.
1757
 *
1758
 * Processing:
1759
 * - try to simplify (r == tt) to a boolean term q. If that works
1760
 *   add q to the internal queue.
1761
 * - check for boolean propagation from (r == tt) to r's children.
1762
 *   Example: (or t_1 ... t_n) == false ---> (t_1 == false), etc.
1763
 * - if (r == tt) can be rewritten to an equality (t1 == t2), check
1764
 *   whether we can eliminate t1 or t2 by substitution.
1765
 * - otherwise, add r or (not r) to one of top_eqs, top_atoms, or top_formulas.
1766
 */
1767

1768
/*
1769
 * Atoms, except equalities
1770
 */
1771
// r is (p t_1 ... t_n)
1772
static void flatten_bool_app(context_t *ctx, term_t r, bool tt) {
252✔
1773
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
252✔
1774
}
252✔
1775

1776
// r is (distinct t1 .... t_n)
1777
static void flatten_distinct(context_t *ctx, term_t r, bool tt) {
97✔
1778
  if (tt) {
97✔
1779
    ivector_push(&ctx->top_atoms, r);
88✔
1780
  } else {
1781
    // not (distinct ...) expands to an or
1782
    ivector_push(&ctx->top_formulas, not(r));
9✔
1783
  }
1784
}
97✔
1785

1786
// r is (select i t) for a tuple t
1787
static void flatten_select(context_t *ctx, term_t r, bool tt) {
×
1788
  term_t t;
1789

1790
  t = simplify_select(ctx, r);
×
1791
  if (t != NULL_TERM) {
×
1792
    int_queue_push(&ctx->queue, signed_term(t, tt));
×
1793
  } else {
1794
    ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
1795
  }
1796
}
×
1797

1798
// r is (bit i t) for a bitvector term t
1799
static void flatten_bit_select(context_t *ctx, term_t r, bool tt) {
33,128✔
1800
  term_t t;
1801

1802
  t = simplify_bit_select(ctx, r);
33,128✔
1803
  if (t != NULL_TERM) {
33,128✔
1804
    int_queue_push(&ctx->queue, signed_term(t, tt));
266✔
1805
  } else {
1806
    ivector_push(&ctx->top_atoms, signed_term(r, tt));
32,862✔
1807
  }
1808
}
33,128✔
1809

1810
// r is (t >= 0) for an arithmetic term t
1811
static void flatten_arith_geq0(context_t *ctx, term_t r, bool tt) {
6,489✔
1812
  term_t t;
1813

1814
  t = simplify_arith_geq0(ctx, r);
6,489✔
1815
  if (t != NULL_TERM) {
6,489✔
1816
    int_queue_push(&ctx->queue, signed_term(t, tt));
1✔
1817
  } else {
1818
    ivector_push(&ctx->top_atoms, signed_term(r, tt));
6,488✔
1819
  }
1820
}
6,489✔
1821

1822
// r is (is-int t)
1823
static void flatten_arith_is_int(context_t *ctx, term_t r, bool tt) {
×
1824
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
1825
}
×
1826

1827
// r is (divides t1 t2)
1828
static void flatten_arith_divides(context_t *ctx, term_t r, bool tt) {
×
1829
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
1830
}
×
1831

1832
// r is (bvge t1 t2) for two bitvector terms t1 and t2
1833
static void flatten_bvge(context_t *ctx, term_t r, bool tt) {
1,491✔
1834
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
1,491✔
1835
}
1,491✔
1836

1837
// r is (bvsge t1 t2) for two bitvector terms t1 and t2
1838
static void flatten_bvsge(context_t *ctx, term_t r, bool tt) {
463✔
1839
  ivector_push(&ctx->top_atoms, signed_term(r, tt));
463✔
1840
}
463✔
1841

1842

1843
/*
1844
 * Equalities
1845
 */
1846
// r is (t == 0) for an arithmetic term t
1847
static void flatten_arith_eq0(context_t *ctx, term_t r, bool tt) {
2,210✔
1848
  term_t t;
1849

1850
  t = simplify_arith_eq0(ctx, r);
2,210✔
1851
  if (t != NULL_TERM) {
2,210✔
1852
    int_queue_push(&ctx->queue, signed_term(t, tt));
1✔
1853
  } else if (tt) {
2,209✔
1854
    ivector_push(&ctx->top_eqs, r);
899✔
1855
  } else {
1856
    ivector_push(&ctx->top_atoms, opposite_term(r));
1,310✔
1857
  }
1858
}
2,210✔
1859

1860
// r is (t1 == t2) for two arithmetic terms t1 and t2
1861
static void flatten_arith_eq(context_t *ctx, term_t r, bool tt) {
4,300✔
1862
  composite_term_t *eq;
1863
  term_t t1, t2, t;
1864

1865
  eq = arith_bineq_atom_desc(ctx->terms, r);
4,300✔
1866
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
4,300✔
1867
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
4,300✔
1868

1869
  if (t1 == t2) {
4,300✔
1870
    if (!tt) {
5✔
1871
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1872
    }
1873
    return; // redundant
5✔
1874
  }
1875

1876
  t = simplify_arith_bineq(ctx, t1, t2);
4,295✔
1877
  if (t != NULL_TERM) {
4,295✔
1878
    int_queue_push(&ctx->queue, signed_term(t, tt));
2✔
1879
  } else if (tt) {
4,293✔
1880
    try_substitution(ctx, t1, t2, r);
2,075✔
1881
  } else {
1882
    ivector_push(&ctx->top_atoms, opposite_term(r));
2,218✔
1883
  }
1884
}
1885

1886
// r is (eq t1 t2): t1 and t2 are either boolean or tuples or uninterpreted
1887
static void flatten_eq(context_t *ctx, term_t r, bool tt) {
6,312✔
1888
  term_table_t *terms;
1889
  composite_term_t *eq;
1890
  term_t t1, t2, t;
1891

1892
  terms = ctx->terms;
6,312✔
1893
  eq = eq_term_desc(terms, r);
6,312✔
1894
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
6,312✔
1895
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
6,312✔
1896

1897
  if (is_boolean_term(terms, t1)) {
6,312✔
1898
    /*
1899
     * Boolean equality
1900
     */
1901
    assert(is_boolean_term(terms, t2));
1902

1903
    t = simplify_bool_eq(ctx, t1, t2);
3,780✔
1904
    if (t != NULL_TERM) {
3,780✔
1905
      int_queue_push(&ctx->queue, signed_term(t, tt));
169✔
1906
    } else {
1907
      // not (eq t1 t2) --> (eq t1 (not t2))
1908
      if (! tt) {
3,611✔
1909
        r = opposite_term(r);
76✔
1910
        t2 = opposite_term(t2);
76✔
1911
      }
1912

1913
      if (index_of(t1) == index_of(t2)) {
3,611✔
1914
        // either (eq t1 t1) or (eq t1 (not t1))
1915
        if (t1 == t2) return;
×
1916
        assert(opposite_bool_terms(t1, t2));
1917
        longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1918
      }
1919

1920
      try_bool_substitution(ctx, t1, t2, r);
3,611✔
1921
    }
1922

1923
  } else {
1924
    /*
1925
     * Non-boolean
1926
     */
1927
    if (t1 == t2) {
2,532✔
1928
      if (! tt) {
×
1929
        longjmp(ctx->env, TRIVIALLY_UNSAT);
×
1930
      }
1931
      return;
×
1932
    }
1933

1934
    if (tt) {
2,532✔
1935
      try_substitution(ctx, t1, t2, r);
1,466✔
1936
    } else {
1937
      ivector_push(&ctx->top_atoms, opposite_term(r));
1,066✔
1938
    }
1939
  }
1940
}
1941

1942
// r is (bveq t1 t2) for two bitvector terms t1 and t2
1943
static void flatten_bveq(context_t *ctx, term_t r, bool tt) {
22,198✔
1944
  term_table_t *terms;
1945
  composite_term_t *eq;
1946
  ivector_t *v;
1947
  term_t t1, t2, t;
1948

1949
  terms = ctx->terms;
22,198✔
1950
  eq = bveq_atom_desc(terms, r);
22,198✔
1951
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
22,198✔
1952
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
22,198✔
1953

1954
  /*
1955
   * First check whether (eq t1 t2) is equivalent to
1956
   * a Boolean term t
1957
   */
1958
  t = simplify_bitvector_eq(ctx, t1, t2);
22,198✔
1959
  if (t != NULL_TERM) {
22,198✔
1960
    t = signed_term(t, tt);
74✔
1961
    if (t == false_term) {
74✔
1962
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
1963
    } else if (t != true_term) {
70✔
1964
      int_queue_push(&ctx->queue, t);
58✔
1965
    }
1966

1967
  } else if (tt) {
22,124✔
1968
    /*
1969
     * try to flatten into a conjunction of terms
1970
     */
1971
    v = &ctx->aux_vector;
19,609✔
1972
    assert(v->size == 0);
1973
    if (bveq_flattens(ctx->terms, t1, t2, v)) {
19,609✔
1974
      /*
1975
       * (bveq t1 t2) is equivalent to (and v[0] ... v[k-1])
1976
       * (bveq t1 t2) is asserted true
1977
       */
1978
      int_queue_push_array(&ctx->queue, v->data, v->size);
5,332✔
1979
    } else {
1980
      /*
1981
       * Did not flatten
1982
       */
1983
      try_substitution(ctx, t1, t2, r);
14,277✔
1984
    }
1985

1986
    ivector_reset(v);
19,609✔
1987

1988
  } else {
1989
    ivector_push(&ctx->top_atoms, opposite_term(r));
2,515✔
1990
  }
1991
}
22,194✔
1992

1993

1994
#if 0
1995
/*
1996
 * Display the results of factoring r
1997
 */
1998
static void show_common_factors(context_t *ctx, term_t r, ivector_t *v) {
1999
  yices_pp_t printer;
2000
  uint32_t i, n;
2001

2002
  n = v->size;
2003
  if (n > 0) {
2004
    printf("--- common factors of r = %"PRId32" ---\n", r);
2005
    init_yices_pp(&printer, stdout, NULL, PP_VMODE, 0);
2006
    pp_term_full(&printer, ctx->terms, r);
2007
    flush_yices_pp(&printer);
2008

2009
    for (i=0; i<n; i++) {
2010
      printf("factor[%"PRIu32"]: ", i);
2011
      pp_term_full(&printer, ctx->terms, v->data[i]);
2012
      flush_yices_pp(&printer);
2013
    }
2014

2015
    delete_yices_pp(&printer, true);
2016
  }
2017
}
2018

2019
#endif
2020

2021
/*
2022
 * Search for common factors of an or
2023
 * - push them in the queue for further flattening
2024
 */
2025
static void push_common_factors(context_t *ctx, term_t r) {
×
2026
  ivector_t *v;
2027
  uint32_t i, n;
2028

2029
  v = &ctx->aux_vector;
×
2030
  context_factor_disjunction(ctx, r, v);
×
2031

2032
#if 0
2033
  show_common_factors(ctx, r, v);
2034
#endif
2035

2036
  n = v->size;
×
2037
  for (i=0; i<n; i++) {
×
2038
    int_queue_push(&ctx->queue, v->data[i]);
×
2039
  }
2040
  ivector_reset(v);
×
2041
}
×
2042

2043
/*
2044
 * Non-atomic terms
2045
 */
2046
// r is (or t1 ... t_n)
2047
static void flatten_or(context_t *ctx, term_t r, bool tt) {
39,050✔
2048
  composite_term_t *d;
2049
  uint32_t i, n;
2050

2051
  if (tt) {
39,050✔
2052
    ivector_push(&ctx->top_formulas, r);
32,002✔
2053
    if (context_or_factoring_enabled(ctx)) {
32,002✔
2054
      push_common_factors(ctx, r);
×
2055
    }
2056
  } else {
2057
    d = or_term_desc(ctx->terms, r);
7,048✔
2058
    n = d->arity;
7,048✔
2059
    for (i=0; i<n; i++) {
67,446✔
2060
      int_queue_push(&ctx->queue, opposite_term(d->arg[i]));
60,398✔
2061
    }
2062
  }
2063
}
39,050✔
2064

2065
// r is (xor t1 ... t_n)
2066
static void flatten_xor(context_t *ctx, term_t r, bool tt) {
7✔
2067
  ivector_push(&ctx->top_formulas, signed_term(r, tt));
7✔
2068
}
7✔
2069

2070
// r is (ite c t1 t2) where t1 and t2 are boolean terms
2071
static void flatten_bool_ite(context_t *ctx, term_t r, bool tt) {
77✔
2072
  term_table_t *terms;
2073
  composite_term_t *d;
2074
  term_t c, t1, t2, t;
2075

2076
  terms = ctx->terms;
77✔
2077
  d = ite_term_desc(terms, r);
77✔
2078
  c = intern_tbl_get_root(&ctx->intern, d->arg[0]);
77✔
2079
  t1 = intern_tbl_get_root(&ctx->intern, d->arg[1]);
77✔
2080
  t2 = intern_tbl_get_root(&ctx->intern, d->arg[2]);
77✔
2081

2082
  t = simplify_ite(ctx, c, t1, t2);
77✔
2083
  if (t != NULL_TERM) {
77✔
2084
    int_queue_push(&ctx->queue, signed_term(t, tt));
2✔
2085
  } else {
2086

2087
    if (tt) {
75✔
2088
      if (c == t2 || term_is_false(ctx, t2)) {
58✔
2089
        // assert (ite c a false) --> assert c and a
2090
        // assert (ite c a c)     --> assert c and a
2091
        int_queue_push(&ctx->queue, c);
1✔
2092
        int_queue_push(&ctx->queue, t1);
1✔
2093
        return;
1✔
2094
      }
2095

2096
      if (opposite_bool_terms(c, t1) || term_is_false(ctx, t1)) {
57✔
2097
        // assert (ite c false b)   --> assert (not c) and b
2098
        // assert (ite c (not c) b) --> assert (not c) and b
2099
        int_queue_push(&ctx->queue, opposite_term(c));
1✔
2100
        int_queue_push(&ctx->queue, t2);
1✔
2101
        return;
1✔
2102
      }
2103

2104
    } else {
2105
      if (opposite_bool_terms(c, t2) || term_is_true(ctx, t2)) {
17✔
2106
        // assert not (ite c a true)    --> assert c and (not a)
2107
        // assert not (ite c a (not c)) --> assert c and (not a)
2108
        int_queue_push(&ctx->queue, c);
1✔
2109
        int_queue_push(&ctx->queue, opposite_term(t1));
1✔
2110
        return;
1✔
2111
      }
2112

2113
      if (c == t1 || term_is_true(ctx, t1)) {
16✔
2114
        // assert not (ite c true b) --> assert (not c) and (not b)
2115
        // assert not (ite c c b)    --> assert (not c) and (not b)
2116
        int_queue_push(&ctx->queue, opposite_term(c));
1✔
2117
        int_queue_push(&ctx->queue, opposite_term(t2));
1✔
2118
        return;
1✔
2119
      }
2120
    }
2121

2122
    // no flattening found
2123
    ivector_push(&ctx->top_formulas, signed_term(r, tt));
71✔
2124
  }
2125
}
2126

2127

2128
/*
2129
 * Simplify and flatten assertion f.
2130
 *
2131
 * Raise an exception via longjmp if there's an error or if a
2132
 * contradiction is detected.
2133
 */
2134
void flatten_assertion(context_t *ctx, term_t f) {
75,374✔
2135
  intern_tbl_t *intern;
2136
  int_queue_t *queue;
2137
  term_table_t *terms;
2138
  term_t t, r;
2139
  int32_t x;
2140
  bool tt;
2141
  int32_t exception;
2142

2143
  queue = &ctx->queue;
75,374✔
2144
  intern = &ctx->intern;
75,374✔
2145
  terms = ctx->terms;
75,374✔
2146

2147
  assert(int_queue_is_empty(queue));
2148
  int_queue_push(queue, f);
75,374✔
2149

2150
  do {
2151
    t = int_queue_pop(queue);           // assert t
151,642✔
2152

2153
    /*
2154
     * Convert (assert t) to (assert r == tt)
2155
     * where r is positive (equal to t or not t)
2156
     * and polarity is either true or false
2157
     */
2158
    r = intern_tbl_get_root(intern, t); // r == t by substitution
151,642✔
2159
    tt = is_pos_term(r);
151,642✔
2160
    r = unsigned_term(r);
151,642✔
2161

2162
    assert(is_pos_term(r) && intern_tbl_is_root(intern, r));
2163

2164
    if (intern_tbl_root_is_mapped(intern, r)) {
151,642✔
2165
      /*
2166
       * r already mapped to something
2167
       * check for trivial unsat
2168
       * then add r or (not r) to top_intern
2169
       */
2170
      x = intern_tbl_map_of_root(intern, r);
34,965✔
2171
      if (x == bool2code(! tt)) {
34,965✔
2172
        exception = TRIVIALLY_UNSAT;
389✔
2173
        goto abort;
389✔
2174
      }
2175

2176
      if (x != bool2code(tt)) {
34,576✔
2177
        ivector_push(&ctx->top_interns, signed_term(r, tt));
434✔
2178
      }
2179

2180
    } else {
2181
      /*
2182
       * r not seen before: record r = tt then explore r
2183
       */
2184
      switch (term_kind(terms, r)) {
116,677✔
2185
      case UNUSED_TERM:
×
2186
      case RESERVED_TERM:
2187
      case CONSTANT_TERM:
2188
        /*
2189
         * NOTE: the constant boolean terms are true and false, which
2190
         * should always be internalized to true_literal or false_literal.
2191
         * That's why we don't have a separate 'CONSTANT_TERM' case.
2192
         */
2193
        exception = INTERNAL_ERROR;
×
2194
        goto abort;
×
2195

2196
      case ARITH_CONSTANT:
×
2197
      case BV64_CONSTANT:
2198
      case BV_CONSTANT:
2199
      case ARITH_FLOOR:
2200
      case ARITH_CEIL:
2201
      case ARITH_ABS:
2202
      case UPDATE_TERM:
2203
      case TUPLE_TERM:
2204
      case LAMBDA_TERM:
2205
      case ARITH_RDIV:
2206
      case ARITH_IDIV:
2207
      case ARITH_MOD:
2208
      case BV_ARRAY:
2209
      case BV_DIV:
2210
      case BV_REM:
2211
      case BV_SDIV:
2212
      case BV_SREM:
2213
      case BV_SMOD:
2214
      case BV_SHL:
2215
      case BV_LSHR:
2216
      case BV_ASHR:
2217
      case POWER_PRODUCT:
2218
      case ARITH_POLY:
2219
      case BV64_POLY:
2220
      case BV_POLY:
2221
        exception = TYPE_ERROR;
×
2222
        goto abort;
×
2223

2224
      case VARIABLE:
×
2225
        exception = FREE_VARIABLE_IN_FORMULA;
×
2226
        goto abort;
×
2227

2228
      case UNINTERPRETED_TERM:
603✔
2229
        assert(intern_tbl_root_is_free(intern, r));
2230
        if (context_var_elim_enabled(ctx)) {
603✔
2231
          intern_tbl_add_subst(intern, r, bool2term(tt));
161✔
2232
        } else {
2233
          intern_tbl_map_root(intern, r, bool2code(tt));
442✔
2234
        }
2235
        break;
603✔
2236

2237
      case ARITH_EQ_ATOM:
2,210✔
2238
        intern_tbl_map_root(intern, r, bool2code(tt));
2,210✔
2239
        flatten_arith_eq0(ctx, r, tt);
2,210✔
2240
        break;
2,210✔
2241

2242
      case ARITH_GE_ATOM:
6,489✔
2243
        intern_tbl_map_root(intern, r, bool2code(tt));
6,489✔
2244
        flatten_arith_geq0(ctx, r, tt);
6,489✔
2245
        break;
6,489✔
2246

2247
      case ARITH_ROOT_ATOM:
×
2248
        exception = FORMULA_NOT_LINEAR;
×
2249
        goto abort;
×
2250

2251
      case ARITH_IS_INT_ATOM:
×
2252
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2253
        flatten_arith_is_int(ctx, r, tt);
×
2254
        break;
×
2255

2256
      case ITE_TERM:
77✔
2257
      case ITE_SPECIAL:
2258
        intern_tbl_map_root(intern, r, bool2code(tt));
77✔
2259
        flatten_bool_ite(ctx, r, tt);
77✔
2260
        break;
77✔
2261

2262
      case APP_TERM:
252✔
2263
        intern_tbl_map_root(intern, r, bool2code(tt));
252✔
2264
        flatten_bool_app(ctx, r, tt);
252✔
2265
        break;
252✔
2266

2267
      case EQ_TERM:
6,312✔
2268
        intern_tbl_map_root(intern, r, bool2code(tt));
6,312✔
2269
        flatten_eq(ctx, r, tt);
6,312✔
2270
        break;
6,312✔
2271

2272
      case DISTINCT_TERM:
97✔
2273
        intern_tbl_map_root(intern, r, bool2code(tt));
97✔
2274
        flatten_distinct(ctx, r, tt);
97✔
2275
        break;
97✔
2276

2277
      case FORALL_TERM:
×
2278
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2279
        ivector_push(&ctx->top_atoms, signed_term(r, tt));
×
2280
        break;
×
2281

2282
      case OR_TERM:
39,050✔
2283
        intern_tbl_map_root(intern, r, bool2code(tt));
39,050✔
2284
        flatten_or(ctx, r, tt);
39,050✔
2285
        break;
39,050✔
2286

2287
      case XOR_TERM:
7✔
2288
        intern_tbl_map_root(intern, r, bool2code(tt));
7✔
2289
        flatten_xor(ctx, r, tt);
7✔
2290
        break;
7✔
2291

2292
      case ARITH_BINEQ_ATOM:
4,300✔
2293
        intern_tbl_map_root(intern, r, bool2code(tt));
4,300✔
2294
        flatten_arith_eq(ctx, r, tt);
4,300✔
2295
        break;
4,300✔
2296

2297
      case ARITH_DIVIDES_ATOM:
×
2298
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2299
        flatten_arith_divides(ctx, r, tt);
×
2300
        break;
×
2301

2302
      case BV_EQ_ATOM:
22,198✔
2303
        intern_tbl_map_root(intern, r, bool2code(tt));
22,198✔
2304
        flatten_bveq(ctx, r, tt);
22,198✔
2305
        break;
22,194✔
2306

2307
      case BV_GE_ATOM:
1,491✔
2308
        intern_tbl_map_root(intern, r, bool2code(tt));
1,491✔
2309
        flatten_bvge(ctx, r, tt);
1,491✔
2310
        break;
1,491✔
2311

2312
      case BV_SGE_ATOM:
463✔
2313
        intern_tbl_map_root(intern, r, bool2code(tt));
463✔
2314
        flatten_bvsge(ctx, r, tt);
463✔
2315
        break;
463✔
2316

2317
      case SELECT_TERM:
×
2318
        intern_tbl_map_root(intern, r, bool2code(tt));
×
2319
        flatten_select(ctx, r, tt);
×
2320
        break;
×
2321

2322
      case BIT_TERM:
33,128✔
2323
        intern_tbl_map_root(intern, r, bool2code(tt));
33,128✔
2324
        flatten_bit_select(ctx, r, tt);
33,128✔
2325
        break;
33,128✔
2326

NEW
2327
      case ARITH_FF_POLY:
×
2328
      case ARITH_FF_CONSTANT:
2329
      case ARITH_FF_EQ_ATOM:
2330
      case ARITH_FF_BINEQ_ATOM:
NEW
2331
        exception = CONTEXT_UNSUPPORTED_THEORY;
×
NEW
2332
        goto abort;
×
2333
      }
2334
    }
2335

2336
  } while (! int_queue_is_empty(queue));
151,249✔
2337

2338
  return;
74,981✔
2339

2340
 abort:
389✔
2341
  assert(exception != 0);
2342
  longjmp(ctx->env, exception);
389✔
2343
}
2344

2345

2346

2347

2348
/*
2349
 * Process all candidate substitutions after flattening
2350
 * - the candidate substitutions are in ctx->subst_eqs
2351
 * - each element in ctx->subst_eqs is a boolean term e
2352
 *   such that e is true or false (by flattening)
2353
 *         and e is equivalent to an equality (t1 == t2)
2354
 *   where one of t1 and t2 is a variable.
2355
 */
2356
void context_process_candidate_subst(context_t *ctx) {
4,092✔
2357
  pseudo_subst_t *subst;
2358
  mark_vector_t *marks;
2359

2360
  subst = context_get_subst(ctx);
4,092✔
2361
  marks = context_get_marks(ctx);
4,092✔
2362
  process_subst_eqs(ctx, subst);
4,092✔
2363
  remove_subst_cycles(ctx);
4,092✔
2364
  finalize_subst_candidates(ctx);
4,092✔
2365

2366
  // cleanup
2367
  ivector_reset(&ctx->subst_eqs);
4,092✔
2368
  reset_pseudo_subst(subst);
4,092✔
2369
  reset_mark_vector(marks);
4,092✔
2370
}
4,092✔
2371

2372

2373

2374

2375
/**************************
2376
 *  AUXILIARY EQUALITIES  *
2377
 *************************/
2378

2379
/*
2380
 * Process an auxiliary equality eq
2381
 * - eq must be an equality term (i.e.,
2382
 *   either EQ_TERM, ARITH_EQ_ATOM, ARITH_BINEQ_ATOM, BVEQ_ATOM)
2383
 */
2384
static void process_aux_eq(context_t *ctx, term_t eq) {
57✔
2385
  composite_term_t *d;
2386
  term_t t1, t2;
2387
  int32_t code;
2388

2389
  assert(intern_tbl_is_root(&ctx->intern, eq));
2390

2391
  if (intern_tbl_root_is_mapped(&ctx->intern, eq)) {
57✔
2392
    // eq is already internalized
2393
    code = intern_tbl_map_of_root(&ctx->intern, eq);
1✔
2394
    if (code == bool2code(false)) {
1✔
2395
      // contradiction
2396
      longjmp(ctx->env, TRIVIALLY_UNSAT);
1✔
2397
    } else if (code != bool2code(true)) {
×
2398
      ivector_push(&ctx->top_interns, eq);
×
2399
    }
2400
  } else {
2401
    // map e to true and try to process it as a substitution
2402
    intern_tbl_map_root(&ctx->intern, eq, bool2code(true));
56✔
2403

2404
    switch (term_kind(ctx->terms, eq)) {
56✔
2405
    case EQ_TERM:
55✔
2406
    case ARITH_BINEQ_ATOM:
2407
    case BV_EQ_ATOM:
2408
      // process e as a substitution if possible
2409
      d = composite_term_desc(ctx->terms, eq);
55✔
2410
      assert(d->arity == 2);
2411
      t1 = intern_tbl_get_root(&ctx->intern, d->arg[0]);
55✔
2412
      t2 = intern_tbl_get_root(&ctx->intern, d->arg[1]);
55✔
2413
      if (is_boolean_term(ctx->terms, t1)) {
55✔
2414
        try_bool_substitution(ctx, t1, t2, eq);
×
2415
      } else {
2416
        try_substitution(ctx, t1, t2, eq);
55✔
2417
      }
2418
      break;
55✔
2419

2420
    case ARITH_EQ_ATOM:
1✔
2421
      ivector_push(&ctx->top_eqs, eq);
1✔
2422
      break;
1✔
2423

2424
    default:
×
2425
      assert(false);
2426
      break;
×
2427
    }
2428
  }
2429
}
56✔
2430

2431

2432
/*
2433
 * Process the auxiliary equalities:
2434
 * - if substitution is not enabled, then all aux equalities are added to top_eqs
2435
 * - otherwise, cheap substitutions are performed and candidate substitutions
2436
 *   are added to subst_eqs.
2437
 *
2438
 * This function raises an exception via longjmp if a contradiction is detected.
2439
 */
2440
void process_aux_eqs(context_t *ctx) {
8✔
2441
  uint32_t i, n;
2442
  ivector_t *aux_eqs;
2443

2444
  aux_eqs = &ctx->aux_eqs;
8✔
2445
  n = aux_eqs->size;
8✔
2446
  for (i=0; i<n; i++) {
64✔
2447
    process_aux_eq(ctx, aux_eqs->data[i]);
57✔
2448
  }
2449

2450
  // cleanup
2451
  ivector_reset(&ctx->aux_eqs);
7✔
2452
}
7✔
2453

2454

2455

2456
/*******************
2457
 *  LEARNED ATOMS  *
2458
 ******************/
2459

2460
/*
2461
 * Process all terms in ctx->aux_atoms:
2462
 */
2463
void process_aux_atoms(context_t *ctx) {
3✔
2464
  ivector_t *v;
2465
  uint32_t i, n;
2466
  term_t t, r;
2467
  int32_t code;
2468

2469
  v = &ctx->aux_atoms;
3✔
2470
  n = v->size;
3✔
2471
  for (i=0; i<n; i++) {
529✔
2472
    t = v->data[i];
526✔
2473
    r = intern_tbl_get_root(&ctx->intern, t);
526✔
2474

2475
    if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
526✔
2476
      // already internalized
2477
      code = intern_tbl_map_of_root(&ctx->intern, r);
2✔
2478
      if (code == bool2code(false)) {
2✔
2479
        // contradiction
2480
        longjmp(ctx->env, TRIVIALLY_UNSAT);
×
2481
      } else if (code != bool2code(true)) {
2✔
2482
        ivector_push(&ctx->top_interns, r);
2✔
2483
      }
2484
    } else {
2485
      // not mapped
2486
      intern_tbl_map_root(&ctx->intern, r, bool2code(true));
524✔
2487
      ivector_push(&ctx->top_atoms, r);
524✔
2488
    }
2489
  }
2490

2491
  ivector_reset(v);
3✔
2492
}
3✔
2493

2494

2495

2496

2497
/********************************
2498
 *  FLATTENING OF DISJUNCTIONS  *
2499
 *******************************/
2500

2501
/*
2502
 * This does two things:
2503
 * 1) rewrite nested OR terms to flat OR terms
2504
 * 2) replace arithmetic disequality by disjunctions of strict inequalities
2505
 *    (i.e., rewrite (x != 0) to (or (x < 0) (x > 0))
2506
 */
2507

2508
/*
2509
 * Build the atom (t < 0)
2510
 */
2511
static term_t lt0_atom(context_t *ctx, term_t t) {
2,562✔
2512
  rba_buffer_t *b;
2513

2514
  assert(is_pos_term(t) && is_arithmetic_term(ctx->terms, t));
2515

2516
  b = ctx->arith_buffer;
2,562✔
2517
  assert(b != NULL && rba_buffer_is_zero(b));
2518

2519
  rba_buffer_add_term(b, ctx->terms, t);
2,562✔
2520
  return mk_direct_arith_lt0(ctx->terms, b, true);
2,562✔
2521
}
2522

2523
/*
2524
 * Build a term equivalent to (t > 0)
2525
 */
2526
static term_t gt0_atom(context_t *ctx, term_t t) {
2,562✔
2527
  rba_buffer_t *b;
2528

2529
  assert(is_pos_term(t) && is_arithmetic_term(ctx->terms, t));
2530

2531
  b = ctx->arith_buffer;
2,562✔
2532
  assert(b != NULL && rba_buffer_is_zero(b));
2533

2534
  rba_buffer_add_term(b, ctx->terms, t);
2,562✔
2535
  return mk_direct_arith_gt0(ctx->terms, b, true);
2,562✔
2536
}
2537

2538

2539
/*
2540
 * Build a term equivalent to (t < u)
2541
 */
2542
static term_t lt_atom(context_t *ctx, term_t t, term_t u) {
6,856✔
2543
  rba_buffer_t *b;
2544

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

2548
  // build atom (t - u < 0)
2549
  b = ctx->arith_buffer;
6,856✔
2550
  assert(b != NULL && rba_buffer_is_zero(b));
2551
  rba_buffer_add_term(b, ctx->terms, t);
6,856✔
2552
  rba_buffer_sub_term(b, ctx->terms, u);
6,856✔
2553
  return mk_direct_arith_lt0(ctx->terms, b, true);
6,856✔
2554
}
2555

2556

2557
/*
2558
 * We use a breadth-first approach:
2559
 * - ctx->queue contains all terms to process
2560
 * - v contains the terms that can't be flattened
2561
 * - ctx->small_cache contains all the terms that have been visited
2562
 *   (including all terms in v and in ctx->queue).
2563
 *
2564
 * The term we're building is (or <elements in v> <elements in the queue>)
2565
 */
2566

2567
/*
2568
 * Push t into ctx->queue if it's not been visited yet
2569
 */
2570
static void flatten_or_push_term(context_t *ctx, term_t t) {
123,903✔
2571
  assert(is_boolean_term(ctx->terms, t));
2572

2573
  if (int_hset_add(ctx->small_cache, t)) {
123,903✔
2574
    int_queue_push(&ctx->queue, t);
123,615✔
2575
  }
2576
}
123,903✔
2577

2578
/*
2579
 * Add t to v if it's not been visited yet
2580
 */
2581
static void flatten_or_add_term(context_t *ctx, ivector_t *v, term_t t) {
11,980✔
2582
  assert(is_boolean_term(ctx->terms, t));
2583

2584
  if (int_hset_add(ctx->small_cache, t)) {
11,980✔
2585
    ivector_push(v, t);
11,980✔
2586
  }
2587
}
11,980✔
2588

2589
/*
2590
 * Process all elements in ctx->queue.
2591
 *
2592
 * For every term t in the queue:
2593
 * - if t is already internalized, keep t and add it to v
2594
 * - if t is (or t1 ... t_n), add t1 ... t_n to the queue
2595
 * - if flattening of disequalities is enabled, and t is (NOT (x == 0)) then
2596
 *   we rewrite (NOT (x == 0)) to (OR (< x 0) (> x 0))
2597
 * - otherwise store t into v
2598
 */
2599
static void flatten_or_process_queue(context_t *ctx, ivector_t *v) {
27,222✔
2600
  term_table_t *terms;
2601
  composite_term_t *or;
2602
  composite_term_t *eq;
2603
  uint32_t i, n;
2604
  term_kind_t kind;
2605
  term_t t, x, y;
2606

2607
  terms = ctx->terms;
27,222✔
2608

2609
  while (! int_queue_is_empty(&ctx->queue)) {
150,837✔
2610
    t = int_queue_pop(&ctx->queue);
123,615✔
2611

2612
    // apply substitutions
2613
    t = intern_tbl_get_root(&ctx->intern, t);
123,615✔
2614

2615
    if (intern_tbl_root_is_mapped(&ctx->intern, t)) {
123,615✔
2616
      // t is already internalized: keep it as is
2617
      ivector_push(v, t);
60,730✔
2618
    } else {
2619
      kind = term_kind(terms, t);
62,885✔
2620
      if (is_pos_term(t) && kind == OR_TERM) {
62,885✔
2621
        // add t's children to the queue
2622
        or = or_term_desc(terms, t);
21,897✔
2623
        n = or->arity;
21,897✔
2624
        for (i=0; i<n; i++) {
67,507✔
2625
          flatten_or_push_term(ctx, or->arg[i]);
45,610✔
2626
        }
2627
      } else if (is_neg_term(t) && context_flatten_diseq_enabled(ctx)) {
40,988✔
2628
        switch (kind) {
26,232✔
2629
        case ARITH_EQ_ATOM:
2,597✔
2630
          /*
2631
           * t is (not (eq x 0)): rewrite to (or (x < 0) (x > 0))
2632
           *
2633
           * Exception: keep it as an equality if x is an if-then-else term
2634
           */
2635
          x = intern_tbl_get_root(&ctx->intern, arith_eq_arg(terms, t));
2,597✔
2636
          if (is_ite_term(terms, x)) {
2,597✔
2637
            ivector_push(v, t);
35✔
2638
          } else {
2639
            flatten_or_add_term(ctx, v, lt0_atom(ctx, x));
2,562✔
2640
            flatten_or_add_term(ctx, v, gt0_atom(ctx, x));
2,562✔
2641
          }
2642
          break;
2,597✔
2643

2644
        case ARITH_BINEQ_ATOM:
5,348✔
2645
          /*
2646
           * t is (not (eq x y)): rewrite to (or (x < y) (y < x))
2647
           *
2648
           * Exception 1: if x or y is an if-then-else term, then it's
2649
           * better to keep (eq x y) because the if-lifting
2650
           * simplifications are more likely to work on
2651
           *    (ite c a b) = y
2652
           * than (ite c a b) >= y AND (ite c a b) <= y
2653
           *
2654
           * Exception 2: if there's an egraph, then it's better
2655
           * to keep (eq x y) as is. It will be converted to an
2656
           * egraph equality.
2657
           */
2658
          eq = arith_bineq_atom_desc(terms, t);
5,348✔
2659
          x = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
5,348✔
2660
          y = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
5,348✔
2661
          if (context_has_egraph(ctx) || is_ite_term(terms, x) || is_ite_term(terms, y)) {
5,348✔
2662
            ivector_push(v, t);
1,920✔
2663
          } else {
2664
            flatten_or_add_term(ctx, v, lt_atom(ctx, x, y));
3,428✔
2665
            flatten_or_add_term(ctx, v, lt_atom(ctx, y, x));
3,428✔
2666
          }
2667
          break;
5,348✔
2668

2669
        default:
18,287✔
2670
          // can't flatten
2671
          ivector_push(v, t);
18,287✔
2672
          break;
18,287✔
2673
        }
2674

2675
      } else {
2676
        // can't flatten
2677
        ivector_push(v, t);
14,756✔
2678
      }
2679
    }
2680
  }
2681
}
27,222✔
2682

2683
/*
2684
 * Flatten a top-level (or t1 .... tp)
2685
 * - initialize the small_cache, then calls the recursive function
2686
 * - the result is stored in v
2687
 */
2688
void flatten_or_term(context_t *ctx, ivector_t *v, composite_term_t *or) {
27,222✔
2689
  uint32_t i, n;
2690

2691
  assert(v->size == 0 && int_queue_is_empty(&ctx->queue));
2692

2693
  (void) context_get_small_cache(ctx); // initialize the cache
27,222✔
2694
  if (context_flatten_diseq_enabled(ctx)) {
27,222✔
2695
    (void) context_get_arith_buffer(ctx);  // allocate the internal buffer
27,222✔
2696
  }
2697

2698
  n = or->arity;
27,222✔
2699
  for (i=0; i<n; i++) {
105,515✔
2700
    flatten_or_push_term(ctx, or->arg[i]);
78,293✔
2701
  }
2702

2703
  flatten_or_process_queue(ctx, v);
27,222✔
2704

2705
  //  context_delete_small_cache(ctx);
2706
  context_reset_small_cache(ctx);
27,222✔
2707
}
27,222✔
2708

2709

2710

2711

2712
/************************
2713
 *  EQUALITY LEARNING   *
2714
 ***********************/
2715

2716
/*
2717
 * Add implied equalities defined by the partition p to the aux_eqs vector
2718
 */
2719
static void add_implied_equalities(context_t *ctx, epartition_t *p) {
51✔
2720
  uint32_t i, n;
2721
  term_t *q, x, y;
2722

2723
  n = p->nclasses;
51✔
2724
  q = p->data;
51✔
2725
  for (i=0; i<n; i++) {
102✔
2726
    x = *q++;
51✔
2727
    assert(x >= 0);
2728
    y = *q ++;
51✔
2729
    while (y >= 0) {
102✔
2730
      add_aux_eq(ctx, x, y);
51✔
2731
      y = *q ++;
51✔
2732
    }
2733
  }
2734
}
51✔
2735

2736

2737
/*
2738
 * Attempt to learn global equalities implied
2739
 * by the formulas stored in ctx->top_formulas.
2740
 * Any such equality is added to ctx->aux_eqs
2741
 */
2742
void analyze_uf(context_t *ctx) {
63✔
2743
  ivector_t *v;
2744
  uint32_t i, n;
2745
  eq_learner_t *eql;
2746
  epartition_t *p;
2747

2748
  eql = objstack_alloc(&ctx->ostack, sizeof(eq_learner_t), (cleaner_t) delete_eq_learner);
63✔
2749
  init_eq_learner(eql, ctx->terms);
63✔
2750
  v = &ctx->top_formulas;
63✔
2751
  n = v->size;
63✔
2752

2753
  for (i=0; i<n; i++) {
1,742✔
2754
    p = eq_learner_process(eql, v->data[i]);
1,679✔
2755
    if (p->nclasses > 0) {
1,679✔
2756
      add_implied_equalities(ctx, p);
51✔
2757
    }
2758
  }
2759

2760
  //  delete_eq_learner(&eql);
2761
  objstack_pop(&ctx->ostack);
63✔
2762
}
63✔
2763

2764

2765

2766

2767
/*************************************************
2768
 *  ANALYSIS FOR THE DIFFERENCE LOGIC FRAGMENTS  *
2769
 ************************************************/
2770

2771
/*
2772
 * Buffer to store a difference logic term.
2773
 *
2774
 * The difference logic fragment contains terms of the following forms:
2775
 *   a + x - y
2776
 *   a + x
2777
 *   a - y
2778
 *   a
2779
 * where x and y are arithmetic variables and a is a constant (possibly a = 0).
2780
 *
2781
 * In IDL, x and y must be integer variables and a must be an integer constant.
2782
 * In RDL, x and y must be real variables.
2783
 *
2784
 * To encode the four types of terms, we use zero_term when x or y is missing:
2785
 *  a + x  -->  a + x - zero_term
2786
 *  a - y  -->  a + zero_term - y
2787
 *  a      -->  a + zero_term - zero_term
2788
 */
2789
typedef struct dl_term_s {
2790
  term_t x;
2791
  term_t y;
2792
  rational_t a;
2793
} dl_term_t;
2794

2795

2796
/*
2797
 * Initialization and cleanup
2798
 */
2799
static void init_dl_term(dl_term_t *triple) {
6,431✔
2800
  triple->x = zero_term;
6,431✔
2801
  triple->y = zero_term;
6,431✔
2802
  q_init(&triple->a);
6,431✔
2803
}
6,431✔
2804

2805
static void delete_dl_term(dl_term_t *triple) {
6,431✔
2806
  q_clear(&triple->a);
6,431✔
2807
}
6,431✔
2808

2809

2810
/*
2811
 * Check whether the triple is in IDL or RDL.
2812
 */
2813
static bool check_dl_fragment(context_t *ctx, dl_term_t *triple, bool idl) {
6,431✔
2814
  assert(is_arithmetic_term(ctx->terms, triple->x) && is_pos_term(triple->x) && intern_tbl_is_root(&ctx->intern, triple->x));
2815
  assert(is_arithmetic_term(ctx->terms, triple->y) && is_pos_term(triple->y) && intern_tbl_is_root(&ctx->intern, triple->y));
2816

2817
  return (triple->x == zero_term || is_integer_root(ctx, triple->x) == idl)
6,412✔
2818
    && (triple->y == zero_term || is_integer_root(ctx, triple->y) == idl)
6,431✔
2819
    && (!idl || q_is_integer(&triple->a));
12,862✔
2820
}
2821

2822

2823
/*
2824
 * Check whether aux contains a difference logic term. If so store the term in *triple.
2825
 * All terms of aux must be roots in ctx->interm.
2826
 *
2827
 * Return true if aux is in the difference logic fragment, false otherwise.
2828
 */
2829
static bool dl_convert_poly_buffer(context_t *ctx, dl_term_t *triple, poly_buffer_t *aux) {
6,431✔
2830
  uint32_t n;
2831
  monomial_t *q;
2832

2833
  n = poly_buffer_nterms(aux);
6,431✔
2834
  if (n > 3) return false;
6,431✔
2835
  if (n == 0) return true;
6,431✔
2836

2837
  q = poly_buffer_mono(aux);
6,424✔
2838

2839
  // constant
2840
  q_clear(&triple->a);
6,424✔
2841
  if (q[0].var == const_idx) {
6,424✔
2842
    q_set(&triple->a, &q[0].coeff);
5,261✔
2843
    q ++;
5,261✔
2844
    n --;
5,261✔
2845
  }
2846

2847
  // deal with the non-constant terms
2848
  if (n == 2 && q_opposite(&q[0].coeff, &q[1].coeff)) {
6,424✔
2849
    if (q_is_one(&q[0].coeff)) {
6,408✔
2850
      // a_0 + x_1 - x_2
2851
      triple->x = q[0].var; // x_1
759✔
2852
      triple->y = q[1].var; // x_2
759✔
2853
      return true;
759✔
2854
    }
2855

2856
    if (q_is_one(&q[1].coeff)) {
5,649✔
2857
      // a_0 - x_1 + x_2
2858
      triple->x = q[1].var; // x_2
5,649✔
2859
      triple->y = q[0].var; // x_1
5,649✔
2860
      return true;
5,649✔
2861
    }
2862

2863
  } else if (n == 1) {
16✔
2864
    if (q_is_one(&q[0].coeff)) {
4✔
2865
      // a_0 + x_1
2866
      triple->x = q[0].var; // x_1
4✔
2867
      triple->y = zero_term;
4✔
2868
      return true;
4✔
2869
    }
2870

2871
    if (q_is_minus_one(&q[0].coeff)) {
×
2872
      // a_0 - x_1
2873
      triple->x = zero_term;
×
2874
      triple->y = q[0].var; // x_1
×
2875
      return true;
×
2876
    }
2877

2878
  } else if (n == 0) {
12✔
2879
    triple->x = zero_term;
12✔
2880
    triple->y = zero_term;
12✔
2881
    return true;
12✔
2882
  }
2883

2884
  return false;
×
2885
}
2886

2887

2888
/*
2889
 * Apply substitutions then check whether p can be converted to a dl term.
2890
 * If so store the result in tiple and return true. Otherwise return false;
2891
 */
2892
static bool dl_convert_poly(context_t *ctx, dl_term_t *triple, polynomial_t *p) {
5,670✔
2893
  poly_buffer_t *aux;
2894
  monomial_t *mono;
2895
  term_table_t *terms;
2896
  uint32_t i, n;
2897
  term_t t;
2898

2899
  aux = context_get_poly_buffer(ctx);
5,670✔
2900
  reset_poly_buffer(aux);
5,670✔
2901

2902
  assert(poly_buffer_is_zero(aux));
2903

2904
  n = p->nterms;
5,670✔
2905
  mono = p->mono;
5,670✔
2906

2907
  /*
2908
   * p is of the form a0 + a_1 t_1 + ... + a_n t_n
2909
   * We replace t_i by its root in S(t_i) in the intern table.
2910
   * The result a0 + a_1 S(t_1) + ... + a_n S(t_n) is stored in buffer aux..
2911
   * Then we check whether aux is a difference logic polynomial.
2912
   */
2913
  assert(n > 0); // because zero polynomial is converted to 0 constant
2914

2915
  // deal with the constant first
2916
  if (mono[0].var == const_idx) {
5,670✔
2917
    poly_buffer_add_const(aux, &mono[0].coeff);
5,263✔
2918
    n --;
5,263✔
2919
    mono ++;
5,263✔
2920
  }
2921

2922
  terms = ctx->terms;
5,670✔
2923
  for (i=0; i<n; i++) {
17,010✔
2924
    t = intern_tbl_get_root(&ctx->intern, mono[i].var);
11,340✔
2925
    poly_buffer_addmul_term(terms, aux, t, &mono[i].coeff);
11,340✔
2926
  }
2927

2928
  normalize_poly_buffer(aux);
5,670✔
2929

2930
  /*
2931
   * The QF_RDL theory, as defined by SMT-LIB, allows constraints of
2932
   * the form (<= (- (* a x) (* a y)) b) where a and b are integer
2933
   * constants. We allow rationals here and we also allow
2934
   * constraints like that for QF_IDL (provided b/a is an integer).
2935
   */
2936
  if (! poly_buffer_is_zero(aux)) {
5,670✔
2937
    (void) poly_buffer_make_monic(aux);
5,665✔
2938
  }
2939

2940
  return dl_convert_poly_buffer(ctx, triple, aux);
5,670✔
2941
}
2942

2943

2944
/*
2945
 * Check whether (x - y) is a difference logic term. If so, store the result in triple
2946
 * and return true. Otherwise return false.
2947
 */
2948
static bool dl_convert_diff(context_t *ctx, dl_term_t *triple, term_t x, term_t y) {
761✔
2949
  term_table_t *terms;
2950
  poly_buffer_t *aux;
2951

2952
  assert(is_arithmetic_term(ctx->terms, x) && is_pos_term(x) &&
2953
         is_arithmetic_term(ctx->terms, y) && is_pos_term(y));
2954

2955
  aux = context_get_poly_buffer(ctx);
761✔
2956
  reset_poly_buffer(aux);
761✔
2957
  assert(poly_buffer_is_zero(aux));
2958

2959
  // build polynomial (x - y) after applying substitutions
2960
  terms = ctx->terms;
761✔
2961
  poly_buffer_add_term(terms, aux, intern_tbl_get_root(&ctx->intern, x));
761✔
2962
  poly_buffer_sub_term(terms, aux, intern_tbl_get_root(&ctx->intern, y));
761✔
2963
  normalize_poly_buffer(aux);
761✔
2964

2965
  return dl_convert_poly_buffer(ctx, triple, aux);
761✔
2966
}
2967

2968

2969
/*
2970
 * Check whether term t is a difference logic term. If so convert t to a dl_term
2971
 * and store that in triple.
2972
 * Return true if the conversion succeeds, false otherwise.
2973
 */
2974
static bool dl_convert_term(context_t *ctx, dl_term_t *triple, term_t t) {
5,670✔
2975
  term_table_t *terms;
2976

2977
  assert(is_arithmetic_term(ctx->terms, t));
2978

2979
  terms = ctx->terms;
5,670✔
2980

2981
  // apply substitution
2982
  t = intern_tbl_get_root(&ctx->intern, t);
5,670✔
2983

2984
  assert(is_arithmetic_term(terms, t) && is_pos_term(t)
2985
         && intern_tbl_is_root(&ctx->intern, t));
2986

2987
  switch (term_kind(terms, t)) {
5,670✔
2988
  case ARITH_CONSTANT:
×
2989
    triple->x = zero_term;
×
2990
    triple->y = zero_term;
×
2991
    q_set(&triple->a, rational_term_desc(terms, t));
×
2992
    return true;
×
2993

2994
  case UNINTERPRETED_TERM:
×
2995
    return dl_convert_diff(ctx, triple, t, zero_term);
×
2996

2997
  case ARITH_POLY:
5,670✔
2998
    return dl_convert_poly(ctx, triple, poly_term_desc(terms, t));
5,670✔
2999

3000
  default:
×
3001
    // TODO: we could accept if-then-else here?
3002
    return false;
×
3003
  }
3004
}
3005

3006

3007

3008
/*
3009
 * Increment the number of variables if t has not been seen before
3010
 */
3011
static void count_dl_var(context_t *ctx, term_t t) {
19✔
3012
  bool new;
3013

3014
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t));
3015

3016
  (void) int_rat_hmap_get(ctx->edge_map, t, &new);
19✔
3017
  ctx->dl_profile->num_vars += new;
19✔
3018
}
19✔
3019

3020
/*
3021
 * Update: edge of weight a from source t
3022
 * - in the edge_map, we assign to term t the max weight of all potential
3023
 *   edges of source t. The weight is an absolute value.
3024
 */
3025
static void count_dl_var_and_edge(context_t *ctx, term_t t, rational_t *a) {
12,824✔
3026
  int_rat_hmap_rec_t *d;
3027
  bool new;
3028

3029
  assert(q_is_nonneg(a));
3030
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t));
3031

3032
  d = int_rat_hmap_get(ctx->edge_map, t, &new);
12,824✔
3033
  ctx->dl_profile->num_vars += new;
12,824✔
3034
  if (q_gt(a, &d->value)) {
12,824✔
3035
    // increase bound on edges of source t
3036
    q_set(&d->value, a);
1,750✔
3037
  }
3038
}
12,824✔
3039

3040

3041
/*
3042
 * Update the difference logic statistics for atom x - y <= a
3043
 * - this corresponds to an edge x --> y of absolute weight a >= 0
3044
 * - if the atom is true, the dl solver will add an edge from x to y of weight a
3045
 * - if the atom if false, the dl solver will and an edge from y to x of weight
3046
 *    (or - a - 1 in IDL case)
3047
 */
3048
static void update_dl_stats(context_t *ctx, term_t x, term_t y, rational_t *a, bool idl) {
3,867✔
3049
  if (x == y) {
3,867✔
3050
    /*
3051
     * The atom simplifies to true or false but we must count x as a variable,
3052
     * because the diff logic solver will still create a variable for x.
3053
     */
3054
    count_dl_var(ctx, x);
9✔
3055
  } else {
3056
    /*
3057
     * We use the absolute value as an upper bound:
3058
     *  x --> y with weight = |a|
3059
     *  y --> x with weight = |a| or |a|+1 if idl
3060
     */
3061
    if (q_is_neg(a)) q_neg(a);
3,858✔
3062
    count_dl_var_and_edge(ctx, x, a);
3,858✔
3063
    if (idl) q_add_one(a);
3,858✔
3064
    count_dl_var_and_edge(ctx, y, a);
3,858✔
3065
    ctx->dl_profile->num_atoms ++;
3,858✔
3066
  }
3067
}
3,867✔
3068

3069

3070
/*
3071
 * Same thing for (x - y == a): the max weight is |a| + 1 for both x and y
3072
 */
3073
static void update_dleq_stats(context_t *ctx, term_t x, term_t y, rational_t *a, bool idl) {
2,564✔
3074
  if (x == y) {
2,564✔
3075
    count_dl_var(ctx, x);
10✔
3076
  } else {
3077
    if (q_is_neg(a)) q_neg(a);
2,554✔
3078
    if (idl) q_add_one(a);
2,554✔
3079
    count_dl_var_and_edge(ctx, x, a);
2,554✔
3080
    count_dl_var_and_edge(ctx, y, a);
2,554✔
3081
    ctx->dl_profile->num_eqs ++;
2,554✔
3082
    ctx->dl_profile->num_atoms ++;
2,554✔
3083
  }
3084
}
2,564✔
3085

3086
/*
3087
 * Check atom (t == 0) and update statistics
3088
 * - idl = true to check for IDL, false for RDL
3089
 */
3090
static bool check_dl_eq0_atom(context_t *ctx, term_t t, bool idl) {
1,803✔
3091
  dl_term_t *triple;
3092
  bool result;
3093

3094
  triple = objstack_alloc(&ctx->ostack, sizeof(dl_term_t), (cleaner_t) delete_dl_term);
1,803✔
3095
  init_dl_term(triple);
1,803✔
3096
  result = dl_convert_term(ctx, triple, t) && check_dl_fragment(ctx, triple, idl);
1,803✔
3097
  if (result) {
1,803✔
3098
    // a + x - y = 0 <--> (y - x = a)
3099
    update_dleq_stats(ctx, triple->y, triple->x, &triple->a, idl);
1,803✔
3100
  }
3101
  //  delete_dl_term(&triple);
3102
  objstack_pop(&ctx->ostack);
1,803✔
3103

3104
  return result;
1,803✔
3105
}
3106

3107
/*
3108
 * Check atom (t >= 0) and update statistics
3109
 */
3110
static bool check_dl_geq0_atom(context_t *ctx, term_t t, bool idl) {
3,867✔
3111
  dl_term_t *triple;
3112
  bool result;
3113

3114
  triple = objstack_alloc(&ctx->ostack, sizeof(dl_term_t), (cleaner_t) delete_dl_term);
3,867✔
3115
  init_dl_term(triple);
3,867✔
3116
  result = dl_convert_term(ctx, triple, t) && check_dl_fragment(ctx, triple, idl);
3,867✔
3117
  if (result) {
3,867✔
3118
    // a + x - y >= 0 <--> (y - x <= -a)
3119
    q_neg(&triple->a);
3,867✔
3120
    update_dl_stats(ctx, triple->y, triple->x, &triple->a, idl);
3,867✔
3121
  }
3122
  //  delete_dl_term(triple);
3123
  objstack_pop(&ctx->ostack);
3,867✔
3124

3125
  return result;
3,867✔
3126
}
3127

3128
/*
3129
 * Check atom (t1 == t2) and update statistics
3130
 */
3131
static bool check_dl_eq_atom(context_t *ctx, term_t t1, term_t t2, bool idl) {
761✔
3132
  dl_term_t *triple;
3133
  bool result;
3134

3135
  triple = objstack_alloc(&ctx->ostack, sizeof(dl_term_t), (cleaner_t) delete_dl_term);
761✔
3136
  init_dl_term(triple);
761✔
3137
  result = dl_convert_diff(ctx, triple, t1, t2) && check_dl_fragment(ctx, triple, idl);
761✔
3138
  if (result) {
761✔
3139
    // a + x - y = 0 <--> (y - x = a)
3140
    update_dleq_stats(ctx, triple->y, triple->x, &triple->a, idl);
761✔
3141
  }
3142
  //  delete_dl_term(triple);
3143
  objstack_pop(&ctx->ostack);
761✔
3144

3145
  return result;
761✔
3146
}
3147

3148

3149
/*
3150
 * Check atom (distinct a[0] .... a[n-1]) and update statistics
3151
 */
3152
static bool check_dl_distinct_atom(context_t *ctx, term_t *a, uint32_t n, bool idl) {
×
3153
  uint32_t i, j;
3154

3155
  assert(n > 2);
3156

3157
  for (i=0; i<n-1; i++) {
×
3158
    for (j=i+1; j<n; j++) {
×
3159
      if (! check_dl_eq_atom(ctx, a[i], a[j], idl)) {
×
3160
        return false;
×
3161
      }
3162
    }
3163
  }
3164

3165
  return true;
×
3166
}
3167

3168

3169
/*
3170
 * Analyze all arithmetic atoms in term t and fill ctx->dl_profile
3171
 * - if idl is true, this checks for integer difference logic
3172
 *   otherwise, checks for real difference logic
3173
 * - cache must be initialized and contain all the terms already visited
3174
 */
3175
static void analyze_dl(context_t *ctx, term_t t, bool idl) {
20,256✔
3176
  term_table_t *terms;
3177
  composite_term_t *cmp;
3178
  uint32_t i, n;
3179
  int32_t idx;
3180
  term_t r;
3181
  int32_t code;
3182

3183
  assert(is_boolean_term(ctx->terms, t));
3184

3185
  idx = index_of(t); // remove negation
20,256✔
3186

3187
  if (int_bvset_add_check(ctx->cache, idx)) {
20,256✔
3188
    /*
3189
     * idx not visited yet
3190
     */
3191
    terms = ctx->terms;
11,773✔
3192
    switch (kind_for_idx(terms, idx)) {
11,773✔
3193
    case CONSTANT_TERM:
6✔
3194
      assert(idx == bool_const);
3195
      break;
6✔
3196

3197
    case UNINTERPRETED_TERM:
728✔
3198
      // follow the substitutions if any
3199
      r = intern_tbl_get_root(&ctx->intern, pos_term(idx));
728✔
3200
      if (r != pos_term(idx)) {
728✔
3201
        analyze_dl(ctx,  r, idl);
57✔
3202
      }
3203
      break;
728✔
3204

3205
    case ITE_TERM:
4,398✔
3206
    case ITE_SPECIAL:
3207
    case OR_TERM:
3208
    case XOR_TERM:
3209
      cmp = composite_for_idx(terms, idx);
4,398✔
3210
      n = cmp->arity;
4,398✔
3211
      for (i=0; i<n; i++) {
18,512✔
3212
        analyze_dl(ctx, cmp->arg[i], idl);
14,114✔
3213
      }
3214
      break;
4,398✔
3215

3216
    case EQ_TERM:
210✔
3217
      cmp = composite_for_idx(terms, idx);
210✔
3218
      assert(cmp->arity == 2);
3219
      if (is_boolean_term(terms, cmp->arg[0])) {
210✔
3220
        // boolean equality
3221
        analyze_dl(ctx, cmp->arg[0], idl);
210✔
3222
        analyze_dl(ctx, cmp->arg[1], idl);
210✔
3223
      } else {
3224
        goto abort;
×
3225
      }
3226
      break;
210✔
3227

3228
    case DISTINCT_TERM:
×
3229
      cmp = composite_for_idx(terms, idx);
×
3230
      if (! check_dl_distinct_atom(ctx, cmp->arg, cmp->arity, idl)) {
×
3231
        goto abort;
×
3232
      }
3233
      break;
×
3234

3235
    case ARITH_EQ_ATOM:
1,803✔
3236
      // term (x == 0): check whether x is a difference logic term
3237
      if (! check_dl_eq0_atom(ctx, integer_value_for_idx(terms, idx), idl)) {
1,803✔
3238
        goto abort;
×
3239
      }
3240
      break;
1,803✔
3241

3242
    case ARITH_GE_ATOM:
3,867✔
3243
      // term (x >= 0): check whether x is a difference logic term
3244
      if (! check_dl_geq0_atom(ctx, integer_value_for_idx(terms, idx), idl)) {
3,867✔
3245
        goto abort;
×
3246
      }
3247
      break;
3,867✔
3248

3249
    case ARITH_BINEQ_ATOM:
761✔
3250
      // term (x == y): check whether x - y is a difference logic term
3251
      cmp = composite_for_idx(terms, idx);
761✔
3252
      assert(cmp->arity == 2);
3253
      if (! check_dl_eq_atom(ctx, cmp->arg[0], cmp->arg[1], idl)) {
761✔
3254
        goto abort;
×
3255
      }
3256
      break;
761✔
3257

3258
    default:
×
3259
      goto abort;
×
3260
    }
3261
  }
3262

3263
  return;
20,256✔
3264

3265
 abort:
×
3266
  code = idl ? FORMULA_NOT_IDL : FORMULA_NOT_RDL;
×
3267
  longjmp(ctx->env, code);
×
3268
}
3269

3270

3271
/*
3272
 * Check all terms in vector v
3273
 */
3274
static void analyze_diff_logic_vector(context_t *ctx, ivector_t *v, bool idl) {
105✔
3275
  uint32_t i, n;
3276

3277
  n = v->size;
105✔
3278
  for (i=0; i<n; i++) {
5,770✔
3279
    analyze_dl(ctx, v->data[i], idl);
5,665✔
3280
  }
3281
}
105✔
3282

3283

3284
/*
3285
 * Check difference logic after flattening:
3286
 * - check whether all formulas in top_eqs, top_atoms, and top_formulas
3287
 *   are in the difference logic fragment. If so, compute the benchmark
3288
 *   profile (i.e., statistics on number of variables + atoms)
3289
 * - if idl is true, all variables must be integer (i.e., the formula is
3290
 *   in the IDL fragment), otherwise all variables must be real (i.e., the
3291
 *   formula is in the RDL fragment).
3292
 *
3293
 * - if all assertions are in IDL or RDL.
3294
 *   the statistics are stored in ctx->dl_profile.
3295
 * - raise an exception (either FORMULA_NOT_IDL or FORMULA_NOT_RDL) otherwise.
3296
 *
3297
 * This function is used to decide whether to use simplex or a
3298
 * specialized solver when the architecture is CTX_AUTO_IDL or
3299
 * CTX_AUTO_RDL.  Because this function is called before the actual
3300
 * arithmetic solver is created, we assume that no arithmetic term is
3301
 * internalized, and that top_interns is empty.
3302
 */
3303
void analyze_diff_logic(context_t *ctx, bool idl) {
35✔
3304
  dl_data_t *stats;
3305
  int_rat_hmap_t *edges;
3306

3307
  assert(ctx->dl_profile == NULL && ctx->edge_map == NULL);
3308

3309
  // allocate and initialize dl_profile, edge_map, and cache
3310
  stats = context_get_dl_profile(ctx);
35✔
3311
  edges = context_get_edge_map(ctx);
35✔
3312
  (void) context_get_cache(ctx);
35✔
3313

3314
  analyze_diff_logic_vector(ctx, &ctx->top_eqs, idl);
35✔
3315
  analyze_diff_logic_vector(ctx, &ctx->top_atoms, idl);
35✔
3316
  analyze_diff_logic_vector(ctx, &ctx->top_formulas, idl);
35✔
3317

3318
  // compute the bound on path length
3319
  int_rat_hmap_sum(edges, &stats->path_bound);
35✔
3320

3321
#if (TRACE || TRACE_DL)
3322
  printf("==== Difference logic ====\n");
3323
  if (idl) {
3324
    printf("---> IDL\n");
3325
  } else {
3326
    printf("---> RDL\n");
3327
  }
3328
  printf("---> %"PRIu32" variables\n", stats->num_vars);
3329
  printf("---> %"PRIu32" atoms\n", stats->num_atoms);
3330
  printf("---> %"PRIu32" equalities\n", stats->num_eqs);
3331
  printf("---> path bound = ");
3332
  q_print(stdout, &stats->path_bound);
3333
  printf("\n");
3334
#endif
3335

3336
  context_free_cache(ctx);
35✔
3337
  context_free_edge_map(ctx);
35✔
3338
}
35✔
3339

3340

3341

3342
/*******************
3343
 *  CONDITIONALS   *
3344
 ******************/
3345

3346
/*
3347
 * Allocate a conditional descriptor from the store
3348
 */
3349
static conditional_t *new_conditional(context_t *ctx) {
5,255✔
3350
  conditional_t *d;
3351

3352
  d = objstore_alloc(&ctx->cstore);
5,255✔
3353
  init_conditional(d, ctx->terms);
5,255✔
3354
  return d;
5,255✔
3355
}
3356

3357
/*
3358
 * Free conditional descriptor d
3359
 */
3360
void context_free_conditional(context_t *ctx, conditional_t *d) {
5,255✔
3361
  delete_conditional(d);
5,255✔
3362
  objstore_free(&ctx->cstore, d);
5,255✔
3363
}
5,255✔
3364

3365
/*
3366
 * Attempt to convert an if-then-else term to a conditional
3367
 * - return NULL if the conversion fails
3368
 * - return a conditional descriptor otherwise
3369
 * - if NON-NULL, the result must be freed when no-longer used
3370
 *   by calling context_free_conditional
3371
 */
3372
conditional_t *context_make_conditional(context_t *ctx, composite_term_t *ite) {
5,255✔
3373
  conditional_t *d;
3374

3375
  assert(ite->arity == 3);
3376

3377
  d = new_conditional(ctx);
5,255✔
3378
  convert_ite_to_conditional(d, ite->arg[0], ite->arg[1], ite->arg[2]);
5,255✔
3379
  if (d->nconds <= 1) {
5,255✔
3380
    context_free_conditional(ctx, d);
4,991✔
3381
    d = NULL;
4,991✔
3382
  }
3383

3384
  return d;
5,255✔
3385
}
3386

3387

3388
/*
3389
 * Check whether conditional_t *d can be simplified
3390
 * - d is of the form
3391
 *    COND c1 --> a1
3392
 *         c2 --> a2
3393
 *         ...
3394
 *         else --> b
3395
 *    END
3396
 *   where c_1 ... c_n are pairwise disjoint
3397
 *
3398
 * - if one of c_i is true, the function returns a_i
3399
 * - if all c_i's are false, the function returns d
3400
 * - in all other cases, the function returns NULL_TERM
3401
 */
3402
term_t simplify_conditional(context_t *ctx, conditional_t *d) {
264✔
3403
  uint32_t i, n;
3404
  bool all_false;
3405
  term_t r, result;
3406

3407
  n = d->nconds;
264✔
3408
  all_false = true;
264✔
3409
  result = NULL_TERM;
264✔
3410

3411
  for (i=0; i<n; i++) {
855✔
3412
    r = intern_tbl_get_root(&ctx->intern, d->pair[i].cond);
609✔
3413
    if (term_is_true(ctx, r)) {
609✔
3414
      result = d->pair[i].val;
18✔
3415
      goto done;
18✔
3416
    }
3417
    all_false &= term_is_false(ctx, r);
591✔
3418
  }
3419

3420
  if (all_false) {
246✔
3421
    result = d->defval;
1✔
3422
  }
3423

3424
 done:
245✔
3425
  return result;
264✔
3426
}
3427

3428

3429
#if 0
3430

3431
/*
3432
 * FOR TESTING ONLY
3433
 */
3434

3435
/*
3436
 * Print result of conversion of t to a conditional structure
3437
 */
3438
static void print_conditional_conversion(conditional_t *d, term_t t) {
3439
  yices_pp_t pp;
3440
  pp_area_t area;
3441
  uint32_t i, n;
3442

3443
  area.width = 400;
3444
  area.height = 300;
3445
  area.offset = 0;
3446
  area.stretch = false;
3447
  area.truncate = true;
3448
  init_default_yices_pp(&pp, stdout, &area);
3449

3450
  pp_open_block(&pp, PP_OPEN);
3451
  pp_string(&pp, "Conversion to conditional for term");
3452
  pp_term_full(&pp, d->terms, t);
3453
  pp_close_block(&pp, false);
3454
  flush_yices_pp(&pp);
3455

3456
  pp_string(&pp, "result:");
3457
  flush_yices_pp(&pp);
3458

3459
  n = d->nconds;
3460
  for (i=0; i<n; i++) {
3461
    pp_open_block(&pp, PP_OPEN_ITE);
3462
    pp_term_full(&pp, d->terms, d->pair[i].cond);
3463
    pp_term_full(&pp, d->terms, d->pair[i].val);
3464
    pp_close_block(&pp, true);
3465
  }
3466

3467
  pp_open_block(&pp, PP_OPEN_PAR);
3468
  pp_string(&pp, "else");
3469
  pp_term_full(&pp, d->terms, d->defval);
3470
  pp_close_block(&pp, true);
3471

3472
  delete_yices_pp(&pp, true);
3473
}
3474

3475
/*
3476
 * Try to flatten an ite term t into a conditional
3477
 * - if that works print the result
3478
 */
3479
void context_test_conditional_for_ite(context_t *ctx, composite_term_t *ite, term_t t) {
3480
  conditional_t condi;
3481

3482
  init_conditional(&condi, ctx->terms);
3483
  convert_ite_to_conditional(&condi, ite->arg[0], ite->arg[1], ite->arg[2]);
3484

3485
  if (condi.nconds > 1) {
3486
    print_conditional_conversion(&condi, t);
3487
  }
3488

3489
  delete_conditional(&condi);
3490
}
3491

3492

3493
#endif
3494

3495

3496
/****************************************************
3497
 *  SIMPLIFICATIONS FOR SPECIAL IF-THEN-ELSE TERMS  *
3498
 ***************************************************/
3499

3500
/*
3501
 * If t is (ite c a b), we can try to rewrite (= t k) into a conjunction
3502
 * of terms using the two rules:
3503
 *   (= (ite c a b) k) --> c and (= a k)        if k != b holds
3504
 *   (= (ite c a b) k) --> (not c) and (= b k)  if k != a holds
3505
 *
3506
 * This works best for the NEC benchmarks in SMT LIB, where many terms
3507
 * are deeply nested if-then-else terms with constant leaves.
3508
 *
3509
 * The function below does that: it rewrites (eq t k) to (and c_0 ... c_n (eq t' k))
3510
 * - the boolean terms c_0 ... c_n are added to vector v
3511
 * - the term t' is returned
3512
 * So the simplification worked it the returned term t' is different from t
3513
 * (and then v->size is not 0).
3514
 */
3515
term_t flatten_ite_equality(context_t *ctx, ivector_t *v, term_t t, term_t k) {
113,524✔
3516
  term_table_t *terms;
3517
  composite_term_t *ite;
3518

3519
  terms = ctx->terms;
113,524✔
3520
  assert(is_pos_term(t) && good_term(terms, t));
3521

3522
  while (is_ite_term(terms, t)) {
838,812✔
3523
    // t is (ite c a b)
3524
    ite = ite_term_desc(terms, t);
769,844✔
3525
    assert(ite->arity == 3);
3526

3527
    if (disequal_terms(terms, k, ite->arg[1], true)) {
769,844✔
3528
      // (t == k) is (not c) and (t == b)
3529
      ivector_push(v, opposite_term(ite->arg[0]));
709,356✔
3530
      t = intern_tbl_get_root(&ctx->intern, ite->arg[2]);
709,356✔
3531

3532
    } else if (disequal_terms(terms, k, ite->arg[2], true)) {
60,488✔
3533
      // (t == k) is c and (t == a)
3534
      ivector_push(v, ite->arg[0]);
15,932✔
3535
      t = intern_tbl_get_root(&ctx->intern, ite->arg[1]);
15,932✔
3536

3537
    } else {
3538
      // no more flattening possible
3539
      break;
44,556✔
3540
    }
3541
  }
3542

3543
  return t;
113,524✔
3544
}
3545

3546

3547

3548

3549

3550

3551

3552
/***********************
3553
 *  SYMMETRY BREAKING  *
3554
 **********************/
3555

3556
#if TRACE_SYM_BREAKING
3557

3558
static void show_constant_set(yices_pp_t *pp, term_table_t *terms, rng_record_t *r) {
3559
  uint32_t i, n;
3560

3561
  n = r->num_constants;
3562
  pp_open_block(pp, PP_OPEN);
3563
  for (i=0; i<n; i++) {
3564
    pp_term(pp, terms, r->cst[i]);
3565
  }
3566
  pp_close_block(pp, false);
3567
}
3568

3569
static void pp_constraints(yices_pp_t *pp, sym_breaker_t *breaker, rng_record_t *r) {
3570
  uint32_t i, j, n;
3571

3572
  n = r->num_terms;
3573
  for (i=0; i<n; i++) {
3574
    j = r->idx[i];
3575
    pp_open_block(pp, PP_OPEN);
3576
    pp_string(pp, "Formula ");
3577
    pp_uint32(pp, j);
3578
    pp_close_block(pp, false);
3579
    flush_yices_pp(pp);
3580

3581
    pp_term_full(pp, breaker->terms, breaker->ctx->top_formulas.data[j]);
3582
    flush_yices_pp(pp);
3583

3584
    pp_open_block(pp, PP_OPEN);
3585
    pp_string(pp, "constraint on term ");
3586
    pp_term_full(pp, breaker->terms, r->trm[i]);
3587
    pp_close_block(pp, false);
3588
    flush_yices_pp(pp);
3589
    flush_yices_pp(pp);
3590
  }
3591
}
3592

3593
static void show_range_constraints(sym_breaker_t *breaker) {
3594
  yices_pp_t pp;
3595
  pp_area_t area;
3596
  rng_record_t **v;
3597
  uint32_t i, n;
3598

3599
  area.width = 150;
3600
  area.height = 30;
3601
  area.offset = 0;
3602
  area.stretch = false;
3603
  area.truncate = true;
3604
  init_default_yices_pp(&pp, stdout, &area);
3605

3606
  v = breaker->sorted_constraints;
3607
  n = breaker->num_constraints;
3608
  for (i=0; i<n; i++) {
3609
    pp_open_block(&pp, PP_OPEN);
3610
    pp_string(&pp, "Range constraints for set: ");
3611
    show_constant_set(&pp, breaker->terms, v[i]);
3612
    pp_close_block(&pp, false);
3613
    flush_yices_pp(&pp);
3614
    flush_yices_pp(&pp);
3615
    pp_constraints(&pp, breaker, v[i]);
3616
  }
3617

3618
  delete_yices_pp(&pp, true);
3619
}
3620

3621
static void print_constant_set(sym_breaker_t *breaker, rng_record_t *r) {
3622
  uint32_t i, n;
3623

3624
  n = r->num_constants;
3625
  for (i=0; i<n; i++) {
3626
    fputc(' ', stdout);
3627
    print_term(stdout, breaker->terms, r->cst[i]);
3628
  }
3629
}
3630

3631
static void print_candidates(sym_breaker_t *breaker, sym_breaker_sets_t *sets) {
3632
  uint32_t i, n;
3633

3634
  printf("--- Candidates ---\n");
3635
  n = sets->num_candidates;
3636
  for (i=0; i<n; i++) {
3637
    printf("   ");
3638
    print_term_full(stdout, breaker->terms, sets->candidates[i]);
3639
    printf("\n");
3640
  }
3641
}
3642

3643
#endif
3644

3645

3646
/*
3647
 * Break symmetries
3648
 */
3649
void break_uf_symmetries(context_t *ctx) {
30✔
3650
  sym_breaker_t *breaker;
3651
  sym_breaker_sets_t *sets;
3652
  rng_record_t **v;
3653
  uint32_t i, j, n;
3654

3655
  breaker = objstack_alloc(&ctx->ostack, sizeof(sym_breaker_t), (cleaner_t) delete_sym_breaker);
30✔
3656
  init_sym_breaker(breaker, ctx);
30✔
3657
  collect_range_constraints(breaker);
30✔
3658

3659
#if TRACE_SYM_BREAKING
3660
  show_range_constraints(breaker);
3661
#endif
3662

3663
  v = breaker->sorted_constraints;
30✔
3664
  n = breaker->num_constraints;
30✔
3665
  if (n > 0) {
30✔
3666
    // test of symmetry breaking
3667
    sets = &breaker->sets;
11✔
3668
    for (i=0; i<n; i++) {
61✔
3669
      if (check_assertion_invariance(breaker, v[i])) {
50✔
3670
#if TRACE_SYM_BREAKING
3671
        printf("Breaking symmetries using set[%"PRIu32"]:", i);
3672
        print_constant_set(breaker, v[i]);
3673
        printf("\n");
3674
#endif
3675
        breaker_sets_copy_record(sets, v[i]);
9✔
3676
        for (j=i+1; j<n; j++) {
44✔
3677
          if (range_record_subset(v[j], v[i])) {
35✔
3678
#if TRACE_SYM_BREAKING
3679
            printf("Adding set[%"PRIu32"]:", j);
3680
            print_constant_set(breaker, v[j]);
3681
            printf("\n");
3682
#endif
3683
            breaker_sets_add_record(sets, v[j]);
34✔
3684
          }
3685
        }
3686
#if TRACE_SYM_BREAKING
3687
        print_candidates(breaker, sets);
3688
        printf("\n");
3689
#endif
3690
        break_symmetries(breaker, sets);
9✔
3691
      } else {
3692
#if TRACE_SYM_BREAKING
3693
        printf("Set[%"PRIu32"]:", i);
3694
        print_constant_set(breaker, v[i]);
3695
        printf(" not symmetrical\n\n");
3696
#endif
3697
      }
3698
    }
3699

3700
  } else {
3701
#if TRACE_SYM_BREAKING
3702
    printf("\n*** NO SYMMETRY CANDIDATES ***\n\n");
3703
#endif
3704
  }
3705

3706
  //  delete_sym_breaker(breaker);
3707
  objstack_pop(&ctx->ostack);
30✔
3708
}
30✔
3709

3710

3711

3712

3713
/******************************
3714
 *  CONDITIONAL DEFINITIONS   *
3715
 *****************************/
3716

3717
void process_conditional_definitions(context_t *ctx) {
52✔
3718
  cond_def_collector_t *collect;
3719
  ivector_t *v;
3720
  uint32_t i, n;
3721

3722
  v = &ctx->top_formulas;
52✔
3723
  n = v->size;
52✔
3724
  if (n > 0) {
52✔
3725
    collect = objstack_alloc(&ctx->ostack, sizeof(cond_def_collector_t),
44✔
3726
                             (cleaner_t) delete_cond_def_collector);
3727
    init_cond_def_collector(collect, ctx);
44✔
3728
    for (i=0; i<n; i++) {
3,517✔
3729
      extract_conditional_definitions(collect, v->data[i]);
3,473✔
3730
    }
3731
    analyze_conditional_definitions(collect);
44✔
3732
    //    delete_cond_def_collector(&collect);
3733
    objstack_pop(&ctx->ostack);
44✔
3734
  }
3735
}
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