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

SRI-CSL / yices2 / 26234961786

21 May 2026 03:14PM UTC coverage: 67.559% (+0.1%) from 67.453%
26234961786

Pull #611

github

disteph
Serialize supplemental MCSAT satellite entry points

Supported by Codex/GPT5.5 and Windsurf/Opus4.7
Pull Request #611: Wrap MCSAT as a Nelson-Oppen theory solver in CDCL(T) architecture

903 of 1349 new or added lines in 17 files covered. (66.94%)

2 existing lines in 2 files now uncovered.

86771 of 128437 relevant lines covered (67.56%)

1608322.57 hits per line

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

79.17
/src/context/context.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
 * ASSERTION CONTEXT
21
 */
22

23
#include <inttypes.h>
24

25
#include "api/context_config.h"
26
#include "context/context.h"
27
#include "context/context_simplifier.h"
28
#include "context/context_utils.h"
29
#include "context/internalization_codes.h"
30
#include "context/ite_flattener.h"
31
#include "solvers/bv/bvsolver.h"
32
#include "solvers/floyd_warshall/idl_floyd_warshall.h"
33
#include "solvers/floyd_warshall/rdl_floyd_warshall.h"
34
#include "solvers/funs/fun_solver.h"
35
#include "solvers/mcsat_satellite.h"
36
#include "solvers/quant/quant_solver.h"
37
#include "solvers/cdcl/delegate.h"
38
#include "solvers/simplex/simplex.h"
39
#include "terms/poly_buffer_terms.h"
40
#include "terms/rba_buffer_terms.h"
41
#include "terms/term_explorer.h"
42
#include "terms/term_manager.h"
43
#include "terms/term_utils.h"
44
#include "utils/int_hash_map.h"
45
#include "utils/memalloc.h"
46

47
#include "mcsat/solver.h"
48
#include "mt/thread_macros.h"
49

50
#include "api/yices_globals.h"
51

52
#define TRACE 0
53

54
#if TRACE
55

56
#include <stdio.h>
57

58
#include "io/term_printer.h"
59
#include "solvers/cdcl/smt_core_printer.h"
60

61
#endif
62

63

64

65

66

67
/**********************
68
 *  INTERNALIZATION   *
69
 *********************/
70

71
/*
72
 * Main internalization functions:
73
 * - convert a term t to an egraph term
74
 * - convert a boolean term t to a literal
75
 * - convert an integer or real term t to an arithmetic variable
76
 * - convert a bitvector term t to a bitvector variable
77
 */
78
static occ_t internalize_to_eterm(context_t *ctx, term_t t);
79
static literal_t internalize_to_literal(context_t *ctx, term_t t);
80
static thvar_t internalize_to_arith(context_t *ctx, term_t t);
81
static thvar_t internalize_to_bv(context_t *ctx, term_t t);
82

83
static literal_t map_arith_eq_to_literal(context_t *ctx, term_t t);
84
static literal_t map_arith_geq_to_literal(context_t *ctx, term_t t);
85
static literal_t map_arith_is_int_to_literal(context_t *ctx, term_t t);
86
static literal_t map_arith_divides_const_to_literal(context_t *ctx, term_t d, term_t t);
87

88
static inline mcsat_satellite_t *context_mcsat_satellite(context_t *ctx);
89
static bool context_atom_requires_mcsat(context_t *ctx, term_t atom);
90
static void context_observe_mcsat_atom(context_t *ctx, term_t atom, literal_t l);
91
static literal_t map_mcsat_atom_to_literal(context_t *ctx, term_t atom);
92
static void context_reset_mcsat_relaxation(context_t *ctx);
93
static void context_disable_mcsat_supplement(context_t *ctx);
94

95

96
/*
97
 * Supplementary MCSAT support (CDCL(T) mode)
98
 */
99
static inline mcsat_satellite_t *context_mcsat_satellite(context_t *ctx) {
25✔
100
  if (ctx->egraph == NULL) {
25✔
NEW
101
    return NULL;
×
102
  }
103
  return (mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT];
25✔
104
}
105

106
static inline bool divisor_requires_mcsat(term_table_t *terms, term_t t) {
5✔
107
  t = unsigned_term(t);
5✔
108
  return term_kind(terms, t) != ARITH_CONSTANT;
5✔
109
}
110

111
/*
112
 * Detect whether t contains arithmetic or finite-field subterms.
113
 * This is used to route all relevant arithmetic/FF atoms to the supplementary
114
 * MCSAT context once supplementation is active.
115
 */
116
static bool term_contains_arith_or_ff(context_t *ctx, term_t t, int_hmap_t *cache) {
26✔
117
  term_table_t *terms;
118
  int_hmap_pair_t *p;
119
  type_t tau;
120
  type_kind_t tkind;
121
  bool found;
122
  uint32_t i, nchildren;
123

124
  if (t < 0) {
26✔
NEW
125
    return false;
×
126
  }
127

128
  t = unsigned_term(t);
26✔
129
  p = int_hmap_find(cache, t);
26✔
130
  if (p != NULL) {
26✔
NEW
131
    return p->val != 0;
×
132
  }
133

134
  terms = ctx->terms;
26✔
135
  tau = term_type(terms, t);
26✔
136
  tkind = type_kind(terms->types, tau);
26✔
137

138
  /*
139
   * Variables of arithmetic/finite-field type may not satisfy
140
   * is_arithmetic_term/is_finitefield_term, so include type-based detection.
141
   */
142
  found = is_arithmetic_term(terms, t) || is_finitefield_term(terms, t) ||
39✔
143
          tkind == INT_TYPE || tkind == REAL_TYPE || is_ff_type(terms->types, tau);
39✔
144

145
  if (!found) {
26✔
146
    if (term_is_projection(terms, t)) {
13✔
NEW
147
      found = term_contains_arith_or_ff(ctx, proj_term_arg(terms, t), cache);
×
148

149
    } else if (term_is_sum(terms, t)) {
13✔
NEW
150
      nchildren = term_num_children(terms, t);
×
NEW
151
      for (i = 0; i < nchildren && !found; i++) {
×
152
        term_t child;
153
        mpq_t q;
NEW
154
        mpq_init(q);
×
NEW
155
        sum_term_component(terms, t, i, q, &child);
×
NEW
156
        found = term_contains_arith_or_ff(ctx, child, cache);
×
NEW
157
        mpq_clear(q);
×
158
      }
159

160
    } else if (term_is_bvsum(terms, t)) {
13✔
161
      int32_t *aux;
162
      uint32_t nbits;
163
      term_t child;
164

NEW
165
      nbits = term_bitsize(terms, t);
×
NEW
166
      aux = (int32_t *) safe_malloc(nbits * sizeof(int32_t));
×
NEW
167
      nchildren = term_num_children(terms, t);
×
NEW
168
      for (i = 0; i < nchildren && !found; i++) {
×
NEW
169
        bvsum_term_component(terms, t, i, aux, &child);
×
NEW
170
        found = term_contains_arith_or_ff(ctx, child, cache);
×
171
      }
NEW
172
      safe_free(aux);
×
173

174
    } else if (term_is_product(terms, t)) {
13✔
NEW
175
      nchildren = term_num_children(terms, t);
×
NEW
176
      for (i = 0; i < nchildren && !found; i++) {
×
177
        term_t child;
178
        uint32_t exp;
NEW
179
        product_term_component(terms, t, i, &child, &exp);
×
NEW
180
        found = term_contains_arith_or_ff(ctx, child, cache);
×
181
      }
182

183
    } else if (term_is_composite(terms, t)) {
13✔
184
      nchildren = term_num_children(terms, t);
13✔
185
      for (i = 0; i < nchildren && !found; i++) {
26✔
186
        found = term_contains_arith_or_ff(ctx, term_child(terms, t, i), cache);
13✔
187
      }
188
    }
189
  }
190

191
  p = int_hmap_get(cache, t);
26✔
192
  p->val = found ? 1 : 0;
26✔
193
  return found;
26✔
194
}
195

196
static bool term_requires_mcsat_supplement(context_t *ctx, term_t t, int_hmap_t *cache) {
83✔
197
  term_table_t *terms;
198
  int_hmap_pair_t *p;
199
  type_t tau;
200
  bool trigger;
201
  uint32_t i, nchildren;
202

203
  if (t < 0) {
83✔
204
    return false;
2✔
205
  }
206

207
  t = unsigned_term(t);
81✔
208
  p = int_hmap_find(cache, t);
81✔
209
  if (p != NULL) {
81✔
210
    return p->val != 0;
1✔
211
  }
212

213
  terms = ctx->terms;
80✔
214
  tau = term_type(terms, t);
80✔
215
  trigger = false;
80✔
216

217
  // finite-field usage
218
  if (is_finitefield_term(terms, t) || is_ff_type(terms->types, tau)) {
80✔
NEW
219
    trigger = true;
×
220
  }
221

222
  if (!trigger) {
80✔
223
    switch (term_kind(terms, t)) {
80✔
224
    case ARITH_ROOT_ATOM:
3✔
225
    case ARITH_FF_CONSTANT:
226
    case ARITH_FF_POLY:
227
    case ARITH_FF_EQ_ATOM:
228
    case ARITH_FF_BINEQ_ATOM:
229
      trigger = true;
3✔
230
      break;
3✔
231

232
    case ARITH_RDIV:
3✔
233
      trigger = divisor_requires_mcsat(terms, arith_rdiv_term_desc(terms, t)->arg[1]);
3✔
234
      break;
3✔
235

NEW
236
    case ARITH_IDIV:
×
NEW
237
      trigger = divisor_requires_mcsat(terms, arith_idiv_term_desc(terms, t)->arg[1]);
×
NEW
238
      break;
×
239

NEW
240
    case ARITH_MOD:
×
NEW
241
      trigger = divisor_requires_mcsat(terms, arith_mod_term_desc(terms, t)->arg[1]);
×
NEW
242
      break;
×
243

NEW
244
    case ARITH_DIVIDES_ATOM:
×
NEW
245
      trigger = divisor_requires_mcsat(terms, arith_divides_atom_desc(terms, t)->arg[0]);
×
NEW
246
      break;
×
247

248
    default:
74✔
249
      break;
74✔
250
    }
251
  }
252

253
  // arithmetic nonlinearity (including deep products in arithmetic predicates)
254
  if (!trigger && is_arithmetic_term(terms, t) && term_degree(terms, t) > 1) {
80✔
255
    trigger = true;
12✔
256
  }
257

258
  if (!trigger) {
80✔
259
    if (term_is_projection(terms, t)) {
63✔
NEW
260
      trigger = term_requires_mcsat_supplement(ctx, proj_term_arg(terms, t), cache);
×
261

262
    } else if (term_is_sum(terms, t)) {
63✔
263
      nchildren = term_num_children(terms, t);
2✔
264
      for (i=0; i<nchildren && !trigger; i++) {
6✔
265
        term_t child;
266
        mpq_t q;
267
        mpq_init(q);
4✔
268
        sum_term_component(terms, t, i, q, &child);
4✔
269
        trigger = term_requires_mcsat_supplement(ctx, child, cache);
4✔
270
        mpq_clear(q);
4✔
271
      }
272

273
    } else if (term_is_bvsum(terms, t)) {
61✔
274
      int32_t *aux;
275
      uint32_t nbits;
276
      term_t child;
277

NEW
278
      nbits = term_bitsize(terms, t);
×
NEW
279
      aux = (int32_t *) safe_malloc(nbits * sizeof(int32_t));
×
NEW
280
      nchildren = term_num_children(terms, t);
×
NEW
281
      for (i=0; i<nchildren && !trigger; i++) {
×
NEW
282
        bvsum_term_component(terms, t, i, aux, &child);
×
NEW
283
        trigger = term_requires_mcsat_supplement(ctx, child, cache);
×
284
      }
NEW
285
      safe_free(aux);
×
286

287
    } else if (term_is_product(terms, t)) {
61✔
NEW
288
      nchildren = term_num_children(terms, t);
×
NEW
289
      for (i=0; i<nchildren && !trigger; i++) {
×
290
        term_t child;
291
        uint32_t exp;
NEW
292
        product_term_component(terms, t, i, &child, &exp);
×
NEW
293
        trigger = term_requires_mcsat_supplement(ctx, child, cache);
×
294
      }
295

296
    } else if (term_is_composite(terms, t)) {
61✔
297
      nchildren = term_num_children(terms, t);
28✔
298
      for (i=0; i<nchildren && !trigger; i++) {
77✔
299
        trigger = term_requires_mcsat_supplement(ctx, term_child(terms, t, i), cache);
49✔
300
      }
301
    }
302
  }
303

304
  p = int_hmap_get(cache, t);
80✔
305
  p->val = trigger ? 1 : 0;
80✔
306
  return trigger;
80✔
307
}
308

309
int32_t context_attach_mcsat_supplement(context_t *ctx) {
8✔
310
  mcsat_satellite_t *sat;
311

312
  if (ctx->mcsat_supplement) {
8✔
NEW
313
    return CTX_NO_ERROR;
×
314
  }
315
  if (ctx->arch == CTX_ARCH_MCSAT || ctx->egraph == NULL) {
8✔
NEW
316
    return CONTEXT_UNSUPPORTED_THEORY;
×
317
  }
318

319
  sat = new_mcsat_satellite(ctx);
8✔
320
  egraph_attach_mcsat_solver(ctx->egraph, sat,
8✔
321
                             mcsat_satellite_ctrl_interface(sat),
322
                             mcsat_satellite_smt_interface(sat),
323
                             NULL);
324
  egraph_attach_arith_observer(ctx->egraph, sat, mcsat_satellite_arith_observer_interface(sat));
8✔
325
  ctx->mcsat_supplement = true;
8✔
326

327
  return CTX_NO_ERROR;
8✔
328
}
329

330
static void context_disable_mcsat_supplement(context_t *ctx) {
8✔
331
  mcsat_satellite_t *sat;
332

333
  if (!ctx->mcsat_supplement || ctx->egraph == NULL) {
8✔
NEW
334
    return;
×
335
  }
336

337
  sat = context_mcsat_satellite(ctx);
8✔
338
  egraph_detach_arith_observer(ctx->egraph, sat);
8✔
339
  egraph_detach_mcsat_solver(ctx->egraph);
8✔
340
  delete_mcsat_satellite(sat);
8✔
341
  ctx->mcsat_supplement = false;
8✔
342
}
343

344
static void context_reset_mcsat_relaxation(context_t *ctx) {
17✔
345
  if (ctx->mcsat_relax_abstractions != NULL) {
17✔
346
    int_hmap_reset(ctx->mcsat_relax_abstractions);
5✔
347
  }
348
  if (ctx->mcsat_relax_abstraction_terms != NULL) {
17✔
349
    int_hset_reset(ctx->mcsat_relax_abstraction_terms);
5✔
350
  }
351
  if (ctx->mcsat_relax_manager != NULL) {
17✔
352
    reset_term_manager(ctx->mcsat_relax_manager);
7✔
353
  }
354
}
17✔
355

356
static void context_delete_mcsat_relaxation(context_t *ctx) {
22,417✔
357
  if (ctx->mcsat_relax_abstractions != NULL) {
22,417✔
358
    delete_int_hmap(ctx->mcsat_relax_abstractions);
6✔
359
    safe_free(ctx->mcsat_relax_abstractions);
6✔
360
    ctx->mcsat_relax_abstractions = NULL;
6✔
361
  }
362
  if (ctx->mcsat_relax_abstraction_terms != NULL) {
22,417✔
363
    delete_int_hset(ctx->mcsat_relax_abstraction_terms);
6✔
364
    safe_free(ctx->mcsat_relax_abstraction_terms);
6✔
365
    ctx->mcsat_relax_abstraction_terms = NULL;
6✔
366
  }
367
  if (ctx->mcsat_relax_manager != NULL) {
22,417✔
368
    delete_term_manager(ctx->mcsat_relax_manager);
7✔
369
    safe_free(ctx->mcsat_relax_manager);
7✔
370
    ctx->mcsat_relax_manager = NULL;
7✔
371
  }
372
}
22,417✔
373

374
static bool mcsat_satellite_candidate_atom(term_table_t *terms, term_t atom) {
59✔
375
  switch (term_kind(terms, atom)) {
59✔
376
  case ARITH_ROOT_ATOM:
43✔
377
  case ARITH_FF_EQ_ATOM:
378
  case ARITH_FF_BINEQ_ATOM:
379
  case ARITH_IS_INT_ATOM:
380
  case ARITH_EQ_ATOM:
381
  case ARITH_GE_ATOM:
382
  case ARITH_BINEQ_ATOM:
383
  case ARITH_DIVIDES_ATOM:
384
    return true;
43✔
385

386
  default:
16✔
387
    return false;
16✔
388
  }
389
}
390

391
static bool context_atom_requires_mcsat(context_t *ctx, term_t atom) {
554,122✔
392
  int_hmap_t cache;
393
  bool trigger;
394

395
  atom = unsigned_term(atom);
554,122✔
396
  if (!ctx->mcsat_supplement || !is_boolean_term(ctx->terms, atom)) {
554,122✔
397
    return false;
554,084✔
398
  }
399
  if (!mcsat_satellite_candidate_atom(ctx->terms, atom)) {
38✔
400
    return false;
8✔
401
  }
402

403
  init_int_hmap(&cache, 0);
30✔
404
  if (!context_has_arith_solver(ctx)) {
30✔
NEW
405
    trigger = term_contains_arith_or_ff(ctx, atom, &cache);
×
NEW
406
    if (!trigger) {
×
NEW
407
      int_hmap_reset(&cache);
×
NEW
408
      trigger = term_requires_mcsat_supplement(ctx, atom, &cache);
×
409
    }
410
  } else {
411
    trigger = term_requires_mcsat_supplement(ctx, atom, &cache);
30✔
412
  }
413
  delete_int_hmap(&cache);
30✔
414

415
  return trigger;
30✔
416
}
417

418
static void context_observe_mcsat_atom(context_t *ctx, term_t atom, literal_t l) {
21✔
419
  int_hmap_t cache;
420
  bool observe;
421

422
  if (!ctx->mcsat_supplement || !is_boolean_term(ctx->terms, atom) ||
21✔
423
      !mcsat_satellite_candidate_atom(ctx->terms, atom)) {
21✔
424
    return;
8✔
425
  }
426

427
  init_int_hmap(&cache, 0);
13✔
428
  observe = term_contains_arith_or_ff(ctx, atom, &cache);
13✔
429
  delete_int_hmap(&cache);
13✔
430

431
  if (observe) {
13✔
432
    int32_t code = egraph_arith_observer_register_atom(ctx->egraph, atom, l);
13✔
433
    if (code < 0) {
13✔
NEW
434
      longjmp(ctx->env, code);
×
435
    }
436
  }
437
}
438

439
static inline bool context_mcsat_relaxation_enabled(context_t *ctx) {
17✔
440
  return ctx->mcsat_supplement && context_has_simplex_solver(ctx);
17✔
441
}
442

443
static term_manager_t *context_get_mcsat_relax_manager(context_t *ctx) {
17✔
444
  term_manager_t *manager;
445

446
  manager = ctx->mcsat_relax_manager;
17✔
447
  if (manager == NULL) {
17✔
448
    manager = (term_manager_t *) safe_malloc(sizeof(term_manager_t));
7✔
449
    init_term_manager(manager, ctx->terms);
7✔
450
    ctx->mcsat_relax_manager = manager;
7✔
451
  }
452
  return manager;
17✔
453
}
454

455
static int_hmap_t *context_get_mcsat_relax_abstractions(context_t *ctx) {
14✔
456
  int_hmap_t *map;
457

458
  map = ctx->mcsat_relax_abstractions;
14✔
459
  if (map == NULL) {
14✔
460
    map = (int_hmap_t *) safe_malloc(sizeof(int_hmap_t));
6✔
461
    init_int_hmap(map, 0);
6✔
462
    ctx->mcsat_relax_abstractions = map;
6✔
463
  }
464
  return map;
14✔
465
}
466

467
static int_hset_t *context_get_mcsat_relax_abstraction_terms(context_t *ctx) {
11✔
468
  int_hset_t *set;
469

470
  set = ctx->mcsat_relax_abstraction_terms;
11✔
471
  if (set == NULL) {
11✔
472
    set = (int_hset_t *) safe_malloc(sizeof(int_hset_t));
6✔
473
    init_int_hset(set, 0);
6✔
474
    ctx->mcsat_relax_abstraction_terms = set;
6✔
475
  }
476
  return set;
11✔
477
}
478

479
static bool context_is_mcsat_relax_abstraction(context_t *ctx, term_t t) {
19✔
480
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
19✔
481
  return ctx->mcsat_relax_abstraction_terms != NULL &&
37✔
482
    int_hset_member(ctx->mcsat_relax_abstraction_terms, t);
18✔
483
}
484

NEW
485
static bool term_requires_mcsat_supplement_uncached(context_t *ctx, term_t t) {
×
486
  int_hmap_t cache;
487
  bool trigger;
488

NEW
489
  init_int_hmap(&cache, 0);
×
NEW
490
  trigger = term_requires_mcsat_supplement(ctx, t, &cache);
×
NEW
491
  delete_int_hmap(&cache);
×
492

NEW
493
  return trigger;
×
494
}
495

NEW
496
static bool arith_const_is_zero(context_t *ctx, term_t t) {
×
NEW
497
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
×
NEW
498
  return term_kind(ctx->terms, t) == ARITH_CONSTANT &&
×
NEW
499
    q_is_zero(rational_term_desc(ctx->terms, t));
×
500
}
501

502
/*
503
 * Fresh internal arithmetic term used as a simplex relaxation variable.
504
 * The term is intentionally not registered as the original nonlinear term:
505
 * it is a pure over-approximation variable for the simplex view.
506
 *
507
 * This cache maps original nonlinear terms to fresh term-table variables,
508
 * rather than directly to simplex thvars.  Internalizing the fresh term gives
509
 * the canonical thvar and keeps the relaxation path in the normal arithmetic
510
 * internalizer.  The companion set identifies these fresh terms so observer
511
 * notifications can ignore only relaxation abstractions, not user terms that
512
 * happen to be internalized while building a relaxation.
513
 */
514
static term_t mcsat_relax_abstraction_for_term(context_t *ctx, term_t t) {
14✔
515
  int_hmap_pair_t *p;
516
  type_t tau;
517

518
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
14✔
519
  p = int_hmap_get(context_get_mcsat_relax_abstractions(ctx), t);
14✔
520
  if (p->val < 0) {
14✔
521
    tau = term_type(ctx->terms, t);
11✔
522
    assert(is_arithmetic_type(tau));
523
    p->val = new_uninterpreted_term(ctx->terms, tau);
11✔
524
    int_hset_add(context_get_mcsat_relax_abstraction_terms(ctx), p->val);
11✔
525
  }
526

527
  return p->val;
14✔
528
}
529

530
static term_t mcsat_relax_arith_term(context_t *ctx, term_manager_t *manager, term_t t);
531

532
static term_t mcsat_relax_pprod(context_t *ctx, term_manager_t *manager, term_t t) {
12✔
533
  pprod_t *p;
534
  term_t *a;
535
  term_t r;
536
  uint32_t i, n;
537

538
  p = pprod_term_desc(ctx->terms, t);
12✔
539
  if (pprod_degree(p) > 1) {
12✔
540
    return mcsat_relax_abstraction_for_term(ctx, t);
12✔
541
  }
542

NEW
543
  n = p->len;
×
NEW
544
  a = alloc_istack_array(&ctx->istack, n);
×
NEW
545
  for (i=0; i<n; i++) {
×
NEW
546
    r = mcsat_relax_arith_term(ctx, manager, p->prod[i].var);
×
NEW
547
    if (r == NULL_TERM) {
×
NEW
548
      free_istack_array(&ctx->istack, a);
×
NEW
549
      return NULL_TERM;
×
550
    }
NEW
551
    a[i] = r;
×
552
  }
553

NEW
554
  r = mk_arith_pprod(manager, p, n, a);
×
NEW
555
  free_istack_array(&ctx->istack, a);
×
556

NEW
557
  return r;
×
558
}
559

560
static term_t mcsat_relax_poly(context_t *ctx, term_manager_t *manager, term_t t) {
4✔
561
  polynomial_t *p;
562
  term_t *a;
563
  term_t r;
564
  uint32_t i, n;
565

566
  p = poly_term_desc(ctx->terms, t);
4✔
567
  n = p->nterms;
4✔
568
  a = alloc_istack_array(&ctx->istack, n);
4✔
569
  for (i=0; i<n; i++) {
10✔
570
    if (p->mono[i].var == const_idx) {
6✔
571
      a[i] = const_idx;
2✔
572
    } else {
573
      r = mcsat_relax_arith_term(ctx, manager, p->mono[i].var);
4✔
574
      if (r == NULL_TERM) {
4✔
NEW
575
        free_istack_array(&ctx->istack, a);
×
NEW
576
        return NULL_TERM;
×
577
      }
578
      a[i] = r;
4✔
579
    }
580
  }
581

582
  r = mk_arith_poly(manager, p, n, a);
4✔
583
  free_istack_array(&ctx->istack, a);
4✔
584

585
  return r;
4✔
586
}
587

NEW
588
static term_t mcsat_relax_const_division(context_t *ctx, term_manager_t *manager, term_kind_t kind, composite_term_t *d) {
×
589
  term_t x, y;
590

591
  assert(d->arity == 2);
NEW
592
  if (arith_const_is_zero(ctx, d->arg[1])) {
×
593
    // The standard internalizer preserves Yices's literal-zero-divisor error.
594
    // If relaxation reaches one as a side term, leave the atom MCSAT-only.
NEW
595
    return NULL_TERM;
×
596
  }
597
  assert(!divisor_requires_mcsat(ctx->terms, d->arg[1]));
598

NEW
599
  x = mcsat_relax_arith_term(ctx, manager, d->arg[0]);
×
NEW
600
  if (x == NULL_TERM) {
×
NEW
601
    return NULL_TERM;
×
602
  }
NEW
603
  y = unsigned_term(intern_tbl_get_root(&ctx->intern, d->arg[1]));
×
604

NEW
605
  switch (kind) {
×
NEW
606
  case ARITH_RDIV:
×
NEW
607
    return mk_arith_rdiv(manager, x, y);
×
NEW
608
  case ARITH_IDIV:
×
NEW
609
    return mk_arith_idiv(manager, x, y);
×
NEW
610
  case ARITH_MOD:
×
NEW
611
    return mk_arith_mod(manager, x, y);
×
NEW
612
  default:
×
613
    assert(false);
NEW
614
    return NULL_TERM;
×
615
  }
616
}
617

618
static term_t mcsat_relax_arith_term(context_t *ctx, term_manager_t *manager, term_t t) {
28✔
619
  term_table_t *terms;
620
  composite_term_t *c;
621
  term_t x;
622

623
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
28✔
624
  terms = ctx->terms;
28✔
625
  assert(is_arithmetic_term(terms, t));
626

627
  switch (term_kind(terms, t)) {
28✔
628
  case ARITH_CONSTANT:
10✔
629
  case UNINTERPRETED_TERM:
630
    return t;
10✔
631

632
  case POWER_PRODUCT:
12✔
633
    return mcsat_relax_pprod(ctx, manager, t);
12✔
634

635
  case ARITH_POLY:
4✔
636
    return mcsat_relax_poly(ctx, manager, t);
4✔
637

NEW
638
  case ARITH_FLOOR:
×
NEW
639
    x = mcsat_relax_arith_term(ctx, manager, arith_floor_arg(terms, t));
×
NEW
640
    return x == NULL_TERM ? NULL_TERM : mk_arith_floor(manager, x);
×
641

NEW
642
  case ARITH_CEIL:
×
NEW
643
    x = mcsat_relax_arith_term(ctx, manager, arith_ceil_arg(terms, t));
×
NEW
644
    return x == NULL_TERM ? NULL_TERM : mk_arith_ceil(manager, x);
×
645

NEW
646
  case ARITH_ABS:
×
NEW
647
    x = mcsat_relax_arith_term(ctx, manager, arith_abs_arg(terms, t));
×
NEW
648
    return x == NULL_TERM ? NULL_TERM : mk_arith_abs(manager, x);
×
649

650
  case ARITH_RDIV:
2✔
651
    c = arith_rdiv_term_desc(terms, t);
2✔
652
    if (divisor_requires_mcsat(terms, c->arg[1])) {
2✔
653
      return mcsat_relax_abstraction_for_term(ctx, t);
2✔
654
    }
NEW
655
    return mcsat_relax_const_division(ctx, manager, ARITH_RDIV, c);
×
656

NEW
657
  case ARITH_IDIV:
×
NEW
658
    c = arith_idiv_term_desc(terms, t);
×
NEW
659
    if (divisor_requires_mcsat(terms, c->arg[1])) {
×
NEW
660
      return mcsat_relax_abstraction_for_term(ctx, t);
×
661
    }
NEW
662
    return mcsat_relax_const_division(ctx, manager, ARITH_IDIV, c);
×
663

NEW
664
  case ARITH_MOD:
×
NEW
665
    c = arith_mod_term_desc(terms, t);
×
NEW
666
    if (divisor_requires_mcsat(terms, c->arg[1])) {
×
NEW
667
      return mcsat_relax_abstraction_for_term(ctx, t);
×
668
    }
NEW
669
    return mcsat_relax_const_division(ctx, manager, ARITH_MOD, c);
×
670

NEW
671
  default:
×
672
    /*
673
     * For arithmetic constructs supported by simplex, keep the term exact.
674
     * If an unsupported construct occurs below an otherwise opaque term
675
     * (for example under an arithmetic ITE), abstract the whole term.
676
     */
NEW
677
    if (term_requires_mcsat_supplement_uncached(ctx, t)) {
×
NEW
678
      return mcsat_relax_abstraction_for_term(ctx, t);
×
679
    }
NEW
680
    return t;
×
681
  }
682
}
683

684
static term_t mcsat_relax_arith_difference(context_t *ctx, term_manager_t *manager, term_t t1, term_t t2) {
10✔
685
  rba_buffer_t *b;
686

687
  b = term_manager_get_arith_buffer(manager);
10✔
688
  reset_rba_buffer(b);
10✔
689
  rba_buffer_add_term(b, ctx->terms, t1);
10✔
690
  rba_buffer_sub_term(b, ctx->terms, t2);
10✔
691

692
  return mk_arith_term(manager, b);
10✔
693
}
694

695
static literal_t map_mcsat_relaxation_to_literal(context_t *ctx, term_t atom) {
17✔
696
  term_table_t *terms;
697
  term_manager_t *manager;
698
  composite_term_t *eq;
699
  literal_t l;
700
  term_t t, u;
701

702
  if (!context_mcsat_relaxation_enabled(ctx)) {
17✔
NEW
703
    return null_literal;
×
704
  }
705

706
  terms = ctx->terms;
17✔
707
  manager = context_get_mcsat_relax_manager(ctx);
17✔
708
  l = null_literal;
17✔
709

710
  switch (term_kind(terms, atom)) {
17✔
NEW
711
  case ARITH_IS_INT_ATOM:
×
NEW
712
    t = mcsat_relax_arith_term(ctx, manager, arith_is_int_arg(terms, atom));
×
NEW
713
    if (t != NULL_TERM) {
×
NEW
714
      l = map_arith_is_int_to_literal(ctx, t);
×
715
    }
NEW
716
    break;
×
717

NEW
718
  case ARITH_EQ_ATOM:
×
NEW
719
    t = mcsat_relax_arith_term(ctx, manager, arith_eq_arg(terms, atom));
×
NEW
720
    if (t != NULL_TERM) {
×
NEW
721
      l = map_arith_eq_to_literal(ctx, t);
×
722
    }
NEW
723
    break;
×
724

725
  case ARITH_GE_ATOM:
4✔
726
    t = mcsat_relax_arith_term(ctx, manager, arith_ge_arg(terms, atom));
4✔
727
    if (t != NULL_TERM) {
4✔
728
      l = map_arith_geq_to_literal(ctx, t);
4✔
729
    }
730
    break;
4✔
731

732
  case ARITH_BINEQ_ATOM:
10✔
733
    eq = arith_bineq_atom_desc(terms, atom);
10✔
734
    t = mcsat_relax_arith_term(ctx, manager, eq->arg[0]);
10✔
735
    u = mcsat_relax_arith_term(ctx, manager, eq->arg[1]);
10✔
736
    if (t != NULL_TERM && u != NULL_TERM) {
10✔
737
      t = mcsat_relax_arith_difference(ctx, manager, t, u);
10✔
738
      l = map_arith_eq_to_literal(ctx, t);
10✔
739
    }
740
    break;
10✔
741

NEW
742
  case ARITH_DIVIDES_ATOM:
×
NEW
743
    eq = arith_divides_atom_desc(terms, atom);
×
NEW
744
    if (!divisor_requires_mcsat(terms, eq->arg[0])) {
×
NEW
745
      t = mcsat_relax_arith_term(ctx, manager, eq->arg[1]);
×
NEW
746
      if (t != NULL_TERM) {
×
NEW
747
        l = map_arith_divides_const_to_literal(ctx, eq->arg[0], t);
×
748
      }
749
    }
NEW
750
    break;
×
751

752
  default:
3✔
753
    break;
3✔
754
  }
755

756
  return l;
17✔
757
}
758

759
static literal_t map_mcsat_atom_to_literal(context_t *ctx, term_t atom) {
17✔
760
  mcsat_satellite_t *sat;
761
  literal_t l, lr;
762
  void *obj;
763
  int32_t code;
764

765
  sat = context_mcsat_satellite(ctx);
17✔
766
  assert(sat != NULL);
767

768
  l = pos_lit(create_boolean_variable(ctx->core));
17✔
769
  obj = NULL;
17✔
770
  code = mcsat_satellite_register_atom(sat, atom, l, &obj);
17✔
771
  if (code < 0) {
17✔
NEW
772
    longjmp(ctx->env, code);
×
773
  }
774

775
  attach_atom_to_bvar(ctx->core, var_of(l), tagged_mcsat_atom(obj));
17✔
776

777
  lr = map_mcsat_relaxation_to_literal(ctx, atom);
17✔
778
  if (lr != null_literal) {
17✔
779
    // Scope the equivalence with the two atoms: if a push-level atom is popped,
780
    // its relaxation literal and these clauses disappear with it.
781
    add_binary_clause(ctx->core, not(l), lr);
14✔
782
    add_binary_clause(ctx->core, l, not(lr));
14✔
783
  }
784

785
  return l;
17✔
786
}
787

788

789

790
/****************************************
791
 *  CONSTRUCTION OF EGRAPH OCCURRENCES  *
792
 ***************************************/
793

794
/*
795
 * Create a new egraph constant of the given type
796
 */
797
static eterm_t make_egraph_constant(context_t *ctx, type_t type, int32_t id) {
1,164✔
798
  assert(type_kind(ctx->types, type) == UNINTERPRETED_TYPE ||
799
         type_kind(ctx->types, type) == SCALAR_TYPE);
800
  return egraph_make_constant(ctx->egraph, type, id);
1,164✔
801
}
802

803

804
/*
805
 * Create a new egraph variable
806
 * - type = its type
807
 */
808
static eterm_t make_egraph_variable(context_t *ctx, type_t type) {
14,087✔
809
  eterm_t u;
810
  bvar_t v;
811

812
  if (type == bool_type(ctx->types)) {
14,087✔
813
    v = create_boolean_variable(ctx->core);
×
814
    u = egraph_bvar2term(ctx->egraph, v);
×
815
  } else {
816
    //    u = egraph_make_variable(ctx->egraph, type);
817
    // it's better to use skolem_term in case type is (tuple ...)
818
    u = egraph_skolem_term(ctx->egraph, type);
14,087✔
819
  }
820
  return u;
14,087✔
821
}
822

823

824
/*
825
 * Type of arithmetic variable x
826
 */
827
static type_t type_of_arithvar(context_t *ctx, thvar_t x) {
1,562✔
828
  type_t tau;
829

830
  tau = real_type(ctx->types);
1,562✔
831
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
1,562✔
832
    tau = int_type(ctx->types);
1,425✔
833
  }
834

835
  return tau;
1,562✔
836
}
837

838

839
/*
840
 * Convert arithmetic variable x to an egraph term
841
 */
842
static occ_t translate_arithvar_to_eterm(context_t *ctx, thvar_t x) {
1,571✔
843
  eterm_t u;
844
  type_t tau;
845

846
  u = ctx->arith.eterm_of_var(ctx->arith_solver, x);
1,571✔
847
  if (u == null_eterm) {
1,571✔
848
    tau = type_of_arithvar(ctx, x);
1,562✔
849
    u = egraph_thvar2term(ctx->egraph, x, tau);
1,562✔
850
  }
851

852
  return pos_occ(u);
1,571✔
853
}
854

855
/*
856
 * Convert bit-vector variable x to an egraph term
857
 * - tau = type of x
858
 */
859
static occ_t translate_bvvar_to_eterm(context_t *ctx, thvar_t x, type_t tau) {
3,693✔
860
  eterm_t u;
861

862
  u = ctx->bv.eterm_of_var(ctx->bv_solver, x);
3,693✔
863
  if (u == null_eterm) {
3,693✔
864
    u = egraph_thvar2term(ctx->egraph, x, tau);
3,672✔
865
  }
866

867
  return pos_occ(u);
3,693✔
868
}
869

870

871
/*
872
 * Convert variable x into an eterm internalization for t
873
 * - tau = type of t
874
 * - if x is mapped to an existing eterm u, return pos_occ(u)
875
 * - otherwise, create an egraph variable u and attach x to u
876
 *   then record the converse mapping [x --> u] in the relevant
877
 *   theory solver
878
 */
879
static occ_t translate_thvar_to_eterm(context_t *ctx, thvar_t x, type_t tau) {
3,348✔
880
  if (is_arithmetic_type(tau)) {
3,348✔
881
    return translate_arithvar_to_eterm(ctx, x);
619✔
882
  } else if (is_bv_type(ctx->types, tau)) {
2,729✔
883
    return translate_bvvar_to_eterm(ctx, x, tau);
2,729✔
884
  } else {
885
    longjmp(ctx->env, INTERNAL_ERROR);
×
886
  }
887
}
888

889

890
/*
891
 * Convert internalization code x for a term t into an egraph term
892
 * - t must be a root in the internalization table and must have
893
 *   positive polarity
894
 */
895
static occ_t translate_code_to_eterm(context_t *ctx, term_t t, int32_t x) {
64,982✔
896
  occ_t u;
897
  type_t tau;
898

899
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t) &&
900
         intern_tbl_map_of_root(&ctx->intern, t) == x);
901

902
  if (code_is_eterm(x)) {
64,982✔
903
    u = code2occ(x);
64,233✔
904
  } else {
905
    // x encodes a theory variable or a literal
906
    // convert that to an egraph term
907
    tau = type_of_root(ctx, t);
749✔
908
    switch (type_kind(ctx->types, tau)) {
749✔
909
    case BOOL_TYPE:
×
910
      u = egraph_literal2occ(ctx->egraph, code2literal(x));
×
911
      break;
×
912

913
    case INT_TYPE:
611✔
914
    case REAL_TYPE:
915
      u = translate_arithvar_to_eterm(ctx, code2thvar(x));
611✔
916
      break;
611✔
917

918
    case BITVECTOR_TYPE:
138✔
919
      u = translate_bvvar_to_eterm(ctx, code2thvar(x), tau);
138✔
920
      break;
138✔
921

922
    default:
×
923
      assert(false);
924
      longjmp(ctx->env, INTERNAL_ERROR);
×
925
    }
926

927
    // remap t to u
928
    intern_tbl_remap_root(&ctx->intern, t, occ2code(u));
749✔
929
  }
930

931
  return u;
64,982✔
932
}
933

934

935
/*
936
 * Internalization error for term t
937
 * - t can't be processed because there's no egraph
938
 * - the error code depends on t's type
939
 */
940
static int32_t uf_error_code(context_t *ctx, term_t t) {
×
941
  int32_t code;
942

943
  assert(! context_has_egraph(ctx));
944

945
  switch (term_type_kind(ctx->terms, t)) {
×
946
  case UNINTERPRETED_TYPE:
×
947
    code = UTYPE_NOT_SUPPORTED;
×
948
    break;
×
949

950
  case SCALAR_TYPE:
×
951
    code = SCALAR_NOT_SUPPORTED;
×
952
    break;
×
953

954
  case FUNCTION_TYPE:
×
955
    code = UF_NOT_SUPPORTED;
×
956
    break;
×
957

958
  case TUPLE_TYPE:
×
959
    code = TUPLE_NOT_SUPPORTED;
×
960
    break;
×
961

962
  default:
×
963
    assert(false);
964
    code = INTERNAL_ERROR;
×
965
    break;
×
966
  }
967

968
  return code;
×
969
}
970

971

972
/*
973
 * Utility to filter out high-order terms:
974
 * - check whether any term in a[0 ... n-1] has function type.
975
 * - if so throw an exception (via lonjmp) if the context does not include
976
 *   the array solver.
977
 */
978
static void check_high_order_support(context_t *ctx, const term_t *a, uint32_t n) {
18,027✔
979
  uint32_t i;
980

981
  if (! context_has_fun_solver(ctx)) {
18,027✔
982
    for (i=0; i<n; i++) {
30,058✔
983
      if (is_function_term(ctx->terms, a[i])) {
17,192✔
984
        longjmp(ctx->env, HIGH_ORDER_FUN_NOT_SUPPORTED);
3✔
985
      }
986
    }
987
  }
988
}
18,024✔
989

990

991
/***********************************************
992
 *  CONVERSION OF COMPOSITES TO EGRAPH TERMS   *
993
 **********************************************/
994

995
/*
996
 * Map apply term to an eterm
997
 * - tau = type of that term
998
 */
999
static occ_t map_apply_to_eterm(context_t *ctx, composite_term_t *app, type_t tau) {
9,685✔
1000
  eterm_t u;
1001
  occ_t *a;
1002
  uint32_t i, n;
1003

1004
  assert(app->arity > 0);
1005
  n = app->arity;
9,685✔
1006

1007
  check_high_order_support(ctx, app->arg+1, n-1);
9,685✔
1008

1009
  a = alloc_istack_array(&ctx->istack, n);
9,685✔
1010
  for (i=0; i<n; i++) {
34,029✔
1011
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
24,344✔
1012
  }
1013

1014
  // a[0] = function
1015
  // a[1 ... n-1] are the arguments
1016
  u = egraph_make_apply(ctx->egraph, a[0], n-1, a+1, tau);
9,685✔
1017
  free_istack_array(&ctx->istack, a);
9,685✔
1018

1019
  //  add_type_constraints(ctx, pos_occ(u), tau);
1020

1021
  return pos_occ(u);
9,685✔
1022
}
1023

1024

1025
/*
1026
 * Build a tuple of same type as t then assert that it's equal to u1
1027
 * - t must be a root in the internalization table
1028
 * - u1 must be equal to t's internalization (as stored in intern_table)
1029
 * This is the skolemization of (exist (x1...x_n) u1 == (tuple x1 ... x_n))
1030
 *
1031
 * - return the eterm u := (tuple x1 ... x_n)
1032
 */
1033
static eterm_t skolem_tuple(context_t *ctx, term_t t, occ_t u1) {
×
1034
  type_t tau;
1035
  eterm_t u;
1036

1037
  assert(intern_tbl_is_root(&ctx->intern, t) && is_pos_term(t) &&
1038
         intern_tbl_map_of_root(&ctx->intern, t) == occ2code(u1));
1039

1040
  tau = intern_tbl_type_of_root(&ctx->intern, t);
×
1041
  u = egraph_skolem_term(ctx->egraph, tau);
×
1042
  egraph_assert_eq_axiom(ctx->egraph, u1, pos_occ(u));
×
1043

1044
  return u;
×
1045
}
1046

1047

1048
/*
1049
 * Convert (select i t) to an egraph term
1050
 * - tau must be the type of that term (should not be bool)
1051
 * - if a new eterm u is created, attach a theory variable to it
1052
 */
1053
static occ_t map_select_to_eterm(context_t *ctx, select_term_t *s, type_t tau) {
245✔
1054
  occ_t u1;
1055
  eterm_t tuple;
1056
  composite_t *tp;
1057

1058
  u1 = internalize_to_eterm(ctx, s->arg);
245✔
1059
  tuple = egraph_get_tuple_in_class(ctx->egraph, term_of_occ(u1));
245✔
1060
  if (tuple == null_eterm) {
245✔
1061
    tuple = skolem_tuple(ctx, s->arg, u1);
×
1062
  }
1063

1064
  tp = egraph_term_body(ctx->egraph, tuple);
245✔
1065
  assert(composite_body(tp) && tp != NULL && composite_kind(tp) == COMPOSITE_TUPLE);
1066

1067
  return tp->child[s->idx];
245✔
1068
}
1069

1070

1071
/*
1072
 * Convert a conditional expression to an egraph term
1073
 * - c = conditional descriptor
1074
 * - tau = type of c
1075
 */
1076
static occ_t map_conditional_to_eterm(context_t *ctx, conditional_t *c, type_t tau) {
12✔
1077
  literal_t *a;
1078
  occ_t u, v;
1079
  uint32_t i, n;
1080
  literal_t l;
1081
  bool all_false;
1082
  term_t t;
1083

1084
#if 0
1085
  printf("---> conditional to eterm\n");
1086
#endif
1087

1088
  t = simplify_conditional(ctx, c);
12✔
1089
  if (t != NULL_TERM) {
12✔
1090
    return internalize_to_eterm(ctx, t);
4✔
1091
  }
1092

1093
  n = c->nconds;
8✔
1094
  a = alloc_istack_array(&ctx->istack, n + 1);
8✔
1095

1096
  all_false = true;
8✔
1097
  u = null_occurrence;
8✔
1098

1099
  for (i=0; i<n; i++) {
24✔
1100
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
16✔
1101
    if (a[i] == true_literal) {
16✔
1102
      /*
1103
       * a[0] ... a[i-1] are all reducible to false
1104
       * but we can't assume that a[0] ... a[i-1] are all false_literals
1105
       * since we don't know how the theory solver internalizes the
1106
       * conditions.
1107
       */
1108
      v = internalize_to_eterm(ctx, c->pair[i].val);
×
1109
      if (all_false) {
×
1110
        // all previous conditions a[0 ... i-1] are false
1111
        assert(u == null_occurrence);
1112
        u = v;
×
1113
      } else {
1114
        // we assert (u == v) as a top-level equality
1115
        egraph_assert_eq_axiom(ctx->egraph, u, v);
×
1116
      }
1117
      goto done;
×
1118
    }
1119
    if (a[i] != false_literal) {
16✔
1120
      if (all_false) {
13✔
1121
        assert(u == null_occurrence);
1122
        u = pos_occ(make_egraph_variable(ctx, tau));
7✔
1123
        all_false = false;
7✔
1124
      }
1125
      // one clause for a[i] => (u = v[i])
1126
      v = internalize_to_eterm(ctx, c->pair[i].val);
13✔
1127
      l = egraph_make_eq(ctx->egraph, u, v);
13✔
1128
      add_binary_clause(ctx->core, not(a[i]), l);
13✔
1129
    }
1130
  }
1131

1132
  if (all_false) {
8✔
1133
    assert(u == null_occurrence);
1134
    u = internalize_to_eterm(ctx, c->defval);
1✔
1135
    goto done;
1✔
1136
  }
1137

1138
  // clause for the default value
1139
  assert(u != null_occurrence);
1140
  v = internalize_to_eterm(ctx, c->defval);
7✔
1141
  l = egraph_make_eq(ctx->egraph, u, v);
7✔
1142
  a[n] = l;
7✔
1143
  add_clause(ctx->core, n+1, a);
7✔
1144

1145
 done:
8✔
1146
  free_istack_array(&ctx->istack, a);
8✔
1147

1148
  return u;
8✔
1149
}
1150

1151

1152
/*
1153
 * Auxiliary function for flattening if-then-else
1154
 * - v contains a conjunction of n literals: l0 /\ ... /\ l_n
1155
 * - we something like (l0 /\ ... /\ l_n implies (x = y))
1156
 *   (i.e., (not l0) \/ ... \/ (not l_n) \/ (x = y)
1157
 * - this function negates all the literals in place
1158
 */
1159
static void ite_prepare_antecedents(ivector_t *v) {
8,348✔
1160
  uint32_t i, n;
1161

1162
  n = v->size;
8,348✔
1163
  for (i=0; i<n; i++) {
20,408✔
1164
    v->data[i] = not(v->data[i]);
12,060✔
1165
  }
1166
}
8,348✔
1167

1168

1169
/*
1170
 * Convert nested if-then-else to  an egraph term
1171
 * - ite = term of the form (ite c1 t1 t2)
1172
 * - c = internalization of c1
1173
 * - tau = type of the term (ite c1 t1 t2)
1174
 */
1175
static occ_t flatten_ite_to_eterm(context_t *ctx, composite_term_t *ite, literal_t c, type_t tau) {
1,168✔
1176
  ite_flattener_t *flattener;
1177
  ivector_t *buffer;
1178
  term_t x;
1179
  occ_t u, v;
1180
  literal_t l;
1181

1182
  u = pos_occ(make_egraph_variable(ctx, tau));
1,168✔
1183

1184
  flattener = objstack_alloc(&ctx->ostack, sizeof(ite_flattener_t), (cleaner_t) delete_ite_flattener);
1,168✔
1185
  init_ite_flattener(flattener);
1,168✔
1186

1187
  ite_flattener_push(flattener, ite, c);
1,168✔
1188

1189
  while (ite_flattener_is_nonempty(flattener)) {
4,210✔
1190
    if (ite_flattener_last_lit_false(flattener)) {
3,042✔
1191
      // dead branch
1192
      ite_flattener_next_branch(flattener);
6✔
1193
      continue;
6✔
1194
    }
1195
    assert(ite_flattener_branch_is_live(flattener));
1196

1197
    x = ite_flattener_leaf(flattener);
3,036✔
1198
    x = intern_tbl_get_root(&ctx->intern, x);
3,036✔
1199

1200
    /*
1201
     * x is the current leaf.
1202
     * If it's (ite ...) then we can expand the tree by pushing x.
1203
     *
1204
     * Heuristic: we don't do it if x is a shared term or if it's
1205
     * already internalized.
1206
     * - we also need a cutoff since the number of branches grows
1207
     *   exponentially.
1208
     */
1209
    if (is_pos_term(x) &&
6,072✔
1210
        is_ite_term(ctx->terms, x) &&
3,036✔
1211
        !intern_tbl_root_is_mapped(&ctx->intern, x) &&
2,473✔
1212
        term_is_not_shared(&ctx->sharing, x)) {
774✔
1213
      /*
1214
       * x is of the form (ite c a b) and not internalized already,
1215
       * we push (ite c a b) on the flattener.
1216
       */
1217
      ite = ite_term_desc(ctx->terms, x);
353✔
1218
      assert(ite->arity == 3);
1219
      c = internalize_to_literal(ctx, ite->arg[0]);
353✔
1220
      ite_flattener_push(flattener, ite, c);
353✔
1221
    } else {
1222
      /*
1223
       * Add the clause [branch conditions => x = u]
1224
       */
1225
      v = internalize_to_eterm(ctx, x);
2,683✔
1226
      l = egraph_make_eq(ctx->egraph, u, v);
2,683✔
1227

1228
      buffer = &ctx->aux_vector;
2,683✔
1229
      assert(buffer->size == 0);
1230
      ite_flattener_get_clause(flattener, buffer);
2,683✔
1231
      ite_prepare_antecedents(buffer);
2,683✔
1232
      ivector_push(buffer, l);
2,683✔
1233
      add_clause(ctx->core, buffer->size, buffer->data);
2,683✔
1234
      ivector_reset(buffer);
2,683✔
1235

1236
      ite_flattener_next_branch(flattener);
2,683✔
1237
    }
1238
  }
1239

1240
  //  delete_ite_flattener(&flattener);
1241
  objstack_pop(&ctx->ostack);
1,168✔
1242

1243
  return u;
1,168✔
1244
}
1245

1246

1247
/*
1248
 * Convert (ite c t1 t2) to an egraph term
1249
 * - tau = type of (ite c t1 t2)
1250
 */
1251
static occ_t map_ite_to_eterm(context_t *ctx, composite_term_t *ite, type_t tau) {
2,168✔
1252
  conditional_t *d;
1253
  eterm_t u;
1254
  occ_t u1, u2, u3;
1255
  literal_t c, l1, l2;
1256

1257
  // NOTE: we could reject (ite c t1 t2) when t1 and t2 are functions and we
1258
  // don't have a function/array solver. But it looks like the egraph can
1259
  // handle it so we accept it. Strictly, it's not a part of UF or QF_UF.
1260

1261
  d = context_make_conditional(ctx, ite);
2,168✔
1262
  if (d != NULL) {
2,168✔
1263
    u1 = map_conditional_to_eterm(ctx, d, tau);
12✔
1264
    context_free_conditional(ctx, d);
12✔
1265
    return u1;
12✔
1266
  }
1267

1268
  c = internalize_to_literal(ctx, ite->arg[0]);
2,156✔
1269
  if (c == true_literal) {
2,156✔
1270
    return internalize_to_eterm(ctx, ite->arg[1]);
110✔
1271
  }
1272
  if (c == false_literal) {
2,046✔
1273
    return internalize_to_eterm(ctx, ite->arg[2]);
15✔
1274
  }
1275

1276
  if (context_ite_flattening_enabled(ctx)) {
2,031✔
1277
    return flatten_ite_to_eterm(ctx, ite, c, tau);
1,168✔
1278
  }
1279

1280
  u2 = internalize_to_eterm(ctx, ite->arg[1]);
863✔
1281
  u3 = internalize_to_eterm(ctx, ite->arg[2]);
863✔
1282

1283
  if (context_keep_ite_enabled(ctx)) {
863✔
1284
    // build the if-then-else in the egraph
1285
    u1 = egraph_literal2occ(ctx->egraph, c);
2✔
1286
    u = egraph_make_ite(ctx->egraph, u1, u2, u3, tau);
2✔
1287
  } else {
1288
    // eliminate the if-then-else
1289
    u = make_egraph_variable(ctx, tau);
861✔
1290
    l1 = egraph_make_eq(ctx->egraph, pos_occ(u), u2);
861✔
1291
    l2 = egraph_make_eq(ctx->egraph, pos_occ(u), u3);
861✔
1292

1293
    assert_ite(&ctx->gate_manager, c, l1, l2, true);
861✔
1294
  }
1295

1296
  return pos_occ(u);
863✔
1297
}
1298

1299

1300

1301
/*
1302
 * Convert (update f t_1 ... t_n v) to a term
1303
 * - tau = type of that term
1304
 */
1305
static occ_t map_update_to_eterm(context_t *ctx, composite_term_t *update, type_t tau) {
11,470✔
1306
  eterm_t u;
1307
  occ_t *a;
1308
  uint32_t i, n;
1309

1310
  assert(update->arity > 2);
1311

1312
  n = update->arity;
11,470✔
1313
  a = alloc_istack_array(&ctx->istack, n);
11,470✔
1314
  for (i=0; i<n; i++) {
45,880✔
1315
    a[i] = internalize_to_eterm(ctx, update->arg[i]);
34,410✔
1316
  }
1317

1318
  // a[0]: function f
1319
  // a[1] ... a[n-2]: t_1 .. t_{n-2}
1320
  // a[n-1]: new value v
1321
  u = egraph_make_update(ctx->egraph, a[0], n-2, a+1, a[n-1], tau);
11,470✔
1322

1323
  free_istack_array(&ctx->istack, a);
11,470✔
1324

1325
  return pos_occ(u);
11,470✔
1326
}
1327

1328

1329

1330
/*
1331
 * Convert (tuple t_1 ... t_n) to a term
1332
 * - tau = type of the tuple
1333
 */
1334
static occ_t map_tuple_to_eterm(context_t *ctx, composite_term_t *tuple, type_t tau) {
190✔
1335
  eterm_t u;
1336
  occ_t *a;
1337
  uint32_t i, n;
1338

1339
  n = tuple->arity;
190✔
1340

1341
  check_high_order_support(ctx, tuple->arg, n);
190✔
1342

1343
  a = alloc_istack_array(&ctx->istack, n);
190✔
1344
  for (i=0; i<n; i++) {
560✔
1345
    a[i] = internalize_to_eterm(ctx, tuple->arg[i]);
370✔
1346
  }
1347

1348
  u = egraph_make_tuple(ctx->egraph, n, a, tau);
190✔
1349
  free_istack_array(&ctx->istack, a);
190✔
1350

1351
  return pos_occ(u);
190✔
1352
}
1353

1354

1355
/*
1356
 * Convert arithmetic and bitvector constants to eterm
1357
 * - check whether the relevant solver exists first
1358
 * - then map the constant to a solver variable x
1359
 *   and convert x to an egraph occurrence
1360
 */
1361
static occ_t map_arith_constant_to_eterm(context_t *ctx, rational_t *q) {
339✔
1362
  thvar_t x;
1363

1364
  if (! context_has_arith_solver(ctx)) {
339✔
1365
    longjmp(ctx->env, ARITH_NOT_SUPPORTED);
×
1366
  }
1367

1368
  x = ctx->arith.create_const(ctx->arith_solver, q);
339✔
1369
  return translate_arithvar_to_eterm(ctx, x);
339✔
1370
}
1371

1372
static occ_t map_bvconst64_to_eterm(context_t *ctx, bvconst64_term_t *c) {
808✔
1373
  thvar_t x;
1374
  type_t tau;
1375

1376
  if (! context_has_bv_solver(ctx)) {
808✔
1377
    longjmp(ctx->env, BV_NOT_SUPPORTED);
×
1378
  }
1379

1380
  x = ctx->bv.create_const64(ctx->bv_solver, c);
808✔
1381
  tau = bv_type(ctx->types, c->bitsize);
808✔
1382

1383
  return translate_bvvar_to_eterm(ctx, x, tau);
808✔
1384
}
1385

1386
static occ_t map_bvconst_to_eterm(context_t *ctx, bvconst_term_t *c) {
18✔
1387
  thvar_t x;
1388
  type_t tau;
1389

1390
  if (! context_has_bv_solver(ctx)) {
18✔
1391
    longjmp(ctx->env, BV_NOT_SUPPORTED);
×
1392
  }
1393

1394
  x = ctx->bv.create_const(ctx->bv_solver, c);
18✔
1395
  tau = bv_type(ctx->types, c->bitsize);
18✔
1396

1397
  return translate_bvvar_to_eterm(ctx, x, tau);
18✔
1398
}
1399

1400

1401

1402
/***************************************
1403
 *  AXIOMS FOR DIV/MOD/FLOOR/CEIL/ABS  *
1404
 **************************************/
1405

1406
/*
1407
 * Auxiliary function: p and map to represent (x - y)
1408
 * - in polynomial p, only the coefficients are relevant
1409
 * - map[0] stores x and map[1] stores y
1410
 * - both p map must be large enough (at least 2 elements)
1411
 */
1412
static void context_store_diff_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
×
1413
  p->nterms = 2;
×
1414
  p->mono[0].var = 1;
×
1415
  q_set_one(&p->mono[0].coeff);       // coeff of x = 1
×
1416
  p->mono[1].var = 2;
×
1417
  q_set_minus_one(&p->mono[1].coeff); // coeff of y = -1
×
1418
  p->mono[2].var = max_idx; // end marker
×
1419

1420
  map[0] = x;
×
1421
  map[1] = y;
×
1422
}
×
1423

1424

1425
/*
1426
 * Same thing for the polynomial (x - y - 1)
1427
 */
1428
static void context_store_diff_minus_one_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
×
1429
  p->nterms = 3;
×
1430
  p->mono[0].var = const_idx;
×
1431
  q_set_minus_one(&p->mono[0].coeff);  // constant = -1
×
1432
  p->mono[1].var = 1;
×
1433
  q_set_one(&p->mono[1].coeff);        // coeff of x = 1
×
1434
  p->mono[2].var = 2;
×
1435
  q_set_minus_one(&p->mono[2].coeff);  // coeff of y = -1
×
1436
  p->mono[3].var = max_idx;
×
1437

1438
  map[0] = null_thvar; // constant
×
1439
  map[1] = x;
×
1440
  map[2] = y;
×
1441
}
×
1442

1443

1444
/*
1445
 * Same thing for the polynomial (x + y)
1446
 */
1447
static void context_store_sum_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
4✔
1448
  p->nterms = 2;
4✔
1449
  p->mono[0].var = 1;
4✔
1450
  q_set_one(&p->mono[0].coeff); // coeff of x = 1
4✔
1451
  p->mono[1].var = 2;
4✔
1452
  q_set_one(&p->mono[1].coeff); // coeff of y = 1
4✔
1453
  p->mono[2].var = max_idx;
4✔
1454

1455
  map[0] = x;
4✔
1456
  map[1] = y;
4✔
1457
}
4✔
1458

1459

1460
/*
1461
 * The lower bound on y = (div x k)  is (k * y <= x) or (x - k * y >= 0)
1462
 * We store the polynomial x - k * y
1463
 */
1464
static void context_store_div_lower_bound(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
21✔
1465
  p->nterms = 2;
21✔
1466
  p->mono[0].var = 1;
21✔
1467
  q_set_one(&p->mono[0].coeff);    // coeff of x = 1
21✔
1468
  p->mono[1].var = 2;
21✔
1469
  q_set_neg(&p->mono[1].coeff, k); // coeff of y = -k
21✔
1470
  p->mono[2].var = max_idx;
21✔
1471

1472
  map[0] = x;
21✔
1473
  map[1] = y;
21✔
1474
}
21✔
1475

1476

1477
/*
1478
 * For converting (divides k x), we use (divides k x) <=> (x <= k * (div x k))
1479
 * or (k * y - x >= 0) for y = (div x k).
1480
 * We store the polynomial - x + k * y.
1481
 */
1482
static void context_store_divides_constraint(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
8✔
1483
  p->nterms = 2;
8✔
1484
  p->mono[0].var = 1;
8✔
1485
  q_set_minus_one(&p->mono[0].coeff);  // coeff of x = -1
8✔
1486
  p->mono[1].var = 2;
8✔
1487
  q_set(&p->mono[1].coeff, k);         // coeff of y = k
8✔
1488
  p->mono[2].var = max_idx;
8✔
1489

1490
  map[0] = x;
8✔
1491
  map[1] = y;
8✔
1492
}
8✔
1493

1494
/*
1495
 * Upper bound on y = (div x k) when both x and y are integer:
1496
 * We have x <= k * y + |k| - 1 or (-x + k y + |k| - 1 >= 0).
1497
 *
1498
 * We store the polynomial - x + k y + |k| - 1
1499
 *
1500
 * NOTE: we don't normalize the constant (|k| - 1) to zero if |k| = 1.
1501
 * This is safe as the simplex solver does not care.
1502
 */
1503
static void context_store_integer_div_upper_bound(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
20✔
1504
  p->nterms = 3;
20✔
1505
  p->mono[0].var = const_idx;
20✔
1506
  q_set_abs(&p->mono[0].coeff, k);
20✔
1507
  q_sub_one(&p->mono[0].coeff);        // constant term = |k| - 1
20✔
1508
  p->mono[1].var = 1;
20✔
1509
  q_set_minus_one(&p->mono[1].coeff);  // coeff of x = -1
20✔
1510
  p->mono[2].var = 2;
20✔
1511
  q_set(&p->mono[2].coeff, k);         // coeff of y = k
20✔
1512
  p->mono[3].var = max_idx;
20✔
1513

1514
  map[0] = null_thvar;
20✔
1515
  map[1] = x;
20✔
1516
  map[2] = y;
20✔
1517
}
20✔
1518

1519
/*
1520
 * Upper bound on y = (div x k) when x or k is not an integer.
1521
 * We have x < k * y + |k| or x - k*y - |k| < 0 or (not (x - k*y - |k| >= 0))
1522
 *
1523
 * We store the polynomial x - ky - |k|
1524
 */
1525
static void context_store_rational_div_upper_bound(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
1✔
1526
  p->nterms = 3;
1✔
1527
  p->mono[0].var = const_idx;
1✔
1528
  q_set_abs(&p->mono[0].coeff, k);
1✔
1529
  q_neg(&p->mono[0].coeff);           // constant term: -|k|
1✔
1530
  p->mono[1].var = 1;
1✔
1531
  q_set_one(&p->mono[1].coeff);       // coeff of x = +1
1✔
1532
  p->mono[2].var = 2;
1✔
1533
  q_set_neg(&p->mono[2].coeff, k);    // coeff of y = -k
1✔
1534
  p->mono[3].var = max_idx;
1✔
1535

1536
  map[0] = null_thvar;
1✔
1537
  map[1] = x;
1✔
1538
  map[2] = y;
1✔
1539
}
1✔
1540

1541

1542
/*
1543
 * Polynomial x - y + k d (for asserting y = k * (div y k) + (mod y k)
1544
 * - d is assumed to be (div y k)
1545
 * - x is assumed to be (mod y k)
1546
 */
1547
static void context_store_divmod_eq(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, thvar_t d, const rational_t *k) {
11✔
1548
  p->nterms = 3;
11✔
1549
  p->mono[0].var = 1;
11✔
1550
  q_set_one(&p->mono[0].coeff);       // coefficient of x = 1
11✔
1551
  p->mono[1].var = 2;
11✔
1552
  q_set_minus_one(&p->mono[1].coeff); // coefficient of y = -1
11✔
1553
  p->mono[2].var = 3;
11✔
1554
  q_set(&p->mono[2].coeff, k);        // coefficient of d = k
11✔
1555
  p->mono[3].var = max_idx;
11✔
1556

1557
  map[0] = x;
11✔
1558
  map[1] = y;
11✔
1559
  map[2] = d;
11✔
1560
}
11✔
1561

1562

1563
/*
1564
 * Bound on x = (mod y k) assuming x and k are integer:
1565
 * - the bound is x <= |k| - 1 (i.e., |k| - 1 - x >= 0)
1566
 *   so we construct |k| - 1 - x
1567
 */
1568
static void context_store_integer_mod_bound(polynomial_t *p, thvar_t *map, thvar_t x, const rational_t *k) {
10✔
1569
  p->nterms = 2;
10✔
1570
  p->mono[0].var = const_idx;
10✔
1571
  q_set_abs(&p->mono[0].coeff, k);
10✔
1572
  q_sub_one(&p->mono[0].coeff);        // constant = |k| - 1
10✔
1573
  p->mono[1].var = 1;
10✔
1574
  q_set_minus_one(&p->mono[1].coeff);  // coeff of x = -1
10✔
1575
  p->mono[2].var = max_idx;
10✔
1576

1577
  map[0] = null_thvar;
10✔
1578
  map[1] = x;
10✔
1579
}
10✔
1580

1581

1582
/*
1583
 * Bound on x = (mod y k) when x or k are rational
1584
 * - the bound is x < |k| or x - |k| < 0 or (not (x - |k| >= 0))
1585
 *   so we construct x - |k|
1586
 */
1587
static void context_store_rational_mod_bound(polynomial_t *p, thvar_t *map, thvar_t x, const rational_t *k) {
1✔
1588
  p->nterms = 2;
1✔
1589
  p->mono[0].var = const_idx;
1✔
1590
  q_set_abs(&p->mono[0].coeff, k);
1✔
1591
  q_neg(&p->mono[0].coeff);            // constant = -|k|
1✔
1592
  p->mono[1].var = 1;
1✔
1593
  q_set_one(&p->mono[1].coeff);        // coeff of x = +1
1✔
1594
  p->mono[2].var = max_idx;
1✔
1595

1596
  map[0] = null_thvar;
1✔
1597
  map[1] = x;
1✔
1598
}
1✔
1599

1600

1601
/*
1602
 * Assert constraints for x := floor(y)
1603
 * - both x and y are variables in the arithmetic solver
1604
 * - x has type integer
1605
 *
1606
 * We assert (x <= y && y < x+1)
1607
 */
1608
static void assert_floor_axioms(context_t *ctx, thvar_t x, thvar_t y) {
×
1609
  polynomial_t *p;
1610
  thvar_t map[3];
1611

1612
  assert(ctx->arith.arith_var_is_int(ctx->arith_solver, x));
1613

1614
  p = context_get_aux_poly(ctx, 4);
×
1615

1616
  // assert (y - x >= 0)
1617
  context_store_diff_poly(p, map, y, x);
×
1618
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
×
1619

1620
  // assert (y - x - 1 < 0) <=> (not (y - x - 1) >= 0)
1621
  context_store_diff_minus_one_poly(p, map, y, x);
×
1622
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
×
1623
}
×
1624

1625

1626
/*
1627
 * Assert constraints for x == ceil(y)
1628
 * - both x and y are variables in the arithmetic solver
1629
 * - x has type integer
1630
 *
1631
 * We assert (x - 1 < y && y <= x)
1632
 */
1633
static void assert_ceil_axioms(context_t *ctx, thvar_t x, thvar_t y) {
×
1634
  polynomial_t *p;
1635
  thvar_t map[3];
1636

1637
  assert(ctx->arith.arith_var_is_int(ctx->arith_solver, x));
1638

1639
  p = context_get_aux_poly(ctx, 4);
×
1640

1641
  // assert (x - y >= 0)
1642
  context_store_diff_poly(p, map, x, y);
×
1643
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
×
1644

1645
  // assert (x - y - 1 < 0) <=> (not (x - y - 1) >= 0)
1646
  context_store_diff_minus_one_poly(p, map, x, y);
×
1647
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
×
1648
}
×
1649

1650

1651
/*
1652
 * Assert constraints for x == abs(y)
1653
 * - x and y must be variables in the arithmetic solver
1654
 *
1655
 * We assert (x >= 0) AND ((x == y) or (x == -y))
1656
 */
1657
static void assert_abs_axioms(context_t *ctx, thvar_t x, thvar_t y) {
4✔
1658
  polynomial_t *p;
1659
  thvar_t map[2];
1660
  literal_t l1, l2;
1661

1662
  // assert (x >= 0)
1663
  ctx->arith.assert_ge_axiom(ctx->arith_solver, x, true);
4✔
1664

1665
  // create l1 := (x == y)
1666
  l1 = ctx->arith.create_vareq_atom(ctx->arith_solver, x, y);
4✔
1667

1668
  // create l2 := (x == -y) that is (x + y == 0)
1669
  p = context_get_aux_poly(ctx, 3);
4✔
1670
  context_store_sum_poly(p, map, x, y);
4✔
1671
  l2 = ctx->arith.create_poly_eq_atom(ctx->arith_solver, p, map);
4✔
1672

1673
  // assert (or l1 l2)
1674
  add_binary_clause(ctx->core, l1, l2);
4✔
1675
}
4✔
1676

1677

1678
/*
1679
 * Constraints for x == (div y k)
1680
 * - x and y must be variables in the arithmetic solver
1681
 * - x must be an integer variable
1682
 * - k is a non-zero rational constant
1683
 *
1684
 * If k and y are integer, we assert
1685
 *   k * x <= y <= k * x + |k| - 1
1686
 *
1687
 * Otherwise, we assert
1688
 *   k * x <= y < k * x + |k|
1689
 */
1690
static void assert_div_axioms(context_t *ctx, thvar_t x, thvar_t y, const rational_t *k) {
21✔
1691
  polynomial_t *p;
1692
  thvar_t map[3];
1693

1694
  p = context_get_aux_poly(ctx, 4);
21✔
1695

1696
  // assert k*x <= y (i.e., y - k*x >= 0)
1697
  context_store_div_lower_bound(p, map, y, x, k);
21✔
1698
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
21✔
1699

1700
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, y) && q_is_integer(k)) {
21✔
1701
    // y and k are both integer
1702
    // assert y <= k*x + |k| - 1 (i.e., - y + k x + |k| - 1 >= 0)
1703
    context_store_integer_div_upper_bound(p, map, y, x, k);
20✔
1704
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
20✔
1705

1706
  } else {
1707
    // assert y < k*x + |k| (i.e., y - k*x - |k| < 0) or (not (y - k*x - |k| >= 0))
1708
    context_store_rational_div_upper_bound(p, map, y, x, k);
1✔
1709
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
1✔
1710
  }
1711
}
21✔
1712

1713

1714
/*
1715
 * Constraints for x == (mod y k)
1716
 * - d must be the variable equal to (div y k)
1717
 * - x and y must be variables in the arithmetic solver
1718
 * - k is a non-zero rational constant.
1719
 *
1720
 * We assert x = y - k * d (i.e., (mod y k) = x - k * (div y k))
1721
 * and 0 <= x < |k|.
1722
 *
1723
 * NOTE: The 0 <= x < |k| part is redundant. It's implied by the
1724
 * div_axioms for d = (div y k). It's cheap enough that I can't
1725
 * see a problem with adding it anyway (it's just an interval for x).
1726
 */
1727
static void assert_mod_axioms(context_t *ctx, thvar_t x, thvar_t y, thvar_t d, const rational_t *k) {
11✔
1728
  polynomial_t *p;
1729
  thvar_t map[3];
1730

1731
  p = context_get_aux_poly(ctx, 4);
11✔
1732

1733
  // assert y = k * d + x (i.e., x - y + k *d = 0)
1734
  context_store_divmod_eq(p, map, x, y, d, k);
11✔
1735
  ctx->arith.assert_poly_eq_axiom(ctx->arith_solver, p, map, true);
11✔
1736

1737
  // assert x >= 0
1738
  ctx->arith.assert_ge_axiom(ctx->arith_solver, x, true);
11✔
1739

1740
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x) && q_is_integer(k)) {
11✔
1741
    // both x and |k| are integer
1742
    // assert x <= |k| - 1, i.e., -x + |k| - 1 >= 0
1743
    context_store_integer_mod_bound(p, map, x, k);
10✔
1744
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
10✔
1745
  } else {
1746
    // assert x < |k|, i.e., x - |k| <0, i.e., (not (x - |k| >= 0))
1747
    context_store_rational_mod_bound(p, map, x, k);
1✔
1748
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
1✔
1749
  }
1750
}
11✔
1751

1752

1753

1754
/******************************************************
1755
 *  CONVERSION OF COMPOSITES TO ARITHMETIC VARIABLES  *
1756
 *****************************************************/
1757

1758
/*
1759
 * Convert a conditional to an arithmetic variable
1760
 * - if is_int is true, the variable is integer otherwise, it's real
1761
 */
1762
static thvar_t map_conditional_to_arith(context_t *ctx, conditional_t *c, bool is_int) {
239✔
1763
  literal_t *a;
1764
  uint32_t i, n;
1765
  thvar_t x, v;
1766
  bool all_false;
1767
  term_t t;
1768

1769
#if 0
1770
  printf("---> conditional to arith\n");
1771
#endif
1772

1773
  t = simplify_conditional(ctx, c);
239✔
1774
  if (t != NULL_TERM) {
239✔
1775
    return internalize_to_arith(ctx, t);
13✔
1776
  }
1777

1778
  n = c->nconds;
226✔
1779
  a = alloc_istack_array(&ctx->istack, n);
226✔
1780

1781
  all_false = true;
226✔
1782
  v = null_thvar;
226✔
1783

1784
  for (i=0; i<n; i++) {
703✔
1785
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
485✔
1786
    if (a[i] == true_literal) {
485✔
1787
      /*
1788
       * a[0] ... a[i-1] are all reducible to false
1789
       * but we can't assume v == null_thvar, since
1790
       * we don't know how the theory solver internalizes
1791
       * the conditions (i.e., some of them may not be false_literal).
1792
       */
1793
      x = internalize_to_arith(ctx, c->pair[i].val);
8✔
1794
      if (all_false) {
8✔
1795
        assert(v == null_thvar);
1796
        v = x;
6✔
1797
      } else {
1798
        // assert (v == x) in the arithmetic solver
1799
        ctx->arith.assert_vareq_axiom(ctx->arith_solver, v, x, true);
2✔
1800
      }
1801
      goto done;
8✔
1802
    }
1803
    if (a[i] != false_literal) {
477✔
1804
      if (all_false) {
460✔
1805
        assert(v == null_thvar);
1806
        v = ctx->arith.create_var(ctx->arith_solver, is_int);
215✔
1807
        all_false = false;
215✔
1808
      }
1809
      // clause for a[i] => (v = c->pair[i].val)
1810
      x = internalize_to_arith(ctx, c->pair[i].val);
460✔
1811
      ctx->arith.assert_cond_vareq_axiom(ctx->arith_solver, a[i], v, x);
460✔
1812
    }
1813
  }
1814

1815
  if (all_false) {
218✔
1816
    assert(v == null_thvar);
1817
    v = internalize_to_arith(ctx, c->defval);
5✔
1818
    goto done;
5✔
1819
  }
1820

1821
  /*
1822
   * last clause (only if some a[i] isn't false):
1823
   * (a[0] \/ ... \/ a[n-1] \/ v == c->defval)
1824
   */
1825
  assert(v != null_thvar);
1826
  x = internalize_to_arith(ctx, c->defval);
213✔
1827
  ctx->arith.assert_clause_vareq_axiom(ctx->arith_solver, n, a, v, x);
213✔
1828

1829
 done:
226✔
1830
  free_istack_array(&ctx->istack, a);
226✔
1831
  return v;
226✔
1832
}
1833

1834

1835
/*
1836
 * Convert nested if-then-else to  an arithmetic variable
1837
 * - ite = term of the form (ite c1 t1 t2)
1838
 * - c = internalization of c1
1839
 * - is_int = true if the if-then-else term is integer (otherwise it's real)
1840
 */
1841
static thvar_t flatten_ite_to_arith(context_t *ctx, composite_term_t *ite, literal_t c, bool is_int) {
2,521✔
1842
  ite_flattener_t *flattener;
1843
  ivector_t *buffer;
1844
  term_t x;
1845
  thvar_t u, v;
1846

1847
  u = ctx->arith.create_var(ctx->arith_solver, is_int);
2,521✔
1848

1849
  flattener = objstack_alloc(&ctx->ostack, sizeof(ite_flattener_t), (cleaner_t) delete_ite_flattener);
2,521✔
1850
  init_ite_flattener(flattener);
2,521✔
1851

1852
  ite_flattener_push(flattener, ite, c);
2,521✔
1853

1854
  while (ite_flattener_is_nonempty(flattener)) {
8,823✔
1855
    if (ite_flattener_last_lit_false(flattener)) {
6,302✔
1856
      // dead branch
1857
      ite_flattener_next_branch(flattener);
7✔
1858
      continue;
7✔
1859
    }
1860
    assert(ite_flattener_branch_is_live(flattener));
1861

1862
    x = ite_flattener_leaf(flattener);
6,295✔
1863
    x = intern_tbl_get_root(&ctx->intern, x);
6,295✔
1864

1865
    /*
1866
     * x is the current leaf
1867
     * If x is of the form (ite c a b) we can push (ite c a b) on the flattener.
1868
     *
1869
     * Heuristics: don't push the term if x is already internalized or if it's
1870
     * shared.
1871
     */
1872
    if (is_pos_term(x) &&
12,590✔
1873
        is_ite_term(ctx->terms, x) &&
6,295✔
1874
        !intern_tbl_root_is_mapped(&ctx->intern, x) &&
3,934✔
1875
        term_is_not_shared(&ctx->sharing, x)) {
1,256✔
1876
      ite = ite_term_desc(ctx->terms, x);
630✔
1877
      assert(ite->arity == 3);
1878
      c = internalize_to_literal(ctx, ite->arg[0]);
630✔
1879
      ite_flattener_push(flattener, ite, c);
630✔
1880
    } else {
1881
      /*
1882
       * Add the clause [branch conditions => x = u]
1883
       */
1884
      v = internalize_to_arith(ctx, x);
5,665✔
1885

1886
      buffer = &ctx->aux_vector;
5,665✔
1887
      assert(buffer->size == 0);
1888
      ite_flattener_get_clause(flattener, buffer);
5,665✔
1889
      ite_prepare_antecedents(buffer);
5,665✔
1890
      // assert [buffer \/ v = u]
1891
      ctx->arith.assert_clause_vareq_axiom(ctx->arith_solver, buffer->size, buffer->data, v, u);
5,665✔
1892
      ivector_reset(buffer);
5,665✔
1893

1894
      ite_flattener_next_branch(flattener);
5,665✔
1895
    }
1896
  }
1897

1898
  //  delete_ite_flattener(&flattener);
1899
   objstack_pop(&ctx->ostack);
2,521✔
1900

1901
  return u;
2,521✔
1902
}
1903

1904
/*
1905
 * Convert if-then-else to an arithmetic variable
1906
 * - if is_int is true, the if-then-else term is integer
1907
 * - otherwise, it's real
1908
 */
1909
static thvar_t map_ite_to_arith(context_t *ctx, composite_term_t *ite, bool is_int) {
3,023✔
1910
  conditional_t *d;
1911
  literal_t c;
1912
  thvar_t v, x;
1913

1914
  assert(ite->arity == 3);
1915

1916
  d = context_make_conditional(ctx, ite);
3,023✔
1917
  if (d != NULL) {
3,023✔
1918
    v = map_conditional_to_arith(ctx, d, is_int);
239✔
1919
    context_free_conditional(ctx, d);
239✔
1920
    return v;
239✔
1921
  }
1922

1923
  c = internalize_to_literal(ctx, ite->arg[0]); // condition
2,784✔
1924
  if (c == true_literal) {
2,784✔
1925
    return internalize_to_arith(ctx, ite->arg[1]);
77✔
1926
  }
1927
  if (c == false_literal) {
2,707✔
1928
    return internalize_to_arith(ctx, ite->arg[2]);
115✔
1929
  }
1930

1931
  if (context_ite_flattening_enabled(ctx)) {
2,592✔
1932
    return flatten_ite_to_arith(ctx, ite, c, is_int);
2,521✔
1933
  }
1934

1935

1936
  /*
1937
   * no simplification: create a fresh variable v and assert (c ==> v = t1)
1938
   * and (not c ==> v = t2)
1939
   */
1940
  v = ctx->arith.create_var(ctx->arith_solver, is_int);
71✔
1941

1942
  x = internalize_to_arith(ctx, ite->arg[1]);
71✔
1943
  ctx->arith.assert_cond_vareq_axiom(ctx->arith_solver, c, v, x); // c ==> v = t1
71✔
1944

1945
  x = internalize_to_arith(ctx, ite->arg[2]);
71✔
1946
  ctx->arith.assert_cond_vareq_axiom(ctx->arith_solver, not(c), v, x); // (not c) ==> v = t2
71✔
1947

1948
  return v;
71✔
1949
}
1950

1951

1952
/*
1953
 * Assert the bounds on t when t is an arithmetic, special if-then-else
1954
 * - x = arithmetic variable mapped to t in the arithmetic solver
1955
 */
1956
static void assert_ite_bounds(context_t *ctx, term_t t, thvar_t x) {
793✔
1957
  term_table_t *terms;
1958
  polynomial_t *p;
1959
  term_t lb, ub;
1960
  thvar_t map[2];
1961

1962
  terms = ctx->terms;
793✔
1963
  assert(is_arithmetic_term(terms, t));
1964

1965
  // get lower and upper bound on t. Both are rational constants
1966
  term_finite_domain_bounds(terms, t, &lb, &ub);
793✔
1967

1968
#if 0
1969
  printf("assert ite bound:\n  term: ");
1970
  print_term_name(stdout, terms, t);
1971
  printf("\n");
1972
  printf("  lower bound: ");
1973
  print_term_full(stdout, terms, lb);
1974
  printf("\n");
1975
  printf("  upper bound: ");
1976
  print_term_full(stdout, terms, ub);
1977
  printf("\n");
1978
#endif
1979

1980
  /*
1981
   * prepare polynomial p:
1982
   * first monomial is a constant, second monomial is either +t or -t
1983
   * map[0] = null (what's mapped to const_idx)
1984
   * map[1] = x = (what's mapped to t)
1985
   */
1986
  p = context_get_aux_poly(ctx, 3);
793✔
1987
  p->nterms = 2;
793✔
1988
  p->mono[0].var = const_idx;
793✔
1989
  p->mono[1].var = t;
793✔
1990
  p->mono[2].var = max_idx;
793✔
1991
  map[0] = null_thvar;
793✔
1992
  map[1] = x;
793✔
1993

1994

1995
  // first bound: t >= lb
1996
  q_set_neg(&p->mono[0].coeff, rational_term_desc(terms, lb)); // -lb
793✔
1997
  q_set_one(&p->mono[1].coeff); // +t
793✔
1998
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true); // assert -lb + t >= 0
793✔
1999

2000
  // second bound: t <= ub
2001
  q_set(&p->mono[0].coeff, rational_term_desc(terms, ub));  // +ub
793✔
2002
  q_set_minus_one(&p->mono[1].coeff);  // -t
793✔
2003
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true); // assert +ub - t >= 0
793✔
2004
}
793✔
2005

2006

2007
/*
2008
 * Convert a power product to an arithmetic variable
2009
 */
2010
static thvar_t map_pprod_to_arith(context_t *ctx, pprod_t *p) {
×
2011
  uint32_t i, n;
2012
  thvar_t *a;
2013
  thvar_t x;
2014

2015
  n = p->len;
×
2016
  a = alloc_istack_array(&ctx->istack, n);
×
2017
  for (i=0; i<n; i++) {
×
2018
    a[i] = internalize_to_arith(ctx, p->prod[i].var);
×
2019
  }
2020

2021
  x = ctx->arith.create_pprod(ctx->arith_solver, p, a);
×
2022
  free_istack_array(&ctx->istack, a);
×
2023

2024
  return x;
×
2025
}
2026

2027

2028
/*
2029
 * Convert polynomial p to an arithmetic variable
2030
 */
2031
static thvar_t map_poly_to_arith(context_t *ctx, polynomial_t *p) {
1,762✔
2032
  uint32_t i, n;
2033
  thvar_t *a;
2034
  thvar_t x;
2035

2036
  n = p->nterms;
1,762✔
2037
  a = alloc_istack_array(&ctx->istack, n);
1,762✔
2038

2039
  // skip the constant if any
2040
  i = 0;
1,762✔
2041
  if (p->mono[0].var == const_idx) {
1,762✔
2042
    a[0] = null_thvar;
467✔
2043
    i ++;
467✔
2044
  }
2045

2046
  // deal with the non-constant monomials
2047
  while (i<n) {
5,035✔
2048
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
3,273✔
2049
    i ++;
3,273✔
2050
  }
2051

2052
  // build the polynomial
2053
  x = ctx->arith.create_poly(ctx->arith_solver, p, a);
1,762✔
2054
  free_istack_array(&ctx->istack, a);
1,762✔
2055

2056
  return x;
1,762✔
2057
}
2058

2059

2060
/*
2061
 * Auxiliary function: return y := (floor x)
2062
 * - check the divmod table first.
2063
 *   If there's a record for (floor x), return the corresponding variable.
2064
 * - Otherwise, create a fresh integer variable y,
2065
 *   assert the axioms for y = (floor x)
2066
 *   add a record to the divmod table and return y.
2067
 */
2068
static thvar_t get_floor(context_t *ctx, thvar_t x) {
×
2069
  thvar_t y;
2070

2071
  y = context_find_var_for_floor(ctx, x);
×
2072
  if (y == null_thvar) {
×
2073
    y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer variable
×
2074
    assert_floor_axioms(ctx, y, x); // assert y = floor(x)
×
2075
    context_record_floor(ctx, x, y); // save the mapping y --> floor(x)
×
2076
  }
2077

2078
  return y;
×
2079
}
2080

2081

2082
/*
2083
 * Return y := (div x k)
2084
 * - check the divmod table first
2085
 * - if (div x k) has already been processed, return the corresponding variable
2086
 * - otherwise create a new variable y, assert the axioms for y = (div x k)
2087
 *   add a record in the divmod table, and return y.
2088
 */
2089
static thvar_t get_div(context_t *ctx, thvar_t x, const rational_t *k) {
25✔
2090
  thvar_t y;
2091

2092
  y = context_find_var_for_div(ctx, x, k);
25✔
2093
  if (y == null_thvar) {
25✔
2094
    // create y := (div x k)
2095
    y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer
21✔
2096
    assert_div_axioms(ctx, y, x, k);
21✔
2097
    context_record_div(ctx, x, k, y);
21✔
2098
  }
2099

2100
  return y;
25✔
2101
}
2102

2103

2104

2105
/*
2106
 * Convert (floor t) to an arithmetic variable
2107
 */
2108
static thvar_t map_floor_to_arith(context_t *ctx, term_t t) {
×
2109
  thvar_t x, y;
2110

2111
  x = internalize_to_arith(ctx, t);
×
2112
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
2113
    // x is integer so (floor x) = x
2114
    y = x;
×
2115
  } else {
2116
    y = get_floor(ctx, x);
×
2117
  }
2118

2119
  return y;
×
2120
}
2121

2122

2123
/*
2124
 * Convert (ceil t) to an arithmetic variable
2125
 */
2126
static thvar_t map_ceil_to_arith(context_t *ctx, term_t t) {
×
2127
  thvar_t x, y;
2128

2129
  x = internalize_to_arith(ctx, t);
×
2130
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
2131
    // x is integer so (ceil x) = x
2132
    y = x;
×
2133
  } else {
2134
    y = context_find_var_for_ceil(ctx, x);
×
2135
    if (y == null_thvar) {
×
2136
      y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer variable
×
2137
      assert_ceil_axioms(ctx, y, x); // assert y = ceil(x)
×
2138
      context_record_ceil(ctx, x, y); // save the mapping y --> ceil(x)
×
2139
    }
2140
  }
2141

2142
  return y;
×
2143
}
2144

2145

2146
/*
2147
 * Convert (abs t) to an arithmetic variable
2148
 */
2149
static thvar_t map_abs_to_arith(context_t *ctx, term_t t) {
4✔
2150
  thvar_t x, y;
2151
  bool is_int;
2152

2153
  x = internalize_to_arith(ctx, t);
4✔
2154
  is_int = ctx->arith.arith_var_is_int(ctx->arith_solver, x);
4✔
2155
  y = ctx->arith.create_var(ctx->arith_solver, is_int); // y := abs(x) has the same type as x
4✔
2156
  assert_abs_axioms(ctx, y, x);
4✔
2157

2158
  return y;
4✔
2159
}
2160

2161

2162
/*
2163
 * Auxiliary function: check whether t is a non-zero arithmetic constant
2164
 * - if so, store t's value in *val
2165
 */
2166
static bool is_non_zero_rational(term_table_t *tbl, term_t t, rational_t *val) {
17✔
2167
  assert(is_arithmetic_term(tbl, t));
2168

2169
  if (term_kind(tbl, t) == ARITH_CONSTANT) {
17✔
2170
    q_set(val, rational_term_desc(tbl, t));
17✔
2171
    return q_is_nonzero(val);
17✔
2172
  }
2173
  return false;
×
2174
}
2175

2176

2177
/*
2178
 * Error in division: either the divisor is zero or is non-constant
2179
 */
2180
static void __attribute__((noreturn))  bad_divisor(context_t *ctx, term_t t) {
3✔
2181
  term_table_t *tbl;
2182
  int code;
2183

2184
  tbl = ctx->terms;
3✔
2185
  assert(is_arithmetic_term(tbl, t) && is_pos_term(t));
2186

2187
  code = FORMULA_NOT_LINEAR;
3✔
2188
  if (term_kind(tbl, t) == ARITH_CONSTANT && q_is_zero(rational_term_desc(tbl, t))) {
3✔
2189
    code = DIV_BY_ZERO;
3✔
2190
  }
2191
  longjmp(ctx->env, code);
3✔
2192
}
2193

2194
/*
2195
 * Convert (/ t1 t2) to an arithmetic variable
2196
 * - t2 must be a non-zero arithmetic constant
2197
 */
2198
static thvar_t map_rdiv_to_arith(context_t *ctx, composite_term_t *div) {
3✔
2199
  // Could try to evaluate t2 then check whether that's a constant
2200
  assert(div->arity == 2);
2201
  bad_divisor(ctx, div->arg[1]);
3✔
2202
}
2203

2204

2205
/*
2206
 * Convert (div t1 t2) to an arithmetic variable.
2207
 * - fails if t2 is not an arithmetic constant or if it's zero
2208
 */
2209
static thvar_t map_idiv_to_arith(context_t *ctx, composite_term_t *div) {
6✔
2210
  rational_t k;
2211
  thvar_t x, y;
2212

2213
  assert(div->arity == 2);
2214

2215
  q_init(&k);
6✔
2216
  if (is_non_zero_rational(ctx->terms, div->arg[1], &k)) { // k := value of t2
6✔
2217
    assert(q_is_nonzero(&k));
2218
    x = internalize_to_arith(ctx, div->arg[0]); // t1
6✔
2219
    y = get_div(ctx, x, &k);
6✔
2220

2221
  } else {
2222
    // division by a non-constant or by zero: not supported by default
2223
    // arithmetic solver for now
2224
    q_clear(&k);
×
2225
    bad_divisor(ctx, div->arg[1]);
×
2226
  }
2227
  q_clear(&k);
6✔
2228

2229
  return y;
6✔
2230
}
2231

2232

2233
/*
2234
 * Convert (mod t1 t2) to an arithmetic variable
2235
 * - t2 must be a non-zero constant
2236
 */
2237
static thvar_t map_mod_to_arith(context_t *ctx, composite_term_t *mod) {
11✔
2238
  rational_t k;
2239
  thvar_t x, y, r;
2240
  bool is_int;
2241

2242
  assert(mod->arity == 2);
2243

2244
  q_init(&k);
11✔
2245
  if (is_non_zero_rational(ctx->terms, mod->arg[1], &k)) { // k := divider
11✔
2246
    x = internalize_to_arith(ctx, mod->arg[0]);
11✔
2247

2248
    // get y := (div x k)
2249
    assert(q_is_nonzero(&k));
2250
    y = get_div(ctx, x, &k);
11✔
2251

2252
    /*
2253
     * r := (mod x k) is x - k * y where y is an integer.
2254
     * If both x and k are integer, then r has integer type. Otherwise,
2255
     * r is a real variable.
2256
     */
2257
    is_int = ctx->arith.arith_var_is_int(ctx->arith_solver, x) && q_is_integer(&k);
11✔
2258
    r = ctx->arith.create_var(ctx->arith_solver, is_int);
11✔
2259
    assert_mod_axioms(ctx, r, x, y, &k);
11✔
2260

2261
  } else {
2262
    // Non-constant or zero divider
2263
    q_clear(&k);
×
2264
    bad_divisor(ctx, mod->arg[1]);
×
2265
  }
2266

2267
  q_clear(&k);
11✔
2268

2269
  return r;
11✔
2270
}
2271

2272

2273

2274
/******************************************************
2275
 *  CONVERSION OF COMPOSITES TO BIT-VECTOR VARIABLES  *
2276
 *****************************************************/
2277

2278
/*
2279
 * Convert if-then-else to a bitvector variable
2280
 */
2281
static thvar_t map_ite_to_bv(context_t *ctx, composite_term_t *ite) {
20,779✔
2282
  literal_t c;
2283
  thvar_t x, y;
2284

2285
  assert(ite->arity == 3);
2286

2287
  c = internalize_to_literal(ctx, ite->arg[0]);
20,779✔
2288
  if (c == true_literal) {
20,779✔
2289
    return internalize_to_bv(ctx, ite->arg[1]);
23✔
2290
  }
2291
  if (c == false_literal) {
20,756✔
2292
    return internalize_to_bv(ctx, ite->arg[2]);
2,082✔
2293
  }
2294

2295
  // no simplification
2296
  x = internalize_to_bv(ctx, ite->arg[1]);
18,674✔
2297
  y = internalize_to_bv(ctx, ite->arg[2]);
18,674✔
2298

2299
  return ctx->bv.create_bvite(ctx->bv_solver, c, x, y);
18,674✔
2300
}
2301

2302

2303
/*
2304
 * Array of bits b
2305
 * - hackish: we locally disable flattening here
2306
 */
2307
static thvar_t map_bvarray_to_bv(context_t *ctx, composite_term_t *b) {
17,037✔
2308
  uint32_t i, n;
2309
  uint32_t save_options;
2310
  literal_t *a;
2311
  thvar_t x;
2312

2313
  n = b->arity;
17,037✔
2314
  a = alloc_istack_array(&ctx->istack, n);
17,037✔
2315

2316
  save_options = ctx->options;
17,037✔
2317
  disable_diseq_and_or_flattening(ctx);
17,037✔
2318
  for (i=0; i<n; i++) {
498,135✔
2319
    a[i] = internalize_to_literal(ctx, b->arg[i]);
481,098✔
2320
  }
2321
  ctx->options = save_options;
17,037✔
2322

2323
  x = ctx->bv.create_bvarray(ctx->bv_solver, a, n);
17,037✔
2324

2325
  free_istack_array(&ctx->istack, a);
17,037✔
2326

2327
  return x;
17,037✔
2328
}
2329

2330

2331
/*
2332
 * Unsigned division: quotient (div u v)
2333
 */
2334
static thvar_t map_bvdiv_to_bv(context_t *ctx, composite_term_t *div) {
97✔
2335
  thvar_t x, y;
2336

2337
  assert(div->arity == 2);
2338
  x = internalize_to_bv(ctx, div->arg[0]);
97✔
2339
  y = internalize_to_bv(ctx, div->arg[1]);
97✔
2340

2341
  return ctx->bv.create_bvdiv(ctx->bv_solver, x, y);
97✔
2342
}
2343

2344

2345
/*
2346
 * Unsigned division: remainder (rem u v)
2347
 */
2348
static thvar_t map_bvrem_to_bv(context_t *ctx, composite_term_t *rem) {
177✔
2349
  thvar_t x, y;
2350

2351
  assert(rem->arity == 2);
2352
  x = internalize_to_bv(ctx, rem->arg[0]);
177✔
2353
  y = internalize_to_bv(ctx, rem->arg[1]);
177✔
2354

2355
  return ctx->bv.create_bvrem(ctx->bv_solver, x, y);
177✔
2356
}
2357

2358

2359
/*
2360
 * Signed division/rounding toward 0: quotient (sdiv u v)
2361
 */
2362
static thvar_t map_bvsdiv_to_bv(context_t *ctx, composite_term_t *sdiv) {
87✔
2363
  thvar_t x, y;
2364

2365
  assert(sdiv->arity == 2);
2366
  x = internalize_to_bv(ctx, sdiv->arg[0]);
87✔
2367
  y = internalize_to_bv(ctx, sdiv->arg[1]);
87✔
2368

2369
  return ctx->bv.create_bvsdiv(ctx->bv_solver, x, y);
87✔
2370
}
2371

2372

2373
/*
2374
 * Signed division/rounding toward 0: remainder (srem u v)
2375
 */
2376
static thvar_t map_bvsrem_to_bv(context_t *ctx, composite_term_t *srem) {
77✔
2377
  thvar_t x, y;
2378

2379
  assert(srem->arity == 2);
2380
  x = internalize_to_bv(ctx, srem->arg[0]);
77✔
2381
  y = internalize_to_bv(ctx, srem->arg[1]);
77✔
2382

2383
  return ctx->bv.create_bvsrem(ctx->bv_solver, x, y);
77✔
2384
}
2385

2386

2387
/*
2388
 * Signed division/rounding toward -infinity: remainder (smod u v)
2389
 */
2390
static thvar_t map_bvsmod_to_bv(context_t *ctx, composite_term_t *smod) {
×
2391
  thvar_t x, y;
2392

2393
  assert(smod->arity == 2);
2394
  x = internalize_to_bv(ctx, smod->arg[0]);
×
2395
  y = internalize_to_bv(ctx, smod->arg[1]);
×
2396

2397
  return ctx->bv.create_bvsmod(ctx->bv_solver, x, y);
×
2398
}
2399

2400

2401
/*
2402
 * Left shift: (shl u v)
2403
 */
2404
static thvar_t map_bvshl_to_bv(context_t *ctx, composite_term_t *shl) {
85✔
2405
  thvar_t x, y;
2406

2407
  assert(shl->arity == 2);
2408
  x = internalize_to_bv(ctx, shl->arg[0]);
85✔
2409
  y = internalize_to_bv(ctx, shl->arg[1]);
85✔
2410

2411
  return ctx->bv.create_bvshl(ctx->bv_solver, x, y);
85✔
2412
}
2413

2414

2415
/*
2416
 * Logical shift right: (lshr u v)
2417
 */
2418
static thvar_t map_bvlshr_to_bv(context_t *ctx, composite_term_t *lshr) {
1,428✔
2419
  thvar_t x, y;
2420

2421
  assert(lshr->arity == 2);
2422
  x = internalize_to_bv(ctx, lshr->arg[0]);
1,428✔
2423
  y = internalize_to_bv(ctx, lshr->arg[1]);
1,428✔
2424

2425
  return ctx->bv.create_bvlshr(ctx->bv_solver, x, y);
1,428✔
2426
}
2427

2428

2429
/*
2430
 * Arithmetic shift right: (ashr u v)
2431
 */
2432
static thvar_t map_bvashr_to_bv(context_t *ctx, composite_term_t *ashr) {
296✔
2433
  thvar_t x, y;
2434

2435
  assert(ashr->arity == 2);
2436
  x = internalize_to_bv(ctx, ashr->arg[0]);
296✔
2437
  y = internalize_to_bv(ctx, ashr->arg[1]);
296✔
2438

2439
  return ctx->bv.create_bvashr(ctx->bv_solver, x, y);
296✔
2440
}
2441

2442

2443

2444
/*
2445
 * TODO: check for simplifications in bitvector arithmetic
2446
 * before translation to bitvector variables.
2447
 *
2448
 * This matters for the wienand-cav2008 benchmarks.
2449
 */
2450

2451
/*
2452
 * Power product
2453
 */
2454
static thvar_t map_pprod_to_bv(context_t *ctx, pprod_t *p) {
585✔
2455
  uint32_t i, n;
2456
  thvar_t *a;
2457
  thvar_t x;
2458

2459
  n = p->len;
585✔
2460
  a = alloc_istack_array(&ctx->istack, n);
585✔
2461
  for (i=0; i<n; i++) {
1,730✔
2462
    a[i] = internalize_to_bv(ctx, p->prod[i].var);
1,145✔
2463
  }
2464

2465
  x = ctx->bv.create_pprod(ctx->bv_solver, p, a);
585✔
2466
  free_istack_array(&ctx->istack, a);
585✔
2467

2468
  return x;
585✔
2469
}
2470

2471

2472
/*
2473
 * Bitvector polynomial, 64bit coefficients
2474
 */
2475
static thvar_t map_bvpoly64_to_bv(context_t *ctx, bvpoly64_t *p) {
12,225✔
2476
  uint32_t i, n;
2477
  thvar_t *a;
2478
  thvar_t x;
2479

2480
  assert(p->nterms > 0);
2481

2482
  n = p->nterms;
12,225✔
2483
  a = alloc_istack_array(&ctx->istack, n);
12,225✔
2484

2485
  // skip the constant if any
2486
  i = 0;
12,225✔
2487
  if (p->mono[0].var == const_idx) {
12,225✔
2488
    a[0] = null_thvar;
3,212✔
2489
    i ++;
3,212✔
2490
  }
2491

2492
  // non-constant monomials
2493
  while (i < n) {
28,477✔
2494
    a[i] = internalize_to_bv(ctx, p->mono[i].var);
16,252✔
2495
    i ++;
16,252✔
2496
  }
2497

2498
  x = ctx->bv.create_poly64(ctx->bv_solver, p, a);
12,225✔
2499
  free_istack_array(&ctx->istack, a);
12,225✔
2500

2501
  return x;
12,225✔
2502
}
2503

2504

2505
/*
2506
 * Bitvector polynomial, coefficients have more than 64bits
2507
 */
2508
static thvar_t map_bvpoly_to_bv(context_t *ctx, bvpoly_t *p) {
607✔
2509
  uint32_t i, n;
2510
  thvar_t *a;
2511
  thvar_t x;
2512

2513
  assert(p->nterms > 0);
2514

2515
  n = p->nterms;
607✔
2516
  a = alloc_istack_array(&ctx->istack, n);
607✔
2517

2518
  // skip the constant if any
2519
  i = 0;
607✔
2520
  if (p->mono[0].var == const_idx) {
607✔
2521
    a[0] = null_thvar;
539✔
2522
    i ++;
539✔
2523
  }
2524

2525
  // non-constant monomials
2526
  while (i < n) {
1,268✔
2527
    a[i] = internalize_to_bv(ctx, p->mono[i].var);
661✔
2528
    i ++;
661✔
2529
  }
2530

2531
  x = ctx->bv.create_poly(ctx->bv_solver, p, a);
607✔
2532
  free_istack_array(&ctx->istack, a);
607✔
2533

2534
  return x;
607✔
2535
}
2536

2537

2538
#if 0
2539
/*
2540
 * Bvpoly buffer: b must be normalized.
2541
 * - not optimal but this shouldn't be called often.
2542
 */
2543
static thvar_t map_bvpoly_buffer_to_bv(context_t *ctx, bvpoly_buffer_t *b) {
2544
  bvpoly64_t *p;
2545
  bvpoly_t *q;
2546
  uint32_t n;
2547
  thvar_t x;
2548

2549
  n = bvpoly_buffer_bitsize(b);
2550

2551
  if (bvpoly_buffer_is_zero(b)) {
2552
    x = ctx->bv.create_zero(ctx->bv_solver, n);
2553
  } else if (n <= 64) {
2554
    p = bvpoly_buffer_getpoly64(b);
2555
    x = map_bvpoly64_to_bv(ctx, p);
2556
    free_bvpoly64(p);
2557
  } else {
2558
    q = bvpoly_buffer_getpoly(b);
2559
    x = map_bvpoly_to_bv(ctx, q);
2560
    free_bvpoly(q);
2561
  }
2562

2563
  if (ctx->mcsat_supplement) {
2564
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
2565
    if (sat != NULL) {
2566
      mcsat_satellite_register_arith_term(sat, x, r);
2567
    }
2568
  }
2569

2570
  return x;
2571
}
2572

2573
#endif
2574

2575
/****************************
2576
 *  CONVERSION TO LITERALS  *
2577
 ***************************/
2578

2579
/*
2580
 * Boolean if-then-else
2581
 */
2582
static literal_t map_ite_to_literal(context_t *ctx, composite_term_t *ite) {
1,863✔
2583
  literal_t l1, l2, l3;
2584

2585
  assert(ite->arity == 3);
2586
  l1 = internalize_to_literal(ctx, ite->arg[0]); // condition
1,863✔
2587
  if (l1 == true_literal) {
1,863✔
2588
    return internalize_to_literal(ctx, ite->arg[1]);
32✔
2589
  }
2590
  if (l1 == false_literal) {
1,831✔
2591
    return internalize_to_literal(ctx, ite->arg[2]);
71✔
2592
  }
2593

2594
  l2 = internalize_to_literal(ctx, ite->arg[1]);
1,760✔
2595
  l3 = internalize_to_literal(ctx, ite->arg[2]);
1,760✔
2596

2597
  return mk_ite_gate(&ctx->gate_manager, l1, l2, l3);
1,760✔
2598
}
2599

2600

2601
/*
2602
 * Generic equality: (eq t1 t2)
2603
 * - t1 and t2 are not arithmetic or bitvector terms
2604
 */
2605
static literal_t map_eq_to_literal(context_t *ctx, composite_term_t *eq) {
14,519✔
2606
  occ_t u, v;
2607
  literal_t l1, l2, l;
2608

2609
  assert(eq->arity == 2);
2610

2611
  if (is_boolean_term(ctx->terms, eq->arg[0])) {
14,519✔
2612
    assert(is_boolean_term(ctx->terms, eq->arg[1]));
2613

2614
    l1 = internalize_to_literal(ctx, eq->arg[0]);
9,058✔
2615
    l2 = internalize_to_literal(ctx, eq->arg[1]);
9,058✔
2616
    l = mk_iff_gate(&ctx->gate_manager, l1, l2);
9,058✔
2617
  } else {
2618
    // filter out high-order terms. It's enough to check eq->arg[0]
2619
    check_high_order_support(ctx, eq->arg, 1);
5,461✔
2620

2621
    u = internalize_to_eterm(ctx, eq->arg[0]);
5,461✔
2622
    v = internalize_to_eterm(ctx, eq->arg[1]);
5,461✔
2623
    l = egraph_make_eq(ctx->egraph, u, v);
5,461✔
2624
  }
2625

2626
  return l;
14,519✔
2627
}
2628

2629

2630
/*
2631
 * (or t1 ... t_n)
2632
 */
2633
static literal_t map_or_to_literal(context_t *ctx, composite_term_t *or) {
81,300✔
2634
  int32_t *a;
2635
  ivector_t *v;
2636
  literal_t l;
2637
  uint32_t i, n;
2638

2639
  if (context_flatten_or_enabled(ctx)) {
81,300✔
2640
    // flatten (or ...): store result in v
2641
    v = &ctx->aux_vector;
13,220✔
2642
    assert(v->size == 0);
2643
    flatten_or_term(ctx, v, or);
13,220✔
2644

2645
    // try easy simplification
2646
    n = v->size;
13,220✔
2647
    if (disjunct_is_true(ctx, v->data, n)) {
13,220✔
2648
      ivector_reset(v);
335✔
2649
      return true_literal;
335✔
2650
    }
2651

2652
    // make a copy of v
2653
    a = alloc_istack_array(&ctx->istack, n);
12,885✔
2654
    for (i=0; i<n; i++) {
70,797✔
2655
      a[i] = v->data[i];
57,912✔
2656
    }
2657
    ivector_reset(v);
12,885✔
2658

2659
    // internalize a[0 ... n-1]
2660
    for (i=0; i<n; i++) {
69,824✔
2661
      l = internalize_to_literal(ctx, a[i]);
57,221✔
2662
      if (l == true_literal) goto done;
57,221✔
2663
      a[i] = l;
56,939✔
2664
    }
2665

2666
  } else {
2667
    // no flattening
2668
    n = or->arity;
68,080✔
2669
    if (disjunct_is_true(ctx, or->arg, n)) {
68,080✔
2670
      return true_literal;
204✔
2671
    }
2672

2673
    a = alloc_istack_array(&ctx->istack, n);
67,876✔
2674
    for (i=0; i<n; i++) {
254,012✔
2675
      l = internalize_to_literal(ctx, or->arg[i]);
186,452✔
2676
      if (l == true_literal) goto done;
186,452✔
2677
      a[i] = l;
186,136✔
2678
    }
2679
  }
2680

2681
  l = mk_or_gate(&ctx->gate_manager, n, a);
80,163✔
2682

2683
 done:
80,761✔
2684
  free_istack_array(&ctx->istack, a);
80,761✔
2685

2686
  return l;
80,761✔
2687
}
2688

2689

2690
/*
2691
 * (xor t1 ... t_n)
2692
 */
2693
static literal_t map_xor_to_literal(context_t *ctx, composite_term_t *xor) {
1✔
2694
  int32_t *a;
2695
  literal_t l;
2696
  uint32_t i, n;
2697

2698
  n = xor->arity;
1✔
2699
  a = alloc_istack_array(&ctx->istack, n);
1✔
2700
  for (i=0; i<n; i++) {
4✔
2701
    a[i] = internalize_to_literal(ctx, xor->arg[i]);
3✔
2702
  }
2703

2704
  l = mk_xor_gate(&ctx->gate_manager, n, a);
1✔
2705
  free_istack_array(&ctx->istack, a);
1✔
2706

2707
  return l;
1✔
2708
}
2709

2710

2711
/*
2712
 * Convert (p t_1 .. t_n) to a literal
2713
 * - create an egraph atom
2714
 */
2715
static literal_t map_apply_to_literal(context_t *ctx, composite_term_t *app) {
4,368✔
2716
  occ_t *a;
2717
  uint32_t i, n;
2718
  literal_t l;
2719

2720
  assert(app->arity > 0);
2721
  n = app->arity;
4,368✔
2722
  a = alloc_istack_array(&ctx->istack, n);
4,368✔
2723
  for (i=0; i<n; i++) {
16,325✔
2724
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
11,957✔
2725
  }
2726

2727
  // a[0] = predicate
2728
  // a[1 ...n-1] = arguments
2729
  l = egraph_make_pred(ctx->egraph, a[0], n-1, a + 1);
4,368✔
2730
  free_istack_array(&ctx->istack, a);
4,368✔
2731

2732
  return l;
4,368✔
2733
}
2734

2735

2736

2737
/*
2738
 * Auxiliary function: translate (distinct a[0 ... n-1]) to a literal,
2739
 * when a[0] ... a[n-1] are arithmetic variables.
2740
 *
2741
 * We expand this into a quadratic number of disequalities.
2742
 */
2743
static literal_t make_arith_distinct(context_t *ctx, uint32_t n, thvar_t *a) {
158✔
2744
  uint32_t i, j;
2745
  ivector_t *v;
2746
  literal_t l;
2747

2748
  assert(n >= 2);
2749

2750
  v = &ctx->aux_vector;
158✔
2751
  assert(v->size == 0);
2752
  for (i=0; i<n-1; i++) {
3,776✔
2753
    for (j=i+1; j<n; j++) {
48,648✔
2754
      l = ctx->arith.create_vareq_atom(ctx->arith_solver, a[i], a[j]);
45,030✔
2755
      ivector_push(v, l);
45,030✔
2756
    }
2757
  }
2758
  l = mk_or_gate(&ctx->gate_manager, v->size, v->data);
158✔
2759
  ivector_reset(v);
158✔
2760

2761
  return not(l);
158✔
2762
}
2763

2764

2765
/*
2766
 * Auxiliary function: translate (distinct a[0 ... n-1]) to a literal,
2767
 * when a[0] ... a[n-1] are bitvector variables.
2768
 *
2769
 * We expand this into a quadratic number of disequalities.
2770
 */
2771
static literal_t make_bv_distinct(context_t *ctx, uint32_t n, thvar_t *a) {
2✔
2772
  uint32_t i, j;
2773
  ivector_t *v;
2774
  literal_t l;
2775

2776
  assert(n >= 2);
2777

2778
  v = &ctx->aux_vector;
2✔
2779
  assert(v->size == 0);
2780
  for (i=0; i<n-1; i++) {
11✔
2781
    for (j=i+1; j<n; j++) {
40✔
2782
      l = ctx->bv.create_eq_atom(ctx->bv_solver, a[i], a[j]);
31✔
2783
      ivector_push(v, l);
31✔
2784
    }
2785
  }
2786
  l = mk_or_gate(&ctx->gate_manager, v->size, v->data);
2✔
2787
  ivector_reset(v);
2✔
2788

2789
  return not(l);
2✔
2790
}
2791

2792

2793
/*
2794
 * Convert (distinct t_1 ... t_n) to a literal
2795
 */
2796
static literal_t map_distinct_to_literal(context_t *ctx, composite_term_t *distinct) {
9✔
2797
  int32_t *a;
2798
  literal_t l;
2799
  uint32_t i, n;
2800

2801
  n = distinct->arity;
9✔
2802
  a = alloc_istack_array(&ctx->istack, n);
9✔
2803
  if (context_has_egraph(ctx)) {
9✔
2804
    // fail if arguments are functions and we don't support high-order terms
2805
    // checking the first argument is enough since they all have the same type
2806
    check_high_order_support(ctx, distinct->arg, 1);
6✔
2807

2808
    // default: translate to the egraph
2809
    for (i=0; i<n; i++) {
25✔
2810
      a[i] = internalize_to_eterm(ctx, distinct->arg[i]);
19✔
2811
    }
2812
    l = egraph_make_distinct(ctx->egraph, n, a);
6✔
2813

2814
  } else if (is_arithmetic_term(ctx->terms, distinct->arg[0])) {
3✔
2815
    // translate to arithmetic variables
2816
    for (i=0; i<n; i++) {
12✔
2817
      a[i] = internalize_to_arith(ctx, distinct->arg[i]);
9✔
2818
    }
2819
    l = make_arith_distinct(ctx, n, a);
3✔
2820

2821
  } else if (is_bitvector_term(ctx->terms, distinct->arg[0])) {
×
2822
    // translate to bitvector variables
2823
    for (i=0; i<n; i++) {
×
2824
      a[i] = internalize_to_bv(ctx, distinct->arg[i]);
×
2825
    }
2826
    l = make_bv_distinct(ctx, n, a);
×
2827

2828
  } else {
2829
    longjmp(ctx->env, uf_error_code(ctx, distinct->arg[0]));
×
2830
  }
2831

2832
  free_istack_array(&ctx->istack, a);
9✔
2833

2834
  return l;
9✔
2835
}
2836

2837

2838

2839
/*
2840
 * Arithmetic atom: p == 0
2841
 */
2842
static literal_t map_poly_eq_to_literal(context_t *ctx, polynomial_t *p) {
1,202✔
2843
  uint32_t i, n;
2844
  thvar_t *a;
2845
  literal_t l;
2846

2847
  n = p->nterms;
1,202✔
2848
  a = alloc_istack_array(&ctx->istack, n);
1,202✔
2849

2850
  // skip the constant if any
2851
  i = 0;
1,202✔
2852
  if (p->mono[0].var == const_idx) {
1,202✔
2853
    a[0] = null_thvar;
580✔
2854
    i ++;
580✔
2855
  }
2856

2857
  // deal with the non-constant monomials
2858
  while (i<n) {
4,186✔
2859
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
2,984✔
2860
    i ++;
2,984✔
2861
  }
2862

2863
  // build the atom
2864
  l = ctx->arith.create_poly_eq_atom(ctx->arith_solver, p, a);
1,202✔
2865
  free_istack_array(&ctx->istack, a);
1,202✔
2866

2867
  return l;
1,202✔
2868
}
2869

2870

2871
/*
2872
 * Arithmetic atom: (p >= 0)
2873
 */
2874
static literal_t map_poly_ge_to_literal(context_t *ctx, polynomial_t *p) {
33,497✔
2875
  uint32_t i, n;
2876
  thvar_t *a;
2877
  literal_t l;
2878

2879
  n = p->nterms;
33,497✔
2880
  a = alloc_istack_array(&ctx->istack, n);
33,497✔
2881

2882
  // skip the constant if any
2883
  i = 0;
33,497✔
2884
  if (p->mono[0].var == const_idx) {
33,497✔
2885
    a[0] = null_thvar;
26,320✔
2886
    i ++;
26,320✔
2887
  }
2888

2889
  // deal with the non-constant monomials
2890
  while (i<n) {
84,656✔
2891
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
51,159✔
2892
    i ++;
51,159✔
2893
  }
2894

2895
  // build the atom
2896
  l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, a);
33,497✔
2897
  free_istack_array(&ctx->istack, a);
33,497✔
2898

2899
  return l;
33,497✔
2900
}
2901

2902

2903
/*
2904
 * Arithmetic atom: (t >= 0)
2905
 */
2906
static literal_t map_arith_geq_to_literal(context_t *ctx, term_t t) {
33,845✔
2907
  term_table_t *terms;
2908
  thvar_t x;
2909
  literal_t l;
2910

2911
  terms = ctx->terms;
33,845✔
2912
  if (term_kind(terms, t) == ARITH_POLY) {
33,845✔
2913
    l = map_poly_ge_to_literal(ctx, poly_term_desc(terms, t));
33,497✔
2914
  } else {
2915
    x = internalize_to_arith(ctx, t);
348✔
2916
    l = ctx->arith.create_ge_atom(ctx->arith_solver, x);
348✔
2917
  }
2918

2919
  return l;
33,845✔
2920
}
2921

2922

2923

2924
/*
2925
 * Arithmetic equalities (eq t1 t2)
2926
 * 1) try to flatten the if-then-elses
2927
 * 2) also apply cheap lift-if rule: (eq (ite c t1 t2) u1) --> (ite c (eq t1 u1) (eq t2 u1))
2928
 */
2929
static literal_t map_arith_bineq(context_t *ctx, term_t t1, term_t u1);
2930

2931
/*
2932
 * Lift equality: (eq (ite c u1 u2) t) --> (ite c (eq u1 t) (eq u2 t))
2933
 */
2934
static literal_t map_ite_arith_bineq(context_t *ctx, composite_term_t *ite, term_t t) {
42,609✔
2935
  literal_t l1, l2, l3;
2936

2937
  assert(ite->arity == 3);
2938
  l1 = internalize_to_literal(ctx, ite->arg[0]);
42,609✔
2939
  if (l1 == true_literal) {
42,609✔
2940
    // (eq (ite true u1 u2) t) --> (eq u1 t)
2941
    return map_arith_bineq(ctx, ite->arg[1], t);
7✔
2942
  }
2943
  if (l1 == false_literal) {
42,602✔
2944
    // (eq (ite true u1 u2) t) --> (eq u2 t)
2945
    return map_arith_bineq(ctx, ite->arg[2], t);
109✔
2946
  }
2947

2948
  // apply lift-if here
2949
  l2 = map_arith_bineq(ctx, ite->arg[1], t);
42,493✔
2950
  l3 = map_arith_bineq(ctx, ite->arg[2], t);
42,493✔
2951

2952
  return mk_ite_gate(&ctx->gate_manager, l1, l2, l3);
42,493✔
2953
}
2954

2955
static literal_t map_arith_bineq_aux(context_t *ctx, term_t t1, term_t t2) {
53,504✔
2956
  term_table_t *terms;
2957
  thvar_t x, y;
2958
  occ_t u, v;
2959
  literal_t l;
2960

2961
  /*
2962
   * Try to apply lift-if rule: (eq (ite c u1 u2) t2) --> (ite c (eq u1 t2) (eq u2 t2))
2963
   * do this only if t2 is not an if-then-else term.
2964
   *
2965
   * Otherwise add the atom (eq t1 t2) to the egraph if possible
2966
   * or create (eq t1 t2) in the arithmetic solver.
2967
   */
2968
  terms = ctx->terms;
53,504✔
2969
  if (is_ite_term(terms, t1) && ! is_ite_term(terms, t2)) {
53,504✔
2970
    l = map_ite_arith_bineq(ctx, ite_term_desc(terms, t1), t2);
38,573✔
2971
  } else if (is_ite_term(terms, t2) && !is_ite_term(terms, t1)) {
14,931✔
2972
    l = map_ite_arith_bineq(ctx, ite_term_desc(terms, t2), t1);
4,036✔
2973
  } else if (context_has_egraph(ctx)) {
10,895✔
2974
    u = internalize_to_eterm(ctx, t1);
3,774✔
2975
    v = internalize_to_eterm(ctx, t2);
3,774✔
2976
    l = egraph_make_eq(ctx->egraph, u, v);
3,774✔
2977
  } else {
2978
    x = internalize_to_arith(ctx, t1);
7,121✔
2979
    y = internalize_to_arith(ctx, t2);
7,121✔
2980
    l = ctx->arith.create_vareq_atom(ctx->arith_solver, x, y);
7,121✔
2981
  }
2982

2983
  return l;
53,504✔
2984
}
2985

2986
static literal_t map_arith_bineq(context_t *ctx, term_t t1, term_t u1) {
95,361✔
2987
  ivector_t *v;
2988
  int32_t *a;
2989
  uint32_t i, n;
2990
  term_t t2, u2;
2991
  literal_t l;
2992

2993
  t1 = intern_tbl_get_root(&ctx->intern, t1);
95,361✔
2994
  u1 = intern_tbl_get_root(&ctx->intern, u1);
95,361✔
2995

2996
  if (t1 == u1) {
95,361✔
2997
    return true_literal;
3,222✔
2998
  }
2999

3000
  /*
3001
   * Check the cache
3002
   */
3003
  l = find_in_eq_cache(ctx, t1, u1);
92,139✔
3004
  if (l == null_literal) {
92,139✔
3005
    /*
3006
     * The pair (t1, u1) is not mapped already.
3007
     * Try to flatten the if-then-else equalities
3008
     */
3009
    v = &ctx->aux_vector;
53,431✔
3010
    assert(v->size == 0);
3011
    t2 = flatten_ite_equality(ctx, v, t1, u1);
53,431✔
3012
    u2 = flatten_ite_equality(ctx, v, u1, t2);
53,431✔
3013

3014
    /*
3015
     * (t1 == u1) is equivalent to (and (t2 == u2) v[0] ... v[n-1])
3016
     * where v[i] = element i of v
3017
     */
3018
    n = v->size;
53,431✔
3019
    if (n == 0) {
53,431✔
3020
      // empty v: return (t2 == u2)
3021
      assert(t1 == t2 && u1 == u2);
3022
      l = map_arith_bineq_aux(ctx, t2, u2);
10,680✔
3023

3024
    } else {
3025
      // build (and (t2 == u2) v[0] ... v[n-1])
3026
      // first make a copy of v into a[0 .. n-1]
3027
      a = alloc_istack_array(&ctx->istack, n+1);
42,751✔
3028
      for (i=0; i<n; i++) {
766,594✔
3029
        a[i] = v->data[i];
723,843✔
3030
      }
3031
      ivector_reset(v);
42,751✔
3032

3033
      // build the internalization of a[0 .. n-1]
3034
      for (i=0; i<n; i++) {
766,594✔
3035
        a[i] = internalize_to_literal(ctx, a[i]);
723,843✔
3036
      }
3037
      a[n] = map_arith_bineq_aux(ctx, t2, u2);
42,751✔
3038

3039
      // build (and a[0] ... a[n])
3040
      l = mk_and_gate(&ctx->gate_manager, n+1, a);
42,751✔
3041
      free_istack_array(&ctx->istack, a);
42,751✔
3042
    }
3043

3044
    /*
3045
     * Store the mapping (t1, u1) --> l in the cache
3046
     */
3047
    add_to_eq_cache(ctx, t1, u1, l);
53,431✔
3048
  }
3049

3050
  return l;
92,139✔
3051
}
3052

3053

3054
static inline literal_t map_arith_bineq_to_literal(context_t *ctx, composite_term_t *eq) {
8,967✔
3055
  assert(eq->arity == 2);
3056
  return map_arith_bineq(ctx, eq->arg[0], eq->arg[1]);
8,967✔
3057
}
3058

3059

3060

3061
/*
3062
 * Arithmetic atom: (t == 0)
3063
 */
3064
static literal_t map_arith_eq_to_literal(context_t *ctx, term_t t) {
2,259✔
3065
  term_table_t *terms;
3066
  thvar_t x;
3067
  literal_t l;
3068

3069
  terms = ctx->terms;
2,259✔
3070
  if (term_kind(terms, t) == ARITH_POLY) {
2,259✔
3071
    l = map_poly_eq_to_literal(ctx, poly_term_desc(terms, t));
1,202✔
3072
  } else if (is_ite_term(terms, t)) {
1,057✔
3073
    l = map_arith_bineq(ctx, t, zero_term);
426✔
3074
  } else {
3075
    x = internalize_to_arith(ctx, t);
631✔
3076
    l = ctx->arith.create_eq_atom(ctx->arith_solver, x);
631✔
3077
  }
3078
  return l;
2,259✔
3079
}
3080

3081

3082
/*
3083
 * DIVIDES AND IS_INT ATOMS
3084
 */
3085

3086
/*
3087
 * We use the rules
3088
 * - (is_int x)    <=> (x <= floor(x))
3089
 * - (divides k x) <=> (x <= k * div(x, k))
3090
 */
3091

3092
// atom (is_int t)
3093
static literal_t map_arith_is_int_to_literal(context_t *ctx, term_t t) {
×
3094
  polynomial_t *p;
3095
  thvar_t map[2];
3096
  thvar_t x, y;
3097
  literal_t l;
3098

3099
  x = internalize_to_arith(ctx, t);
×
3100
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
3101
    l = true_literal;
×
3102
  } else {
3103
    // we convert (is_int x) to (x <= floor(x))
3104
    y = get_floor(ctx, x); // y is floor x
×
3105
    p = context_get_aux_poly(ctx, 3);
×
3106
    context_store_diff_poly(p, map, y, x); // (p, map) := (y - x)
×
3107
    // atom (x <= y) is the same as (p >= 0)
3108
    l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, map);
×
3109
  }
3110

3111
  return l;
×
3112
}
3113

3114
// atom (divides k t)  we assume k != 0 and constant
3115
static literal_t map_arith_divides_const_to_literal(context_t *ctx, term_t d, term_t t) {
8✔
3116
  rational_t k;
3117
  polynomial_t *p;
3118
  thvar_t map[2];
3119
  thvar_t x, y;
3120
  literal_t l;
3121

3122
  assert(term_kind(ctx->terms, d) == ARITH_CONSTANT);
3123

3124
  // make a copy of the divider in k
3125
  q_init(&k);
8✔
3126
  q_set(&k, rational_term_desc(ctx->terms, d));
8✔
3127
  assert(q_is_nonzero(&k));
3128

3129
  x = internalize_to_arith(ctx, t); // this is t
8✔
3130
  y = get_div(ctx, x, &k);  // y := (div x k)
8✔
3131
  p = context_get_aux_poly(ctx, 3);
8✔
3132
  context_store_divides_constraint(p, map, x, y, &k); // p is (- x + k * y)
8✔
3133
  // atom (x <= k * y) is (p >= 0)
3134
  l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, map);
8✔
3135

3136
  q_clear(&k);
8✔
3137

3138
  return l;
8✔
3139
}
3140

3141
// atom (divides k t)  we assume k != 0
3142
static literal_t map_arith_divides_to_literal(context_t *ctx, composite_term_t *divides) {
8✔
3143
  term_t d;
3144

3145
  assert(divides->arity == 2);
3146

3147
  d = divides->arg[0];
8✔
3148
  if (term_kind(ctx->terms, d) == ARITH_CONSTANT) {
8✔
3149
    return map_arith_divides_const_to_literal(ctx, d, divides->arg[1]);
8✔
3150
  } else {
3151
    // k is not a constant: not supported
3152
    longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
3153
  }
3154
}
3155

3156

3157
/*
3158
 * BITVECTOR ATOMS
3159
 */
3160

3161
/*
3162
 * Auxiliary function: atom for (t == 0)
3163
 */
3164
static literal_t map_bveq0_to_literal(context_t *ctx, term_t t) {
10✔
3165
  uint32_t n;
3166
  thvar_t x, y;
3167

3168
  t = intern_tbl_get_root(&ctx->intern, t);
10✔
3169
  n = term_bitsize(ctx->terms, t);
10✔
3170
  x = internalize_to_bv(ctx, t);
10✔
3171
  y = ctx->bv.create_zero(ctx->bv_solver, n);
10✔
3172

3173
  return ctx->bv.create_eq_atom(ctx->bv_solver, x, y);
10✔
3174
}
3175

3176
static literal_t map_bveq_to_literal(context_t *ctx, composite_term_t *eq) {
4,864✔
3177
  bveq_simp_t simp;
3178
  term_t t, t1, t2;
3179
  thvar_t x, y;
3180

3181
  assert(eq->arity == 2);
3182

3183
  /*
3184
   * Apply substitution then check for simplifications
3185
   */
3186
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
4,864✔
3187
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
4,864✔
3188
  t = simplify_bitvector_eq(ctx, t1, t2);
4,864✔
3189
  if (t != NULL_TERM) {
4,864✔
3190
    // (bveq t1 t2) is equivalent to t
3191
    return internalize_to_literal(ctx, t);
77✔
3192
  }
3193

3194
  /*
3195
   * More simplifications
3196
   */
3197
  try_arithmetic_bveq_simplification(ctx, &simp, t1, t2);
4,787✔
3198
  switch (simp.code) {
4,787✔
3199
  case BVEQ_CODE_TRUE:
×
3200
    return true_literal;
×
3201

3202
  case BVEQ_CODE_FALSE:
×
3203
    return false_literal;
×
3204

3205
  case BVEQ_CODE_REDUCED:
11✔
3206
    t1 = intern_tbl_get_root(&ctx->intern, simp.left);
11✔
3207
    t2 = intern_tbl_get_root(&ctx->intern, simp.right);
11✔
3208
    break;
11✔
3209

3210
  case BVEQ_CODE_REDUCED0:
10✔
3211
    // (t1 == t2) is reduced to (simp.left == 0)
3212
    // we create the atom directly here:
3213
    return map_bveq0_to_literal(ctx, simp.left);
10✔
3214

3215
  default:
4,766✔
3216
    break;
4,766✔
3217
  }
3218

3219
  if (equal_bitvector_factors(ctx, t1, t2)) {
4,777✔
3220
    return true_literal;
×
3221
  }
3222

3223
  /*
3224
   * NOTE: creating (eq t1 t2) in the egraph instead makes things worse
3225
   */
3226
  x = internalize_to_bv(ctx, t1);
4,777✔
3227
  y = internalize_to_bv(ctx, t2);
4,777✔
3228
  return ctx->bv.create_eq_atom(ctx->bv_solver, x, y);
4,777✔
3229
}
3230

3231
static literal_t map_bvge_to_literal(context_t *ctx, composite_term_t *ge) {
2,302✔
3232
  thvar_t x, y;
3233

3234
  assert(ge->arity == 2);
3235
  x = internalize_to_bv(ctx, ge->arg[0]);
2,302✔
3236
  y = internalize_to_bv(ctx, ge->arg[1]);
2,302✔
3237

3238
  return ctx->bv.create_ge_atom(ctx->bv_solver, x, y);
2,302✔
3239
}
3240

3241
static literal_t map_bvsge_to_literal(context_t *ctx, composite_term_t *sge) {
2,907✔
3242
  thvar_t x, y;
3243

3244
  assert(sge->arity == 2);
3245
  x = internalize_to_bv(ctx, sge->arg[0]);
2,907✔
3246
  y = internalize_to_bv(ctx, sge->arg[1]);
2,907✔
3247

3248
  return ctx->bv.create_sge_atom(ctx->bv_solver, x, y);
2,907✔
3249
}
3250

3251

3252
// Select bit
3253
static literal_t map_bit_select_to_literal(context_t *ctx, select_term_t *select) {
264,228✔
3254
  term_t t, s;
3255
  thvar_t x;
3256

3257
  /*
3258
   * Apply substitution then try to simplify
3259
   */
3260
  t = intern_tbl_get_root(&ctx->intern, select->arg);
264,228✔
3261
  s = extract_bit(ctx->terms, t, select->idx);
264,228✔
3262
  if (s != NULL_TERM) {
264,228✔
3263
    // (select t i) is s
3264
    return internalize_to_literal(ctx, s);
25,181✔
3265
  } else {
3266
    // no simplification
3267
    x = internalize_to_bv(ctx, t);
239,047✔
3268
    return ctx->bv.select_bit(ctx->bv_solver, x, select->idx);
239,047✔
3269
  }
3270
}
3271

3272

3273
/****************************************
3274
 *  INTERNALIZATION TO ETERM: TOPLEVEL  *
3275
 ***************************************/
3276

3277
static occ_t internalize_to_eterm(context_t *ctx, term_t t) {
103,355✔
3278
  term_table_t *terms;
3279
  term_t root;
3280
  term_t r;
3281
  uint32_t polarity;
3282
  int32_t code;
3283
  int32_t exception;
3284
  type_t tau;
3285
  occ_t u;
3286
  literal_t l;
3287
  thvar_t x;
3288

3289
  if (! context_has_egraph(ctx)) {
103,355✔
3290
    exception = uf_error_code(ctx, t);
×
3291
    goto abort;
×
3292
  }
3293

3294
  root = intern_tbl_get_root(&ctx->intern, t);
103,355✔
3295
  polarity = polarity_of(root);
103,355✔
3296
  root = unsigned_term(root);
103,355✔
3297
  r = root;
103,355✔
3298

3299
  /*
3300
   * r is a positive root in the internalization table
3301
   * polarity is 0 or 1
3302
   * if polarity is 0, then t is equal to r by substitution
3303
   * if polarity is 1, then t is equal to (not r)
3304
   */
3305
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
103,355✔
3306
    /*
3307
     * r already internalized
3308
     */
3309
    code = intern_tbl_map_of_root(&ctx->intern, r);
64,981✔
3310
    u = translate_code_to_eterm(ctx, r, code);
64,981✔
3311
  } else {
3312
    /*
3313
     * Compute r's internalization:
3314
     * - if it's a boolean term, convert r to a literal l then
3315
     *   remap l to an egraph term
3316
     * - otherwise, recursively construct an egraph term and map it to r
3317
     */
3318
    terms = ctx->terms;
38,374✔
3319
    tau = type_of_root(ctx, r);
38,374✔
3320
    if (is_unit_type(ctx->types, tau)) {
38,374✔
3321
      // Canonicalize singleton types to one representative term.
3322
      r = get_unit_type_rep(terms, tau);
7✔
3323
      r = intern_tbl_get_root(&ctx->intern, r);
7✔
3324
      r = unsigned_term(r);
7✔
3325
      assert(is_pos_term(r) && intern_tbl_is_root(&ctx->intern, r));
3326
      if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
7✔
3327
        code = intern_tbl_map_of_root(&ctx->intern, r);
1✔
3328
        u = translate_code_to_eterm(ctx, r, code);
1✔
3329
        if (root != r) {
1✔
3330
          if (intern_tbl_root_is_free(&ctx->intern, root)) {
1✔
3331
            intern_tbl_map_root(&ctx->intern, root, occ2code(u));
1✔
3332
          } else {
3333
            // If root is already mapped, it must map to the same egraph
3334
            // occurrence we are about to return for the unit-type rep.
3335
            assert(intern_tbl_map_of_root(&ctx->intern, root) == occ2code(u));  // LCOV_EXCL_LINE - consistency check, unreachable on well-formed inputs
3336
          }
3337
        }
3338
        return u ^ polarity;
1✔
3339
      }
3340
    }
3341

3342
    if (is_boolean_type(tau)) {
38,373✔
3343
      l = internalize_to_literal(ctx, r);
38✔
3344
      u = egraph_literal2occ(ctx->egraph, l);
38✔
3345
      intern_tbl_remap_root(&ctx->intern, r, occ2code(u));
38✔
3346
    } else {
3347
      /*
3348
       * r is not a boolean term
3349
       */
3350
      assert(polarity == 0);
3351

3352
      switch (term_kind(terms, r)) {
38,335✔
3353
      case CONSTANT_TERM:
1,164✔
3354
        u = pos_occ(make_egraph_constant(ctx, tau, constant_term_index(terms, r)));
1,164✔
3355
        break;
1,164✔
3356

3357
      case ARITH_CONSTANT:
339✔
3358
        u = map_arith_constant_to_eterm(ctx, rational_term_desc(terms, r));
339✔
3359
        break;
339✔
3360

3361
      case BV64_CONSTANT:
808✔
3362
        u = map_bvconst64_to_eterm(ctx, bvconst64_term_desc(terms, r));
808✔
3363
        break;
808✔
3364

3365
      case BV_CONSTANT:
18✔
3366
        u = map_bvconst_to_eterm(ctx, bvconst_term_desc(terms, r));
18✔
3367
        break;
18✔
3368

3369
      case VARIABLE:
×
3370
        exception = FREE_VARIABLE_IN_FORMULA;
×
3371
        goto abort;
×
3372

3373
      case UNINTERPRETED_TERM:
12,051✔
3374
        u = pos_occ(make_egraph_variable(ctx, tau));
12,051✔
3375
        //        add_type_constraints(ctx, u, tau);
3376
        break;
12,051✔
3377

3378
      case ARITH_FLOOR:
×
3379
        assert(is_integer_type(tau));
3380
        x = map_floor_to_arith(ctx, arith_floor_arg(terms, r));
×
3381
        u = translate_arithvar_to_eterm(ctx, x);
×
3382
        break;
×
3383

3384
      case ARITH_CEIL:
×
3385
        assert(is_integer_type(tau));
3386
        x = map_ceil_to_arith(ctx, arith_ceil_arg(terms, r));
×
3387
        u = translate_arithvar_to_eterm(ctx, x);
×
3388
        break;
×
3389

3390
      case ARITH_ABS:
×
3391
        x = map_abs_to_arith(ctx, arith_abs_arg(terms, r));
×
3392
        u = translate_arithvar_to_eterm(ctx, x);
×
3393
        break;
×
3394

3395
      case ITE_TERM:
2,168✔
3396
      case ITE_SPECIAL:
3397
        u = map_ite_to_eterm(ctx, ite_term_desc(terms, r), tau);
2,168✔
3398
        break;
2,168✔
3399

3400
      case APP_TERM:
6,531✔
3401
        u = map_apply_to_eterm(ctx, app_term_desc(terms, r), tau);
6,531✔
3402
        break;
6,531✔
3403

3404
      case ARITH_RDIV:
×
3405
        assert(is_arithmetic_type(tau));
3406
        x = map_rdiv_to_arith(ctx, arith_rdiv_term_desc(terms, r));
×
3407
        u = translate_arithvar_to_eterm(ctx, x);
×
3408
        break;
×
3409

3410
      case ARITH_IDIV:
×
3411
        assert(is_integer_type(tau));
3412
        x = map_idiv_to_arith(ctx, arith_idiv_term_desc(terms, r));
×
3413
        u = translate_arithvar_to_eterm(ctx, x); // (div t u) has type int
×
3414
        break;
×
3415

3416
      case ARITH_MOD:
2✔
3417
        x = map_mod_to_arith(ctx, arith_mod_term_desc(terms, r));
2✔
3418
        u = translate_arithvar_to_eterm(ctx, x);
2✔
3419
        break;
2✔
3420

3421
      case TUPLE_TERM:
190✔
3422
        u = map_tuple_to_eterm(ctx, tuple_term_desc(terms, r), tau);
190✔
3423
        break;
190✔
3424

3425
      case SELECT_TERM:
245✔
3426
        u = map_select_to_eterm(ctx, select_term_desc(terms, r), tau);
245✔
3427
        break;
245✔
3428

3429
      case UPDATE_TERM:
11,470✔
3430
        u = map_update_to_eterm(ctx, update_term_desc(terms, r), tau);
11,470✔
3431
        break;
11,470✔
3432

3433
      case LAMBDA_TERM:
1✔
3434
        // not ready for lambda terms yet:
3435
        exception = LAMBDAS_NOT_SUPPORTED;
1✔
3436
        goto abort;
1✔
3437

3438
      case BV_ARRAY:
1,711✔
3439
        x = map_bvarray_to_bv(ctx, bvarray_term_desc(terms, r));
1,711✔
3440
        u = translate_thvar_to_eterm(ctx, x, tau);
1,711✔
3441
        break;
1,711✔
3442

3443
      case BV_DIV:
1✔
3444
        x = map_bvdiv_to_bv(ctx, bvdiv_term_desc(terms, r));
1✔
3445
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3446
        break;
1✔
3447

3448
      case BV_REM:
2✔
3449
        x = map_bvrem_to_bv(ctx, bvrem_term_desc(terms, r));
2✔
3450
        u = translate_thvar_to_eterm(ctx, x, tau);
2✔
3451
        break;
2✔
3452

3453
      case BV_SDIV:
1✔
3454
        x = map_bvsdiv_to_bv(ctx, bvsdiv_term_desc(terms, r));
1✔
3455
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3456
        break;
1✔
3457

3458
      case BV_SREM:
1✔
3459
        x = map_bvsrem_to_bv(ctx, bvsrem_term_desc(terms, r));
1✔
3460
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3461
        break;
1✔
3462

3463
      case BV_SMOD:
×
3464
        x = map_bvsmod_to_bv(ctx, bvsmod_term_desc(terms, r));
×
3465
        u = translate_thvar_to_eterm(ctx, x, tau);
×
3466
        break;
×
3467

3468
      case BV_SHL:
×
3469
        x = map_bvshl_to_bv(ctx, bvshl_term_desc(terms, r));
×
3470
        u = translate_thvar_to_eterm(ctx, x, tau);
×
3471
        break;
×
3472

3473
      case BV_LSHR:
1✔
3474
        x = map_bvlshr_to_bv(ctx, bvlshr_term_desc(terms, r));
1✔
3475
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3476
        break;
1✔
3477

3478
      case BV_ASHR:
1✔
3479
        x = map_bvashr_to_bv(ctx, bvashr_term_desc(terms, r));
1✔
3480
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3481
        break;
1✔
3482

3483
      case POWER_PRODUCT:
1✔
3484
        if (is_arithmetic_type(tau)) {
1✔
3485
          x = map_pprod_to_arith(ctx, pprod_term_desc(terms, r));
×
3486
        } else {
3487
          assert(is_bv_type(ctx->types, tau));
3488
          x = map_pprod_to_bv(ctx, pprod_term_desc(terms, r));
1✔
3489
        }
3490
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3491
        break;
1✔
3492

3493
      case ARITH_POLY:
619✔
3494
        x = map_poly_to_arith(ctx, poly_term_desc(terms, r));
619✔
3495
        u = translate_thvar_to_eterm(ctx, x, tau);
619✔
3496
        break;
619✔
3497

3498
      case BV64_POLY:
1,008✔
3499
        x = map_bvpoly64_to_bv(ctx, bvpoly64_term_desc(terms, r));
1,008✔
3500
        u = translate_thvar_to_eterm(ctx, x, tau);
1,008✔
3501
        break;
1,008✔
3502

3503
      case BV_POLY:
2✔
3504
        x = map_bvpoly_to_bv(ctx, bvpoly_term_desc(terms, r));
2✔
3505
        u = translate_thvar_to_eterm(ctx, x, tau);
2✔
3506
        break;
2✔
3507

3508
      default:
×
3509
        exception = INTERNAL_ERROR;
×
3510
        goto abort;
×
3511
      }
3512

3513
      // store the mapping r --> u
3514
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
38,334✔
3515
    }
3516
  }
3517

3518
  // If we canonicalized root to a different unit-type representative r,
3519
  // remember that root internalizes to the same egraph occurrence.
3520
  if (root != r) {
103,353✔
3521
    if (intern_tbl_root_is_free(&ctx->intern, root)) {
1✔
3522
      intern_tbl_map_root(&ctx->intern, root, occ2code(u));
1✔
3523
    } else {
3524
      // If root was mapped during the recursive internalization of r (e.g.,
3525
      // because root was reached as a sub-term), the mapping must agree
3526
      // with the occurrence we are about to return.
3527
      assert(intern_tbl_map_of_root(&ctx->intern, root) == occ2code(u));  // LCOV_EXCL_LINE - consistency check, unreachable on well-formed inputs
3528
    }
3529
  }
3530

3531
  // fix the polarity
3532
  return u ^ polarity;
103,353✔
3533

3534
 abort:
1✔
3535
  longjmp(ctx->env, exception);
1✔
3536
}
3537

3538

3539

3540

3541
/****************************************
3542
 *  CONVERSION TO ARITHMETIC VARIABLES  *
3543
 ***************************************/
3544

3545
/*
3546
 * Translate internalization code x to an arithmetic variable
3547
 * - if the code is for an egraph term u, then we return the
3548
 *   theory variable attached to u in the egraph.
3549
 * - otherwise, x must be the code of an arithmetic variable v,
3550
 *   we return v.
3551
 */
3552
static thvar_t translate_code_to_arith(context_t *ctx, int32_t x) {
99,882✔
3553
  eterm_t u;
3554
  thvar_t v;
3555

3556
  assert(code_is_valid(x));
3557

3558
  if (code_is_eterm(x)) {
99,882✔
3559
    u = code2eterm(x);
6,521✔
3560
    assert(ctx->egraph != NULL && egraph_term_is_arith(ctx->egraph, u));
3561
    v = egraph_term_base_thvar(ctx->egraph, u);
6,521✔
3562
  } else {
3563
    v = code2thvar(x);
93,361✔
3564
  }
3565

3566
  assert(v != null_thvar);
3567
  return v;
99,882✔
3568
}
3569

3570

3571
static thvar_t internalize_to_arith(context_t *ctx, term_t t) {
120,805✔
3572
  term_table_t *terms;
3573
  int32_t exception;
3574
  int32_t code;
3575
  term_t r;
3576
  occ_t u;
3577
  thvar_t x;
3578

3579
  assert(is_arithmetic_term(ctx->terms, t));
3580

3581
  if (! context_has_arith_solver(ctx)) {
120,805✔
3582
    exception = ARITH_NOT_SUPPORTED;
×
3583
    goto abort;
×
3584
  }
3585

3586
  /*
3587
   * Apply term substitution: t --> r
3588
   */
3589
  r = intern_tbl_get_root(&ctx->intern, t);
120,805✔
3590
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
120,805✔
3591
    /*
3592
     * r already internalized
3593
     */
3594
    code = intern_tbl_map_of_root(&ctx->intern, r);
99,723✔
3595
    x = translate_code_to_arith(ctx, code);
99,723✔
3596

3597
  } else {
3598
    /*
3599
     * Compute the internalization
3600
     */
3601
    terms = ctx->terms;
21,082✔
3602

3603
    switch (term_kind(terms, r)) {
21,082✔
3604
    case ARITH_CONSTANT:
1,270✔
3605
      x = ctx->arith.create_const(ctx->arith_solver, rational_term_desc(terms, r));
1,270✔
3606
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
1,270✔
3607
      break;
1,270✔
3608

3609
    case UNINTERPRETED_TERM:
15,387✔
3610
      x = ctx->arith.create_var(ctx->arith_solver, is_integer_root(ctx, r));
15,387✔
3611
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
15,387✔
3612
      //      printf("mapping: %s --> i!%d\n", term_name(ctx->terms, r), (int) x);
3613
      //      fflush(stdout);
3614
      break;
15,387✔
3615

3616
    case ARITH_FLOOR:
×
3617
      x = map_floor_to_arith(ctx, arith_floor_arg(terms, r));
×
3618
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3619
      break;
×
3620

3621
    case ARITH_CEIL:
×
3622
      x = map_ceil_to_arith(ctx, arith_ceil_arg(terms, r));
×
3623
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3624
      break;
×
3625

3626
    case ARITH_ABS:
4✔
3627
      x = map_abs_to_arith(ctx, arith_abs_arg(terms, r));
4✔
3628
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
4✔
3629
      break;
4✔
3630

3631
    case ITE_TERM:
2,230✔
3632
      x = map_ite_to_arith(ctx, ite_term_desc(terms, r), is_integer_root(ctx, r));
2,230✔
3633
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
2,230✔
3634
      break;
2,230✔
3635

3636
    case ITE_SPECIAL:
793✔
3637
      x = map_ite_to_arith(ctx, ite_term_desc(terms, r), is_integer_root(ctx, r));
793✔
3638
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
793✔
3639
      if (context_ite_bounds_enabled(ctx)) {
793✔
3640
        assert_ite_bounds(ctx, r, x);
793✔
3641
      }
3642
      break;
793✔
3643

3644
    case APP_TERM:
702✔
3645
      u = map_apply_to_eterm(ctx, app_term_desc(terms, r), type_of_root(ctx, r));
702✔
3646
      assert(egraph_term_is_arith(ctx->egraph, term_of_occ(u)));
3647
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
702✔
3648
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
702✔
3649
      assert(x != null_thvar);
3650
      break;
702✔
3651

3652
    case ARITH_RDIV:
3✔
3653
      x = map_rdiv_to_arith(ctx, arith_rdiv_term_desc(terms, r));
3✔
3654
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3655
      break;
×
3656

3657
    case ARITH_IDIV:
6✔
3658
      x = map_idiv_to_arith(ctx, arith_idiv_term_desc(terms, r));
6✔
3659
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
6✔
3660
      break;
6✔
3661

3662
    case ARITH_MOD:
9✔
3663
      x = map_mod_to_arith(ctx, arith_mod_term_desc(terms, r));
9✔
3664
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
9✔
3665
      break;
9✔
3666

3667
    case SELECT_TERM:
×
3668
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), type_of_root(ctx, r));
×
3669
      assert(egraph_term_is_arith(ctx->egraph, term_of_occ(u)));
3670
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3671
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
×
3672
      assert(x != null_thvar);
3673
      break;
×
3674

3675
    case POWER_PRODUCT:
×
3676
      x = map_pprod_to_arith(ctx, pprod_term_desc(terms, r));
×
3677
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3678
      break;
×
3679

3680
    case ARITH_POLY:
678✔
3681
      x = map_poly_to_arith(ctx, poly_term_desc(terms, r));
678✔
3682
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
678✔
3683
      break;
678✔
3684

3685
    case VARIABLE:
×
3686
      exception = FREE_VARIABLE_IN_FORMULA;
×
3687
      goto abort;
×
3688

3689
    default:
×
3690
      exception = INTERNAL_ERROR;
×
3691
      goto abort;
×
3692
    }
3693

3694
  }
3695

3696
  if (ctx->mcsat_supplement && ctx->egraph != NULL &&
120,802✔
3697
      !context_is_mcsat_relax_abstraction(ctx, unsigned_term(r))) {
19✔
3698
    egraph_arith_observer_register_arith_term(ctx->egraph, x, unsigned_term(r));
5✔
3699
  }
3700

3701
  return x;
120,802✔
3702

3703
 abort:
×
3704
  longjmp(ctx->env, exception);
×
3705
}
3706

3707

3708

3709
/***************************************
3710
 *  CONVERSION TO BITVECTOR VARIABLES  *
3711
 **************************************/
3712

3713
/*
3714
 * Translate internalization code x to a bitvector variable
3715
 * - if x is for an egraph term u, then we return the theory variable
3716
 *   attached to u in the egraph.
3717
 * - otherwise, x must be the code of a bitvector variable v, so we return v.
3718
 */
3719
static thvar_t translate_code_to_bv(context_t *ctx, int32_t x) {
299,215✔
3720
  eterm_t u;
3721
  thvar_t v;
3722

3723
  assert(code_is_valid(x));
3724

3725
  if (code_is_eterm(x)) {
299,215✔
3726
    u = code2eterm(x);
29,164✔
3727
    assert(ctx->egraph != NULL && egraph_term_is_bv(ctx->egraph, u));
3728
    v = egraph_term_base_thvar(ctx->egraph, u);
29,164✔
3729
  } else {
3730
    v = code2thvar(x);
270,051✔
3731
  }
3732

3733
  assert(v != null_thvar);
3734

3735
  return v;
299,215✔
3736
}
3737

3738
/*
3739
 * Place holders for now
3740
 */
3741
static thvar_t internalize_to_bv(context_t *ctx, term_t t) {
376,316✔
3742
  term_table_t *terms;
3743
  int32_t exception;
3744
  int32_t code;
3745
  term_t r;
3746
  occ_t u;
3747
  thvar_t x;
3748

3749
  assert(is_bitvector_term(ctx->terms, t));
3750

3751
  if (! context_has_bv_solver(ctx)) {
376,316✔
3752
    exception = BV_NOT_SUPPORTED;
×
3753
    goto abort;
×
3754
  }
3755

3756
  /*
3757
   * Apply the term substitution: t --> r
3758
   */
3759
  r = intern_tbl_get_root(&ctx->intern, t);
376,316✔
3760
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
376,316✔
3761
    // r is already internalized
3762
    code = intern_tbl_map_of_root(&ctx->intern, r);
299,215✔
3763
    x = translate_code_to_bv(ctx, code);
299,215✔
3764
  } else {
3765
    // compute r's internalization
3766
    terms = ctx->terms;
77,101✔
3767

3768
    switch (term_kind(terms, r)) {
77,101✔
3769
    case BV64_CONSTANT:
7,018✔
3770
      x = ctx->bv.create_const64(ctx->bv_solver, bvconst64_term_desc(terms, r));
7,018✔
3771
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
7,018✔
3772
      break;
7,018✔
3773

3774
    case BV_CONSTANT:
440✔
3775
      x = ctx->bv.create_const(ctx->bv_solver, bvconst_term_desc(terms, r));
440✔
3776
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
440✔
3777
      break;
440✔
3778

3779
    case UNINTERPRETED_TERM:
16,440✔
3780
      x = ctx->bv.create_var(ctx->bv_solver, term_bitsize(terms, r));
16,440✔
3781
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
16,440✔
3782
      break;
16,440✔
3783

3784
    case ITE_TERM:
20,779✔
3785
    case ITE_SPECIAL:
3786
      x = map_ite_to_bv(ctx, ite_term_desc(terms, r));
20,779✔
3787
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
20,779✔
3788
      break;
20,779✔
3789

3790
    case APP_TERM:
2,452✔
3791
      u = map_apply_to_eterm(ctx, app_term_desc(terms, r), type_of_root(ctx, r));
2,452✔
3792
      assert(egraph_term_is_bv(ctx->egraph, term_of_occ(u)));
3793
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
2,452✔
3794
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
2,452✔
3795
      assert(x != null_thvar);
3796
      break;
2,452✔
3797

3798
    case BV_ARRAY:
15,326✔
3799
      x = map_bvarray_to_bv(ctx, bvarray_term_desc(terms, r));
15,326✔
3800
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
15,326✔
3801
      break;
15,326✔
3802

3803
    case BV_DIV:
96✔
3804
      x = map_bvdiv_to_bv(ctx, bvdiv_term_desc(terms, r));
96✔
3805
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
96✔
3806
      break;
96✔
3807

3808
    case BV_REM:
175✔
3809
      x = map_bvrem_to_bv(ctx, bvrem_term_desc(terms, r));
175✔
3810
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
175✔
3811
      break;
175✔
3812

3813
    case BV_SDIV:
86✔
3814
      x = map_bvsdiv_to_bv(ctx, bvsdiv_term_desc(terms, r));
86✔
3815
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
86✔
3816
      break;
86✔
3817

3818
    case BV_SREM:
76✔
3819
      x = map_bvsrem_to_bv(ctx, bvsrem_term_desc(terms, r));
76✔
3820
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
76✔
3821
      break;
76✔
3822

3823
    case BV_SMOD:
×
3824
      x = map_bvsmod_to_bv(ctx, bvsmod_term_desc(terms, r));
×
3825
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3826
      break;
×
3827

3828
    case BV_SHL:
85✔
3829
      x = map_bvshl_to_bv(ctx, bvshl_term_desc(terms, r));
85✔
3830
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
85✔
3831
      break;
85✔
3832

3833
    case BV_LSHR:
1,427✔
3834
      x = map_bvlshr_to_bv(ctx, bvlshr_term_desc(terms, r));
1,427✔
3835
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
1,427✔
3836
      break;
1,427✔
3837

3838
    case BV_ASHR:
295✔
3839
      x = map_bvashr_to_bv(ctx, bvashr_term_desc(terms, r));
295✔
3840
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
295✔
3841
      break;
295✔
3842

3843
    case SELECT_TERM:
×
3844
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), type_of_root(ctx, r));
×
3845
      assert(egraph_term_is_bv(ctx->egraph, term_of_occ(u)));
3846
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3847
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
×
3848
      assert(x != null_thvar);
3849
      break;
×
3850

3851
    case POWER_PRODUCT:
584✔
3852
      x = map_pprod_to_bv(ctx, pprod_term_desc(terms, r));
584✔
3853
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
584✔
3854
      break;
584✔
3855

3856
    case BV64_POLY:
11,217✔
3857
      x = map_bvpoly64_to_bv(ctx, bvpoly64_term_desc(terms, r));
11,217✔
3858
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
11,217✔
3859
      break;
11,217✔
3860

3861
    case BV_POLY:
605✔
3862
      x = map_bvpoly_to_bv(ctx, bvpoly_term_desc(terms, r));
605✔
3863
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
605✔
3864
      break;
605✔
3865

3866
    case VARIABLE:
×
3867
      exception = FREE_VARIABLE_IN_FORMULA;
×
3868
      goto abort;
×
3869

3870
    default:
×
3871
      exception = INTERNAL_ERROR;
×
3872
      goto abort;
×
3873
    }
3874
  }
3875

3876
  return x;
376,316✔
3877

3878
 abort:
×
3879
  longjmp(ctx->env, exception);
×
3880
}
3881

3882

3883

3884

3885

3886

3887
/****************************
3888
 *  CONVERSION TO LITERALS  *
3889
 ***************************/
3890

3891
/*
3892
 * Translate an internalization code x to a literal
3893
 * - if x is the code of an egraph occurrence u, we return the
3894
 *   theory variable for u in the egraph
3895
 * - otherwise, x should be the code of a literal l in the core
3896
 */
3897
static literal_t translate_code_to_literal(context_t *ctx, int32_t x) {
1,397,361✔
3898
  occ_t u;
3899
  literal_t l;
3900

3901
  assert(code_is_valid(x));
3902
  if (code_is_eterm(x)) {
1,397,361✔
3903
    u = code2occ(x);
129,809✔
3904
    if (term_of_occ(u) == true_eterm) {
129,809✔
3905
      l = mk_lit(const_bvar, polarity_of(u));
129,809✔
3906

3907
      assert((u == true_occ && l == true_literal) ||
3908
             (u == false_occ && l == false_literal));
3909
    } else {
3910
      assert(ctx->egraph != NULL);
3911
      l = egraph_occ2literal(ctx->egraph, u);
×
3912
    }
3913
  } else {
3914
    l = code2literal(x);
1,267,552✔
3915
  }
3916

3917
  return l;
1,397,361✔
3918
}
3919

3920
static literal_t internalize_to_literal(context_t *ctx, term_t t) {
1,825,200✔
3921
  term_table_t *terms;
3922
  int32_t code;
3923
  uint32_t polarity;
3924
  term_t r;
3925
  literal_t l;
3926
  occ_t u;
3927

3928
  assert(is_boolean_term(ctx->terms, t));
3929

3930
  r = intern_tbl_get_root(&ctx->intern, t);
1,825,200✔
3931
  polarity = polarity_of(r);
1,825,200✔
3932
  r = unsigned_term(r);
1,825,200✔
3933

3934
  /*
3935
   * At this point:
3936
   * 1) r is a positive root in the internalization table
3937
   * 2) polarity is 1 or 0
3938
   * 3) if polarity is 0, then t is equal to r by substitution
3939
   *    if polarity is 1, then t is equal to (not r)
3940
   *
3941
   * We get l := internalization of r
3942
   * then return l or (not l) depending on polarity.
3943
   */
3944

3945
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
1,825,200✔
3946
    /*
3947
     * r already internalized
3948
     */
3949
    code = intern_tbl_map_of_root(&ctx->intern, r);
1,397,361✔
3950
    l = translate_code_to_literal(ctx, code);
1,397,361✔
3951

3952
  } else {
3953
    /*
3954
     * Recursively compute r's internalization
3955
     */
3956
    if (context_atom_requires_mcsat(ctx, r)) {
427,839✔
3957
      l = map_mcsat_atom_to_literal(ctx, r);
3✔
3958
      intern_tbl_map_root(&ctx->intern, r, literal2code(l));
3✔
3959
      goto done;
3✔
3960
    }
3961

3962
    terms = ctx->terms;
427,836✔
3963
    switch (term_kind(terms, r)) {
427,836✔
3964
    case CONSTANT_TERM:
×
3965
      assert(r == true_term);
3966
      l = true_literal;
×
3967
      break;
×
3968

3969
    case VARIABLE:
×
3970
      longjmp(ctx->env, FREE_VARIABLE_IN_FORMULA);
×
3971
      break;
3972

3973
    case UNINTERPRETED_TERM:
6,410✔
3974
      l = pos_lit(create_boolean_variable(ctx->core));
6,410✔
3975
      break;
6,410✔
3976

3977
    case ITE_TERM:
1,863✔
3978
    case ITE_SPECIAL:
3979
      l = map_ite_to_literal(ctx, ite_term_desc(terms, r));
1,863✔
3980
      break;
1,863✔
3981

3982
    case EQ_TERM:
14,519✔
3983
      l = map_eq_to_literal(ctx, eq_term_desc(terms, r));
14,519✔
3984
      break;
14,519✔
3985

3986
    case OR_TERM:
81,300✔
3987
      l = map_or_to_literal(ctx, or_term_desc(terms, r));
81,300✔
3988
      break;
81,300✔
3989

3990
    case XOR_TERM:
1✔
3991
      l = map_xor_to_literal(ctx, xor_term_desc(terms, r));
1✔
3992
      break;
1✔
3993

3994
    case ARITH_IS_INT_ATOM:
×
3995
      l = map_arith_is_int_to_literal(ctx, arith_is_int_arg(terms, r));
×
3996
      break;
×
3997

3998
    case ARITH_EQ_ATOM:
2,249✔
3999
      l = map_arith_eq_to_literal(ctx, arith_eq_arg(terms, r));
2,249✔
4000
      break;
2,249✔
4001

4002
    case ARITH_GE_ATOM:
33,841✔
4003
      l = map_arith_geq_to_literal(ctx, arith_ge_arg(terms, r));
33,841✔
4004
      break;
33,841✔
4005

4006
    case ARITH_BINEQ_ATOM:
8,967✔
4007
      l = map_arith_bineq_to_literal(ctx, arith_bineq_atom_desc(terms, r));
8,967✔
4008
      break;
8,967✔
4009

4010
    case ARITH_DIVIDES_ATOM:
8✔
4011
      l = map_arith_divides_to_literal(ctx, arith_divides_atom_desc(terms, r));
8✔
4012
      break;
8✔
4013

NEW
4014
    case ARITH_ROOT_ATOM:
×
NEW
4015
      longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
4016
      break;
4017

NEW
4018
    case ARITH_FF_EQ_ATOM:
×
4019
    case ARITH_FF_BINEQ_ATOM:
NEW
4020
      longjmp(ctx->env, CONTEXT_UNSUPPORTED_THEORY);
×
4021
      break;
4022

4023
    case APP_TERM:
4,368✔
4024
      l = map_apply_to_literal(ctx, app_term_desc(terms, r));
4,368✔
4025
      break;
4,368✔
4026

4027
    case SELECT_TERM:
×
4028
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), bool_type(ctx->types));
×
4029
      assert(egraph_term_is_bool(ctx->egraph, term_of_occ(u)));
4030
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
4031
      l = egraph_occ2literal(ctx->egraph, u);
×
4032
      // we don't want to map r to l here
4033
      goto done;
×
4034

4035
    case DISTINCT_TERM:
9✔
4036
      l = map_distinct_to_literal(ctx, distinct_term_desc(terms, r));
9✔
4037
      break;
9✔
4038

4039
    case FORALL_TERM:
×
4040
      if (context_in_strict_mode(ctx)) {
×
4041
        longjmp(ctx->env, QUANTIFIERS_NOT_SUPPORTED);
×
4042
      }
4043
      // lax mode: turn forall into a proposition
4044
      l = pos_lit(create_boolean_variable(ctx->core));
×
4045
      break;
×
4046

4047
    case BIT_TERM:
264,228✔
4048
      l = map_bit_select_to_literal(ctx, bit_term_desc(terms, r));
264,228✔
4049
      break;
264,228✔
4050

4051
    case BV_EQ_ATOM:
4,864✔
4052
      l = map_bveq_to_literal(ctx, bveq_atom_desc(terms, r));
4,864✔
4053
      break;
4,864✔
4054

4055
    case BV_GE_ATOM:
2,302✔
4056
      l = map_bvge_to_literal(ctx, bvge_atom_desc(terms, r));
2,302✔
4057
      break;
2,302✔
4058

4059
    case BV_SGE_ATOM:
2,907✔
4060
      l = map_bvsge_to_literal(ctx, bvsge_atom_desc(terms, r));
2,907✔
4061
      break;
2,907✔
4062

4063
    default:
×
4064
      longjmp(ctx->env, INTERNAL_ERROR);
×
4065
      break;
4066
    }
4067

4068
    if (ctx->mcsat_supplement) {
427,836✔
4069
      context_observe_mcsat_atom(ctx, r, l);
4✔
4070
    }
4071

4072
    // map r to l in the internalization table
4073
    intern_tbl_map_root(&ctx->intern, r, literal2code(l));
427,836✔
4074
  }
4075

4076
 done:
1,825,200✔
4077
  return l ^ polarity;
1,825,200✔
4078
}
4079

4080

4081

4082
/******************************************************
4083
 *  TOP-LEVEL ASSERTIONS: TERMS ALREADY INTERNALIZED  *
4084
 *****************************************************/
4085

4086
/*
4087
 * Assert (x == tt) for an internalization code x
4088
 */
4089
static void assert_internalization_code(context_t *ctx, int32_t x, bool tt) {
924✔
4090
  occ_t g;
4091
  literal_t l;
4092

4093
  assert(code_is_valid(x));
4094

4095
  if (code_is_eterm(x)) {
924✔
4096
    // normalize to assertion (g == true)
4097
    g = code2occ(x);
10✔
4098
    if (! tt) g = opposite_occ(g);
10✔
4099

4100
    // We must deal with 'true_occ/false_occ' separately
4101
    // since they may be used even if there's no actual egraph.
4102
    if (g == false_occ) {
10✔
4103
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
4104
    } else if (g != true_occ) {
6✔
4105
      assert(ctx->egraph != NULL);
4106
      if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
×
4107
        egraph_assert_axiom(ctx->egraph, g);
×
4108
      } else {
4109
        l = egraph_make_eq(ctx->egraph, g, true_occ);
×
4110
        add_unit_clause(ctx->core, l);
×
4111
      }
4112
    }
4113
  } else {
4114
    l = code2literal(x);
914✔
4115
    if (! tt) l = not(l);
914✔
4116
    add_unit_clause(ctx->core, l);
914✔
4117
  }
4118
}
920✔
4119

4120
/*
4121
 * Assert t == true where t is a term that's already mapped
4122
 * either to a literal or to an egraph occurrence.
4123
 * - t must be a root in the internalization table
4124
 */
4125
static void assert_toplevel_intern(context_t *ctx, term_t t) {
739✔
4126
  int32_t code;
4127
  bool tt;
4128

4129
  assert(is_boolean_term(ctx->terms, t) &&
4130
         intern_tbl_is_root(&ctx->intern, t) &&
4131
         intern_tbl_root_is_mapped(&ctx->intern, t));
4132

4133
  tt = is_pos_term(t);
739✔
4134
  t = unsigned_term(t);
739✔
4135
  code = intern_tbl_map_of_root(&ctx->intern, t);
739✔
4136

4137
  assert_internalization_code(ctx, code, tt);
739✔
4138
}
739✔
4139

4140

4141

4142

4143

4144

4145

4146
/********************************
4147
 *   ARITHMETIC SUBSTITUTIONS   *
4148
 *******************************/
4149

4150
/*
4151
 * TODO: improve this in the integer case:
4152
 * - all_int is based on p's type in the term table and does
4153
 *   not take the context's substitutions into account.
4154
 * - integral_poly_after_div requires all coefficients
4155
 *   to be integer. This could be generalized to polynomials
4156
 *   with integer variables and rational coefficients.
4157
 */
4158

4159
/*
4160
 * Check whether term t can be eliminated by an arithmetic substitution
4161
 * - t's root must be uninterpreted and not internalized yet
4162
 */
4163
static bool is_elimination_candidate(context_t *ctx, term_t t) {
2,742✔
4164
  term_t r;
4165

4166
  r = intern_tbl_get_root(&ctx->intern, t);
2,742✔
4167
  return intern_tbl_root_is_free(&ctx->intern, r);
2,742✔
4168
}
4169

4170

4171
/*
4172
 * Replace every variable of t by the root of t in the internalization table
4173
 * - the result is stored in buffer
4174
 */
4175
static void apply_renaming_to_poly(context_t *ctx, polynomial_t *p,  poly_buffer_t *buffer) {
544✔
4176
  uint32_t i, n;
4177
  term_t t;
4178

4179
  reset_poly_buffer(buffer);
544✔
4180

4181
  assert(poly_buffer_is_zero(buffer));
4182

4183
  n = p->nterms;
544✔
4184
  for (i=0; i<n; i++) {
2,599✔
4185
    t = p->mono[i].var;
2,055✔
4186
    if (t == const_idx) {
2,055✔
4187
      poly_buffer_add_const(buffer, &p->mono[i].coeff);
180✔
4188
    } else {
4189
      // replace t by its root
4190
      t = intern_tbl_get_root(&ctx->intern, t);
1,875✔
4191
      poly_buffer_addmul_term(ctx->terms, buffer, t, &p->mono[i].coeff);
1,875✔
4192
    }
4193
  }
4194

4195
  normalize_poly_buffer(buffer);
544✔
4196
}
544✔
4197

4198

4199
/*
4200
 * Auxiliary function: check whether p/a is an integral polynomial
4201
 * assuming all variables and coefficients of p are integer.
4202
 * - check whether all coefficients are multiple of a
4203
 * - a must be non-zero
4204
 */
4205
static bool integralpoly_after_div(poly_buffer_t *buffer, rational_t *a) {
318✔
4206
  uint32_t i, n;
4207

4208
  if (q_is_one(a) || q_is_minus_one(a)) {
318✔
4209
    return true;
265✔
4210
  }
4211

4212
  n = buffer->nterms;
53✔
4213
  for (i=0; i<n; i++) {
64✔
4214
    if (! q_divides(a, &buffer->mono[i].coeff)) return false;
63✔
4215
  }
4216
  return true;
1✔
4217
}
4218

4219

4220
/*
4221
 * Check whether a top-level assertion (p == 0) can be
4222
 * rewritten (t == q) where t is not internalized yet.
4223
 * - all_int is true if p is an integer polynomial (i.e.,
4224
 *   all coefficients and all terms of p are integer).
4225
 * - p = input polynomial
4226
 * - return t or null_term if no adequate t is found
4227
 */
4228
static term_t try_poly_substitution(context_t *ctx, poly_buffer_t *buffer, bool all_int) {
544✔
4229
  uint32_t i, n;
4230
  term_t t;
4231

4232
  // check for a free variable in buffer
4233
  n = buffer->nterms;
544✔
4234
  for (i=0; i<n; i++) {
1,128✔
4235
    t = buffer->mono[i].var;
1,049✔
4236
    if (t != const_idx && is_elimination_candidate(ctx, t)) {
1,049✔
4237
      if (in_real_class(ctx, t) ||
518✔
4238
          (all_int && integralpoly_after_div(buffer, &buffer->mono[i].coeff))) {
318✔
4239
        // t is candidate for elimination
4240
        return t;
465✔
4241
      }
4242
    }
4243
  }
4244

4245
  return NULL_TERM;
79✔
4246
}
4247

4248

4249
/*
4250
 * Build polynomial - p/a + x in the context's aux_poly buffer
4251
 * where a = coefficient of x in p
4252
 * - x must occur in p
4253
 */
4254
static polynomial_t *build_poly_substitution(context_t *ctx, poly_buffer_t *buffer, term_t x) {
465✔
4255
  polynomial_t *q;
4256
  monomial_t *mono;
4257
  uint32_t i, n;
4258
  term_t y;
4259
  rational_t *a;
4260

4261
  n = buffer->nterms;
465✔
4262

4263
  // first get coefficient of x in buffer
4264
  a = NULL; // otherwise GCC complains
465✔
4265
  for (i=0; i<n; i++) {
2,283✔
4266
    y = buffer->mono[i].var;
1,818✔
4267
    if (y == x) {
1,818✔
4268
      a = &buffer->mono[i].coeff;
465✔
4269
    }
4270
  }
4271
  assert(a != NULL && n > 0);
4272

4273
  q = context_get_aux_poly(ctx, n);
465✔
4274
  q->nterms = n-1;
465✔
4275
  mono = q->mono;
465✔
4276

4277
  // compute - buffer/a (but skip monomial a.x)
4278
  for (i=0; i<n; i++) {
2,283✔
4279
    y = buffer->mono[i].var;
1,818✔
4280
    if (y != x) {
1,818✔
4281
      mono->var = y;
1,353✔
4282
      q_set_neg(&mono->coeff, &buffer->mono[i].coeff);
1,353✔
4283
      q_div(&mono->coeff, a);
1,353✔
4284
      mono ++;
1,353✔
4285
    }
4286
  }
4287

4288
  // end marker
4289
  mono->var = max_idx;
465✔
4290

4291
  return q;
465✔
4292
}
4293

4294

4295

4296
/*
4297
 * Try to eliminate a toplevel equality (p == 0) by variable substitution:
4298
 * - i.e., try to rewrite p == 0 into (x - q) == 0 where x is a free variable
4299
 *   then store the substitution x --> q in the internalization table.
4300
 * - all_int is true if p is an integer polynomial (i.e., all variables and all
4301
 *   coefficients of p are integer)
4302
 *
4303
 * - return true if the elimination succeeds
4304
 * - return false otherwise
4305
 */
4306
static bool try_arithvar_elim(context_t *ctx, polynomial_t *p, bool all_int) {
544✔
4307
  poly_buffer_t *buffer;
4308
  polynomial_t *q;
4309
  uint32_t i, n;
4310
  term_t t, u, r;
4311
  thvar_t x;
4312

4313
  /*
4314
   * First pass: internalize every term of p that's not a variable
4315
   * - we do that first to avoid circular substitutions (occurs-check)
4316
   */
4317
  n = p->nterms;
544✔
4318
  for (i=0; i<n; i++) {
2,599✔
4319
    t = p->mono[i].var;
2,055✔
4320
    if (t != const_idx && ! is_elimination_candidate(ctx, t)) {
2,055✔
4321
      (void) internalize_to_arith(ctx, t);
599✔
4322
    }
4323
  }
4324

4325

4326
  /*
4327
   * Apply variable renaming: this is to avoid circularities
4328
   * if p is of the form ... + a x + ... + b y + ...
4329
   * where both x and y are variables in the same class (i.e.,
4330
   * both are elimination candidates).
4331
   */
4332
  buffer = context_get_poly_buffer(ctx);
544✔
4333
  apply_renaming_to_poly(ctx, p, buffer);
544✔
4334

4335
  /*
4336
   * Search for a variable to substitute
4337
   */
4338
  u = try_poly_substitution(ctx, buffer, all_int);
544✔
4339
  if (u == NULL_TERM) {
544✔
4340
    return false; // no substitution found
79✔
4341
  }
4342

4343
  /*
4344
   * buffer is of the form a.u + p0, we rewrite (buffer == 0) to (u == q)
4345
   * where q = -1/a * p0
4346
   */
4347
  q = build_poly_substitution(ctx, buffer, u); // q is in ctx->aux_poly
465✔
4348

4349
  // convert q to a theory variable in the arithmetic solver
4350
  x = map_poly_to_arith(ctx, q);
465✔
4351

4352
  // map u (and its root) to x
4353
  r = intern_tbl_get_root(&ctx->intern, u);
465✔
4354
  assert(intern_tbl_root_is_free(&ctx->intern, r) && is_pos_term(r));
4355
  intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
465✔
4356

4357
#if TRACE
4358
  printf("---> toplevel equality: ");
4359
  print_polynomial(stdout, p);
4360
  printf(" == 0\n");
4361
  printf("     simplified to ");
4362
  print_term(stdout, ctx->terms, u);
4363
  printf(" := ");
4364
  print_polynomial(stdout, q);
4365
  printf("\n");
4366
#endif
4367

4368
  return true;
465✔
4369
}
4370

4371

4372

4373

4374

4375

4376

4377
/******************************************************
4378
 *  TOP-LEVEL ARITHMETIC EQUALITIES OR DISEQUALITIES  *
4379
 *****************************************************/
4380

4381
static void assert_arith_bineq(context_t *ctx, term_t t1, term_t t2, bool tt);
4382

4383
/*
4384
 * Top-level equality: t == (ite c u1 u2) between arithmetic terms
4385
 * - apply lift-if rule: (t == (ite c u1 u2)) --> (ite c (t == u1) (t == u2)
4386
 * - if tt is true: assert the equality otherwise assert the disequality
4387
 */
4388
static void assert_ite_arith_bineq(context_t *ctx, composite_term_t *ite, term_t t, bool tt) {
451✔
4389
  literal_t l1, l2, l3;
4390

4391
  assert(ite->arity == 3);
4392

4393
  l1 = internalize_to_literal(ctx, ite->arg[0]);
451✔
4394
  if (l1 == true_literal) {
451✔
4395
    // (ite c u1 u2) --> u1
4396
    assert_arith_bineq(ctx, ite->arg[1], t, tt);
3✔
4397
  } else if (l1 == false_literal) {
448✔
4398
    // (ite c u1 u2) --> u2
4399
    assert_arith_bineq(ctx, ite->arg[2], t, tt);
15✔
4400
  } else {
4401
    l2 = map_arith_bineq(ctx, ite->arg[1], t); // (u1 == t)
433✔
4402
    l3 = map_arith_bineq(ctx, ite->arg[2], t); // (u2 == t)
433✔
4403
    assert_ite(&ctx->gate_manager, l1, l2, l3, tt);
433✔
4404
  }
4405
}
451✔
4406

4407

4408
/*
4409
 * Try substitution t1 := t2
4410
 * - both are arithmetic terms and roots in the internalization table
4411
 */
4412
static void try_arithvar_bineq_elim(context_t *ctx, term_t t1, term_t t2) {
171✔
4413
  intern_tbl_t *intern;
4414
  thvar_t x, y;
4415
  int32_t code;
4416

4417
  assert(is_pos_term(t1) && intern_tbl_is_root(&ctx->intern, t1) &&
4418
         intern_tbl_root_is_free(&ctx->intern, t1));
4419

4420
  intern = &ctx->intern;
171✔
4421

4422
  if (is_constant_term(ctx->terms, t2)) {
171✔
4423
    if (intern_tbl_valid_const_subst(intern, t1, t2)) {
9✔
4424
      intern_tbl_add_subst(intern, t1, t2);
9✔
4425
    } else {
4426
      // unsat by type incompatibility
4427
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4428
    }
4429

4430
  } else if (intern_tbl_sound_subst(intern, t1, t2)) {
162✔
4431
    /*
4432
     * Internalize t2 to x.
4433
     * If t1 is still free after that, we can map t1 to x
4434
     * otherwise, t2 depends on t1 so we can't substitute.
4435
     */
4436
    x = internalize_to_arith(ctx, t2);
161✔
4437
    if (intern_tbl_root_is_free(intern, t1)) {
161✔
4438
      intern_tbl_map_root(&ctx->intern, t1, thvar2code(x));
2✔
4439
    } else {
4440
      assert(intern_tbl_root_is_mapped(intern, t1));
4441
      code = intern_tbl_map_of_root(intern, t1);
159✔
4442
      y = translate_code_to_arith(ctx, code);
159✔
4443

4444
      // assert x == y in the arithmetic solver
4445
      ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, true);
159✔
4446
    }
4447
  } else {
4448
    x = internalize_to_arith(ctx, t1);
1✔
4449
    y = internalize_to_arith(ctx, t2);
1✔
4450
    ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, true);
1✔
4451
  }
4452
}
171✔
4453

4454

4455
/*
4456
 * Top-level arithmetic equality t1 == t2:
4457
 * - if tt is true: assert t1 == t2 otherwise assert (t1 != t2)
4458
 * - both t1 and t2 are arithmetic terms and roots in the internalization table
4459
 * - the equality (t1 == t2) is not reducible by if-then-else flattening
4460
 */
4461
static void assert_arith_bineq_aux(context_t *ctx, term_t t1, term_t t2, bool tt) {
3,342✔
4462
  term_table_t *terms;
4463
  intern_tbl_t *intern;;
4464
  bool free1, free2;
4465
  thvar_t x, y;
4466
  occ_t u, v;
4467

4468
  assert(is_pos_term(t1) && intern_tbl_is_root(&ctx->intern, t1) &&
4469
         is_pos_term(t2) && intern_tbl_is_root(&ctx->intern, t2));
4470

4471
  terms = ctx->terms;
3,342✔
4472
  if (is_ite_term(terms, t1) && !is_ite_term(terms, t2)) {
3,342✔
4473
    assert_ite_arith_bineq(ctx, ite_term_desc(terms, t1), t2, tt);
112✔
4474
    return;
112✔
4475
  }
4476

4477
  if (is_ite_term(terms, t2) && !is_ite_term(terms, t1)) {
3,230✔
4478
    assert_ite_arith_bineq(ctx, ite_term_desc(terms, t2), t1, tt);
339✔
4479
    return;
339✔
4480
  }
4481

4482
  if (tt && context_arith_elim_enabled(ctx)) {
2,891✔
4483
    /*
4484
     * try a substitution
4485
     */
4486
    intern = &ctx->intern;
347✔
4487
    free1 = intern_tbl_root_is_free(intern, t1);
347✔
4488
    free2 = intern_tbl_root_is_free(intern, t2);
347✔
4489

4490
    if (free1 && free2) {
347✔
4491
      if (t1 != t2) {
1✔
4492
        intern_tbl_merge_classes(intern, t1, t2);
1✔
4493
      }
4494
      return;
1✔
4495
    }
4496

4497
    if (free1) {
346✔
4498
      try_arithvar_bineq_elim(ctx, t1, t2);
164✔
4499
      return;
164✔
4500
    }
4501

4502
    if (free2) {
182✔
4503
      try_arithvar_bineq_elim(ctx, t2, t1);
7✔
4504
      return;
7✔
4505
    }
4506

4507
  }
4508

4509
  /*
4510
   * Default: assert the constraint in the egraph or in the arithmetic
4511
   * solver if there's no egraph.
4512
   */
4513
  if (context_has_egraph(ctx)) {
2,719✔
4514
    u = internalize_to_eterm(ctx, t1);
1,658✔
4515
    v = internalize_to_eterm(ctx, t2);
1,658✔
4516
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
1,658✔
4517
      if (tt) {
1,658✔
4518
        egraph_assert_eq_axiom(ctx->egraph, u, v);
162✔
4519
      } else {
4520
        egraph_assert_diseq_axiom(ctx->egraph, u, v);
1,496✔
4521
      }
4522
    } else {
4523
      literal_t l = egraph_make_eq(ctx->egraph, u, v);
×
4524
      if (tt) {
×
4525
        add_unit_clause(ctx->core, l);
×
4526
      } else {
4527
        add_unit_clause(ctx->core, not(l));
×
4528
      }
4529
    }
4530
  } else {
4531
    x = internalize_to_arith(ctx, t1);
1,061✔
4532
    y = internalize_to_arith(ctx, t2);
1,061✔
4533
    ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, tt);
1,061✔
4534
  }
4535
}
4536

4537

4538

4539

4540
/*****************************************************
4541
 *  INTERNALIZATION OF TOP-LEVEL ATOMS AND FORMULAS  *
4542
 ****************************************************/
4543

4544
/*
4545
 * Recursive function: assert (t == tt) for a boolean term t
4546
 * - this is used when a toplevel formula simplifies to t
4547
 *   For example (ite c t u) --> t if c is true.
4548
 * - t is not necessarily a root in the internalization table
4549
 */
4550
static void assert_term(context_t *ctx, term_t t, bool tt);
4551

4552

4553
/*
4554
 * Top-level predicate: (p t_1 .. t_n)
4555
 * - if tt is true: assert (p t_1 ... t_n)
4556
 * - if tt is false: assert (not (p t_1 ... t_n))
4557
 */
4558
static void assert_toplevel_apply(context_t *ctx, composite_term_t *app, bool tt) {
252✔
4559
  occ_t *a;
4560
  uint32_t i, n;
4561

4562
  assert(app->arity > 0);
4563

4564
  n = app->arity;
252✔
4565

4566
  check_high_order_support(ctx, app->arg+1, n-1);
252✔
4567

4568
  a = alloc_istack_array(&ctx->istack, n);
252✔
4569
  for (i=0; i<n; i++) {
1,030✔
4570
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
778✔
4571
  }
4572

4573
  if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
252✔
4574
    if (tt) {
242✔
4575
      egraph_assert_pred_axiom(ctx->egraph, a[0], n-1, a+1);
214✔
4576
    } else {
4577
      egraph_assert_notpred_axiom(ctx->egraph, a[0], n-1, a+1);
28✔
4578
    }
4579
  } else {
4580
    literal_t l = egraph_make_pred(ctx->egraph, a[0], n-1, a+1);
10✔
4581
    if (tt) {
10✔
4582
      add_unit_clause(ctx->core, l);
3✔
4583
    } else {
4584
      add_unit_clause(ctx->core, not(l));
7✔
4585
    }
4586
  }
4587

4588
  free_istack_array(&ctx->istack, a);
252✔
4589
}
252✔
4590

4591

4592
/*
4593
 * Top-level (select i t)
4594
 * - if tt is true: assert (select i t)
4595
 * - if tt is false: assert (not (select i t))
4596
 */
4597
static void assert_toplevel_select(context_t *ctx, select_term_t *select, bool tt) {
×
4598
  occ_t u;
4599

4600
  u = map_select_to_eterm(ctx, select, bool_type(ctx->types));
×
4601
  if (! tt) {
×
4602
    u = opposite_occ(u);
×
4603
  }
4604
  if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
×
4605
    egraph_assert_axiom(ctx->egraph, u);
×
4606
  } else {
4607
    literal_t l = egraph_make_eq(ctx->egraph, u, true_occ);
×
4608
    add_unit_clause(ctx->core, l);
×
4609
  }
4610
}
×
4611

4612

4613
/*
4614
 * Top-level equality between Boolean terms
4615
 * - if tt is true, assert t1 == t2
4616
 * - if tt is false, assert t1 != t2
4617
 */
4618
static void assert_toplevel_iff(context_t *ctx, term_t t1, term_t t2, bool tt) {
2,739✔
4619
  term_t t;
4620
  literal_t l1, l2;
4621

4622
  /*
4623
   * Apply substitution then try flattening
4624
   */
4625
  t1 = intern_tbl_get_root(&ctx->intern, t1);
2,739✔
4626
  t2 = intern_tbl_get_root(&ctx->intern, t2);
2,739✔
4627
  if (t1 == t2) {
2,739✔
4628
    // (eq t1 t2) is true
4629
    if (!tt) {
×
4630
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4631
    }
4632
  }
4633
  // try simplification
4634
  t = simplify_bool_eq(ctx, t1, t2);
2,739✔
4635
  if (t != NULL_TERM) {
2,739✔
4636
    // (eq t1 t2) is equivalent to t
4637
    assert_term(ctx, t, tt) ;
17✔
4638
  } else {
4639
    // no simplification
4640
    l1 = internalize_to_literal(ctx, t1);
2,722✔
4641
    l2 = internalize_to_literal(ctx, t2);
2,722✔
4642
    assert_iff(&ctx->gate_manager, l1, l2, tt);
2,722✔
4643

4644
#if 0
4645
    if (tt) {
4646
      printf("top assert: (eq ");
4647
      print_literal(stdout, l1);
4648
      printf(" ");
4649
      print_literal(stdout, l2);
4650
      printf(")\n");
4651
    } else {
4652
      printf("top assert: (xor ");
4653
      print_literal(stdout, l1);
4654
      printf(" ");
4655
      print_literal(stdout, l2);
4656
      printf(")\n");
4657
    }
4658
#endif
4659
  }
4660
}
2,739✔
4661

4662
/*
4663
 * Top-level equality assertion (eq t1 t2):
4664
 * - if tt is true, assert (t1 == t2)
4665
 *   if tt is false, assert (t1 != t2)
4666
 */
4667
static void assert_toplevel_eq(context_t *ctx, composite_term_t *eq, bool tt) {
5,156✔
4668
  occ_t u1, u2;
4669

4670
  assert(eq->arity == 2);
4671

4672
  if (is_boolean_term(ctx->terms, eq->arg[0])) {
5,156✔
4673
    assert(is_boolean_term(ctx->terms, eq->arg[1]));
4674
    assert_toplevel_iff(ctx, eq->arg[0], eq->arg[1], tt);
2,739✔
4675
  } else {
4676
    // filter out high-order terms. It's enough to check eq->arg[0]
4677
    check_high_order_support(ctx, eq->arg, 1);
2,417✔
4678

4679
    u1 = internalize_to_eterm(ctx, eq->arg[0]);
2,416✔
4680
    u2 = internalize_to_eterm(ctx, eq->arg[1]);
2,416✔
4681
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
2,415✔
4682
      if (tt) {
2,401✔
4683
        egraph_assert_eq_axiom(ctx->egraph, u1, u2);
1,323✔
4684
      } else {
4685
        egraph_assert_diseq_axiom(ctx->egraph, u1, u2);
1,078✔
4686
      }
4687
    } else {
4688
      literal_t l = egraph_make_eq(ctx->egraph, u1, u2);
14✔
4689
      if (tt) {
14✔
4690
        add_unit_clause(ctx->core, l);
9✔
4691
      } else {
4692
        add_unit_clause(ctx->core, not(l));
5✔
4693
      }
4694
    }
4695
  }
4696
}
5,154✔
4697

4698

4699
/*
4700
 * Assertion (distinct a[0] .... a[n-1]) == tt
4701
 * when a[0] ... a[n-1] are arithmetic variables.
4702
 */
4703
static void assert_arith_distinct(context_t *ctx, uint32_t n, thvar_t *a, bool tt) {
155✔
4704
  literal_t l;
4705

4706
  l = make_arith_distinct(ctx, n, a);
155✔
4707
  if (! tt) {
155✔
4708
    l = not(l);
4✔
4709
  }
4710
  add_unit_clause(ctx->core, l);
155✔
4711
}
155✔
4712

4713

4714
/*
4715
 * Assertion (distinct a[0] .... a[n-1]) == tt
4716
 * when a[0] ... a[n-1] are bitvector variables.
4717
 */
4718
static void assert_bv_distinct(context_t *ctx, uint32_t n, thvar_t *a, bool tt) {
2✔
4719
  literal_t l;
4720

4721
  l = make_bv_distinct(ctx, n, a);
2✔
4722
  if (! tt) {
2✔
4723
    l = not(l);
1✔
4724
  }
4725
  add_unit_clause(ctx->core, l);
2✔
4726
}
2✔
4727

4728

4729
/*
4730
 * Generic (distinct t1 .. t_n)
4731
 * - if tt: assert (distinct t_1 ... t_n)
4732
 * - otherwise: assert (not (distinct t_1 ... t_n))
4733
 */
4734
static void assert_toplevel_distinct(context_t *ctx, composite_term_t *distinct, bool tt) {
173✔
4735
  uint32_t i, n;
4736
  int32_t *a;
4737

4738
  n = distinct->arity;
173✔
4739
  assert(n >= 2);
4740

4741
  a = alloc_istack_array(&ctx->istack, n);
173✔
4742

4743
  if (context_has_egraph(ctx)) {
173✔
4744
    // fail if arguments have function types and we don't
4745
    // have a function/array solver
4746
    check_high_order_support(ctx, distinct->arg, 1);
16✔
4747

4748
    // forward the assertion to the egraph
4749
    for (i=0; i<n; i++) {
69✔
4750
      a[i] = internalize_to_eterm(ctx, distinct->arg[i]);
55✔
4751
    }
4752

4753
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
14✔
4754
      if (tt) {
14✔
4755
        egraph_assert_distinct_axiom(ctx->egraph, n, a);
10✔
4756
      } else {
4757
        egraph_assert_notdistinct_axiom(ctx->egraph, n, a);
4✔
4758
      }
4759
    } else {
4760
      literal_t l = egraph_make_distinct(ctx->egraph, n, a);
×
4761
      if (tt) {
×
4762
        add_unit_clause(ctx->core, l);
×
4763
      } else {
4764
        add_unit_clause(ctx->core, not(l));
×
4765
      }
4766
    }
4767

4768
  } else if (is_arithmetic_term(ctx->terms, distinct->arg[0])) {
157✔
4769
    // translate to arithmetic then assert
4770
    for (i=0; i<n; i++) {
3,922✔
4771
      a[i] = internalize_to_arith(ctx, distinct->arg[i]);
3,767✔
4772
    }
4773
    assert_arith_distinct(ctx, n, a, tt);
155✔
4774

4775
  } else if (is_bitvector_term(ctx->terms, distinct->arg[0])) {
2✔
4776
    // translate to bitvectors then assert
4777
    for (i=0; i<n; i++) {
13✔
4778
      a[i] = internalize_to_bv(ctx, distinct->arg[i]);
11✔
4779
    }
4780
    assert_bv_distinct(ctx, n, a, tt);
2✔
4781

4782
  } else {
4783
    longjmp(ctx->env, uf_error_code(ctx, distinct->arg[0]));
×
4784
  }
4785

4786
  free_istack_array(&ctx->istack, a);
171✔
4787
}
171✔
4788

4789

4790

4791
/*
4792
 * Top-level arithmetic equality t1 == u1:
4793
 * - t1 and u1 are arithmetic terms
4794
 * - if tt is true assert (t1 == u1) otherwise assert (t1 != u1)
4795
 * - apply lift-if simplifications and variable elimination
4796
 */
4797
static void assert_arith_bineq(context_t *ctx, term_t t1, term_t u1, bool tt) {
3,415✔
4798
  ivector_t *v;
4799
  int32_t *a;
4800
  uint32_t i, n;
4801
  term_t t2, u2;
4802

4803
  /*
4804
   * Apply substitutions then try if-then-else flattening
4805
   */
4806
  t1 = intern_tbl_get_root(&ctx->intern, t1);
3,415✔
4807
  u1 = intern_tbl_get_root(&ctx->intern, u1);
3,415✔
4808

4809
  v = &ctx->aux_vector;
3,415✔
4810
  assert(v->size == 0);
4811
  t2 = flatten_ite_equality(ctx, v, t1, u1);
3,415✔
4812
  u2 = flatten_ite_equality(ctx, v, u1, t2);
3,415✔
4813

4814
  /*
4815
   * (t1 == u1) is now equivalent to
4816
   * the conjunction of (t2 == u2) and all the terms in v
4817
   */
4818
  n = v->size;
3,415✔
4819
  if (n == 0) {
3,415✔
4820
    /*
4821
     * The simple flattening did not work.
4822
     */
4823
    assert(t1 == t2 && u1 == u2);
4824
    assert_arith_bineq_aux(ctx, t2, u2, tt);
3,329✔
4825

4826
  } else {
4827
    // make a copy of v[0 ... n-1]
4828
    // and reserve a[n] for the literal (eq t2 u2)
4829
    a = alloc_istack_array(&ctx->istack, n+1);
86✔
4830
    for (i=0; i<n; i++) {
1,531✔
4831
      a[i] = v->data[i];
1,445✔
4832
    }
4833
    ivector_reset(v);
86✔
4834

4835
    if (tt) {
86✔
4836
      // assert (and a[0] ... a[n-1] (eq t2 u2))
4837
      for (i=0; i<n; i++) {
340✔
4838
        assert_term(ctx, a[i], true);
327✔
4839
      }
4840

4841
      /*
4842
       * The assertions a[0] ... a[n-1] may have
4843
       * caused roots to be merged. So we must
4844
       * apply term substitution again.
4845
       */
4846
      t2 = intern_tbl_get_root(&ctx->intern, t2);
13✔
4847
      u2 = intern_tbl_get_root(&ctx->intern, u2);
13✔
4848
      assert_arith_bineq_aux(ctx, t2, u2, true);
13✔
4849

4850
    } else {
4851
      // assert (or (not a[0]) ... (not a[n-1]) (not (eq t2 u2)))
4852
      for (i=0; i<n; i++) {
1,191✔
4853
        a[i] = not(internalize_to_literal(ctx, a[i]));
1,118✔
4854
      }
4855
      a[n] = not(map_arith_bineq_aux(ctx, t2, u2));
73✔
4856

4857
      add_clause(ctx->core, n+1, a);
73✔
4858
    }
4859

4860
    free_istack_array(&ctx->istack, a);
86✔
4861
  }
4862
}
3,415✔
4863

4864

4865
/*
4866
 * Top-level arithmetic assertion:
4867
 * - if tt is true, assert p == 0
4868
 * - if tt is false, assert p != 0
4869
 */
4870
static void assert_toplevel_poly_eq(context_t *ctx, polynomial_t *p, bool tt) {
1,273✔
4871
  uint32_t i, n;
4872
  thvar_t *a;
4873

4874
  n = p->nterms;
1,273✔
4875
  a = alloc_istack_array(&ctx->istack, n);;
1,273✔
4876
  // skip the constant if any
4877
  i = 0;
1,273✔
4878
  if (p->mono[0].var == const_idx) {
1,273✔
4879
    a[0] = null_thvar;
1,208✔
4880
    i ++;
1,208✔
4881
  }
4882

4883
  // deal with the non-constant monomials
4884
  while (i<n) {
3,928✔
4885
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
2,655✔
4886
    i ++;
2,655✔
4887
  }
4888

4889
  // assertion
4890
  ctx->arith.assert_poly_eq_axiom(ctx->arith_solver, p, a, tt);
1,273✔
4891
  free_istack_array(&ctx->istack, a);
1,273✔
4892
}
1,273✔
4893

4894

4895

4896
/*
4897
 * Top-level arithmetic equality:
4898
 * - t is an arithmetic term
4899
 * - if tt is true, assert (t == 0)
4900
 * - otherwise, assert (t != 0)
4901
 */
4902
static void assert_toplevel_arith_eq(context_t *ctx, term_t t, bool tt) {
2,270✔
4903
  term_table_t *terms;
4904
  polynomial_t *p;
4905
  bool all_int;
4906
  thvar_t x;
4907

4908
  assert(is_arithmetic_term(ctx->terms, t));
4909

4910
  terms = ctx->terms;
2,270✔
4911
  if (tt && context_arith_elim_enabled(ctx) && term_kind(terms, t) == ARITH_POLY) {
2,270✔
4912
    /*
4913
     * Polynomial equality: a_1 t_1 + ... + a_n t_n = 0
4914
     * attempt to eliminate one of t_1 ... t_n
4915
     */
4916
    p = poly_term_desc(terms, t);
544✔
4917
    all_int = is_integer_term(terms, t);
544✔
4918
    if (try_arithvar_elim(ctx, p, all_int)) { // elimination worked
544✔
4919
      return;
465✔
4920
    }
4921
  }
4922

4923
  // default
4924
  if (term_kind(terms, t) == ARITH_POLY) {
1,805✔
4925
    assert_toplevel_poly_eq(ctx, poly_term_desc(terms, t), tt);
1,273✔
4926
  } else if (is_ite_term(terms, t)) {
532✔
4927
    assert_arith_bineq(ctx, t, zero_term, tt);
8✔
4928
  } else {
4929
    x = internalize_to_arith(ctx, t);
524✔
4930
    ctx->arith.assert_eq_axiom(ctx->arith_solver, x, tt);
522✔
4931
  }
4932
}
4933

4934

4935

4936
/*
4937
 * Top-level arithmetic assertion:
4938
 * - if tt is true, assert p >= 0
4939
 * - if tt is false, assert p < 0
4940
 */
4941
static void assert_toplevel_poly_geq(context_t *ctx, polynomial_t *p, bool tt) {
25,932✔
4942
  uint32_t i, n;
4943
  thvar_t *a;
4944

4945
  n = p->nterms;
25,932✔
4946
  a = alloc_istack_array(&ctx->istack, n);;
25,932✔
4947
  // skip the constant if any
4948
  i = 0;
25,932✔
4949
  if (p->mono[0].var == const_idx) {
25,932✔
4950
    a[0] = null_thvar;
25,106✔
4951
    i ++;
25,106✔
4952
  }
4953

4954
  // deal with the non-constant monomials
4955
  while (i<n) {
55,607✔
4956
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
29,676✔
4957
    i ++;
29,675✔
4958
  }
4959

4960
  // assertion
4961
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, a, tt);
25,931✔
4962
  free_istack_array(&ctx->istack, a);
25,931✔
4963
}
25,931✔
4964

4965

4966

4967
/*
4968
 * Top-level arithmetic inequality:
4969
 * - t is an arithmetic term
4970
 * - if tt is true, assert (t >= 0)
4971
 * - if tt is false, assert (t < 0)
4972
 */
4973
static void assert_toplevel_arith_geq(context_t *ctx, term_t t, bool tt) {
27,858✔
4974
  term_table_t *terms;
4975
  thvar_t x;
4976

4977
  assert(is_arithmetic_term(ctx->terms, t));
4978

4979
  terms = ctx->terms;
27,858✔
4980
  if (term_kind(terms, t) == ARITH_POLY) {
27,858✔
4981
    assert_toplevel_poly_geq(ctx, poly_term_desc(terms, t), tt);
25,932✔
4982
  } else {
4983
    x = internalize_to_arith(ctx, t);
1,926✔
4984
    ctx->arith.assert_ge_axiom(ctx->arith_solver, x, tt);
1,926✔
4985
  }
4986
}
27,857✔
4987

4988

4989
/*
4990
 * Top-level binary equality: (eq t u)
4991
 * - both t and u are arithmetic terms
4992
 * - if tt is true, assert (t == u)
4993
 * - if tt is false, assert (t != u)
4994
 */
4995
static void assert_toplevel_arith_bineq(context_t *ctx, composite_term_t *eq, bool tt) {
3,389✔
4996
  assert(eq->arity == 2);
4997
  assert_arith_bineq(ctx, eq->arg[0], eq->arg[1], tt);
3,389✔
4998
}
3,389✔
4999

5000

5001

5002
/*
5003
 * Top-level (is_int t)
5004
 * - t is an arithmetic term
5005
 * - if tt is true, assert (t <= (floor t))
5006
 * - if tt is false, asssert (t > (floor t))
5007
 *
5008
 * NOTE: instead of asserting (t <= (floor t)) we could create a fresh
5009
 * integer variable z and assert (t = z).
5010
 */
5011
static void assert_toplevel_arith_is_int(context_t *ctx, term_t t, bool tt) {
×
5012
  polynomial_t *p;
5013
  thvar_t map[2];
5014
  thvar_t x, y;
5015

5016
  x = internalize_to_arith(ctx, t);
×
5017
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
5018
    if (!tt) {
×
5019
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5020
    }
5021
  } else {
5022
    // x is not an integer variable
5023
    y = get_floor(ctx, x); // y := (floor x)
×
5024
    p = context_get_aux_poly(ctx, 3);
×
5025
    context_store_diff_poly(p, map, y, x); // (p, map) stores (y - x)
×
5026
    // assert either (p >= 0) --> (x <= floor(x))
5027
    // or (p < 0) --> (x > (floor x)
5028
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, tt);
×
5029
  }
5030
}
×
5031

5032

5033
/*
5034
 * Top-level (divides k t)
5035
 * - if tt is true, assert (t <= k * (div t k))
5036
 * - if tt is false, assert (t > k * (div t k))
5037
 *
5038
 * We assume (k != 0) since (divides 0 t) is rewritten to (t == 0) by
5039
 * the term manager.
5040
 *
5041
 * NOTE: instead of asserting (t <= k * (div t k)) we could create a fresh
5042
 * integer variable z and assert (t = k * z).
5043
 */
5044
static void assert_toplevel_arith_divides(context_t *ctx, composite_term_t *divides, bool tt) {
×
5045
  rational_t k;
5046
  polynomial_t *p;
5047
  thvar_t map[2];
5048
  thvar_t x, y;
5049
  term_t d;
5050

5051
  assert(divides->arity == 2);
5052

5053
  d = divides->arg[0];
×
5054
  if (term_kind(ctx->terms, d) == ARITH_CONSTANT) {
×
5055
    // copy the divider
5056
    q_init(&k);
×
5057
    q_set(&k, rational_term_desc(ctx->terms, d));
×
5058
    assert(q_is_nonzero(&k));
5059

5060
    x = internalize_to_arith(ctx, divides->arg[1]);
×
5061
    y = get_div(ctx, x, &k);  // y := (div x k);
×
5062
    p = context_get_aux_poly(ctx, 3);
×
5063
    context_store_divides_constraint(p, map, x, y, &k); // p is (- x + k * y)
×
5064

5065
    // if tt, assert (p >= 0) <=> x <= k * y
5066
    // if not tt, assert (p < 0) <=> x > k * y
5067
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, tt);
×
5068

5069
    q_clear(&k);
×
5070
  } else {
5071
    // not a constant divider: not supported
5072
    longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
5073
  }
5074
}
×
5075

5076

5077

5078

5079

5080

5081
/*
5082
 * Top-level conditional
5083
 * - c = conditional descriptor
5084
 * - if tt is true: assert c otherwise assert not c
5085
 *
5086
 * - c->nconds = number of clauses in the conditional
5087
 * - for each clause i: c->pair[i] = <cond, val>
5088
 * - c->defval = default value
5089
 */
5090
static void assert_toplevel_conditional(context_t *ctx, conditional_t *c, bool tt) {
13✔
5091
  uint32_t i, n;
5092
  literal_t *a;
5093
  literal_t l;
5094
  bool all_false;
5095
  term_t t;
5096

5097
#if 0
5098
  printf("---> toplevel conditional\n");
5099
#endif
5100

5101
  t = simplify_conditional(ctx, c);
13✔
5102
  if (t != NULL_TERM) {
13✔
5103
    assert_term(ctx, t, tt);
2✔
5104
    return;
2✔
5105
  }
5106

5107
  n = c->nconds;
11✔
5108
  a = alloc_istack_array(&ctx->istack, n + 1);
11✔
5109

5110
  all_false = true;
11✔
5111
  for (i=0; i<n; i++) {
72✔
5112
    // a[i] = condition for pair[i]
5113
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
62✔
5114
    if (a[i] == true_literal) {
62✔
5115
      // if a[i] is true, all other conditions must be false
5116
      assert_term(ctx, c->pair[i].val, tt);
1✔
5117
      goto done;
1✔
5118
    }
5119
    if (a[i] != false_literal) {
61✔
5120
      // l = value for pair[i]
5121
      l = signed_literal(internalize_to_literal(ctx, c->pair[i].val), tt);
58✔
5122
      add_binary_clause(ctx->core, not(a[i]), l); // a[i] => v[i]
58✔
5123
      all_false = false;
58✔
5124
    }
5125
  }
5126

5127
  if (all_false) {
10✔
5128
    // all a[i]s are false: no need for a clause
5129
    assert_term(ctx, c->defval, tt);
1✔
5130
    goto done;
1✔
5131
  }
5132

5133
  // last clause: (a[0] \/ .... \/ a[n] \/ +/-defval)
5134
  a[n] = signed_literal(internalize_to_literal(ctx, c->defval), tt);
9✔
5135
  add_clause(ctx->core, n+1, a);
9✔
5136

5137
  // cleanup
5138
 done:
11✔
5139
  free_istack_array(&ctx->istack, a);
11✔
5140
}
5141

5142

5143

5144
/*
5145
 * Top-level boolean if-then-else (ite c t1 t2)
5146
 * - if tt is true: assert (ite c t1 t2)
5147
 * - if tt is false: assert (not (ite c t1 t2))
5148
 */
5149
static void assert_toplevel_ite(context_t *ctx, composite_term_t *ite, bool tt) {
70✔
5150
  conditional_t *d;
5151
  literal_t l1, l2, l3;
5152

5153
  assert(ite->arity == 3);
5154

5155
  // high-order ite should work. See map_ite_to_eterm
5156

5157
  d = context_make_conditional(ctx, ite);
70✔
5158
  if (d != NULL) {
70✔
5159
    assert_toplevel_conditional(ctx, d, tt);
13✔
5160
    context_free_conditional(ctx, d);
13✔
5161
    return;
13✔
5162
  }
5163

5164
  l1 = internalize_to_literal(ctx, ite->arg[0]);
57✔
5165
  if (l1 == true_literal) {
57✔
5166
    assert_term(ctx, ite->arg[1], tt);
5✔
5167
  } else if (l1 == false_literal) {
52✔
5168
    assert_term(ctx, ite->arg[2], tt);
2✔
5169
  } else {
5170
    l2 = internalize_to_literal(ctx, ite->arg[1]);
50✔
5171
    l3 = internalize_to_literal(ctx, ite->arg[2]);
50✔
5172
    assert_ite(&ctx->gate_manager, l1, l2, l3, tt);
50✔
5173
  }
5174
}
5175

5176

5177
/*
5178
 * Top-level (or t1 ... t_n)
5179
 * - it tt is true: add a clause
5180
 * - it tt is false: assert (not t1) ... (not t_n)
5181
 */
5182
static void assert_toplevel_or(context_t *ctx, composite_term_t *or, bool tt) {
42,971✔
5183
  ivector_t *v;
5184
  int32_t *a;
5185
  uint32_t i, n;
5186

5187
  if (tt) {
42,971✔
5188
    if (context_flatten_or_enabled(ctx)) {
42,955✔
5189
      // Flatten into vector v
5190
      v = &ctx->aux_vector;
15,019✔
5191
      assert(v->size == 0);
5192
      flatten_or_term(ctx, v, or);
15,019✔
5193

5194
      // if v contains a true_term, ignore the clause
5195
      n = v->size;
15,019✔
5196
      if (disjunct_is_true(ctx, v->data, n)) {
15,019✔
5197
        ivector_reset(v);
971✔
5198
        return;
971✔
5199
      }
5200

5201
      // make a copy of v
5202
      a = alloc_istack_array(&ctx->istack, n);
14,048✔
5203
      for (i=0; i<n; i++) {
58,759✔
5204
        a[i] = v->data[i];
44,711✔
5205
      }
5206
      ivector_reset(v);
14,048✔
5207

5208
      for (i=0; i<n; i++) {
58,436✔
5209
        a[i] = internalize_to_literal(ctx, a[i]);
44,541✔
5210
        if (a[i] == true_literal) goto done;
44,541✔
5211
      }
5212

5213
    } else {
5214
      /*
5215
       * No flattening
5216
       */
5217
      n = or->arity;
27,936✔
5218
      if (disjunct_is_true(ctx, or->arg, n)) {
27,936✔
5219
        return;
2,503✔
5220
      }
5221

5222
      a = alloc_istack_array(&ctx->istack, n);
25,433✔
5223
      for (i=0; i<n; i++) {
143,590✔
5224
        a[i] = internalize_to_literal(ctx, or->arg[i]);
118,257✔
5225
        if (a[i] == true_literal) goto done;
118,257✔
5226
      }
5227
    }
5228

5229
    // assert (or a[0] ... a[n-1])
5230
    add_clause(ctx->core, n, a);
39,228✔
5231

5232
  done:
39,481✔
5233
    free_istack_array(&ctx->istack, a);
39,481✔
5234

5235
  } else {
5236
    /*
5237
     * Propagate to children:
5238
     *  (or t_0 ... t_n-1) is false
5239
     * so all children must be false too
5240
     */
5241
    n = or->arity;
16✔
5242
    for (i=0; i<n; i++) {
48✔
5243
      assert_term(ctx, or->arg[i], false);
32✔
5244
    }
5245
  }
5246

5247
}
5248

5249

5250
/*
5251
 * Top-level (xor t1 ... t_n) == tt
5252
 */
5253
static void assert_toplevel_xor(context_t *ctx, composite_term_t *xor, bool tt) {
7✔
5254
  int32_t *a;
5255
  uint32_t i, n;
5256

5257
  n = xor->arity;
7✔
5258
  a = alloc_istack_array(&ctx->istack, n);
7✔
5259
  for (i=0; i<n; i++) {
58✔
5260
    a[i] = internalize_to_literal(ctx, xor->arg[i]);
51✔
5261
  }
5262

5263
  assert_xor(&ctx->gate_manager, n, a, tt);
7✔
5264
  free_istack_array(&ctx->istack, a);
7✔
5265
}
7✔
5266

5267

5268

5269
/*
5270
 * Top-level bit select
5271
 */
5272
static void assert_toplevel_bit_select(context_t *ctx, select_term_t *select, bool tt) {
32,805✔
5273
  term_t t, s;
5274
  thvar_t x;
5275

5276
  /*
5277
   * Check for simplification
5278
   */
5279
  t = intern_tbl_get_root(&ctx->intern, select->arg);
32,805✔
5280
  s = extract_bit(ctx->terms, t, select->idx);
32,805✔
5281
  if (s != NULL_TERM) {
32,805✔
5282
    // (select t i) is s
5283
    assert_term(ctx, s, tt);
63✔
5284
  } else {
5285
    // no simplification
5286
    x = internalize_to_bv(ctx, select->arg);
32,742✔
5287
    ctx->bv.set_bit(ctx->bv_solver, x, select->idx, tt);
32,742✔
5288
  }
5289
}
32,804✔
5290

5291

5292
/*
5293
 * Top-level bitvector atoms
5294
 */
5295
// Auxiliary function: assert (t == 0) or (t != 0) depending on tt
5296
static void assert_toplevel_bveq0(context_t *ctx, term_t t, bool tt) {
41✔
5297
  uint32_t n;
5298
  thvar_t x, y;
5299

5300
  t = intern_tbl_get_root(&ctx->intern, t);
41✔
5301
  n = term_bitsize(ctx->terms, t);
41✔
5302
  x = internalize_to_bv(ctx, t);
41✔
5303
  y = ctx->bv.create_zero(ctx->bv_solver, n);
41✔
5304
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x, y, tt);
41✔
5305
}
41✔
5306

5307

5308
/*
5309
 * Experimental: when t1 and t2 have a common factor C:
5310
 *   t1 = C * u1
5311
 *   t2 = C * u2
5312
 * then we have (t1 /= t2) implies (u1 /= u2).
5313
 * So we can add (u1 /= u2) when (t1 /= t2) is asserted.
5314
 * This is redundant but it may help solving the problem, especially if C is a
5315
 * complex expression.
5316
 */
5317
static void assert_factored_inequality(context_t *ctx, bvfactoring_t *f) {
9✔
5318
  term_t u1, u2;
5319
  thvar_t x, y;
5320

5321
  assert(f->code == BVFACTOR_FOUND);
5322

5323
  //  printf("Asserting factored inequality\n\n");
5324

5325
  u1 = bitvector_factoring_left_term(ctx, f);
9✔
5326
  u2 = bitvector_factoring_right_term(ctx, f);
9✔
5327
  x = internalize_to_bv(ctx, u1);
9✔
5328
  y = internalize_to_bv(ctx, u2);
9✔
5329
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x,  y, false);
9✔
5330
}
9✔
5331

5332
static void assert_toplevel_bveq(context_t *ctx, composite_term_t *eq, bool tt) {
9,370✔
5333
  bveq_simp_t simp;
5334
  ivector_t *v;
5335
  int32_t *a;
5336
  term_t t, t1, t2;
5337
  thvar_t x, y;
5338
  uint32_t i, n;
5339

5340
  assert(eq->arity == 2);
5341

5342
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
9,370✔
5343
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
9,370✔
5344
  t = simplify_bitvector_eq(ctx, t1, t2);
9,370✔
5345
  if (t != NULL_TERM) {
9,370✔
5346
    // (bveq t1 t2) is equivalent to t
5347
    assert_term(ctx, t, tt);
18✔
5348
    return;
74✔
5349
  }
5350

5351
  if (tt) {
9,352✔
5352
    // try to flatten to a conjunction of terms
5353
    v = &ctx->aux_vector;
7,534✔
5354
    assert(v->size == 0);
5355
    if (bveq_flattens(ctx->terms, t1, t2, v)) {
7,534✔
5356
      /*
5357
       * (bveq t1 t2) is equivalent to (and v[0] ... v[k])
5358
       * (bveq t1 t2) is true at the toplevel so v[0] ... v[k] must all be true
5359
       */
5360

5361
      // make a copy of v
5362
      n = v->size;
19✔
5363
      a = alloc_istack_array(&ctx->istack, n);
19✔
5364
      for (i=0; i<n; i++) {
579✔
5365
        a[i] = v->data[i];
560✔
5366
      }
5367
      ivector_reset(v);
19✔
5368

5369
      // assert
5370
      for (i=0; i<n; i++) {
548✔
5371
        assert_term(ctx, a[i], true);
530✔
5372
      }
5373

5374
      free_istack_array(&ctx->istack, a);
18✔
5375
      return;
18✔
5376
    }
5377

5378
    // flattening failed
5379
    ivector_reset(v);
7,515✔
5380
  }
5381

5382
  /*
5383
   * Try more simplifications
5384
   */
5385
  try_arithmetic_bveq_simplification(ctx, &simp, t1, t2);
9,333✔
5386
  switch (simp.code) {
9,333✔
5387
  case BVEQ_CODE_TRUE:
×
5388
    if (!tt) longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5389
    break;
×
5390

5391
  case BVEQ_CODE_FALSE:
×
5392
    if (tt) longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5393
    break;
×
5394

5395
  case BVEQ_CODE_REDUCED:
36✔
5396
    t1 = intern_tbl_get_root(&ctx->intern, simp.left);
36✔
5397
    t2 = intern_tbl_get_root(&ctx->intern, simp.right);
36✔
5398
    break;
36✔
5399

5400
  case BVEQ_CODE_REDUCED0:
41✔
5401
    // reduced to simp.left == 0
5402
    assert_toplevel_bveq0(ctx, simp.left, tt);
41✔
5403
    return;
41✔
5404

5405
  default:
9,256✔
5406
    break;
9,256✔
5407
  }
5408

5409
  /*
5410
   * Try Factoring
5411
   */
5412
  if (!tt) {
9,292✔
5413
    bvfactoring_t *factoring;
5414
    bool eq = false;
1,783✔
5415

5416
    factoring = objstack_alloc(&ctx->ostack, sizeof(bvfactoring_t), (cleaner_t) delete_bvfactoring);
1,783✔
5417
    init_bvfactoring(factoring);
1,783✔
5418

5419
    try_bitvector_factoring(ctx, factoring, t1, t2);
1,783✔
5420
    switch (factoring->code) {
1,783✔
5421
    case BVFACTOR_EQUAL:
4✔
5422
      eq = true;
4✔
5423
      break;
4✔
5424

5425
    case BVFACTOR_FOUND:
9✔
5426
      assert_factored_inequality(ctx, factoring);
9✔
5427
      break;
9✔
5428

5429
    default:
1,770✔
5430
      break;
1,770✔
5431
    }
5432
    // delete_bvfactoring(&factoring);
5433
    objstack_pop(&ctx->ostack);
1,783✔
5434

5435
    if (eq) {
1,783✔
5436
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
5437
    }
5438
  }
5439

5440
  /*
5441
   * NOTE: asserting (eq t1 t2) in the egraph instead makes things worse
5442
   */
5443
  x = internalize_to_bv(ctx, t1);
9,288✔
5444
  y = internalize_to_bv(ctx, t2);
9,288✔
5445
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x,  y, tt);
9,288✔
5446
}
5447

5448
static void assert_toplevel_bvge(context_t *ctx, composite_term_t *ge, bool tt) {
1,488✔
5449
  thvar_t x, y;
5450

5451
  assert(ge->arity == 2);
5452

5453
  x = internalize_to_bv(ctx, ge->arg[0]);
1,488✔
5454
  y = internalize_to_bv(ctx, ge->arg[1]);
1,488✔
5455
  ctx->bv.assert_ge_axiom(ctx->bv_solver, x,  y, tt);
1,488✔
5456
}
1,488✔
5457

5458
static void assert_toplevel_bvsge(context_t *ctx, composite_term_t *sge, bool tt) {
459✔
5459
  thvar_t x, y;
5460

5461
  assert(sge->arity == 2);
5462

5463
  x = internalize_to_bv(ctx, sge->arg[0]);
459✔
5464
  y = internalize_to_bv(ctx, sge->arg[1]);
459✔
5465
  ctx->bv.assert_sge_axiom(ctx->bv_solver, x,  y, tt);
459✔
5466
}
459✔
5467

5468

5469

5470
/*
5471
 * Top-level formula t:
5472
 * - t is a boolean term (or the negation of a boolean term)
5473
 * - t must be a root in the internalization table and must be mapped to true
5474
 */
5475
static void assert_toplevel_formula(context_t *ctx, term_t t) {
125,456✔
5476
  term_table_t *terms;
5477
  int32_t code;
5478
  literal_t l;
5479
  bool tt;
5480

5481
  assert(is_boolean_term(ctx->terms, t) &&
5482
         intern_tbl_is_root(&ctx->intern, t) &&
5483
         term_is_true(ctx, t));
5484

5485
  tt = is_pos_term(t);
125,456✔
5486
  t = unsigned_term(t);
125,456✔
5487

5488
  /*
5489
   * Now: t is a root and has positive polarity
5490
   * - tt indicates whether we assert t or (not t):
5491
   *   tt true: assert t
5492
   *   tt false: assert (not t)
5493
   */
5494
  terms = ctx->terms;
125,456✔
5495
  if (context_atom_requires_mcsat(ctx, t)) {
125,456✔
5496
    l = map_mcsat_atom_to_literal(ctx, t);
14✔
5497
    code = literal2code(l);
14✔
5498
    intern_tbl_remap_root(&ctx->intern, t, code);
14✔
5499
    assert_internalization_code(ctx, code, tt);
14✔
5500
    return;
14✔
5501
  }
5502
  if (ctx->mcsat_supplement) {
125,442✔
5503
    context_observe_mcsat_atom(ctx, t, tt ? true_literal : false_literal);
17✔
5504
  }
5505

5506
  switch (term_kind(terms, t)) {
125,442✔
5507
  case CONSTANT_TERM:
×
5508
  case UNINTERPRETED_TERM:
5509
    // should be eliminated by flattening
5510
    code = INTERNAL_ERROR;
×
5511
    goto abort;
×
5512

5513
  case ITE_TERM:
68✔
5514
  case ITE_SPECIAL:
5515
    assert_toplevel_ite(ctx, ite_term_desc(terms, t), tt);
68✔
5516
    break;
68✔
5517

5518
  case OR_TERM:
42,940✔
5519
    assert_toplevel_or(ctx, or_term_desc(terms, t), tt);
42,940✔
5520
    break;
42,940✔
5521

5522
  case XOR_TERM:
7✔
5523
    assert_toplevel_xor(ctx, xor_term_desc(terms, t), tt);
7✔
5524
    break;
7✔
5525

5526
  case EQ_TERM:
5,145✔
5527
    assert_toplevel_eq(ctx, eq_term_desc(terms, t), tt);
5,145✔
5528
    break;
5,143✔
5529

5530
  case ARITH_IS_INT_ATOM:
×
5531
    assert_toplevel_arith_is_int(ctx, arith_is_int_arg(terms, t), tt);
×
5532
    break;
×
5533

5534
  case ARITH_EQ_ATOM:
2,266✔
5535
    assert_toplevel_arith_eq(ctx, arith_eq_arg(terms, t), tt);
2,266✔
5536
    break;
2,264✔
5537

5538
  case ARITH_GE_ATOM:
27,851✔
5539
    assert_toplevel_arith_geq(ctx, arith_ge_arg(terms, t), tt);
27,851✔
5540
    break;
27,850✔
5541

5542
  case ARITH_BINEQ_ATOM:
3,208✔
5543
    assert_toplevel_arith_bineq(ctx, arith_bineq_atom_desc(terms, t), tt);
3,208✔
5544
    break;
3,208✔
5545

5546
  case ARITH_DIVIDES_ATOM:
×
5547
    assert_toplevel_arith_divides(ctx, arith_divides_atom_desc(terms, t), tt);
×
5548
    break;
×
5549

5550
  case APP_TERM:
250✔
5551
    assert_toplevel_apply(ctx, app_term_desc(terms, t), tt);
250✔
5552
    break;
250✔
5553

5554
  case SELECT_TERM:
×
5555
    assert_toplevel_select(ctx, select_term_desc(terms, t), tt);
×
5556
    break;
×
5557

5558
  case DISTINCT_TERM:
173✔
5559
    assert_toplevel_distinct(ctx, distinct_term_desc(terms, t), tt);
173✔
5560
    break;
171✔
5561

5562
  case VARIABLE:
×
5563
    code = FREE_VARIABLE_IN_FORMULA;
×
5564
    goto abort;
×
5565

5566
  case FORALL_TERM:
×
5567
    if (context_in_strict_mode(ctx)) {
×
5568
      code = QUANTIFIERS_NOT_SUPPORTED;
×
5569
      goto abort;
×
5570
    }
5571
    break;
×
5572

5573
  case BIT_TERM:
32,262✔
5574
    assert_toplevel_bit_select(ctx, bit_term_desc(terms, t), tt);
32,262✔
5575
    break;
32,262✔
5576

5577
  case BV_EQ_ATOM:
9,331✔
5578
    assert_toplevel_bveq(ctx, bveq_atom_desc(terms, t), tt);
9,331✔
5579
    break;
9,323✔
5580

5581
  case BV_GE_ATOM:
1,486✔
5582
    assert_toplevel_bvge(ctx, bvge_atom_desc(terms, t), tt);
1,486✔
5583
    break;
1,486✔
5584

5585
  case BV_SGE_ATOM:
455✔
5586
    assert_toplevel_bvsge(ctx, bvsge_atom_desc(terms, t), tt);
455✔
5587
    break;
455✔
5588

5589
  default:
×
5590
    code = INTERNAL_ERROR;
×
5591
    goto abort;
×
5592
  }
5593

5594
  return;
125,427✔
5595

5596
 abort:
×
5597
  longjmp(ctx->env, code);
×
5598
}
5599

5600

5601

5602
/*
5603
 * Assert (t == tt) for a boolean term t:
5604
 * - if t is not internalized, record the mapping
5605
 *   (root t) --> tt in the internalization table
5606
 */
5607
static void assert_term(context_t *ctx, term_t t, bool tt) {
998✔
5608
  term_table_t *terms;
5609
  int32_t code;
5610
  literal_t l;
5611

5612
  assert(is_boolean_term(ctx->terms, t));
5613

5614
  /*
5615
   * Apply substitution + fix polarity
5616
   */
5617
  t = intern_tbl_get_root(&ctx->intern, t);
998✔
5618
  tt ^= is_neg_term(t);
998✔
5619
  t = unsigned_term(t);
998✔
5620

5621
  if (intern_tbl_root_is_mapped(&ctx->intern, t)) {
998✔
5622
    /*
5623
     * The root is already mapped:
5624
     * Either t is already internalized, or it occurs in
5625
     * one of the vectors top_eqs, top_atoms, top_formulas
5626
     * and it will be internalized/asserted later.
5627
     */
5628
    code = intern_tbl_map_of_root(&ctx->intern, t);
171✔
5629
    assert_internalization_code(ctx, code, tt);
171✔
5630

5631
  } else {
5632
    if (context_atom_requires_mcsat(ctx, t)) {
827✔
NEW
5633
      l = map_mcsat_atom_to_literal(ctx, t);
×
NEW
5634
      code = literal2code(l);
×
NEW
5635
      intern_tbl_map_root(&ctx->intern, t, code);
×
NEW
5636
      assert_internalization_code(ctx, code, tt);
×
NEW
5637
      return;
×
5638
    }
5639
    if (ctx->mcsat_supplement) {
827✔
NEW
5640
      context_observe_mcsat_atom(ctx, t, tt ? true_literal : false_literal);
×
5641
    }
5642

5643
    // store the mapping t --> tt
5644
    intern_tbl_map_root(&ctx->intern, t, bool2code(tt));
827✔
5645

5646
    // internalize and assert
5647
    terms = ctx->terms;
827✔
5648
    switch (term_kind(terms, t)) {
827✔
5649
    case CONSTANT_TERM:
×
5650
      // should always be internalized
5651
      code = INTERNAL_ERROR;
×
5652
      goto abort;
×
5653

5654
    case UNINTERPRETED_TERM:
1✔
5655
      // nothing to do: t --> true/false in the internalization table
5656
      break;
1✔
5657

5658
    case ITE_TERM:
2✔
5659
    case ITE_SPECIAL:
5660
      assert_toplevel_ite(ctx, ite_term_desc(terms, t), tt);
2✔
5661
      break;
2✔
5662

5663
    case OR_TERM:
31✔
5664
      assert_toplevel_or(ctx, or_term_desc(terms, t), tt);
31✔
5665
      break;
31✔
5666

5667
    case XOR_TERM:
×
5668
      assert_toplevel_xor(ctx, xor_term_desc(terms, t), tt);
×
5669
      break;
×
5670

5671
    case EQ_TERM:
11✔
5672
      assert_toplevel_eq(ctx, eq_term_desc(terms, t), tt);
11✔
5673
      break;
11✔
5674

5675
    case ARITH_IS_INT_ATOM:
×
5676
      assert_toplevel_arith_is_int(ctx, arith_is_int_arg(terms, t), tt);
×
5677
      break;
×
5678

5679
    case ARITH_EQ_ATOM:
4✔
5680
      assert_toplevel_arith_eq(ctx, arith_eq_arg(terms, t), tt);
4✔
5681
      break;
4✔
5682

5683
    case ARITH_GE_ATOM:
7✔
5684
      assert_toplevel_arith_geq(ctx, arith_ge_arg(terms, t), tt);
7✔
5685
      break;
7✔
5686

5687
    case ARITH_BINEQ_ATOM:
181✔
5688
      assert_toplevel_arith_bineq(ctx, arith_bineq_atom_desc(terms, t), tt);
181✔
5689
      break;
181✔
5690

5691
    case ARITH_DIVIDES_ATOM:
×
5692
      assert_toplevel_arith_divides(ctx, arith_divides_atom_desc(terms, t), tt);
×
5693
      break;
×
5694

5695
    case APP_TERM:
2✔
5696
      assert_toplevel_apply(ctx, app_term_desc(terms, t), tt);
2✔
5697
      break;
2✔
5698

5699
    case SELECT_TERM:
×
5700
      assert_toplevel_select(ctx, select_term_desc(terms, t), tt);
×
5701
      break;
×
5702

5703
    case DISTINCT_TERM:
×
5704
      assert_toplevel_distinct(ctx, distinct_term_desc(terms, t), tt);
×
5705
      break;
×
5706

5707
    case VARIABLE:
×
5708
      code = FREE_VARIABLE_IN_FORMULA;
×
5709
      goto abort;
×
5710

5711
    case FORALL_TERM:
×
5712
      if (context_in_strict_mode(ctx)) {
×
5713
        code = QUANTIFIERS_NOT_SUPPORTED;
×
5714
        goto abort;
×
5715
      }
5716
      break;
×
5717

5718
    case BIT_TERM:
543✔
5719
      assert_toplevel_bit_select(ctx, bit_term_desc(terms, t), tt);
543✔
5720
      break;
542✔
5721

5722
    case BV_EQ_ATOM:
39✔
5723
      assert_toplevel_bveq(ctx, bveq_atom_desc(terms, t), tt);
39✔
5724
      break;
39✔
5725

5726
    case BV_GE_ATOM:
2✔
5727
      assert_toplevel_bvge(ctx, bvge_atom_desc(terms, t), tt);
2✔
5728
      break;
2✔
5729

5730
    case BV_SGE_ATOM:
4✔
5731
      assert_toplevel_bvsge(ctx, bvsge_atom_desc(terms, t), tt);
4✔
5732
      break;
4✔
5733

5734
    default:
×
5735
      code = INTERNAL_ERROR;
×
5736
      goto abort;
×
5737
    }
5738
  }
5739

5740
  return;
993✔
5741

5742
 abort:
×
5743
  longjmp(ctx->env, code);
×
5744
}
5745

5746

5747

5748

5749
/************************
5750
 *  PARAMETERS/OPTIONS  *
5751
 ***********************/
5752

5753
/*
5754
 * Map architecture id to theories word
5755
 */
5756
static const uint32_t arch2theories[NUM_ARCH] = {
5757
  0,                           //  CTX_ARCH_NOSOLVERS --> empty theory
5758

5759
  UF_MASK,                     //  CTX_ARCH_EG
5760
  ARITH_MASK,                  //  CTX_ARCH_SPLX
5761
  IDL_MASK,                    //  CTX_ARCH_IFW
5762
  RDL_MASK,                    //  CTX_ARCH_RFW
5763
  BV_MASK,                     //  CTX_ARCH_BV
5764
  UF_MASK|FUN_MASK,            //  CTX_ARCH_EGFUN
5765
  UF_MASK|ARITH_MASK,          //  CTX_ARCH_EGSPLX
5766
  UF_MASK|BV_MASK,             //  CTX_ARCH_EGBV
5767
  UF_MASK|ARITH_MASK|FUN_MASK, //  CTX_ARCH_EGFUNSPLX
5768
  UF_MASK|BV_MASK|FUN_MASK,    //  CTX_ARCH_EGFUNBV
5769
  UF_MASK|BV_MASK|ARITH_MASK,  //  CTX_ARCH_EGSPLXBV
5770
  ALLTH_MASK,                  //  CTX_ARCH_EGFUNSPLXBV
5771

5772
  IDL_MASK,                    //  CTX_ARCH_AUTO_IDL
5773
  RDL_MASK,                    //  CTX_ARCH_AUTO_RDL
5774

5775
  UF_MASK|ARITH_MASK|FUN_MASK  //  CTX_ARCH_MCSAT
5776
};
5777

5778

5779
/*
5780
 * Each architecture has a fixed set of solver components:
5781
 * - the set of components is stored as a bit vector (on 8bits)
5782
 * - this uses the following bit-masks
5783
 * For the AUTO_xxx architecture, nothing is required initially,
5784
 * so the bitmask is 0.
5785
 */
5786
#define EGRPH  0x1
5787
#define SPLX   0x2
5788
#define IFW    0x4
5789
#define RFW    0x8
5790
#define BVSLVR 0x10
5791
#define FSLVR  0x20
5792
#define MCSAT  0x40
5793

5794
static const uint8_t arch_components[NUM_ARCH] = {
5795
  0,                        //  CTX_ARCH_NOSOLVERS
5796

5797
  EGRPH,                    //  CTX_ARCH_EG
5798
  SPLX,                     //  CTX_ARCH_SPLX
5799
  IFW,                      //  CTX_ARCH_IFW
5800
  RFW,                      //  CTX_ARCH_RFW
5801
  BVSLVR,                   //  CTX_ARCH_BV
5802
  EGRPH|FSLVR,              //  CTX_ARCH_EGFUN
5803
  EGRPH|SPLX,               //  CTX_ARCH_EGSPLX
5804
  EGRPH|BVSLVR,             //  CTX_ARCH_EGBV
5805
  EGRPH|SPLX|FSLVR,         //  CTX_ARCH_EGFUNSPLX
5806
  EGRPH|BVSLVR|FSLVR,       //  CTX_ARCH_EGFUNBV
5807
  EGRPH|SPLX|BVSLVR,        //  CTX_ARCH_EGSPLXBV
5808
  EGRPH|SPLX|BVSLVR|FSLVR,  //  CTX_ARCH_EGFUNSPLXBV
5809

5810
  0,                        //  CTX_ARCH_AUTO_IDL
5811
  0,                        //  CTX_ARCH_AUTO_RDL
5812

5813
  MCSAT                     //  CTX_ARCH_MCSAT
5814
};
5815

5816

5817
/*
5818
 * Smt mode for a context mode
5819
 */
5820
static const smt_mode_t core_mode[NUM_MODES] = {
5821
  SMT_MODE_BASIC,       // one check
5822
  SMT_MODE_BASIC,       // multichecks
5823
  SMT_MODE_PUSHPOP,     // push/pop
5824
  SMT_MODE_INTERACTIVE, // interactive
5825
};
5826

5827

5828
/*
5829
 * Flags for a context mode
5830
 */
5831
static const uint32_t mode2options[NUM_MODES] = {
5832
  0,
5833
  MULTICHECKS_OPTION_MASK,
5834
  MULTICHECKS_OPTION_MASK|PUSHPOP_OPTION_MASK,
5835
  MULTICHECKS_OPTION_MASK|PUSHPOP_OPTION_MASK|CLEANINT_OPTION_MASK,
5836
};
5837

5838

5839

5840

5841

5842

5843
/*
5844
 * SIMPLEX OPTIONS
5845
 */
5846

5847
/*
5848
 * Which version of the arithmetic solver is present
5849
 */
5850
bool context_has_idl_solver(context_t *ctx) {
8✔
5851
  uint8_t solvers;
5852
  solvers = arch_components[ctx->arch];
8✔
5853
  return ctx->arith_solver != NULL && (solvers & IFW);
8✔
5854
}
5855

5856
bool context_has_rdl_solver(context_t *ctx) {
×
5857
  uint8_t solvers;
5858
  solvers = arch_components[ctx->arch];
×
5859
  return ctx->arith_solver != NULL && (solvers & RFW);
×
5860
}
5861

5862
bool context_has_simplex_solver(context_t *ctx) {
45,892✔
5863
  uint8_t solvers;
5864
  solvers = arch_components[ctx->arch];
45,892✔
5865
  return ctx->arith_solver != NULL && (solvers & SPLX);
45,892✔
5866
}
5867

5868

5869
/*
5870
 * If the simplex solver already exists, the options are propagated.
5871
 * Otherwise, they are recorded into the option flags. They will
5872
 * be set up when the simplex solver is created.
5873
 */
5874
void enable_splx_eager_lemmas(context_t *ctx) {
179✔
5875
  ctx->options |= SPLX_EGRLMAS_OPTION_MASK;
179✔
5876
  if (context_has_simplex_solver(ctx)) {
179✔
5877
    simplex_enable_eager_lemmas(ctx->arith_solver);
179✔
5878
  }
5879
}
179✔
5880

5881
void disable_splx_eager_lemmas(context_t *ctx) {
×
5882
  ctx->options &= ~SPLX_EGRLMAS_OPTION_MASK;
×
5883
  if (context_has_simplex_solver(ctx)) {
×
5884
    simplex_disable_eager_lemmas(ctx->arith_solver);
×
5885
  }
5886
}
×
5887

5888

5889
void enable_splx_periodic_icheck(context_t *ctx) {
153✔
5890
  ctx->options |= SPLX_ICHECK_OPTION_MASK;
153✔
5891
  if (context_has_simplex_solver(ctx)) {
153✔
5892
    simplex_enable_periodic_icheck(ctx->arith_solver);
142✔
5893
  }
5894
}
153✔
5895

5896
void disable_splx_periodic_icheck(context_t *ctx) {
×
5897
  ctx->options &= ~SPLX_ICHECK_OPTION_MASK;
×
5898
  if (context_has_simplex_solver(ctx)) {
×
5899
    simplex_disable_periodic_icheck(ctx->arith_solver);
×
5900
  }
5901
}
×
5902

5903
void enable_splx_eqprop(context_t *ctx) {
78✔
5904
  ctx->options |= SPLX_EQPROP_OPTION_MASK;
78✔
5905
  if (context_has_simplex_solver(ctx)) {
78✔
5906
    simplex_enable_eqprop(ctx->arith_solver);
78✔
5907
  }
5908
}
78✔
5909

5910
void disable_splx_eqprop(context_t *ctx) {
×
5911
  ctx->options &= ~SPLX_EQPROP_OPTION_MASK;
×
5912
  if (context_has_simplex_solver(ctx)) {
×
5913
    simplex_disable_eqprop(ctx->arith_solver);
×
5914
  }
5915
}
×
5916

5917

5918

5919

5920
/******************
5921
 *  EMPTY SOLVER  *
5922
 *****************/
5923

5924
/*
5925
 * We need an empty theory solver for initializing
5926
 * the core if the architecture is NOSOLVERS.
5927
 */
5928
static void donothing(void *solver) {
2,609✔
5929
}
2,609✔
5930

5931
static void null_backtrack(void *solver, uint32_t backlevel) {
×
5932
}
×
5933

5934
static bool null_propagate(void *solver) {
×
5935
  return true;
×
5936
}
5937

5938
static fcheck_code_t null_final_check(void *solver) {
×
5939
  return FCHECK_SAT;
×
5940
}
5941

5942
static th_ctrl_interface_t null_ctrl = {
5943
  donothing,        // start_internalization
5944
  donothing,        // start_search
5945
  null_propagate,   // propagate
5946
  null_final_check, // final check
5947
  donothing,        // increase_decision_level
5948
  null_backtrack,   // backtrack
5949
  donothing,        // push
5950
  donothing,        // pop
5951
  donothing,        // reset
5952
  donothing,        // clear
5953
};
5954

5955

5956
// for the smt interface, nothing should be called since there are no atoms
5957
static th_smt_interface_t null_smt = {
5958
  NULL, NULL, NULL, NULL, NULL,
5959
};
5960

5961

5962

5963

5964
/****************************
5965
 *  ARCHITECTURE & SOLVERS  *
5966
 ***************************/
5967

5968
/*
5969
 * Check whether a given architecture includes a specific solver
5970
 */
5971
bool context_arch_has_egraph(context_arch_t arch) {
417✔
5972
  return arch_components[arch] & EGRPH;
417✔
5973
}
5974

5975
bool context_arch_has_bv(context_arch_t arch) {
×
5976
  return arch_components[arch] & BVSLVR;
×
5977
}
5978

5979
bool context_arch_has_fun(context_arch_t arch) {
×
5980
  return arch_components[arch] & FSLVR;
×
5981
}
5982

5983
bool context_arch_has_arith(context_arch_t arch) {
×
5984
  return arch_components[arch] & (SPLX|IFW|RFW);
×
5985
}
5986

5987
bool context_arch_has_mcsat(context_arch_t arch) {
×
5988
  return arch_components[arch] & MCSAT;
×
5989
}
5990

5991
bool context_arch_has_simplex(context_arch_t arch) {
×
5992
  return arch_components[arch] & SPLX;
×
5993
}
5994

5995
bool context_arch_has_ifw(context_arch_t arch) {
×
5996
  return arch_components[arch] & IFW;
×
5997
}
5998

5999
bool context_arch_has_rfw(context_arch_t arch) {
×
6000
  return arch_components[arch] & RFW;
×
6001
}
6002

6003

6004
/****************************
6005
 *  SOLVER INITIALIZATION   *
6006
 ***************************/
6007

6008
/*
6009
 * Create and initialize the egraph
6010
 * - the core must be created first
6011
 */
6012
static void create_egraph(context_t *ctx) {
4,795✔
6013
  egraph_t *egraph;
6014

6015
  assert(ctx->egraph == NULL);
6016

6017
  egraph = (egraph_t *) safe_malloc(sizeof(egraph_t));
4,795✔
6018
  init_egraph(egraph, ctx->types);
4,795✔
6019
  ctx->egraph = egraph;
4,795✔
6020
}
4,795✔
6021

6022

6023
/*
6024
 * Create and initialize the mcsat solver
6025
 */
6026
static void create_mcsat(context_t *ctx) {
748✔
6027
  assert(ctx->mcsat == NULL);
6028
  ctx->mcsat = mcsat_new(ctx);
748✔
6029
}
748✔
6030

6031

6032

6033
/*
6034
 * Create and initialize the idl solver and attach it to the core
6035
 * - there must be no other solvers and no egraph
6036
 * - if automatic is true, attach the solver to the core, otherwise
6037
 *   initialize the core
6038
 * - copy the solver's internalization interface into arith
6039
 */
6040
static void create_idl_solver(context_t *ctx, bool automatic) {
26✔
6041
  idl_solver_t *solver;
6042
  smt_mode_t cmode;
6043

6044
  assert(ctx->egraph == NULL && ctx->arith_solver == NULL && ctx->bv_solver == NULL &&
6045
         ctx->fun_solver == NULL && ctx->core != NULL);
6046

6047
  cmode = core_mode[ctx->mode];
26✔
6048
  solver = (idl_solver_t *) safe_malloc(sizeof(idl_solver_t));
26✔
6049
  init_idl_solver(solver, ctx->core, &ctx->gate_manager);
26✔
6050
  if (automatic) {
26✔
6051
    smt_core_reset_thsolver(ctx->core, solver, idl_ctrl_interface(solver),
26✔
6052
                            idl_smt_interface(solver));
6053
  } else {
6054
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, idl_ctrl_interface(solver),
×
6055
                  idl_smt_interface(solver), cmode);
6056
  }
6057
  idl_solver_init_jmpbuf(solver, &ctx->env);
26✔
6058
  ctx->arith_solver = solver;
26✔
6059
  ctx->arith = *idl_arith_interface(solver);
26✔
6060
}
26✔
6061

6062

6063
/*
6064
 * Create and initialize the rdl solver and attach it to the core.
6065
 * - there must be no other solvers and no egraph
6066
 * - if automatic is true, attach rdl to the core, otherwise
6067
 *   initialize the core
6068
 * - copy the solver's internalization interface in ctx->arith
6069
 */
6070
static void create_rdl_solver(context_t *ctx, bool automatic) {
8✔
6071
  rdl_solver_t *solver;
6072
  smt_mode_t cmode;
6073

6074
  assert(ctx->egraph == NULL && ctx->arith_solver == NULL && ctx->bv_solver == NULL &&
6075
         ctx->fun_solver == NULL && ctx->core != NULL);
6076

6077
  cmode = core_mode[ctx->mode];
8✔
6078
  solver = (rdl_solver_t *) safe_malloc(sizeof(rdl_solver_t));
8✔
6079
  init_rdl_solver(solver, ctx->core, &ctx->gate_manager);
8✔
6080
  if (automatic) {
8✔
6081
    smt_core_reset_thsolver(ctx->core, solver, rdl_ctrl_interface(solver),
8✔
6082
                            rdl_smt_interface(solver));
6083
  } else {
6084
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, rdl_ctrl_interface(solver),
×
6085
                  rdl_smt_interface(solver), cmode);
6086
  }
6087
  rdl_solver_init_jmpbuf(solver, &ctx->env);
8✔
6088
  ctx->arith_solver = solver;
8✔
6089
  ctx->arith = *rdl_arith_interface(solver);
8✔
6090
}
8✔
6091

6092

6093
/*
6094
 * Create an initialize the simplex solver and attach it to the core
6095
 * or to the egraph if the egraph exists.
6096
 * - if automatic is true, this is part of auto_idl or auto_rdl. So the
6097
 *   core is already initialized.
6098
 */
6099
static void create_simplex_solver(context_t *ctx, bool automatic) {
14,911✔
6100
  simplex_solver_t *solver;
6101
  smt_mode_t cmode;
6102

6103
  assert(ctx->arith_solver == NULL && ctx->core != NULL);
6104

6105
  cmode = core_mode[ctx->mode];
14,911✔
6106
  solver = (simplex_solver_t *) safe_malloc(sizeof(simplex_solver_t));
14,911✔
6107
  init_simplex_solver(solver, ctx->core, &ctx->gate_manager, ctx->egraph);
14,911✔
6108

6109
  // set simplex options
6110
  if (splx_eager_lemmas_enabled(ctx)) {
14,911✔
6111
    simplex_enable_eager_lemmas(solver);
×
6112
  }
6113
  if (splx_periodic_icheck_enabled(ctx)) {
14,911✔
6114
    simplex_enable_periodic_icheck(solver);
×
6115
  }
6116
  if (splx_eqprop_enabled(ctx)) {
14,911✔
6117
    simplex_enable_eqprop(solver);
×
6118
  }
6119

6120
  // row saving must be enabled unless we're in ONECHECK mode
6121
  if (ctx->mode != CTX_MODE_ONECHECK) {
14,911✔
6122
    simplex_enable_row_saving(solver);
14,758✔
6123
  }
6124

6125
  if (ctx->egraph != NULL) {
14,911✔
6126
    // attach the simplex solver as a satellite solver to the egraph
6127
    egraph_attach_arithsolver(ctx->egraph, solver, simplex_ctrl_interface(solver),
4,338✔
6128
                              simplex_smt_interface(solver), simplex_egraph_interface(solver),
6129
                              simplex_arith_egraph_interface(solver));
6130
  } else if (!automatic) {
10,573✔
6131
    // attach simplex to the core and initialize the core
6132
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, simplex_ctrl_interface(solver),
10,572✔
6133
                  simplex_smt_interface(solver), cmode);
6134
  } else {
6135
    // the core is already initialized: attach simplex
6136
    smt_core_reset_thsolver(ctx->core, solver, simplex_ctrl_interface(solver),
1✔
6137
                            simplex_smt_interface(solver));
6138
  }
6139

6140
  simplex_solver_init_jmpbuf(solver, &ctx->env);
14,911✔
6141
  ctx->arith_solver = solver;
14,911✔
6142
  ctx->arith = *simplex_arith_interface(solver);
14,911✔
6143
}
14,911✔
6144

6145

6146
/*
6147
 * Create IDL/SIMPLEX solver based on ctx->dl_profile
6148
 */
6149
static void create_auto_idl_solver(context_t *ctx) {
27✔
6150
  dl_data_t *profile;
6151
  int32_t bound;
6152
  double atom_density;
6153

6154
  assert(ctx->dl_profile != NULL);
6155
  profile = ctx->dl_profile;
27✔
6156

6157
  if (q_is_smallint(&profile->path_bound)) {
27✔
6158
    bound = q_get_smallint(&profile->path_bound);
26✔
6159
  } else {
6160
    bound = INT32_MAX;
1✔
6161
  }
6162

6163
  if (bound >= 1073741824) {
27✔
6164
    // simplex required because of arithmetic overflow
6165
    create_simplex_solver(ctx, true);
1✔
6166
    ctx->arch = CTX_ARCH_SPLX;
1✔
6167
  } else if (profile->num_vars >= 1000) {
26✔
6168
    // too many variables for FW
6169
    create_simplex_solver(ctx, true);
×
6170
    ctx->arch = CTX_ARCH_SPLX;
×
6171
  } else if (profile->num_vars <= 200 || profile->num_eqs == 0) {
26✔
6172
    // use FW for now, until we've tested SIMPLEX more
6173
    // 0 equalities usually means a scheduling problem
6174
    // --flatten works better on IDL/FW
6175
    create_idl_solver(ctx, true);
26✔
6176
    ctx->arch = CTX_ARCH_IFW;
26✔
6177
    enable_diseq_and_or_flattening(ctx);
26✔
6178

6179
  } else {
6180

6181
    // problem density
6182
    if (profile->num_vars > 0) {
×
6183
      atom_density = ((double) profile->num_atoms)/profile->num_vars;
×
6184
    } else {
6185
      atom_density = 0;
×
6186
    }
6187

6188
    if (atom_density >= 10.0) {
×
6189
      // high density: use FW
6190
      create_idl_solver(ctx, true);
×
6191
      ctx->arch = CTX_ARCH_IFW;
×
6192
      enable_diseq_and_or_flattening(ctx);
×
6193
    } else {
6194
      create_simplex_solver(ctx, true);
×
6195
      ctx->arch = CTX_ARCH_SPLX;
×
6196
    }
6197
  }
6198
}
27✔
6199

6200

6201
/*
6202
 * Create RDL/SIMPLEX solver based on ctx->dl_profile
6203
 */
6204
static void create_auto_rdl_solver(context_t *ctx) {
8✔
6205
  dl_data_t *profile;
6206
  double atom_density;
6207

6208
  assert(ctx->dl_profile != NULL);
6209
  profile = ctx->dl_profile;
8✔
6210

6211
  if (profile->num_vars >= 1000) {
8✔
6212
    create_simplex_solver(ctx, true);
×
6213
    ctx->arch = CTX_ARCH_SPLX;
×
6214
  } else if (profile->num_vars <= 200 || profile->num_eqs == 0) {
8✔
6215
    create_rdl_solver(ctx, true);
8✔
6216
    ctx->arch = CTX_ARCH_RFW;
8✔
6217
  } else {
6218
    // problem density
6219
    if (profile->num_vars > 0) {
×
6220
      atom_density = ((double) profile->num_atoms)/profile->num_vars;
×
6221
    } else {
6222
      atom_density = 0;
×
6223
    }
6224

6225
    if (atom_density >= 7.0) {
×
6226
      // high density: use FW
6227
      create_rdl_solver(ctx, true);
×
6228
      ctx->arch = CTX_ARCH_RFW;
×
6229
    } else {
6230
      // low-density: use SIMPLEX
6231
      create_simplex_solver(ctx, true);
×
6232
      ctx->arch = CTX_ARCH_SPLX;
×
6233
    }
6234
  }
6235
}
8✔
6236

6237

6238

6239
/*
6240
 * Create the bitvector solver
6241
 * - attach it to the egraph if there's an egraph
6242
 * - attach it to the core and initialize the core otherwise
6243
 */
6244
static void create_bv_solver(context_t *ctx) {
10,687✔
6245
  bv_solver_t *solver;
6246
  smt_mode_t cmode;
6247

6248
  assert(ctx->bv_solver == NULL && ctx->core != NULL);
6249

6250
  cmode = core_mode[ctx->mode];
10,687✔
6251
  solver = (bv_solver_t *) safe_malloc(sizeof(bv_solver_t));
10,687✔
6252
  init_bv_solver(solver, ctx->core, ctx->egraph);
10,687✔
6253

6254
  if (ctx->egraph != NULL) {
10,687✔
6255
    // attach as a satellite to the egraph
6256
    egraph_attach_bvsolver(ctx->egraph, solver, bv_solver_ctrl_interface(solver),
4,420✔
6257
                           bv_solver_smt_interface(solver), bv_solver_egraph_interface(solver),
6258
                           bv_solver_bv_egraph_interface(solver));
6259
  } else {
6260
    // attach to the core and initialize the core
6261
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, bv_solver_ctrl_interface(solver),
6,267✔
6262
                  bv_solver_smt_interface(solver), cmode);
6263
  }
6264

6265
  // EXPERIMENT
6266
  //  smt_core_make_etable(ctx->core);
6267
  // END
6268

6269
  bv_solver_init_jmpbuf(solver, &ctx->env);
10,687✔
6270
  ctx->bv_solver = solver;
10,687✔
6271
  ctx->bv = *bv_solver_bv_interface(solver);
10,687✔
6272
}
10,687✔
6273

6274

6275
/*
6276
 * Create the array/function theory solver and attach it to the egraph
6277
 */
6278
static void create_fun_solver(context_t *ctx) {
4,427✔
6279
  fun_solver_t *solver;
6280

6281
  assert(ctx->egraph != NULL && ctx->fun_solver == NULL);
6282

6283
  solver = (fun_solver_t *) safe_malloc(sizeof(fun_solver_t));
4,427✔
6284
  init_fun_solver(solver, ctx->core, &ctx->gate_manager, ctx->egraph, ctx->types);
4,427✔
6285
  egraph_attach_funsolver(ctx->egraph, solver, fun_solver_ctrl_interface(solver),
4,427✔
6286
                          fun_solver_egraph_interface(solver),
6287
                          fun_solver_fun_egraph_interface(solver));
6288

6289
  ctx->fun_solver = solver;
4,427✔
6290
}
4,427✔
6291

6292

6293
/*
6294
 * Allocate and initialize solvers based on architecture and mode
6295
 * - core and gate manager must exist at this point
6296
 * - if the architecture is either AUTO_IDL or AUTO_RDL, no theory solver
6297
 *   is allocated yet, and the core is initialized for Boolean only
6298
 * - otherwise, all components are ready and initialized, including the core.
6299
 */
6300
static void init_solvers(context_t *ctx) {
22,418✔
6301
  uint8_t solvers;
6302
  smt_core_t *core;
6303
  smt_mode_t cmode;
6304
  egraph_t *egraph;
6305

6306
  solvers = arch_components[ctx->arch];
22,418✔
6307

6308
  ctx->egraph = NULL;
22,418✔
6309
  ctx->arith_solver = NULL;
22,418✔
6310
  ctx->bv_solver = NULL;
22,418✔
6311
  ctx->fun_solver = NULL;
22,418✔
6312
  ctx->quant_solver = NULL;
22,418✔
6313
  ctx->mcsat_supplement = false;
22,418✔
6314

6315
  // Create egraph first, then satellite solvers
6316
  if (solvers & EGRPH) {
22,418✔
6317
    create_egraph(ctx);
4,795✔
6318
  }
6319

6320
  // Create mcsat
6321
  if (solvers & MCSAT) {
22,418✔
6322
    create_mcsat(ctx);
748✔
6323
  }
6324

6325
  // Arithmetic solver
6326
  if (solvers & SPLX) {
22,418✔
6327
    create_simplex_solver(ctx, false);
14,910✔
6328
  } else if (solvers & IFW) {
7,508✔
6329
    create_idl_solver(ctx, false);
×
6330
  } else if (solvers & RFW) {
7,508✔
6331
    create_rdl_solver(ctx, false);
×
6332
  }
6333

6334
  // Bitvector solver
6335
  if (solvers & BVSLVR) {
22,418✔
6336
    create_bv_solver(ctx);
10,687✔
6337
  }
6338

6339
  // Array solver
6340
  if (solvers & FSLVR) {
22,418✔
6341
    create_fun_solver(ctx);
4,427✔
6342
  }
6343

6344
  /*
6345
   * At this point all solvers are ready and initialized, except the
6346
   * egraph and core if the egraph is present or the core if there are
6347
   * no solvers, or if arch is AUTO_IDL or AUTO_RDL.
6348
   */
6349
  cmode = core_mode[ctx->mode];   // initialization mode for the core
22,418✔
6350
  egraph = ctx->egraph;
22,418✔
6351
  core = ctx->core;
22,418✔
6352
  if (egraph != NULL) {
22,418✔
6353
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, egraph, egraph_ctrl_interface(egraph),
4,795✔
6354
                  egraph_smt_interface(egraph), cmode);
6355
    egraph_attach_core(egraph, core);
4,795✔
6356

6357
  } else if (solvers == 0) {
17,623✔
6358
    /*
6359
     * Boolean solver only. If arch if AUTO_IDL or AUTO_RDL, the
6360
     * theory solver will be changed later by create_auto_idl_solver
6361
     * or create_auto_rdl_solver.
6362
     */
6363
    assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL);
6364
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, NULL, &null_ctrl, &null_smt, cmode);
36✔
6365
  } else if (solvers == MCSAT) {
17,587✔
6366
    /*
6367
     * MCsat solver only, we create the core, but never use it.
6368
     */
6369
    assert(ctx->egraph == NULL && ctx->arith_solver == NULL &&
6370
           ctx->bv_solver == NULL && ctx->fun_solver == NULL);
6371
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, NULL, &null_ctrl, &null_smt, cmode);
748✔
6372
  }
6373

6374
  /*
6375
   * Optimization: if the arch is NOSOLVERS or BV then we set bool_only in the core
6376
   */
6377
  if (ctx->arch == CTX_ARCH_NOSOLVERS || ctx->arch == CTX_ARCH_BV) {
22,418✔
6378
    smt_core_set_bool_only(core);
6,267✔
6379
  }
6380
}
22,418✔
6381

6382

6383

6384

6385
/*
6386
 * Delete the arithmetic solver
6387
 */
6388
static void delete_arith_solver(context_t *ctx) {
14,944✔
6389
  uint8_t solvers;
6390

6391
  assert(ctx->arith_solver != NULL);
6392

6393
  solvers = arch_components[ctx->arch];
14,944✔
6394
  if (solvers & IFW) {
14,944✔
6395
    delete_idl_solver(ctx->arith_solver);
26✔
6396
  } else if (solvers & RFW) {
14,918✔
6397
    delete_rdl_solver(ctx->arith_solver);
8✔
6398
  } else if (solvers & SPLX) {
14,910✔
6399
    delete_simplex_solver(ctx->arith_solver);
14,910✔
6400
  }
6401
  safe_free(ctx->arith_solver);
14,944✔
6402
  ctx->arith_solver = NULL;
14,944✔
6403
}
14,944✔
6404

6405

6406

6407

6408
/*****************************
6409
 *  CONTEXT INITIALIZATION   *
6410
 ****************************/
6411

6412
/*
6413
 * Check mode and architecture
6414
 */
6415
#ifndef NDEBUG
6416
static inline bool valid_mode(context_mode_t mode) {
6417
  return CTX_MODE_ONECHECK <= mode && mode <= CTX_MODE_INTERACTIVE;
6418
}
6419

6420
static inline bool valid_arch(context_arch_t arch) {
6421
  return CTX_ARCH_NOSOLVERS <= arch && arch <= CTX_ARCH_MCSAT;
6422
}
6423
#endif
6424

6425

6426
/*
6427
 * Initialize ctx for the given mode and architecture
6428
 * - terms = term table for that context
6429
 * - qflag = true means quantifiers allowed
6430
 * - qflag = false means no quantifiers
6431
 */
6432
void init_context(context_t *ctx, term_table_t *terms, smt_logic_t logic,
22,418✔
6433
                  context_mode_t mode, context_arch_t arch, bool qflag) {
6434
  assert(valid_mode(mode) && valid_arch(arch));
6435

6436
  /*
6437
   * Set architecture and options
6438
   */
6439
  ctx->mode = mode;
22,418✔
6440
  ctx->arch = arch;
22,418✔
6441
  ctx->logic = logic;
22,418✔
6442
  ctx->sat_delegate = SAT_DELEGATE_NONE;
22,418✔
6443
  ctx->sat_delegate_incremental_mode = SAT_DELEGATE_MODE_REBUILD;
22,418✔
6444
  ctx->sat_delegate_incremental_mode_set = false;
22,418✔
6445
  ctx->theories = arch2theories[arch];
22,418✔
6446
  ctx->options = mode2options[mode];
22,418✔
6447
  if (qflag) {
22,418✔
6448
    // quantifiers require egraph
6449
    assert((ctx->theories & UF_MASK) != 0);
6450
    ctx->theories |= QUANT_MASK;
×
6451
  }
6452

6453
  ctx->base_level = 0;
22,418✔
6454
  context_reset_sat_delegate_stats(ctx);
22,418✔
6455

6456
  /*
6457
   * The core is always needed: allocate it here. It's not initialized yet.
6458
   * The other solver are optionals.
6459
   *
6460
   * TODO: we could skip this when we use MCSAT (since then the core is
6461
   * not needed).
6462
   */
6463
  ctx->core = (smt_core_t *) safe_malloc(sizeof(smt_core_t));
22,418✔
6464
  ctx->egraph = NULL;
22,418✔
6465
  ctx->mcsat = NULL;
22,418✔
6466
  ctx->arith_solver = NULL;
22,418✔
6467
  ctx->bv_solver = NULL;
22,418✔
6468
  ctx->fun_solver = NULL;
22,418✔
6469
  ctx->quant_solver = NULL;
22,418✔
6470

6471
  /*
6472
   * Global tables + gate manager
6473
   */
6474
  ctx->types = terms->types;
22,418✔
6475
  ctx->terms = terms;
22,418✔
6476
  init_gate_manager(&ctx->gate_manager, ctx->core);
22,418✔
6477

6478
  /*
6479
   * Simplification/internalization support
6480
   */
6481
  init_intern_tbl(&ctx->intern, 0, terms);
22,418✔
6482
  init_ivector(&ctx->top_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6483
  init_ivector(&ctx->top_atoms, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6484
  init_ivector(&ctx->top_formulas, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6485
  init_ivector(&ctx->top_interns, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6486

6487
  /*
6488
   * Force the internalization mapping for true and false
6489
   * - true  term --> true_occ
6490
   * - false term --> false_occ
6491
   * This mapping holds even if there's no egraph.
6492
   */
6493
  intern_tbl_map_root(&ctx->intern, true_term, bool2code(true));
22,418✔
6494

6495
  /*
6496
   * Auxiliary internalization buffers
6497
   */
6498
  init_ivector(&ctx->subst_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6499
  init_ivector(&ctx->aux_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6500
  init_ivector(&ctx->aux_atoms, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6501
  init_ivector(&ctx->aux_vector, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6502
  init_int_queue(&ctx->queue, 0);
22,418✔
6503
  init_istack(&ctx->istack);
22,418✔
6504
  init_objstack(&ctx->ostack);
22,418✔
6505
  init_sharing_map(&ctx->sharing, &ctx->intern);
22,418✔
6506
  init_objstore(&ctx->cstore, sizeof(conditional_t), 32);
22,418✔
6507
  init_assumption_stack(&ctx->assumptions);
22,418✔
6508

6509
  ctx->subst = NULL;
22,418✔
6510
  ctx->marks = NULL;
22,418✔
6511
  ctx->cache = NULL;
22,418✔
6512
  ctx->small_cache = NULL;
22,418✔
6513
  ctx->edge_map = NULL;
22,418✔
6514
  ctx->eq_cache = NULL;
22,418✔
6515
  ctx->divmod_table = NULL;
22,418✔
6516
  ctx->explorer = NULL;
22,418✔
6517
  ctx->unsat_core_cache = NULL;
22,418✔
6518
  ctx->sat_delegate_state = NULL;
22,418✔
6519

6520
  ctx->dl_profile = NULL;
22,418✔
6521
  ctx->arith_buffer = NULL;
22,418✔
6522
  ctx->poly_buffer = NULL;
22,418✔
6523
  ctx->aux_poly = NULL;
22,418✔
6524
  ctx->aux_poly_size = 0;
22,418✔
6525

6526
  ctx->bvpoly_buffer = NULL;
22,418✔
6527

6528
  q_init(&ctx->aux);
22,418✔
6529
  init_bvconstant(&ctx->bv_buffer);
22,418✔
6530

6531
  ctx->trace = NULL;
22,418✔
6532

6533
  // mcsat options default
6534
  init_mcsat_options(&ctx->mcsat_options);
22,418✔
6535
  init_ivector(&ctx->mcsat_var_order, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6536
  init_ivector(&ctx->mcsat_initial_var_order, CTX_DEFAULT_VECTOR_SIZE);
22,418✔
6537
  ctx->mcsat_relax_abstractions = NULL;
22,418✔
6538
  ctx->mcsat_relax_abstraction_terms = NULL;
22,418✔
6539
  ctx->mcsat_relax_manager = NULL;
22,418✔
6540
  /*
6541
   * Allocate and initialize the solvers and core
6542
   * NOTE: no theory solver yet if arch is AUTO_IDL or AUTO_RDL
6543
   */
6544
  init_solvers(ctx);
22,418✔
6545

6546
  ctx->en_quant = false;
22,418✔
6547
}
22,418✔
6548

6549

6550

6551

6552
/*
6553
 * Delete ctx
6554
 */
6555
void delete_context(context_t *ctx) {
22,417✔
6556
  context_sat_delegate_state_cleanup(ctx);
22,417✔
6557

6558
  if (ctx->core != NULL) {
22,417✔
6559
    delete_smt_core(ctx->core);
22,417✔
6560
    safe_free(ctx->core);
22,417✔
6561
    ctx->core = NULL;
22,417✔
6562
  }
6563

6564
  if (ctx->mcsat != NULL) {
22,417✔
6565
    mcsat_destruct(ctx->mcsat);
748✔
6566
    safe_free(ctx->mcsat);
748✔
6567
    ctx->mcsat = NULL;
748✔
6568
  }
6569

6570
  if (ctx->mcsat_supplement) {
22,417✔
6571
    context_disable_mcsat_supplement(ctx);
8✔
6572
  }
6573

6574
  if (ctx->egraph != NULL) {
22,417✔
6575
    delete_egraph(ctx->egraph);
4,794✔
6576
    safe_free(ctx->egraph);
4,794✔
6577
    ctx->egraph = NULL;
4,794✔
6578
  }
6579

6580
  if (ctx->arith_solver != NULL) {
22,417✔
6581
    delete_arith_solver(ctx);
14,944✔
6582
  }
6583

6584
  if (ctx->fun_solver != NULL) {
22,417✔
6585
    delete_fun_solver(ctx->fun_solver);
4,426✔
6586
    safe_free(ctx->fun_solver);
4,426✔
6587
    ctx->fun_solver = NULL;
4,426✔
6588
  }
6589

6590
  if (ctx->quant_solver != NULL) {
22,417✔
6591
    delete_quant_solver(ctx->quant_solver);
52✔
6592
    safe_free(ctx->quant_solver);
52✔
6593
    ctx->quant_solver = NULL;
52✔
6594
  }
6595

6596
  if (ctx->bv_solver != NULL) {
22,417✔
6597
    delete_bv_solver(ctx->bv_solver);
10,686✔
6598
    safe_free(ctx->bv_solver);
10,686✔
6599
    ctx->bv_solver = NULL;
10,686✔
6600
  }
6601

6602
  delete_gate_manager(&ctx->gate_manager);
22,417✔
6603
  /* delete_mcsat_options(&ctx->mcsat_options); // if used then the same memory is freed twice */
6604
  delete_ivector(&ctx->mcsat_var_order);
22,417✔
6605
  delete_ivector(&ctx->mcsat_initial_var_order);
22,417✔
6606
  context_delete_mcsat_relaxation(ctx);
22,417✔
6607

6608
  delete_intern_tbl(&ctx->intern);
22,417✔
6609
  delete_ivector(&ctx->top_eqs);
22,417✔
6610
  delete_ivector(&ctx->top_atoms);
22,417✔
6611
  delete_ivector(&ctx->top_formulas);
22,417✔
6612
  delete_ivector(&ctx->top_interns);
22,417✔
6613

6614
  delete_ivector(&ctx->subst_eqs);
22,417✔
6615
  delete_ivector(&ctx->aux_eqs);
22,417✔
6616
  delete_ivector(&ctx->aux_atoms);
22,417✔
6617
  delete_ivector(&ctx->aux_vector);
22,417✔
6618
  delete_int_queue(&ctx->queue);
22,417✔
6619
  delete_istack(&ctx->istack);
22,417✔
6620
  delete_objstack(&ctx->ostack);
22,417✔
6621
  delete_sharing_map(&ctx->sharing);
22,417✔
6622
  delete_objstore(&ctx->cstore);
22,417✔
6623
  delete_assumption_stack(&ctx->assumptions);
22,417✔
6624

6625
  context_free_subst(ctx);
22,417✔
6626
  context_free_marks(ctx);
22,417✔
6627
  context_free_cache(ctx);
22,417✔
6628
  context_free_small_cache(ctx);
22,417✔
6629
  context_free_eq_cache(ctx);
22,417✔
6630
  context_free_divmod_table(ctx);
22,417✔
6631
  context_free_explorer(ctx);
22,417✔
6632

6633
  context_free_dl_profile(ctx);
22,417✔
6634
  context_free_edge_map(ctx);
22,417✔
6635
  context_free_arith_buffer(ctx);
22,417✔
6636
  context_free_poly_buffer(ctx);
22,417✔
6637
  context_free_aux_poly(ctx);
22,417✔
6638

6639
  context_free_bvpoly_buffer(ctx);
22,417✔
6640
  context_invalidate_unsat_core_cache(ctx);
22,417✔
6641

6642
  q_clear(&ctx->aux);
22,417✔
6643
  delete_bvconstant(&ctx->bv_buffer);
22,417✔
6644
}
22,417✔
6645

6646
void context_invalidate_unsat_core_cache(context_t *ctx) {
88,232✔
6647
  if (ctx->unsat_core_cache != NULL) {
88,232✔
6648
    delete_ivector(ctx->unsat_core_cache);
2,741✔
6649
    safe_free(ctx->unsat_core_cache);
2,741✔
6650
    ctx->unsat_core_cache = NULL;
2,741✔
6651
  }
6652
}
88,232✔
6653

6654

6655

6656
/*
6657
 * Reset: remove all assertions and clear all internalization tables
6658
 */
6659
void reset_context(context_t *ctx) {
17✔
6660
  ctx->base_level = 0;
17✔
6661
  context_reset_sat_delegate_stats(ctx);
17✔
6662
  context_invalidate_unsat_core_cache(ctx);
17✔
6663
  context_sat_delegate_state_cleanup(ctx);
17✔
6664

6665
  reset_smt_core(ctx->core); // this propagates reset to all solvers
17✔
6666

6667
  if (ctx->mcsat != NULL) {
17✔
6668
    mcsat_reset(ctx->mcsat);
9✔
6669
  }
6670

6671
  reset_gate_manager(&ctx->gate_manager);
17✔
6672

6673
  ivector_reset(&ctx->mcsat_var_order);
17✔
6674
  ivector_reset(&ctx->mcsat_initial_var_order);
17✔
6675
  context_reset_mcsat_relaxation(ctx);
17✔
6676

6677
  reset_intern_tbl(&ctx->intern);
17✔
6678
  ivector_reset(&ctx->top_eqs);
17✔
6679
  ivector_reset(&ctx->top_atoms);
17✔
6680
  ivector_reset(&ctx->top_formulas);
17✔
6681
  ivector_reset(&ctx->top_interns);
17✔
6682

6683
  // Force the internalization mapping for true and false
6684
  intern_tbl_map_root(&ctx->intern, true_term, bool2code(true));
17✔
6685

6686
  ivector_reset(&ctx->subst_eqs);
17✔
6687
  ivector_reset(&ctx->aux_eqs);
17✔
6688
  ivector_reset(&ctx->aux_atoms);
17✔
6689
  ivector_reset(&ctx->aux_vector);
17✔
6690
  int_queue_reset(&ctx->queue);
17✔
6691
  reset_istack(&ctx->istack);
17✔
6692
  reset_objstack(&ctx->ostack);
17✔
6693
  reset_sharing_map(&ctx->sharing);
17✔
6694
  reset_objstore(&ctx->cstore);
17✔
6695
  reset_assumption_stack(&ctx->assumptions);
17✔
6696

6697
  context_free_subst(ctx);
17✔
6698
  context_free_marks(ctx);
17✔
6699
  context_reset_small_cache(ctx);
17✔
6700
  context_reset_eq_cache(ctx);
17✔
6701
  context_reset_divmod_table(ctx);
17✔
6702
  context_reset_explorer(ctx);
17✔
6703

6704
  context_free_arith_buffer(ctx);
17✔
6705
  context_reset_poly_buffer(ctx);
17✔
6706
  context_free_aux_poly(ctx);
17✔
6707
  context_free_dl_profile(ctx);
17✔
6708

6709
  context_free_bvpoly_buffer(ctx);
17✔
6710

6711
  q_clear(&ctx->aux);
17✔
6712
}
17✔
6713

6714

6715
/*
6716
 * Add tracer to ctx and ctx->core
6717
 */
6718
void context_set_trace(context_t *ctx, tracer_t *trace) {
285✔
6719
  assert(ctx->trace == NULL);
6720
  ctx->trace = trace;
285✔
6721
  smt_core_set_trace(ctx->core, trace);
285✔
6722
  if (ctx->mcsat != NULL) {
285✔
6723
    mcsat_set_tracer(ctx->mcsat, trace);
285✔
6724
  }
6725
  if (ctx->mcsat_supplement) {
285✔
NEW
6726
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
×
NEW
6727
    if (sat != NULL) {
×
NEW
6728
      mcsat_satellite_set_trace(sat, trace);
×
6729
    }
6730
  }
6731
}
285✔
6732

6733

6734
/*
6735
 * Push and pop
6736
 */
6737
void context_push(context_t *ctx) {
18,592✔
6738
  assert(context_supports_pushpop(ctx));
6739
  context_invalidate_unsat_core_cache(ctx);
18,592✔
6740
  smt_push(ctx->core);  // propagates to all solvers
18,592✔
6741
  if (ctx->mcsat != NULL) {
18,592✔
6742
    mcsat_push(ctx->mcsat);
1,342✔
6743
  }
6744
  intern_tbl_push(&ctx->intern);
18,592✔
6745
  assumption_stack_push(&ctx->assumptions);
18,592✔
6746
  context_eq_cache_push(ctx);
18,592✔
6747
  context_divmod_table_push(ctx);
18,592✔
6748

6749
  ctx->base_level ++;
18,592✔
6750
}
18,592✔
6751

6752
void context_pop(context_t *ctx) {
1,574✔
6753
  assert(context_supports_pushpop(ctx) && ctx->base_level > 0);
6754
  context_invalidate_unsat_core_cache(ctx);
1,574✔
6755
  smt_pop(ctx->core);   // propagates to all solvers
1,574✔
6756
  if (ctx->mcsat != NULL) {
1,574✔
6757
    mcsat_pop(ctx->mcsat);
1,258✔
6758
  }
6759
  intern_tbl_pop(&ctx->intern);
1,574✔
6760
  assumption_stack_pop(&ctx->assumptions);
1,574✔
6761
  context_eq_cache_pop(ctx);
1,574✔
6762
  context_divmod_table_pop(ctx);
1,574✔
6763

6764
  context_sat_delegate_state_pop(ctx, ctx->base_level);
1,574✔
6765

6766
  ctx->base_level --;
1,574✔
6767
}
1,574✔
6768

6769

6770

6771

6772

6773
/****************************
6774
 *   ASSERTIONS AND CHECK   *
6775
 ***************************/
6776

6777
/*
6778
 * Build the sharing data
6779
 * - processes all the assertions in vectors top_eqs, top_atoms, top_formulas
6780
 * - this function should be called after building the substitutions
6781
 */
6782
static void context_build_sharing_data(context_t *ctx) {
71,971✔
6783
  sharing_map_t *map;
6784

6785
  map = &ctx->sharing;
71,971✔
6786
  reset_sharing_map(map);
71,971✔
6787
  sharing_map_add_terms(map, ctx->top_eqs.data, ctx->top_eqs.size);
71,971✔
6788
  sharing_map_add_terms(map, ctx->top_atoms.data, ctx->top_atoms.size);
71,971✔
6789
  sharing_map_add_terms(map, ctx->top_formulas.data, ctx->top_formulas.size);
71,971✔
6790
}
71,971✔
6791

6792

6793
#if 0
6794
/*
6795
 * PROVISIONAL: SHOW ASSERTIONS
6796
 */
6797
static void context_show_assertions(const context_t *ctx, uint32_t n, const term_t *a) {
6798
  pp_area_t area;
6799
  yices_pp_t printer;
6800
  uint32_t i;
6801

6802
  area.width = 80;
6803
  area.height = UINT32_MAX;
6804
  area.offset = 0;
6805
  area.stretch = false;
6806
  area.truncate = false;
6807
  init_yices_pp(&printer, stdout, &area, PP_VMODE, 0);
6808

6809
  for (i=0; i<n; i++) {
6810
    pp_term_full(&printer, ctx->terms, a[i]);
6811
    flush_yices_pp(&printer);
6812
  }
6813
  delete_yices_pp(&printer, true);
6814
}
6815
#endif
6816

6817
/*
6818
 * Flatten and internalize assertions a[0 ... n-1]
6819
 * - all elements a[i] must be valid boolean term in ctx->terms
6820
 * - return code:
6821
 *   TRIVIALLY_UNSAT if there's an easy contradiction
6822
 *   CTX_NO_ERROR if the assertions were processed without error
6823
 *   a negative error code otherwise.
6824
 */
6825
static int32_t context_process_assertions(context_t *ctx, uint32_t n, const term_t *a) {
74,787✔
6826
  ivector_t *v;
6827
  uint32_t i;
6828
  int code;
6829

6830
  ivector_reset(&ctx->top_eqs);
74,787✔
6831
  ivector_reset(&ctx->top_atoms);
74,787✔
6832
  ivector_reset(&ctx->top_formulas);
74,787✔
6833
  ivector_reset(&ctx->top_interns);
74,787✔
6834
  ivector_reset(&ctx->subst_eqs);
74,787✔
6835
  ivector_reset(&ctx->aux_eqs);
74,787✔
6836
  ivector_reset(&ctx->aux_atoms);
74,787✔
6837

6838
  code = setjmp(ctx->env);
74,787✔
6839
  if (code == 0) {
75,185✔
6840

6841
    // If using MCSAT, just check and done
6842
    if (ctx->mcsat != NULL) {
74,787✔
6843
      // TBD: quant support
6844
      assert(!context_quant_enabled(ctx));
6845
      code = mcsat_assert_formulas(ctx->mcsat, n, a);
2,444✔
6846
      goto done;
2,433✔
6847
    }
6848

6849
#if 0
6850
    printf("\n=== Context: process assertions ===\n");
6851
    context_show_assertions(ctx, n, a);
6852
    printf("===\n\n");
6853
#endif
6854

6855
    // flatten
6856
    for (i=0; i<n; i++) {
195,765✔
6857
      flatten_assertion(ctx, a[i]);
123,793✔
6858
    }
6859

6860
    trace_printf(ctx->trace, 6, "(done flattening)\n");
71,972✔
6861

6862
    /*
6863
     * At this point, the assertions are stored into the vectors
6864
     * top_eqs, top_atoms, top_formulas, and top_interns
6865
     * - more top-level equalities may be in subst_eqs
6866
     * - ctx->intern stores the internalized terms and the variable
6867
     *   substitutions.
6868
     */
6869

6870
    switch (ctx->arch) {
71,972✔
6871
    // TBD: make sure following preprocessings work with quant enabled
6872
    case CTX_ARCH_EG:
3,329✔
6873
      /*
6874
       * UF problem: we must process subst_eqs last since the
6875
       * preprocessing may add new equalities in aux_eqs that may end
6876
       * up in subst_eqs after the call to process_aux_eqs.
6877
       */
6878
      if (context_breaksym_enabled(ctx)) {
3,329✔
6879
        break_uf_symmetries(ctx);
30✔
6880
      }
6881
      if (context_eq_abstraction_enabled(ctx)) {
3,329✔
6882
        analyze_uf(ctx);
64✔
6883
      }
6884
      if (ctx->aux_eqs.size > 0) {
3,329✔
6885
        process_aux_eqs(ctx);
6✔
6886
      }
6887
      if (ctx->subst_eqs.size > 0) {
3,328✔
6888
        context_process_candidate_subst(ctx);
10✔
6889
      }
6890
      break;
3,328✔
6891

6892
    case CTX_ARCH_AUTO_IDL:
27✔
6893
      /*
6894
       * For difference logic, we must process the subst_eqs first
6895
       * (otherwise analyze_diff_logic may give wrong results).
6896
       */
6897
      if (ctx->subst_eqs.size > 0) {
27✔
6898
        context_process_candidate_subst(ctx);
×
6899
      }
6900
      analyze_diff_logic(ctx, true);
27✔
6901
      create_auto_idl_solver(ctx);
27✔
6902
      break;
27✔
6903

6904
    case CTX_ARCH_AUTO_RDL:
8✔
6905
      /*
6906
       * Difference logic, we must process the subst_eqs first
6907
       */
6908
      trace_printf(ctx->trace, 6, "(auto-idl solver)\n");
8✔
6909
      if (ctx->subst_eqs.size > 0) {
8✔
6910
        context_process_candidate_subst(ctx);
×
6911
      }
6912
      analyze_diff_logic(ctx, false);
8✔
6913
      create_auto_rdl_solver(ctx);
8✔
6914
      break;
8✔
6915

6916
    case CTX_ARCH_SPLX:
30,674✔
6917
      /*
6918
       * Simplex, like EG, may add aux_atoms so we must process
6919
       * subst_eqs last here.
6920
       */
6921
      trace_printf(ctx->trace, 6, "(Simplex solver)\n");
30,674✔
6922
      // more optional processing
6923
      if (context_cond_def_preprocessing_enabled(ctx)) {
30,674✔
6924
        process_conditional_definitions(ctx);
52✔
6925
        if (ctx->aux_eqs.size > 0) {
52✔
6926
          process_aux_eqs(ctx);
2✔
6927
        }
6928
        if (ctx->aux_atoms.size > 0) {
52✔
6929
          process_aux_atoms(ctx);
3✔
6930
        }
6931
      }
6932
      if (ctx->subst_eqs.size > 0) {
30,674✔
6933
        context_process_candidate_subst(ctx);
16✔
6934
      }
6935
      break;
30,674✔
6936

6937
    default:
37,934✔
6938
      /*
6939
       * Process the candidate variable substitutions if any
6940
       */
6941
      if (ctx->subst_eqs.size > 0) {
37,934✔
6942
        context_process_candidate_subst(ctx);
2,749✔
6943
      }
6944
      break;
37,934✔
6945
    }
6946

6947
    /*
6948
     * Sharing
6949
     */
6950
    context_build_sharing_data(ctx);
71,971✔
6951

6952
    /*
6953
     * Notify the core + solver(s)
6954
     */
6955
    if (!context_quant_enabled(ctx)) {
71,971✔
6956
        // TBD: make sure this is correct
6957
      internalization_start(ctx->core);
69,438✔
6958
    }
6959

6960
    /*
6961
     * Assert top_eqs, top_atoms, top_formulas, top_interns
6962
     */
6963
    code = CTX_NO_ERROR;
71,971✔
6964

6965
    // first: all terms that are already internalized
6966
    v = &ctx->top_interns;
71,971✔
6967
    n = v->size;
71,971✔
6968
    if (n > 0) {
71,971✔
6969
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" existing terms)\n", n);
284✔
6970
      i = 0;
284✔
6971
      do {
6972
        assert_toplevel_intern(ctx, v->data[i]);
739✔
6973
        i ++;
739✔
6974
      } while (i < n);
739✔
6975

6976
      // one round of propagation
6977
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
284✔
6978
        code = TRIVIALLY_UNSAT;
11✔
6979
        goto done;
11✔
6980
      }
6981
    }
6982

6983
    // second: all top-level equalities
6984
    v = &ctx->top_eqs;
71,960✔
6985
    n = v->size;
71,960✔
6986
    if (n > 0) {
71,960✔
6987
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level equalities)\n", n);
6,780✔
6988
      i = 0;
6,780✔
6989
      do {
6990
        assert_toplevel_formula(ctx, v->data[i]);
10,842✔
6991
        i ++;
10,838✔
6992
      } while (i < n);
10,838✔
6993

6994
      // one round of propagation
6995
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
6,776✔
6996
        code = TRIVIALLY_UNSAT;
69✔
6997
        goto done;
69✔
6998
      }
6999
    }
7000

7001
    // third: all top-level atoms (other than equalities)
7002
    v = &ctx->top_atoms;
71,887✔
7003
    n = v->size;
71,887✔
7004
    if (n > 0) {
71,887✔
7005
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level atoms)\n", n);
15,581✔
7006
      i = 0;
15,581✔
7007
      do {
7008
        assert_toplevel_formula(ctx, v->data[i]);
68,867✔
7009
        i ++;
68,856✔
7010
      } while (i < n);
68,856✔
7011

7012
      // one round of propagation
7013
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
15,570✔
7014
        code = TRIVIALLY_UNSAT;
78✔
7015
        goto done;
78✔
7016
      }
7017
    }
7018

7019
    // last: all non-atomic, formulas
7020
    v =  &ctx->top_formulas;
71,798✔
7021
    n = v->size;
71,798✔
7022
    if (n > 0) {
71,798✔
7023
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level formulas)\n", n);
22,021✔
7024
      i = 0;
22,021✔
7025
      do {
7026
        assert_toplevel_formula(ctx, v->data[i]);
45,747✔
7027
        i ++;
45,747✔
7028
      } while (i < n);
45,747✔
7029

7030
      // one round of propagation
7031
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
22,021✔
7032
        code = TRIVIALLY_UNSAT;
63✔
7033
        goto done;
63✔
7034
      }
7035
    }
7036

7037
  } else {
7038
    /*
7039
     * Exception: return from longjmp(ctx->env, code);
7040
     */
7041
    ivector_reset(&ctx->aux_vector);
398✔
7042
    reset_istack(&ctx->istack);
398✔
7043
    reset_objstack(&ctx->ostack);
398✔
7044
    int_queue_reset(&ctx->queue);
398✔
7045
    context_free_subst(ctx);
398✔
7046
    context_free_marks(ctx);
398✔
7047
  }
7048

7049
 done:
74,787✔
7050
  return code;
74,787✔
7051
}
7052

7053
/*
7054
 * Assert all formulas f[0] ... f[n-1]
7055
 * The context status must be IDLE.
7056
 *
7057
 * Return code:
7058
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
7059
 *   (in that case the context status is set to UNSAT)
7060
 * - CTX_NO_ERROR means no internalization error and status not
7061
 *   determined
7062
 * - otherwise, the code is negative to report an error.
7063
 */
7064
int32_t _o_assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
72,253✔
7065
  int32_t code;
7066

7067
  assert(ctx->arch == CTX_ARCH_AUTO_IDL ||
7068
         ctx->arch == CTX_ARCH_AUTO_RDL ||
7069
         smt_status(ctx->core) == YICES_STATUS_IDLE);
7070
  assert(!context_quant_enabled(ctx));
7071

7072
  code = context_process_assertions(ctx, n, f);
72,253✔
7073
  if (code == TRIVIALLY_UNSAT) {
72,253✔
7074
    if (ctx->arch == CTX_ARCH_AUTO_IDL || ctx->arch == CTX_ARCH_AUTO_RDL) {
600✔
7075
      // cleanup: reset arch/config to 'no theory'
7076
      assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL &&
7077
             ctx->mode == CTX_MODE_ONECHECK);
7078
      ctx->arch = CTX_ARCH_NOSOLVERS;
1✔
7079
      ctx->theories = 0;
1✔
7080
      ctx->options = 0;
1✔
7081
    }
7082

7083
    if( smt_status(ctx->core) != YICES_STATUS_UNSAT) {
600✔
7084
      // force UNSAT in the core
7085
      add_empty_clause(ctx->core);
379✔
7086
      ctx->core->status = YICES_STATUS_UNSAT;
379✔
7087
    }
7088
  }
7089

7090
  return code;
72,253✔
7091
}
7092

7093
/*
7094
 * Assert all formulas f[0] ... f[n-1] during quantifier instantiation
7095
 * The context status must be SEARCHING.
7096
 *
7097
 * Return code:
7098
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
7099
 *   (in that case the context status is set to UNSAT)
7100
 * - CTX_NO_ERROR means no internalization error and status not
7101
 *   determined
7102
 * - otherwise, the code is negative to report an error.
7103
 */
7104
int32_t quant_assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
2,534✔
7105
  int32_t code;
7106

7107
  assert(context_quant_enabled(ctx));
7108
  assert(smt_status(ctx->core) == YICES_STATUS_SEARCHING);
7109

7110
  code = context_process_assertions(ctx, n, f);
2,534✔
7111
  if (code == TRIVIALLY_UNSAT) {
2,534✔
7112
    if (ctx->arch == CTX_ARCH_AUTO_IDL || ctx->arch == CTX_ARCH_AUTO_RDL) {
1✔
7113
      // cleanup: reset arch/config to 'no theory'
7114
      assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL &&
7115
      ctx->mode == CTX_MODE_ONECHECK);
7116
      ctx->arch = CTX_ARCH_NOSOLVERS;
×
7117
      ctx->theories = 0;
×
7118
      ctx->options = 0;
×
7119
    }
7120

7121
    if( smt_status(ctx->core) != YICES_STATUS_UNSAT) {
1✔
7122
      // force UNSAT in the core
7123
      add_empty_clause(ctx->core);
1✔
7124
      ctx->core->status = YICES_STATUS_UNSAT;
1✔
7125
    }
7126
  }
7127

7128
  return code;
2,534✔
7129
}
7130

7131
int32_t assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
18,470✔
7132
  MT_PROTECT(int32_t, __yices_globals.lock, _o_assert_formulas(ctx, n, f));
18,470✔
7133
}
7134

7135

7136

7137

7138
/*
7139
 * Assert a boolean formula f.
7140
 *
7141
 * The context status must be IDLE.
7142
 *
7143
 * Return code:
7144
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
7145
 *   (in that case the context status is set to UNSAT)
7146
 * - CTX_NO_ERROR means no internalization error and status not
7147
 *   determined
7148
 * - otherwise, the code is negative. The assertion could
7149
 *   not be processed.
7150
 */
7151
int32_t _o_assert_formula(context_t *ctx, term_t f) {
53,783✔
7152
  return _o_assert_formulas(ctx, 1, &f);
53,783✔
7153
}
7154

7155
int32_t assert_formula(context_t *ctx, term_t f) {
49,307✔
7156
  MT_PROTECT(int32_t, __yices_globals.lock, _o_assert_formula(ctx, f));
49,307✔
7157
}
7158

7159

7160
/*
7161
 * Convert boolean term t to a literal l in context ctx
7162
 * - t must be a boolean term
7163
 * - return a negative code if there's an error
7164
 * - return a literal (l >= 0) otherwise.
7165
 */
7166
int32_t context_internalize(context_t *ctx, term_t t) {
87,725✔
7167
  int code;
7168
  literal_t l;
7169

7170
  ivector_reset(&ctx->top_eqs);
87,725✔
7171
  ivector_reset(&ctx->top_atoms);
87,725✔
7172
  ivector_reset(&ctx->top_formulas);
87,725✔
7173
  ivector_reset(&ctx->top_interns);
87,725✔
7174
  ivector_reset(&ctx->subst_eqs);
87,725✔
7175
  ivector_reset(&ctx->aux_eqs);
87,725✔
7176

7177
  code = setjmp(ctx->env);
87,725✔
7178
  if (code == 0) {
87,725✔
7179
    // we must call internalization start first
7180
    if (!context_quant_enabled(ctx)) {
87,725✔
7181
      // TBD: make sure this is correct
7182
      internalization_start(ctx->core);
87,621✔
7183
    }
7184
    l = internalize_to_literal(ctx, t);
87,725✔
7185
  } else {
7186
    assert(code < 0);
7187
    /*
7188
     * Clean up
7189
     */
7190
    ivector_reset(&ctx->aux_vector);
×
7191
    reset_istack(&ctx->istack);
×
7192
    int_queue_reset(&ctx->queue);
×
7193
    context_free_subst(ctx);
×
7194
    context_free_marks(ctx);
×
7195
    l = code;
×
7196
  }
7197

7198
  return l;
87,725✔
7199
}
7200

7201

7202
/*
7203
 * Build an assumption for Boolean term t:
7204
 * - this converts t to a literal l in context ctx
7205
 *   then create an indicator variable x in the core
7206
 *   and add the clause (x => l) in the core.
7207
 * - return a negative code if t can't be internalized
7208
 * - return the literal x otherwise (where x>=0).
7209
 */
7210
int32_t context_add_assumption(context_t *ctx, term_t t) {
87,630✔
7211
  int32_t l, x;
7212

7213
  // check if we already have an assumption literal for t
7214
  x = assumption_literal_for_term(&ctx->assumptions, t);
87,630✔
7215
  if (x < 0) {
87,630✔
7216
    l = context_internalize(ctx, t);
87,621✔
7217
    if (l < 0) return l; // error code
87,621✔
7218

7219
    x = pos_lit(create_boolean_variable(ctx->core));
87,621✔
7220
    add_binary_clause(ctx->core, not(x), l); // clause (x implies l)
87,621✔
7221

7222
    assumption_stack_add(&ctx->assumptions, t, x);
87,621✔
7223
  }
7224

7225
  return x;
87,630✔
7226
}
7227

7228

7229

7230
/*
7231
 * PROVISIONAL: FOR TESTING/DEBUGGING
7232
 */
7233

7234
/*
7235
 * Preprocess formula f or array of formulas f[0 ... n-1]
7236
 * - this does flattening + build substitutions
7237
 * - return code: as in assert_formulas
7238
 * - the result is stored in the internal vectors
7239
 *     ctx->top_interns
7240
 *     ctx->top_eqs
7241
 *     ctx->top_atoms
7242
 *     ctx->top_formulas
7243
 *   + ctx->intern stores substitutions
7244
 */
7245
int32_t context_process_formulas(context_t *ctx, uint32_t n, term_t *f) {
×
7246
  uint32_t i;
7247
  int code;
7248

7249
  ivector_reset(&ctx->top_eqs);
×
7250
  ivector_reset(&ctx->top_atoms);
×
7251
  ivector_reset(&ctx->top_formulas);
×
7252
  ivector_reset(&ctx->top_interns);
×
7253
  ivector_reset(&ctx->subst_eqs);
×
7254
  ivector_reset(&ctx->aux_eqs);
×
7255
  ivector_reset(&ctx->aux_atoms);
×
7256

7257
  code = setjmp(ctx->env);
×
7258
  if (code == 0) {
×
7259
    // flatten
7260
    for (i=0; i<n; i++) {
×
7261
      flatten_assertion(ctx, f[i]);
×
7262
    }
7263

7264
    /*
7265
     * At this point, the assertions are stored into the vectors
7266
     * top_eqs, top_atoms, top_formulas, and top_interns
7267
     * - more top-level equalities may be in subst_eqs
7268
     * - ctx->intern stores the internalized terms and the variable
7269
     *   substitutions.
7270
     */
7271

7272
    switch (ctx->arch) {
×
7273
    case CTX_ARCH_EG:
×
7274
      /*
7275
       * UF problem: we must process subst_eqs last since the
7276
       * preprocessing may add new equalities in aux_eqs that may end
7277
       * up in subst_eqs after the call to process_aux_eqs.
7278
       */
7279
      if (context_breaksym_enabled(ctx)) {
×
7280
        break_uf_symmetries(ctx);
×
7281
      }
7282
      if (context_eq_abstraction_enabled(ctx)) {
×
7283
        analyze_uf(ctx);
×
7284
      }
7285
      if (ctx->aux_eqs.size > 0) {
×
7286
        process_aux_eqs(ctx);
×
7287
      }
7288
      if (ctx->subst_eqs.size > 0) {
×
7289
        context_process_candidate_subst(ctx);
×
7290
      }
7291
      break;
×
7292

7293
    case CTX_ARCH_AUTO_IDL:
×
7294
      /*
7295
       * For difference logic, we must process the subst_eqs first
7296
       * (otherwise analyze_diff_logic may give wrong results).
7297
       */
7298
      if (ctx->subst_eqs.size > 0) {
×
7299
        context_process_candidate_subst(ctx);
×
7300
      }
7301
      analyze_diff_logic(ctx, true);
×
7302
      create_auto_idl_solver(ctx);
×
7303
      break;
×
7304

7305
    case CTX_ARCH_AUTO_RDL:
×
7306
      /*
7307
       * Difference logic, we must process the subst_eqs first
7308
       */
7309
      if (ctx->subst_eqs.size > 0) {
×
7310
        context_process_candidate_subst(ctx);
×
7311
      }
7312
      analyze_diff_logic(ctx, false);
×
7313
      create_auto_rdl_solver(ctx);
×
7314
      break;
×
7315

7316
    case CTX_ARCH_SPLX:
×
7317
      /*
7318
       * Simplex, like EG, may add aux_atoms so we must process
7319
       * subst_eqs last here.
7320
       */
7321
      // more optional processing
7322
      if (context_cond_def_preprocessing_enabled(ctx)) {
×
7323
        process_conditional_definitions(ctx);
×
7324
        if (ctx->aux_eqs.size > 0) {
×
7325
          process_aux_eqs(ctx);
×
7326
        }
7327
        if (ctx->aux_atoms.size > 0) {
×
7328
          process_aux_atoms(ctx);
×
7329
        }
7330
      }
7331
      if (ctx->subst_eqs.size > 0) {
×
7332
        context_process_candidate_subst(ctx);
×
7333
      }
7334
      break;
×
7335

7336
    default:
×
7337
      /*
7338
       * Process the candidate variable substitutions if any
7339
       */
7340
      if (ctx->subst_eqs.size > 0) {
×
7341
        context_process_candidate_subst(ctx);
×
7342
      }
7343
      break;
×
7344
    }
7345

7346
    /*
7347
     * Sharing
7348
     */
7349
    context_build_sharing_data(ctx);
×
7350

7351
    code = CTX_NO_ERROR;
×
7352

7353
  } else {
7354
    /*
7355
     * Exception: return from longjmp(ctx->env, code);
7356
     */
7357
    ivector_reset(&ctx->aux_vector);
×
7358
    reset_istack(&ctx->istack);
×
7359
    int_queue_reset(&ctx->queue);
×
7360
    context_free_subst(ctx);
×
7361
    context_free_marks(ctx);
×
7362
  }
7363

7364
  return code;
×
7365
}
7366

7367
int32_t context_process_formula(context_t *ctx, term_t f) {
×
7368
  return context_process_formulas(ctx, 1, &f);
×
7369
}
7370

7371

7372

7373
/*
7374
 * The search function 'check_context' is defined in context_solver.c
7375
 */
7376

7377

7378
/*
7379
 * Interrupt the search.
7380
 */
7381
void context_stop_search(context_t *ctx) {
3✔
7382
  if (ctx->mcsat == NULL) {
3✔
7383
    stop_search(ctx->core);
3✔
7384
    if (context_has_simplex_solver(ctx)) {
3✔
7385
      simplex_stop_search(ctx->arith_solver);
3✔
7386
    }
7387
  } else {
7388
    mcsat_stop_search(ctx->mcsat);
×
7389
  }
7390
}
3✔
7391

7392

7393

7394
/*
7395
 * Cleanup: restore ctx to a good state after check_context
7396
 * is interrupted.
7397
 */
7398
void context_cleanup(context_t *ctx) {
1✔
7399
  // restore the state to IDLE, propagate to all solvers (via pop)
7400
  assert(context_supports_cleaninterrupt(ctx));
7401
  context_invalidate_unsat_core_cache(ctx);
1✔
7402
  if (ctx->mcsat == NULL) {
1✔
7403
    smt_cleanup(ctx->core);
1✔
7404
  } else {
7405
    mcsat_clear(ctx->mcsat);
×
7406
  }
7407
}
1✔
7408

7409

7410

7411
/*
7412
 * Clear: prepare for more assertions and checks
7413
 * - free the boolean assignment
7414
 * - reset the status to IDLE
7415
 */
7416
void context_clear(context_t *ctx) {
42,255✔
7417
  assert(context_supports_multichecks(ctx));
7418
  context_invalidate_unsat_core_cache(ctx);
42,255✔
7419
  if (ctx->mcsat == NULL) {
42,255✔
7420
    smt_clear(ctx->core);
41,894✔
7421
  } else {
7422
    mcsat_clear(ctx->mcsat);
361✔
7423
  }
7424
}
42,255✔
7425

7426

7427

7428
/*
7429
 * Clear_unsat: prepare for pop if the status is UNSAT
7430
 * - remove assumptions if any
7431
 *
7432
 * - if clean interrupt is enabled, then there may be a mismatch between
7433
 *   the context's base_level and the core base_level.
7434
 * - it's possible to have ctx->core.base_level = ctx->base_level + 1
7435
 * - this happens because start_search in smt_core does an internal smt_push
7436
 *   to allow the core to be restored to a clean state if search is interrupted.
7437
 * - if search is not interrupted and the search returns UNSAT, then we're
7438
 *   in a state with core base level = context base level + 1.
7439
 */
7440
void context_clear_unsat(context_t *ctx) {
657✔
7441
  context_invalidate_unsat_core_cache(ctx);
657✔
7442
  if (ctx->mcsat == NULL) {
657✔
7443
    smt_clear_unsat(ctx->core);
421✔
7444
    assert(smt_base_level(ctx->core) == ctx->base_level);
7445
  } else {
7446
    mcsat_clear(ctx->mcsat);
236✔
7447
  }
7448
}
657✔
7449

7450

7451

7452
/*
7453
 * Add the blocking clause to ctx
7454
 * - ctx->status must be either SAT or UNKNOWN
7455
 * - this collects all decision literals in the current truth assignment
7456
 *   (say l_1, ..., l_k) then clears the current assignment and adds the
7457
 *  clause ((not l_1) \/ ... \/ (not l_k)).
7458
 *
7459
 * Return code:
7460
 * - TRIVIALLY_UNSAT: means that the blocking clause is empty (i.e., k = 0)
7461
 *   (in that case, the context status is set to UNSAT)
7462
 * - CTX_NO_ERROR: means that the blocking clause is not empty (i.e., k > 0)
7463
 *   (In this case, the context status is set to IDLE)
7464
 */
7465
int32_t assert_blocking_clause(context_t *ctx) {
24,855✔
7466
  ivector_t *v;
7467
  uint32_t i, n;
7468
  int32_t code;
7469

7470
  assert(smt_status(ctx->core) == YICES_STATUS_SAT ||
7471
         smt_status(ctx->core) == YICES_STATUS_UNKNOWN);
7472

7473
  // get decision literals and build the blocking clause
7474
  v = &ctx->aux_vector;
24,855✔
7475
  assert(v->size == 0);
7476
  collect_decision_literals(ctx->core, v);
24,855✔
7477
  n = v->size;
24,855✔
7478
  for (i=0; i<n; i++) {
36,264✔
7479
    v->data[i] = not(v->data[i]);
11,409✔
7480
  }
7481

7482
  // prepare for the new assertion + notify solvers of a new assertion
7483
  context_clear(ctx);
24,855✔
7484
  internalization_start(ctx->core);
24,855✔
7485

7486
  // add the blocking clause
7487
  add_clause(ctx->core, n, v->data);
24,855✔
7488
  ivector_reset(v);
24,855✔
7489

7490
  // force UNSAT if n = 0
7491
  code = CTX_NO_ERROR;
24,855✔
7492
  if (n == 0) {
24,855✔
7493
    code = TRIVIALLY_UNSAT;
16,817✔
7494
    ctx->core->status = YICES_STATUS_UNSAT;
16,817✔
7495
  }
7496

7497
  assert(n == 0 || smt_status(ctx->core) == YICES_STATUS_IDLE);
7498

7499
  return code;
24,855✔
7500
}
7501

7502

7503

7504

7505
/********************************
7506
 *  GARBAGE COLLECTION SUPPORT  *
7507
 *******************************/
7508

7509
/*
7510
 * Marker for all terms present in the eq_map
7511
 * - aux = the relevant term table.
7512
 * - each record p stores <k0, k1, val> where k0 and k1 are both
7513
 *   terms in aux and val is a literal in the core
7514
 */
7515
static void ctx_mark_eq(void *aux, const pmap2_rec_t *p) {
×
7516
  term_table_set_gc_mark(aux, index_of(p->k0));
×
7517
  term_table_set_gc_mark(aux, index_of(p->k1));
×
7518
}
×
7519

7520

7521
/*
7522
 * Go through all data structures in ctx and mark all terms and types
7523
 * that they use.
7524
 */
7525
void context_gc_mark(context_t *ctx) {
12✔
7526
  if (ctx->egraph != NULL) {
12✔
7527
    egraph_gc_mark(ctx->egraph);
1✔
7528
  }
7529
  if (ctx->fun_solver != NULL) {
12✔
7530
    fun_solver_gc_mark(ctx->fun_solver);
1✔
7531
  }
7532

7533
  intern_tbl_gc_mark(&ctx->intern);
12✔
7534

7535
  // empty all the term vectors to be safe
7536
  ivector_reset(&ctx->top_eqs);
12✔
7537
  ivector_reset(&ctx->top_atoms);
12✔
7538
  ivector_reset(&ctx->top_formulas);
12✔
7539
  ivector_reset(&ctx->top_interns);
12✔
7540
  ivector_reset(&ctx->subst_eqs);
12✔
7541
  ivector_reset(&ctx->aux_eqs);
12✔
7542

7543
  if (ctx->eq_cache != NULL) {
12✔
7544
    pmap2_iterate(ctx->eq_cache, ctx->terms, ctx_mark_eq);
×
7545
  }
7546

7547
  if (ctx->unsat_core_cache != NULL) {
12✔
7548
    uint32_t i, n;
7549
    n = ctx->unsat_core_cache->size;
×
7550
    for (i=0; i<n; i++) {
×
7551
      term_table_set_gc_mark(ctx->terms, index_of(ctx->unsat_core_cache->data[i]));
×
7552
    }
7553
  }
7554

7555
  if (ctx->mcsat != NULL) {
12✔
7556
    mcsat_gc_mark(ctx->mcsat);
11✔
7557
  }
7558
  if (ctx->mcsat_supplement) {
12✔
NEW
7559
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
×
NEW
7560
    if (sat != NULL) {
×
NEW
7561
      mcsat_satellite_gc_mark(sat);
×
7562
    }
7563
  }
7564
}
12✔
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