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

SRI-CSL / yices2 / 26210537113

21 May 2026 06:55AM UTC coverage: 67.563% (+0.1%) from 67.453%
26210537113

Pull #611

github

disteph
Fix MCSAT supplement context cleanup

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

746 of 1098 new or added lines in 17 files covered. (67.94%)

2 existing lines in 2 files now uncovered.

86614 of 128198 relevant lines covered (67.56%)

1612038.29 hits per line

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

80.43
/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/term_explorer.h"
41
#include "terms/term_utils.h"
42
#include "utils/int_hash_map.h"
43
#include "utils/memalloc.h"
44

45
#include "mcsat/solver.h"
46
#include "mt/thread_macros.h"
47

48
#include "api/yices_globals.h"
49

50
#define TRACE 0
51

52
#if TRACE
53

54
#include <stdio.h>
55

56
#include "io/term_printer.h"
57
#include "solvers/cdcl/smt_core_printer.h"
58

59
#endif
60

61

62

63

64

65
/**********************
66
 *  INTERNALIZATION   *
67
 *********************/
68

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

81
static inline mcsat_satellite_t *context_mcsat_satellite(context_t *ctx);
82
static bool context_atom_requires_mcsat(context_t *ctx, term_t atom);
83
static void context_observe_mcsat_atom(context_t *ctx, term_t atom, literal_t l);
84
static literal_t map_mcsat_atom_to_literal(context_t *ctx, term_t atom);
85
static void context_disable_mcsat_supplement(context_t *ctx);
86

87

88
/*
89
 * Supplementary MCSAT support (CDCL(T) mode)
90
 */
91
static inline mcsat_satellite_t *context_mcsat_satellite(context_t *ctx) {
20✔
92
  if (ctx->egraph == NULL) {
20✔
NEW
93
    return NULL;
×
94
  }
95
  return (mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT];
20✔
96
}
97

98
static inline bool divisor_requires_mcsat(term_table_t *terms, term_t t) {
3✔
99
  t = unsigned_term(t);
3✔
100
  return term_kind(terms, t) != ARITH_CONSTANT;
3✔
101
}
102

103
/*
104
 * Detect whether t contains arithmetic or finite-field subterms.
105
 * This is used to route all relevant arithmetic/FF atoms to the supplementary
106
 * MCSAT context once supplementation is active.
107
 */
108
static bool term_contains_arith_or_ff(context_t *ctx, term_t t, int_hmap_t *cache) {
20✔
109
  term_table_t *terms;
110
  int_hmap_pair_t *p;
111
  type_t tau;
112
  type_kind_t tkind;
113
  bool found;
114
  uint32_t i, nchildren;
115

116
  if (t < 0) {
20✔
NEW
117
    return false;
×
118
  }
119

120
  t = unsigned_term(t);
20✔
121
  p = int_hmap_find(cache, t);
20✔
122
  if (p != NULL) {
20✔
NEW
123
    return p->val != 0;
×
124
  }
125

126
  terms = ctx->terms;
20✔
127
  tau = term_type(terms, t);
20✔
128
  tkind = type_kind(terms->types, tau);
20✔
129

130
  /*
131
   * Variables of arithmetic/finite-field type may not satisfy
132
   * is_arithmetic_term/is_finitefield_term, so include type-based detection.
133
   */
134
  found = is_arithmetic_term(terms, t) || is_finitefield_term(terms, t) ||
30✔
135
          tkind == INT_TYPE || tkind == REAL_TYPE || is_ff_type(terms->types, tau);
30✔
136

137
  if (!found) {
20✔
138
    if (term_is_projection(terms, t)) {
10✔
NEW
139
      found = term_contains_arith_or_ff(ctx, proj_term_arg(terms, t), cache);
×
140

141
    } else if (term_is_sum(terms, t)) {
10✔
NEW
142
      nchildren = term_num_children(terms, t);
×
NEW
143
      for (i = 0; i < nchildren && !found; i++) {
×
144
        term_t child;
145
        mpq_t q;
NEW
146
        mpq_init(q);
×
NEW
147
        sum_term_component(terms, t, i, q, &child);
×
NEW
148
        found = term_contains_arith_or_ff(ctx, child, cache);
×
NEW
149
        mpq_clear(q);
×
150
      }
151

152
    } else if (term_is_bvsum(terms, t)) {
10✔
153
      int32_t *aux;
154
      uint32_t nbits;
155
      term_t child;
156

NEW
157
      nbits = term_bitsize(terms, t);
×
NEW
158
      aux = (int32_t *) safe_malloc(nbits * sizeof(int32_t));
×
NEW
159
      nchildren = term_num_children(terms, t);
×
NEW
160
      for (i = 0; i < nchildren && !found; i++) {
×
NEW
161
        bvsum_term_component(terms, t, i, aux, &child);
×
NEW
162
        found = term_contains_arith_or_ff(ctx, child, cache);
×
163
      }
NEW
164
      safe_free(aux);
×
165

166
    } else if (term_is_product(terms, t)) {
10✔
NEW
167
      nchildren = term_num_children(terms, t);
×
NEW
168
      for (i = 0; i < nchildren && !found; i++) {
×
169
        term_t child;
170
        uint32_t exp;
NEW
171
        product_term_component(terms, t, i, &child, &exp);
×
NEW
172
        found = term_contains_arith_or_ff(ctx, child, cache);
×
173
      }
174

175
    } else if (term_is_composite(terms, t)) {
10✔
176
      nchildren = term_num_children(terms, t);
10✔
177
      for (i = 0; i < nchildren && !found; i++) {
20✔
178
        found = term_contains_arith_or_ff(ctx, term_child(terms, t, i), cache);
10✔
179
      }
180
    }
181
  }
182

183
  p = int_hmap_get(cache, t);
20✔
184
  p->val = found ? 1 : 0;
20✔
185
  return found;
20✔
186
}
187

188
static bool term_requires_mcsat_supplement(context_t *ctx, term_t t, int_hmap_t *cache) {
65✔
189
  term_table_t *terms;
190
  int_hmap_pair_t *p;
191
  type_t tau;
192
  bool trigger;
193
  uint32_t i, nchildren;
194

195
  if (t < 0) {
65✔
196
    return false;
2✔
197
  }
198

199
  t = unsigned_term(t);
63✔
200
  p = int_hmap_find(cache, t);
63✔
201
  if (p != NULL) {
63✔
202
    return p->val != 0;
1✔
203
  }
204

205
  terms = ctx->terms;
62✔
206
  tau = term_type(terms, t);
62✔
207
  trigger = false;
62✔
208

209
  // finite-field usage
210
  if (is_finitefield_term(terms, t) || is_ff_type(terms->types, tau)) {
62✔
NEW
211
    trigger = true;
×
212
  }
213

214
  if (!trigger) {
62✔
215
    switch (term_kind(terms, t)) {
62✔
216
    case ARITH_ROOT_ATOM:
3✔
217
    case ARITH_FF_CONSTANT:
218
    case ARITH_FF_POLY:
219
    case ARITH_FF_EQ_ATOM:
220
    case ARITH_FF_BINEQ_ATOM:
221
      trigger = true;
3✔
222
      break;
3✔
223

224
    case ARITH_RDIV:
3✔
225
      trigger = divisor_requires_mcsat(terms, arith_rdiv_term_desc(terms, t)->arg[1]);
3✔
226
      break;
3✔
227

NEW
228
    case ARITH_IDIV:
×
NEW
229
      trigger = divisor_requires_mcsat(terms, arith_idiv_term_desc(terms, t)->arg[1]);
×
NEW
230
      break;
×
231

NEW
232
    case ARITH_MOD:
×
NEW
233
      trigger = divisor_requires_mcsat(terms, arith_mod_term_desc(terms, t)->arg[1]);
×
NEW
234
      break;
×
235

NEW
236
    case ARITH_DIVIDES_ATOM:
×
NEW
237
      trigger = divisor_requires_mcsat(terms, arith_divides_atom_desc(terms, t)->arg[0]);
×
NEW
238
      break;
×
239

240
    default:
56✔
241
      break;
56✔
242
    }
243
  }
244

245
  // arithmetic nonlinearity (including deep products in arithmetic predicates)
246
  if (!trigger && is_arithmetic_term(terms, t) && term_degree(terms, t) > 1) {
62✔
247
    trigger = true;
8✔
248
  }
249

250
  if (!trigger) {
62✔
251
    if (term_is_projection(terms, t)) {
49✔
NEW
252
      trigger = term_requires_mcsat_supplement(ctx, proj_term_arg(terms, t), cache);
×
253

254
    } else if (term_is_sum(terms, t)) {
49✔
255
      nchildren = term_num_children(terms, t);
2✔
256
      for (i=0; i<nchildren && !trigger; i++) {
6✔
257
        term_t child;
258
        mpq_t q;
259
        mpq_init(q);
4✔
260
        sum_term_component(terms, t, i, q, &child);
4✔
261
        trigger = term_requires_mcsat_supplement(ctx, child, cache);
4✔
262
        mpq_clear(q);
4✔
263
      }
264

265
    } else if (term_is_bvsum(terms, t)) {
47✔
266
      int32_t *aux;
267
      uint32_t nbits;
268
      term_t child;
269

NEW
270
      nbits = term_bitsize(terms, t);
×
NEW
271
      aux = (int32_t *) safe_malloc(nbits * sizeof(int32_t));
×
NEW
272
      nchildren = term_num_children(terms, t);
×
NEW
273
      for (i=0; i<nchildren && !trigger; i++) {
×
NEW
274
        bvsum_term_component(terms, t, i, aux, &child);
×
NEW
275
        trigger = term_requires_mcsat_supplement(ctx, child, cache);
×
276
      }
NEW
277
      safe_free(aux);
×
278

279
    } else if (term_is_product(terms, t)) {
47✔
NEW
280
      nchildren = term_num_children(terms, t);
×
NEW
281
      for (i=0; i<nchildren && !trigger; i++) {
×
282
        term_t child;
283
        uint32_t exp;
NEW
284
        product_term_component(terms, t, i, &child, &exp);
×
NEW
285
        trigger = term_requires_mcsat_supplement(ctx, child, cache);
×
286
      }
287

288
    } else if (term_is_composite(terms, t)) {
47✔
289
      nchildren = term_num_children(terms, t);
21✔
290
      for (i=0; i<nchildren && !trigger; i++) {
59✔
291
        trigger = term_requires_mcsat_supplement(ctx, term_child(terms, t, i), cache);
38✔
292
      }
293
    }
294
  }
295

296
  p = int_hmap_get(cache, t);
62✔
297
  p->val = trigger ? 1 : 0;
62✔
298
  return trigger;
62✔
299
}
300

301
int32_t context_attach_mcsat_supplement(context_t *ctx) {
7✔
302
  mcsat_satellite_t *sat;
303

304
  if (ctx->mcsat_supplement) {
7✔
NEW
305
    return CTX_NO_ERROR;
×
306
  }
307
  if (ctx->arch == CTX_ARCH_MCSAT || ctx->egraph == NULL) {
7✔
NEW
308
    return CONTEXT_UNSUPPORTED_THEORY;
×
309
  }
310

311
  sat = new_mcsat_satellite(ctx);
7✔
312
  egraph_attach_mcsat_solver(ctx->egraph, sat,
7✔
313
                             mcsat_satellite_ctrl_interface(sat),
314
                             mcsat_satellite_smt_interface(sat),
315
                             NULL);
316
  egraph_attach_arith_observer(ctx->egraph, sat, mcsat_satellite_arith_observer_interface(sat));
7✔
317
  ctx->mcsat_supplement = true;
7✔
318

319
  return CTX_NO_ERROR;
7✔
320
}
321

322
static void context_disable_mcsat_supplement(context_t *ctx) {
7✔
323
  mcsat_satellite_t *sat;
324

325
  if (!ctx->mcsat_supplement || ctx->egraph == NULL) {
7✔
NEW
326
    return;
×
327
  }
328

329
  sat = context_mcsat_satellite(ctx);
7✔
330
  egraph_detach_arith_observer(ctx->egraph, sat);
7✔
331
  egraph_detach_mcsat_solver(ctx->egraph);
7✔
332
  delete_mcsat_satellite(sat);
7✔
333
  ctx->mcsat_supplement = false;
7✔
334
}
335

336
static bool mcsat_satellite_candidate_atom(term_table_t *terms, term_t atom) {
49✔
337
  switch (term_kind(terms, atom)) {
49✔
338
  case ARITH_ROOT_ATOM:
33✔
339
  case ARITH_FF_EQ_ATOM:
340
  case ARITH_FF_BINEQ_ATOM:
341
  case ARITH_IS_INT_ATOM:
342
  case ARITH_EQ_ATOM:
343
  case ARITH_GE_ATOM:
344
  case ARITH_BINEQ_ATOM:
345
  case ARITH_DIVIDES_ATOM:
346
    return true;
33✔
347

348
  default:
16✔
349
    return false;
16✔
350
  }
351
}
352

353
static bool context_atom_requires_mcsat(context_t *ctx, term_t atom) {
554,115✔
354
  int_hmap_t cache;
355
  bool trigger;
356

357
  atom = unsigned_term(atom);
554,115✔
358
  if (!ctx->mcsat_supplement || !is_boolean_term(ctx->terms, atom)) {
554,115✔
359
    return false;
554,084✔
360
  }
361
  if (!mcsat_satellite_candidate_atom(ctx->terms, atom)) {
31✔
362
    return false;
8✔
363
  }
364

365
  init_int_hmap(&cache, 0);
23✔
366
  if (!context_has_arith_solver(ctx)) {
23✔
NEW
367
    trigger = term_contains_arith_or_ff(ctx, atom, &cache);
×
NEW
368
    if (!trigger) {
×
NEW
369
      int_hmap_reset(&cache);
×
NEW
370
      trigger = term_requires_mcsat_supplement(ctx, atom, &cache);
×
371
    }
372
  } else {
373
    trigger = term_requires_mcsat_supplement(ctx, atom, &cache);
23✔
374
  }
375
  delete_int_hmap(&cache);
23✔
376

377
  return trigger;
23✔
378
}
379

380
static void context_observe_mcsat_atom(context_t *ctx, term_t atom, literal_t l) {
18✔
381
  int_hmap_t cache;
382
  bool observe;
383

384
  if (!ctx->mcsat_supplement || !is_boolean_term(ctx->terms, atom) ||
18✔
385
      !mcsat_satellite_candidate_atom(ctx->terms, atom)) {
18✔
386
    return;
8✔
387
  }
388

389
  init_int_hmap(&cache, 0);
10✔
390
  observe = term_contains_arith_or_ff(ctx, atom, &cache);
10✔
391
  delete_int_hmap(&cache);
10✔
392

393
  if (observe) {
10✔
394
    int32_t code = egraph_arith_observer_register_atom(ctx->egraph, atom, l);
10✔
395
    if (code < 0) {
10✔
NEW
396
      longjmp(ctx->env, code);
×
397
    }
398
  }
399
}
400

401
static literal_t map_mcsat_atom_to_literal(context_t *ctx, term_t atom) {
13✔
402
  mcsat_satellite_t *sat;
403
  literal_t l;
404
  void *obj;
405
  int32_t code;
406

407
  sat = context_mcsat_satellite(ctx);
13✔
408
  assert(sat != NULL);
409

410
  l = pos_lit(create_boolean_variable(ctx->core));
13✔
411
  obj = NULL;
13✔
412
  code = mcsat_satellite_register_atom(sat, atom, l, &obj);
13✔
413
  if (code < 0) {
13✔
NEW
414
    longjmp(ctx->env, code);
×
415
  }
416

417
  attach_atom_to_bvar(ctx->core, var_of(l), tagged_mcsat_atom(obj));
13✔
418
  return l;
13✔
419
}
420

421

422

423
/****************************************
424
 *  CONSTRUCTION OF EGRAPH OCCURRENCES  *
425
 ***************************************/
426

427
/*
428
 * Create a new egraph constant of the given type
429
 */
430
static eterm_t make_egraph_constant(context_t *ctx, type_t type, int32_t id) {
1,164✔
431
  assert(type_kind(ctx->types, type) == UNINTERPRETED_TYPE ||
432
         type_kind(ctx->types, type) == SCALAR_TYPE);
433
  return egraph_make_constant(ctx->egraph, type, id);
1,164✔
434
}
435

436

437
/*
438
 * Create a new egraph variable
439
 * - type = its type
440
 */
441
static eterm_t make_egraph_variable(context_t *ctx, type_t type) {
14,087✔
442
  eterm_t u;
443
  bvar_t v;
444

445
  if (type == bool_type(ctx->types)) {
14,087✔
446
    v = create_boolean_variable(ctx->core);
×
447
    u = egraph_bvar2term(ctx->egraph, v);
×
448
  } else {
449
    //    u = egraph_make_variable(ctx->egraph, type);
450
    // it's better to use skolem_term in case type is (tuple ...)
451
    u = egraph_skolem_term(ctx->egraph, type);
14,087✔
452
  }
453
  return u;
14,087✔
454
}
455

456

457
/*
458
 * Type of arithmetic variable x
459
 */
460
static type_t type_of_arithvar(context_t *ctx, thvar_t x) {
1,562✔
461
  type_t tau;
462

463
  tau = real_type(ctx->types);
1,562✔
464
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
1,562✔
465
    tau = int_type(ctx->types);
1,425✔
466
  }
467

468
  return tau;
1,562✔
469
}
470

471

472
/*
473
 * Convert arithmetic variable x to an egraph term
474
 */
475
static occ_t translate_arithvar_to_eterm(context_t *ctx, thvar_t x) {
1,571✔
476
  eterm_t u;
477
  type_t tau;
478

479
  u = ctx->arith.eterm_of_var(ctx->arith_solver, x);
1,571✔
480
  if (u == null_eterm) {
1,571✔
481
    tau = type_of_arithvar(ctx, x);
1,562✔
482
    u = egraph_thvar2term(ctx->egraph, x, tau);
1,562✔
483
  }
484

485
  return pos_occ(u);
1,571✔
486
}
487

488
/*
489
 * Convert bit-vector variable x to an egraph term
490
 * - tau = type of x
491
 */
492
static occ_t translate_bvvar_to_eterm(context_t *ctx, thvar_t x, type_t tau) {
3,693✔
493
  eterm_t u;
494

495
  u = ctx->bv.eterm_of_var(ctx->bv_solver, x);
3,693✔
496
  if (u == null_eterm) {
3,693✔
497
    u = egraph_thvar2term(ctx->egraph, x, tau);
3,672✔
498
  }
499

500
  return pos_occ(u);
3,693✔
501
}
502

503

504
/*
505
 * Convert variable x into an eterm internalization for t
506
 * - tau = type of t
507
 * - if x is mapped to an existing eterm u, return pos_occ(u)
508
 * - otherwise, create an egraph variable u and attach x to u
509
 *   then record the converse mapping [x --> u] in the relevant
510
 *   theory solver
511
 */
512
static occ_t translate_thvar_to_eterm(context_t *ctx, thvar_t x, type_t tau) {
3,348✔
513
  if (is_arithmetic_type(tau)) {
3,348✔
514
    return translate_arithvar_to_eterm(ctx, x);
619✔
515
  } else if (is_bv_type(ctx->types, tau)) {
2,729✔
516
    return translate_bvvar_to_eterm(ctx, x, tau);
2,729✔
517
  } else {
518
    longjmp(ctx->env, INTERNAL_ERROR);
×
519
  }
520
}
521

522

523
/*
524
 * Convert internalization code x for a term t into an egraph term
525
 * - t must be a root in the internalization table and must have
526
 *   positive polarity
527
 */
528
static occ_t translate_code_to_eterm(context_t *ctx, term_t t, int32_t x) {
64,982✔
529
  occ_t u;
530
  type_t tau;
531

532
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t) &&
533
         intern_tbl_map_of_root(&ctx->intern, t) == x);
534

535
  if (code_is_eterm(x)) {
64,982✔
536
    u = code2occ(x);
64,233✔
537
  } else {
538
    // x encodes a theory variable or a literal
539
    // convert that to an egraph term
540
    tau = type_of_root(ctx, t);
749✔
541
    switch (type_kind(ctx->types, tau)) {
749✔
542
    case BOOL_TYPE:
×
543
      u = egraph_literal2occ(ctx->egraph, code2literal(x));
×
544
      break;
×
545

546
    case INT_TYPE:
611✔
547
    case REAL_TYPE:
548
      u = translate_arithvar_to_eterm(ctx, code2thvar(x));
611✔
549
      break;
611✔
550

551
    case BITVECTOR_TYPE:
138✔
552
      u = translate_bvvar_to_eterm(ctx, code2thvar(x), tau);
138✔
553
      break;
138✔
554

555
    default:
×
556
      assert(false);
557
      longjmp(ctx->env, INTERNAL_ERROR);
×
558
    }
559

560
    // remap t to u
561
    intern_tbl_remap_root(&ctx->intern, t, occ2code(u));
749✔
562
  }
563

564
  return u;
64,982✔
565
}
566

567

568
/*
569
 * Internalization error for term t
570
 * - t can't be processed because there's no egraph
571
 * - the error code depends on t's type
572
 */
573
static int32_t uf_error_code(context_t *ctx, term_t t) {
×
574
  int32_t code;
575

576
  assert(! context_has_egraph(ctx));
577

578
  switch (term_type_kind(ctx->terms, t)) {
×
579
  case UNINTERPRETED_TYPE:
×
580
    code = UTYPE_NOT_SUPPORTED;
×
581
    break;
×
582

583
  case SCALAR_TYPE:
×
584
    code = SCALAR_NOT_SUPPORTED;
×
585
    break;
×
586

587
  case FUNCTION_TYPE:
×
588
    code = UF_NOT_SUPPORTED;
×
589
    break;
×
590

591
  case TUPLE_TYPE:
×
592
    code = TUPLE_NOT_SUPPORTED;
×
593
    break;
×
594

595
  default:
×
596
    assert(false);
597
    code = INTERNAL_ERROR;
×
598
    break;
×
599
  }
600

601
  return code;
×
602
}
603

604

605
/*
606
 * Utility to filter out high-order terms:
607
 * - check whether any term in a[0 ... n-1] has function type.
608
 * - if so throw an exception (via lonjmp) if the context does not include
609
 *   the array solver.
610
 */
611
static void check_high_order_support(context_t *ctx, const term_t *a, uint32_t n) {
18,027✔
612
  uint32_t i;
613

614
  if (! context_has_fun_solver(ctx)) {
18,027✔
615
    for (i=0; i<n; i++) {
30,058✔
616
      if (is_function_term(ctx->terms, a[i])) {
17,192✔
617
        longjmp(ctx->env, HIGH_ORDER_FUN_NOT_SUPPORTED);
3✔
618
      }
619
    }
620
  }
621
}
18,024✔
622

623

624
/***********************************************
625
 *  CONVERSION OF COMPOSITES TO EGRAPH TERMS   *
626
 **********************************************/
627

628
/*
629
 * Map apply term to an eterm
630
 * - tau = type of that term
631
 */
632
static occ_t map_apply_to_eterm(context_t *ctx, composite_term_t *app, type_t tau) {
9,685✔
633
  eterm_t u;
634
  occ_t *a;
635
  uint32_t i, n;
636

637
  assert(app->arity > 0);
638
  n = app->arity;
9,685✔
639

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

642
  a = alloc_istack_array(&ctx->istack, n);
9,685✔
643
  for (i=0; i<n; i++) {
34,029✔
644
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
24,344✔
645
  }
646

647
  // a[0] = function
648
  // a[1 ... n-1] are the arguments
649
  u = egraph_make_apply(ctx->egraph, a[0], n-1, a+1, tau);
9,685✔
650
  free_istack_array(&ctx->istack, a);
9,685✔
651

652
  //  add_type_constraints(ctx, pos_occ(u), tau);
653

654
  return pos_occ(u);
9,685✔
655
}
656

657

658
/*
659
 * Build a tuple of same type as t then assert that it's equal to u1
660
 * - t must be a root in the internalization table
661
 * - u1 must be equal to t's internalization (as stored in intern_table)
662
 * This is the skolemization of (exist (x1...x_n) u1 == (tuple x1 ... x_n))
663
 *
664
 * - return the eterm u := (tuple x1 ... x_n)
665
 */
666
static eterm_t skolem_tuple(context_t *ctx, term_t t, occ_t u1) {
×
667
  type_t tau;
668
  eterm_t u;
669

670
  assert(intern_tbl_is_root(&ctx->intern, t) && is_pos_term(t) &&
671
         intern_tbl_map_of_root(&ctx->intern, t) == occ2code(u1));
672

673
  tau = intern_tbl_type_of_root(&ctx->intern, t);
×
674
  u = egraph_skolem_term(ctx->egraph, tau);
×
675
  egraph_assert_eq_axiom(ctx->egraph, u1, pos_occ(u));
×
676

677
  return u;
×
678
}
679

680

681
/*
682
 * Convert (select i t) to an egraph term
683
 * - tau must be the type of that term (should not be bool)
684
 * - if a new eterm u is created, attach a theory variable to it
685
 */
686
static occ_t map_select_to_eterm(context_t *ctx, select_term_t *s, type_t tau) {
245✔
687
  occ_t u1;
688
  eterm_t tuple;
689
  composite_t *tp;
690

691
  u1 = internalize_to_eterm(ctx, s->arg);
245✔
692
  tuple = egraph_get_tuple_in_class(ctx->egraph, term_of_occ(u1));
245✔
693
  if (tuple == null_eterm) {
245✔
694
    tuple = skolem_tuple(ctx, s->arg, u1);
×
695
  }
696

697
  tp = egraph_term_body(ctx->egraph, tuple);
245✔
698
  assert(composite_body(tp) && tp != NULL && composite_kind(tp) == COMPOSITE_TUPLE);
699

700
  return tp->child[s->idx];
245✔
701
}
702

703

704
/*
705
 * Convert a conditional expression to an egraph term
706
 * - c = conditional descriptor
707
 * - tau = type of c
708
 */
709
static occ_t map_conditional_to_eterm(context_t *ctx, conditional_t *c, type_t tau) {
12✔
710
  literal_t *a;
711
  occ_t u, v;
712
  uint32_t i, n;
713
  literal_t l;
714
  bool all_false;
715
  term_t t;
716

717
#if 0
718
  printf("---> conditional to eterm\n");
719
#endif
720

721
  t = simplify_conditional(ctx, c);
12✔
722
  if (t != NULL_TERM) {
12✔
723
    return internalize_to_eterm(ctx, t);
4✔
724
  }
725

726
  n = c->nconds;
8✔
727
  a = alloc_istack_array(&ctx->istack, n + 1);
8✔
728

729
  all_false = true;
8✔
730
  u = null_occurrence;
8✔
731

732
  for (i=0; i<n; i++) {
24✔
733
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
16✔
734
    if (a[i] == true_literal) {
16✔
735
      /*
736
       * a[0] ... a[i-1] are all reducible to false
737
       * but we can't assume that a[0] ... a[i-1] are all false_literals
738
       * since we don't know how the theory solver internalizes the
739
       * conditions.
740
       */
741
      v = internalize_to_eterm(ctx, c->pair[i].val);
×
742
      if (all_false) {
×
743
        // all previous conditions a[0 ... i-1] are false
744
        assert(u == null_occurrence);
745
        u = v;
×
746
      } else {
747
        // we assert (u == v) as a top-level equality
748
        egraph_assert_eq_axiom(ctx->egraph, u, v);
×
749
      }
750
      goto done;
×
751
    }
752
    if (a[i] != false_literal) {
16✔
753
      if (all_false) {
13✔
754
        assert(u == null_occurrence);
755
        u = pos_occ(make_egraph_variable(ctx, tau));
7✔
756
        all_false = false;
7✔
757
      }
758
      // one clause for a[i] => (u = v[i])
759
      v = internalize_to_eterm(ctx, c->pair[i].val);
13✔
760
      l = egraph_make_eq(ctx->egraph, u, v);
13✔
761
      add_binary_clause(ctx->core, not(a[i]), l);
13✔
762
    }
763
  }
764

765
  if (all_false) {
8✔
766
    assert(u == null_occurrence);
767
    u = internalize_to_eterm(ctx, c->defval);
1✔
768
    goto done;
1✔
769
  }
770

771
  // clause for the default value
772
  assert(u != null_occurrence);
773
  v = internalize_to_eterm(ctx, c->defval);
7✔
774
  l = egraph_make_eq(ctx->egraph, u, v);
7✔
775
  a[n] = l;
7✔
776
  add_clause(ctx->core, n+1, a);
7✔
777

778
 done:
8✔
779
  free_istack_array(&ctx->istack, a);
8✔
780

781
  return u;
8✔
782
}
783

784

785
/*
786
 * Auxiliary function for flattening if-then-else
787
 * - v contains a conjunction of n literals: l0 /\ ... /\ l_n
788
 * - we something like (l0 /\ ... /\ l_n implies (x = y))
789
 *   (i.e., (not l0) \/ ... \/ (not l_n) \/ (x = y)
790
 * - this function negates all the literals in place
791
 */
792
static void ite_prepare_antecedents(ivector_t *v) {
8,348✔
793
  uint32_t i, n;
794

795
  n = v->size;
8,348✔
796
  for (i=0; i<n; i++) {
20,408✔
797
    v->data[i] = not(v->data[i]);
12,060✔
798
  }
799
}
8,348✔
800

801

802
/*
803
 * Convert nested if-then-else to  an egraph term
804
 * - ite = term of the form (ite c1 t1 t2)
805
 * - c = internalization of c1
806
 * - tau = type of the term (ite c1 t1 t2)
807
 */
808
static occ_t flatten_ite_to_eterm(context_t *ctx, composite_term_t *ite, literal_t c, type_t tau) {
1,168✔
809
  ite_flattener_t *flattener;
810
  ivector_t *buffer;
811
  term_t x;
812
  occ_t u, v;
813
  literal_t l;
814

815
  u = pos_occ(make_egraph_variable(ctx, tau));
1,168✔
816

817
  flattener = objstack_alloc(&ctx->ostack, sizeof(ite_flattener_t), (cleaner_t) delete_ite_flattener);
1,168✔
818
  init_ite_flattener(flattener);
1,168✔
819

820
  ite_flattener_push(flattener, ite, c);
1,168✔
821

822
  while (ite_flattener_is_nonempty(flattener)) {
4,210✔
823
    if (ite_flattener_last_lit_false(flattener)) {
3,042✔
824
      // dead branch
825
      ite_flattener_next_branch(flattener);
6✔
826
      continue;
6✔
827
    }
828
    assert(ite_flattener_branch_is_live(flattener));
829

830
    x = ite_flattener_leaf(flattener);
3,036✔
831
    x = intern_tbl_get_root(&ctx->intern, x);
3,036✔
832

833
    /*
834
     * x is the current leaf.
835
     * If it's (ite ...) then we can expand the tree by pushing x.
836
     *
837
     * Heuristic: we don't do it if x is a shared term or if it's
838
     * already internalized.
839
     * - we also need a cutoff since the number of branches grows
840
     *   exponentially.
841
     */
842
    if (is_pos_term(x) &&
6,072✔
843
        is_ite_term(ctx->terms, x) &&
3,036✔
844
        !intern_tbl_root_is_mapped(&ctx->intern, x) &&
2,473✔
845
        term_is_not_shared(&ctx->sharing, x)) {
774✔
846
      /*
847
       * x is of the form (ite c a b) and not internalized already,
848
       * we push (ite c a b) on the flattener.
849
       */
850
      ite = ite_term_desc(ctx->terms, x);
353✔
851
      assert(ite->arity == 3);
852
      c = internalize_to_literal(ctx, ite->arg[0]);
353✔
853
      ite_flattener_push(flattener, ite, c);
353✔
854
    } else {
855
      /*
856
       * Add the clause [branch conditions => x = u]
857
       */
858
      v = internalize_to_eterm(ctx, x);
2,683✔
859
      l = egraph_make_eq(ctx->egraph, u, v);
2,683✔
860

861
      buffer = &ctx->aux_vector;
2,683✔
862
      assert(buffer->size == 0);
863
      ite_flattener_get_clause(flattener, buffer);
2,683✔
864
      ite_prepare_antecedents(buffer);
2,683✔
865
      ivector_push(buffer, l);
2,683✔
866
      add_clause(ctx->core, buffer->size, buffer->data);
2,683✔
867
      ivector_reset(buffer);
2,683✔
868

869
      ite_flattener_next_branch(flattener);
2,683✔
870
    }
871
  }
872

873
  //  delete_ite_flattener(&flattener);
874
  objstack_pop(&ctx->ostack);
1,168✔
875

876
  return u;
1,168✔
877
}
878

879

880
/*
881
 * Convert (ite c t1 t2) to an egraph term
882
 * - tau = type of (ite c t1 t2)
883
 */
884
static occ_t map_ite_to_eterm(context_t *ctx, composite_term_t *ite, type_t tau) {
2,168✔
885
  conditional_t *d;
886
  eterm_t u;
887
  occ_t u1, u2, u3;
888
  literal_t c, l1, l2;
889

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

894
  d = context_make_conditional(ctx, ite);
2,168✔
895
  if (d != NULL) {
2,168✔
896
    u1 = map_conditional_to_eterm(ctx, d, tau);
12✔
897
    context_free_conditional(ctx, d);
12✔
898
    return u1;
12✔
899
  }
900

901
  c = internalize_to_literal(ctx, ite->arg[0]);
2,156✔
902
  if (c == true_literal) {
2,156✔
903
    return internalize_to_eterm(ctx, ite->arg[1]);
110✔
904
  }
905
  if (c == false_literal) {
2,046✔
906
    return internalize_to_eterm(ctx, ite->arg[2]);
15✔
907
  }
908

909
  if (context_ite_flattening_enabled(ctx)) {
2,031✔
910
    return flatten_ite_to_eterm(ctx, ite, c, tau);
1,168✔
911
  }
912

913
  u2 = internalize_to_eterm(ctx, ite->arg[1]);
863✔
914
  u3 = internalize_to_eterm(ctx, ite->arg[2]);
863✔
915

916
  if (context_keep_ite_enabled(ctx)) {
863✔
917
    // build the if-then-else in the egraph
918
    u1 = egraph_literal2occ(ctx->egraph, c);
2✔
919
    u = egraph_make_ite(ctx->egraph, u1, u2, u3, tau);
2✔
920
  } else {
921
    // eliminate the if-then-else
922
    u = make_egraph_variable(ctx, tau);
861✔
923
    l1 = egraph_make_eq(ctx->egraph, pos_occ(u), u2);
861✔
924
    l2 = egraph_make_eq(ctx->egraph, pos_occ(u), u3);
861✔
925

926
    assert_ite(&ctx->gate_manager, c, l1, l2, true);
861✔
927
  }
928

929
  return pos_occ(u);
863✔
930
}
931

932

933

934
/*
935
 * Convert (update f t_1 ... t_n v) to a term
936
 * - tau = type of that term
937
 */
938
static occ_t map_update_to_eterm(context_t *ctx, composite_term_t *update, type_t tau) {
11,470✔
939
  eterm_t u;
940
  occ_t *a;
941
  uint32_t i, n;
942

943
  assert(update->arity > 2);
944

945
  n = update->arity;
11,470✔
946
  a = alloc_istack_array(&ctx->istack, n);
11,470✔
947
  for (i=0; i<n; i++) {
45,880✔
948
    a[i] = internalize_to_eterm(ctx, update->arg[i]);
34,410✔
949
  }
950

951
  // a[0]: function f
952
  // a[1] ... a[n-2]: t_1 .. t_{n-2}
953
  // a[n-1]: new value v
954
  u = egraph_make_update(ctx->egraph, a[0], n-2, a+1, a[n-1], tau);
11,470✔
955

956
  free_istack_array(&ctx->istack, a);
11,470✔
957

958
  return pos_occ(u);
11,470✔
959
}
960

961

962

963
/*
964
 * Convert (tuple t_1 ... t_n) to a term
965
 * - tau = type of the tuple
966
 */
967
static occ_t map_tuple_to_eterm(context_t *ctx, composite_term_t *tuple, type_t tau) {
190✔
968
  eterm_t u;
969
  occ_t *a;
970
  uint32_t i, n;
971

972
  n = tuple->arity;
190✔
973

974
  check_high_order_support(ctx, tuple->arg, n);
190✔
975

976
  a = alloc_istack_array(&ctx->istack, n);
190✔
977
  for (i=0; i<n; i++) {
560✔
978
    a[i] = internalize_to_eterm(ctx, tuple->arg[i]);
370✔
979
  }
980

981
  u = egraph_make_tuple(ctx->egraph, n, a, tau);
190✔
982
  free_istack_array(&ctx->istack, a);
190✔
983

984
  return pos_occ(u);
190✔
985
}
986

987

988
/*
989
 * Convert arithmetic and bitvector constants to eterm
990
 * - check whether the relevant solver exists first
991
 * - then map the constant to a solver variable x
992
 *   and convert x to an egraph occurrence
993
 */
994
static occ_t map_arith_constant_to_eterm(context_t *ctx, rational_t *q) {
339✔
995
  thvar_t x;
996

997
  if (! context_has_arith_solver(ctx)) {
339✔
998
    longjmp(ctx->env, ARITH_NOT_SUPPORTED);
×
999
  }
1000

1001
  x = ctx->arith.create_const(ctx->arith_solver, q);
339✔
1002
  return translate_arithvar_to_eterm(ctx, x);
339✔
1003
}
1004

1005
static occ_t map_bvconst64_to_eterm(context_t *ctx, bvconst64_term_t *c) {
808✔
1006
  thvar_t x;
1007
  type_t tau;
1008

1009
  if (! context_has_bv_solver(ctx)) {
808✔
1010
    longjmp(ctx->env, BV_NOT_SUPPORTED);
×
1011
  }
1012

1013
  x = ctx->bv.create_const64(ctx->bv_solver, c);
808✔
1014
  tau = bv_type(ctx->types, c->bitsize);
808✔
1015

1016
  return translate_bvvar_to_eterm(ctx, x, tau);
808✔
1017
}
1018

1019
static occ_t map_bvconst_to_eterm(context_t *ctx, bvconst_term_t *c) {
18✔
1020
  thvar_t x;
1021
  type_t tau;
1022

1023
  if (! context_has_bv_solver(ctx)) {
18✔
1024
    longjmp(ctx->env, BV_NOT_SUPPORTED);
×
1025
  }
1026

1027
  x = ctx->bv.create_const(ctx->bv_solver, c);
18✔
1028
  tau = bv_type(ctx->types, c->bitsize);
18✔
1029

1030
  return translate_bvvar_to_eterm(ctx, x, tau);
18✔
1031
}
1032

1033

1034

1035
/***************************************
1036
 *  AXIOMS FOR DIV/MOD/FLOOR/CEIL/ABS  *
1037
 **************************************/
1038

1039
/*
1040
 * Auxiliary function: p and map to represent (x - y)
1041
 * - in polynomial p, only the coefficients are relevant
1042
 * - map[0] stores x and map[1] stores y
1043
 * - both p map must be large enough (at least 2 elements)
1044
 */
1045
static void context_store_diff_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
×
1046
  p->nterms = 2;
×
1047
  p->mono[0].var = 1;
×
1048
  q_set_one(&p->mono[0].coeff);       // coeff of x = 1
×
1049
  p->mono[1].var = 2;
×
1050
  q_set_minus_one(&p->mono[1].coeff); // coeff of y = -1
×
1051
  p->mono[2].var = max_idx; // end marker
×
1052

1053
  map[0] = x;
×
1054
  map[1] = y;
×
1055
}
×
1056

1057

1058
/*
1059
 * Same thing for the polynomial (x - y - 1)
1060
 */
1061
static void context_store_diff_minus_one_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
×
1062
  p->nterms = 3;
×
1063
  p->mono[0].var = const_idx;
×
1064
  q_set_minus_one(&p->mono[0].coeff);  // constant = -1
×
1065
  p->mono[1].var = 1;
×
1066
  q_set_one(&p->mono[1].coeff);        // coeff of x = 1
×
1067
  p->mono[2].var = 2;
×
1068
  q_set_minus_one(&p->mono[2].coeff);  // coeff of y = -1
×
1069
  p->mono[3].var = max_idx;
×
1070

1071
  map[0] = null_thvar; // constant
×
1072
  map[1] = x;
×
1073
  map[2] = y;
×
1074
}
×
1075

1076

1077
/*
1078
 * Same thing for the polynomial (x + y)
1079
 */
1080
static void context_store_sum_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
4✔
1081
  p->nterms = 2;
4✔
1082
  p->mono[0].var = 1;
4✔
1083
  q_set_one(&p->mono[0].coeff); // coeff of x = 1
4✔
1084
  p->mono[1].var = 2;
4✔
1085
  q_set_one(&p->mono[1].coeff); // coeff of y = 1
4✔
1086
  p->mono[2].var = max_idx;
4✔
1087

1088
  map[0] = x;
4✔
1089
  map[1] = y;
4✔
1090
}
4✔
1091

1092

1093
/*
1094
 * The lower bound on y = (div x k)  is (k * y <= x) or (x - k * y >= 0)
1095
 * We store the polynomial x - k * y
1096
 */
1097
static void context_store_div_lower_bound(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
21✔
1098
  p->nterms = 2;
21✔
1099
  p->mono[0].var = 1;
21✔
1100
  q_set_one(&p->mono[0].coeff);    // coeff of x = 1
21✔
1101
  p->mono[1].var = 2;
21✔
1102
  q_set_neg(&p->mono[1].coeff, k); // coeff of y = -k
21✔
1103
  p->mono[2].var = max_idx;
21✔
1104

1105
  map[0] = x;
21✔
1106
  map[1] = y;
21✔
1107
}
21✔
1108

1109

1110
/*
1111
 * For converting (divides k x), we use (divides k x) <=> (x <= k * (div x k))
1112
 * or (k * y - x >= 0) for y = (div x k).
1113
 * We store the polynomial - x + k * y.
1114
 */
1115
static void context_store_divides_constraint(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
8✔
1116
  p->nterms = 2;
8✔
1117
  p->mono[0].var = 1;
8✔
1118
  q_set_minus_one(&p->mono[0].coeff);  // coeff of x = -1
8✔
1119
  p->mono[1].var = 2;
8✔
1120
  q_set(&p->mono[1].coeff, k);         // coeff of y = k
8✔
1121
  p->mono[2].var = max_idx;
8✔
1122

1123
  map[0] = x;
8✔
1124
  map[1] = y;
8✔
1125
}
8✔
1126

1127
/*
1128
 * Upper bound on y = (div x k) when both x and y are integer:
1129
 * We have x <= k * y + |k| - 1 or (-x + k y + |k| - 1 >= 0).
1130
 *
1131
 * We store the polynomial - x + k y + |k| - 1
1132
 *
1133
 * NOTE: we don't normalize the constant (|k| - 1) to zero if |k| = 1.
1134
 * This is safe as the simplex solver does not care.
1135
 */
1136
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✔
1137
  p->nterms = 3;
20✔
1138
  p->mono[0].var = const_idx;
20✔
1139
  q_set_abs(&p->mono[0].coeff, k);
20✔
1140
  q_sub_one(&p->mono[0].coeff);        // constant term = |k| - 1
20✔
1141
  p->mono[1].var = 1;
20✔
1142
  q_set_minus_one(&p->mono[1].coeff);  // coeff of x = -1
20✔
1143
  p->mono[2].var = 2;
20✔
1144
  q_set(&p->mono[2].coeff, k);         // coeff of y = k
20✔
1145
  p->mono[3].var = max_idx;
20✔
1146

1147
  map[0] = null_thvar;
20✔
1148
  map[1] = x;
20✔
1149
  map[2] = y;
20✔
1150
}
20✔
1151

1152
/*
1153
 * Upper bound on y = (div x k) when x or k is not an integer.
1154
 * We have x < k * y + |k| or x - k*y - |k| < 0 or (not (x - k*y - |k| >= 0))
1155
 *
1156
 * We store the polynomial x - ky - |k|
1157
 */
1158
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✔
1159
  p->nterms = 3;
1✔
1160
  p->mono[0].var = const_idx;
1✔
1161
  q_set_abs(&p->mono[0].coeff, k);
1✔
1162
  q_neg(&p->mono[0].coeff);           // constant term: -|k|
1✔
1163
  p->mono[1].var = 1;
1✔
1164
  q_set_one(&p->mono[1].coeff);       // coeff of x = +1
1✔
1165
  p->mono[2].var = 2;
1✔
1166
  q_set_neg(&p->mono[2].coeff, k);    // coeff of y = -k
1✔
1167
  p->mono[3].var = max_idx;
1✔
1168

1169
  map[0] = null_thvar;
1✔
1170
  map[1] = x;
1✔
1171
  map[2] = y;
1✔
1172
}
1✔
1173

1174

1175
/*
1176
 * Polynomial x - y + k d (for asserting y = k * (div y k) + (mod y k)
1177
 * - d is assumed to be (div y k)
1178
 * - x is assumed to be (mod y k)
1179
 */
1180
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✔
1181
  p->nterms = 3;
11✔
1182
  p->mono[0].var = 1;
11✔
1183
  q_set_one(&p->mono[0].coeff);       // coefficient of x = 1
11✔
1184
  p->mono[1].var = 2;
11✔
1185
  q_set_minus_one(&p->mono[1].coeff); // coefficient of y = -1
11✔
1186
  p->mono[2].var = 3;
11✔
1187
  q_set(&p->mono[2].coeff, k);        // coefficient of d = k
11✔
1188
  p->mono[3].var = max_idx;
11✔
1189

1190
  map[0] = x;
11✔
1191
  map[1] = y;
11✔
1192
  map[2] = d;
11✔
1193
}
11✔
1194

1195

1196
/*
1197
 * Bound on x = (mod y k) assuming x and k are integer:
1198
 * - the bound is x <= |k| - 1 (i.e., |k| - 1 - x >= 0)
1199
 *   so we construct |k| - 1 - x
1200
 */
1201
static void context_store_integer_mod_bound(polynomial_t *p, thvar_t *map, thvar_t x, const rational_t *k) {
10✔
1202
  p->nterms = 2;
10✔
1203
  p->mono[0].var = const_idx;
10✔
1204
  q_set_abs(&p->mono[0].coeff, k);
10✔
1205
  q_sub_one(&p->mono[0].coeff);        // constant = |k| - 1
10✔
1206
  p->mono[1].var = 1;
10✔
1207
  q_set_minus_one(&p->mono[1].coeff);  // coeff of x = -1
10✔
1208
  p->mono[2].var = max_idx;
10✔
1209

1210
  map[0] = null_thvar;
10✔
1211
  map[1] = x;
10✔
1212
}
10✔
1213

1214

1215
/*
1216
 * Bound on x = (mod y k) when x or k are rational
1217
 * - the bound is x < |k| or x - |k| < 0 or (not (x - |k| >= 0))
1218
 *   so we construct x - |k|
1219
 */
1220
static void context_store_rational_mod_bound(polynomial_t *p, thvar_t *map, thvar_t x, const rational_t *k) {
1✔
1221
  p->nterms = 2;
1✔
1222
  p->mono[0].var = const_idx;
1✔
1223
  q_set_abs(&p->mono[0].coeff, k);
1✔
1224
  q_neg(&p->mono[0].coeff);            // constant = -|k|
1✔
1225
  p->mono[1].var = 1;
1✔
1226
  q_set_one(&p->mono[1].coeff);        // coeff of x = +1
1✔
1227
  p->mono[2].var = max_idx;
1✔
1228

1229
  map[0] = null_thvar;
1✔
1230
  map[1] = x;
1✔
1231
}
1✔
1232

1233

1234
/*
1235
 * Assert constraints for x := floor(y)
1236
 * - both x and y are variables in the arithmetic solver
1237
 * - x has type integer
1238
 *
1239
 * We assert (x <= y && y < x+1)
1240
 */
1241
static void assert_floor_axioms(context_t *ctx, thvar_t x, thvar_t y) {
×
1242
  polynomial_t *p;
1243
  thvar_t map[3];
1244

1245
  assert(ctx->arith.arith_var_is_int(ctx->arith_solver, x));
1246

1247
  p = context_get_aux_poly(ctx, 4);
×
1248

1249
  // assert (y - x >= 0)
1250
  context_store_diff_poly(p, map, y, x);
×
1251
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
×
1252

1253
  // assert (y - x - 1 < 0) <=> (not (y - x - 1) >= 0)
1254
  context_store_diff_minus_one_poly(p, map, y, x);
×
1255
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
×
1256
}
×
1257

1258

1259
/*
1260
 * Assert constraints for x == ceil(y)
1261
 * - both x and y are variables in the arithmetic solver
1262
 * - x has type integer
1263
 *
1264
 * We assert (x - 1 < y && y <= x)
1265
 */
1266
static void assert_ceil_axioms(context_t *ctx, thvar_t x, thvar_t y) {
×
1267
  polynomial_t *p;
1268
  thvar_t map[3];
1269

1270
  assert(ctx->arith.arith_var_is_int(ctx->arith_solver, x));
1271

1272
  p = context_get_aux_poly(ctx, 4);
×
1273

1274
  // assert (x - y >= 0)
1275
  context_store_diff_poly(p, map, x, y);
×
1276
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
×
1277

1278
  // assert (x - y - 1 < 0) <=> (not (x - y - 1) >= 0)
1279
  context_store_diff_minus_one_poly(p, map, x, y);
×
1280
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
×
1281
}
×
1282

1283

1284
/*
1285
 * Assert constraints for x == abs(y)
1286
 * - x and y must be variables in the arithmetic solver
1287
 *
1288
 * We assert (x >= 0) AND ((x == y) or (x == -y))
1289
 */
1290
static void assert_abs_axioms(context_t *ctx, thvar_t x, thvar_t y) {
4✔
1291
  polynomial_t *p;
1292
  thvar_t map[2];
1293
  literal_t l1, l2;
1294

1295
  // assert (x >= 0)
1296
  ctx->arith.assert_ge_axiom(ctx->arith_solver, x, true);
4✔
1297

1298
  // create l1 := (x == y)
1299
  l1 = ctx->arith.create_vareq_atom(ctx->arith_solver, x, y);
4✔
1300

1301
  // create l2 := (x == -y) that is (x + y == 0)
1302
  p = context_get_aux_poly(ctx, 3);
4✔
1303
  context_store_sum_poly(p, map, x, y);
4✔
1304
  l2 = ctx->arith.create_poly_eq_atom(ctx->arith_solver, p, map);
4✔
1305

1306
  // assert (or l1 l2)
1307
  add_binary_clause(ctx->core, l1, l2);
4✔
1308
}
4✔
1309

1310

1311
/*
1312
 * Constraints for x == (div y k)
1313
 * - x and y must be variables in the arithmetic solver
1314
 * - x must be an integer variable
1315
 * - k is a non-zero rational constant
1316
 *
1317
 * If k and y are integer, we assert
1318
 *   k * x <= y <= k * x + |k| - 1
1319
 *
1320
 * Otherwise, we assert
1321
 *   k * x <= y < k * x + |k|
1322
 */
1323
static void assert_div_axioms(context_t *ctx, thvar_t x, thvar_t y, const rational_t *k) {
21✔
1324
  polynomial_t *p;
1325
  thvar_t map[3];
1326

1327
  p = context_get_aux_poly(ctx, 4);
21✔
1328

1329
  // assert k*x <= y (i.e., y - k*x >= 0)
1330
  context_store_div_lower_bound(p, map, y, x, k);
21✔
1331
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
21✔
1332

1333
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, y) && q_is_integer(k)) {
21✔
1334
    // y and k are both integer
1335
    // assert y <= k*x + |k| - 1 (i.e., - y + k x + |k| - 1 >= 0)
1336
    context_store_integer_div_upper_bound(p, map, y, x, k);
20✔
1337
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
20✔
1338

1339
  } else {
1340
    // assert y < k*x + |k| (i.e., y - k*x - |k| < 0) or (not (y - k*x - |k| >= 0))
1341
    context_store_rational_div_upper_bound(p, map, y, x, k);
1✔
1342
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
1✔
1343
  }
1344
}
21✔
1345

1346

1347
/*
1348
 * Constraints for x == (mod y k)
1349
 * - d must be the variable equal to (div y k)
1350
 * - x and y must be variables in the arithmetic solver
1351
 * - k is a non-zero rational constant.
1352
 *
1353
 * We assert x = y - k * d (i.e., (mod y k) = x - k * (div y k))
1354
 * and 0 <= x < |k|.
1355
 *
1356
 * NOTE: The 0 <= x < |k| part is redundant. It's implied by the
1357
 * div_axioms for d = (div y k). It's cheap enough that I can't
1358
 * see a problem with adding it anyway (it's just an interval for x).
1359
 */
1360
static void assert_mod_axioms(context_t *ctx, thvar_t x, thvar_t y, thvar_t d, const rational_t *k) {
11✔
1361
  polynomial_t *p;
1362
  thvar_t map[3];
1363

1364
  p = context_get_aux_poly(ctx, 4);
11✔
1365

1366
  // assert y = k * d + x (i.e., x - y + k *d = 0)
1367
  context_store_divmod_eq(p, map, x, y, d, k);
11✔
1368
  ctx->arith.assert_poly_eq_axiom(ctx->arith_solver, p, map, true);
11✔
1369

1370
  // assert x >= 0
1371
  ctx->arith.assert_ge_axiom(ctx->arith_solver, x, true);
11✔
1372

1373
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x) && q_is_integer(k)) {
11✔
1374
    // both x and |k| are integer
1375
    // assert x <= |k| - 1, i.e., -x + |k| - 1 >= 0
1376
    context_store_integer_mod_bound(p, map, x, k);
10✔
1377
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
10✔
1378
  } else {
1379
    // assert x < |k|, i.e., x - |k| <0, i.e., (not (x - |k| >= 0))
1380
    context_store_rational_mod_bound(p, map, x, k);
1✔
1381
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
1✔
1382
  }
1383
}
11✔
1384

1385

1386

1387
/******************************************************
1388
 *  CONVERSION OF COMPOSITES TO ARITHMETIC VARIABLES  *
1389
 *****************************************************/
1390

1391
/*
1392
 * Convert a conditional to an arithmetic variable
1393
 * - if is_int is true, the variable is integer otherwise, it's real
1394
 */
1395
static thvar_t map_conditional_to_arith(context_t *ctx, conditional_t *c, bool is_int) {
239✔
1396
  literal_t *a;
1397
  uint32_t i, n;
1398
  thvar_t x, v;
1399
  bool all_false;
1400
  term_t t;
1401

1402
#if 0
1403
  printf("---> conditional to arith\n");
1404
#endif
1405

1406
  t = simplify_conditional(ctx, c);
239✔
1407
  if (t != NULL_TERM) {
239✔
1408
    return internalize_to_arith(ctx, t);
13✔
1409
  }
1410

1411
  n = c->nconds;
226✔
1412
  a = alloc_istack_array(&ctx->istack, n);
226✔
1413

1414
  all_false = true;
226✔
1415
  v = null_thvar;
226✔
1416

1417
  for (i=0; i<n; i++) {
703✔
1418
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
485✔
1419
    if (a[i] == true_literal) {
485✔
1420
      /*
1421
       * a[0] ... a[i-1] are all reducible to false
1422
       * but we can't assume v == null_thvar, since
1423
       * we don't know how the theory solver internalizes
1424
       * the conditions (i.e., some of them may not be false_literal).
1425
       */
1426
      x = internalize_to_arith(ctx, c->pair[i].val);
8✔
1427
      if (all_false) {
8✔
1428
        assert(v == null_thvar);
1429
        v = x;
6✔
1430
      } else {
1431
        // assert (v == x) in the arithmetic solver
1432
        ctx->arith.assert_vareq_axiom(ctx->arith_solver, v, x, true);
2✔
1433
      }
1434
      goto done;
8✔
1435
    }
1436
    if (a[i] != false_literal) {
477✔
1437
      if (all_false) {
460✔
1438
        assert(v == null_thvar);
1439
        v = ctx->arith.create_var(ctx->arith_solver, is_int);
215✔
1440
        all_false = false;
215✔
1441
      }
1442
      // clause for a[i] => (v = c->pair[i].val)
1443
      x = internalize_to_arith(ctx, c->pair[i].val);
460✔
1444
      ctx->arith.assert_cond_vareq_axiom(ctx->arith_solver, a[i], v, x);
460✔
1445
    }
1446
  }
1447

1448
  if (all_false) {
218✔
1449
    assert(v == null_thvar);
1450
    v = internalize_to_arith(ctx, c->defval);
5✔
1451
    goto done;
5✔
1452
  }
1453

1454
  /*
1455
   * last clause (only if some a[i] isn't false):
1456
   * (a[0] \/ ... \/ a[n-1] \/ v == c->defval)
1457
   */
1458
  assert(v != null_thvar);
1459
  x = internalize_to_arith(ctx, c->defval);
213✔
1460
  ctx->arith.assert_clause_vareq_axiom(ctx->arith_solver, n, a, v, x);
213✔
1461

1462
 done:
226✔
1463
  free_istack_array(&ctx->istack, a);
226✔
1464
  return v;
226✔
1465
}
1466

1467

1468
/*
1469
 * Convert nested if-then-else to  an arithmetic variable
1470
 * - ite = term of the form (ite c1 t1 t2)
1471
 * - c = internalization of c1
1472
 * - is_int = true if the if-then-else term is integer (otherwise it's real)
1473
 */
1474
static thvar_t flatten_ite_to_arith(context_t *ctx, composite_term_t *ite, literal_t c, bool is_int) {
2,521✔
1475
  ite_flattener_t *flattener;
1476
  ivector_t *buffer;
1477
  term_t x;
1478
  thvar_t u, v;
1479

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

1482
  flattener = objstack_alloc(&ctx->ostack, sizeof(ite_flattener_t), (cleaner_t) delete_ite_flattener);
2,521✔
1483
  init_ite_flattener(flattener);
2,521✔
1484

1485
  ite_flattener_push(flattener, ite, c);
2,521✔
1486

1487
  while (ite_flattener_is_nonempty(flattener)) {
8,823✔
1488
    if (ite_flattener_last_lit_false(flattener)) {
6,302✔
1489
      // dead branch
1490
      ite_flattener_next_branch(flattener);
7✔
1491
      continue;
7✔
1492
    }
1493
    assert(ite_flattener_branch_is_live(flattener));
1494

1495
    x = ite_flattener_leaf(flattener);
6,295✔
1496
    x = intern_tbl_get_root(&ctx->intern, x);
6,295✔
1497

1498
    /*
1499
     * x is the current leaf
1500
     * If x is of the form (ite c a b) we can push (ite c a b) on the flattener.
1501
     *
1502
     * Heuristics: don't push the term if x is already internalized or if it's
1503
     * shared.
1504
     */
1505
    if (is_pos_term(x) &&
12,590✔
1506
        is_ite_term(ctx->terms, x) &&
6,295✔
1507
        !intern_tbl_root_is_mapped(&ctx->intern, x) &&
3,934✔
1508
        term_is_not_shared(&ctx->sharing, x)) {
1,256✔
1509
      ite = ite_term_desc(ctx->terms, x);
630✔
1510
      assert(ite->arity == 3);
1511
      c = internalize_to_literal(ctx, ite->arg[0]);
630✔
1512
      ite_flattener_push(flattener, ite, c);
630✔
1513
    } else {
1514
      /*
1515
       * Add the clause [branch conditions => x = u]
1516
       */
1517
      v = internalize_to_arith(ctx, x);
5,665✔
1518

1519
      buffer = &ctx->aux_vector;
5,665✔
1520
      assert(buffer->size == 0);
1521
      ite_flattener_get_clause(flattener, buffer);
5,665✔
1522
      ite_prepare_antecedents(buffer);
5,665✔
1523
      // assert [buffer \/ v = u]
1524
      ctx->arith.assert_clause_vareq_axiom(ctx->arith_solver, buffer->size, buffer->data, v, u);
5,665✔
1525
      ivector_reset(buffer);
5,665✔
1526

1527
      ite_flattener_next_branch(flattener);
5,665✔
1528
    }
1529
  }
1530

1531
  //  delete_ite_flattener(&flattener);
1532
   objstack_pop(&ctx->ostack);
2,521✔
1533

1534
  return u;
2,521✔
1535
}
1536

1537
/*
1538
 * Convert if-then-else to an arithmetic variable
1539
 * - if is_int is true, the if-then-else term is integer
1540
 * - otherwise, it's real
1541
 */
1542
static thvar_t map_ite_to_arith(context_t *ctx, composite_term_t *ite, bool is_int) {
3,023✔
1543
  conditional_t *d;
1544
  literal_t c;
1545
  thvar_t v, x;
1546

1547
  assert(ite->arity == 3);
1548

1549
  d = context_make_conditional(ctx, ite);
3,023✔
1550
  if (d != NULL) {
3,023✔
1551
    v = map_conditional_to_arith(ctx, d, is_int);
239✔
1552
    context_free_conditional(ctx, d);
239✔
1553
    return v;
239✔
1554
  }
1555

1556
  c = internalize_to_literal(ctx, ite->arg[0]); // condition
2,784✔
1557
  if (c == true_literal) {
2,784✔
1558
    return internalize_to_arith(ctx, ite->arg[1]);
77✔
1559
  }
1560
  if (c == false_literal) {
2,707✔
1561
    return internalize_to_arith(ctx, ite->arg[2]);
115✔
1562
  }
1563

1564
  if (context_ite_flattening_enabled(ctx)) {
2,592✔
1565
    return flatten_ite_to_arith(ctx, ite, c, is_int);
2,521✔
1566
  }
1567

1568

1569
  /*
1570
   * no simplification: create a fresh variable v and assert (c ==> v = t1)
1571
   * and (not c ==> v = t2)
1572
   */
1573
  v = ctx->arith.create_var(ctx->arith_solver, is_int);
71✔
1574

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

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

1581
  return v;
71✔
1582
}
1583

1584

1585
/*
1586
 * Assert the bounds on t when t is an arithmetic, special if-then-else
1587
 * - x = arithmetic variable mapped to t in the arithmetic solver
1588
 */
1589
static void assert_ite_bounds(context_t *ctx, term_t t, thvar_t x) {
793✔
1590
  term_table_t *terms;
1591
  polynomial_t *p;
1592
  term_t lb, ub;
1593
  thvar_t map[2];
1594

1595
  terms = ctx->terms;
793✔
1596
  assert(is_arithmetic_term(terms, t));
1597

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

1601
#if 0
1602
  printf("assert ite bound:\n  term: ");
1603
  print_term_name(stdout, terms, t);
1604
  printf("\n");
1605
  printf("  lower bound: ");
1606
  print_term_full(stdout, terms, lb);
1607
  printf("\n");
1608
  printf("  upper bound: ");
1609
  print_term_full(stdout, terms, ub);
1610
  printf("\n");
1611
#endif
1612

1613
  /*
1614
   * prepare polynomial p:
1615
   * first monomial is a constant, second monomial is either +t or -t
1616
   * map[0] = null (what's mapped to const_idx)
1617
   * map[1] = x = (what's mapped to t)
1618
   */
1619
  p = context_get_aux_poly(ctx, 3);
793✔
1620
  p->nterms = 2;
793✔
1621
  p->mono[0].var = const_idx;
793✔
1622
  p->mono[1].var = t;
793✔
1623
  p->mono[2].var = max_idx;
793✔
1624
  map[0] = null_thvar;
793✔
1625
  map[1] = x;
793✔
1626

1627

1628
  // first bound: t >= lb
1629
  q_set_neg(&p->mono[0].coeff, rational_term_desc(terms, lb)); // -lb
793✔
1630
  q_set_one(&p->mono[1].coeff); // +t
793✔
1631
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true); // assert -lb + t >= 0
793✔
1632

1633
  // second bound: t <= ub
1634
  q_set(&p->mono[0].coeff, rational_term_desc(terms, ub));  // +ub
793✔
1635
  q_set_minus_one(&p->mono[1].coeff);  // -t
793✔
1636
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true); // assert +ub - t >= 0
793✔
1637
}
793✔
1638

1639

1640
/*
1641
 * Convert a power product to an arithmetic variable
1642
 */
1643
static thvar_t map_pprod_to_arith(context_t *ctx, pprod_t *p) {
×
1644
  uint32_t i, n;
1645
  thvar_t *a;
1646
  thvar_t x;
1647

1648
  n = p->len;
×
1649
  a = alloc_istack_array(&ctx->istack, n);
×
1650
  for (i=0; i<n; i++) {
×
1651
    a[i] = internalize_to_arith(ctx, p->prod[i].var);
×
1652
  }
1653

1654
  x = ctx->arith.create_pprod(ctx->arith_solver, p, a);
×
1655
  free_istack_array(&ctx->istack, a);
×
1656

1657
  return x;
×
1658
}
1659

1660

1661
/*
1662
 * Convert polynomial p to an arithmetic variable
1663
 */
1664
static thvar_t map_poly_to_arith(context_t *ctx, polynomial_t *p) {
1,762✔
1665
  uint32_t i, n;
1666
  thvar_t *a;
1667
  thvar_t x;
1668

1669
  n = p->nterms;
1,762✔
1670
  a = alloc_istack_array(&ctx->istack, n);
1,762✔
1671

1672
  // skip the constant if any
1673
  i = 0;
1,762✔
1674
  if (p->mono[0].var == const_idx) {
1,762✔
1675
    a[0] = null_thvar;
467✔
1676
    i ++;
467✔
1677
  }
1678

1679
  // deal with the non-constant monomials
1680
  while (i<n) {
5,035✔
1681
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
3,273✔
1682
    i ++;
3,273✔
1683
  }
1684

1685
  // build the polynomial
1686
  x = ctx->arith.create_poly(ctx->arith_solver, p, a);
1,762✔
1687
  free_istack_array(&ctx->istack, a);
1,762✔
1688

1689
  return x;
1,762✔
1690
}
1691

1692

1693
/*
1694
 * Auxiliary function: return y := (floor x)
1695
 * - check the divmod table first.
1696
 *   If there's a record for (floor x), return the corresponding variable.
1697
 * - Otherwise, create a fresh integer variable y,
1698
 *   assert the axioms for y = (floor x)
1699
 *   add a record to the divmod table and return y.
1700
 */
1701
static thvar_t get_floor(context_t *ctx, thvar_t x) {
×
1702
  thvar_t y;
1703

1704
  y = context_find_var_for_floor(ctx, x);
×
1705
  if (y == null_thvar) {
×
1706
    y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer variable
×
1707
    assert_floor_axioms(ctx, y, x); // assert y = floor(x)
×
1708
    context_record_floor(ctx, x, y); // save the mapping y --> floor(x)
×
1709
  }
1710

1711
  return y;
×
1712
}
1713

1714

1715
/*
1716
 * Return y := (div x k)
1717
 * - check the divmod table first
1718
 * - if (div x k) has already been processed, return the corresponding variable
1719
 * - otherwise create a new variable y, assert the axioms for y = (div x k)
1720
 *   add a record in the divmod table, and return y.
1721
 */
1722
static thvar_t get_div(context_t *ctx, thvar_t x, const rational_t *k) {
25✔
1723
  thvar_t y;
1724

1725
  y = context_find_var_for_div(ctx, x, k);
25✔
1726
  if (y == null_thvar) {
25✔
1727
    // create y := (div x k)
1728
    y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer
21✔
1729
    assert_div_axioms(ctx, y, x, k);
21✔
1730
    context_record_div(ctx, x, k, y);
21✔
1731
  }
1732

1733
  return y;
25✔
1734
}
1735

1736

1737

1738
/*
1739
 * Convert (floor t) to an arithmetic variable
1740
 */
1741
static thvar_t map_floor_to_arith(context_t *ctx, term_t t) {
×
1742
  thvar_t x, y;
1743

1744
  x = internalize_to_arith(ctx, t);
×
1745
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
1746
    // x is integer so (floor x) = x
1747
    y = x;
×
1748
  } else {
1749
    y = get_floor(ctx, x);
×
1750
  }
1751

1752
  return y;
×
1753
}
1754

1755

1756
/*
1757
 * Convert (ceil t) to an arithmetic variable
1758
 */
1759
static thvar_t map_ceil_to_arith(context_t *ctx, term_t t) {
×
1760
  thvar_t x, y;
1761

1762
  x = internalize_to_arith(ctx, t);
×
1763
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
1764
    // x is integer so (ceil x) = x
1765
    y = x;
×
1766
  } else {
1767
    y = context_find_var_for_ceil(ctx, x);
×
1768
    if (y == null_thvar) {
×
1769
      y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer variable
×
1770
      assert_ceil_axioms(ctx, y, x); // assert y = ceil(x)
×
1771
      context_record_ceil(ctx, x, y); // save the mapping y --> ceil(x)
×
1772
    }
1773
  }
1774

1775
  return y;
×
1776
}
1777

1778

1779
/*
1780
 * Convert (abs t) to an arithmetic variable
1781
 */
1782
static thvar_t map_abs_to_arith(context_t *ctx, term_t t) {
4✔
1783
  thvar_t x, y;
1784
  bool is_int;
1785

1786
  x = internalize_to_arith(ctx, t);
4✔
1787
  is_int = ctx->arith.arith_var_is_int(ctx->arith_solver, x);
4✔
1788
  y = ctx->arith.create_var(ctx->arith_solver, is_int); // y := abs(x) has the same type as x
4✔
1789
  assert_abs_axioms(ctx, y, x);
4✔
1790

1791
  return y;
4✔
1792
}
1793

1794

1795
/*
1796
 * Auxiliary function: check whether t is a non-zero arithmetic constant
1797
 * - if so, store t's value in *val
1798
 */
1799
static bool is_non_zero_rational(term_table_t *tbl, term_t t, rational_t *val) {
17✔
1800
  assert(is_arithmetic_term(tbl, t));
1801

1802
  if (term_kind(tbl, t) == ARITH_CONSTANT) {
17✔
1803
    q_set(val, rational_term_desc(tbl, t));
17✔
1804
    return q_is_nonzero(val);
17✔
1805
  }
1806
  return false;
×
1807
}
1808

1809

1810
/*
1811
 * Error in division: either the divisor is zero or is non-constant
1812
 */
1813
static void __attribute__((noreturn))  bad_divisor(context_t *ctx, term_t t) {
3✔
1814
  term_table_t *tbl;
1815
  int code;
1816

1817
  tbl = ctx->terms;
3✔
1818
  assert(is_arithmetic_term(tbl, t) && is_pos_term(t));
1819

1820
  code = FORMULA_NOT_LINEAR;
3✔
1821
  if (term_kind(tbl, t) == ARITH_CONSTANT && q_is_zero(rational_term_desc(tbl, t))) {
3✔
1822
    code = DIV_BY_ZERO;
3✔
1823
  }
1824
  longjmp(ctx->env, code);
3✔
1825
}
1826

1827
/*
1828
 * Convert (/ t1 t2) to an arithmetic variable
1829
 * - t2 must be a non-zero arithmetic constant
1830
 */
1831
static thvar_t map_rdiv_to_arith(context_t *ctx, composite_term_t *div) {
3✔
1832
  // Could try to evaluate t2 then check whether that's a constant
1833
  assert(div->arity == 2);
1834
  bad_divisor(ctx, div->arg[1]);
3✔
1835
}
1836

1837

1838
/*
1839
 * Convert (div t1 t2) to an arithmetic variable.
1840
 * - fails if t2 is not an arithmetic constant or if it's zero
1841
 */
1842
static thvar_t map_idiv_to_arith(context_t *ctx, composite_term_t *div) {
6✔
1843
  rational_t k;
1844
  thvar_t x, y;
1845

1846
  assert(div->arity == 2);
1847

1848
  q_init(&k);
6✔
1849
  if (is_non_zero_rational(ctx->terms, div->arg[1], &k)) { // k := value of t2
6✔
1850
    assert(q_is_nonzero(&k));
1851
    x = internalize_to_arith(ctx, div->arg[0]); // t1
6✔
1852
    y = get_div(ctx, x, &k);
6✔
1853

1854
  } else {
1855
    // division by a non-constant or by zero: not supported by default
1856
    // arithmetic solver for now
1857
    q_clear(&k);
×
1858
    bad_divisor(ctx, div->arg[1]);
×
1859
  }
1860
  q_clear(&k);
6✔
1861

1862
  return y;
6✔
1863
}
1864

1865

1866
/*
1867
 * Convert (mod t1 t2) to an arithmetic variable
1868
 * - t2 must be a non-zero constant
1869
 */
1870
static thvar_t map_mod_to_arith(context_t *ctx, composite_term_t *mod) {
11✔
1871
  rational_t k;
1872
  thvar_t x, y, r;
1873
  bool is_int;
1874

1875
  assert(mod->arity == 2);
1876

1877
  q_init(&k);
11✔
1878
  if (is_non_zero_rational(ctx->terms, mod->arg[1], &k)) { // k := divider
11✔
1879
    x = internalize_to_arith(ctx, mod->arg[0]);
11✔
1880

1881
    // get y := (div x k)
1882
    assert(q_is_nonzero(&k));
1883
    y = get_div(ctx, x, &k);
11✔
1884

1885
    /*
1886
     * r := (mod x k) is x - k * y where y is an integer.
1887
     * If both x and k are integer, then r has integer type. Otherwise,
1888
     * r is a real variable.
1889
     */
1890
    is_int = ctx->arith.arith_var_is_int(ctx->arith_solver, x) && q_is_integer(&k);
11✔
1891
    r = ctx->arith.create_var(ctx->arith_solver, is_int);
11✔
1892
    assert_mod_axioms(ctx, r, x, y, &k);
11✔
1893

1894
  } else {
1895
    // Non-constant or zero divider
1896
    q_clear(&k);
×
1897
    bad_divisor(ctx, mod->arg[1]);
×
1898
  }
1899

1900
  q_clear(&k);
11✔
1901

1902
  return r;
11✔
1903
}
1904

1905

1906

1907
/******************************************************
1908
 *  CONVERSION OF COMPOSITES TO BIT-VECTOR VARIABLES  *
1909
 *****************************************************/
1910

1911
/*
1912
 * Convert if-then-else to a bitvector variable
1913
 */
1914
static thvar_t map_ite_to_bv(context_t *ctx, composite_term_t *ite) {
20,779✔
1915
  literal_t c;
1916
  thvar_t x, y;
1917

1918
  assert(ite->arity == 3);
1919

1920
  c = internalize_to_literal(ctx, ite->arg[0]);
20,779✔
1921
  if (c == true_literal) {
20,779✔
1922
    return internalize_to_bv(ctx, ite->arg[1]);
23✔
1923
  }
1924
  if (c == false_literal) {
20,756✔
1925
    return internalize_to_bv(ctx, ite->arg[2]);
2,082✔
1926
  }
1927

1928
  // no simplification
1929
  x = internalize_to_bv(ctx, ite->arg[1]);
18,674✔
1930
  y = internalize_to_bv(ctx, ite->arg[2]);
18,674✔
1931

1932
  return ctx->bv.create_bvite(ctx->bv_solver, c, x, y);
18,674✔
1933
}
1934

1935

1936
/*
1937
 * Array of bits b
1938
 * - hackish: we locally disable flattening here
1939
 */
1940
static thvar_t map_bvarray_to_bv(context_t *ctx, composite_term_t *b) {
17,037✔
1941
  uint32_t i, n;
1942
  uint32_t save_options;
1943
  literal_t *a;
1944
  thvar_t x;
1945

1946
  n = b->arity;
17,037✔
1947
  a = alloc_istack_array(&ctx->istack, n);
17,037✔
1948

1949
  save_options = ctx->options;
17,037✔
1950
  disable_diseq_and_or_flattening(ctx);
17,037✔
1951
  for (i=0; i<n; i++) {
498,135✔
1952
    a[i] = internalize_to_literal(ctx, b->arg[i]);
481,098✔
1953
  }
1954
  ctx->options = save_options;
17,037✔
1955

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

1958
  free_istack_array(&ctx->istack, a);
17,037✔
1959

1960
  return x;
17,037✔
1961
}
1962

1963

1964
/*
1965
 * Unsigned division: quotient (div u v)
1966
 */
1967
static thvar_t map_bvdiv_to_bv(context_t *ctx, composite_term_t *div) {
97✔
1968
  thvar_t x, y;
1969

1970
  assert(div->arity == 2);
1971
  x = internalize_to_bv(ctx, div->arg[0]);
97✔
1972
  y = internalize_to_bv(ctx, div->arg[1]);
97✔
1973

1974
  return ctx->bv.create_bvdiv(ctx->bv_solver, x, y);
97✔
1975
}
1976

1977

1978
/*
1979
 * Unsigned division: remainder (rem u v)
1980
 */
1981
static thvar_t map_bvrem_to_bv(context_t *ctx, composite_term_t *rem) {
177✔
1982
  thvar_t x, y;
1983

1984
  assert(rem->arity == 2);
1985
  x = internalize_to_bv(ctx, rem->arg[0]);
177✔
1986
  y = internalize_to_bv(ctx, rem->arg[1]);
177✔
1987

1988
  return ctx->bv.create_bvrem(ctx->bv_solver, x, y);
177✔
1989
}
1990

1991

1992
/*
1993
 * Signed division/rounding toward 0: quotient (sdiv u v)
1994
 */
1995
static thvar_t map_bvsdiv_to_bv(context_t *ctx, composite_term_t *sdiv) {
87✔
1996
  thvar_t x, y;
1997

1998
  assert(sdiv->arity == 2);
1999
  x = internalize_to_bv(ctx, sdiv->arg[0]);
87✔
2000
  y = internalize_to_bv(ctx, sdiv->arg[1]);
87✔
2001

2002
  return ctx->bv.create_bvsdiv(ctx->bv_solver, x, y);
87✔
2003
}
2004

2005

2006
/*
2007
 * Signed division/rounding toward 0: remainder (srem u v)
2008
 */
2009
static thvar_t map_bvsrem_to_bv(context_t *ctx, composite_term_t *srem) {
77✔
2010
  thvar_t x, y;
2011

2012
  assert(srem->arity == 2);
2013
  x = internalize_to_bv(ctx, srem->arg[0]);
77✔
2014
  y = internalize_to_bv(ctx, srem->arg[1]);
77✔
2015

2016
  return ctx->bv.create_bvsrem(ctx->bv_solver, x, y);
77✔
2017
}
2018

2019

2020
/*
2021
 * Signed division/rounding toward -infinity: remainder (smod u v)
2022
 */
2023
static thvar_t map_bvsmod_to_bv(context_t *ctx, composite_term_t *smod) {
×
2024
  thvar_t x, y;
2025

2026
  assert(smod->arity == 2);
2027
  x = internalize_to_bv(ctx, smod->arg[0]);
×
2028
  y = internalize_to_bv(ctx, smod->arg[1]);
×
2029

2030
  return ctx->bv.create_bvsmod(ctx->bv_solver, x, y);
×
2031
}
2032

2033

2034
/*
2035
 * Left shift: (shl u v)
2036
 */
2037
static thvar_t map_bvshl_to_bv(context_t *ctx, composite_term_t *shl) {
85✔
2038
  thvar_t x, y;
2039

2040
  assert(shl->arity == 2);
2041
  x = internalize_to_bv(ctx, shl->arg[0]);
85✔
2042
  y = internalize_to_bv(ctx, shl->arg[1]);
85✔
2043

2044
  return ctx->bv.create_bvshl(ctx->bv_solver, x, y);
85✔
2045
}
2046

2047

2048
/*
2049
 * Logical shift right: (lshr u v)
2050
 */
2051
static thvar_t map_bvlshr_to_bv(context_t *ctx, composite_term_t *lshr) {
1,428✔
2052
  thvar_t x, y;
2053

2054
  assert(lshr->arity == 2);
2055
  x = internalize_to_bv(ctx, lshr->arg[0]);
1,428✔
2056
  y = internalize_to_bv(ctx, lshr->arg[1]);
1,428✔
2057

2058
  return ctx->bv.create_bvlshr(ctx->bv_solver, x, y);
1,428✔
2059
}
2060

2061

2062
/*
2063
 * Arithmetic shift right: (ashr u v)
2064
 */
2065
static thvar_t map_bvashr_to_bv(context_t *ctx, composite_term_t *ashr) {
296✔
2066
  thvar_t x, y;
2067

2068
  assert(ashr->arity == 2);
2069
  x = internalize_to_bv(ctx, ashr->arg[0]);
296✔
2070
  y = internalize_to_bv(ctx, ashr->arg[1]);
296✔
2071

2072
  return ctx->bv.create_bvashr(ctx->bv_solver, x, y);
296✔
2073
}
2074

2075

2076

2077
/*
2078
 * TODO: check for simplifications in bitvector arithmetic
2079
 * before translation to bitvector variables.
2080
 *
2081
 * This matters for the wienand-cav2008 benchmarks.
2082
 */
2083

2084
/*
2085
 * Power product
2086
 */
2087
static thvar_t map_pprod_to_bv(context_t *ctx, pprod_t *p) {
585✔
2088
  uint32_t i, n;
2089
  thvar_t *a;
2090
  thvar_t x;
2091

2092
  n = p->len;
585✔
2093
  a = alloc_istack_array(&ctx->istack, n);
585✔
2094
  for (i=0; i<n; i++) {
1,730✔
2095
    a[i] = internalize_to_bv(ctx, p->prod[i].var);
1,145✔
2096
  }
2097

2098
  x = ctx->bv.create_pprod(ctx->bv_solver, p, a);
585✔
2099
  free_istack_array(&ctx->istack, a);
585✔
2100

2101
  return x;
585✔
2102
}
2103

2104

2105
/*
2106
 * Bitvector polynomial, 64bit coefficients
2107
 */
2108
static thvar_t map_bvpoly64_to_bv(context_t *ctx, bvpoly64_t *p) {
12,225✔
2109
  uint32_t i, n;
2110
  thvar_t *a;
2111
  thvar_t x;
2112

2113
  assert(p->nterms > 0);
2114

2115
  n = p->nterms;
12,225✔
2116
  a = alloc_istack_array(&ctx->istack, n);
12,225✔
2117

2118
  // skip the constant if any
2119
  i = 0;
12,225✔
2120
  if (p->mono[0].var == const_idx) {
12,225✔
2121
    a[0] = null_thvar;
3,212✔
2122
    i ++;
3,212✔
2123
  }
2124

2125
  // non-constant monomials
2126
  while (i < n) {
28,477✔
2127
    a[i] = internalize_to_bv(ctx, p->mono[i].var);
16,252✔
2128
    i ++;
16,252✔
2129
  }
2130

2131
  x = ctx->bv.create_poly64(ctx->bv_solver, p, a);
12,225✔
2132
  free_istack_array(&ctx->istack, a);
12,225✔
2133

2134
  return x;
12,225✔
2135
}
2136

2137

2138
/*
2139
 * Bitvector polynomial, coefficients have more than 64bits
2140
 */
2141
static thvar_t map_bvpoly_to_bv(context_t *ctx, bvpoly_t *p) {
607✔
2142
  uint32_t i, n;
2143
  thvar_t *a;
2144
  thvar_t x;
2145

2146
  assert(p->nterms > 0);
2147

2148
  n = p->nterms;
607✔
2149
  a = alloc_istack_array(&ctx->istack, n);
607✔
2150

2151
  // skip the constant if any
2152
  i = 0;
607✔
2153
  if (p->mono[0].var == const_idx) {
607✔
2154
    a[0] = null_thvar;
539✔
2155
    i ++;
539✔
2156
  }
2157

2158
  // non-constant monomials
2159
  while (i < n) {
1,268✔
2160
    a[i] = internalize_to_bv(ctx, p->mono[i].var);
661✔
2161
    i ++;
661✔
2162
  }
2163

2164
  x = ctx->bv.create_poly(ctx->bv_solver, p, a);
607✔
2165
  free_istack_array(&ctx->istack, a);
607✔
2166

2167
  return x;
607✔
2168
}
2169

2170

2171
#if 0
2172
/*
2173
 * Bvpoly buffer: b must be normalized.
2174
 * - not optimal but this shouldn't be called often.
2175
 */
2176
static thvar_t map_bvpoly_buffer_to_bv(context_t *ctx, bvpoly_buffer_t *b) {
2177
  bvpoly64_t *p;
2178
  bvpoly_t *q;
2179
  uint32_t n;
2180
  thvar_t x;
2181

2182
  n = bvpoly_buffer_bitsize(b);
2183

2184
  if (bvpoly_buffer_is_zero(b)) {
2185
    x = ctx->bv.create_zero(ctx->bv_solver, n);
2186
  } else if (n <= 64) {
2187
    p = bvpoly_buffer_getpoly64(b);
2188
    x = map_bvpoly64_to_bv(ctx, p);
2189
    free_bvpoly64(p);
2190
  } else {
2191
    q = bvpoly_buffer_getpoly(b);
2192
    x = map_bvpoly_to_bv(ctx, q);
2193
    free_bvpoly(q);
2194
  }
2195

2196
  if (ctx->mcsat_supplement) {
2197
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
2198
    if (sat != NULL) {
2199
      mcsat_satellite_register_arith_term(sat, x, r);
2200
    }
2201
  }
2202

2203
  return x;
2204
}
2205

2206
#endif
2207

2208
/****************************
2209
 *  CONVERSION TO LITERALS  *
2210
 ***************************/
2211

2212
/*
2213
 * Boolean if-then-else
2214
 */
2215
static literal_t map_ite_to_literal(context_t *ctx, composite_term_t *ite) {
1,863✔
2216
  literal_t l1, l2, l3;
2217

2218
  assert(ite->arity == 3);
2219
  l1 = internalize_to_literal(ctx, ite->arg[0]); // condition
1,863✔
2220
  if (l1 == true_literal) {
1,863✔
2221
    return internalize_to_literal(ctx, ite->arg[1]);
32✔
2222
  }
2223
  if (l1 == false_literal) {
1,831✔
2224
    return internalize_to_literal(ctx, ite->arg[2]);
71✔
2225
  }
2226

2227
  l2 = internalize_to_literal(ctx, ite->arg[1]);
1,760✔
2228
  l3 = internalize_to_literal(ctx, ite->arg[2]);
1,760✔
2229

2230
  return mk_ite_gate(&ctx->gate_manager, l1, l2, l3);
1,760✔
2231
}
2232

2233

2234
/*
2235
 * Generic equality: (eq t1 t2)
2236
 * - t1 and t2 are not arithmetic or bitvector terms
2237
 */
2238
static literal_t map_eq_to_literal(context_t *ctx, composite_term_t *eq) {
14,519✔
2239
  occ_t u, v;
2240
  literal_t l1, l2, l;
2241

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

2244
  if (is_boolean_term(ctx->terms, eq->arg[0])) {
14,519✔
2245
    assert(is_boolean_term(ctx->terms, eq->arg[1]));
2246

2247
    l1 = internalize_to_literal(ctx, eq->arg[0]);
9,058✔
2248
    l2 = internalize_to_literal(ctx, eq->arg[1]);
9,058✔
2249
    l = mk_iff_gate(&ctx->gate_manager, l1, l2);
9,058✔
2250
  } else {
2251
    // filter out high-order terms. It's enough to check eq->arg[0]
2252
    check_high_order_support(ctx, eq->arg, 1);
5,461✔
2253

2254
    u = internalize_to_eterm(ctx, eq->arg[0]);
5,461✔
2255
    v = internalize_to_eterm(ctx, eq->arg[1]);
5,461✔
2256
    l = egraph_make_eq(ctx->egraph, u, v);
5,461✔
2257
  }
2258

2259
  return l;
14,519✔
2260
}
2261

2262

2263
/*
2264
 * (or t1 ... t_n)
2265
 */
2266
static literal_t map_or_to_literal(context_t *ctx, composite_term_t *or) {
81,300✔
2267
  int32_t *a;
2268
  ivector_t *v;
2269
  literal_t l;
2270
  uint32_t i, n;
2271

2272
  if (context_flatten_or_enabled(ctx)) {
81,300✔
2273
    // flatten (or ...): store result in v
2274
    v = &ctx->aux_vector;
13,220✔
2275
    assert(v->size == 0);
2276
    flatten_or_term(ctx, v, or);
13,220✔
2277

2278
    // try easy simplification
2279
    n = v->size;
13,220✔
2280
    if (disjunct_is_true(ctx, v->data, n)) {
13,220✔
2281
      ivector_reset(v);
335✔
2282
      return true_literal;
335✔
2283
    }
2284

2285
    // make a copy of v
2286
    a = alloc_istack_array(&ctx->istack, n);
12,885✔
2287
    for (i=0; i<n; i++) {
70,797✔
2288
      a[i] = v->data[i];
57,912✔
2289
    }
2290
    ivector_reset(v);
12,885✔
2291

2292
    // internalize a[0 ... n-1]
2293
    for (i=0; i<n; i++) {
69,824✔
2294
      l = internalize_to_literal(ctx, a[i]);
57,221✔
2295
      if (l == true_literal) goto done;
57,221✔
2296
      a[i] = l;
56,939✔
2297
    }
2298

2299
  } else {
2300
    // no flattening
2301
    n = or->arity;
68,080✔
2302
    if (disjunct_is_true(ctx, or->arg, n)) {
68,080✔
2303
      return true_literal;
204✔
2304
    }
2305

2306
    a = alloc_istack_array(&ctx->istack, n);
67,876✔
2307
    for (i=0; i<n; i++) {
254,012✔
2308
      l = internalize_to_literal(ctx, or->arg[i]);
186,452✔
2309
      if (l == true_literal) goto done;
186,452✔
2310
      a[i] = l;
186,136✔
2311
    }
2312
  }
2313

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

2316
 done:
80,761✔
2317
  free_istack_array(&ctx->istack, a);
80,761✔
2318

2319
  return l;
80,761✔
2320
}
2321

2322

2323
/*
2324
 * (xor t1 ... t_n)
2325
 */
2326
static literal_t map_xor_to_literal(context_t *ctx, composite_term_t *xor) {
1✔
2327
  int32_t *a;
2328
  literal_t l;
2329
  uint32_t i, n;
2330

2331
  n = xor->arity;
1✔
2332
  a = alloc_istack_array(&ctx->istack, n);
1✔
2333
  for (i=0; i<n; i++) {
4✔
2334
    a[i] = internalize_to_literal(ctx, xor->arg[i]);
3✔
2335
  }
2336

2337
  l = mk_xor_gate(&ctx->gate_manager, n, a);
1✔
2338
  free_istack_array(&ctx->istack, a);
1✔
2339

2340
  return l;
1✔
2341
}
2342

2343

2344
/*
2345
 * Convert (p t_1 .. t_n) to a literal
2346
 * - create an egraph atom
2347
 */
2348
static literal_t map_apply_to_literal(context_t *ctx, composite_term_t *app) {
4,368✔
2349
  occ_t *a;
2350
  uint32_t i, n;
2351
  literal_t l;
2352

2353
  assert(app->arity > 0);
2354
  n = app->arity;
4,368✔
2355
  a = alloc_istack_array(&ctx->istack, n);
4,368✔
2356
  for (i=0; i<n; i++) {
16,325✔
2357
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
11,957✔
2358
  }
2359

2360
  // a[0] = predicate
2361
  // a[1 ...n-1] = arguments
2362
  l = egraph_make_pred(ctx->egraph, a[0], n-1, a + 1);
4,368✔
2363
  free_istack_array(&ctx->istack, a);
4,368✔
2364

2365
  return l;
4,368✔
2366
}
2367

2368

2369

2370
/*
2371
 * Auxiliary function: translate (distinct a[0 ... n-1]) to a literal,
2372
 * when a[0] ... a[n-1] are arithmetic variables.
2373
 *
2374
 * We expand this into a quadratic number of disequalities.
2375
 */
2376
static literal_t make_arith_distinct(context_t *ctx, uint32_t n, thvar_t *a) {
158✔
2377
  uint32_t i, j;
2378
  ivector_t *v;
2379
  literal_t l;
2380

2381
  assert(n >= 2);
2382

2383
  v = &ctx->aux_vector;
158✔
2384
  assert(v->size == 0);
2385
  for (i=0; i<n-1; i++) {
3,776✔
2386
    for (j=i+1; j<n; j++) {
48,648✔
2387
      l = ctx->arith.create_vareq_atom(ctx->arith_solver, a[i], a[j]);
45,030✔
2388
      ivector_push(v, l);
45,030✔
2389
    }
2390
  }
2391
  l = mk_or_gate(&ctx->gate_manager, v->size, v->data);
158✔
2392
  ivector_reset(v);
158✔
2393

2394
  return not(l);
158✔
2395
}
2396

2397

2398
/*
2399
 * Auxiliary function: translate (distinct a[0 ... n-1]) to a literal,
2400
 * when a[0] ... a[n-1] are bitvector variables.
2401
 *
2402
 * We expand this into a quadratic number of disequalities.
2403
 */
2404
static literal_t make_bv_distinct(context_t *ctx, uint32_t n, thvar_t *a) {
2✔
2405
  uint32_t i, j;
2406
  ivector_t *v;
2407
  literal_t l;
2408

2409
  assert(n >= 2);
2410

2411
  v = &ctx->aux_vector;
2✔
2412
  assert(v->size == 0);
2413
  for (i=0; i<n-1; i++) {
11✔
2414
    for (j=i+1; j<n; j++) {
40✔
2415
      l = ctx->bv.create_eq_atom(ctx->bv_solver, a[i], a[j]);
31✔
2416
      ivector_push(v, l);
31✔
2417
    }
2418
  }
2419
  l = mk_or_gate(&ctx->gate_manager, v->size, v->data);
2✔
2420
  ivector_reset(v);
2✔
2421

2422
  return not(l);
2✔
2423
}
2424

2425

2426
/*
2427
 * Convert (distinct t_1 ... t_n) to a literal
2428
 */
2429
static literal_t map_distinct_to_literal(context_t *ctx, composite_term_t *distinct) {
9✔
2430
  int32_t *a;
2431
  literal_t l;
2432
  uint32_t i, n;
2433

2434
  n = distinct->arity;
9✔
2435
  a = alloc_istack_array(&ctx->istack, n);
9✔
2436
  if (context_has_egraph(ctx)) {
9✔
2437
    // fail if arguments are functions and we don't support high-order terms
2438
    // checking the first argument is enough since they all have the same type
2439
    check_high_order_support(ctx, distinct->arg, 1);
6✔
2440

2441
    // default: translate to the egraph
2442
    for (i=0; i<n; i++) {
25✔
2443
      a[i] = internalize_to_eterm(ctx, distinct->arg[i]);
19✔
2444
    }
2445
    l = egraph_make_distinct(ctx->egraph, n, a);
6✔
2446

2447
  } else if (is_arithmetic_term(ctx->terms, distinct->arg[0])) {
3✔
2448
    // translate to arithmetic variables
2449
    for (i=0; i<n; i++) {
12✔
2450
      a[i] = internalize_to_arith(ctx, distinct->arg[i]);
9✔
2451
    }
2452
    l = make_arith_distinct(ctx, n, a);
3✔
2453

2454
  } else if (is_bitvector_term(ctx->terms, distinct->arg[0])) {
×
2455
    // translate to bitvector variables
2456
    for (i=0; i<n; i++) {
×
2457
      a[i] = internalize_to_bv(ctx, distinct->arg[i]);
×
2458
    }
2459
    l = make_bv_distinct(ctx, n, a);
×
2460

2461
  } else {
2462
    longjmp(ctx->env, uf_error_code(ctx, distinct->arg[0]));
×
2463
  }
2464

2465
  free_istack_array(&ctx->istack, a);
9✔
2466

2467
  return l;
9✔
2468
}
2469

2470

2471

2472
/*
2473
 * Arithmetic atom: p == 0
2474
 */
2475
static literal_t map_poly_eq_to_literal(context_t *ctx, polynomial_t *p) {
1,192✔
2476
  uint32_t i, n;
2477
  thvar_t *a;
2478
  literal_t l;
2479

2480
  n = p->nterms;
1,192✔
2481
  a = alloc_istack_array(&ctx->istack, n);
1,192✔
2482

2483
  // skip the constant if any
2484
  i = 0;
1,192✔
2485
  if (p->mono[0].var == const_idx) {
1,192✔
2486
    a[0] = null_thvar;
570✔
2487
    i ++;
570✔
2488
  }
2489

2490
  // deal with the non-constant monomials
2491
  while (i<n) {
4,166✔
2492
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
2,974✔
2493
    i ++;
2,974✔
2494
  }
2495

2496
  // build the atom
2497
  l = ctx->arith.create_poly_eq_atom(ctx->arith_solver, p, a);
1,192✔
2498
  free_istack_array(&ctx->istack, a);
1,192✔
2499

2500
  return l;
1,192✔
2501
}
2502

2503

2504
/*
2505
 * Arithmetic atom: (p >= 0)
2506
 */
2507
static literal_t map_poly_ge_to_literal(context_t *ctx, polynomial_t *p) {
33,493✔
2508
  uint32_t i, n;
2509
  thvar_t *a;
2510
  literal_t l;
2511

2512
  n = p->nterms;
33,493✔
2513
  a = alloc_istack_array(&ctx->istack, n);
33,493✔
2514

2515
  // skip the constant if any
2516
  i = 0;
33,493✔
2517
  if (p->mono[0].var == const_idx) {
33,493✔
2518
    a[0] = null_thvar;
26,318✔
2519
    i ++;
26,318✔
2520
  }
2521

2522
  // deal with the non-constant monomials
2523
  while (i<n) {
84,648✔
2524
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
51,155✔
2525
    i ++;
51,155✔
2526
  }
2527

2528
  // build the atom
2529
  l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, a);
33,493✔
2530
  free_istack_array(&ctx->istack, a);
33,493✔
2531

2532
  return l;
33,493✔
2533
}
2534

2535

2536
/*
2537
 * Arithmetic atom: (t >= 0)
2538
 */
2539
static literal_t map_arith_geq_to_literal(context_t *ctx, term_t t) {
33,841✔
2540
  term_table_t *terms;
2541
  thvar_t x;
2542
  literal_t l;
2543

2544
  terms = ctx->terms;
33,841✔
2545
  if (term_kind(terms, t) == ARITH_POLY) {
33,841✔
2546
    l = map_poly_ge_to_literal(ctx, poly_term_desc(terms, t));
33,493✔
2547
  } else {
2548
    x = internalize_to_arith(ctx, t);
348✔
2549
    l = ctx->arith.create_ge_atom(ctx->arith_solver, x);
348✔
2550
  }
2551

2552
  return l;
33,841✔
2553
}
2554

2555

2556

2557
/*
2558
 * Arithmetic equalities (eq t1 t2)
2559
 * 1) try to flatten the if-then-elses
2560
 * 2) also apply cheap lift-if rule: (eq (ite c t1 t2) u1) --> (ite c (eq t1 u1) (eq t2 u1))
2561
 */
2562
static literal_t map_arith_bineq(context_t *ctx, term_t t1, term_t u1);
2563

2564
/*
2565
 * Lift equality: (eq (ite c u1 u2) t) --> (ite c (eq u1 t) (eq u2 t))
2566
 */
2567
static literal_t map_ite_arith_bineq(context_t *ctx, composite_term_t *ite, term_t t) {
42,609✔
2568
  literal_t l1, l2, l3;
2569

2570
  assert(ite->arity == 3);
2571
  l1 = internalize_to_literal(ctx, ite->arg[0]);
42,609✔
2572
  if (l1 == true_literal) {
42,609✔
2573
    // (eq (ite true u1 u2) t) --> (eq u1 t)
2574
    return map_arith_bineq(ctx, ite->arg[1], t);
7✔
2575
  }
2576
  if (l1 == false_literal) {
42,602✔
2577
    // (eq (ite true u1 u2) t) --> (eq u2 t)
2578
    return map_arith_bineq(ctx, ite->arg[2], t);
109✔
2579
  }
2580

2581
  // apply lift-if here
2582
  l2 = map_arith_bineq(ctx, ite->arg[1], t);
42,493✔
2583
  l3 = map_arith_bineq(ctx, ite->arg[2], t);
42,493✔
2584

2585
  return mk_ite_gate(&ctx->gate_manager, l1, l2, l3);
42,493✔
2586
}
2587

2588
static literal_t map_arith_bineq_aux(context_t *ctx, term_t t1, term_t t2) {
53,504✔
2589
  term_table_t *terms;
2590
  thvar_t x, y;
2591
  occ_t u, v;
2592
  literal_t l;
2593

2594
  /*
2595
   * Try to apply lift-if rule: (eq (ite c u1 u2) t2) --> (ite c (eq u1 t2) (eq u2 t2))
2596
   * do this only if t2 is not an if-then-else term.
2597
   *
2598
   * Otherwise add the atom (eq t1 t2) to the egraph if possible
2599
   * or create (eq t1 t2) in the arithmetic solver.
2600
   */
2601
  terms = ctx->terms;
53,504✔
2602
  if (is_ite_term(terms, t1) && ! is_ite_term(terms, t2)) {
53,504✔
2603
    l = map_ite_arith_bineq(ctx, ite_term_desc(terms, t1), t2);
38,573✔
2604
  } else if (is_ite_term(terms, t2) && !is_ite_term(terms, t1)) {
14,931✔
2605
    l = map_ite_arith_bineq(ctx, ite_term_desc(terms, t2), t1);
4,036✔
2606
  } else if (context_has_egraph(ctx)) {
10,895✔
2607
    u = internalize_to_eterm(ctx, t1);
3,774✔
2608
    v = internalize_to_eterm(ctx, t2);
3,774✔
2609
    l = egraph_make_eq(ctx->egraph, u, v);
3,774✔
2610
  } else {
2611
    x = internalize_to_arith(ctx, t1);
7,121✔
2612
    y = internalize_to_arith(ctx, t2);
7,121✔
2613
    l = ctx->arith.create_vareq_atom(ctx->arith_solver, x, y);
7,121✔
2614
  }
2615

2616
  return l;
53,504✔
2617
}
2618

2619
static literal_t map_arith_bineq(context_t *ctx, term_t t1, term_t u1) {
95,361✔
2620
  ivector_t *v;
2621
  int32_t *a;
2622
  uint32_t i, n;
2623
  term_t t2, u2;
2624
  literal_t l;
2625

2626
  t1 = intern_tbl_get_root(&ctx->intern, t1);
95,361✔
2627
  u1 = intern_tbl_get_root(&ctx->intern, u1);
95,361✔
2628

2629
  if (t1 == u1) {
95,361✔
2630
    return true_literal;
3,222✔
2631
  }
2632

2633
  /*
2634
   * Check the cache
2635
   */
2636
  l = find_in_eq_cache(ctx, t1, u1);
92,139✔
2637
  if (l == null_literal) {
92,139✔
2638
    /*
2639
     * The pair (t1, u1) is not mapped already.
2640
     * Try to flatten the if-then-else equalities
2641
     */
2642
    v = &ctx->aux_vector;
53,431✔
2643
    assert(v->size == 0);
2644
    t2 = flatten_ite_equality(ctx, v, t1, u1);
53,431✔
2645
    u2 = flatten_ite_equality(ctx, v, u1, t2);
53,431✔
2646

2647
    /*
2648
     * (t1 == u1) is equivalent to (and (t2 == u2) v[0] ... v[n-1])
2649
     * where v[i] = element i of v
2650
     */
2651
    n = v->size;
53,431✔
2652
    if (n == 0) {
53,431✔
2653
      // empty v: return (t2 == u2)
2654
      assert(t1 == t2 && u1 == u2);
2655
      l = map_arith_bineq_aux(ctx, t2, u2);
10,680✔
2656

2657
    } else {
2658
      // build (and (t2 == u2) v[0] ... v[n-1])
2659
      // first make a copy of v into a[0 .. n-1]
2660
      a = alloc_istack_array(&ctx->istack, n+1);
42,751✔
2661
      for (i=0; i<n; i++) {
766,594✔
2662
        a[i] = v->data[i];
723,843✔
2663
      }
2664
      ivector_reset(v);
42,751✔
2665

2666
      // build the internalization of a[0 .. n-1]
2667
      for (i=0; i<n; i++) {
766,594✔
2668
        a[i] = internalize_to_literal(ctx, a[i]);
723,843✔
2669
      }
2670
      a[n] = map_arith_bineq_aux(ctx, t2, u2);
42,751✔
2671

2672
      // build (and a[0] ... a[n])
2673
      l = mk_and_gate(&ctx->gate_manager, n+1, a);
42,751✔
2674
      free_istack_array(&ctx->istack, a);
42,751✔
2675
    }
2676

2677
    /*
2678
     * Store the mapping (t1, u1) --> l in the cache
2679
     */
2680
    add_to_eq_cache(ctx, t1, u1, l);
53,431✔
2681
  }
2682

2683
  return l;
92,139✔
2684
}
2685

2686

2687
static inline literal_t map_arith_bineq_to_literal(context_t *ctx, composite_term_t *eq) {
8,967✔
2688
  assert(eq->arity == 2);
2689
  return map_arith_bineq(ctx, eq->arg[0], eq->arg[1]);
8,967✔
2690
}
2691

2692

2693

2694
/*
2695
 * Arithmetic atom: (t == 0)
2696
 */
2697
static literal_t map_arith_eq_to_literal(context_t *ctx, term_t t) {
2,249✔
2698
  term_table_t *terms;
2699
  thvar_t x;
2700
  literal_t l;
2701

2702
  terms = ctx->terms;
2,249✔
2703
  if (term_kind(terms, t) == ARITH_POLY) {
2,249✔
2704
    l = map_poly_eq_to_literal(ctx, poly_term_desc(terms, t));
1,192✔
2705
  } else if (is_ite_term(terms, t)) {
1,057✔
2706
    l = map_arith_bineq(ctx, t, zero_term);
426✔
2707
  } else {
2708
    x = internalize_to_arith(ctx, t);
631✔
2709
    l = ctx->arith.create_eq_atom(ctx->arith_solver, x);
631✔
2710
  }
2711
  return l;
2,249✔
2712
}
2713

2714

2715
/*
2716
 * DIVIDES AND IS_INT ATOMS
2717
 */
2718

2719
/*
2720
 * We use the rules
2721
 * - (is_int x)    <=> (x <= floor(x))
2722
 * - (divides k x) <=> (x <= k * div(x, k))
2723
 */
2724

2725
// atom (is_int t)
2726
static literal_t map_arith_is_int_to_literal(context_t *ctx, term_t t) {
×
2727
  polynomial_t *p;
2728
  thvar_t map[2];
2729
  thvar_t x, y;
2730
  literal_t l;
2731

2732
  x = internalize_to_arith(ctx, t);
×
2733
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
2734
    l = true_literal;
×
2735
  } else {
2736
    // we convert (is_int x) to (x <= floor(x))
2737
    y = get_floor(ctx, x); // y is floor x
×
2738
    p = context_get_aux_poly(ctx, 3);
×
2739
    context_store_diff_poly(p, map, y, x); // (p, map) := (y - x)
×
2740
    // atom (x <= y) is the same as (p >= 0)
2741
    l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, map);
×
2742
  }
2743

2744
  return l;
×
2745
}
2746

2747
// atom (divides k t)  we assume k != 0
2748
static literal_t map_arith_divides_to_literal(context_t *ctx, composite_term_t *divides) {
8✔
2749
  rational_t k;
2750
  polynomial_t *p;
2751
  thvar_t map[2];
2752
  thvar_t x, y;
2753
  term_t d;
2754
  literal_t l;
2755

2756
  assert(divides->arity == 2);
2757

2758
  d = divides->arg[0];
8✔
2759
  if (term_kind(ctx->terms, d) == ARITH_CONSTANT) {
8✔
2760
    // make a copy of divides->arg[0] in k
2761
    q_init(&k);
8✔
2762
    q_set(&k, rational_term_desc(ctx->terms, d));
8✔
2763
    assert(q_is_nonzero(&k));
2764

2765
    x = internalize_to_arith(ctx, divides->arg[1]); // this is t
8✔
2766
    y = get_div(ctx, x, &k);  // y := (div x k)
8✔
2767
    p = context_get_aux_poly(ctx, 3);
8✔
2768
    context_store_divides_constraint(p, map, x, y, &k); // p is (- x + k * y)
8✔
2769
    // atom (x <= k * y) is (p >= 0)
2770
    l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, map);
8✔
2771

2772
    q_clear(&k);
8✔
2773

2774
    return l;
8✔
2775

2776
  } else {
2777
    // k is not a constant: not supported
2778
    longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
2779
  }
2780
}
2781

2782

2783
/*
2784
 * BITVECTOR ATOMS
2785
 */
2786

2787
/*
2788
 * Auxiliary function: atom for (t == 0)
2789
 */
2790
static literal_t map_bveq0_to_literal(context_t *ctx, term_t t) {
10✔
2791
  uint32_t n;
2792
  thvar_t x, y;
2793

2794
  t = intern_tbl_get_root(&ctx->intern, t);
10✔
2795
  n = term_bitsize(ctx->terms, t);
10✔
2796
  x = internalize_to_bv(ctx, t);
10✔
2797
  y = ctx->bv.create_zero(ctx->bv_solver, n);
10✔
2798

2799
  return ctx->bv.create_eq_atom(ctx->bv_solver, x, y);
10✔
2800
}
2801

2802
static literal_t map_bveq_to_literal(context_t *ctx, composite_term_t *eq) {
4,864✔
2803
  bveq_simp_t simp;
2804
  term_t t, t1, t2;
2805
  thvar_t x, y;
2806

2807
  assert(eq->arity == 2);
2808

2809
  /*
2810
   * Apply substitution then check for simplifications
2811
   */
2812
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
4,864✔
2813
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
4,864✔
2814
  t = simplify_bitvector_eq(ctx, t1, t2);
4,864✔
2815
  if (t != NULL_TERM) {
4,864✔
2816
    // (bveq t1 t2) is equivalent to t
2817
    return internalize_to_literal(ctx, t);
77✔
2818
  }
2819

2820
  /*
2821
   * More simplifications
2822
   */
2823
  try_arithmetic_bveq_simplification(ctx, &simp, t1, t2);
4,787✔
2824
  switch (simp.code) {
4,787✔
2825
  case BVEQ_CODE_TRUE:
×
2826
    return true_literal;
×
2827

2828
  case BVEQ_CODE_FALSE:
×
2829
    return false_literal;
×
2830

2831
  case BVEQ_CODE_REDUCED:
11✔
2832
    t1 = intern_tbl_get_root(&ctx->intern, simp.left);
11✔
2833
    t2 = intern_tbl_get_root(&ctx->intern, simp.right);
11✔
2834
    break;
11✔
2835

2836
  case BVEQ_CODE_REDUCED0:
10✔
2837
    // (t1 == t2) is reduced to (simp.left == 0)
2838
    // we create the atom directly here:
2839
    return map_bveq0_to_literal(ctx, simp.left);
10✔
2840

2841
  default:
4,766✔
2842
    break;
4,766✔
2843
  }
2844

2845
  if (equal_bitvector_factors(ctx, t1, t2)) {
4,777✔
2846
    return true_literal;
×
2847
  }
2848

2849
  /*
2850
   * NOTE: creating (eq t1 t2) in the egraph instead makes things worse
2851
   */
2852
  x = internalize_to_bv(ctx, t1);
4,777✔
2853
  y = internalize_to_bv(ctx, t2);
4,777✔
2854
  return ctx->bv.create_eq_atom(ctx->bv_solver, x, y);
4,777✔
2855
}
2856

2857
static literal_t map_bvge_to_literal(context_t *ctx, composite_term_t *ge) {
2,302✔
2858
  thvar_t x, y;
2859

2860
  assert(ge->arity == 2);
2861
  x = internalize_to_bv(ctx, ge->arg[0]);
2,302✔
2862
  y = internalize_to_bv(ctx, ge->arg[1]);
2,302✔
2863

2864
  return ctx->bv.create_ge_atom(ctx->bv_solver, x, y);
2,302✔
2865
}
2866

2867
static literal_t map_bvsge_to_literal(context_t *ctx, composite_term_t *sge) {
2,907✔
2868
  thvar_t x, y;
2869

2870
  assert(sge->arity == 2);
2871
  x = internalize_to_bv(ctx, sge->arg[0]);
2,907✔
2872
  y = internalize_to_bv(ctx, sge->arg[1]);
2,907✔
2873

2874
  return ctx->bv.create_sge_atom(ctx->bv_solver, x, y);
2,907✔
2875
}
2876

2877

2878
// Select bit
2879
static literal_t map_bit_select_to_literal(context_t *ctx, select_term_t *select) {
264,228✔
2880
  term_t t, s;
2881
  thvar_t x;
2882

2883
  /*
2884
   * Apply substitution then try to simplify
2885
   */
2886
  t = intern_tbl_get_root(&ctx->intern, select->arg);
264,228✔
2887
  s = extract_bit(ctx->terms, t, select->idx);
264,228✔
2888
  if (s != NULL_TERM) {
264,228✔
2889
    // (select t i) is s
2890
    return internalize_to_literal(ctx, s);
25,181✔
2891
  } else {
2892
    // no simplification
2893
    x = internalize_to_bv(ctx, t);
239,047✔
2894
    return ctx->bv.select_bit(ctx->bv_solver, x, select->idx);
239,047✔
2895
  }
2896
}
2897

2898

2899
/****************************************
2900
 *  INTERNALIZATION TO ETERM: TOPLEVEL  *
2901
 ***************************************/
2902

2903
static occ_t internalize_to_eterm(context_t *ctx, term_t t) {
103,355✔
2904
  term_table_t *terms;
2905
  term_t root;
2906
  term_t r;
2907
  uint32_t polarity;
2908
  int32_t code;
2909
  int32_t exception;
2910
  type_t tau;
2911
  occ_t u;
2912
  literal_t l;
2913
  thvar_t x;
2914

2915
  if (! context_has_egraph(ctx)) {
103,355✔
2916
    exception = uf_error_code(ctx, t);
×
2917
    goto abort;
×
2918
  }
2919

2920
  root = intern_tbl_get_root(&ctx->intern, t);
103,355✔
2921
  polarity = polarity_of(root);
103,355✔
2922
  root = unsigned_term(root);
103,355✔
2923
  r = root;
103,355✔
2924

2925
  /*
2926
   * r is a positive root in the internalization table
2927
   * polarity is 0 or 1
2928
   * if polarity is 0, then t is equal to r by substitution
2929
   * if polarity is 1, then t is equal to (not r)
2930
   */
2931
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
103,355✔
2932
    /*
2933
     * r already internalized
2934
     */
2935
    code = intern_tbl_map_of_root(&ctx->intern, r);
64,981✔
2936
    u = translate_code_to_eterm(ctx, r, code);
64,981✔
2937
  } else {
2938
    /*
2939
     * Compute r's internalization:
2940
     * - if it's a boolean term, convert r to a literal l then
2941
     *   remap l to an egraph term
2942
     * - otherwise, recursively construct an egraph term and map it to r
2943
     */
2944
    terms = ctx->terms;
38,374✔
2945
    tau = type_of_root(ctx, r);
38,374✔
2946
    if (is_unit_type(ctx->types, tau)) {
38,374✔
2947
      // Canonicalize singleton types to one representative term.
2948
      r = get_unit_type_rep(terms, tau);
7✔
2949
      r = intern_tbl_get_root(&ctx->intern, r);
7✔
2950
      r = unsigned_term(r);
7✔
2951
      assert(is_pos_term(r) && intern_tbl_is_root(&ctx->intern, r));
2952
      if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
7✔
2953
        code = intern_tbl_map_of_root(&ctx->intern, r);
1✔
2954
        u = translate_code_to_eterm(ctx, r, code);
1✔
2955
        if (root != r) {
1✔
2956
          if (intern_tbl_root_is_free(&ctx->intern, root)) {
1✔
2957
            intern_tbl_map_root(&ctx->intern, root, occ2code(u));
1✔
2958
          } else {
2959
            // If root is already mapped, it must map to the same egraph
2960
            // occurrence we are about to return for the unit-type rep.
2961
            assert(intern_tbl_map_of_root(&ctx->intern, root) == occ2code(u));  // LCOV_EXCL_LINE - consistency check, unreachable on well-formed inputs
2962
          }
2963
        }
2964
        return u ^ polarity;
1✔
2965
      }
2966
    }
2967

2968
    if (is_boolean_type(tau)) {
38,373✔
2969
      l = internalize_to_literal(ctx, r);
38✔
2970
      u = egraph_literal2occ(ctx->egraph, l);
38✔
2971
      intern_tbl_remap_root(&ctx->intern, r, occ2code(u));
38✔
2972
    } else {
2973
      /*
2974
       * r is not a boolean term
2975
       */
2976
      assert(polarity == 0);
2977

2978
      switch (term_kind(terms, r)) {
38,335✔
2979
      case CONSTANT_TERM:
1,164✔
2980
        u = pos_occ(make_egraph_constant(ctx, tau, constant_term_index(terms, r)));
1,164✔
2981
        break;
1,164✔
2982

2983
      case ARITH_CONSTANT:
339✔
2984
        u = map_arith_constant_to_eterm(ctx, rational_term_desc(terms, r));
339✔
2985
        break;
339✔
2986

2987
      case BV64_CONSTANT:
808✔
2988
        u = map_bvconst64_to_eterm(ctx, bvconst64_term_desc(terms, r));
808✔
2989
        break;
808✔
2990

2991
      case BV_CONSTANT:
18✔
2992
        u = map_bvconst_to_eterm(ctx, bvconst_term_desc(terms, r));
18✔
2993
        break;
18✔
2994

2995
      case VARIABLE:
×
2996
        exception = FREE_VARIABLE_IN_FORMULA;
×
2997
        goto abort;
×
2998

2999
      case UNINTERPRETED_TERM:
12,051✔
3000
        u = pos_occ(make_egraph_variable(ctx, tau));
12,051✔
3001
        //        add_type_constraints(ctx, u, tau);
3002
        break;
12,051✔
3003

3004
      case ARITH_FLOOR:
×
3005
        assert(is_integer_type(tau));
3006
        x = map_floor_to_arith(ctx, arith_floor_arg(terms, r));
×
3007
        u = translate_arithvar_to_eterm(ctx, x);
×
3008
        break;
×
3009

3010
      case ARITH_CEIL:
×
3011
        assert(is_integer_type(tau));
3012
        x = map_ceil_to_arith(ctx, arith_ceil_arg(terms, r));
×
3013
        u = translate_arithvar_to_eterm(ctx, x);
×
3014
        break;
×
3015

3016
      case ARITH_ABS:
×
3017
        x = map_abs_to_arith(ctx, arith_abs_arg(terms, r));
×
3018
        u = translate_arithvar_to_eterm(ctx, x);
×
3019
        break;
×
3020

3021
      case ITE_TERM:
2,168✔
3022
      case ITE_SPECIAL:
3023
        u = map_ite_to_eterm(ctx, ite_term_desc(terms, r), tau);
2,168✔
3024
        break;
2,168✔
3025

3026
      case APP_TERM:
6,531✔
3027
        u = map_apply_to_eterm(ctx, app_term_desc(terms, r), tau);
6,531✔
3028
        break;
6,531✔
3029

3030
      case ARITH_RDIV:
×
3031
        assert(is_arithmetic_type(tau));
3032
        x = map_rdiv_to_arith(ctx, arith_rdiv_term_desc(terms, r));
×
3033
        u = translate_arithvar_to_eterm(ctx, x);
×
3034
        break;
×
3035

3036
      case ARITH_IDIV:
×
3037
        assert(is_integer_type(tau));
3038
        x = map_idiv_to_arith(ctx, arith_idiv_term_desc(terms, r));
×
3039
        u = translate_arithvar_to_eterm(ctx, x); // (div t u) has type int
×
3040
        break;
×
3041

3042
      case ARITH_MOD:
2✔
3043
        x = map_mod_to_arith(ctx, arith_mod_term_desc(terms, r));
2✔
3044
        u = translate_arithvar_to_eterm(ctx, x);
2✔
3045
        break;
2✔
3046

3047
      case TUPLE_TERM:
190✔
3048
        u = map_tuple_to_eterm(ctx, tuple_term_desc(terms, r), tau);
190✔
3049
        break;
190✔
3050

3051
      case SELECT_TERM:
245✔
3052
        u = map_select_to_eterm(ctx, select_term_desc(terms, r), tau);
245✔
3053
        break;
245✔
3054

3055
      case UPDATE_TERM:
11,470✔
3056
        u = map_update_to_eterm(ctx, update_term_desc(terms, r), tau);
11,470✔
3057
        break;
11,470✔
3058

3059
      case LAMBDA_TERM:
1✔
3060
        // not ready for lambda terms yet:
3061
        exception = LAMBDAS_NOT_SUPPORTED;
1✔
3062
        goto abort;
1✔
3063

3064
      case BV_ARRAY:
1,711✔
3065
        x = map_bvarray_to_bv(ctx, bvarray_term_desc(terms, r));
1,711✔
3066
        u = translate_thvar_to_eterm(ctx, x, tau);
1,711✔
3067
        break;
1,711✔
3068

3069
      case BV_DIV:
1✔
3070
        x = map_bvdiv_to_bv(ctx, bvdiv_term_desc(terms, r));
1✔
3071
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3072
        break;
1✔
3073

3074
      case BV_REM:
2✔
3075
        x = map_bvrem_to_bv(ctx, bvrem_term_desc(terms, r));
2✔
3076
        u = translate_thvar_to_eterm(ctx, x, tau);
2✔
3077
        break;
2✔
3078

3079
      case BV_SDIV:
1✔
3080
        x = map_bvsdiv_to_bv(ctx, bvsdiv_term_desc(terms, r));
1✔
3081
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3082
        break;
1✔
3083

3084
      case BV_SREM:
1✔
3085
        x = map_bvsrem_to_bv(ctx, bvsrem_term_desc(terms, r));
1✔
3086
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3087
        break;
1✔
3088

3089
      case BV_SMOD:
×
3090
        x = map_bvsmod_to_bv(ctx, bvsmod_term_desc(terms, r));
×
3091
        u = translate_thvar_to_eterm(ctx, x, tau);
×
3092
        break;
×
3093

3094
      case BV_SHL:
×
3095
        x = map_bvshl_to_bv(ctx, bvshl_term_desc(terms, r));
×
3096
        u = translate_thvar_to_eterm(ctx, x, tau);
×
3097
        break;
×
3098

3099
      case BV_LSHR:
1✔
3100
        x = map_bvlshr_to_bv(ctx, bvlshr_term_desc(terms, r));
1✔
3101
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3102
        break;
1✔
3103

3104
      case BV_ASHR:
1✔
3105
        x = map_bvashr_to_bv(ctx, bvashr_term_desc(terms, r));
1✔
3106
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3107
        break;
1✔
3108

3109
      case POWER_PRODUCT:
1✔
3110
        if (is_arithmetic_type(tau)) {
1✔
3111
          x = map_pprod_to_arith(ctx, pprod_term_desc(terms, r));
×
3112
        } else {
3113
          assert(is_bv_type(ctx->types, tau));
3114
          x = map_pprod_to_bv(ctx, pprod_term_desc(terms, r));
1✔
3115
        }
3116
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3117
        break;
1✔
3118

3119
      case ARITH_POLY:
619✔
3120
        x = map_poly_to_arith(ctx, poly_term_desc(terms, r));
619✔
3121
        u = translate_thvar_to_eterm(ctx, x, tau);
619✔
3122
        break;
619✔
3123

3124
      case BV64_POLY:
1,008✔
3125
        x = map_bvpoly64_to_bv(ctx, bvpoly64_term_desc(terms, r));
1,008✔
3126
        u = translate_thvar_to_eterm(ctx, x, tau);
1,008✔
3127
        break;
1,008✔
3128

3129
      case BV_POLY:
2✔
3130
        x = map_bvpoly_to_bv(ctx, bvpoly_term_desc(terms, r));
2✔
3131
        u = translate_thvar_to_eterm(ctx, x, tau);
2✔
3132
        break;
2✔
3133

3134
      default:
×
3135
        exception = INTERNAL_ERROR;
×
3136
        goto abort;
×
3137
      }
3138

3139
      // store the mapping r --> u
3140
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
38,334✔
3141
    }
3142
  }
3143

3144
  // If we canonicalized root to a different unit-type representative r,
3145
  // remember that root internalizes to the same egraph occurrence.
3146
  if (root != r) {
103,353✔
3147
    if (intern_tbl_root_is_free(&ctx->intern, root)) {
1✔
3148
      intern_tbl_map_root(&ctx->intern, root, occ2code(u));
1✔
3149
    } else {
3150
      // If root was mapped during the recursive internalization of r (e.g.,
3151
      // because root was reached as a sub-term), the mapping must agree
3152
      // with the occurrence we are about to return.
3153
      assert(intern_tbl_map_of_root(&ctx->intern, root) == occ2code(u));  // LCOV_EXCL_LINE - consistency check, unreachable on well-formed inputs
3154
    }
3155
  }
3156

3157
  // fix the polarity
3158
  return u ^ polarity;
103,353✔
3159

3160
 abort:
1✔
3161
  longjmp(ctx->env, exception);
1✔
3162
}
3163

3164

3165

3166

3167
/****************************************
3168
 *  CONVERSION TO ARITHMETIC VARIABLES  *
3169
 ***************************************/
3170

3171
/*
3172
 * Translate internalization code x to an arithmetic variable
3173
 * - if the code is for an egraph term u, then we return the
3174
 *   theory variable attached to u in the egraph.
3175
 * - otherwise, x must be the code of an arithmetic variable v,
3176
 *   we return v.
3177
 */
3178
static thvar_t translate_code_to_arith(context_t *ctx, int32_t x) {
99,880✔
3179
  eterm_t u;
3180
  thvar_t v;
3181

3182
  assert(code_is_valid(x));
3183

3184
  if (code_is_eterm(x)) {
99,880✔
3185
    u = code2eterm(x);
6,521✔
3186
    assert(ctx->egraph != NULL && egraph_term_is_arith(ctx->egraph, u));
3187
    v = egraph_term_base_thvar(ctx->egraph, u);
6,521✔
3188
  } else {
3189
    v = code2thvar(x);
93,359✔
3190
  }
3191

3192
  assert(v != null_thvar);
3193
  return v;
99,880✔
3194
}
3195

3196

3197
static thvar_t internalize_to_arith(context_t *ctx, term_t t) {
120,790✔
3198
  term_table_t *terms;
3199
  int32_t exception;
3200
  int32_t code;
3201
  term_t r;
3202
  occ_t u;
3203
  thvar_t x;
3204

3205
  assert(is_arithmetic_term(ctx->terms, t));
3206

3207
  if (! context_has_arith_solver(ctx)) {
120,790✔
3208
    exception = ARITH_NOT_SUPPORTED;
×
3209
    goto abort;
×
3210
  }
3211

3212
  /*
3213
   * Apply term substitution: t --> r
3214
   */
3215
  r = intern_tbl_get_root(&ctx->intern, t);
120,790✔
3216
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
120,790✔
3217
    /*
3218
     * r already internalized
3219
     */
3220
    code = intern_tbl_map_of_root(&ctx->intern, r);
99,721✔
3221
    x = translate_code_to_arith(ctx, code);
99,721✔
3222

3223
  } else {
3224
    /*
3225
     * Compute the internalization
3226
     */
3227
    terms = ctx->terms;
21,069✔
3228

3229
    switch (term_kind(terms, r)) {
21,069✔
3230
    case ARITH_CONSTANT:
1,270✔
3231
      x = ctx->arith.create_const(ctx->arith_solver, rational_term_desc(terms, r));
1,270✔
3232
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
1,270✔
3233
      break;
1,270✔
3234

3235
    case UNINTERPRETED_TERM:
15,374✔
3236
      x = ctx->arith.create_var(ctx->arith_solver, is_integer_root(ctx, r));
15,374✔
3237
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
15,374✔
3238
      //      printf("mapping: %s --> i!%d\n", term_name(ctx->terms, r), (int) x);
3239
      //      fflush(stdout);
3240
      break;
15,374✔
3241

3242
    case ARITH_FLOOR:
×
3243
      x = map_floor_to_arith(ctx, arith_floor_arg(terms, r));
×
3244
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3245
      break;
×
3246

3247
    case ARITH_CEIL:
×
3248
      x = map_ceil_to_arith(ctx, arith_ceil_arg(terms, r));
×
3249
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3250
      break;
×
3251

3252
    case ARITH_ABS:
4✔
3253
      x = map_abs_to_arith(ctx, arith_abs_arg(terms, r));
4✔
3254
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
4✔
3255
      break;
4✔
3256

3257
    case ITE_TERM:
2,230✔
3258
      x = map_ite_to_arith(ctx, ite_term_desc(terms, r), is_integer_root(ctx, r));
2,230✔
3259
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
2,230✔
3260
      break;
2,230✔
3261

3262
    case ITE_SPECIAL:
793✔
3263
      x = map_ite_to_arith(ctx, ite_term_desc(terms, r), is_integer_root(ctx, r));
793✔
3264
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
793✔
3265
      if (context_ite_bounds_enabled(ctx)) {
793✔
3266
        assert_ite_bounds(ctx, r, x);
793✔
3267
      }
3268
      break;
793✔
3269

3270
    case APP_TERM:
702✔
3271
      u = map_apply_to_eterm(ctx, app_term_desc(terms, r), type_of_root(ctx, r));
702✔
3272
      assert(egraph_term_is_arith(ctx->egraph, term_of_occ(u)));
3273
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
702✔
3274
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
702✔
3275
      assert(x != null_thvar);
3276
      break;
702✔
3277

3278
    case ARITH_RDIV:
3✔
3279
      x = map_rdiv_to_arith(ctx, arith_rdiv_term_desc(terms, r));
3✔
3280
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3281
      break;
×
3282

3283
    case ARITH_IDIV:
6✔
3284
      x = map_idiv_to_arith(ctx, arith_idiv_term_desc(terms, r));
6✔
3285
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
6✔
3286
      break;
6✔
3287

3288
    case ARITH_MOD:
9✔
3289
      x = map_mod_to_arith(ctx, arith_mod_term_desc(terms, r));
9✔
3290
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
9✔
3291
      break;
9✔
3292

3293
    case SELECT_TERM:
×
3294
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), type_of_root(ctx, r));
×
3295
      assert(egraph_term_is_arith(ctx->egraph, term_of_occ(u)));
3296
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3297
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
×
3298
      assert(x != null_thvar);
3299
      break;
×
3300

3301
    case POWER_PRODUCT:
×
3302
      x = map_pprod_to_arith(ctx, pprod_term_desc(terms, r));
×
3303
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3304
      break;
×
3305

3306
    case ARITH_POLY:
678✔
3307
      x = map_poly_to_arith(ctx, poly_term_desc(terms, r));
678✔
3308
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
678✔
3309
      break;
678✔
3310

3311
    case VARIABLE:
×
3312
      exception = FREE_VARIABLE_IN_FORMULA;
×
3313
      goto abort;
×
3314

3315
    default:
×
3316
      exception = INTERNAL_ERROR;
×
3317
      goto abort;
×
3318
    }
3319

3320
  }
3321

3322
  if (ctx->mcsat_supplement && ctx->egraph != NULL) {
120,787✔
3323
    egraph_arith_observer_register_arith_term(ctx->egraph, x, unsigned_term(r));
4✔
3324
  }
3325

3326
  return x;
120,787✔
3327

3328
 abort:
×
3329
  longjmp(ctx->env, exception);
×
3330
}
3331

3332

3333

3334
/***************************************
3335
 *  CONVERSION TO BITVECTOR VARIABLES  *
3336
 **************************************/
3337

3338
/*
3339
 * Translate internalization code x to a bitvector variable
3340
 * - if x is for an egraph term u, then we return the theory variable
3341
 *   attached to u in the egraph.
3342
 * - otherwise, x must be the code of a bitvector variable v, so we return v.
3343
 */
3344
static thvar_t translate_code_to_bv(context_t *ctx, int32_t x) {
299,215✔
3345
  eterm_t u;
3346
  thvar_t v;
3347

3348
  assert(code_is_valid(x));
3349

3350
  if (code_is_eterm(x)) {
299,215✔
3351
    u = code2eterm(x);
29,164✔
3352
    assert(ctx->egraph != NULL && egraph_term_is_bv(ctx->egraph, u));
3353
    v = egraph_term_base_thvar(ctx->egraph, u);
29,164✔
3354
  } else {
3355
    v = code2thvar(x);
270,051✔
3356
  }
3357

3358
  assert(v != null_thvar);
3359

3360
  return v;
299,215✔
3361
}
3362

3363
/*
3364
 * Place holders for now
3365
 */
3366
static thvar_t internalize_to_bv(context_t *ctx, term_t t) {
376,316✔
3367
  term_table_t *terms;
3368
  int32_t exception;
3369
  int32_t code;
3370
  term_t r;
3371
  occ_t u;
3372
  thvar_t x;
3373

3374
  assert(is_bitvector_term(ctx->terms, t));
3375

3376
  if (! context_has_bv_solver(ctx)) {
376,316✔
3377
    exception = BV_NOT_SUPPORTED;
×
3378
    goto abort;
×
3379
  }
3380

3381
  /*
3382
   * Apply the term substitution: t --> r
3383
   */
3384
  r = intern_tbl_get_root(&ctx->intern, t);
376,316✔
3385
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
376,316✔
3386
    // r is already internalized
3387
    code = intern_tbl_map_of_root(&ctx->intern, r);
299,215✔
3388
    x = translate_code_to_bv(ctx, code);
299,215✔
3389
  } else {
3390
    // compute r's internalization
3391
    terms = ctx->terms;
77,101✔
3392

3393
    switch (term_kind(terms, r)) {
77,101✔
3394
    case BV64_CONSTANT:
7,018✔
3395
      x = ctx->bv.create_const64(ctx->bv_solver, bvconst64_term_desc(terms, r));
7,018✔
3396
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
7,018✔
3397
      break;
7,018✔
3398

3399
    case BV_CONSTANT:
440✔
3400
      x = ctx->bv.create_const(ctx->bv_solver, bvconst_term_desc(terms, r));
440✔
3401
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
440✔
3402
      break;
440✔
3403

3404
    case UNINTERPRETED_TERM:
16,440✔
3405
      x = ctx->bv.create_var(ctx->bv_solver, term_bitsize(terms, r));
16,440✔
3406
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
16,440✔
3407
      break;
16,440✔
3408

3409
    case ITE_TERM:
20,779✔
3410
    case ITE_SPECIAL:
3411
      x = map_ite_to_bv(ctx, ite_term_desc(terms, r));
20,779✔
3412
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
20,779✔
3413
      break;
20,779✔
3414

3415
    case APP_TERM:
2,452✔
3416
      u = map_apply_to_eterm(ctx, app_term_desc(terms, r), type_of_root(ctx, r));
2,452✔
3417
      assert(egraph_term_is_bv(ctx->egraph, term_of_occ(u)));
3418
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
2,452✔
3419
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
2,452✔
3420
      assert(x != null_thvar);
3421
      break;
2,452✔
3422

3423
    case BV_ARRAY:
15,326✔
3424
      x = map_bvarray_to_bv(ctx, bvarray_term_desc(terms, r));
15,326✔
3425
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
15,326✔
3426
      break;
15,326✔
3427

3428
    case BV_DIV:
96✔
3429
      x = map_bvdiv_to_bv(ctx, bvdiv_term_desc(terms, r));
96✔
3430
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
96✔
3431
      break;
96✔
3432

3433
    case BV_REM:
175✔
3434
      x = map_bvrem_to_bv(ctx, bvrem_term_desc(terms, r));
175✔
3435
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
175✔
3436
      break;
175✔
3437

3438
    case BV_SDIV:
86✔
3439
      x = map_bvsdiv_to_bv(ctx, bvsdiv_term_desc(terms, r));
86✔
3440
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
86✔
3441
      break;
86✔
3442

3443
    case BV_SREM:
76✔
3444
      x = map_bvsrem_to_bv(ctx, bvsrem_term_desc(terms, r));
76✔
3445
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
76✔
3446
      break;
76✔
3447

3448
    case BV_SMOD:
×
3449
      x = map_bvsmod_to_bv(ctx, bvsmod_term_desc(terms, r));
×
3450
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3451
      break;
×
3452

3453
    case BV_SHL:
85✔
3454
      x = map_bvshl_to_bv(ctx, bvshl_term_desc(terms, r));
85✔
3455
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
85✔
3456
      break;
85✔
3457

3458
    case BV_LSHR:
1,427✔
3459
      x = map_bvlshr_to_bv(ctx, bvlshr_term_desc(terms, r));
1,427✔
3460
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
1,427✔
3461
      break;
1,427✔
3462

3463
    case BV_ASHR:
295✔
3464
      x = map_bvashr_to_bv(ctx, bvashr_term_desc(terms, r));
295✔
3465
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
295✔
3466
      break;
295✔
3467

3468
    case SELECT_TERM:
×
3469
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), type_of_root(ctx, r));
×
3470
      assert(egraph_term_is_bv(ctx->egraph, term_of_occ(u)));
3471
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3472
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
×
3473
      assert(x != null_thvar);
3474
      break;
×
3475

3476
    case POWER_PRODUCT:
584✔
3477
      x = map_pprod_to_bv(ctx, pprod_term_desc(terms, r));
584✔
3478
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
584✔
3479
      break;
584✔
3480

3481
    case BV64_POLY:
11,217✔
3482
      x = map_bvpoly64_to_bv(ctx, bvpoly64_term_desc(terms, r));
11,217✔
3483
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
11,217✔
3484
      break;
11,217✔
3485

3486
    case BV_POLY:
605✔
3487
      x = map_bvpoly_to_bv(ctx, bvpoly_term_desc(terms, r));
605✔
3488
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
605✔
3489
      break;
605✔
3490

3491
    case VARIABLE:
×
3492
      exception = FREE_VARIABLE_IN_FORMULA;
×
3493
      goto abort;
×
3494

3495
    default:
×
3496
      exception = INTERNAL_ERROR;
×
3497
      goto abort;
×
3498
    }
3499
  }
3500

3501
  return x;
376,316✔
3502

3503
 abort:
×
3504
  longjmp(ctx->env, exception);
×
3505
}
3506

3507

3508

3509

3510

3511

3512
/****************************
3513
 *  CONVERSION TO LITERALS  *
3514
 ***************************/
3515

3516
/*
3517
 * Translate an internalization code x to a literal
3518
 * - if x is the code of an egraph occurrence u, we return the
3519
 *   theory variable for u in the egraph
3520
 * - otherwise, x should be the code of a literal l in the core
3521
 */
3522
static literal_t translate_code_to_literal(context_t *ctx, int32_t x) {
1,397,361✔
3523
  occ_t u;
3524
  literal_t l;
3525

3526
  assert(code_is_valid(x));
3527
  if (code_is_eterm(x)) {
1,397,361✔
3528
    u = code2occ(x);
129,809✔
3529
    if (term_of_occ(u) == true_eterm) {
129,809✔
3530
      l = mk_lit(const_bvar, polarity_of(u));
129,809✔
3531

3532
      assert((u == true_occ && l == true_literal) ||
3533
             (u == false_occ && l == false_literal));
3534
    } else {
3535
      assert(ctx->egraph != NULL);
3536
      l = egraph_occ2literal(ctx->egraph, u);
×
3537
    }
3538
  } else {
3539
    l = code2literal(x);
1,267,552✔
3540
  }
3541

3542
  return l;
1,397,361✔
3543
}
3544

3545
static literal_t internalize_to_literal(context_t *ctx, term_t t) {
1,825,200✔
3546
  term_table_t *terms;
3547
  int32_t code;
3548
  uint32_t polarity;
3549
  term_t r;
3550
  literal_t l;
3551
  occ_t u;
3552

3553
  assert(is_boolean_term(ctx->terms, t));
3554

3555
  r = intern_tbl_get_root(&ctx->intern, t);
1,825,200✔
3556
  polarity = polarity_of(r);
1,825,200✔
3557
  r = unsigned_term(r);
1,825,200✔
3558

3559
  /*
3560
   * At this point:
3561
   * 1) r is a positive root in the internalization table
3562
   * 2) polarity is 1 or 0
3563
   * 3) if polarity is 0, then t is equal to r by substitution
3564
   *    if polarity is 1, then t is equal to (not r)
3565
   *
3566
   * We get l := internalization of r
3567
   * then return l or (not l) depending on polarity.
3568
   */
3569

3570
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
1,825,200✔
3571
    /*
3572
     * r already internalized
3573
     */
3574
    code = intern_tbl_map_of_root(&ctx->intern, r);
1,397,361✔
3575
    l = translate_code_to_literal(ctx, code);
1,397,361✔
3576

3577
  } else {
3578
    /*
3579
     * Recursively compute r's internalization
3580
     */
3581
    if (context_atom_requires_mcsat(ctx, r)) {
427,839✔
3582
      l = map_mcsat_atom_to_literal(ctx, r);
3✔
3583
      intern_tbl_map_root(&ctx->intern, r, literal2code(l));
3✔
3584
      goto done;
3✔
3585
    }
3586

3587
    terms = ctx->terms;
427,836✔
3588
    switch (term_kind(terms, r)) {
427,836✔
3589
    case CONSTANT_TERM:
×
3590
      assert(r == true_term);
3591
      l = true_literal;
×
3592
      break;
×
3593

3594
    case VARIABLE:
×
3595
      longjmp(ctx->env, FREE_VARIABLE_IN_FORMULA);
×
3596
      break;
3597

3598
    case UNINTERPRETED_TERM:
6,410✔
3599
      l = pos_lit(create_boolean_variable(ctx->core));
6,410✔
3600
      break;
6,410✔
3601

3602
    case ITE_TERM:
1,863✔
3603
    case ITE_SPECIAL:
3604
      l = map_ite_to_literal(ctx, ite_term_desc(terms, r));
1,863✔
3605
      break;
1,863✔
3606

3607
    case EQ_TERM:
14,519✔
3608
      l = map_eq_to_literal(ctx, eq_term_desc(terms, r));
14,519✔
3609
      break;
14,519✔
3610

3611
    case OR_TERM:
81,300✔
3612
      l = map_or_to_literal(ctx, or_term_desc(terms, r));
81,300✔
3613
      break;
81,300✔
3614

3615
    case XOR_TERM:
1✔
3616
      l = map_xor_to_literal(ctx, xor_term_desc(terms, r));
1✔
3617
      break;
1✔
3618

3619
    case ARITH_IS_INT_ATOM:
×
3620
      l = map_arith_is_int_to_literal(ctx, arith_is_int_arg(terms, r));
×
3621
      break;
×
3622

3623
    case ARITH_EQ_ATOM:
2,249✔
3624
      l = map_arith_eq_to_literal(ctx, arith_eq_arg(terms, r));
2,249✔
3625
      break;
2,249✔
3626

3627
    case ARITH_GE_ATOM:
33,841✔
3628
      l = map_arith_geq_to_literal(ctx, arith_ge_arg(terms, r));
33,841✔
3629
      break;
33,841✔
3630

3631
    case ARITH_BINEQ_ATOM:
8,967✔
3632
      l = map_arith_bineq_to_literal(ctx, arith_bineq_atom_desc(terms, r));
8,967✔
3633
      break;
8,967✔
3634

3635
    case ARITH_DIVIDES_ATOM:
8✔
3636
      l = map_arith_divides_to_literal(ctx, arith_divides_atom_desc(terms, r));
8✔
3637
      break;
8✔
3638

NEW
3639
    case ARITH_ROOT_ATOM:
×
NEW
3640
      longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
3641
      break;
3642

NEW
3643
    case ARITH_FF_EQ_ATOM:
×
3644
    case ARITH_FF_BINEQ_ATOM:
NEW
3645
      longjmp(ctx->env, CONTEXT_UNSUPPORTED_THEORY);
×
3646
      break;
3647

3648
    case APP_TERM:
4,368✔
3649
      l = map_apply_to_literal(ctx, app_term_desc(terms, r));
4,368✔
3650
      break;
4,368✔
3651

3652
    case SELECT_TERM:
×
3653
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), bool_type(ctx->types));
×
3654
      assert(egraph_term_is_bool(ctx->egraph, term_of_occ(u)));
3655
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3656
      l = egraph_occ2literal(ctx->egraph, u);
×
3657
      // we don't want to map r to l here
3658
      goto done;
×
3659

3660
    case DISTINCT_TERM:
9✔
3661
      l = map_distinct_to_literal(ctx, distinct_term_desc(terms, r));
9✔
3662
      break;
9✔
3663

3664
    case FORALL_TERM:
×
3665
      if (context_in_strict_mode(ctx)) {
×
3666
        longjmp(ctx->env, QUANTIFIERS_NOT_SUPPORTED);
×
3667
      }
3668
      // lax mode: turn forall into a proposition
3669
      l = pos_lit(create_boolean_variable(ctx->core));
×
3670
      break;
×
3671

3672
    case BIT_TERM:
264,228✔
3673
      l = map_bit_select_to_literal(ctx, bit_term_desc(terms, r));
264,228✔
3674
      break;
264,228✔
3675

3676
    case BV_EQ_ATOM:
4,864✔
3677
      l = map_bveq_to_literal(ctx, bveq_atom_desc(terms, r));
4,864✔
3678
      break;
4,864✔
3679

3680
    case BV_GE_ATOM:
2,302✔
3681
      l = map_bvge_to_literal(ctx, bvge_atom_desc(terms, r));
2,302✔
3682
      break;
2,302✔
3683

3684
    case BV_SGE_ATOM:
2,907✔
3685
      l = map_bvsge_to_literal(ctx, bvsge_atom_desc(terms, r));
2,907✔
3686
      break;
2,907✔
3687

3688
    default:
×
3689
      longjmp(ctx->env, INTERNAL_ERROR);
×
3690
      break;
3691
    }
3692

3693
    if (ctx->mcsat_supplement) {
427,836✔
3694
      context_observe_mcsat_atom(ctx, r, l);
4✔
3695
    }
3696

3697
    // map r to l in the internalization table
3698
    intern_tbl_map_root(&ctx->intern, r, literal2code(l));
427,836✔
3699
  }
3700

3701
 done:
1,825,200✔
3702
  return l ^ polarity;
1,825,200✔
3703
}
3704

3705

3706

3707
/******************************************************
3708
 *  TOP-LEVEL ASSERTIONS: TERMS ALREADY INTERNALIZED  *
3709
 *****************************************************/
3710

3711
/*
3712
 * Assert (x == tt) for an internalization code x
3713
 */
3714
static void assert_internalization_code(context_t *ctx, int32_t x, bool tt) {
920✔
3715
  occ_t g;
3716
  literal_t l;
3717

3718
  assert(code_is_valid(x));
3719

3720
  if (code_is_eterm(x)) {
920✔
3721
    // normalize to assertion (g == true)
3722
    g = code2occ(x);
10✔
3723
    if (! tt) g = opposite_occ(g);
10✔
3724

3725
    // We must deal with 'true_occ/false_occ' separately
3726
    // since they may be used even if there's no actual egraph.
3727
    if (g == false_occ) {
10✔
3728
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
3729
    } else if (g != true_occ) {
6✔
3730
      assert(ctx->egraph != NULL);
3731
      if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
×
3732
        egraph_assert_axiom(ctx->egraph, g);
×
3733
      } else {
3734
        l = egraph_make_eq(ctx->egraph, g, true_occ);
×
3735
        add_unit_clause(ctx->core, l);
×
3736
      }
3737
    }
3738
  } else {
3739
    l = code2literal(x);
910✔
3740
    if (! tt) l = not(l);
910✔
3741
    add_unit_clause(ctx->core, l);
910✔
3742
  }
3743
}
916✔
3744

3745
/*
3746
 * Assert t == true where t is a term that's already mapped
3747
 * either to a literal or to an egraph occurrence.
3748
 * - t must be a root in the internalization table
3749
 */
3750
static void assert_toplevel_intern(context_t *ctx, term_t t) {
739✔
3751
  int32_t code;
3752
  bool tt;
3753

3754
  assert(is_boolean_term(ctx->terms, t) &&
3755
         intern_tbl_is_root(&ctx->intern, t) &&
3756
         intern_tbl_root_is_mapped(&ctx->intern, t));
3757

3758
  tt = is_pos_term(t);
739✔
3759
  t = unsigned_term(t);
739✔
3760
  code = intern_tbl_map_of_root(&ctx->intern, t);
739✔
3761

3762
  assert_internalization_code(ctx, code, tt);
739✔
3763
}
739✔
3764

3765

3766

3767

3768

3769

3770

3771
/********************************
3772
 *   ARITHMETIC SUBSTITUTIONS   *
3773
 *******************************/
3774

3775
/*
3776
 * TODO: improve this in the integer case:
3777
 * - all_int is based on p's type in the term table and does
3778
 *   not take the context's substitutions into account.
3779
 * - integral_poly_after_div requires all coefficients
3780
 *   to be integer. This could be generalized to polynomials
3781
 *   with integer variables and rational coefficients.
3782
 */
3783

3784
/*
3785
 * Check whether term t can be eliminated by an arithmetic substitution
3786
 * - t's root must be uninterpreted and not internalized yet
3787
 */
3788
static bool is_elimination_candidate(context_t *ctx, term_t t) {
2,742✔
3789
  term_t r;
3790

3791
  r = intern_tbl_get_root(&ctx->intern, t);
2,742✔
3792
  return intern_tbl_root_is_free(&ctx->intern, r);
2,742✔
3793
}
3794

3795

3796
/*
3797
 * Replace every variable of t by the root of t in the internalization table
3798
 * - the result is stored in buffer
3799
 */
3800
static void apply_renaming_to_poly(context_t *ctx, polynomial_t *p,  poly_buffer_t *buffer) {
544✔
3801
  uint32_t i, n;
3802
  term_t t;
3803

3804
  reset_poly_buffer(buffer);
544✔
3805

3806
  assert(poly_buffer_is_zero(buffer));
3807

3808
  n = p->nterms;
544✔
3809
  for (i=0; i<n; i++) {
2,599✔
3810
    t = p->mono[i].var;
2,055✔
3811
    if (t == const_idx) {
2,055✔
3812
      poly_buffer_add_const(buffer, &p->mono[i].coeff);
180✔
3813
    } else {
3814
      // replace t by its root
3815
      t = intern_tbl_get_root(&ctx->intern, t);
1,875✔
3816
      poly_buffer_addmul_term(ctx->terms, buffer, t, &p->mono[i].coeff);
1,875✔
3817
    }
3818
  }
3819

3820
  normalize_poly_buffer(buffer);
544✔
3821
}
544✔
3822

3823

3824
/*
3825
 * Auxiliary function: check whether p/a is an integral polynomial
3826
 * assuming all variables and coefficients of p are integer.
3827
 * - check whether all coefficients are multiple of a
3828
 * - a must be non-zero
3829
 */
3830
static bool integralpoly_after_div(poly_buffer_t *buffer, rational_t *a) {
318✔
3831
  uint32_t i, n;
3832

3833
  if (q_is_one(a) || q_is_minus_one(a)) {
318✔
3834
    return true;
265✔
3835
  }
3836

3837
  n = buffer->nterms;
53✔
3838
  for (i=0; i<n; i++) {
64✔
3839
    if (! q_divides(a, &buffer->mono[i].coeff)) return false;
63✔
3840
  }
3841
  return true;
1✔
3842
}
3843

3844

3845
/*
3846
 * Check whether a top-level assertion (p == 0) can be
3847
 * rewritten (t == q) where t is not internalized yet.
3848
 * - all_int is true if p is an integer polynomial (i.e.,
3849
 *   all coefficients and all terms of p are integer).
3850
 * - p = input polynomial
3851
 * - return t or null_term if no adequate t is found
3852
 */
3853
static term_t try_poly_substitution(context_t *ctx, poly_buffer_t *buffer, bool all_int) {
544✔
3854
  uint32_t i, n;
3855
  term_t t;
3856

3857
  // check for a free variable in buffer
3858
  n = buffer->nterms;
544✔
3859
  for (i=0; i<n; i++) {
1,128✔
3860
    t = buffer->mono[i].var;
1,049✔
3861
    if (t != const_idx && is_elimination_candidate(ctx, t)) {
1,049✔
3862
      if (in_real_class(ctx, t) ||
518✔
3863
          (all_int && integralpoly_after_div(buffer, &buffer->mono[i].coeff))) {
318✔
3864
        // t is candidate for elimination
3865
        return t;
465✔
3866
      }
3867
    }
3868
  }
3869

3870
  return NULL_TERM;
79✔
3871
}
3872

3873

3874
/*
3875
 * Build polynomial - p/a + x in the context's aux_poly buffer
3876
 * where a = coefficient of x in p
3877
 * - x must occur in p
3878
 */
3879
static polynomial_t *build_poly_substitution(context_t *ctx, poly_buffer_t *buffer, term_t x) {
465✔
3880
  polynomial_t *q;
3881
  monomial_t *mono;
3882
  uint32_t i, n;
3883
  term_t y;
3884
  rational_t *a;
3885

3886
  n = buffer->nterms;
465✔
3887

3888
  // first get coefficient of x in buffer
3889
  a = NULL; // otherwise GCC complains
465✔
3890
  for (i=0; i<n; i++) {
2,283✔
3891
    y = buffer->mono[i].var;
1,818✔
3892
    if (y == x) {
1,818✔
3893
      a = &buffer->mono[i].coeff;
465✔
3894
    }
3895
  }
3896
  assert(a != NULL && n > 0);
3897

3898
  q = context_get_aux_poly(ctx, n);
465✔
3899
  q->nterms = n-1;
465✔
3900
  mono = q->mono;
465✔
3901

3902
  // compute - buffer/a (but skip monomial a.x)
3903
  for (i=0; i<n; i++) {
2,283✔
3904
    y = buffer->mono[i].var;
1,818✔
3905
    if (y != x) {
1,818✔
3906
      mono->var = y;
1,353✔
3907
      q_set_neg(&mono->coeff, &buffer->mono[i].coeff);
1,353✔
3908
      q_div(&mono->coeff, a);
1,353✔
3909
      mono ++;
1,353✔
3910
    }
3911
  }
3912

3913
  // end marker
3914
  mono->var = max_idx;
465✔
3915

3916
  return q;
465✔
3917
}
3918

3919

3920

3921
/*
3922
 * Try to eliminate a toplevel equality (p == 0) by variable substitution:
3923
 * - i.e., try to rewrite p == 0 into (x - q) == 0 where x is a free variable
3924
 *   then store the substitution x --> q in the internalization table.
3925
 * - all_int is true if p is an integer polynomial (i.e., all variables and all
3926
 *   coefficients of p are integer)
3927
 *
3928
 * - return true if the elimination succeeds
3929
 * - return false otherwise
3930
 */
3931
static bool try_arithvar_elim(context_t *ctx, polynomial_t *p, bool all_int) {
544✔
3932
  poly_buffer_t *buffer;
3933
  polynomial_t *q;
3934
  uint32_t i, n;
3935
  term_t t, u, r;
3936
  thvar_t x;
3937

3938
  /*
3939
   * First pass: internalize every term of p that's not a variable
3940
   * - we do that first to avoid circular substitutions (occurs-check)
3941
   */
3942
  n = p->nterms;
544✔
3943
  for (i=0; i<n; i++) {
2,599✔
3944
    t = p->mono[i].var;
2,055✔
3945
    if (t != const_idx && ! is_elimination_candidate(ctx, t)) {
2,055✔
3946
      (void) internalize_to_arith(ctx, t);
599✔
3947
    }
3948
  }
3949

3950

3951
  /*
3952
   * Apply variable renaming: this is to avoid circularities
3953
   * if p is of the form ... + a x + ... + b y + ...
3954
   * where both x and y are variables in the same class (i.e.,
3955
   * both are elimination candidates).
3956
   */
3957
  buffer = context_get_poly_buffer(ctx);
544✔
3958
  apply_renaming_to_poly(ctx, p, buffer);
544✔
3959

3960
  /*
3961
   * Search for a variable to substitute
3962
   */
3963
  u = try_poly_substitution(ctx, buffer, all_int);
544✔
3964
  if (u == NULL_TERM) {
544✔
3965
    return false; // no substitution found
79✔
3966
  }
3967

3968
  /*
3969
   * buffer is of the form a.u + p0, we rewrite (buffer == 0) to (u == q)
3970
   * where q = -1/a * p0
3971
   */
3972
  q = build_poly_substitution(ctx, buffer, u); // q is in ctx->aux_poly
465✔
3973

3974
  // convert q to a theory variable in the arithmetic solver
3975
  x = map_poly_to_arith(ctx, q);
465✔
3976

3977
  // map u (and its root) to x
3978
  r = intern_tbl_get_root(&ctx->intern, u);
465✔
3979
  assert(intern_tbl_root_is_free(&ctx->intern, r) && is_pos_term(r));
3980
  intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
465✔
3981

3982
#if TRACE
3983
  printf("---> toplevel equality: ");
3984
  print_polynomial(stdout, p);
3985
  printf(" == 0\n");
3986
  printf("     simplified to ");
3987
  print_term(stdout, ctx->terms, u);
3988
  printf(" := ");
3989
  print_polynomial(stdout, q);
3990
  printf("\n");
3991
#endif
3992

3993
  return true;
465✔
3994
}
3995

3996

3997

3998

3999

4000

4001

4002
/******************************************************
4003
 *  TOP-LEVEL ARITHMETIC EQUALITIES OR DISEQUALITIES  *
4004
 *****************************************************/
4005

4006
static void assert_arith_bineq(context_t *ctx, term_t t1, term_t t2, bool tt);
4007

4008
/*
4009
 * Top-level equality: t == (ite c u1 u2) between arithmetic terms
4010
 * - apply lift-if rule: (t == (ite c u1 u2)) --> (ite c (t == u1) (t == u2)
4011
 * - if tt is true: assert the equality otherwise assert the disequality
4012
 */
4013
static void assert_ite_arith_bineq(context_t *ctx, composite_term_t *ite, term_t t, bool tt) {
451✔
4014
  literal_t l1, l2, l3;
4015

4016
  assert(ite->arity == 3);
4017

4018
  l1 = internalize_to_literal(ctx, ite->arg[0]);
451✔
4019
  if (l1 == true_literal) {
451✔
4020
    // (ite c u1 u2) --> u1
4021
    assert_arith_bineq(ctx, ite->arg[1], t, tt);
3✔
4022
  } else if (l1 == false_literal) {
448✔
4023
    // (ite c u1 u2) --> u2
4024
    assert_arith_bineq(ctx, ite->arg[2], t, tt);
15✔
4025
  } else {
4026
    l2 = map_arith_bineq(ctx, ite->arg[1], t); // (u1 == t)
433✔
4027
    l3 = map_arith_bineq(ctx, ite->arg[2], t); // (u2 == t)
433✔
4028
    assert_ite(&ctx->gate_manager, l1, l2, l3, tt);
433✔
4029
  }
4030
}
451✔
4031

4032

4033
/*
4034
 * Try substitution t1 := t2
4035
 * - both are arithmetic terms and roots in the internalization table
4036
 */
4037
static void try_arithvar_bineq_elim(context_t *ctx, term_t t1, term_t t2) {
169✔
4038
  intern_tbl_t *intern;
4039
  thvar_t x, y;
4040
  int32_t code;
4041

4042
  assert(is_pos_term(t1) && intern_tbl_is_root(&ctx->intern, t1) &&
4043
         intern_tbl_root_is_free(&ctx->intern, t1));
4044

4045
  intern = &ctx->intern;
169✔
4046

4047
  if (is_constant_term(ctx->terms, t2)) {
169✔
4048
    if (intern_tbl_valid_const_subst(intern, t1, t2)) {
7✔
4049
      intern_tbl_add_subst(intern, t1, t2);
7✔
4050
    } else {
4051
      // unsat by type incompatibility
4052
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4053
    }
4054

4055
  } else if (intern_tbl_sound_subst(intern, t1, t2)) {
162✔
4056
    /*
4057
     * Internalize t2 to x.
4058
     * If t1 is still free after that, we can map t1 to x
4059
     * otherwise, t2 depends on t1 so we can't substitute.
4060
     */
4061
    x = internalize_to_arith(ctx, t2);
161✔
4062
    if (intern_tbl_root_is_free(intern, t1)) {
161✔
4063
      intern_tbl_map_root(&ctx->intern, t1, thvar2code(x));
2✔
4064
    } else {
4065
      assert(intern_tbl_root_is_mapped(intern, t1));
4066
      code = intern_tbl_map_of_root(intern, t1);
159✔
4067
      y = translate_code_to_arith(ctx, code);
159✔
4068

4069
      // assert x == y in the arithmetic solver
4070
      ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, true);
159✔
4071
    }
4072
  } else {
4073
    x = internalize_to_arith(ctx, t1);
1✔
4074
    y = internalize_to_arith(ctx, t2);
1✔
4075
    ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, true);
1✔
4076
  }
4077
}
169✔
4078

4079

4080
/*
4081
 * Top-level arithmetic equality t1 == t2:
4082
 * - if tt is true: assert t1 == t2 otherwise assert (t1 != t2)
4083
 * - both t1 and t2 are arithmetic terms and roots in the internalization table
4084
 * - the equality (t1 == t2) is not reducible by if-then-else flattening
4085
 */
4086
static void assert_arith_bineq_aux(context_t *ctx, term_t t1, term_t t2, bool tt) {
3,340✔
4087
  term_table_t *terms;
4088
  intern_tbl_t *intern;;
4089
  bool free1, free2;
4090
  thvar_t x, y;
4091
  occ_t u, v;
4092

4093
  assert(is_pos_term(t1) && intern_tbl_is_root(&ctx->intern, t1) &&
4094
         is_pos_term(t2) && intern_tbl_is_root(&ctx->intern, t2));
4095

4096
  terms = ctx->terms;
3,340✔
4097
  if (is_ite_term(terms, t1) && !is_ite_term(terms, t2)) {
3,340✔
4098
    assert_ite_arith_bineq(ctx, ite_term_desc(terms, t1), t2, tt);
112✔
4099
    return;
112✔
4100
  }
4101

4102
  if (is_ite_term(terms, t2) && !is_ite_term(terms, t1)) {
3,228✔
4103
    assert_ite_arith_bineq(ctx, ite_term_desc(terms, t2), t1, tt);
339✔
4104
    return;
339✔
4105
  }
4106

4107
  if (tt && context_arith_elim_enabled(ctx)) {
2,889✔
4108
    /*
4109
     * try a substitution
4110
     */
4111
    intern = &ctx->intern;
345✔
4112
    free1 = intern_tbl_root_is_free(intern, t1);
345✔
4113
    free2 = intern_tbl_root_is_free(intern, t2);
345✔
4114

4115
    if (free1 && free2) {
345✔
4116
      if (t1 != t2) {
1✔
4117
        intern_tbl_merge_classes(intern, t1, t2);
1✔
4118
      }
4119
      return;
1✔
4120
    }
4121

4122
    if (free1) {
344✔
4123
      try_arithvar_bineq_elim(ctx, t1, t2);
164✔
4124
      return;
164✔
4125
    }
4126

4127
    if (free2) {
180✔
4128
      try_arithvar_bineq_elim(ctx, t2, t1);
5✔
4129
      return;
5✔
4130
    }
4131

4132
  }
4133

4134
  /*
4135
   * Default: assert the constraint in the egraph or in the arithmetic
4136
   * solver if there's no egraph.
4137
   */
4138
  if (context_has_egraph(ctx)) {
2,719✔
4139
    u = internalize_to_eterm(ctx, t1);
1,658✔
4140
    v = internalize_to_eterm(ctx, t2);
1,658✔
4141
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
1,658✔
4142
      if (tt) {
1,658✔
4143
        egraph_assert_eq_axiom(ctx->egraph, u, v);
162✔
4144
      } else {
4145
        egraph_assert_diseq_axiom(ctx->egraph, u, v);
1,496✔
4146
      }
4147
    } else {
4148
      literal_t l = egraph_make_eq(ctx->egraph, u, v);
×
4149
      if (tt) {
×
4150
        add_unit_clause(ctx->core, l);
×
4151
      } else {
4152
        add_unit_clause(ctx->core, not(l));
×
4153
      }
4154
    }
4155
  } else {
4156
    x = internalize_to_arith(ctx, t1);
1,061✔
4157
    y = internalize_to_arith(ctx, t2);
1,061✔
4158
    ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, tt);
1,061✔
4159
  }
4160
}
4161

4162

4163

4164

4165
/*****************************************************
4166
 *  INTERNALIZATION OF TOP-LEVEL ATOMS AND FORMULAS  *
4167
 ****************************************************/
4168

4169
/*
4170
 * Recursive function: assert (t == tt) for a boolean term t
4171
 * - this is used when a toplevel formula simplifies to t
4172
 *   For example (ite c t u) --> t if c is true.
4173
 * - t is not necessarily a root in the internalization table
4174
 */
4175
static void assert_term(context_t *ctx, term_t t, bool tt);
4176

4177

4178
/*
4179
 * Top-level predicate: (p t_1 .. t_n)
4180
 * - if tt is true: assert (p t_1 ... t_n)
4181
 * - if tt is false: assert (not (p t_1 ... t_n))
4182
 */
4183
static void assert_toplevel_apply(context_t *ctx, composite_term_t *app, bool tt) {
252✔
4184
  occ_t *a;
4185
  uint32_t i, n;
4186

4187
  assert(app->arity > 0);
4188

4189
  n = app->arity;
252✔
4190

4191
  check_high_order_support(ctx, app->arg+1, n-1);
252✔
4192

4193
  a = alloc_istack_array(&ctx->istack, n);
252✔
4194
  for (i=0; i<n; i++) {
1,030✔
4195
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
778✔
4196
  }
4197

4198
  if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
252✔
4199
    if (tt) {
242✔
4200
      egraph_assert_pred_axiom(ctx->egraph, a[0], n-1, a+1);
214✔
4201
    } else {
4202
      egraph_assert_notpred_axiom(ctx->egraph, a[0], n-1, a+1);
28✔
4203
    }
4204
  } else {
4205
    literal_t l = egraph_make_pred(ctx->egraph, a[0], n-1, a+1);
10✔
4206
    if (tt) {
10✔
4207
      add_unit_clause(ctx->core, l);
3✔
4208
    } else {
4209
      add_unit_clause(ctx->core, not(l));
7✔
4210
    }
4211
  }
4212

4213
  free_istack_array(&ctx->istack, a);
252✔
4214
}
252✔
4215

4216

4217
/*
4218
 * Top-level (select i t)
4219
 * - if tt is true: assert (select i t)
4220
 * - if tt is false: assert (not (select i t))
4221
 */
4222
static void assert_toplevel_select(context_t *ctx, select_term_t *select, bool tt) {
×
4223
  occ_t u;
4224

4225
  u = map_select_to_eterm(ctx, select, bool_type(ctx->types));
×
4226
  if (! tt) {
×
4227
    u = opposite_occ(u);
×
4228
  }
4229
  if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
×
4230
    egraph_assert_axiom(ctx->egraph, u);
×
4231
  } else {
4232
    literal_t l = egraph_make_eq(ctx->egraph, u, true_occ);
×
4233
    add_unit_clause(ctx->core, l);
×
4234
  }
4235
}
×
4236

4237

4238
/*
4239
 * Top-level equality between Boolean terms
4240
 * - if tt is true, assert t1 == t2
4241
 * - if tt is false, assert t1 != t2
4242
 */
4243
static void assert_toplevel_iff(context_t *ctx, term_t t1, term_t t2, bool tt) {
2,739✔
4244
  term_t t;
4245
  literal_t l1, l2;
4246

4247
  /*
4248
   * Apply substitution then try flattening
4249
   */
4250
  t1 = intern_tbl_get_root(&ctx->intern, t1);
2,739✔
4251
  t2 = intern_tbl_get_root(&ctx->intern, t2);
2,739✔
4252
  if (t1 == t2) {
2,739✔
4253
    // (eq t1 t2) is true
4254
    if (!tt) {
×
4255
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4256
    }
4257
  }
4258
  // try simplification
4259
  t = simplify_bool_eq(ctx, t1, t2);
2,739✔
4260
  if (t != NULL_TERM) {
2,739✔
4261
    // (eq t1 t2) is equivalent to t
4262
    assert_term(ctx, t, tt) ;
17✔
4263
  } else {
4264
    // no simplification
4265
    l1 = internalize_to_literal(ctx, t1);
2,722✔
4266
    l2 = internalize_to_literal(ctx, t2);
2,722✔
4267
    assert_iff(&ctx->gate_manager, l1, l2, tt);
2,722✔
4268

4269
#if 0
4270
    if (tt) {
4271
      printf("top assert: (eq ");
4272
      print_literal(stdout, l1);
4273
      printf(" ");
4274
      print_literal(stdout, l2);
4275
      printf(")\n");
4276
    } else {
4277
      printf("top assert: (xor ");
4278
      print_literal(stdout, l1);
4279
      printf(" ");
4280
      print_literal(stdout, l2);
4281
      printf(")\n");
4282
    }
4283
#endif
4284
  }
4285
}
2,739✔
4286

4287
/*
4288
 * Top-level equality assertion (eq t1 t2):
4289
 * - if tt is true, assert (t1 == t2)
4290
 *   if tt is false, assert (t1 != t2)
4291
 */
4292
static void assert_toplevel_eq(context_t *ctx, composite_term_t *eq, bool tt) {
5,156✔
4293
  occ_t u1, u2;
4294

4295
  assert(eq->arity == 2);
4296

4297
  if (is_boolean_term(ctx->terms, eq->arg[0])) {
5,156✔
4298
    assert(is_boolean_term(ctx->terms, eq->arg[1]));
4299
    assert_toplevel_iff(ctx, eq->arg[0], eq->arg[1], tt);
2,739✔
4300
  } else {
4301
    // filter out high-order terms. It's enough to check eq->arg[0]
4302
    check_high_order_support(ctx, eq->arg, 1);
2,417✔
4303

4304
    u1 = internalize_to_eterm(ctx, eq->arg[0]);
2,416✔
4305
    u2 = internalize_to_eterm(ctx, eq->arg[1]);
2,416✔
4306
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
2,415✔
4307
      if (tt) {
2,401✔
4308
        egraph_assert_eq_axiom(ctx->egraph, u1, u2);
1,323✔
4309
      } else {
4310
        egraph_assert_diseq_axiom(ctx->egraph, u1, u2);
1,078✔
4311
      }
4312
    } else {
4313
      literal_t l = egraph_make_eq(ctx->egraph, u1, u2);
14✔
4314
      if (tt) {
14✔
4315
        add_unit_clause(ctx->core, l);
9✔
4316
      } else {
4317
        add_unit_clause(ctx->core, not(l));
5✔
4318
      }
4319
    }
4320
  }
4321
}
5,154✔
4322

4323

4324
/*
4325
 * Assertion (distinct a[0] .... a[n-1]) == tt
4326
 * when a[0] ... a[n-1] are arithmetic variables.
4327
 */
4328
static void assert_arith_distinct(context_t *ctx, uint32_t n, thvar_t *a, bool tt) {
155✔
4329
  literal_t l;
4330

4331
  l = make_arith_distinct(ctx, n, a);
155✔
4332
  if (! tt) {
155✔
4333
    l = not(l);
4✔
4334
  }
4335
  add_unit_clause(ctx->core, l);
155✔
4336
}
155✔
4337

4338

4339
/*
4340
 * Assertion (distinct a[0] .... a[n-1]) == tt
4341
 * when a[0] ... a[n-1] are bitvector variables.
4342
 */
4343
static void assert_bv_distinct(context_t *ctx, uint32_t n, thvar_t *a, bool tt) {
2✔
4344
  literal_t l;
4345

4346
  l = make_bv_distinct(ctx, n, a);
2✔
4347
  if (! tt) {
2✔
4348
    l = not(l);
1✔
4349
  }
4350
  add_unit_clause(ctx->core, l);
2✔
4351
}
2✔
4352

4353

4354
/*
4355
 * Generic (distinct t1 .. t_n)
4356
 * - if tt: assert (distinct t_1 ... t_n)
4357
 * - otherwise: assert (not (distinct t_1 ... t_n))
4358
 */
4359
static void assert_toplevel_distinct(context_t *ctx, composite_term_t *distinct, bool tt) {
173✔
4360
  uint32_t i, n;
4361
  int32_t *a;
4362

4363
  n = distinct->arity;
173✔
4364
  assert(n >= 2);
4365

4366
  a = alloc_istack_array(&ctx->istack, n);
173✔
4367

4368
  if (context_has_egraph(ctx)) {
173✔
4369
    // fail if arguments have function types and we don't
4370
    // have a function/array solver
4371
    check_high_order_support(ctx, distinct->arg, 1);
16✔
4372

4373
    // forward the assertion to the egraph
4374
    for (i=0; i<n; i++) {
69✔
4375
      a[i] = internalize_to_eterm(ctx, distinct->arg[i]);
55✔
4376
    }
4377

4378
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
14✔
4379
      if (tt) {
14✔
4380
        egraph_assert_distinct_axiom(ctx->egraph, n, a);
10✔
4381
      } else {
4382
        egraph_assert_notdistinct_axiom(ctx->egraph, n, a);
4✔
4383
      }
4384
    } else {
4385
      literal_t l = egraph_make_distinct(ctx->egraph, n, a);
×
4386
      if (tt) {
×
4387
        add_unit_clause(ctx->core, l);
×
4388
      } else {
4389
        add_unit_clause(ctx->core, not(l));
×
4390
      }
4391
    }
4392

4393
  } else if (is_arithmetic_term(ctx->terms, distinct->arg[0])) {
157✔
4394
    // translate to arithmetic then assert
4395
    for (i=0; i<n; i++) {
3,922✔
4396
      a[i] = internalize_to_arith(ctx, distinct->arg[i]);
3,767✔
4397
    }
4398
    assert_arith_distinct(ctx, n, a, tt);
155✔
4399

4400
  } else if (is_bitvector_term(ctx->terms, distinct->arg[0])) {
2✔
4401
    // translate to bitvectors then assert
4402
    for (i=0; i<n; i++) {
13✔
4403
      a[i] = internalize_to_bv(ctx, distinct->arg[i]);
11✔
4404
    }
4405
    assert_bv_distinct(ctx, n, a, tt);
2✔
4406

4407
  } else {
4408
    longjmp(ctx->env, uf_error_code(ctx, distinct->arg[0]));
×
4409
  }
4410

4411
  free_istack_array(&ctx->istack, a);
171✔
4412
}
171✔
4413

4414

4415

4416
/*
4417
 * Top-level arithmetic equality t1 == u1:
4418
 * - t1 and u1 are arithmetic terms
4419
 * - if tt is true assert (t1 == u1) otherwise assert (t1 != u1)
4420
 * - apply lift-if simplifications and variable elimination
4421
 */
4422
static void assert_arith_bineq(context_t *ctx, term_t t1, term_t u1, bool tt) {
3,413✔
4423
  ivector_t *v;
4424
  int32_t *a;
4425
  uint32_t i, n;
4426
  term_t t2, u2;
4427

4428
  /*
4429
   * Apply substitutions then try if-then-else flattening
4430
   */
4431
  t1 = intern_tbl_get_root(&ctx->intern, t1);
3,413✔
4432
  u1 = intern_tbl_get_root(&ctx->intern, u1);
3,413✔
4433

4434
  v = &ctx->aux_vector;
3,413✔
4435
  assert(v->size == 0);
4436
  t2 = flatten_ite_equality(ctx, v, t1, u1);
3,413✔
4437
  u2 = flatten_ite_equality(ctx, v, u1, t2);
3,413✔
4438

4439
  /*
4440
   * (t1 == u1) is now equivalent to
4441
   * the conjunction of (t2 == u2) and all the terms in v
4442
   */
4443
  n = v->size;
3,413✔
4444
  if (n == 0) {
3,413✔
4445
    /*
4446
     * The simple flattening did not work.
4447
     */
4448
    assert(t1 == t2 && u1 == u2);
4449
    assert_arith_bineq_aux(ctx, t2, u2, tt);
3,327✔
4450

4451
  } else {
4452
    // make a copy of v[0 ... n-1]
4453
    // and reserve a[n] for the literal (eq t2 u2)
4454
    a = alloc_istack_array(&ctx->istack, n+1);
86✔
4455
    for (i=0; i<n; i++) {
1,531✔
4456
      a[i] = v->data[i];
1,445✔
4457
    }
4458
    ivector_reset(v);
86✔
4459

4460
    if (tt) {
86✔
4461
      // assert (and a[0] ... a[n-1] (eq t2 u2))
4462
      for (i=0; i<n; i++) {
340✔
4463
        assert_term(ctx, a[i], true);
327✔
4464
      }
4465

4466
      /*
4467
       * The assertions a[0] ... a[n-1] may have
4468
       * caused roots to be merged. So we must
4469
       * apply term substitution again.
4470
       */
4471
      t2 = intern_tbl_get_root(&ctx->intern, t2);
13✔
4472
      u2 = intern_tbl_get_root(&ctx->intern, u2);
13✔
4473
      assert_arith_bineq_aux(ctx, t2, u2, true);
13✔
4474

4475
    } else {
4476
      // assert (or (not a[0]) ... (not a[n-1]) (not (eq t2 u2)))
4477
      for (i=0; i<n; i++) {
1,191✔
4478
        a[i] = not(internalize_to_literal(ctx, a[i]));
1,118✔
4479
      }
4480
      a[n] = not(map_arith_bineq_aux(ctx, t2, u2));
73✔
4481

4482
      add_clause(ctx->core, n+1, a);
73✔
4483
    }
4484

4485
    free_istack_array(&ctx->istack, a);
86✔
4486
  }
4487
}
3,413✔
4488

4489

4490
/*
4491
 * Top-level arithmetic assertion:
4492
 * - if tt is true, assert p == 0
4493
 * - if tt is false, assert p != 0
4494
 */
4495
static void assert_toplevel_poly_eq(context_t *ctx, polynomial_t *p, bool tt) {
1,273✔
4496
  uint32_t i, n;
4497
  thvar_t *a;
4498

4499
  n = p->nterms;
1,273✔
4500
  a = alloc_istack_array(&ctx->istack, n);;
1,273✔
4501
  // skip the constant if any
4502
  i = 0;
1,273✔
4503
  if (p->mono[0].var == const_idx) {
1,273✔
4504
    a[0] = null_thvar;
1,208✔
4505
    i ++;
1,208✔
4506
  }
4507

4508
  // deal with the non-constant monomials
4509
  while (i<n) {
3,928✔
4510
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
2,655✔
4511
    i ++;
2,655✔
4512
  }
4513

4514
  // assertion
4515
  ctx->arith.assert_poly_eq_axiom(ctx->arith_solver, p, a, tt);
1,273✔
4516
  free_istack_array(&ctx->istack, a);
1,273✔
4517
}
1,273✔
4518

4519

4520

4521
/*
4522
 * Top-level arithmetic equality:
4523
 * - t is an arithmetic term
4524
 * - if tt is true, assert (t == 0)
4525
 * - otherwise, assert (t != 0)
4526
 */
4527
static void assert_toplevel_arith_eq(context_t *ctx, term_t t, bool tt) {
2,269✔
4528
  term_table_t *terms;
4529
  polynomial_t *p;
4530
  bool all_int;
4531
  thvar_t x;
4532

4533
  assert(is_arithmetic_term(ctx->terms, t));
4534

4535
  terms = ctx->terms;
2,269✔
4536
  if (tt && context_arith_elim_enabled(ctx) && term_kind(terms, t) == ARITH_POLY) {
2,269✔
4537
    /*
4538
     * Polynomial equality: a_1 t_1 + ... + a_n t_n = 0
4539
     * attempt to eliminate one of t_1 ... t_n
4540
     */
4541
    p = poly_term_desc(terms, t);
544✔
4542
    all_int = is_integer_term(terms, t);
544✔
4543
    if (try_arithvar_elim(ctx, p, all_int)) { // elimination worked
544✔
4544
      return;
465✔
4545
    }
4546
  }
4547

4548
  // default
4549
  if (term_kind(terms, t) == ARITH_POLY) {
1,804✔
4550
    assert_toplevel_poly_eq(ctx, poly_term_desc(terms, t), tt);
1,273✔
4551
  } else if (is_ite_term(terms, t)) {
531✔
4552
    assert_arith_bineq(ctx, t, zero_term, tt);
8✔
4553
  } else {
4554
    x = internalize_to_arith(ctx, t);
523✔
4555
    ctx->arith.assert_eq_axiom(ctx->arith_solver, x, tt);
521✔
4556
  }
4557
}
4558

4559

4560

4561
/*
4562
 * Top-level arithmetic assertion:
4563
 * - if tt is true, assert p >= 0
4564
 * - if tt is false, assert p < 0
4565
 */
4566
static void assert_toplevel_poly_geq(context_t *ctx, polynomial_t *p, bool tt) {
25,932✔
4567
  uint32_t i, n;
4568
  thvar_t *a;
4569

4570
  n = p->nterms;
25,932✔
4571
  a = alloc_istack_array(&ctx->istack, n);;
25,932✔
4572
  // skip the constant if any
4573
  i = 0;
25,932✔
4574
  if (p->mono[0].var == const_idx) {
25,932✔
4575
    a[0] = null_thvar;
25,106✔
4576
    i ++;
25,106✔
4577
  }
4578

4579
  // deal with the non-constant monomials
4580
  while (i<n) {
55,607✔
4581
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
29,676✔
4582
    i ++;
29,675✔
4583
  }
4584

4585
  // assertion
4586
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, a, tt);
25,931✔
4587
  free_istack_array(&ctx->istack, a);
25,931✔
4588
}
25,931✔
4589

4590

4591

4592
/*
4593
 * Top-level arithmetic inequality:
4594
 * - t is an arithmetic term
4595
 * - if tt is true, assert (t >= 0)
4596
 * - if tt is false, assert (t < 0)
4597
 */
4598
static void assert_toplevel_arith_geq(context_t *ctx, term_t t, bool tt) {
27,858✔
4599
  term_table_t *terms;
4600
  thvar_t x;
4601

4602
  assert(is_arithmetic_term(ctx->terms, t));
4603

4604
  terms = ctx->terms;
27,858✔
4605
  if (term_kind(terms, t) == ARITH_POLY) {
27,858✔
4606
    assert_toplevel_poly_geq(ctx, poly_term_desc(terms, t), tt);
25,932✔
4607
  } else {
4608
    x = internalize_to_arith(ctx, t);
1,926✔
4609
    ctx->arith.assert_ge_axiom(ctx->arith_solver, x, tt);
1,926✔
4610
  }
4611
}
27,857✔
4612

4613

4614
/*
4615
 * Top-level binary equality: (eq t u)
4616
 * - both t and u are arithmetic terms
4617
 * - if tt is true, assert (t == u)
4618
 * - if tt is false, assert (t != u)
4619
 */
4620
static void assert_toplevel_arith_bineq(context_t *ctx, composite_term_t *eq, bool tt) {
3,387✔
4621
  assert(eq->arity == 2);
4622
  assert_arith_bineq(ctx, eq->arg[0], eq->arg[1], tt);
3,387✔
4623
}
3,387✔
4624

4625

4626

4627
/*
4628
 * Top-level (is_int t)
4629
 * - t is an arithmetic term
4630
 * - if tt is true, assert (t <= (floor t))
4631
 * - if tt is false, asssert (t > (floor t))
4632
 *
4633
 * NOTE: instead of asserting (t <= (floor t)) we could create a fresh
4634
 * integer variable z and assert (t = z).
4635
 */
4636
static void assert_toplevel_arith_is_int(context_t *ctx, term_t t, bool tt) {
×
4637
  polynomial_t *p;
4638
  thvar_t map[2];
4639
  thvar_t x, y;
4640

4641
  x = internalize_to_arith(ctx, t);
×
4642
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
4643
    if (!tt) {
×
4644
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4645
    }
4646
  } else {
4647
    // x is not an integer variable
4648
    y = get_floor(ctx, x); // y := (floor x)
×
4649
    p = context_get_aux_poly(ctx, 3);
×
4650
    context_store_diff_poly(p, map, y, x); // (p, map) stores (y - x)
×
4651
    // assert either (p >= 0) --> (x <= floor(x))
4652
    // or (p < 0) --> (x > (floor x)
4653
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, tt);
×
4654
  }
4655
}
×
4656

4657

4658
/*
4659
 * Top-level (divides k t)
4660
 * - if tt is true, assert (t <= k * (div t k))
4661
 * - if tt is false, assert (t > k * (div t k))
4662
 *
4663
 * We assume (k != 0) since (divides 0 t) is rewritten to (t == 0) by
4664
 * the term manager.
4665
 *
4666
 * NOTE: instead of asserting (t <= k * (div t k)) we could create a fresh
4667
 * integer variable z and assert (t = k * z).
4668
 */
4669
static void assert_toplevel_arith_divides(context_t *ctx, composite_term_t *divides, bool tt) {
×
4670
  rational_t k;
4671
  polynomial_t *p;
4672
  thvar_t map[2];
4673
  thvar_t x, y;
4674
  term_t d;
4675

4676
  assert(divides->arity == 2);
4677

4678
  d = divides->arg[0];
×
4679
  if (term_kind(ctx->terms, d) == ARITH_CONSTANT) {
×
4680
    // copy the divider
4681
    q_init(&k);
×
4682
    q_set(&k, rational_term_desc(ctx->terms, d));
×
4683
    assert(q_is_nonzero(&k));
4684

4685
    x = internalize_to_arith(ctx, divides->arg[1]);
×
4686
    y = get_div(ctx, x, &k);  // y := (div x k);
×
4687
    p = context_get_aux_poly(ctx, 3);
×
4688
    context_store_divides_constraint(p, map, x, y, &k); // p is (- x + k * y)
×
4689

4690
    // if tt, assert (p >= 0) <=> x <= k * y
4691
    // if not tt, assert (p < 0) <=> x > k * y
4692
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, tt);
×
4693

4694
    q_clear(&k);
×
4695
  } else {
4696
    // not a constant divider: not supported
4697
    longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
4698
  }
4699
}
×
4700

4701

4702

4703

4704

4705

4706
/*
4707
 * Top-level conditional
4708
 * - c = conditional descriptor
4709
 * - if tt is true: assert c otherwise assert not c
4710
 *
4711
 * - c->nconds = number of clauses in the conditional
4712
 * - for each clause i: c->pair[i] = <cond, val>
4713
 * - c->defval = default value
4714
 */
4715
static void assert_toplevel_conditional(context_t *ctx, conditional_t *c, bool tt) {
13✔
4716
  uint32_t i, n;
4717
  literal_t *a;
4718
  literal_t l;
4719
  bool all_false;
4720
  term_t t;
4721

4722
#if 0
4723
  printf("---> toplevel conditional\n");
4724
#endif
4725

4726
  t = simplify_conditional(ctx, c);
13✔
4727
  if (t != NULL_TERM) {
13✔
4728
    assert_term(ctx, t, tt);
2✔
4729
    return;
2✔
4730
  }
4731

4732
  n = c->nconds;
11✔
4733
  a = alloc_istack_array(&ctx->istack, n + 1);
11✔
4734

4735
  all_false = true;
11✔
4736
  for (i=0; i<n; i++) {
72✔
4737
    // a[i] = condition for pair[i]
4738
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
62✔
4739
    if (a[i] == true_literal) {
62✔
4740
      // if a[i] is true, all other conditions must be false
4741
      assert_term(ctx, c->pair[i].val, tt);
1✔
4742
      goto done;
1✔
4743
    }
4744
    if (a[i] != false_literal) {
61✔
4745
      // l = value for pair[i]
4746
      l = signed_literal(internalize_to_literal(ctx, c->pair[i].val), tt);
58✔
4747
      add_binary_clause(ctx->core, not(a[i]), l); // a[i] => v[i]
58✔
4748
      all_false = false;
58✔
4749
    }
4750
  }
4751

4752
  if (all_false) {
10✔
4753
    // all a[i]s are false: no need for a clause
4754
    assert_term(ctx, c->defval, tt);
1✔
4755
    goto done;
1✔
4756
  }
4757

4758
  // last clause: (a[0] \/ .... \/ a[n] \/ +/-defval)
4759
  a[n] = signed_literal(internalize_to_literal(ctx, c->defval), tt);
9✔
4760
  add_clause(ctx->core, n+1, a);
9✔
4761

4762
  // cleanup
4763
 done:
11✔
4764
  free_istack_array(&ctx->istack, a);
11✔
4765
}
4766

4767

4768

4769
/*
4770
 * Top-level boolean if-then-else (ite c t1 t2)
4771
 * - if tt is true: assert (ite c t1 t2)
4772
 * - if tt is false: assert (not (ite c t1 t2))
4773
 */
4774
static void assert_toplevel_ite(context_t *ctx, composite_term_t *ite, bool tt) {
70✔
4775
  conditional_t *d;
4776
  literal_t l1, l2, l3;
4777

4778
  assert(ite->arity == 3);
4779

4780
  // high-order ite should work. See map_ite_to_eterm
4781

4782
  d = context_make_conditional(ctx, ite);
70✔
4783
  if (d != NULL) {
70✔
4784
    assert_toplevel_conditional(ctx, d, tt);
13✔
4785
    context_free_conditional(ctx, d);
13✔
4786
    return;
13✔
4787
  }
4788

4789
  l1 = internalize_to_literal(ctx, ite->arg[0]);
57✔
4790
  if (l1 == true_literal) {
57✔
4791
    assert_term(ctx, ite->arg[1], tt);
5✔
4792
  } else if (l1 == false_literal) {
52✔
4793
    assert_term(ctx, ite->arg[2], tt);
2✔
4794
  } else {
4795
    l2 = internalize_to_literal(ctx, ite->arg[1]);
50✔
4796
    l3 = internalize_to_literal(ctx, ite->arg[2]);
50✔
4797
    assert_ite(&ctx->gate_manager, l1, l2, l3, tt);
50✔
4798
  }
4799
}
4800

4801

4802
/*
4803
 * Top-level (or t1 ... t_n)
4804
 * - it tt is true: add a clause
4805
 * - it tt is false: assert (not t1) ... (not t_n)
4806
 */
4807
static void assert_toplevel_or(context_t *ctx, composite_term_t *or, bool tt) {
42,971✔
4808
  ivector_t *v;
4809
  int32_t *a;
4810
  uint32_t i, n;
4811

4812
  if (tt) {
42,971✔
4813
    if (context_flatten_or_enabled(ctx)) {
42,955✔
4814
      // Flatten into vector v
4815
      v = &ctx->aux_vector;
15,019✔
4816
      assert(v->size == 0);
4817
      flatten_or_term(ctx, v, or);
15,019✔
4818

4819
      // if v contains a true_term, ignore the clause
4820
      n = v->size;
15,019✔
4821
      if (disjunct_is_true(ctx, v->data, n)) {
15,019✔
4822
        ivector_reset(v);
971✔
4823
        return;
971✔
4824
      }
4825

4826
      // make a copy of v
4827
      a = alloc_istack_array(&ctx->istack, n);
14,048✔
4828
      for (i=0; i<n; i++) {
58,759✔
4829
        a[i] = v->data[i];
44,711✔
4830
      }
4831
      ivector_reset(v);
14,048✔
4832

4833
      for (i=0; i<n; i++) {
58,436✔
4834
        a[i] = internalize_to_literal(ctx, a[i]);
44,541✔
4835
        if (a[i] == true_literal) goto done;
44,541✔
4836
      }
4837

4838
    } else {
4839
      /*
4840
       * No flattening
4841
       */
4842
      n = or->arity;
27,936✔
4843
      if (disjunct_is_true(ctx, or->arg, n)) {
27,936✔
4844
        return;
2,503✔
4845
      }
4846

4847
      a = alloc_istack_array(&ctx->istack, n);
25,433✔
4848
      for (i=0; i<n; i++) {
143,590✔
4849
        a[i] = internalize_to_literal(ctx, or->arg[i]);
118,257✔
4850
        if (a[i] == true_literal) goto done;
118,257✔
4851
      }
4852
    }
4853

4854
    // assert (or a[0] ... a[n-1])
4855
    add_clause(ctx->core, n, a);
39,228✔
4856

4857
  done:
39,481✔
4858
    free_istack_array(&ctx->istack, a);
39,481✔
4859

4860
  } else {
4861
    /*
4862
     * Propagate to children:
4863
     *  (or t_0 ... t_n-1) is false
4864
     * so all children must be false too
4865
     */
4866
    n = or->arity;
16✔
4867
    for (i=0; i<n; i++) {
48✔
4868
      assert_term(ctx, or->arg[i], false);
32✔
4869
    }
4870
  }
4871

4872
}
4873

4874

4875
/*
4876
 * Top-level (xor t1 ... t_n) == tt
4877
 */
4878
static void assert_toplevel_xor(context_t *ctx, composite_term_t *xor, bool tt) {
7✔
4879
  int32_t *a;
4880
  uint32_t i, n;
4881

4882
  n = xor->arity;
7✔
4883
  a = alloc_istack_array(&ctx->istack, n);
7✔
4884
  for (i=0; i<n; i++) {
58✔
4885
    a[i] = internalize_to_literal(ctx, xor->arg[i]);
51✔
4886
  }
4887

4888
  assert_xor(&ctx->gate_manager, n, a, tt);
7✔
4889
  free_istack_array(&ctx->istack, a);
7✔
4890
}
7✔
4891

4892

4893

4894
/*
4895
 * Top-level bit select
4896
 */
4897
static void assert_toplevel_bit_select(context_t *ctx, select_term_t *select, bool tt) {
32,805✔
4898
  term_t t, s;
4899
  thvar_t x;
4900

4901
  /*
4902
   * Check for simplification
4903
   */
4904
  t = intern_tbl_get_root(&ctx->intern, select->arg);
32,805✔
4905
  s = extract_bit(ctx->terms, t, select->idx);
32,805✔
4906
  if (s != NULL_TERM) {
32,805✔
4907
    // (select t i) is s
4908
    assert_term(ctx, s, tt);
63✔
4909
  } else {
4910
    // no simplification
4911
    x = internalize_to_bv(ctx, select->arg);
32,742✔
4912
    ctx->bv.set_bit(ctx->bv_solver, x, select->idx, tt);
32,742✔
4913
  }
4914
}
32,804✔
4915

4916

4917
/*
4918
 * Top-level bitvector atoms
4919
 */
4920
// Auxiliary function: assert (t == 0) or (t != 0) depending on tt
4921
static void assert_toplevel_bveq0(context_t *ctx, term_t t, bool tt) {
41✔
4922
  uint32_t n;
4923
  thvar_t x, y;
4924

4925
  t = intern_tbl_get_root(&ctx->intern, t);
41✔
4926
  n = term_bitsize(ctx->terms, t);
41✔
4927
  x = internalize_to_bv(ctx, t);
41✔
4928
  y = ctx->bv.create_zero(ctx->bv_solver, n);
41✔
4929
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x, y, tt);
41✔
4930
}
41✔
4931

4932

4933
/*
4934
 * Experimental: when t1 and t2 have a common factor C:
4935
 *   t1 = C * u1
4936
 *   t2 = C * u2
4937
 * then we have (t1 /= t2) implies (u1 /= u2).
4938
 * So we can add (u1 /= u2) when (t1 /= t2) is asserted.
4939
 * This is redundant but it may help solving the problem, especially if C is a
4940
 * complex expression.
4941
 */
4942
static void assert_factored_inequality(context_t *ctx, bvfactoring_t *f) {
9✔
4943
  term_t u1, u2;
4944
  thvar_t x, y;
4945

4946
  assert(f->code == BVFACTOR_FOUND);
4947

4948
  //  printf("Asserting factored inequality\n\n");
4949

4950
  u1 = bitvector_factoring_left_term(ctx, f);
9✔
4951
  u2 = bitvector_factoring_right_term(ctx, f);
9✔
4952
  x = internalize_to_bv(ctx, u1);
9✔
4953
  y = internalize_to_bv(ctx, u2);
9✔
4954
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x,  y, false);
9✔
4955
}
9✔
4956

4957
static void assert_toplevel_bveq(context_t *ctx, composite_term_t *eq, bool tt) {
9,370✔
4958
  bveq_simp_t simp;
4959
  ivector_t *v;
4960
  int32_t *a;
4961
  term_t t, t1, t2;
4962
  thvar_t x, y;
4963
  uint32_t i, n;
4964

4965
  assert(eq->arity == 2);
4966

4967
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
9,370✔
4968
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
9,370✔
4969
  t = simplify_bitvector_eq(ctx, t1, t2);
9,370✔
4970
  if (t != NULL_TERM) {
9,370✔
4971
    // (bveq t1 t2) is equivalent to t
4972
    assert_term(ctx, t, tt);
18✔
4973
    return;
74✔
4974
  }
4975

4976
  if (tt) {
9,352✔
4977
    // try to flatten to a conjunction of terms
4978
    v = &ctx->aux_vector;
7,534✔
4979
    assert(v->size == 0);
4980
    if (bveq_flattens(ctx->terms, t1, t2, v)) {
7,534✔
4981
      /*
4982
       * (bveq t1 t2) is equivalent to (and v[0] ... v[k])
4983
       * (bveq t1 t2) is true at the toplevel so v[0] ... v[k] must all be true
4984
       */
4985

4986
      // make a copy of v
4987
      n = v->size;
19✔
4988
      a = alloc_istack_array(&ctx->istack, n);
19✔
4989
      for (i=0; i<n; i++) {
579✔
4990
        a[i] = v->data[i];
560✔
4991
      }
4992
      ivector_reset(v);
19✔
4993

4994
      // assert
4995
      for (i=0; i<n; i++) {
548✔
4996
        assert_term(ctx, a[i], true);
530✔
4997
      }
4998

4999
      free_istack_array(&ctx->istack, a);
18✔
5000
      return;
18✔
5001
    }
5002

5003
    // flattening failed
5004
    ivector_reset(v);
7,515✔
5005
  }
5006

5007
  /*
5008
   * Try more simplifications
5009
   */
5010
  try_arithmetic_bveq_simplification(ctx, &simp, t1, t2);
9,333✔
5011
  switch (simp.code) {
9,333✔
5012
  case BVEQ_CODE_TRUE:
×
5013
    if (!tt) longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5014
    break;
×
5015

5016
  case BVEQ_CODE_FALSE:
×
5017
    if (tt) longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5018
    break;
×
5019

5020
  case BVEQ_CODE_REDUCED:
36✔
5021
    t1 = intern_tbl_get_root(&ctx->intern, simp.left);
36✔
5022
    t2 = intern_tbl_get_root(&ctx->intern, simp.right);
36✔
5023
    break;
36✔
5024

5025
  case BVEQ_CODE_REDUCED0:
41✔
5026
    // reduced to simp.left == 0
5027
    assert_toplevel_bveq0(ctx, simp.left, tt);
41✔
5028
    return;
41✔
5029

5030
  default:
9,256✔
5031
    break;
9,256✔
5032
  }
5033

5034
  /*
5035
   * Try Factoring
5036
   */
5037
  if (!tt) {
9,292✔
5038
    bvfactoring_t *factoring;
5039
    bool eq = false;
1,783✔
5040

5041
    factoring = objstack_alloc(&ctx->ostack, sizeof(bvfactoring_t), (cleaner_t) delete_bvfactoring);
1,783✔
5042
    init_bvfactoring(factoring);
1,783✔
5043

5044
    try_bitvector_factoring(ctx, factoring, t1, t2);
1,783✔
5045
    switch (factoring->code) {
1,783✔
5046
    case BVFACTOR_EQUAL:
4✔
5047
      eq = true;
4✔
5048
      break;
4✔
5049

5050
    case BVFACTOR_FOUND:
9✔
5051
      assert_factored_inequality(ctx, factoring);
9✔
5052
      break;
9✔
5053

5054
    default:
1,770✔
5055
      break;
1,770✔
5056
    }
5057
    // delete_bvfactoring(&factoring);
5058
    objstack_pop(&ctx->ostack);
1,783✔
5059

5060
    if (eq) {
1,783✔
5061
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
5062
    }
5063
  }
5064

5065
  /*
5066
   * NOTE: asserting (eq t1 t2) in the egraph instead makes things worse
5067
   */
5068
  x = internalize_to_bv(ctx, t1);
9,288✔
5069
  y = internalize_to_bv(ctx, t2);
9,288✔
5070
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x,  y, tt);
9,288✔
5071
}
5072

5073
static void assert_toplevel_bvge(context_t *ctx, composite_term_t *ge, bool tt) {
1,488✔
5074
  thvar_t x, y;
5075

5076
  assert(ge->arity == 2);
5077

5078
  x = internalize_to_bv(ctx, ge->arg[0]);
1,488✔
5079
  y = internalize_to_bv(ctx, ge->arg[1]);
1,488✔
5080
  ctx->bv.assert_ge_axiom(ctx->bv_solver, x,  y, tt);
1,488✔
5081
}
1,488✔
5082

5083
static void assert_toplevel_bvsge(context_t *ctx, composite_term_t *sge, bool tt) {
459✔
5084
  thvar_t x, y;
5085

5086
  assert(sge->arity == 2);
5087

5088
  x = internalize_to_bv(ctx, sge->arg[0]);
459✔
5089
  y = internalize_to_bv(ctx, sge->arg[1]);
459✔
5090
  ctx->bv.assert_sge_axiom(ctx->bv_solver, x,  y, tt);
459✔
5091
}
459✔
5092

5093

5094

5095
/*
5096
 * Top-level formula t:
5097
 * - t is a boolean term (or the negation of a boolean term)
5098
 * - t must be a root in the internalization table and must be mapped to true
5099
 */
5100
static void assert_toplevel_formula(context_t *ctx, term_t t) {
125,449✔
5101
  term_table_t *terms;
5102
  int32_t code;
5103
  literal_t l;
5104
  bool tt;
5105

5106
  assert(is_boolean_term(ctx->terms, t) &&
5107
         intern_tbl_is_root(&ctx->intern, t) &&
5108
         term_is_true(ctx, t));
5109

5110
  tt = is_pos_term(t);
125,449✔
5111
  t = unsigned_term(t);
125,449✔
5112

5113
  /*
5114
   * Now: t is a root and has positive polarity
5115
   * - tt indicates whether we assert t or (not t):
5116
   *   tt true: assert t
5117
   *   tt false: assert (not t)
5118
   */
5119
  terms = ctx->terms;
125,449✔
5120
  if (context_atom_requires_mcsat(ctx, t)) {
125,449✔
5121
    l = map_mcsat_atom_to_literal(ctx, t);
10✔
5122
    code = literal2code(l);
10✔
5123
    intern_tbl_remap_root(&ctx->intern, t, code);
10✔
5124
    assert_internalization_code(ctx, code, tt);
10✔
5125
    return;
10✔
5126
  }
5127
  if (ctx->mcsat_supplement) {
125,439✔
5128
    context_observe_mcsat_atom(ctx, t, tt ? true_literal : false_literal);
14✔
5129
  }
5130

5131
  switch (term_kind(terms, t)) {
125,439✔
5132
  case CONSTANT_TERM:
×
5133
  case UNINTERPRETED_TERM:
5134
    // should be eliminated by flattening
5135
    code = INTERNAL_ERROR;
×
5136
    goto abort;
×
5137

5138
  case ITE_TERM:
68✔
5139
  case ITE_SPECIAL:
5140
    assert_toplevel_ite(ctx, ite_term_desc(terms, t), tt);
68✔
5141
    break;
68✔
5142

5143
  case OR_TERM:
42,940✔
5144
    assert_toplevel_or(ctx, or_term_desc(terms, t), tt);
42,940✔
5145
    break;
42,940✔
5146

5147
  case XOR_TERM:
7✔
5148
    assert_toplevel_xor(ctx, xor_term_desc(terms, t), tt);
7✔
5149
    break;
7✔
5150

5151
  case EQ_TERM:
5,145✔
5152
    assert_toplevel_eq(ctx, eq_term_desc(terms, t), tt);
5,145✔
5153
    break;
5,143✔
5154

5155
  case ARITH_IS_INT_ATOM:
×
5156
    assert_toplevel_arith_is_int(ctx, arith_is_int_arg(terms, t), tt);
×
5157
    break;
×
5158

5159
  case ARITH_EQ_ATOM:
2,265✔
5160
    assert_toplevel_arith_eq(ctx, arith_eq_arg(terms, t), tt);
2,265✔
5161
    break;
2,263✔
5162

5163
  case ARITH_GE_ATOM:
27,851✔
5164
    assert_toplevel_arith_geq(ctx, arith_ge_arg(terms, t), tt);
27,851✔
5165
    break;
27,850✔
5166

5167
  case ARITH_BINEQ_ATOM:
3,206✔
5168
    assert_toplevel_arith_bineq(ctx, arith_bineq_atom_desc(terms, t), tt);
3,206✔
5169
    break;
3,206✔
5170

5171
  case ARITH_DIVIDES_ATOM:
×
5172
    assert_toplevel_arith_divides(ctx, arith_divides_atom_desc(terms, t), tt);
×
5173
    break;
×
5174

5175
  case APP_TERM:
250✔
5176
    assert_toplevel_apply(ctx, app_term_desc(terms, t), tt);
250✔
5177
    break;
250✔
5178

5179
  case SELECT_TERM:
×
5180
    assert_toplevel_select(ctx, select_term_desc(terms, t), tt);
×
5181
    break;
×
5182

5183
  case DISTINCT_TERM:
173✔
5184
    assert_toplevel_distinct(ctx, distinct_term_desc(terms, t), tt);
173✔
5185
    break;
171✔
5186

5187
  case VARIABLE:
×
5188
    code = FREE_VARIABLE_IN_FORMULA;
×
5189
    goto abort;
×
5190

5191
  case FORALL_TERM:
×
5192
    if (context_in_strict_mode(ctx)) {
×
5193
      code = QUANTIFIERS_NOT_SUPPORTED;
×
5194
      goto abort;
×
5195
    }
5196
    break;
×
5197

5198
  case BIT_TERM:
32,262✔
5199
    assert_toplevel_bit_select(ctx, bit_term_desc(terms, t), tt);
32,262✔
5200
    break;
32,262✔
5201

5202
  case BV_EQ_ATOM:
9,331✔
5203
    assert_toplevel_bveq(ctx, bveq_atom_desc(terms, t), tt);
9,331✔
5204
    break;
9,323✔
5205

5206
  case BV_GE_ATOM:
1,486✔
5207
    assert_toplevel_bvge(ctx, bvge_atom_desc(terms, t), tt);
1,486✔
5208
    break;
1,486✔
5209

5210
  case BV_SGE_ATOM:
455✔
5211
    assert_toplevel_bvsge(ctx, bvsge_atom_desc(terms, t), tt);
455✔
5212
    break;
455✔
5213

5214
  default:
×
5215
    code = INTERNAL_ERROR;
×
5216
    goto abort;
×
5217
  }
5218

5219
  return;
125,424✔
5220

5221
 abort:
×
5222
  longjmp(ctx->env, code);
×
5223
}
5224

5225

5226

5227
/*
5228
 * Assert (t == tt) for a boolean term t:
5229
 * - if t is not internalized, record the mapping
5230
 *   (root t) --> tt in the internalization table
5231
 */
5232
static void assert_term(context_t *ctx, term_t t, bool tt) {
998✔
5233
  term_table_t *terms;
5234
  int32_t code;
5235
  literal_t l;
5236

5237
  assert(is_boolean_term(ctx->terms, t));
5238

5239
  /*
5240
   * Apply substitution + fix polarity
5241
   */
5242
  t = intern_tbl_get_root(&ctx->intern, t);
998✔
5243
  tt ^= is_neg_term(t);
998✔
5244
  t = unsigned_term(t);
998✔
5245

5246
  if (intern_tbl_root_is_mapped(&ctx->intern, t)) {
998✔
5247
    /*
5248
     * The root is already mapped:
5249
     * Either t is already internalized, or it occurs in
5250
     * one of the vectors top_eqs, top_atoms, top_formulas
5251
     * and it will be internalized/asserted later.
5252
     */
5253
    code = intern_tbl_map_of_root(&ctx->intern, t);
171✔
5254
    assert_internalization_code(ctx, code, tt);
171✔
5255

5256
  } else {
5257
    if (context_atom_requires_mcsat(ctx, t)) {
827✔
NEW
5258
      l = map_mcsat_atom_to_literal(ctx, t);
×
NEW
5259
      code = literal2code(l);
×
NEW
5260
      intern_tbl_map_root(&ctx->intern, t, code);
×
NEW
5261
      assert_internalization_code(ctx, code, tt);
×
NEW
5262
      return;
×
5263
    }
5264
    if (ctx->mcsat_supplement) {
827✔
NEW
5265
      context_observe_mcsat_atom(ctx, t, tt ? true_literal : false_literal);
×
5266
    }
5267

5268
    // store the mapping t --> tt
5269
    intern_tbl_map_root(&ctx->intern, t, bool2code(tt));
827✔
5270

5271
    // internalize and assert
5272
    terms = ctx->terms;
827✔
5273
    switch (term_kind(terms, t)) {
827✔
5274
    case CONSTANT_TERM:
×
5275
      // should always be internalized
5276
      code = INTERNAL_ERROR;
×
5277
      goto abort;
×
5278

5279
    case UNINTERPRETED_TERM:
1✔
5280
      // nothing to do: t --> true/false in the internalization table
5281
      break;
1✔
5282

5283
    case ITE_TERM:
2✔
5284
    case ITE_SPECIAL:
5285
      assert_toplevel_ite(ctx, ite_term_desc(terms, t), tt);
2✔
5286
      break;
2✔
5287

5288
    case OR_TERM:
31✔
5289
      assert_toplevel_or(ctx, or_term_desc(terms, t), tt);
31✔
5290
      break;
31✔
5291

5292
    case XOR_TERM:
×
5293
      assert_toplevel_xor(ctx, xor_term_desc(terms, t), tt);
×
5294
      break;
×
5295

5296
    case EQ_TERM:
11✔
5297
      assert_toplevel_eq(ctx, eq_term_desc(terms, t), tt);
11✔
5298
      break;
11✔
5299

5300
    case ARITH_IS_INT_ATOM:
×
5301
      assert_toplevel_arith_is_int(ctx, arith_is_int_arg(terms, t), tt);
×
5302
      break;
×
5303

5304
    case ARITH_EQ_ATOM:
4✔
5305
      assert_toplevel_arith_eq(ctx, arith_eq_arg(terms, t), tt);
4✔
5306
      break;
4✔
5307

5308
    case ARITH_GE_ATOM:
7✔
5309
      assert_toplevel_arith_geq(ctx, arith_ge_arg(terms, t), tt);
7✔
5310
      break;
7✔
5311

5312
    case ARITH_BINEQ_ATOM:
181✔
5313
      assert_toplevel_arith_bineq(ctx, arith_bineq_atom_desc(terms, t), tt);
181✔
5314
      break;
181✔
5315

5316
    case ARITH_DIVIDES_ATOM:
×
5317
      assert_toplevel_arith_divides(ctx, arith_divides_atom_desc(terms, t), tt);
×
5318
      break;
×
5319

5320
    case APP_TERM:
2✔
5321
      assert_toplevel_apply(ctx, app_term_desc(terms, t), tt);
2✔
5322
      break;
2✔
5323

5324
    case SELECT_TERM:
×
5325
      assert_toplevel_select(ctx, select_term_desc(terms, t), tt);
×
5326
      break;
×
5327

5328
    case DISTINCT_TERM:
×
5329
      assert_toplevel_distinct(ctx, distinct_term_desc(terms, t), tt);
×
5330
      break;
×
5331

5332
    case VARIABLE:
×
5333
      code = FREE_VARIABLE_IN_FORMULA;
×
5334
      goto abort;
×
5335

5336
    case FORALL_TERM:
×
5337
      if (context_in_strict_mode(ctx)) {
×
5338
        code = QUANTIFIERS_NOT_SUPPORTED;
×
5339
        goto abort;
×
5340
      }
5341
      break;
×
5342

5343
    case BIT_TERM:
543✔
5344
      assert_toplevel_bit_select(ctx, bit_term_desc(terms, t), tt);
543✔
5345
      break;
542✔
5346

5347
    case BV_EQ_ATOM:
39✔
5348
      assert_toplevel_bveq(ctx, bveq_atom_desc(terms, t), tt);
39✔
5349
      break;
39✔
5350

5351
    case BV_GE_ATOM:
2✔
5352
      assert_toplevel_bvge(ctx, bvge_atom_desc(terms, t), tt);
2✔
5353
      break;
2✔
5354

5355
    case BV_SGE_ATOM:
4✔
5356
      assert_toplevel_bvsge(ctx, bvsge_atom_desc(terms, t), tt);
4✔
5357
      break;
4✔
5358

5359
    default:
×
5360
      code = INTERNAL_ERROR;
×
5361
      goto abort;
×
5362
    }
5363
  }
5364

5365
  return;
993✔
5366

5367
 abort:
×
5368
  longjmp(ctx->env, code);
×
5369
}
5370

5371

5372

5373

5374
/************************
5375
 *  PARAMETERS/OPTIONS  *
5376
 ***********************/
5377

5378
/*
5379
 * Map architecture id to theories word
5380
 */
5381
static const uint32_t arch2theories[NUM_ARCH] = {
5382
  0,                           //  CTX_ARCH_NOSOLVERS --> empty theory
5383

5384
  UF_MASK,                     //  CTX_ARCH_EG
5385
  ARITH_MASK,                  //  CTX_ARCH_SPLX
5386
  IDL_MASK,                    //  CTX_ARCH_IFW
5387
  RDL_MASK,                    //  CTX_ARCH_RFW
5388
  BV_MASK,                     //  CTX_ARCH_BV
5389
  UF_MASK|FUN_MASK,            //  CTX_ARCH_EGFUN
5390
  UF_MASK|ARITH_MASK,          //  CTX_ARCH_EGSPLX
5391
  UF_MASK|BV_MASK,             //  CTX_ARCH_EGBV
5392
  UF_MASK|ARITH_MASK|FUN_MASK, //  CTX_ARCH_EGFUNSPLX
5393
  UF_MASK|BV_MASK|FUN_MASK,    //  CTX_ARCH_EGFUNBV
5394
  UF_MASK|BV_MASK|ARITH_MASK,  //  CTX_ARCH_EGSPLXBV
5395
  ALLTH_MASK,                  //  CTX_ARCH_EGFUNSPLXBV
5396

5397
  IDL_MASK,                    //  CTX_ARCH_AUTO_IDL
5398
  RDL_MASK,                    //  CTX_ARCH_AUTO_RDL
5399

5400
  UF_MASK|ARITH_MASK|FUN_MASK  //  CTX_ARCH_MCSAT
5401
};
5402

5403

5404
/*
5405
 * Each architecture has a fixed set of solver components:
5406
 * - the set of components is stored as a bit vector (on 8bits)
5407
 * - this uses the following bit-masks
5408
 * For the AUTO_xxx architecture, nothing is required initially,
5409
 * so the bitmask is 0.
5410
 */
5411
#define EGRPH  0x1
5412
#define SPLX   0x2
5413
#define IFW    0x4
5414
#define RFW    0x8
5415
#define BVSLVR 0x10
5416
#define FSLVR  0x20
5417
#define MCSAT  0x40
5418

5419
static const uint8_t arch_components[NUM_ARCH] = {
5420
  0,                        //  CTX_ARCH_NOSOLVERS
5421

5422
  EGRPH,                    //  CTX_ARCH_EG
5423
  SPLX,                     //  CTX_ARCH_SPLX
5424
  IFW,                      //  CTX_ARCH_IFW
5425
  RFW,                      //  CTX_ARCH_RFW
5426
  BVSLVR,                   //  CTX_ARCH_BV
5427
  EGRPH|FSLVR,              //  CTX_ARCH_EGFUN
5428
  EGRPH|SPLX,               //  CTX_ARCH_EGSPLX
5429
  EGRPH|BVSLVR,             //  CTX_ARCH_EGBV
5430
  EGRPH|SPLX|FSLVR,         //  CTX_ARCH_EGFUNSPLX
5431
  EGRPH|BVSLVR|FSLVR,       //  CTX_ARCH_EGFUNBV
5432
  EGRPH|SPLX|BVSLVR,        //  CTX_ARCH_EGSPLXBV
5433
  EGRPH|SPLX|BVSLVR|FSLVR,  //  CTX_ARCH_EGFUNSPLXBV
5434

5435
  0,                        //  CTX_ARCH_AUTO_IDL
5436
  0,                        //  CTX_ARCH_AUTO_RDL
5437

5438
  MCSAT                     //  CTX_ARCH_MCSAT
5439
};
5440

5441

5442
/*
5443
 * Smt mode for a context mode
5444
 */
5445
static const smt_mode_t core_mode[NUM_MODES] = {
5446
  SMT_MODE_BASIC,       // one check
5447
  SMT_MODE_BASIC,       // multichecks
5448
  SMT_MODE_PUSHPOP,     // push/pop
5449
  SMT_MODE_INTERACTIVE, // interactive
5450
};
5451

5452

5453
/*
5454
 * Flags for a context mode
5455
 */
5456
static const uint32_t mode2options[NUM_MODES] = {
5457
  0,
5458
  MULTICHECKS_OPTION_MASK,
5459
  MULTICHECKS_OPTION_MASK|PUSHPOP_OPTION_MASK,
5460
  MULTICHECKS_OPTION_MASK|PUSHPOP_OPTION_MASK|CLEANINT_OPTION_MASK,
5461
};
5462

5463

5464

5465

5466

5467

5468
/*
5469
 * SIMPLEX OPTIONS
5470
 */
5471

5472
/*
5473
 * Which version of the arithmetic solver is present
5474
 */
5475
bool context_has_idl_solver(context_t *ctx) {
8✔
5476
  uint8_t solvers;
5477
  solvers = arch_components[ctx->arch];
8✔
5478
  return ctx->arith_solver != NULL && (solvers & IFW);
8✔
5479
}
5480

5481
bool context_has_rdl_solver(context_t *ctx) {
×
5482
  uint8_t solvers;
5483
  solvers = arch_components[ctx->arch];
×
5484
  return ctx->arith_solver != NULL && (solvers & RFW);
×
5485
}
5486

5487
bool context_has_simplex_solver(context_t *ctx) {
45,871✔
5488
  uint8_t solvers;
5489
  solvers = arch_components[ctx->arch];
45,871✔
5490
  return ctx->arith_solver != NULL && (solvers & SPLX);
45,871✔
5491
}
5492

5493

5494
/*
5495
 * If the simplex solver already exists, the options are propagated.
5496
 * Otherwise, they are recorded into the option flags. They will
5497
 * be set up when the simplex solver is created.
5498
 */
5499
void enable_splx_eager_lemmas(context_t *ctx) {
178✔
5500
  ctx->options |= SPLX_EGRLMAS_OPTION_MASK;
178✔
5501
  if (context_has_simplex_solver(ctx)) {
178✔
5502
    simplex_enable_eager_lemmas(ctx->arith_solver);
178✔
5503
  }
5504
}
178✔
5505

5506
void disable_splx_eager_lemmas(context_t *ctx) {
×
5507
  ctx->options &= ~SPLX_EGRLMAS_OPTION_MASK;
×
5508
  if (context_has_simplex_solver(ctx)) {
×
5509
    simplex_disable_eager_lemmas(ctx->arith_solver);
×
5510
  }
5511
}
×
5512

5513

5514
void enable_splx_periodic_icheck(context_t *ctx) {
152✔
5515
  ctx->options |= SPLX_ICHECK_OPTION_MASK;
152✔
5516
  if (context_has_simplex_solver(ctx)) {
152✔
5517
    simplex_enable_periodic_icheck(ctx->arith_solver);
141✔
5518
  }
5519
}
152✔
5520

5521
void disable_splx_periodic_icheck(context_t *ctx) {
×
5522
  ctx->options &= ~SPLX_ICHECK_OPTION_MASK;
×
5523
  if (context_has_simplex_solver(ctx)) {
×
5524
    simplex_disable_periodic_icheck(ctx->arith_solver);
×
5525
  }
5526
}
×
5527

5528
void enable_splx_eqprop(context_t *ctx) {
77✔
5529
  ctx->options |= SPLX_EQPROP_OPTION_MASK;
77✔
5530
  if (context_has_simplex_solver(ctx)) {
77✔
5531
    simplex_enable_eqprop(ctx->arith_solver);
77✔
5532
  }
5533
}
77✔
5534

5535
void disable_splx_eqprop(context_t *ctx) {
×
5536
  ctx->options &= ~SPLX_EQPROP_OPTION_MASK;
×
5537
  if (context_has_simplex_solver(ctx)) {
×
5538
    simplex_disable_eqprop(ctx->arith_solver);
×
5539
  }
5540
}
×
5541

5542

5543

5544

5545
/******************
5546
 *  EMPTY SOLVER  *
5547
 *****************/
5548

5549
/*
5550
 * We need an empty theory solver for initializing
5551
 * the core if the architecture is NOSOLVERS.
5552
 */
5553
static void donothing(void *solver) {
2,607✔
5554
}
2,607✔
5555

5556
static void null_backtrack(void *solver, uint32_t backlevel) {
×
5557
}
×
5558

5559
static bool null_propagate(void *solver) {
×
5560
  return true;
×
5561
}
5562

5563
static fcheck_code_t null_final_check(void *solver) {
×
5564
  return FCHECK_SAT;
×
5565
}
5566

5567
static th_ctrl_interface_t null_ctrl = {
5568
  donothing,        // start_internalization
5569
  donothing,        // start_search
5570
  null_propagate,   // propagate
5571
  null_final_check, // final check
5572
  donothing,        // increase_decision_level
5573
  null_backtrack,   // backtrack
5574
  donothing,        // push
5575
  donothing,        // pop
5576
  donothing,        // reset
5577
  donothing,        // clear
5578
};
5579

5580

5581
// for the smt interface, nothing should be called since there are no atoms
5582
static th_smt_interface_t null_smt = {
5583
  NULL, NULL, NULL, NULL, NULL,
5584
};
5585

5586

5587

5588

5589
/****************************
5590
 *  ARCHITECTURE & SOLVERS  *
5591
 ***************************/
5592

5593
/*
5594
 * Check whether a given architecture includes a specific solver
5595
 */
5596
bool context_arch_has_egraph(context_arch_t arch) {
417✔
5597
  return arch_components[arch] & EGRPH;
417✔
5598
}
5599

5600
bool context_arch_has_bv(context_arch_t arch) {
×
5601
  return arch_components[arch] & BVSLVR;
×
5602
}
5603

5604
bool context_arch_has_fun(context_arch_t arch) {
×
5605
  return arch_components[arch] & FSLVR;
×
5606
}
5607

5608
bool context_arch_has_arith(context_arch_t arch) {
×
5609
  return arch_components[arch] & (SPLX|IFW|RFW);
×
5610
}
5611

5612
bool context_arch_has_mcsat(context_arch_t arch) {
×
5613
  return arch_components[arch] & MCSAT;
×
5614
}
5615

5616
bool context_arch_has_simplex(context_arch_t arch) {
×
5617
  return arch_components[arch] & SPLX;
×
5618
}
5619

5620
bool context_arch_has_ifw(context_arch_t arch) {
×
5621
  return arch_components[arch] & IFW;
×
5622
}
5623

5624
bool context_arch_has_rfw(context_arch_t arch) {
×
5625
  return arch_components[arch] & RFW;
×
5626
}
5627

5628

5629
/****************************
5630
 *  SOLVER INITIALIZATION   *
5631
 ***************************/
5632

5633
/*
5634
 * Create and initialize the egraph
5635
 * - the core must be created first
5636
 */
5637
static void create_egraph(context_t *ctx) {
4,794✔
5638
  egraph_t *egraph;
5639

5640
  assert(ctx->egraph == NULL);
5641

5642
  egraph = (egraph_t *) safe_malloc(sizeof(egraph_t));
4,794✔
5643
  init_egraph(egraph, ctx->types);
4,794✔
5644
  ctx->egraph = egraph;
4,794✔
5645
}
4,794✔
5646

5647

5648
/*
5649
 * Create and initialize the mcsat solver
5650
 */
5651
static void create_mcsat(context_t *ctx) {
747✔
5652
  assert(ctx->mcsat == NULL);
5653
  ctx->mcsat = mcsat_new(ctx);
747✔
5654
}
747✔
5655

5656

5657

5658
/*
5659
 * Create and initialize the idl solver and attach it to the core
5660
 * - there must be no other solvers and no egraph
5661
 * - if automatic is true, attach the solver to the core, otherwise
5662
 *   initialize the core
5663
 * - copy the solver's internalization interface into arith
5664
 */
5665
static void create_idl_solver(context_t *ctx, bool automatic) {
26✔
5666
  idl_solver_t *solver;
5667
  smt_mode_t cmode;
5668

5669
  assert(ctx->egraph == NULL && ctx->arith_solver == NULL && ctx->bv_solver == NULL &&
5670
         ctx->fun_solver == NULL && ctx->core != NULL);
5671

5672
  cmode = core_mode[ctx->mode];
26✔
5673
  solver = (idl_solver_t *) safe_malloc(sizeof(idl_solver_t));
26✔
5674
  init_idl_solver(solver, ctx->core, &ctx->gate_manager);
26✔
5675
  if (automatic) {
26✔
5676
    smt_core_reset_thsolver(ctx->core, solver, idl_ctrl_interface(solver),
26✔
5677
                            idl_smt_interface(solver));
5678
  } else {
5679
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, idl_ctrl_interface(solver),
×
5680
                  idl_smt_interface(solver), cmode);
5681
  }
5682
  idl_solver_init_jmpbuf(solver, &ctx->env);
26✔
5683
  ctx->arith_solver = solver;
26✔
5684
  ctx->arith = *idl_arith_interface(solver);
26✔
5685
}
26✔
5686

5687

5688
/*
5689
 * Create and initialize the rdl solver and attach it to the core.
5690
 * - there must be no other solvers and no egraph
5691
 * - if automatic is true, attach rdl to the core, otherwise
5692
 *   initialize the core
5693
 * - copy the solver's internalization interface in ctx->arith
5694
 */
5695
static void create_rdl_solver(context_t *ctx, bool automatic) {
8✔
5696
  rdl_solver_t *solver;
5697
  smt_mode_t cmode;
5698

5699
  assert(ctx->egraph == NULL && ctx->arith_solver == NULL && ctx->bv_solver == NULL &&
5700
         ctx->fun_solver == NULL && ctx->core != NULL);
5701

5702
  cmode = core_mode[ctx->mode];
8✔
5703
  solver = (rdl_solver_t *) safe_malloc(sizeof(rdl_solver_t));
8✔
5704
  init_rdl_solver(solver, ctx->core, &ctx->gate_manager);
8✔
5705
  if (automatic) {
8✔
5706
    smt_core_reset_thsolver(ctx->core, solver, rdl_ctrl_interface(solver),
8✔
5707
                            rdl_smt_interface(solver));
5708
  } else {
5709
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, rdl_ctrl_interface(solver),
×
5710
                  rdl_smt_interface(solver), cmode);
5711
  }
5712
  rdl_solver_init_jmpbuf(solver, &ctx->env);
8✔
5713
  ctx->arith_solver = solver;
8✔
5714
  ctx->arith = *rdl_arith_interface(solver);
8✔
5715
}
8✔
5716

5717

5718
/*
5719
 * Create an initialize the simplex solver and attach it to the core
5720
 * or to the egraph if the egraph exists.
5721
 * - if automatic is true, this is part of auto_idl or auto_rdl. So the
5722
 *   core is already initialized.
5723
 */
5724
static void create_simplex_solver(context_t *ctx, bool automatic) {
14,910✔
5725
  simplex_solver_t *solver;
5726
  smt_mode_t cmode;
5727

5728
  assert(ctx->arith_solver == NULL && ctx->core != NULL);
5729

5730
  cmode = core_mode[ctx->mode];
14,910✔
5731
  solver = (simplex_solver_t *) safe_malloc(sizeof(simplex_solver_t));
14,910✔
5732
  init_simplex_solver(solver, ctx->core, &ctx->gate_manager, ctx->egraph);
14,910✔
5733

5734
  // set simplex options
5735
  if (splx_eager_lemmas_enabled(ctx)) {
14,910✔
5736
    simplex_enable_eager_lemmas(solver);
×
5737
  }
5738
  if (splx_periodic_icheck_enabled(ctx)) {
14,910✔
5739
    simplex_enable_periodic_icheck(solver);
×
5740
  }
5741
  if (splx_eqprop_enabled(ctx)) {
14,910✔
5742
    simplex_enable_eqprop(solver);
×
5743
  }
5744

5745
  // row saving must be enabled unless we're in ONECHECK mode
5746
  if (ctx->mode != CTX_MODE_ONECHECK) {
14,910✔
5747
    simplex_enable_row_saving(solver);
14,757✔
5748
  }
5749

5750
  if (ctx->egraph != NULL) {
14,910✔
5751
    // attach the simplex solver as a satellite solver to the egraph
5752
    egraph_attach_arithsolver(ctx->egraph, solver, simplex_ctrl_interface(solver),
4,337✔
5753
                              simplex_smt_interface(solver), simplex_egraph_interface(solver),
5754
                              simplex_arith_egraph_interface(solver));
5755
  } else if (!automatic) {
10,573✔
5756
    // attach simplex to the core and initialize the core
5757
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, simplex_ctrl_interface(solver),
10,572✔
5758
                  simplex_smt_interface(solver), cmode);
5759
  } else {
5760
    // the core is already initialized: attach simplex
5761
    smt_core_reset_thsolver(ctx->core, solver, simplex_ctrl_interface(solver),
1✔
5762
                            simplex_smt_interface(solver));
5763
  }
5764

5765
  simplex_solver_init_jmpbuf(solver, &ctx->env);
14,910✔
5766
  ctx->arith_solver = solver;
14,910✔
5767
  ctx->arith = *simplex_arith_interface(solver);
14,910✔
5768
}
14,910✔
5769

5770

5771
/*
5772
 * Create IDL/SIMPLEX solver based on ctx->dl_profile
5773
 */
5774
static void create_auto_idl_solver(context_t *ctx) {
27✔
5775
  dl_data_t *profile;
5776
  int32_t bound;
5777
  double atom_density;
5778

5779
  assert(ctx->dl_profile != NULL);
5780
  profile = ctx->dl_profile;
27✔
5781

5782
  if (q_is_smallint(&profile->path_bound)) {
27✔
5783
    bound = q_get_smallint(&profile->path_bound);
26✔
5784
  } else {
5785
    bound = INT32_MAX;
1✔
5786
  }
5787

5788
  if (bound >= 1073741824) {
27✔
5789
    // simplex required because of arithmetic overflow
5790
    create_simplex_solver(ctx, true);
1✔
5791
    ctx->arch = CTX_ARCH_SPLX;
1✔
5792
  } else if (profile->num_vars >= 1000) {
26✔
5793
    // too many variables for FW
5794
    create_simplex_solver(ctx, true);
×
5795
    ctx->arch = CTX_ARCH_SPLX;
×
5796
  } else if (profile->num_vars <= 200 || profile->num_eqs == 0) {
26✔
5797
    // use FW for now, until we've tested SIMPLEX more
5798
    // 0 equalities usually means a scheduling problem
5799
    // --flatten works better on IDL/FW
5800
    create_idl_solver(ctx, true);
26✔
5801
    ctx->arch = CTX_ARCH_IFW;
26✔
5802
    enable_diseq_and_or_flattening(ctx);
26✔
5803

5804
  } else {
5805

5806
    // problem density
5807
    if (profile->num_vars > 0) {
×
5808
      atom_density = ((double) profile->num_atoms)/profile->num_vars;
×
5809
    } else {
5810
      atom_density = 0;
×
5811
    }
5812

5813
    if (atom_density >= 10.0) {
×
5814
      // high density: use FW
5815
      create_idl_solver(ctx, true);
×
5816
      ctx->arch = CTX_ARCH_IFW;
×
5817
      enable_diseq_and_or_flattening(ctx);
×
5818
    } else {
5819
      create_simplex_solver(ctx, true);
×
5820
      ctx->arch = CTX_ARCH_SPLX;
×
5821
    }
5822
  }
5823
}
27✔
5824

5825

5826
/*
5827
 * Create RDL/SIMPLEX solver based on ctx->dl_profile
5828
 */
5829
static void create_auto_rdl_solver(context_t *ctx) {
8✔
5830
  dl_data_t *profile;
5831
  double atom_density;
5832

5833
  assert(ctx->dl_profile != NULL);
5834
  profile = ctx->dl_profile;
8✔
5835

5836
  if (profile->num_vars >= 1000) {
8✔
5837
    create_simplex_solver(ctx, true);
×
5838
    ctx->arch = CTX_ARCH_SPLX;
×
5839
  } else if (profile->num_vars <= 200 || profile->num_eqs == 0) {
8✔
5840
    create_rdl_solver(ctx, true);
8✔
5841
    ctx->arch = CTX_ARCH_RFW;
8✔
5842
  } else {
5843
    // problem density
5844
    if (profile->num_vars > 0) {
×
5845
      atom_density = ((double) profile->num_atoms)/profile->num_vars;
×
5846
    } else {
5847
      atom_density = 0;
×
5848
    }
5849

5850
    if (atom_density >= 7.0) {
×
5851
      // high density: use FW
5852
      create_rdl_solver(ctx, true);
×
5853
      ctx->arch = CTX_ARCH_RFW;
×
5854
    } else {
5855
      // low-density: use SIMPLEX
5856
      create_simplex_solver(ctx, true);
×
5857
      ctx->arch = CTX_ARCH_SPLX;
×
5858
    }
5859
  }
5860
}
8✔
5861

5862

5863

5864
/*
5865
 * Create the bitvector solver
5866
 * - attach it to the egraph if there's an egraph
5867
 * - attach it to the core and initialize the core otherwise
5868
 */
5869
static void create_bv_solver(context_t *ctx) {
10,684✔
5870
  bv_solver_t *solver;
5871
  smt_mode_t cmode;
5872

5873
  assert(ctx->bv_solver == NULL && ctx->core != NULL);
5874

5875
  cmode = core_mode[ctx->mode];
10,684✔
5876
  solver = (bv_solver_t *) safe_malloc(sizeof(bv_solver_t));
10,684✔
5877
  init_bv_solver(solver, ctx->core, ctx->egraph);
10,684✔
5878

5879
  if (ctx->egraph != NULL) {
10,684✔
5880
    // attach as a satellite to the egraph
5881
    egraph_attach_bvsolver(ctx->egraph, solver, bv_solver_ctrl_interface(solver),
4,420✔
5882
                           bv_solver_smt_interface(solver), bv_solver_egraph_interface(solver),
5883
                           bv_solver_bv_egraph_interface(solver));
5884
  } else {
5885
    // attach to the core and initialize the core
5886
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, bv_solver_ctrl_interface(solver),
6,264✔
5887
                  bv_solver_smt_interface(solver), cmode);
5888
  }
5889

5890
  // EXPERIMENT
5891
  //  smt_core_make_etable(ctx->core);
5892
  // END
5893

5894
  bv_solver_init_jmpbuf(solver, &ctx->env);
10,684✔
5895
  ctx->bv_solver = solver;
10,684✔
5896
  ctx->bv = *bv_solver_bv_interface(solver);
10,684✔
5897
}
10,684✔
5898

5899

5900
/*
5901
 * Create the array/function theory solver and attach it to the egraph
5902
 */
5903
static void create_fun_solver(context_t *ctx) {
4,427✔
5904
  fun_solver_t *solver;
5905

5906
  assert(ctx->egraph != NULL && ctx->fun_solver == NULL);
5907

5908
  solver = (fun_solver_t *) safe_malloc(sizeof(fun_solver_t));
4,427✔
5909
  init_fun_solver(solver, ctx->core, &ctx->gate_manager, ctx->egraph, ctx->types);
4,427✔
5910
  egraph_attach_funsolver(ctx->egraph, solver, fun_solver_ctrl_interface(solver),
4,427✔
5911
                          fun_solver_egraph_interface(solver),
5912
                          fun_solver_fun_egraph_interface(solver));
5913

5914
  ctx->fun_solver = solver;
4,427✔
5915
}
4,427✔
5916

5917

5918
/*
5919
 * Allocate and initialize solvers based on architecture and mode
5920
 * - core and gate manager must exist at this point
5921
 * - if the architecture is either AUTO_IDL or AUTO_RDL, no theory solver
5922
 *   is allocated yet, and the core is initialized for Boolean only
5923
 * - otherwise, all components are ready and initialized, including the core.
5924
 */
5925
static void init_solvers(context_t *ctx) {
22,413✔
5926
  uint8_t solvers;
5927
  smt_core_t *core;
5928
  smt_mode_t cmode;
5929
  egraph_t *egraph;
5930

5931
  solvers = arch_components[ctx->arch];
22,413✔
5932

5933
  ctx->egraph = NULL;
22,413✔
5934
  ctx->arith_solver = NULL;
22,413✔
5935
  ctx->bv_solver = NULL;
22,413✔
5936
  ctx->fun_solver = NULL;
22,413✔
5937
  ctx->quant_solver = NULL;
22,413✔
5938
  ctx->mcsat_supplement = false;
22,413✔
5939

5940
  // Create egraph first, then satellite solvers
5941
  if (solvers & EGRPH) {
22,413✔
5942
    create_egraph(ctx);
4,794✔
5943
  }
5944

5945
  // Create mcsat
5946
  if (solvers & MCSAT) {
22,413✔
5947
    create_mcsat(ctx);
747✔
5948
  }
5949

5950
  // Arithmetic solver
5951
  if (solvers & SPLX) {
22,413✔
5952
    create_simplex_solver(ctx, false);
14,909✔
5953
  } else if (solvers & IFW) {
7,504✔
5954
    create_idl_solver(ctx, false);
×
5955
  } else if (solvers & RFW) {
7,504✔
5956
    create_rdl_solver(ctx, false);
×
5957
  }
5958

5959
  // Bitvector solver
5960
  if (solvers & BVSLVR) {
22,413✔
5961
    create_bv_solver(ctx);
10,684✔
5962
  }
5963

5964
  // Array solver
5965
  if (solvers & FSLVR) {
22,413✔
5966
    create_fun_solver(ctx);
4,427✔
5967
  }
5968

5969
  /*
5970
   * At this point all solvers are ready and initialized, except the
5971
   * egraph and core if the egraph is present or the core if there are
5972
   * no solvers, or if arch is AUTO_IDL or AUTO_RDL.
5973
   */
5974
  cmode = core_mode[ctx->mode];   // initialization mode for the core
22,413✔
5975
  egraph = ctx->egraph;
22,413✔
5976
  core = ctx->core;
22,413✔
5977
  if (egraph != NULL) {
22,413✔
5978
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, egraph, egraph_ctrl_interface(egraph),
4,794✔
5979
                  egraph_smt_interface(egraph), cmode);
5980
    egraph_attach_core(egraph, core);
4,794✔
5981

5982
  } else if (solvers == 0) {
17,619✔
5983
    /*
5984
     * Boolean solver only. If arch if AUTO_IDL or AUTO_RDL, the
5985
     * theory solver will be changed later by create_auto_idl_solver
5986
     * or create_auto_rdl_solver.
5987
     */
5988
    assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL);
5989
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, NULL, &null_ctrl, &null_smt, cmode);
36✔
5990
  } else if (solvers == MCSAT) {
17,583✔
5991
    /*
5992
     * MCsat solver only, we create the core, but never use it.
5993
     */
5994
    assert(ctx->egraph == NULL && ctx->arith_solver == NULL &&
5995
           ctx->bv_solver == NULL && ctx->fun_solver == NULL);
5996
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, NULL, &null_ctrl, &null_smt, cmode);
747✔
5997
  }
5998

5999
  /*
6000
   * Optimization: if the arch is NOSOLVERS or BV then we set bool_only in the core
6001
   */
6002
  if (ctx->arch == CTX_ARCH_NOSOLVERS || ctx->arch == CTX_ARCH_BV) {
22,413✔
6003
    smt_core_set_bool_only(core);
6,264✔
6004
  }
6005
}
22,413✔
6006

6007

6008

6009

6010
/*
6011
 * Delete the arithmetic solver
6012
 */
6013
static void delete_arith_solver(context_t *ctx) {
14,943✔
6014
  uint8_t solvers;
6015

6016
  assert(ctx->arith_solver != NULL);
6017

6018
  solvers = arch_components[ctx->arch];
14,943✔
6019
  if (solvers & IFW) {
14,943✔
6020
    delete_idl_solver(ctx->arith_solver);
26✔
6021
  } else if (solvers & RFW) {
14,917✔
6022
    delete_rdl_solver(ctx->arith_solver);
8✔
6023
  } else if (solvers & SPLX) {
14,909✔
6024
    delete_simplex_solver(ctx->arith_solver);
14,909✔
6025
  }
6026
  safe_free(ctx->arith_solver);
14,943✔
6027
  ctx->arith_solver = NULL;
14,943✔
6028
}
14,943✔
6029

6030

6031

6032

6033
/*****************************
6034
 *  CONTEXT INITIALIZATION   *
6035
 ****************************/
6036

6037
/*
6038
 * Check mode and architecture
6039
 */
6040
#ifndef NDEBUG
6041
static inline bool valid_mode(context_mode_t mode) {
6042
  return CTX_MODE_ONECHECK <= mode && mode <= CTX_MODE_INTERACTIVE;
6043
}
6044

6045
static inline bool valid_arch(context_arch_t arch) {
6046
  return CTX_ARCH_NOSOLVERS <= arch && arch <= CTX_ARCH_MCSAT;
6047
}
6048
#endif
6049

6050

6051
/*
6052
 * Initialize ctx for the given mode and architecture
6053
 * - terms = term table for that context
6054
 * - qflag = true means quantifiers allowed
6055
 * - qflag = false means no quantifiers
6056
 */
6057
void init_context(context_t *ctx, term_table_t *terms, smt_logic_t logic,
22,413✔
6058
                  context_mode_t mode, context_arch_t arch, bool qflag) {
6059
  assert(valid_mode(mode) && valid_arch(arch));
6060

6061
  /*
6062
   * Set architecture and options
6063
   */
6064
  ctx->mode = mode;
22,413✔
6065
  ctx->arch = arch;
22,413✔
6066
  ctx->logic = logic;
22,413✔
6067
  ctx->sat_delegate = SAT_DELEGATE_NONE;
22,413✔
6068
  ctx->sat_delegate_incremental_mode = SAT_DELEGATE_MODE_REBUILD;
22,413✔
6069
  ctx->sat_delegate_incremental_mode_set = false;
22,413✔
6070
  ctx->theories = arch2theories[arch];
22,413✔
6071
  ctx->options = mode2options[mode];
22,413✔
6072
  if (qflag) {
22,413✔
6073
    // quantifiers require egraph
6074
    assert((ctx->theories & UF_MASK) != 0);
6075
    ctx->theories |= QUANT_MASK;
×
6076
  }
6077

6078
  ctx->base_level = 0;
22,413✔
6079
  context_reset_sat_delegate_stats(ctx);
22,413✔
6080

6081
  /*
6082
   * The core is always needed: allocate it here. It's not initialized yet.
6083
   * The other solver are optionals.
6084
   *
6085
   * TODO: we could skip this when we use MCSAT (since then the core is
6086
   * not needed).
6087
   */
6088
  ctx->core = (smt_core_t *) safe_malloc(sizeof(smt_core_t));
22,413✔
6089
  ctx->egraph = NULL;
22,413✔
6090
  ctx->mcsat = NULL;
22,413✔
6091
  ctx->arith_solver = NULL;
22,413✔
6092
  ctx->bv_solver = NULL;
22,413✔
6093
  ctx->fun_solver = NULL;
22,413✔
6094
  ctx->quant_solver = NULL;
22,413✔
6095

6096
  /*
6097
   * Global tables + gate manager
6098
   */
6099
  ctx->types = terms->types;
22,413✔
6100
  ctx->terms = terms;
22,413✔
6101
  init_gate_manager(&ctx->gate_manager, ctx->core);
22,413✔
6102

6103
  /*
6104
   * Simplification/internalization support
6105
   */
6106
  init_intern_tbl(&ctx->intern, 0, terms);
22,413✔
6107
  init_ivector(&ctx->top_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6108
  init_ivector(&ctx->top_atoms, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6109
  init_ivector(&ctx->top_formulas, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6110
  init_ivector(&ctx->top_interns, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6111

6112
  /*
6113
   * Force the internalization mapping for true and false
6114
   * - true  term --> true_occ
6115
   * - false term --> false_occ
6116
   * This mapping holds even if there's no egraph.
6117
   */
6118
  intern_tbl_map_root(&ctx->intern, true_term, bool2code(true));
22,413✔
6119

6120
  /*
6121
   * Auxiliary internalization buffers
6122
   */
6123
  init_ivector(&ctx->subst_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6124
  init_ivector(&ctx->aux_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6125
  init_ivector(&ctx->aux_atoms, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6126
  init_ivector(&ctx->aux_vector, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6127
  init_int_queue(&ctx->queue, 0);
22,413✔
6128
  init_istack(&ctx->istack);
22,413✔
6129
  init_objstack(&ctx->ostack);
22,413✔
6130
  init_sharing_map(&ctx->sharing, &ctx->intern);
22,413✔
6131
  init_objstore(&ctx->cstore, sizeof(conditional_t), 32);
22,413✔
6132
  init_assumption_stack(&ctx->assumptions);
22,413✔
6133

6134
  ctx->subst = NULL;
22,413✔
6135
  ctx->marks = NULL;
22,413✔
6136
  ctx->cache = NULL;
22,413✔
6137
  ctx->small_cache = NULL;
22,413✔
6138
  ctx->edge_map = NULL;
22,413✔
6139
  ctx->eq_cache = NULL;
22,413✔
6140
  ctx->divmod_table = NULL;
22,413✔
6141
  ctx->explorer = NULL;
22,413✔
6142
  ctx->unsat_core_cache = NULL;
22,413✔
6143
  ctx->sat_delegate_state = NULL;
22,413✔
6144

6145
  ctx->dl_profile = NULL;
22,413✔
6146
  ctx->arith_buffer = NULL;
22,413✔
6147
  ctx->poly_buffer = NULL;
22,413✔
6148
  ctx->aux_poly = NULL;
22,413✔
6149
  ctx->aux_poly_size = 0;
22,413✔
6150

6151
  ctx->bvpoly_buffer = NULL;
22,413✔
6152

6153
  q_init(&ctx->aux);
22,413✔
6154
  init_bvconstant(&ctx->bv_buffer);
22,413✔
6155

6156
  ctx->trace = NULL;
22,413✔
6157

6158
  // mcsat options default
6159
  init_mcsat_options(&ctx->mcsat_options);
22,413✔
6160
  init_ivector(&ctx->mcsat_var_order, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6161
  init_ivector(&ctx->mcsat_initial_var_order, CTX_DEFAULT_VECTOR_SIZE);
22,413✔
6162
  /*
6163
   * Allocate and initialize the solvers and core
6164
   * NOTE: no theory solver yet if arch is AUTO_IDL or AUTO_RDL
6165
   */
6166
  init_solvers(ctx);
22,413✔
6167

6168
  ctx->en_quant = false;
22,413✔
6169
}
22,413✔
6170

6171

6172

6173

6174
/*
6175
 * Delete ctx
6176
 */
6177
void delete_context(context_t *ctx) {
22,412✔
6178
  context_sat_delegate_state_cleanup(ctx);
22,412✔
6179

6180
  if (ctx->core != NULL) {
22,412✔
6181
    delete_smt_core(ctx->core);
22,412✔
6182
    safe_free(ctx->core);
22,412✔
6183
    ctx->core = NULL;
22,412✔
6184
  }
6185

6186
  if (ctx->mcsat != NULL) {
22,412✔
6187
    mcsat_destruct(ctx->mcsat);
747✔
6188
    safe_free(ctx->mcsat);
747✔
6189
    ctx->mcsat = NULL;
747✔
6190
  }
6191

6192
  if (ctx->mcsat_supplement) {
22,412✔
6193
    context_disable_mcsat_supplement(ctx);
7✔
6194
  }
6195

6196
  if (ctx->egraph != NULL) {
22,412✔
6197
    delete_egraph(ctx->egraph);
4,793✔
6198
    safe_free(ctx->egraph);
4,793✔
6199
    ctx->egraph = NULL;
4,793✔
6200
  }
6201

6202
  if (ctx->arith_solver != NULL) {
22,412✔
6203
    delete_arith_solver(ctx);
14,943✔
6204
  }
6205

6206
  if (ctx->fun_solver != NULL) {
22,412✔
6207
    delete_fun_solver(ctx->fun_solver);
4,426✔
6208
    safe_free(ctx->fun_solver);
4,426✔
6209
    ctx->fun_solver = NULL;
4,426✔
6210
  }
6211

6212
  if (ctx->quant_solver != NULL) {
22,412✔
6213
    delete_quant_solver(ctx->quant_solver);
52✔
6214
    safe_free(ctx->quant_solver);
52✔
6215
    ctx->quant_solver = NULL;
52✔
6216
  }
6217

6218
  if (ctx->bv_solver != NULL) {
22,412✔
6219
    delete_bv_solver(ctx->bv_solver);
10,683✔
6220
    safe_free(ctx->bv_solver);
10,683✔
6221
    ctx->bv_solver = NULL;
10,683✔
6222
  }
6223

6224
  delete_gate_manager(&ctx->gate_manager);
22,412✔
6225
  /* delete_mcsat_options(&ctx->mcsat_options); // if used then the same memory is freed twice */
6226
  delete_ivector(&ctx->mcsat_var_order);
22,412✔
6227
  delete_ivector(&ctx->mcsat_initial_var_order);
22,412✔
6228

6229
  delete_intern_tbl(&ctx->intern);
22,412✔
6230
  delete_ivector(&ctx->top_eqs);
22,412✔
6231
  delete_ivector(&ctx->top_atoms);
22,412✔
6232
  delete_ivector(&ctx->top_formulas);
22,412✔
6233
  delete_ivector(&ctx->top_interns);
22,412✔
6234

6235
  delete_ivector(&ctx->subst_eqs);
22,412✔
6236
  delete_ivector(&ctx->aux_eqs);
22,412✔
6237
  delete_ivector(&ctx->aux_atoms);
22,412✔
6238
  delete_ivector(&ctx->aux_vector);
22,412✔
6239
  delete_int_queue(&ctx->queue);
22,412✔
6240
  delete_istack(&ctx->istack);
22,412✔
6241
  delete_objstack(&ctx->ostack);
22,412✔
6242
  delete_sharing_map(&ctx->sharing);
22,412✔
6243
  delete_objstore(&ctx->cstore);
22,412✔
6244
  delete_assumption_stack(&ctx->assumptions);
22,412✔
6245

6246
  context_free_subst(ctx);
22,412✔
6247
  context_free_marks(ctx);
22,412✔
6248
  context_free_cache(ctx);
22,412✔
6249
  context_free_small_cache(ctx);
22,412✔
6250
  context_free_eq_cache(ctx);
22,412✔
6251
  context_free_divmod_table(ctx);
22,412✔
6252
  context_free_explorer(ctx);
22,412✔
6253

6254
  context_free_dl_profile(ctx);
22,412✔
6255
  context_free_edge_map(ctx);
22,412✔
6256
  context_free_arith_buffer(ctx);
22,412✔
6257
  context_free_poly_buffer(ctx);
22,412✔
6258
  context_free_aux_poly(ctx);
22,412✔
6259

6260
  context_free_bvpoly_buffer(ctx);
22,412✔
6261
  context_invalidate_unsat_core_cache(ctx);
22,412✔
6262

6263
  q_clear(&ctx->aux);
22,412✔
6264
  delete_bvconstant(&ctx->bv_buffer);
22,412✔
6265
}
22,412✔
6266

6267
void context_invalidate_unsat_core_cache(context_t *ctx) {
88,221✔
6268
  if (ctx->unsat_core_cache != NULL) {
88,221✔
6269
    delete_ivector(ctx->unsat_core_cache);
2,741✔
6270
    safe_free(ctx->unsat_core_cache);
2,741✔
6271
    ctx->unsat_core_cache = NULL;
2,741✔
6272
  }
6273
}
88,221✔
6274

6275

6276

6277
/*
6278
 * Reset: remove all assertions and clear all internalization tables
6279
 */
6280
void reset_context(context_t *ctx) {
13✔
6281
  ctx->base_level = 0;
13✔
6282
  context_reset_sat_delegate_stats(ctx);
13✔
6283
  context_invalidate_unsat_core_cache(ctx);
13✔
6284
  context_sat_delegate_state_cleanup(ctx);
13✔
6285

6286
  reset_smt_core(ctx->core); // this propagates reset to all solvers
13✔
6287

6288
  if (ctx->mcsat != NULL) {
13✔
6289
    mcsat_reset(ctx->mcsat);
7✔
6290
  }
6291

6292
  reset_gate_manager(&ctx->gate_manager);
13✔
6293

6294
  ivector_reset(&ctx->mcsat_var_order);
13✔
6295
  ivector_reset(&ctx->mcsat_initial_var_order);
13✔
6296

6297
  reset_intern_tbl(&ctx->intern);
13✔
6298
  ivector_reset(&ctx->top_eqs);
13✔
6299
  ivector_reset(&ctx->top_atoms);
13✔
6300
  ivector_reset(&ctx->top_formulas);
13✔
6301
  ivector_reset(&ctx->top_interns);
13✔
6302

6303
  // Force the internalization mapping for true and false
6304
  intern_tbl_map_root(&ctx->intern, true_term, bool2code(true));
13✔
6305

6306
  ivector_reset(&ctx->subst_eqs);
13✔
6307
  ivector_reset(&ctx->aux_eqs);
13✔
6308
  ivector_reset(&ctx->aux_atoms);
13✔
6309
  ivector_reset(&ctx->aux_vector);
13✔
6310
  int_queue_reset(&ctx->queue);
13✔
6311
  reset_istack(&ctx->istack);
13✔
6312
  reset_objstack(&ctx->ostack);
13✔
6313
  reset_sharing_map(&ctx->sharing);
13✔
6314
  reset_objstore(&ctx->cstore);
13✔
6315
  reset_assumption_stack(&ctx->assumptions);
13✔
6316

6317
  context_free_subst(ctx);
13✔
6318
  context_free_marks(ctx);
13✔
6319
  context_reset_small_cache(ctx);
13✔
6320
  context_reset_eq_cache(ctx);
13✔
6321
  context_reset_divmod_table(ctx);
13✔
6322
  context_reset_explorer(ctx);
13✔
6323

6324
  context_free_arith_buffer(ctx);
13✔
6325
  context_reset_poly_buffer(ctx);
13✔
6326
  context_free_aux_poly(ctx);
13✔
6327
  context_free_dl_profile(ctx);
13✔
6328

6329
  context_free_bvpoly_buffer(ctx);
13✔
6330

6331
  q_clear(&ctx->aux);
13✔
6332
}
13✔
6333

6334

6335
/*
6336
 * Add tracer to ctx and ctx->core
6337
 */
6338
void context_set_trace(context_t *ctx, tracer_t *trace) {
285✔
6339
  assert(ctx->trace == NULL);
6340
  ctx->trace = trace;
285✔
6341
  smt_core_set_trace(ctx->core, trace);
285✔
6342
  if (ctx->mcsat != NULL) {
285✔
6343
    mcsat_set_tracer(ctx->mcsat, trace);
285✔
6344
  }
6345
  if (ctx->mcsat_supplement) {
285✔
NEW
6346
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
×
NEW
6347
    if (sat != NULL) {
×
NEW
6348
      mcsat_satellite_set_trace(sat, trace);
×
6349
    }
6350
  }
6351
}
285✔
6352

6353

6354
/*
6355
 * Push and pop
6356
 */
6357
void context_push(context_t *ctx) {
18,592✔
6358
  assert(context_supports_pushpop(ctx));
6359
  context_invalidate_unsat_core_cache(ctx);
18,592✔
6360
  smt_push(ctx->core);  // propagates to all solvers
18,592✔
6361
  if (ctx->mcsat != NULL) {
18,592✔
6362
    mcsat_push(ctx->mcsat);
1,342✔
6363
  }
6364
  intern_tbl_push(&ctx->intern);
18,592✔
6365
  assumption_stack_push(&ctx->assumptions);
18,592✔
6366
  context_eq_cache_push(ctx);
18,592✔
6367
  context_divmod_table_push(ctx);
18,592✔
6368

6369
  ctx->base_level ++;
18,592✔
6370
}
18,592✔
6371

6372
void context_pop(context_t *ctx) {
1,574✔
6373
  assert(context_supports_pushpop(ctx) && ctx->base_level > 0);
6374
  context_invalidate_unsat_core_cache(ctx);
1,574✔
6375
  smt_pop(ctx->core);   // propagates to all solvers
1,574✔
6376
  if (ctx->mcsat != NULL) {
1,574✔
6377
    mcsat_pop(ctx->mcsat);
1,258✔
6378
  }
6379
  intern_tbl_pop(&ctx->intern);
1,574✔
6380
  assumption_stack_pop(&ctx->assumptions);
1,574✔
6381
  context_eq_cache_pop(ctx);
1,574✔
6382
  context_divmod_table_pop(ctx);
1,574✔
6383

6384
  context_sat_delegate_state_pop(ctx, ctx->base_level);
1,574✔
6385

6386
  ctx->base_level --;
1,574✔
6387
}
1,574✔
6388

6389

6390

6391

6392

6393
/****************************
6394
 *   ASSERTIONS AND CHECK   *
6395
 ***************************/
6396

6397
/*
6398
 * Build the sharing data
6399
 * - processes all the assertions in vectors top_eqs, top_atoms, top_formulas
6400
 * - this function should be called after building the substitutions
6401
 */
6402
static void context_build_sharing_data(context_t *ctx) {
71,964✔
6403
  sharing_map_t *map;
6404

6405
  map = &ctx->sharing;
71,964✔
6406
  reset_sharing_map(map);
71,964✔
6407
  sharing_map_add_terms(map, ctx->top_eqs.data, ctx->top_eqs.size);
71,964✔
6408
  sharing_map_add_terms(map, ctx->top_atoms.data, ctx->top_atoms.size);
71,964✔
6409
  sharing_map_add_terms(map, ctx->top_formulas.data, ctx->top_formulas.size);
71,964✔
6410
}
71,964✔
6411

6412

6413
#if 0
6414
/*
6415
 * PROVISIONAL: SHOW ASSERTIONS
6416
 */
6417
static void context_show_assertions(const context_t *ctx, uint32_t n, const term_t *a) {
6418
  pp_area_t area;
6419
  yices_pp_t printer;
6420
  uint32_t i;
6421

6422
  area.width = 80;
6423
  area.height = UINT32_MAX;
6424
  area.offset = 0;
6425
  area.stretch = false;
6426
  area.truncate = false;
6427
  init_yices_pp(&printer, stdout, &area, PP_VMODE, 0);
6428

6429
  for (i=0; i<n; i++) {
6430
    pp_term_full(&printer, ctx->terms, a[i]);
6431
    flush_yices_pp(&printer);
6432
  }
6433
  delete_yices_pp(&printer, true);
6434
}
6435
#endif
6436

6437
/*
6438
 * Flatten and internalize assertions a[0 ... n-1]
6439
 * - all elements a[i] must be valid boolean term in ctx->terms
6440
 * - return code:
6441
 *   TRIVIALLY_UNSAT if there's an easy contradiction
6442
 *   CTX_NO_ERROR if the assertions were processed without error
6443
 *   a negative error code otherwise.
6444
 */
6445
static int32_t context_process_assertions(context_t *ctx, uint32_t n, const term_t *a) {
74,780✔
6446
  ivector_t *v;
6447
  uint32_t i;
6448
  int code;
6449

6450
  ivector_reset(&ctx->top_eqs);
74,780✔
6451
  ivector_reset(&ctx->top_atoms);
74,780✔
6452
  ivector_reset(&ctx->top_formulas);
74,780✔
6453
  ivector_reset(&ctx->top_interns);
74,780✔
6454
  ivector_reset(&ctx->subst_eqs);
74,780✔
6455
  ivector_reset(&ctx->aux_eqs);
74,780✔
6456
  ivector_reset(&ctx->aux_atoms);
74,780✔
6457

6458
  code = setjmp(ctx->env);
74,780✔
6459
  if (code == 0) {
75,178✔
6460

6461
    // If using MCSAT, just check and done
6462
    if (ctx->mcsat != NULL) {
74,780✔
6463
      // TBD: quant support
6464
      assert(!context_quant_enabled(ctx));
6465
      code = mcsat_assert_formulas(ctx->mcsat, n, a);
2,444✔
6466
      goto done;
2,433✔
6467
    }
6468

6469
#if 0
6470
    printf("\n=== Context: process assertions ===\n");
6471
    context_show_assertions(ctx, n, a);
6472
    printf("===\n\n");
6473
#endif
6474

6475
    // flatten
6476
    for (i=0; i<n; i++) {
195,751✔
6477
      flatten_assertion(ctx, a[i]);
123,786✔
6478
    }
6479

6480
    trace_printf(ctx->trace, 6, "(done flattening)\n");
71,965✔
6481

6482
    /*
6483
     * At this point, the assertions are stored into the vectors
6484
     * top_eqs, top_atoms, top_formulas, and top_interns
6485
     * - more top-level equalities may be in subst_eqs
6486
     * - ctx->intern stores the internalized terms and the variable
6487
     *   substitutions.
6488
     */
6489

6490
    switch (ctx->arch) {
71,965✔
6491
    // TBD: make sure following preprocessings work with quant enabled
6492
    case CTX_ARCH_EG:
3,329✔
6493
      /*
6494
       * UF problem: we must process subst_eqs last since the
6495
       * preprocessing may add new equalities in aux_eqs that may end
6496
       * up in subst_eqs after the call to process_aux_eqs.
6497
       */
6498
      if (context_breaksym_enabled(ctx)) {
3,329✔
6499
        break_uf_symmetries(ctx);
30✔
6500
      }
6501
      if (context_eq_abstraction_enabled(ctx)) {
3,329✔
6502
        analyze_uf(ctx);
64✔
6503
      }
6504
      if (ctx->aux_eqs.size > 0) {
3,329✔
6505
        process_aux_eqs(ctx);
6✔
6506
      }
6507
      if (ctx->subst_eqs.size > 0) {
3,328✔
6508
        context_process_candidate_subst(ctx);
10✔
6509
      }
6510
      break;
3,328✔
6511

6512
    case CTX_ARCH_AUTO_IDL:
27✔
6513
      /*
6514
       * For difference logic, we must process the subst_eqs first
6515
       * (otherwise analyze_diff_logic may give wrong results).
6516
       */
6517
      if (ctx->subst_eqs.size > 0) {
27✔
6518
        context_process_candidate_subst(ctx);
×
6519
      }
6520
      analyze_diff_logic(ctx, true);
27✔
6521
      create_auto_idl_solver(ctx);
27✔
6522
      break;
27✔
6523

6524
    case CTX_ARCH_AUTO_RDL:
8✔
6525
      /*
6526
       * Difference logic, we must process the subst_eqs first
6527
       */
6528
      trace_printf(ctx->trace, 6, "(auto-idl solver)\n");
8✔
6529
      if (ctx->subst_eqs.size > 0) {
8✔
6530
        context_process_candidate_subst(ctx);
×
6531
      }
6532
      analyze_diff_logic(ctx, false);
8✔
6533
      create_auto_rdl_solver(ctx);
8✔
6534
      break;
8✔
6535

6536
    case CTX_ARCH_SPLX:
30,674✔
6537
      /*
6538
       * Simplex, like EG, may add aux_atoms so we must process
6539
       * subst_eqs last here.
6540
       */
6541
      trace_printf(ctx->trace, 6, "(Simplex solver)\n");
30,674✔
6542
      // more optional processing
6543
      if (context_cond_def_preprocessing_enabled(ctx)) {
30,674✔
6544
        process_conditional_definitions(ctx);
52✔
6545
        if (ctx->aux_eqs.size > 0) {
52✔
6546
          process_aux_eqs(ctx);
2✔
6547
        }
6548
        if (ctx->aux_atoms.size > 0) {
52✔
6549
          process_aux_atoms(ctx);
3✔
6550
        }
6551
      }
6552
      if (ctx->subst_eqs.size > 0) {
30,674✔
6553
        context_process_candidate_subst(ctx);
16✔
6554
      }
6555
      break;
30,674✔
6556

6557
    default:
37,927✔
6558
      /*
6559
       * Process the candidate variable substitutions if any
6560
       */
6561
      if (ctx->subst_eqs.size > 0) {
37,927✔
6562
        context_process_candidate_subst(ctx);
2,749✔
6563
      }
6564
      break;
37,927✔
6565
    }
6566

6567
    /*
6568
     * Sharing
6569
     */
6570
    context_build_sharing_data(ctx);
71,964✔
6571

6572
    /*
6573
     * Notify the core + solver(s)
6574
     */
6575
    if (!context_quant_enabled(ctx)) {
71,964✔
6576
        // TBD: make sure this is correct
6577
      internalization_start(ctx->core);
69,431✔
6578
    }
6579

6580
    /*
6581
     * Assert top_eqs, top_atoms, top_formulas, top_interns
6582
     */
6583
    code = CTX_NO_ERROR;
71,964✔
6584

6585
    // first: all terms that are already internalized
6586
    v = &ctx->top_interns;
71,964✔
6587
    n = v->size;
71,964✔
6588
    if (n > 0) {
71,964✔
6589
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" existing terms)\n", n);
284✔
6590
      i = 0;
284✔
6591
      do {
6592
        assert_toplevel_intern(ctx, v->data[i]);
739✔
6593
        i ++;
739✔
6594
      } while (i < n);
739✔
6595

6596
      // one round of propagation
6597
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
284✔
6598
        code = TRIVIALLY_UNSAT;
11✔
6599
        goto done;
11✔
6600
      }
6601
    }
6602

6603
    // second: all top-level equalities
6604
    v = &ctx->top_eqs;
71,953✔
6605
    n = v->size;
71,953✔
6606
    if (n > 0) {
71,953✔
6607
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level equalities)\n", n);
6,776✔
6608
      i = 0;
6,776✔
6609
      do {
6610
        assert_toplevel_formula(ctx, v->data[i]);
10,838✔
6611
        i ++;
10,834✔
6612
      } while (i < n);
10,834✔
6613

6614
      // one round of propagation
6615
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
6,772✔
6616
        code = TRIVIALLY_UNSAT;
69✔
6617
        goto done;
69✔
6618
      }
6619
    }
6620

6621
    // third: all top-level atoms (other than equalities)
6622
    v = &ctx->top_atoms;
71,880✔
6623
    n = v->size;
71,880✔
6624
    if (n > 0) {
71,880✔
6625
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level atoms)\n", n);
15,578✔
6626
      i = 0;
15,578✔
6627
      do {
6628
        assert_toplevel_formula(ctx, v->data[i]);
68,864✔
6629
        i ++;
68,853✔
6630
      } while (i < n);
68,853✔
6631

6632
      // one round of propagation
6633
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
15,567✔
6634
        code = TRIVIALLY_UNSAT;
76✔
6635
        goto done;
76✔
6636
      }
6637
    }
6638

6639
    // last: all non-atomic, formulas
6640
    v =  &ctx->top_formulas;
71,793✔
6641
    n = v->size;
71,793✔
6642
    if (n > 0) {
71,793✔
6643
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level formulas)\n", n);
22,021✔
6644
      i = 0;
22,021✔
6645
      do {
6646
        assert_toplevel_formula(ctx, v->data[i]);
45,747✔
6647
        i ++;
45,747✔
6648
      } while (i < n);
45,747✔
6649

6650
      // one round of propagation
6651
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
22,021✔
6652
        code = TRIVIALLY_UNSAT;
63✔
6653
        goto done;
63✔
6654
      }
6655
    }
6656

6657
  } else {
6658
    /*
6659
     * Exception: return from longjmp(ctx->env, code);
6660
     */
6661
    ivector_reset(&ctx->aux_vector);
398✔
6662
    reset_istack(&ctx->istack);
398✔
6663
    reset_objstack(&ctx->ostack);
398✔
6664
    int_queue_reset(&ctx->queue);
398✔
6665
    context_free_subst(ctx);
398✔
6666
    context_free_marks(ctx);
398✔
6667
  }
6668

6669
 done:
74,780✔
6670
  return code;
74,780✔
6671
}
6672

6673
/*
6674
 * Assert all formulas f[0] ... f[n-1]
6675
 * The context status must be IDLE.
6676
 *
6677
 * Return code:
6678
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
6679
 *   (in that case the context status is set to UNSAT)
6680
 * - CTX_NO_ERROR means no internalization error and status not
6681
 *   determined
6682
 * - otherwise, the code is negative to report an error.
6683
 */
6684
int32_t _o_assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
72,246✔
6685
  int32_t code;
6686

6687
  assert(ctx->arch == CTX_ARCH_AUTO_IDL ||
6688
         ctx->arch == CTX_ARCH_AUTO_RDL ||
6689
         smt_status(ctx->core) == YICES_STATUS_IDLE);
6690
  assert(!context_quant_enabled(ctx));
6691

6692
  code = context_process_assertions(ctx, n, f);
72,246✔
6693
  if (code == TRIVIALLY_UNSAT) {
72,246✔
6694
    if (ctx->arch == CTX_ARCH_AUTO_IDL || ctx->arch == CTX_ARCH_AUTO_RDL) {
598✔
6695
      // cleanup: reset arch/config to 'no theory'
6696
      assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL &&
6697
             ctx->mode == CTX_MODE_ONECHECK);
6698
      ctx->arch = CTX_ARCH_NOSOLVERS;
1✔
6699
      ctx->theories = 0;
1✔
6700
      ctx->options = 0;
1✔
6701
    }
6702

6703
    if( smt_status(ctx->core) != YICES_STATUS_UNSAT) {
598✔
6704
      // force UNSAT in the core
6705
      add_empty_clause(ctx->core);
379✔
6706
      ctx->core->status = YICES_STATUS_UNSAT;
379✔
6707
    }
6708
  }
6709

6710
  return code;
72,246✔
6711
}
6712

6713
/*
6714
 * Assert all formulas f[0] ... f[n-1] during quantifier instantiation
6715
 * The context status must be SEARCHING.
6716
 *
6717
 * Return code:
6718
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
6719
 *   (in that case the context status is set to UNSAT)
6720
 * - CTX_NO_ERROR means no internalization error and status not
6721
 *   determined
6722
 * - otherwise, the code is negative to report an error.
6723
 */
6724
int32_t quant_assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
2,534✔
6725
  int32_t code;
6726

6727
  assert(context_quant_enabled(ctx));
6728
  assert(smt_status(ctx->core) == YICES_STATUS_SEARCHING);
6729

6730
  code = context_process_assertions(ctx, n, f);
2,534✔
6731
  if (code == TRIVIALLY_UNSAT) {
2,534✔
6732
    if (ctx->arch == CTX_ARCH_AUTO_IDL || ctx->arch == CTX_ARCH_AUTO_RDL) {
1✔
6733
      // cleanup: reset arch/config to 'no theory'
6734
      assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL &&
6735
      ctx->mode == CTX_MODE_ONECHECK);
6736
      ctx->arch = CTX_ARCH_NOSOLVERS;
×
6737
      ctx->theories = 0;
×
6738
      ctx->options = 0;
×
6739
    }
6740

6741
    if( smt_status(ctx->core) != YICES_STATUS_UNSAT) {
1✔
6742
      // force UNSAT in the core
6743
      add_empty_clause(ctx->core);
1✔
6744
      ctx->core->status = YICES_STATUS_UNSAT;
1✔
6745
    }
6746
  }
6747

6748
  return code;
2,534✔
6749
}
6750

6751
int32_t assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
18,470✔
6752
  MT_PROTECT(int32_t, __yices_globals.lock, _o_assert_formulas(ctx, n, f));
18,470✔
6753
}
6754

6755

6756

6757

6758
/*
6759
 * Assert a boolean formula f.
6760
 *
6761
 * The context status must be IDLE.
6762
 *
6763
 * Return code:
6764
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
6765
 *   (in that case the context status is set to UNSAT)
6766
 * - CTX_NO_ERROR means no internalization error and status not
6767
 *   determined
6768
 * - otherwise, the code is negative. The assertion could
6769
 *   not be processed.
6770
 */
6771
int32_t _o_assert_formula(context_t *ctx, term_t f) {
53,776✔
6772
  return _o_assert_formulas(ctx, 1, &f);
53,776✔
6773
}
6774

6775
int32_t assert_formula(context_t *ctx, term_t f) {
49,307✔
6776
  MT_PROTECT(int32_t, __yices_globals.lock, _o_assert_formula(ctx, f));
49,307✔
6777
}
6778

6779

6780
/*
6781
 * Convert boolean term t to a literal l in context ctx
6782
 * - t must be a boolean term
6783
 * - return a negative code if there's an error
6784
 * - return a literal (l >= 0) otherwise.
6785
 */
6786
int32_t context_internalize(context_t *ctx, term_t t) {
87,725✔
6787
  int code;
6788
  literal_t l;
6789

6790
  ivector_reset(&ctx->top_eqs);
87,725✔
6791
  ivector_reset(&ctx->top_atoms);
87,725✔
6792
  ivector_reset(&ctx->top_formulas);
87,725✔
6793
  ivector_reset(&ctx->top_interns);
87,725✔
6794
  ivector_reset(&ctx->subst_eqs);
87,725✔
6795
  ivector_reset(&ctx->aux_eqs);
87,725✔
6796

6797
  code = setjmp(ctx->env);
87,725✔
6798
  if (code == 0) {
87,725✔
6799
    // we must call internalization start first
6800
    if (!context_quant_enabled(ctx)) {
87,725✔
6801
      // TBD: make sure this is correct
6802
      internalization_start(ctx->core);
87,621✔
6803
    }
6804
    l = internalize_to_literal(ctx, t);
87,725✔
6805
  } else {
6806
    assert(code < 0);
6807
    /*
6808
     * Clean up
6809
     */
6810
    ivector_reset(&ctx->aux_vector);
×
6811
    reset_istack(&ctx->istack);
×
6812
    int_queue_reset(&ctx->queue);
×
6813
    context_free_subst(ctx);
×
6814
    context_free_marks(ctx);
×
6815
    l = code;
×
6816
  }
6817

6818
  return l;
87,725✔
6819
}
6820

6821

6822
/*
6823
 * Build an assumption for Boolean term t:
6824
 * - this converts t to a literal l in context ctx
6825
 *   then create an indicator variable x in the core
6826
 *   and add the clause (x => l) in the core.
6827
 * - return a negative code if t can't be internalized
6828
 * - return the literal x otherwise (where x>=0).
6829
 */
6830
int32_t context_add_assumption(context_t *ctx, term_t t) {
87,630✔
6831
  int32_t l, x;
6832

6833
  // check if we already have an assumption literal for t
6834
  x = assumption_literal_for_term(&ctx->assumptions, t);
87,630✔
6835
  if (x < 0) {
87,630✔
6836
    l = context_internalize(ctx, t);
87,621✔
6837
    if (l < 0) return l; // error code
87,621✔
6838

6839
    x = pos_lit(create_boolean_variable(ctx->core));
87,621✔
6840
    add_binary_clause(ctx->core, not(x), l); // clause (x implies l)
87,621✔
6841

6842
    assumption_stack_add(&ctx->assumptions, t, x);
87,621✔
6843
  }
6844

6845
  return x;
87,630✔
6846
}
6847

6848

6849

6850
/*
6851
 * PROVISIONAL: FOR TESTING/DEBUGGING
6852
 */
6853

6854
/*
6855
 * Preprocess formula f or array of formulas f[0 ... n-1]
6856
 * - this does flattening + build substitutions
6857
 * - return code: as in assert_formulas
6858
 * - the result is stored in the internal vectors
6859
 *     ctx->top_interns
6860
 *     ctx->top_eqs
6861
 *     ctx->top_atoms
6862
 *     ctx->top_formulas
6863
 *   + ctx->intern stores substitutions
6864
 */
6865
int32_t context_process_formulas(context_t *ctx, uint32_t n, term_t *f) {
×
6866
  uint32_t i;
6867
  int code;
6868

6869
  ivector_reset(&ctx->top_eqs);
×
6870
  ivector_reset(&ctx->top_atoms);
×
6871
  ivector_reset(&ctx->top_formulas);
×
6872
  ivector_reset(&ctx->top_interns);
×
6873
  ivector_reset(&ctx->subst_eqs);
×
6874
  ivector_reset(&ctx->aux_eqs);
×
6875
  ivector_reset(&ctx->aux_atoms);
×
6876

6877
  code = setjmp(ctx->env);
×
6878
  if (code == 0) {
×
6879
    // flatten
6880
    for (i=0; i<n; i++) {
×
6881
      flatten_assertion(ctx, f[i]);
×
6882
    }
6883

6884
    /*
6885
     * At this point, the assertions are stored into the vectors
6886
     * top_eqs, top_atoms, top_formulas, and top_interns
6887
     * - more top-level equalities may be in subst_eqs
6888
     * - ctx->intern stores the internalized terms and the variable
6889
     *   substitutions.
6890
     */
6891

6892
    switch (ctx->arch) {
×
6893
    case CTX_ARCH_EG:
×
6894
      /*
6895
       * UF problem: we must process subst_eqs last since the
6896
       * preprocessing may add new equalities in aux_eqs that may end
6897
       * up in subst_eqs after the call to process_aux_eqs.
6898
       */
6899
      if (context_breaksym_enabled(ctx)) {
×
6900
        break_uf_symmetries(ctx);
×
6901
      }
6902
      if (context_eq_abstraction_enabled(ctx)) {
×
6903
        analyze_uf(ctx);
×
6904
      }
6905
      if (ctx->aux_eqs.size > 0) {
×
6906
        process_aux_eqs(ctx);
×
6907
      }
6908
      if (ctx->subst_eqs.size > 0) {
×
6909
        context_process_candidate_subst(ctx);
×
6910
      }
6911
      break;
×
6912

6913
    case CTX_ARCH_AUTO_IDL:
×
6914
      /*
6915
       * For difference logic, we must process the subst_eqs first
6916
       * (otherwise analyze_diff_logic may give wrong results).
6917
       */
6918
      if (ctx->subst_eqs.size > 0) {
×
6919
        context_process_candidate_subst(ctx);
×
6920
      }
6921
      analyze_diff_logic(ctx, true);
×
6922
      create_auto_idl_solver(ctx);
×
6923
      break;
×
6924

6925
    case CTX_ARCH_AUTO_RDL:
×
6926
      /*
6927
       * Difference logic, we must process the subst_eqs first
6928
       */
6929
      if (ctx->subst_eqs.size > 0) {
×
6930
        context_process_candidate_subst(ctx);
×
6931
      }
6932
      analyze_diff_logic(ctx, false);
×
6933
      create_auto_rdl_solver(ctx);
×
6934
      break;
×
6935

6936
    case CTX_ARCH_SPLX:
×
6937
      /*
6938
       * Simplex, like EG, may add aux_atoms so we must process
6939
       * subst_eqs last here.
6940
       */
6941
      // more optional processing
6942
      if (context_cond_def_preprocessing_enabled(ctx)) {
×
6943
        process_conditional_definitions(ctx);
×
6944
        if (ctx->aux_eqs.size > 0) {
×
6945
          process_aux_eqs(ctx);
×
6946
        }
6947
        if (ctx->aux_atoms.size > 0) {
×
6948
          process_aux_atoms(ctx);
×
6949
        }
6950
      }
6951
      if (ctx->subst_eqs.size > 0) {
×
6952
        context_process_candidate_subst(ctx);
×
6953
      }
6954
      break;
×
6955

6956
    default:
×
6957
      /*
6958
       * Process the candidate variable substitutions if any
6959
       */
6960
      if (ctx->subst_eqs.size > 0) {
×
6961
        context_process_candidate_subst(ctx);
×
6962
      }
6963
      break;
×
6964
    }
6965

6966
    /*
6967
     * Sharing
6968
     */
6969
    context_build_sharing_data(ctx);
×
6970

6971
    code = CTX_NO_ERROR;
×
6972

6973
  } else {
6974
    /*
6975
     * Exception: return from longjmp(ctx->env, code);
6976
     */
6977
    ivector_reset(&ctx->aux_vector);
×
6978
    reset_istack(&ctx->istack);
×
6979
    int_queue_reset(&ctx->queue);
×
6980
    context_free_subst(ctx);
×
6981
    context_free_marks(ctx);
×
6982
  }
6983

6984
  return code;
×
6985
}
6986

6987
int32_t context_process_formula(context_t *ctx, term_t f) {
×
6988
  return context_process_formulas(ctx, 1, &f);
×
6989
}
6990

6991

6992

6993
/*
6994
 * The search function 'check_context' is defined in context_solver.c
6995
 */
6996

6997

6998
/*
6999
 * Interrupt the search.
7000
 */
7001
void context_stop_search(context_t *ctx) {
3✔
7002
  if (ctx->mcsat == NULL) {
3✔
7003
    stop_search(ctx->core);
3✔
7004
    if (context_has_simplex_solver(ctx)) {
3✔
7005
      simplex_stop_search(ctx->arith_solver);
3✔
7006
    }
7007
  } else {
7008
    mcsat_stop_search(ctx->mcsat);
×
7009
  }
7010
}
3✔
7011

7012

7013

7014
/*
7015
 * Cleanup: restore ctx to a good state after check_context
7016
 * is interrupted.
7017
 */
7018
void context_cleanup(context_t *ctx) {
1✔
7019
  // restore the state to IDLE, propagate to all solvers (via pop)
7020
  assert(context_supports_cleaninterrupt(ctx));
7021
  context_invalidate_unsat_core_cache(ctx);
1✔
7022
  if (ctx->mcsat == NULL) {
1✔
7023
    smt_cleanup(ctx->core);
1✔
7024
  } else {
7025
    mcsat_clear(ctx->mcsat);
×
7026
  }
7027
}
1✔
7028

7029

7030

7031
/*
7032
 * Clear: prepare for more assertions and checks
7033
 * - free the boolean assignment
7034
 * - reset the status to IDLE
7035
 */
7036
void context_clear(context_t *ctx) {
42,255✔
7037
  assert(context_supports_multichecks(ctx));
7038
  context_invalidate_unsat_core_cache(ctx);
42,255✔
7039
  if (ctx->mcsat == NULL) {
42,255✔
7040
    smt_clear(ctx->core);
41,894✔
7041
  } else {
7042
    mcsat_clear(ctx->mcsat);
361✔
7043
  }
7044
}
42,255✔
7045

7046

7047

7048
/*
7049
 * Clear_unsat: prepare for pop if the status is UNSAT
7050
 * - remove assumptions if any
7051
 *
7052
 * - if clean interrupt is enabled, then there may be a mismatch between
7053
 *   the context's base_level and the core base_level.
7054
 * - it's possible to have ctx->core.base_level = ctx->base_level + 1
7055
 * - this happens because start_search in smt_core does an internal smt_push
7056
 *   to allow the core to be restored to a clean state if search is interrupted.
7057
 * - if search is not interrupted and the search returns UNSAT, then we're
7058
 *   in a state with core base level = context base level + 1.
7059
 */
7060
void context_clear_unsat(context_t *ctx) {
655✔
7061
  context_invalidate_unsat_core_cache(ctx);
655✔
7062
  if (ctx->mcsat == NULL) {
655✔
7063
    smt_clear_unsat(ctx->core);
419✔
7064
    assert(smt_base_level(ctx->core) == ctx->base_level);
7065
  } else {
7066
    mcsat_clear(ctx->mcsat);
236✔
7067
  }
7068
}
655✔
7069

7070

7071

7072
/*
7073
 * Add the blocking clause to ctx
7074
 * - ctx->status must be either SAT or UNKNOWN
7075
 * - this collects all decision literals in the current truth assignment
7076
 *   (say l_1, ..., l_k) then clears the current assignment and adds the
7077
 *  clause ((not l_1) \/ ... \/ (not l_k)).
7078
 *
7079
 * Return code:
7080
 * - TRIVIALLY_UNSAT: means that the blocking clause is empty (i.e., k = 0)
7081
 *   (in that case, the context status is set to UNSAT)
7082
 * - CTX_NO_ERROR: means that the blocking clause is not empty (i.e., k > 0)
7083
 *   (In this case, the context status is set to IDLE)
7084
 */
7085
int32_t assert_blocking_clause(context_t *ctx) {
24,855✔
7086
  ivector_t *v;
7087
  uint32_t i, n;
7088
  int32_t code;
7089

7090
  assert(smt_status(ctx->core) == YICES_STATUS_SAT ||
7091
         smt_status(ctx->core) == YICES_STATUS_UNKNOWN);
7092

7093
  // get decision literals and build the blocking clause
7094
  v = &ctx->aux_vector;
24,855✔
7095
  assert(v->size == 0);
7096
  collect_decision_literals(ctx->core, v);
24,855✔
7097
  n = v->size;
24,855✔
7098
  for (i=0; i<n; i++) {
36,264✔
7099
    v->data[i] = not(v->data[i]);
11,409✔
7100
  }
7101

7102
  // prepare for the new assertion + notify solvers of a new assertion
7103
  context_clear(ctx);
24,855✔
7104
  internalization_start(ctx->core);
24,855✔
7105

7106
  // add the blocking clause
7107
  add_clause(ctx->core, n, v->data);
24,855✔
7108
  ivector_reset(v);
24,855✔
7109

7110
  // force UNSAT if n = 0
7111
  code = CTX_NO_ERROR;
24,855✔
7112
  if (n == 0) {
24,855✔
7113
    code = TRIVIALLY_UNSAT;
16,817✔
7114
    ctx->core->status = YICES_STATUS_UNSAT;
16,817✔
7115
  }
7116

7117
  assert(n == 0 || smt_status(ctx->core) == YICES_STATUS_IDLE);
7118

7119
  return code;
24,855✔
7120
}
7121

7122

7123

7124

7125
/********************************
7126
 *  GARBAGE COLLECTION SUPPORT  *
7127
 *******************************/
7128

7129
/*
7130
 * Marker for all terms present in the eq_map
7131
 * - aux = the relevant term table.
7132
 * - each record p stores <k0, k1, val> where k0 and k1 are both
7133
 *   terms in aux and val is a literal in the core
7134
 */
7135
static void ctx_mark_eq(void *aux, const pmap2_rec_t *p) {
×
7136
  term_table_set_gc_mark(aux, index_of(p->k0));
×
7137
  term_table_set_gc_mark(aux, index_of(p->k1));
×
7138
}
×
7139

7140

7141
/*
7142
 * Go through all data structures in ctx and mark all terms and types
7143
 * that they use.
7144
 */
7145
void context_gc_mark(context_t *ctx) {
12✔
7146
  if (ctx->egraph != NULL) {
12✔
7147
    egraph_gc_mark(ctx->egraph);
1✔
7148
  }
7149
  if (ctx->fun_solver != NULL) {
12✔
7150
    fun_solver_gc_mark(ctx->fun_solver);
1✔
7151
  }
7152

7153
  intern_tbl_gc_mark(&ctx->intern);
12✔
7154

7155
  // empty all the term vectors to be safe
7156
  ivector_reset(&ctx->top_eqs);
12✔
7157
  ivector_reset(&ctx->top_atoms);
12✔
7158
  ivector_reset(&ctx->top_formulas);
12✔
7159
  ivector_reset(&ctx->top_interns);
12✔
7160
  ivector_reset(&ctx->subst_eqs);
12✔
7161
  ivector_reset(&ctx->aux_eqs);
12✔
7162

7163
  if (ctx->eq_cache != NULL) {
12✔
7164
    pmap2_iterate(ctx->eq_cache, ctx->terms, ctx_mark_eq);
×
7165
  }
7166

7167
  if (ctx->unsat_core_cache != NULL) {
12✔
7168
    uint32_t i, n;
7169
    n = ctx->unsat_core_cache->size;
×
7170
    for (i=0; i<n; i++) {
×
7171
      term_table_set_gc_mark(ctx->terms, index_of(ctx->unsat_core_cache->data[i]));
×
7172
    }
7173
  }
7174

7175
  if (ctx->mcsat != NULL) {
12✔
7176
    mcsat_gc_mark(ctx->mcsat);
11✔
7177
  }
7178
  if (ctx->mcsat_supplement) {
12✔
NEW
7179
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
×
NEW
7180
    if (sat != NULL) {
×
NEW
7181
      mcsat_satellite_gc_mark(sat);
×
7182
    }
7183
  }
7184
}
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