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

SRI-CSL / yices2 / 26465582027

26 May 2026 05:54PM UTC coverage: 68.878% (+0.09%) from 68.786%
26465582027

Pull #611

github

web-flow
Merge branch 'master' into mcsat-supplement-cdclt
Pull Request #611: Wrap MCSAT as a Nelson-Oppen theory solver in CDCL(T) architecture

914 of 1365 new or added lines in 17 files covered. (66.96%)

2 existing lines in 2 files now uncovered.

88499 of 128486 relevant lines covered (68.88%)

1606903.79 hits per line

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

79.17
/src/context/context.c
1
/*
2
 * This file is part of the Yices SMT Solver.
3
 * Copyright (C) 2017 SRI International.
4
 *
5
 * Yices is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * Yices is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
/*
20
 * ASSERTION CONTEXT
21
 */
22

23
#include <inttypes.h>
24

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

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

50
#include "api/yices_globals.h"
51

52
#define TRACE 0
53

54
#if TRACE
55

56
#include <stdio.h>
57

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

61
#endif
62

63

64

65

66

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

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

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

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

95

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

327
  return CTX_NO_ERROR;
9✔
328
}
329

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

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

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

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

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

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

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

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

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

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

415
  return trigger;
33✔
416
}
417

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

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

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

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

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

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

446
  manager = ctx->mcsat_relax_manager;
19✔
447
  if (manager == NULL) {
19✔
448
    /*
449
     * Use a private manager over the shared term table so relaxation rewrites
450
     * do not reuse in-flight arithmetic buffers from the main internalizer.
451
     */
452
    manager = (term_manager_t *) safe_malloc(sizeof(term_manager_t));
8✔
453
    init_term_manager(manager, ctx->terms);
8✔
454
    ctx->mcsat_relax_manager = manager;
8✔
455
  }
456
  return manager;
19✔
457
}
458

459
static int_hmap_t *context_get_mcsat_relax_abstractions(context_t *ctx) {
16✔
460
  int_hmap_t *map;
461

462
  map = ctx->mcsat_relax_abstractions;
16✔
463
  if (map == NULL) {
16✔
464
    map = (int_hmap_t *) safe_malloc(sizeof(int_hmap_t));
7✔
465
    init_int_hmap(map, 0);
7✔
466
    ctx->mcsat_relax_abstractions = map;
7✔
467
  }
468
  return map;
16✔
469
}
470

471
static int_hset_t *context_get_mcsat_relax_abstraction_terms(context_t *ctx) {
13✔
472
  int_hset_t *set;
473

474
  set = ctx->mcsat_relax_abstraction_terms;
13✔
475
  if (set == NULL) {
13✔
476
    set = (int_hset_t *) safe_malloc(sizeof(int_hset_t));
7✔
477
    init_int_hset(set, 0);
7✔
478
    ctx->mcsat_relax_abstraction_terms = set;
7✔
479
  }
480
  return set;
13✔
481
}
482

483
static bool context_is_mcsat_relax_abstraction(context_t *ctx, term_t t) {
21✔
484
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
21✔
485
  return ctx->mcsat_relax_abstraction_terms != NULL &&
41✔
486
    int_hset_member(ctx->mcsat_relax_abstraction_terms, t);
20✔
487
}
488

NEW
489
static bool term_requires_mcsat_supplement_uncached(context_t *ctx, term_t t) {
×
490
  int_hmap_t cache;
491
  bool trigger;
492

NEW
493
  init_int_hmap(&cache, 0);
×
NEW
494
  trigger = term_requires_mcsat_supplement(ctx, t, &cache);
×
NEW
495
  delete_int_hmap(&cache);
×
496

NEW
497
  return trigger;
×
498
}
499

NEW
500
static bool arith_const_is_zero(context_t *ctx, term_t t) {
×
NEW
501
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
×
NEW
502
  return term_kind(ctx->terms, t) == ARITH_CONSTANT &&
×
NEW
503
    q_is_zero(rational_term_desc(ctx->terms, t));
×
504
}
505

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

522
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
16✔
523
  p = int_hmap_get(context_get_mcsat_relax_abstractions(ctx), t);
16✔
524
  if (p->val < 0) {
16✔
525
    tau = term_type(ctx->terms, t);
13✔
526
    assert(is_arithmetic_type(tau));
527
    p->val = new_uninterpreted_term(ctx->terms, tau);
13✔
528
    int_hset_add(context_get_mcsat_relax_abstraction_terms(ctx), p->val);
13✔
529
  }
530

531
  return p->val;
16✔
532
}
533

534
static term_t mcsat_relax_arith_term(context_t *ctx, term_manager_t *manager, term_t t);
535

536
static term_t mcsat_relax_pprod(context_t *ctx, term_manager_t *manager, term_t t) {
14✔
537
  pprod_t *p;
538
  term_t *a;
539
  term_t r;
540
  uint32_t i, n;
541

542
  p = pprod_term_desc(ctx->terms, t);
14✔
543
  if (pprod_degree(p) > 1) {
14✔
544
    return mcsat_relax_abstraction_for_term(ctx, t);
14✔
545
  }
546

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

NEW
558
  r = mk_arith_pprod(manager, p, n, a);
×
NEW
559
  free_istack_array(&ctx->istack, a);
×
560

NEW
561
  return r;
×
562
}
563

564
static term_t mcsat_relax_poly(context_t *ctx, term_manager_t *manager, term_t t) {
4✔
565
  polynomial_t *p;
566
  term_t *a;
567
  term_t r;
568
  uint32_t i, n;
569

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

586
  r = mk_arith_poly(manager, p, n, a);
4✔
587
  free_istack_array(&ctx->istack, a);
4✔
588

589
  return r;
4✔
590
}
591

NEW
592
static term_t mcsat_relax_const_division(context_t *ctx, term_manager_t *manager, term_kind_t kind, composite_term_t *d) {
×
593
  term_t x, y;
594

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

NEW
603
  x = mcsat_relax_arith_term(ctx, manager, d->arg[0]);
×
NEW
604
  if (x == NULL_TERM) {
×
NEW
605
    return NULL_TERM;
×
606
  }
NEW
607
  y = unsigned_term(intern_tbl_get_root(&ctx->intern, d->arg[1]));
×
608

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

622
/*
623
 * Build a simplex over-approximation of t.  NULL_TERM means that no sound
624
 * linear relaxation could be built; callers must then leave the atom
625
 * MCSAT-only.
626
 */
627
static term_t mcsat_relax_arith_term(context_t *ctx, term_manager_t *manager, term_t t) {
32✔
628
  term_table_t *terms;
629
  composite_term_t *c;
630
  term_t x;
631

632
  t = unsigned_term(intern_tbl_get_root(&ctx->intern, t));
32✔
633
  terms = ctx->terms;
32✔
634
  assert(is_arithmetic_term(terms, t));
635

636
  switch (term_kind(terms, t)) {
32✔
637
  case ARITH_CONSTANT:
12✔
638
  case UNINTERPRETED_TERM:
639
    return t;
12✔
640

641
  case POWER_PRODUCT:
14✔
642
    return mcsat_relax_pprod(ctx, manager, t);
14✔
643

644
  case ARITH_POLY:
4✔
645
    return mcsat_relax_poly(ctx, manager, t);
4✔
646

NEW
647
  case ARITH_FLOOR:
×
NEW
648
    x = mcsat_relax_arith_term(ctx, manager, arith_floor_arg(terms, t));
×
NEW
649
    return x == NULL_TERM ? NULL_TERM : mk_arith_floor(manager, x);
×
650

NEW
651
  case ARITH_CEIL:
×
NEW
652
    x = mcsat_relax_arith_term(ctx, manager, arith_ceil_arg(terms, t));
×
NEW
653
    return x == NULL_TERM ? NULL_TERM : mk_arith_ceil(manager, x);
×
654

NEW
655
  case ARITH_ABS:
×
NEW
656
    x = mcsat_relax_arith_term(ctx, manager, arith_abs_arg(terms, t));
×
NEW
657
    return x == NULL_TERM ? NULL_TERM : mk_arith_abs(manager, x);
×
658

659
  case ARITH_RDIV:
2✔
660
    c = arith_rdiv_term_desc(terms, t);
2✔
661
    if (divisor_requires_mcsat(terms, c->arg[1])) {
2✔
662
      return mcsat_relax_abstraction_for_term(ctx, t);
2✔
663
    }
NEW
664
    return mcsat_relax_const_division(ctx, manager, ARITH_RDIV, c);
×
665

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

NEW
673
  case ARITH_MOD:
×
NEW
674
    c = arith_mod_term_desc(terms, t);
×
NEW
675
    if (divisor_requires_mcsat(terms, c->arg[1])) {
×
NEW
676
      return mcsat_relax_abstraction_for_term(ctx, t);
×
677
    }
NEW
678
    return mcsat_relax_const_division(ctx, manager, ARITH_MOD, c);
×
679

NEW
680
  default:
×
681
    /*
682
     * For arithmetic constructs supported by simplex, keep the term exact.
683
     * If an unsupported construct occurs below an otherwise opaque term
684
     * (for example under an arithmetic ITE), abstract the whole term.
685
     */
NEW
686
    if (term_requires_mcsat_supplement_uncached(ctx, t)) {
×
NEW
687
      return mcsat_relax_abstraction_for_term(ctx, t);
×
688
    }
NEW
689
    return t;
×
690
  }
691
}
692

693
static term_t mcsat_relax_arith_difference(context_t *ctx, term_manager_t *manager, term_t t1, term_t t2) {
12✔
694
  rba_buffer_t *b;
695

696
  b = term_manager_get_arith_buffer(manager);
12✔
697
  reset_rba_buffer(b);
12✔
698
  rba_buffer_add_term(b, ctx->terms, t1);
12✔
699
  rba_buffer_sub_term(b, ctx->terms, t2);
12✔
700

701
  return mk_arith_term(manager, b);
12✔
702
}
703

704
static literal_t map_mcsat_relaxation_to_literal(context_t *ctx, term_t atom) {
19✔
705
  term_table_t *terms;
706
  term_manager_t *manager;
707
  composite_term_t *eq;
708
  literal_t l;
709
  term_t t, u;
710

711
  if (!context_mcsat_relaxation_enabled(ctx)) {
19✔
NEW
712
    return null_literal;
×
713
  }
714

715
  terms = ctx->terms;
19✔
716
  manager = context_get_mcsat_relax_manager(ctx);
19✔
717
  l = null_literal;
19✔
718

719
  switch (term_kind(terms, atom)) {
19✔
NEW
720
  case ARITH_IS_INT_ATOM:
×
NEW
721
    t = mcsat_relax_arith_term(ctx, manager, arith_is_int_arg(terms, atom));
×
NEW
722
    if (t != NULL_TERM) {
×
NEW
723
      l = map_arith_is_int_to_literal(ctx, t);
×
724
    }
NEW
725
    break;
×
726

NEW
727
  case ARITH_EQ_ATOM:
×
NEW
728
    t = mcsat_relax_arith_term(ctx, manager, arith_eq_arg(terms, atom));
×
NEW
729
    if (t != NULL_TERM) {
×
NEW
730
      l = map_arith_eq_to_literal(ctx, t);
×
731
    }
NEW
732
    break;
×
733

734
  case ARITH_GE_ATOM:
4✔
735
    t = mcsat_relax_arith_term(ctx, manager, arith_ge_arg(terms, atom));
4✔
736
    if (t != NULL_TERM) {
4✔
737
      l = map_arith_geq_to_literal(ctx, t);
4✔
738
    }
739
    break;
4✔
740

741
  case ARITH_BINEQ_ATOM:
12✔
742
    eq = arith_bineq_atom_desc(terms, atom);
12✔
743
    t = mcsat_relax_arith_term(ctx, manager, eq->arg[0]);
12✔
744
    u = mcsat_relax_arith_term(ctx, manager, eq->arg[1]);
12✔
745
    if (t != NULL_TERM && u != NULL_TERM) {
12✔
746
      t = mcsat_relax_arith_difference(ctx, manager, t, u);
12✔
747
      l = map_arith_eq_to_literal(ctx, t);
12✔
748
    }
749
    break;
12✔
750

NEW
751
  case ARITH_DIVIDES_ATOM:
×
NEW
752
    eq = arith_divides_atom_desc(terms, atom);
×
NEW
753
    if (!divisor_requires_mcsat(terms, eq->arg[0])) {
×
NEW
754
      t = mcsat_relax_arith_term(ctx, manager, eq->arg[1]);
×
NEW
755
      if (t != NULL_TERM) {
×
NEW
756
        l = map_arith_divides_const_to_literal(ctx, eq->arg[0], t);
×
757
      }
758
    }
NEW
759
    break;
×
760

761
  default:
3✔
762
    /*
763
     * Finite-field and other non-simplex atoms stay MCSAT-only: simplex has
764
     * no useful linear relaxation for them.
765
     */
766
    break;
3✔
767
  }
768

769
  return l;
19✔
770
}
771

772
static literal_t map_mcsat_atom_to_literal(context_t *ctx, term_t atom) {
19✔
773
  mcsat_satellite_t *sat;
774
  literal_t l, lr;
775
  void *obj;
776
  int32_t code;
777

778
  sat = context_mcsat_satellite(ctx);
19✔
779
  assert(sat != NULL);
780

781
  l = pos_lit(create_boolean_variable(ctx->core));
19✔
782
  obj = NULL;
19✔
783
  code = mcsat_satellite_register_atom(sat, atom, l, &obj);
19✔
784
  if (code < 0) {
19✔
NEW
785
    longjmp(ctx->env, code);
×
786
  }
787

788
  attach_atom_to_bvar(ctx->core, var_of(l), tagged_mcsat_atom(obj));
19✔
789

790
  lr = map_mcsat_relaxation_to_literal(ctx, atom);
19✔
791
  if (lr != null_literal) {
19✔
792
    /*
793
     * Link the exact MCSAT atom to its simplex relaxation.  The clauses are
794
     * added with the atoms that introduce both literals; after pop, the
795
     * literals are no longer reachable from active assertions.
796
     */
797
    add_binary_clause(ctx->core, not(l), lr);
16✔
798
    add_binary_clause(ctx->core, l, not(lr));
16✔
799
  }
800

801
  return l;
19✔
802
}
803

804

805

806
/****************************************
807
 *  CONSTRUCTION OF EGRAPH OCCURRENCES  *
808
 ***************************************/
809

810
/*
811
 * Create a new egraph constant of the given type
812
 */
813
static eterm_t make_egraph_constant(context_t *ctx, type_t type, int32_t id) {
1,164✔
814
  assert(type_kind(ctx->types, type) == UNINTERPRETED_TYPE ||
815
         type_kind(ctx->types, type) == SCALAR_TYPE);
816
  return egraph_make_constant(ctx->egraph, type, id);
1,164✔
817
}
818

819

820
/*
821
 * Create a new egraph variable
822
 * - type = its type
823
 */
824
static eterm_t make_egraph_variable(context_t *ctx, type_t type) {
14,087✔
825
  eterm_t u;
826
  bvar_t v;
827

828
  if (type == bool_type(ctx->types)) {
14,087✔
829
    v = create_boolean_variable(ctx->core);
×
830
    u = egraph_bvar2term(ctx->egraph, v);
×
831
  } else {
832
    //    u = egraph_make_variable(ctx->egraph, type);
833
    // it's better to use skolem_term in case type is (tuple ...)
834
    u = egraph_skolem_term(ctx->egraph, type);
14,087✔
835
  }
836
  return u;
14,087✔
837
}
838

839

840
/*
841
 * Type of arithmetic variable x
842
 */
843
static type_t type_of_arithvar(context_t *ctx, thvar_t x) {
1,562✔
844
  type_t tau;
845

846
  tau = real_type(ctx->types);
1,562✔
847
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
1,562✔
848
    tau = int_type(ctx->types);
1,425✔
849
  }
850

851
  return tau;
1,562✔
852
}
853

854

855
/*
856
 * Convert arithmetic variable x to an egraph term
857
 */
858
static occ_t translate_arithvar_to_eterm(context_t *ctx, thvar_t x) {
1,571✔
859
  eterm_t u;
860
  type_t tau;
861

862
  u = ctx->arith.eterm_of_var(ctx->arith_solver, x);
1,571✔
863
  if (u == null_eterm) {
1,571✔
864
    tau = type_of_arithvar(ctx, x);
1,562✔
865
    u = egraph_thvar2term(ctx->egraph, x, tau);
1,562✔
866
  }
867

868
  return pos_occ(u);
1,571✔
869
}
870

871
/*
872
 * Convert bit-vector variable x to an egraph term
873
 * - tau = type of x
874
 */
875
static occ_t translate_bvvar_to_eterm(context_t *ctx, thvar_t x, type_t tau) {
3,693✔
876
  eterm_t u;
877

878
  u = ctx->bv.eterm_of_var(ctx->bv_solver, x);
3,693✔
879
  if (u == null_eterm) {
3,693✔
880
    u = egraph_thvar2term(ctx->egraph, x, tau);
3,672✔
881
  }
882

883
  return pos_occ(u);
3,693✔
884
}
885

886

887
/*
888
 * Convert variable x into an eterm internalization for t
889
 * - tau = type of t
890
 * - if x is mapped to an existing eterm u, return pos_occ(u)
891
 * - otherwise, create an egraph variable u and attach x to u
892
 *   then record the converse mapping [x --> u] in the relevant
893
 *   theory solver
894
 */
895
static occ_t translate_thvar_to_eterm(context_t *ctx, thvar_t x, type_t tau) {
3,348✔
896
  if (is_arithmetic_type(tau)) {
3,348✔
897
    return translate_arithvar_to_eterm(ctx, x);
619✔
898
  } else if (is_bv_type(ctx->types, tau)) {
2,729✔
899
    return translate_bvvar_to_eterm(ctx, x, tau);
2,729✔
900
  } else {
901
    longjmp(ctx->env, INTERNAL_ERROR);
×
902
  }
903
}
904

905

906
/*
907
 * Convert internalization code x for a term t into an egraph term
908
 * - t must be a root in the internalization table and must have
909
 *   positive polarity
910
 */
911
static occ_t translate_code_to_eterm(context_t *ctx, term_t t, int32_t x) {
64,982✔
912
  occ_t u;
913
  type_t tau;
914

915
  assert(is_pos_term(t) && intern_tbl_is_root(&ctx->intern, t) &&
916
         intern_tbl_map_of_root(&ctx->intern, t) == x);
917

918
  if (code_is_eterm(x)) {
64,982✔
919
    u = code2occ(x);
64,233✔
920
  } else {
921
    // x encodes a theory variable or a literal
922
    // convert that to an egraph term
923
    tau = type_of_root(ctx, t);
749✔
924
    switch (type_kind(ctx->types, tau)) {
749✔
925
    case BOOL_TYPE:
×
926
      u = egraph_literal2occ(ctx->egraph, code2literal(x));
×
927
      break;
×
928

929
    case INT_TYPE:
611✔
930
    case REAL_TYPE:
931
      u = translate_arithvar_to_eterm(ctx, code2thvar(x));
611✔
932
      break;
611✔
933

934
    case BITVECTOR_TYPE:
138✔
935
      u = translate_bvvar_to_eterm(ctx, code2thvar(x), tau);
138✔
936
      break;
138✔
937

938
    default:
×
939
      assert(false);
940
      longjmp(ctx->env, INTERNAL_ERROR);
×
941
    }
942

943
    // remap t to u
944
    intern_tbl_remap_root(&ctx->intern, t, occ2code(u));
749✔
945
  }
946

947
  return u;
64,982✔
948
}
949

950

951
/*
952
 * Internalization error for term t
953
 * - t can't be processed because there's no egraph
954
 * - the error code depends on t's type
955
 */
956
static int32_t uf_error_code(context_t *ctx, term_t t) {
×
957
  int32_t code;
958

959
  assert(! context_has_egraph(ctx));
960

961
  switch (term_type_kind(ctx->terms, t)) {
×
962
  case UNINTERPRETED_TYPE:
×
963
    code = UTYPE_NOT_SUPPORTED;
×
964
    break;
×
965

966
  case SCALAR_TYPE:
×
967
    code = SCALAR_NOT_SUPPORTED;
×
968
    break;
×
969

970
  case FUNCTION_TYPE:
×
971
    code = UF_NOT_SUPPORTED;
×
972
    break;
×
973

974
  case TUPLE_TYPE:
×
975
    code = TUPLE_NOT_SUPPORTED;
×
976
    break;
×
977

978
  default:
×
979
    assert(false);
980
    code = INTERNAL_ERROR;
×
981
    break;
×
982
  }
983

984
  return code;
×
985
}
986

987

988
/*
989
 * Utility to filter out high-order terms:
990
 * - check whether any term in a[0 ... n-1] has function type.
991
 * - if so throw an exception (via lonjmp) if the context does not include
992
 *   the array solver.
993
 */
994
static void check_high_order_support(context_t *ctx, const term_t *a, uint32_t n) {
18,027✔
995
  uint32_t i;
996

997
  if (! context_has_fun_solver(ctx)) {
18,027✔
998
    for (i=0; i<n; i++) {
30,058✔
999
      if (is_function_term(ctx->terms, a[i])) {
17,192✔
1000
        longjmp(ctx->env, HIGH_ORDER_FUN_NOT_SUPPORTED);
3✔
1001
      }
1002
    }
1003
  }
1004
}
18,024✔
1005

1006

1007
/***********************************************
1008
 *  CONVERSION OF COMPOSITES TO EGRAPH TERMS   *
1009
 **********************************************/
1010

1011
/*
1012
 * Map apply term to an eterm
1013
 * - tau = type of that term
1014
 */
1015
static occ_t map_apply_to_eterm(context_t *ctx, composite_term_t *app, type_t tau) {
9,685✔
1016
  eterm_t u;
1017
  occ_t *a;
1018
  uint32_t i, n;
1019

1020
  assert(app->arity > 0);
1021
  n = app->arity;
9,685✔
1022

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

1025
  a = alloc_istack_array(&ctx->istack, n);
9,685✔
1026
  for (i=0; i<n; i++) {
34,029✔
1027
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
24,344✔
1028
  }
1029

1030
  // a[0] = function
1031
  // a[1 ... n-1] are the arguments
1032
  u = egraph_make_apply(ctx->egraph, a[0], n-1, a+1, tau);
9,685✔
1033
  free_istack_array(&ctx->istack, a);
9,685✔
1034

1035
  //  add_type_constraints(ctx, pos_occ(u), tau);
1036

1037
  return pos_occ(u);
9,685✔
1038
}
1039

1040

1041
/*
1042
 * Build a tuple of same type as t then assert that it's equal to u1
1043
 * - t must be a root in the internalization table
1044
 * - u1 must be equal to t's internalization (as stored in intern_table)
1045
 * This is the skolemization of (exist (x1...x_n) u1 == (tuple x1 ... x_n))
1046
 *
1047
 * - return the eterm u := (tuple x1 ... x_n)
1048
 */
1049
static eterm_t skolem_tuple(context_t *ctx, term_t t, occ_t u1) {
×
1050
  type_t tau;
1051
  eterm_t u;
1052

1053
  assert(intern_tbl_is_root(&ctx->intern, t) && is_pos_term(t) &&
1054
         intern_tbl_map_of_root(&ctx->intern, t) == occ2code(u1));
1055

1056
  tau = intern_tbl_type_of_root(&ctx->intern, t);
×
1057
  u = egraph_skolem_term(ctx->egraph, tau);
×
1058
  egraph_assert_eq_axiom(ctx->egraph, u1, pos_occ(u));
×
1059

1060
  return u;
×
1061
}
1062

1063

1064
/*
1065
 * Convert (select i t) to an egraph term
1066
 * - tau must be the type of that term (should not be bool)
1067
 * - if a new eterm u is created, attach a theory variable to it
1068
 */
1069
static occ_t map_select_to_eterm(context_t *ctx, select_term_t *s, type_t tau) {
245✔
1070
  occ_t u1;
1071
  eterm_t tuple;
1072
  composite_t *tp;
1073

1074
  u1 = internalize_to_eterm(ctx, s->arg);
245✔
1075
  tuple = egraph_get_tuple_in_class(ctx->egraph, term_of_occ(u1));
245✔
1076
  if (tuple == null_eterm) {
245✔
1077
    tuple = skolem_tuple(ctx, s->arg, u1);
×
1078
  }
1079

1080
  tp = egraph_term_body(ctx->egraph, tuple);
245✔
1081
  assert(composite_body(tp) && tp != NULL && composite_kind(tp) == COMPOSITE_TUPLE);
1082

1083
  return tp->child[s->idx];
245✔
1084
}
1085

1086

1087
/*
1088
 * Convert a conditional expression to an egraph term
1089
 * - c = conditional descriptor
1090
 * - tau = type of c
1091
 */
1092
static occ_t map_conditional_to_eterm(context_t *ctx, conditional_t *c, type_t tau) {
12✔
1093
  literal_t *a;
1094
  occ_t u, v;
1095
  uint32_t i, n;
1096
  literal_t l;
1097
  bool all_false;
1098
  term_t t;
1099

1100
#if 0
1101
  printf("---> conditional to eterm\n");
1102
#endif
1103

1104
  t = simplify_conditional(ctx, c);
12✔
1105
  if (t != NULL_TERM) {
12✔
1106
    return internalize_to_eterm(ctx, t);
4✔
1107
  }
1108

1109
  n = c->nconds;
8✔
1110
  a = alloc_istack_array(&ctx->istack, n + 1);
8✔
1111

1112
  all_false = true;
8✔
1113
  u = null_occurrence;
8✔
1114

1115
  for (i=0; i<n; i++) {
24✔
1116
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
16✔
1117
    if (a[i] == true_literal) {
16✔
1118
      /*
1119
       * a[0] ... a[i-1] are all reducible to false
1120
       * but we can't assume that a[0] ... a[i-1] are all false_literals
1121
       * since we don't know how the theory solver internalizes the
1122
       * conditions.
1123
       */
1124
      v = internalize_to_eterm(ctx, c->pair[i].val);
×
1125
      if (all_false) {
×
1126
        // all previous conditions a[0 ... i-1] are false
1127
        assert(u == null_occurrence);
1128
        u = v;
×
1129
      } else {
1130
        // we assert (u == v) as a top-level equality
1131
        egraph_assert_eq_axiom(ctx->egraph, u, v);
×
1132
      }
1133
      goto done;
×
1134
    }
1135
    if (a[i] != false_literal) {
16✔
1136
      if (all_false) {
13✔
1137
        assert(u == null_occurrence);
1138
        u = pos_occ(make_egraph_variable(ctx, tau));
7✔
1139
        all_false = false;
7✔
1140
      }
1141
      // one clause for a[i] => (u = v[i])
1142
      v = internalize_to_eterm(ctx, c->pair[i].val);
13✔
1143
      l = egraph_make_eq(ctx->egraph, u, v);
13✔
1144
      add_binary_clause(ctx->core, not(a[i]), l);
13✔
1145
    }
1146
  }
1147

1148
  if (all_false) {
8✔
1149
    assert(u == null_occurrence);
1150
    u = internalize_to_eterm(ctx, c->defval);
1✔
1151
    goto done;
1✔
1152
  }
1153

1154
  // clause for the default value
1155
  assert(u != null_occurrence);
1156
  v = internalize_to_eterm(ctx, c->defval);
7✔
1157
  l = egraph_make_eq(ctx->egraph, u, v);
7✔
1158
  a[n] = l;
7✔
1159
  add_clause(ctx->core, n+1, a);
7✔
1160

1161
 done:
8✔
1162
  free_istack_array(&ctx->istack, a);
8✔
1163

1164
  return u;
8✔
1165
}
1166

1167

1168
/*
1169
 * Auxiliary function for flattening if-then-else
1170
 * - v contains a conjunction of n literals: l0 /\ ... /\ l_n
1171
 * - we something like (l0 /\ ... /\ l_n implies (x = y))
1172
 *   (i.e., (not l0) \/ ... \/ (not l_n) \/ (x = y)
1173
 * - this function negates all the literals in place
1174
 */
1175
static void ite_prepare_antecedents(ivector_t *v) {
8,348✔
1176
  uint32_t i, n;
1177

1178
  n = v->size;
8,348✔
1179
  for (i=0; i<n; i++) {
20,408✔
1180
    v->data[i] = not(v->data[i]);
12,060✔
1181
  }
1182
}
8,348✔
1183

1184

1185
/*
1186
 * Convert nested if-then-else to  an egraph term
1187
 * - ite = term of the form (ite c1 t1 t2)
1188
 * - c = internalization of c1
1189
 * - tau = type of the term (ite c1 t1 t2)
1190
 */
1191
static occ_t flatten_ite_to_eterm(context_t *ctx, composite_term_t *ite, literal_t c, type_t tau) {
1,168✔
1192
  ite_flattener_t *flattener;
1193
  ivector_t *buffer;
1194
  term_t x;
1195
  occ_t u, v;
1196
  literal_t l;
1197

1198
  u = pos_occ(make_egraph_variable(ctx, tau));
1,168✔
1199

1200
  flattener = objstack_alloc(&ctx->ostack, sizeof(ite_flattener_t), (cleaner_t) delete_ite_flattener);
1,168✔
1201
  init_ite_flattener(flattener);
1,168✔
1202

1203
  ite_flattener_push(flattener, ite, c);
1,168✔
1204

1205
  while (ite_flattener_is_nonempty(flattener)) {
4,210✔
1206
    if (ite_flattener_last_lit_false(flattener)) {
3,042✔
1207
      // dead branch
1208
      ite_flattener_next_branch(flattener);
6✔
1209
      continue;
6✔
1210
    }
1211
    assert(ite_flattener_branch_is_live(flattener));
1212

1213
    x = ite_flattener_leaf(flattener);
3,036✔
1214
    x = intern_tbl_get_root(&ctx->intern, x);
3,036✔
1215

1216
    /*
1217
     * x is the current leaf.
1218
     * If it's (ite ...) then we can expand the tree by pushing x.
1219
     *
1220
     * Heuristic: we don't do it if x is a shared term or if it's
1221
     * already internalized.
1222
     * - we also need a cutoff since the number of branches grows
1223
     *   exponentially.
1224
     */
1225
    if (is_pos_term(x) &&
6,072✔
1226
        is_ite_term(ctx->terms, x) &&
3,036✔
1227
        !intern_tbl_root_is_mapped(&ctx->intern, x) &&
2,473✔
1228
        term_is_not_shared(&ctx->sharing, x)) {
774✔
1229
      /*
1230
       * x is of the form (ite c a b) and not internalized already,
1231
       * we push (ite c a b) on the flattener.
1232
       */
1233
      ite = ite_term_desc(ctx->terms, x);
353✔
1234
      assert(ite->arity == 3);
1235
      c = internalize_to_literal(ctx, ite->arg[0]);
353✔
1236
      ite_flattener_push(flattener, ite, c);
353✔
1237
    } else {
1238
      /*
1239
       * Add the clause [branch conditions => x = u]
1240
       */
1241
      v = internalize_to_eterm(ctx, x);
2,683✔
1242
      l = egraph_make_eq(ctx->egraph, u, v);
2,683✔
1243

1244
      buffer = &ctx->aux_vector;
2,683✔
1245
      assert(buffer->size == 0);
1246
      ite_flattener_get_clause(flattener, buffer);
2,683✔
1247
      ite_prepare_antecedents(buffer);
2,683✔
1248
      ivector_push(buffer, l);
2,683✔
1249
      add_clause(ctx->core, buffer->size, buffer->data);
2,683✔
1250
      ivector_reset(buffer);
2,683✔
1251

1252
      ite_flattener_next_branch(flattener);
2,683✔
1253
    }
1254
  }
1255

1256
  //  delete_ite_flattener(&flattener);
1257
  objstack_pop(&ctx->ostack);
1,168✔
1258

1259
  return u;
1,168✔
1260
}
1261

1262

1263
/*
1264
 * Convert (ite c t1 t2) to an egraph term
1265
 * - tau = type of (ite c t1 t2)
1266
 */
1267
static occ_t map_ite_to_eterm(context_t *ctx, composite_term_t *ite, type_t tau) {
2,168✔
1268
  conditional_t *d;
1269
  eterm_t u;
1270
  occ_t u1, u2, u3;
1271
  literal_t c, l1, l2;
1272

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

1277
  d = context_make_conditional(ctx, ite);
2,168✔
1278
  if (d != NULL) {
2,168✔
1279
    u1 = map_conditional_to_eterm(ctx, d, tau);
12✔
1280
    context_free_conditional(ctx, d);
12✔
1281
    return u1;
12✔
1282
  }
1283

1284
  c = internalize_to_literal(ctx, ite->arg[0]);
2,156✔
1285
  if (c == true_literal) {
2,156✔
1286
    return internalize_to_eterm(ctx, ite->arg[1]);
110✔
1287
  }
1288
  if (c == false_literal) {
2,046✔
1289
    return internalize_to_eterm(ctx, ite->arg[2]);
15✔
1290
  }
1291

1292
  if (context_ite_flattening_enabled(ctx)) {
2,031✔
1293
    return flatten_ite_to_eterm(ctx, ite, c, tau);
1,168✔
1294
  }
1295

1296
  u2 = internalize_to_eterm(ctx, ite->arg[1]);
863✔
1297
  u3 = internalize_to_eterm(ctx, ite->arg[2]);
863✔
1298

1299
  if (context_keep_ite_enabled(ctx)) {
863✔
1300
    // build the if-then-else in the egraph
1301
    u1 = egraph_literal2occ(ctx->egraph, c);
2✔
1302
    u = egraph_make_ite(ctx->egraph, u1, u2, u3, tau);
2✔
1303
  } else {
1304
    // eliminate the if-then-else
1305
    u = make_egraph_variable(ctx, tau);
861✔
1306
    l1 = egraph_make_eq(ctx->egraph, pos_occ(u), u2);
861✔
1307
    l2 = egraph_make_eq(ctx->egraph, pos_occ(u), u3);
861✔
1308

1309
    assert_ite(&ctx->gate_manager, c, l1, l2, true);
861✔
1310
  }
1311

1312
  return pos_occ(u);
863✔
1313
}
1314

1315

1316

1317
/*
1318
 * Convert (update f t_1 ... t_n v) to a term
1319
 * - tau = type of that term
1320
 */
1321
static occ_t map_update_to_eterm(context_t *ctx, composite_term_t *update, type_t tau) {
11,470✔
1322
  eterm_t u;
1323
  occ_t *a;
1324
  uint32_t i, n;
1325

1326
  assert(update->arity > 2);
1327

1328
  n = update->arity;
11,470✔
1329
  a = alloc_istack_array(&ctx->istack, n);
11,470✔
1330
  for (i=0; i<n; i++) {
45,880✔
1331
    a[i] = internalize_to_eterm(ctx, update->arg[i]);
34,410✔
1332
  }
1333

1334
  // a[0]: function f
1335
  // a[1] ... a[n-2]: t_1 .. t_{n-2}
1336
  // a[n-1]: new value v
1337
  u = egraph_make_update(ctx->egraph, a[0], n-2, a+1, a[n-1], tau);
11,470✔
1338

1339
  free_istack_array(&ctx->istack, a);
11,470✔
1340

1341
  return pos_occ(u);
11,470✔
1342
}
1343

1344

1345

1346
/*
1347
 * Convert (tuple t_1 ... t_n) to a term
1348
 * - tau = type of the tuple
1349
 */
1350
static occ_t map_tuple_to_eterm(context_t *ctx, composite_term_t *tuple, type_t tau) {
190✔
1351
  eterm_t u;
1352
  occ_t *a;
1353
  uint32_t i, n;
1354

1355
  n = tuple->arity;
190✔
1356

1357
  check_high_order_support(ctx, tuple->arg, n);
190✔
1358

1359
  a = alloc_istack_array(&ctx->istack, n);
190✔
1360
  for (i=0; i<n; i++) {
560✔
1361
    a[i] = internalize_to_eterm(ctx, tuple->arg[i]);
370✔
1362
  }
1363

1364
  u = egraph_make_tuple(ctx->egraph, n, a, tau);
190✔
1365
  free_istack_array(&ctx->istack, a);
190✔
1366

1367
  return pos_occ(u);
190✔
1368
}
1369

1370

1371
/*
1372
 * Convert arithmetic and bitvector constants to eterm
1373
 * - check whether the relevant solver exists first
1374
 * - then map the constant to a solver variable x
1375
 *   and convert x to an egraph occurrence
1376
 */
1377
static occ_t map_arith_constant_to_eterm(context_t *ctx, rational_t *q) {
339✔
1378
  thvar_t x;
1379

1380
  if (! context_has_arith_solver(ctx)) {
339✔
1381
    longjmp(ctx->env, ARITH_NOT_SUPPORTED);
×
1382
  }
1383

1384
  x = ctx->arith.create_const(ctx->arith_solver, q);
339✔
1385
  return translate_arithvar_to_eterm(ctx, x);
339✔
1386
}
1387

1388
static occ_t map_bvconst64_to_eterm(context_t *ctx, bvconst64_term_t *c) {
808✔
1389
  thvar_t x;
1390
  type_t tau;
1391

1392
  if (! context_has_bv_solver(ctx)) {
808✔
1393
    longjmp(ctx->env, BV_NOT_SUPPORTED);
×
1394
  }
1395

1396
  x = ctx->bv.create_const64(ctx->bv_solver, c);
808✔
1397
  tau = bv_type(ctx->types, c->bitsize);
808✔
1398

1399
  return translate_bvvar_to_eterm(ctx, x, tau);
808✔
1400
}
1401

1402
static occ_t map_bvconst_to_eterm(context_t *ctx, bvconst_term_t *c) {
18✔
1403
  thvar_t x;
1404
  type_t tau;
1405

1406
  if (! context_has_bv_solver(ctx)) {
18✔
1407
    longjmp(ctx->env, BV_NOT_SUPPORTED);
×
1408
  }
1409

1410
  x = ctx->bv.create_const(ctx->bv_solver, c);
18✔
1411
  tau = bv_type(ctx->types, c->bitsize);
18✔
1412

1413
  return translate_bvvar_to_eterm(ctx, x, tau);
18✔
1414
}
1415

1416

1417

1418
/***************************************
1419
 *  AXIOMS FOR DIV/MOD/FLOOR/CEIL/ABS  *
1420
 **************************************/
1421

1422
/*
1423
 * Auxiliary function: p and map to represent (x - y)
1424
 * - in polynomial p, only the coefficients are relevant
1425
 * - map[0] stores x and map[1] stores y
1426
 * - both p map must be large enough (at least 2 elements)
1427
 */
1428
static void context_store_diff_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
×
1429
  p->nterms = 2;
×
1430
  p->mono[0].var = 1;
×
1431
  q_set_one(&p->mono[0].coeff);       // coeff of x = 1
×
1432
  p->mono[1].var = 2;
×
1433
  q_set_minus_one(&p->mono[1].coeff); // coeff of y = -1
×
1434
  p->mono[2].var = max_idx; // end marker
×
1435

1436
  map[0] = x;
×
1437
  map[1] = y;
×
1438
}
×
1439

1440

1441
/*
1442
 * Same thing for the polynomial (x - y - 1)
1443
 */
1444
static void context_store_diff_minus_one_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
×
1445
  p->nterms = 3;
×
1446
  p->mono[0].var = const_idx;
×
1447
  q_set_minus_one(&p->mono[0].coeff);  // constant = -1
×
1448
  p->mono[1].var = 1;
×
1449
  q_set_one(&p->mono[1].coeff);        // coeff of x = 1
×
1450
  p->mono[2].var = 2;
×
1451
  q_set_minus_one(&p->mono[2].coeff);  // coeff of y = -1
×
1452
  p->mono[3].var = max_idx;
×
1453

1454
  map[0] = null_thvar; // constant
×
1455
  map[1] = x;
×
1456
  map[2] = y;
×
1457
}
×
1458

1459

1460
/*
1461
 * Same thing for the polynomial (x + y)
1462
 */
1463
static void context_store_sum_poly(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y) {
4✔
1464
  p->nterms = 2;
4✔
1465
  p->mono[0].var = 1;
4✔
1466
  q_set_one(&p->mono[0].coeff); // coeff of x = 1
4✔
1467
  p->mono[1].var = 2;
4✔
1468
  q_set_one(&p->mono[1].coeff); // coeff of y = 1
4✔
1469
  p->mono[2].var = max_idx;
4✔
1470

1471
  map[0] = x;
4✔
1472
  map[1] = y;
4✔
1473
}
4✔
1474

1475

1476
/*
1477
 * The lower bound on y = (div x k)  is (k * y <= x) or (x - k * y >= 0)
1478
 * We store the polynomial x - k * y
1479
 */
1480
static void context_store_div_lower_bound(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
21✔
1481
  p->nterms = 2;
21✔
1482
  p->mono[0].var = 1;
21✔
1483
  q_set_one(&p->mono[0].coeff);    // coeff of x = 1
21✔
1484
  p->mono[1].var = 2;
21✔
1485
  q_set_neg(&p->mono[1].coeff, k); // coeff of y = -k
21✔
1486
  p->mono[2].var = max_idx;
21✔
1487

1488
  map[0] = x;
21✔
1489
  map[1] = y;
21✔
1490
}
21✔
1491

1492

1493
/*
1494
 * For converting (divides k x), we use (divides k x) <=> (x <= k * (div x k))
1495
 * or (k * y - x >= 0) for y = (div x k).
1496
 * We store the polynomial - x + k * y.
1497
 */
1498
static void context_store_divides_constraint(polynomial_t *p, thvar_t *map, thvar_t x, thvar_t y, const rational_t *k) {
8✔
1499
  p->nterms = 2;
8✔
1500
  p->mono[0].var = 1;
8✔
1501
  q_set_minus_one(&p->mono[0].coeff);  // coeff of x = -1
8✔
1502
  p->mono[1].var = 2;
8✔
1503
  q_set(&p->mono[1].coeff, k);         // coeff of y = k
8✔
1504
  p->mono[2].var = max_idx;
8✔
1505

1506
  map[0] = x;
8✔
1507
  map[1] = y;
8✔
1508
}
8✔
1509

1510
/*
1511
 * Upper bound on y = (div x k) when both x and y are integer:
1512
 * We have x <= k * y + |k| - 1 or (-x + k y + |k| - 1 >= 0).
1513
 *
1514
 * We store the polynomial - x + k y + |k| - 1
1515
 *
1516
 * NOTE: we don't normalize the constant (|k| - 1) to zero if |k| = 1.
1517
 * This is safe as the simplex solver does not care.
1518
 */
1519
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✔
1520
  p->nterms = 3;
20✔
1521
  p->mono[0].var = const_idx;
20✔
1522
  q_set_abs(&p->mono[0].coeff, k);
20✔
1523
  q_sub_one(&p->mono[0].coeff);        // constant term = |k| - 1
20✔
1524
  p->mono[1].var = 1;
20✔
1525
  q_set_minus_one(&p->mono[1].coeff);  // coeff of x = -1
20✔
1526
  p->mono[2].var = 2;
20✔
1527
  q_set(&p->mono[2].coeff, k);         // coeff of y = k
20✔
1528
  p->mono[3].var = max_idx;
20✔
1529

1530
  map[0] = null_thvar;
20✔
1531
  map[1] = x;
20✔
1532
  map[2] = y;
20✔
1533
}
20✔
1534

1535
/*
1536
 * Upper bound on y = (div x k) when x or k is not an integer.
1537
 * We have x < k * y + |k| or x - k*y - |k| < 0 or (not (x - k*y - |k| >= 0))
1538
 *
1539
 * We store the polynomial x - ky - |k|
1540
 */
1541
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✔
1542
  p->nterms = 3;
1✔
1543
  p->mono[0].var = const_idx;
1✔
1544
  q_set_abs(&p->mono[0].coeff, k);
1✔
1545
  q_neg(&p->mono[0].coeff);           // constant term: -|k|
1✔
1546
  p->mono[1].var = 1;
1✔
1547
  q_set_one(&p->mono[1].coeff);       // coeff of x = +1
1✔
1548
  p->mono[2].var = 2;
1✔
1549
  q_set_neg(&p->mono[2].coeff, k);    // coeff of y = -k
1✔
1550
  p->mono[3].var = max_idx;
1✔
1551

1552
  map[0] = null_thvar;
1✔
1553
  map[1] = x;
1✔
1554
  map[2] = y;
1✔
1555
}
1✔
1556

1557

1558
/*
1559
 * Polynomial x - y + k d (for asserting y = k * (div y k) + (mod y k)
1560
 * - d is assumed to be (div y k)
1561
 * - x is assumed to be (mod y k)
1562
 */
1563
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✔
1564
  p->nterms = 3;
11✔
1565
  p->mono[0].var = 1;
11✔
1566
  q_set_one(&p->mono[0].coeff);       // coefficient of x = 1
11✔
1567
  p->mono[1].var = 2;
11✔
1568
  q_set_minus_one(&p->mono[1].coeff); // coefficient of y = -1
11✔
1569
  p->mono[2].var = 3;
11✔
1570
  q_set(&p->mono[2].coeff, k);        // coefficient of d = k
11✔
1571
  p->mono[3].var = max_idx;
11✔
1572

1573
  map[0] = x;
11✔
1574
  map[1] = y;
11✔
1575
  map[2] = d;
11✔
1576
}
11✔
1577

1578

1579
/*
1580
 * Bound on x = (mod y k) assuming x and k are integer:
1581
 * - the bound is x <= |k| - 1 (i.e., |k| - 1 - x >= 0)
1582
 *   so we construct |k| - 1 - x
1583
 */
1584
static void context_store_integer_mod_bound(polynomial_t *p, thvar_t *map, thvar_t x, const rational_t *k) {
10✔
1585
  p->nterms = 2;
10✔
1586
  p->mono[0].var = const_idx;
10✔
1587
  q_set_abs(&p->mono[0].coeff, k);
10✔
1588
  q_sub_one(&p->mono[0].coeff);        // constant = |k| - 1
10✔
1589
  p->mono[1].var = 1;
10✔
1590
  q_set_minus_one(&p->mono[1].coeff);  // coeff of x = -1
10✔
1591
  p->mono[2].var = max_idx;
10✔
1592

1593
  map[0] = null_thvar;
10✔
1594
  map[1] = x;
10✔
1595
}
10✔
1596

1597

1598
/*
1599
 * Bound on x = (mod y k) when x or k are rational
1600
 * - the bound is x < |k| or x - |k| < 0 or (not (x - |k| >= 0))
1601
 *   so we construct x - |k|
1602
 */
1603
static void context_store_rational_mod_bound(polynomial_t *p, thvar_t *map, thvar_t x, const rational_t *k) {
1✔
1604
  p->nterms = 2;
1✔
1605
  p->mono[0].var = const_idx;
1✔
1606
  q_set_abs(&p->mono[0].coeff, k);
1✔
1607
  q_neg(&p->mono[0].coeff);            // constant = -|k|
1✔
1608
  p->mono[1].var = 1;
1✔
1609
  q_set_one(&p->mono[1].coeff);        // coeff of x = +1
1✔
1610
  p->mono[2].var = max_idx;
1✔
1611

1612
  map[0] = null_thvar;
1✔
1613
  map[1] = x;
1✔
1614
}
1✔
1615

1616

1617
/*
1618
 * Assert constraints for x := floor(y)
1619
 * - both x and y are variables in the arithmetic solver
1620
 * - x has type integer
1621
 *
1622
 * We assert (x <= y && y < x+1)
1623
 */
1624
static void assert_floor_axioms(context_t *ctx, thvar_t x, thvar_t y) {
×
1625
  polynomial_t *p;
1626
  thvar_t map[3];
1627

1628
  assert(ctx->arith.arith_var_is_int(ctx->arith_solver, x));
1629

1630
  p = context_get_aux_poly(ctx, 4);
×
1631

1632
  // assert (y - x >= 0)
1633
  context_store_diff_poly(p, map, y, x);
×
1634
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
×
1635

1636
  // assert (y - x - 1 < 0) <=> (not (y - x - 1) >= 0)
1637
  context_store_diff_minus_one_poly(p, map, y, x);
×
1638
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
×
1639
}
×
1640

1641

1642
/*
1643
 * Assert constraints for x == ceil(y)
1644
 * - both x and y are variables in the arithmetic solver
1645
 * - x has type integer
1646
 *
1647
 * We assert (x - 1 < y && y <= x)
1648
 */
1649
static void assert_ceil_axioms(context_t *ctx, thvar_t x, thvar_t y) {
×
1650
  polynomial_t *p;
1651
  thvar_t map[3];
1652

1653
  assert(ctx->arith.arith_var_is_int(ctx->arith_solver, x));
1654

1655
  p = context_get_aux_poly(ctx, 4);
×
1656

1657
  // assert (x - y >= 0)
1658
  context_store_diff_poly(p, map, x, y);
×
1659
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
×
1660

1661
  // assert (x - y - 1 < 0) <=> (not (x - y - 1) >= 0)
1662
  context_store_diff_minus_one_poly(p, map, x, y);
×
1663
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
×
1664
}
×
1665

1666

1667
/*
1668
 * Assert constraints for x == abs(y)
1669
 * - x and y must be variables in the arithmetic solver
1670
 *
1671
 * We assert (x >= 0) AND ((x == y) or (x == -y))
1672
 */
1673
static void assert_abs_axioms(context_t *ctx, thvar_t x, thvar_t y) {
4✔
1674
  polynomial_t *p;
1675
  thvar_t map[2];
1676
  literal_t l1, l2;
1677

1678
  // assert (x >= 0)
1679
  ctx->arith.assert_ge_axiom(ctx->arith_solver, x, true);
4✔
1680

1681
  // create l1 := (x == y)
1682
  l1 = ctx->arith.create_vareq_atom(ctx->arith_solver, x, y);
4✔
1683

1684
  // create l2 := (x == -y) that is (x + y == 0)
1685
  p = context_get_aux_poly(ctx, 3);
4✔
1686
  context_store_sum_poly(p, map, x, y);
4✔
1687
  l2 = ctx->arith.create_poly_eq_atom(ctx->arith_solver, p, map);
4✔
1688

1689
  // assert (or l1 l2)
1690
  add_binary_clause(ctx->core, l1, l2);
4✔
1691
}
4✔
1692

1693

1694
/*
1695
 * Constraints for x == (div y k)
1696
 * - x and y must be variables in the arithmetic solver
1697
 * - x must be an integer variable
1698
 * - k is a non-zero rational constant
1699
 *
1700
 * If k and y are integer, we assert
1701
 *   k * x <= y <= k * x + |k| - 1
1702
 *
1703
 * Otherwise, we assert
1704
 *   k * x <= y < k * x + |k|
1705
 */
1706
static void assert_div_axioms(context_t *ctx, thvar_t x, thvar_t y, const rational_t *k) {
21✔
1707
  polynomial_t *p;
1708
  thvar_t map[3];
1709

1710
  p = context_get_aux_poly(ctx, 4);
21✔
1711

1712
  // assert k*x <= y (i.e., y - k*x >= 0)
1713
  context_store_div_lower_bound(p, map, y, x, k);
21✔
1714
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
21✔
1715

1716
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, y) && q_is_integer(k)) {
21✔
1717
    // y and k are both integer
1718
    // assert y <= k*x + |k| - 1 (i.e., - y + k x + |k| - 1 >= 0)
1719
    context_store_integer_div_upper_bound(p, map, y, x, k);
20✔
1720
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
20✔
1721

1722
  } else {
1723
    // assert y < k*x + |k| (i.e., y - k*x - |k| < 0) or (not (y - k*x - |k| >= 0))
1724
    context_store_rational_div_upper_bound(p, map, y, x, k);
1✔
1725
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
1✔
1726
  }
1727
}
21✔
1728

1729

1730
/*
1731
 * Constraints for x == (mod y k)
1732
 * - d must be the variable equal to (div y k)
1733
 * - x and y must be variables in the arithmetic solver
1734
 * - k is a non-zero rational constant.
1735
 *
1736
 * We assert x = y - k * d (i.e., (mod y k) = x - k * (div y k))
1737
 * and 0 <= x < |k|.
1738
 *
1739
 * NOTE: The 0 <= x < |k| part is redundant. It's implied by the
1740
 * div_axioms for d = (div y k). It's cheap enough that I can't
1741
 * see a problem with adding it anyway (it's just an interval for x).
1742
 */
1743
static void assert_mod_axioms(context_t *ctx, thvar_t x, thvar_t y, thvar_t d, const rational_t *k) {
11✔
1744
  polynomial_t *p;
1745
  thvar_t map[3];
1746

1747
  p = context_get_aux_poly(ctx, 4);
11✔
1748

1749
  // assert y = k * d + x (i.e., x - y + k *d = 0)
1750
  context_store_divmod_eq(p, map, x, y, d, k);
11✔
1751
  ctx->arith.assert_poly_eq_axiom(ctx->arith_solver, p, map, true);
11✔
1752

1753
  // assert x >= 0
1754
  ctx->arith.assert_ge_axiom(ctx->arith_solver, x, true);
11✔
1755

1756
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x) && q_is_integer(k)) {
11✔
1757
    // both x and |k| are integer
1758
    // assert x <= |k| - 1, i.e., -x + |k| - 1 >= 0
1759
    context_store_integer_mod_bound(p, map, x, k);
10✔
1760
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true);
10✔
1761
  } else {
1762
    // assert x < |k|, i.e., x - |k| <0, i.e., (not (x - |k| >= 0))
1763
    context_store_rational_mod_bound(p, map, x, k);
1✔
1764
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, false);
1✔
1765
  }
1766
}
11✔
1767

1768

1769

1770
/******************************************************
1771
 *  CONVERSION OF COMPOSITES TO ARITHMETIC VARIABLES  *
1772
 *****************************************************/
1773

1774
/*
1775
 * Convert a conditional to an arithmetic variable
1776
 * - if is_int is true, the variable is integer otherwise, it's real
1777
 */
1778
static thvar_t map_conditional_to_arith(context_t *ctx, conditional_t *c, bool is_int) {
239✔
1779
  literal_t *a;
1780
  uint32_t i, n;
1781
  thvar_t x, v;
1782
  bool all_false;
1783
  term_t t;
1784

1785
#if 0
1786
  printf("---> conditional to arith\n");
1787
#endif
1788

1789
  t = simplify_conditional(ctx, c);
239✔
1790
  if (t != NULL_TERM) {
239✔
1791
    return internalize_to_arith(ctx, t);
13✔
1792
  }
1793

1794
  n = c->nconds;
226✔
1795
  a = alloc_istack_array(&ctx->istack, n);
226✔
1796

1797
  all_false = true;
226✔
1798
  v = null_thvar;
226✔
1799

1800
  for (i=0; i<n; i++) {
703✔
1801
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
485✔
1802
    if (a[i] == true_literal) {
485✔
1803
      /*
1804
       * a[0] ... a[i-1] are all reducible to false
1805
       * but we can't assume v == null_thvar, since
1806
       * we don't know how the theory solver internalizes
1807
       * the conditions (i.e., some of them may not be false_literal).
1808
       */
1809
      x = internalize_to_arith(ctx, c->pair[i].val);
8✔
1810
      if (all_false) {
8✔
1811
        assert(v == null_thvar);
1812
        v = x;
6✔
1813
      } else {
1814
        // assert (v == x) in the arithmetic solver
1815
        ctx->arith.assert_vareq_axiom(ctx->arith_solver, v, x, true);
2✔
1816
      }
1817
      goto done;
8✔
1818
    }
1819
    if (a[i] != false_literal) {
477✔
1820
      if (all_false) {
460✔
1821
        assert(v == null_thvar);
1822
        v = ctx->arith.create_var(ctx->arith_solver, is_int);
215✔
1823
        all_false = false;
215✔
1824
      }
1825
      // clause for a[i] => (v = c->pair[i].val)
1826
      x = internalize_to_arith(ctx, c->pair[i].val);
460✔
1827
      ctx->arith.assert_cond_vareq_axiom(ctx->arith_solver, a[i], v, x);
460✔
1828
    }
1829
  }
1830

1831
  if (all_false) {
218✔
1832
    assert(v == null_thvar);
1833
    v = internalize_to_arith(ctx, c->defval);
5✔
1834
    goto done;
5✔
1835
  }
1836

1837
  /*
1838
   * last clause (only if some a[i] isn't false):
1839
   * (a[0] \/ ... \/ a[n-1] \/ v == c->defval)
1840
   */
1841
  assert(v != null_thvar);
1842
  x = internalize_to_arith(ctx, c->defval);
213✔
1843
  ctx->arith.assert_clause_vareq_axiom(ctx->arith_solver, n, a, v, x);
213✔
1844

1845
 done:
226✔
1846
  free_istack_array(&ctx->istack, a);
226✔
1847
  return v;
226✔
1848
}
1849

1850

1851
/*
1852
 * Convert nested if-then-else to  an arithmetic variable
1853
 * - ite = term of the form (ite c1 t1 t2)
1854
 * - c = internalization of c1
1855
 * - is_int = true if the if-then-else term is integer (otherwise it's real)
1856
 */
1857
static thvar_t flatten_ite_to_arith(context_t *ctx, composite_term_t *ite, literal_t c, bool is_int) {
2,521✔
1858
  ite_flattener_t *flattener;
1859
  ivector_t *buffer;
1860
  term_t x;
1861
  thvar_t u, v;
1862

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

1865
  flattener = objstack_alloc(&ctx->ostack, sizeof(ite_flattener_t), (cleaner_t) delete_ite_flattener);
2,521✔
1866
  init_ite_flattener(flattener);
2,521✔
1867

1868
  ite_flattener_push(flattener, ite, c);
2,521✔
1869

1870
  while (ite_flattener_is_nonempty(flattener)) {
8,823✔
1871
    if (ite_flattener_last_lit_false(flattener)) {
6,302✔
1872
      // dead branch
1873
      ite_flattener_next_branch(flattener);
7✔
1874
      continue;
7✔
1875
    }
1876
    assert(ite_flattener_branch_is_live(flattener));
1877

1878
    x = ite_flattener_leaf(flattener);
6,295✔
1879
    x = intern_tbl_get_root(&ctx->intern, x);
6,295✔
1880

1881
    /*
1882
     * x is the current leaf
1883
     * If x is of the form (ite c a b) we can push (ite c a b) on the flattener.
1884
     *
1885
     * Heuristics: don't push the term if x is already internalized or if it's
1886
     * shared.
1887
     */
1888
    if (is_pos_term(x) &&
12,590✔
1889
        is_ite_term(ctx->terms, x) &&
6,295✔
1890
        !intern_tbl_root_is_mapped(&ctx->intern, x) &&
3,934✔
1891
        term_is_not_shared(&ctx->sharing, x)) {
1,256✔
1892
      ite = ite_term_desc(ctx->terms, x);
630✔
1893
      assert(ite->arity == 3);
1894
      c = internalize_to_literal(ctx, ite->arg[0]);
630✔
1895
      ite_flattener_push(flattener, ite, c);
630✔
1896
    } else {
1897
      /*
1898
       * Add the clause [branch conditions => x = u]
1899
       */
1900
      v = internalize_to_arith(ctx, x);
5,665✔
1901

1902
      buffer = &ctx->aux_vector;
5,665✔
1903
      assert(buffer->size == 0);
1904
      ite_flattener_get_clause(flattener, buffer);
5,665✔
1905
      ite_prepare_antecedents(buffer);
5,665✔
1906
      // assert [buffer \/ v = u]
1907
      ctx->arith.assert_clause_vareq_axiom(ctx->arith_solver, buffer->size, buffer->data, v, u);
5,665✔
1908
      ivector_reset(buffer);
5,665✔
1909

1910
      ite_flattener_next_branch(flattener);
5,665✔
1911
    }
1912
  }
1913

1914
  //  delete_ite_flattener(&flattener);
1915
   objstack_pop(&ctx->ostack);
2,521✔
1916

1917
  return u;
2,521✔
1918
}
1919

1920
/*
1921
 * Convert if-then-else to an arithmetic variable
1922
 * - if is_int is true, the if-then-else term is integer
1923
 * - otherwise, it's real
1924
 */
1925
static thvar_t map_ite_to_arith(context_t *ctx, composite_term_t *ite, bool is_int) {
3,023✔
1926
  conditional_t *d;
1927
  literal_t c;
1928
  thvar_t v, x;
1929

1930
  assert(ite->arity == 3);
1931

1932
  d = context_make_conditional(ctx, ite);
3,023✔
1933
  if (d != NULL) {
3,023✔
1934
    v = map_conditional_to_arith(ctx, d, is_int);
239✔
1935
    context_free_conditional(ctx, d);
239✔
1936
    return v;
239✔
1937
  }
1938

1939
  c = internalize_to_literal(ctx, ite->arg[0]); // condition
2,784✔
1940
  if (c == true_literal) {
2,784✔
1941
    return internalize_to_arith(ctx, ite->arg[1]);
77✔
1942
  }
1943
  if (c == false_literal) {
2,707✔
1944
    return internalize_to_arith(ctx, ite->arg[2]);
115✔
1945
  }
1946

1947
  if (context_ite_flattening_enabled(ctx)) {
2,592✔
1948
    return flatten_ite_to_arith(ctx, ite, c, is_int);
2,521✔
1949
  }
1950

1951

1952
  /*
1953
   * no simplification: create a fresh variable v and assert (c ==> v = t1)
1954
   * and (not c ==> v = t2)
1955
   */
1956
  v = ctx->arith.create_var(ctx->arith_solver, is_int);
71✔
1957

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

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

1964
  return v;
71✔
1965
}
1966

1967

1968
/*
1969
 * Assert the bounds on t when t is an arithmetic, special if-then-else
1970
 * - x = arithmetic variable mapped to t in the arithmetic solver
1971
 */
1972
static void assert_ite_bounds(context_t *ctx, term_t t, thvar_t x) {
793✔
1973
  term_table_t *terms;
1974
  polynomial_t *p;
1975
  term_t lb, ub;
1976
  thvar_t map[2];
1977

1978
  terms = ctx->terms;
793✔
1979
  assert(is_arithmetic_term(terms, t));
1980

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

1984
#if 0
1985
  printf("assert ite bound:\n  term: ");
1986
  print_term_name(stdout, terms, t);
1987
  printf("\n");
1988
  printf("  lower bound: ");
1989
  print_term_full(stdout, terms, lb);
1990
  printf("\n");
1991
  printf("  upper bound: ");
1992
  print_term_full(stdout, terms, ub);
1993
  printf("\n");
1994
#endif
1995

1996
  /*
1997
   * prepare polynomial p:
1998
   * first monomial is a constant, second monomial is either +t or -t
1999
   * map[0] = null (what's mapped to const_idx)
2000
   * map[1] = x = (what's mapped to t)
2001
   */
2002
  p = context_get_aux_poly(ctx, 3);
793✔
2003
  p->nterms = 2;
793✔
2004
  p->mono[0].var = const_idx;
793✔
2005
  p->mono[1].var = t;
793✔
2006
  p->mono[2].var = max_idx;
793✔
2007
  map[0] = null_thvar;
793✔
2008
  map[1] = x;
793✔
2009

2010

2011
  // first bound: t >= lb
2012
  q_set_neg(&p->mono[0].coeff, rational_term_desc(terms, lb)); // -lb
793✔
2013
  q_set_one(&p->mono[1].coeff); // +t
793✔
2014
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true); // assert -lb + t >= 0
793✔
2015

2016
  // second bound: t <= ub
2017
  q_set(&p->mono[0].coeff, rational_term_desc(terms, ub));  // +ub
793✔
2018
  q_set_minus_one(&p->mono[1].coeff);  // -t
793✔
2019
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, true); // assert +ub - t >= 0
793✔
2020
}
793✔
2021

2022

2023
/*
2024
 * Convert a power product to an arithmetic variable
2025
 */
2026
static thvar_t map_pprod_to_arith(context_t *ctx, pprod_t *p) {
×
2027
  uint32_t i, n;
2028
  thvar_t *a;
2029
  thvar_t x;
2030

2031
  n = p->len;
×
2032
  a = alloc_istack_array(&ctx->istack, n);
×
2033
  for (i=0; i<n; i++) {
×
2034
    a[i] = internalize_to_arith(ctx, p->prod[i].var);
×
2035
  }
2036

2037
  x = ctx->arith.create_pprod(ctx->arith_solver, p, a);
×
2038
  free_istack_array(&ctx->istack, a);
×
2039

2040
  return x;
×
2041
}
2042

2043

2044
/*
2045
 * Convert polynomial p to an arithmetic variable
2046
 */
2047
static thvar_t map_poly_to_arith(context_t *ctx, polynomial_t *p) {
1,762✔
2048
  uint32_t i, n;
2049
  thvar_t *a;
2050
  thvar_t x;
2051

2052
  n = p->nterms;
1,762✔
2053
  a = alloc_istack_array(&ctx->istack, n);
1,762✔
2054

2055
  // skip the constant if any
2056
  i = 0;
1,762✔
2057
  if (p->mono[0].var == const_idx) {
1,762✔
2058
    a[0] = null_thvar;
467✔
2059
    i ++;
467✔
2060
  }
2061

2062
  // deal with the non-constant monomials
2063
  while (i<n) {
5,035✔
2064
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
3,273✔
2065
    i ++;
3,273✔
2066
  }
2067

2068
  // build the polynomial
2069
  x = ctx->arith.create_poly(ctx->arith_solver, p, a);
1,762✔
2070
  free_istack_array(&ctx->istack, a);
1,762✔
2071

2072
  return x;
1,762✔
2073
}
2074

2075

2076
/*
2077
 * Auxiliary function: return y := (floor x)
2078
 * - check the divmod table first.
2079
 *   If there's a record for (floor x), return the corresponding variable.
2080
 * - Otherwise, create a fresh integer variable y,
2081
 *   assert the axioms for y = (floor x)
2082
 *   add a record to the divmod table and return y.
2083
 */
2084
static thvar_t get_floor(context_t *ctx, thvar_t x) {
×
2085
  thvar_t y;
2086

2087
  y = context_find_var_for_floor(ctx, x);
×
2088
  if (y == null_thvar) {
×
2089
    y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer variable
×
2090
    assert_floor_axioms(ctx, y, x); // assert y = floor(x)
×
2091
    context_record_floor(ctx, x, y); // save the mapping y --> floor(x)
×
2092
  }
2093

2094
  return y;
×
2095
}
2096

2097

2098
/*
2099
 * Return y := (div x k)
2100
 * - check the divmod table first
2101
 * - if (div x k) has already been processed, return the corresponding variable
2102
 * - otherwise create a new variable y, assert the axioms for y = (div x k)
2103
 *   add a record in the divmod table, and return y.
2104
 */
2105
static thvar_t get_div(context_t *ctx, thvar_t x, const rational_t *k) {
25✔
2106
  thvar_t y;
2107

2108
  y = context_find_var_for_div(ctx, x, k);
25✔
2109
  if (y == null_thvar) {
25✔
2110
    // create y := (div x k)
2111
    y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer
21✔
2112
    assert_div_axioms(ctx, y, x, k);
21✔
2113
    context_record_div(ctx, x, k, y);
21✔
2114
  }
2115

2116
  return y;
25✔
2117
}
2118

2119

2120

2121
/*
2122
 * Convert (floor t) to an arithmetic variable
2123
 */
2124
static thvar_t map_floor_to_arith(context_t *ctx, term_t t) {
×
2125
  thvar_t x, y;
2126

2127
  x = internalize_to_arith(ctx, t);
×
2128
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
2129
    // x is integer so (floor x) = x
2130
    y = x;
×
2131
  } else {
2132
    y = get_floor(ctx, x);
×
2133
  }
2134

2135
  return y;
×
2136
}
2137

2138

2139
/*
2140
 * Convert (ceil t) to an arithmetic variable
2141
 */
2142
static thvar_t map_ceil_to_arith(context_t *ctx, term_t t) {
×
2143
  thvar_t x, y;
2144

2145
  x = internalize_to_arith(ctx, t);
×
2146
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
2147
    // x is integer so (ceil x) = x
2148
    y = x;
×
2149
  } else {
2150
    y = context_find_var_for_ceil(ctx, x);
×
2151
    if (y == null_thvar) {
×
2152
      y = ctx->arith.create_var(ctx->arith_solver, true); // y is an integer variable
×
2153
      assert_ceil_axioms(ctx, y, x); // assert y = ceil(x)
×
2154
      context_record_ceil(ctx, x, y); // save the mapping y --> ceil(x)
×
2155
    }
2156
  }
2157

2158
  return y;
×
2159
}
2160

2161

2162
/*
2163
 * Convert (abs t) to an arithmetic variable
2164
 */
2165
static thvar_t map_abs_to_arith(context_t *ctx, term_t t) {
4✔
2166
  thvar_t x, y;
2167
  bool is_int;
2168

2169
  x = internalize_to_arith(ctx, t);
4✔
2170
  is_int = ctx->arith.arith_var_is_int(ctx->arith_solver, x);
4✔
2171
  y = ctx->arith.create_var(ctx->arith_solver, is_int); // y := abs(x) has the same type as x
4✔
2172
  assert_abs_axioms(ctx, y, x);
4✔
2173

2174
  return y;
4✔
2175
}
2176

2177

2178
/*
2179
 * Auxiliary function: check whether t is a non-zero arithmetic constant
2180
 * - if so, store t's value in *val
2181
 */
2182
static bool is_non_zero_rational(term_table_t *tbl, term_t t, rational_t *val) {
17✔
2183
  assert(is_arithmetic_term(tbl, t));
2184

2185
  if (term_kind(tbl, t) == ARITH_CONSTANT) {
17✔
2186
    q_set(val, rational_term_desc(tbl, t));
17✔
2187
    return q_is_nonzero(val);
17✔
2188
  }
2189
  return false;
×
2190
}
2191

2192

2193
/*
2194
 * Error in division: either the divisor is zero or is non-constant
2195
 */
2196
static void __attribute__((noreturn))  bad_divisor(context_t *ctx, term_t t) {
3✔
2197
  term_table_t *tbl;
2198
  int code;
2199

2200
  tbl = ctx->terms;
3✔
2201
  assert(is_arithmetic_term(tbl, t) && is_pos_term(t));
2202

2203
  code = FORMULA_NOT_LINEAR;
3✔
2204
  if (term_kind(tbl, t) == ARITH_CONSTANT && q_is_zero(rational_term_desc(tbl, t))) {
3✔
2205
    code = DIV_BY_ZERO;
3✔
2206
  }
2207
  longjmp(ctx->env, code);
3✔
2208
}
2209

2210
/*
2211
 * Convert (/ t1 t2) to an arithmetic variable
2212
 * - t2 must be a non-zero arithmetic constant
2213
 */
2214
static thvar_t map_rdiv_to_arith(context_t *ctx, composite_term_t *div) {
3✔
2215
  // Could try to evaluate t2 then check whether that's a constant
2216
  assert(div->arity == 2);
2217
  bad_divisor(ctx, div->arg[1]);
3✔
2218
}
2219

2220

2221
/*
2222
 * Convert (div t1 t2) to an arithmetic variable.
2223
 * - fails if t2 is not an arithmetic constant or if it's zero
2224
 */
2225
static thvar_t map_idiv_to_arith(context_t *ctx, composite_term_t *div) {
6✔
2226
  rational_t k;
2227
  thvar_t x, y;
2228

2229
  assert(div->arity == 2);
2230

2231
  q_init(&k);
6✔
2232
  if (is_non_zero_rational(ctx->terms, div->arg[1], &k)) { // k := value of t2
6✔
2233
    assert(q_is_nonzero(&k));
2234
    x = internalize_to_arith(ctx, div->arg[0]); // t1
6✔
2235
    y = get_div(ctx, x, &k);
6✔
2236

2237
  } else {
2238
    // division by a non-constant or by zero: not supported by default
2239
    // arithmetic solver for now
2240
    q_clear(&k);
×
2241
    bad_divisor(ctx, div->arg[1]);
×
2242
  }
2243
  q_clear(&k);
6✔
2244

2245
  return y;
6✔
2246
}
2247

2248

2249
/*
2250
 * Convert (mod t1 t2) to an arithmetic variable
2251
 * - t2 must be a non-zero constant
2252
 */
2253
static thvar_t map_mod_to_arith(context_t *ctx, composite_term_t *mod) {
11✔
2254
  rational_t k;
2255
  thvar_t x, y, r;
2256
  bool is_int;
2257

2258
  assert(mod->arity == 2);
2259

2260
  q_init(&k);
11✔
2261
  if (is_non_zero_rational(ctx->terms, mod->arg[1], &k)) { // k := divider
11✔
2262
    x = internalize_to_arith(ctx, mod->arg[0]);
11✔
2263

2264
    // get y := (div x k)
2265
    assert(q_is_nonzero(&k));
2266
    y = get_div(ctx, x, &k);
11✔
2267

2268
    /*
2269
     * r := (mod x k) is x - k * y where y is an integer.
2270
     * If both x and k are integer, then r has integer type. Otherwise,
2271
     * r is a real variable.
2272
     */
2273
    is_int = ctx->arith.arith_var_is_int(ctx->arith_solver, x) && q_is_integer(&k);
11✔
2274
    r = ctx->arith.create_var(ctx->arith_solver, is_int);
11✔
2275
    assert_mod_axioms(ctx, r, x, y, &k);
11✔
2276

2277
  } else {
2278
    // Non-constant or zero divider
2279
    q_clear(&k);
×
2280
    bad_divisor(ctx, mod->arg[1]);
×
2281
  }
2282

2283
  q_clear(&k);
11✔
2284

2285
  return r;
11✔
2286
}
2287

2288

2289

2290
/******************************************************
2291
 *  CONVERSION OF COMPOSITES TO BIT-VECTOR VARIABLES  *
2292
 *****************************************************/
2293

2294
/*
2295
 * Convert if-then-else to a bitvector variable
2296
 */
2297
static thvar_t map_ite_to_bv(context_t *ctx, composite_term_t *ite) {
20,779✔
2298
  literal_t c;
2299
  thvar_t x, y;
2300

2301
  assert(ite->arity == 3);
2302

2303
  c = internalize_to_literal(ctx, ite->arg[0]);
20,779✔
2304
  if (c == true_literal) {
20,779✔
2305
    return internalize_to_bv(ctx, ite->arg[1]);
23✔
2306
  }
2307
  if (c == false_literal) {
20,756✔
2308
    return internalize_to_bv(ctx, ite->arg[2]);
2,082✔
2309
  }
2310

2311
  // no simplification
2312
  x = internalize_to_bv(ctx, ite->arg[1]);
18,674✔
2313
  y = internalize_to_bv(ctx, ite->arg[2]);
18,674✔
2314

2315
  return ctx->bv.create_bvite(ctx->bv_solver, c, x, y);
18,674✔
2316
}
2317

2318

2319
/*
2320
 * Array of bits b
2321
 * - hackish: we locally disable flattening here
2322
 */
2323
static thvar_t map_bvarray_to_bv(context_t *ctx, composite_term_t *b) {
17,037✔
2324
  uint32_t i, n;
2325
  uint32_t save_options;
2326
  literal_t *a;
2327
  thvar_t x;
2328

2329
  n = b->arity;
17,037✔
2330
  a = alloc_istack_array(&ctx->istack, n);
17,037✔
2331

2332
  save_options = ctx->options;
17,037✔
2333
  disable_diseq_and_or_flattening(ctx);
17,037✔
2334
  for (i=0; i<n; i++) {
498,135✔
2335
    a[i] = internalize_to_literal(ctx, b->arg[i]);
481,098✔
2336
  }
2337
  ctx->options = save_options;
17,037✔
2338

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

2341
  free_istack_array(&ctx->istack, a);
17,037✔
2342

2343
  return x;
17,037✔
2344
}
2345

2346

2347
/*
2348
 * Unsigned division: quotient (div u v)
2349
 */
2350
static thvar_t map_bvdiv_to_bv(context_t *ctx, composite_term_t *div) {
97✔
2351
  thvar_t x, y;
2352

2353
  assert(div->arity == 2);
2354
  x = internalize_to_bv(ctx, div->arg[0]);
97✔
2355
  y = internalize_to_bv(ctx, div->arg[1]);
97✔
2356

2357
  return ctx->bv.create_bvdiv(ctx->bv_solver, x, y);
97✔
2358
}
2359

2360

2361
/*
2362
 * Unsigned division: remainder (rem u v)
2363
 */
2364
static thvar_t map_bvrem_to_bv(context_t *ctx, composite_term_t *rem) {
177✔
2365
  thvar_t x, y;
2366

2367
  assert(rem->arity == 2);
2368
  x = internalize_to_bv(ctx, rem->arg[0]);
177✔
2369
  y = internalize_to_bv(ctx, rem->arg[1]);
177✔
2370

2371
  return ctx->bv.create_bvrem(ctx->bv_solver, x, y);
177✔
2372
}
2373

2374

2375
/*
2376
 * Signed division/rounding toward 0: quotient (sdiv u v)
2377
 */
2378
static thvar_t map_bvsdiv_to_bv(context_t *ctx, composite_term_t *sdiv) {
87✔
2379
  thvar_t x, y;
2380

2381
  assert(sdiv->arity == 2);
2382
  x = internalize_to_bv(ctx, sdiv->arg[0]);
87✔
2383
  y = internalize_to_bv(ctx, sdiv->arg[1]);
87✔
2384

2385
  return ctx->bv.create_bvsdiv(ctx->bv_solver, x, y);
87✔
2386
}
2387

2388

2389
/*
2390
 * Signed division/rounding toward 0: remainder (srem u v)
2391
 */
2392
static thvar_t map_bvsrem_to_bv(context_t *ctx, composite_term_t *srem) {
77✔
2393
  thvar_t x, y;
2394

2395
  assert(srem->arity == 2);
2396
  x = internalize_to_bv(ctx, srem->arg[0]);
77✔
2397
  y = internalize_to_bv(ctx, srem->arg[1]);
77✔
2398

2399
  return ctx->bv.create_bvsrem(ctx->bv_solver, x, y);
77✔
2400
}
2401

2402

2403
/*
2404
 * Signed division/rounding toward -infinity: remainder (smod u v)
2405
 */
2406
static thvar_t map_bvsmod_to_bv(context_t *ctx, composite_term_t *smod) {
×
2407
  thvar_t x, y;
2408

2409
  assert(smod->arity == 2);
2410
  x = internalize_to_bv(ctx, smod->arg[0]);
×
2411
  y = internalize_to_bv(ctx, smod->arg[1]);
×
2412

2413
  return ctx->bv.create_bvsmod(ctx->bv_solver, x, y);
×
2414
}
2415

2416

2417
/*
2418
 * Left shift: (shl u v)
2419
 */
2420
static thvar_t map_bvshl_to_bv(context_t *ctx, composite_term_t *shl) {
85✔
2421
  thvar_t x, y;
2422

2423
  assert(shl->arity == 2);
2424
  x = internalize_to_bv(ctx, shl->arg[0]);
85✔
2425
  y = internalize_to_bv(ctx, shl->arg[1]);
85✔
2426

2427
  return ctx->bv.create_bvshl(ctx->bv_solver, x, y);
85✔
2428
}
2429

2430

2431
/*
2432
 * Logical shift right: (lshr u v)
2433
 */
2434
static thvar_t map_bvlshr_to_bv(context_t *ctx, composite_term_t *lshr) {
1,428✔
2435
  thvar_t x, y;
2436

2437
  assert(lshr->arity == 2);
2438
  x = internalize_to_bv(ctx, lshr->arg[0]);
1,428✔
2439
  y = internalize_to_bv(ctx, lshr->arg[1]);
1,428✔
2440

2441
  return ctx->bv.create_bvlshr(ctx->bv_solver, x, y);
1,428✔
2442
}
2443

2444

2445
/*
2446
 * Arithmetic shift right: (ashr u v)
2447
 */
2448
static thvar_t map_bvashr_to_bv(context_t *ctx, composite_term_t *ashr) {
296✔
2449
  thvar_t x, y;
2450

2451
  assert(ashr->arity == 2);
2452
  x = internalize_to_bv(ctx, ashr->arg[0]);
296✔
2453
  y = internalize_to_bv(ctx, ashr->arg[1]);
296✔
2454

2455
  return ctx->bv.create_bvashr(ctx->bv_solver, x, y);
296✔
2456
}
2457

2458

2459

2460
/*
2461
 * TODO: check for simplifications in bitvector arithmetic
2462
 * before translation to bitvector variables.
2463
 *
2464
 * This matters for the wienand-cav2008 benchmarks.
2465
 */
2466

2467
/*
2468
 * Power product
2469
 */
2470
static thvar_t map_pprod_to_bv(context_t *ctx, pprod_t *p) {
585✔
2471
  uint32_t i, n;
2472
  thvar_t *a;
2473
  thvar_t x;
2474

2475
  n = p->len;
585✔
2476
  a = alloc_istack_array(&ctx->istack, n);
585✔
2477
  for (i=0; i<n; i++) {
1,730✔
2478
    a[i] = internalize_to_bv(ctx, p->prod[i].var);
1,145✔
2479
  }
2480

2481
  x = ctx->bv.create_pprod(ctx->bv_solver, p, a);
585✔
2482
  free_istack_array(&ctx->istack, a);
585✔
2483

2484
  return x;
585✔
2485
}
2486

2487

2488
/*
2489
 * Bitvector polynomial, 64bit coefficients
2490
 */
2491
static thvar_t map_bvpoly64_to_bv(context_t *ctx, bvpoly64_t *p) {
12,225✔
2492
  uint32_t i, n;
2493
  thvar_t *a;
2494
  thvar_t x;
2495

2496
  assert(p->nterms > 0);
2497

2498
  n = p->nterms;
12,225✔
2499
  a = alloc_istack_array(&ctx->istack, n);
12,225✔
2500

2501
  // skip the constant if any
2502
  i = 0;
12,225✔
2503
  if (p->mono[0].var == const_idx) {
12,225✔
2504
    a[0] = null_thvar;
3,212✔
2505
    i ++;
3,212✔
2506
  }
2507

2508
  // non-constant monomials
2509
  while (i < n) {
28,477✔
2510
    a[i] = internalize_to_bv(ctx, p->mono[i].var);
16,252✔
2511
    i ++;
16,252✔
2512
  }
2513

2514
  x = ctx->bv.create_poly64(ctx->bv_solver, p, a);
12,225✔
2515
  free_istack_array(&ctx->istack, a);
12,225✔
2516

2517
  return x;
12,225✔
2518
}
2519

2520

2521
/*
2522
 * Bitvector polynomial, coefficients have more than 64bits
2523
 */
2524
static thvar_t map_bvpoly_to_bv(context_t *ctx, bvpoly_t *p) {
607✔
2525
  uint32_t i, n;
2526
  thvar_t *a;
2527
  thvar_t x;
2528

2529
  assert(p->nterms > 0);
2530

2531
  n = p->nterms;
607✔
2532
  a = alloc_istack_array(&ctx->istack, n);
607✔
2533

2534
  // skip the constant if any
2535
  i = 0;
607✔
2536
  if (p->mono[0].var == const_idx) {
607✔
2537
    a[0] = null_thvar;
539✔
2538
    i ++;
539✔
2539
  }
2540

2541
  // non-constant monomials
2542
  while (i < n) {
1,268✔
2543
    a[i] = internalize_to_bv(ctx, p->mono[i].var);
661✔
2544
    i ++;
661✔
2545
  }
2546

2547
  x = ctx->bv.create_poly(ctx->bv_solver, p, a);
607✔
2548
  free_istack_array(&ctx->istack, a);
607✔
2549

2550
  return x;
607✔
2551
}
2552

2553

2554
#if 0
2555
/*
2556
 * Bvpoly buffer: b must be normalized.
2557
 * - not optimal but this shouldn't be called often.
2558
 */
2559
static thvar_t map_bvpoly_buffer_to_bv(context_t *ctx, bvpoly_buffer_t *b) {
2560
  bvpoly64_t *p;
2561
  bvpoly_t *q;
2562
  uint32_t n;
2563
  thvar_t x;
2564

2565
  n = bvpoly_buffer_bitsize(b);
2566

2567
  if (bvpoly_buffer_is_zero(b)) {
2568
    x = ctx->bv.create_zero(ctx->bv_solver, n);
2569
  } else if (n <= 64) {
2570
    p = bvpoly_buffer_getpoly64(b);
2571
    x = map_bvpoly64_to_bv(ctx, p);
2572
    free_bvpoly64(p);
2573
  } else {
2574
    q = bvpoly_buffer_getpoly(b);
2575
    x = map_bvpoly_to_bv(ctx, q);
2576
    free_bvpoly(q);
2577
  }
2578

2579
  if (ctx->mcsat_supplement) {
2580
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
2581
    if (sat != NULL) {
2582
      mcsat_satellite_register_arith_term(sat, x, r);
2583
    }
2584
  }
2585

2586
  return x;
2587
}
2588

2589
#endif
2590

2591
/****************************
2592
 *  CONVERSION TO LITERALS  *
2593
 ***************************/
2594

2595
/*
2596
 * Boolean if-then-else
2597
 */
2598
static literal_t map_ite_to_literal(context_t *ctx, composite_term_t *ite) {
1,863✔
2599
  literal_t l1, l2, l3;
2600

2601
  assert(ite->arity == 3);
2602
  l1 = internalize_to_literal(ctx, ite->arg[0]); // condition
1,863✔
2603
  if (l1 == true_literal) {
1,863✔
2604
    return internalize_to_literal(ctx, ite->arg[1]);
32✔
2605
  }
2606
  if (l1 == false_literal) {
1,831✔
2607
    return internalize_to_literal(ctx, ite->arg[2]);
71✔
2608
  }
2609

2610
  l2 = internalize_to_literal(ctx, ite->arg[1]);
1,760✔
2611
  l3 = internalize_to_literal(ctx, ite->arg[2]);
1,760✔
2612

2613
  return mk_ite_gate(&ctx->gate_manager, l1, l2, l3);
1,760✔
2614
}
2615

2616

2617
/*
2618
 * Generic equality: (eq t1 t2)
2619
 * - t1 and t2 are not arithmetic or bitvector terms
2620
 */
2621
static literal_t map_eq_to_literal(context_t *ctx, composite_term_t *eq) {
14,519✔
2622
  occ_t u, v;
2623
  literal_t l1, l2, l;
2624

2625
  assert(eq->arity == 2);
2626

2627
  if (is_boolean_term(ctx->terms, eq->arg[0])) {
14,519✔
2628
    assert(is_boolean_term(ctx->terms, eq->arg[1]));
2629

2630
    l1 = internalize_to_literal(ctx, eq->arg[0]);
9,058✔
2631
    l2 = internalize_to_literal(ctx, eq->arg[1]);
9,058✔
2632
    l = mk_iff_gate(&ctx->gate_manager, l1, l2);
9,058✔
2633
  } else {
2634
    // filter out high-order terms. It's enough to check eq->arg[0]
2635
    check_high_order_support(ctx, eq->arg, 1);
5,461✔
2636

2637
    u = internalize_to_eterm(ctx, eq->arg[0]);
5,461✔
2638
    v = internalize_to_eterm(ctx, eq->arg[1]);
5,461✔
2639
    l = egraph_make_eq(ctx->egraph, u, v);
5,461✔
2640
  }
2641

2642
  return l;
14,519✔
2643
}
2644

2645

2646
/*
2647
 * (or t1 ... t_n)
2648
 */
2649
static literal_t map_or_to_literal(context_t *ctx, composite_term_t *or) {
81,300✔
2650
  int32_t *a;
2651
  ivector_t *v;
2652
  literal_t l;
2653
  uint32_t i, n;
2654

2655
  if (context_flatten_or_enabled(ctx)) {
81,300✔
2656
    // flatten (or ...): store result in v
2657
    v = &ctx->aux_vector;
13,220✔
2658
    assert(v->size == 0);
2659
    flatten_or_term(ctx, v, or);
13,220✔
2660

2661
    // try easy simplification
2662
    n = v->size;
13,220✔
2663
    if (disjunct_is_true(ctx, v->data, n)) {
13,220✔
2664
      ivector_reset(v);
335✔
2665
      return true_literal;
335✔
2666
    }
2667

2668
    // make a copy of v
2669
    a = alloc_istack_array(&ctx->istack, n);
12,885✔
2670
    for (i=0; i<n; i++) {
70,797✔
2671
      a[i] = v->data[i];
57,912✔
2672
    }
2673
    ivector_reset(v);
12,885✔
2674

2675
    // internalize a[0 ... n-1]
2676
    for (i=0; i<n; i++) {
69,824✔
2677
      l = internalize_to_literal(ctx, a[i]);
57,221✔
2678
      if (l == true_literal) goto done;
57,221✔
2679
      a[i] = l;
56,939✔
2680
    }
2681

2682
  } else {
2683
    // no flattening
2684
    n = or->arity;
68,080✔
2685
    if (disjunct_is_true(ctx, or->arg, n)) {
68,080✔
2686
      return true_literal;
204✔
2687
    }
2688

2689
    a = alloc_istack_array(&ctx->istack, n);
67,876✔
2690
    for (i=0; i<n; i++) {
254,012✔
2691
      l = internalize_to_literal(ctx, or->arg[i]);
186,452✔
2692
      if (l == true_literal) goto done;
186,452✔
2693
      a[i] = l;
186,136✔
2694
    }
2695
  }
2696

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

2699
 done:
80,761✔
2700
  free_istack_array(&ctx->istack, a);
80,761✔
2701

2702
  return l;
80,761✔
2703
}
2704

2705

2706
/*
2707
 * (xor t1 ... t_n)
2708
 */
2709
static literal_t map_xor_to_literal(context_t *ctx, composite_term_t *xor) {
1✔
2710
  int32_t *a;
2711
  literal_t l;
2712
  uint32_t i, n;
2713

2714
  n = xor->arity;
1✔
2715
  a = alloc_istack_array(&ctx->istack, n);
1✔
2716
  for (i=0; i<n; i++) {
4✔
2717
    a[i] = internalize_to_literal(ctx, xor->arg[i]);
3✔
2718
  }
2719

2720
  l = mk_xor_gate(&ctx->gate_manager, n, a);
1✔
2721
  free_istack_array(&ctx->istack, a);
1✔
2722

2723
  return l;
1✔
2724
}
2725

2726

2727
/*
2728
 * Convert (p t_1 .. t_n) to a literal
2729
 * - create an egraph atom
2730
 */
2731
static literal_t map_apply_to_literal(context_t *ctx, composite_term_t *app) {
4,368✔
2732
  occ_t *a;
2733
  uint32_t i, n;
2734
  literal_t l;
2735

2736
  assert(app->arity > 0);
2737
  n = app->arity;
4,368✔
2738
  a = alloc_istack_array(&ctx->istack, n);
4,368✔
2739
  for (i=0; i<n; i++) {
16,325✔
2740
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
11,957✔
2741
  }
2742

2743
  // a[0] = predicate
2744
  // a[1 ...n-1] = arguments
2745
  l = egraph_make_pred(ctx->egraph, a[0], n-1, a + 1);
4,368✔
2746
  free_istack_array(&ctx->istack, a);
4,368✔
2747

2748
  return l;
4,368✔
2749
}
2750

2751

2752

2753
/*
2754
 * Auxiliary function: translate (distinct a[0 ... n-1]) to a literal,
2755
 * when a[0] ... a[n-1] are arithmetic variables.
2756
 *
2757
 * We expand this into a quadratic number of disequalities.
2758
 */
2759
static literal_t make_arith_distinct(context_t *ctx, uint32_t n, thvar_t *a) {
158✔
2760
  uint32_t i, j;
2761
  ivector_t *v;
2762
  literal_t l;
2763

2764
  assert(n >= 2);
2765

2766
  v = &ctx->aux_vector;
158✔
2767
  assert(v->size == 0);
2768
  for (i=0; i<n-1; i++) {
3,776✔
2769
    for (j=i+1; j<n; j++) {
48,648✔
2770
      l = ctx->arith.create_vareq_atom(ctx->arith_solver, a[i], a[j]);
45,030✔
2771
      ivector_push(v, l);
45,030✔
2772
    }
2773
  }
2774
  l = mk_or_gate(&ctx->gate_manager, v->size, v->data);
158✔
2775
  ivector_reset(v);
158✔
2776

2777
  return not(l);
158✔
2778
}
2779

2780

2781
/*
2782
 * Auxiliary function: translate (distinct a[0 ... n-1]) to a literal,
2783
 * when a[0] ... a[n-1] are bitvector variables.
2784
 *
2785
 * We expand this into a quadratic number of disequalities.
2786
 */
2787
static literal_t make_bv_distinct(context_t *ctx, uint32_t n, thvar_t *a) {
2✔
2788
  uint32_t i, j;
2789
  ivector_t *v;
2790
  literal_t l;
2791

2792
  assert(n >= 2);
2793

2794
  v = &ctx->aux_vector;
2✔
2795
  assert(v->size == 0);
2796
  for (i=0; i<n-1; i++) {
11✔
2797
    for (j=i+1; j<n; j++) {
40✔
2798
      l = ctx->bv.create_eq_atom(ctx->bv_solver, a[i], a[j]);
31✔
2799
      ivector_push(v, l);
31✔
2800
    }
2801
  }
2802
  l = mk_or_gate(&ctx->gate_manager, v->size, v->data);
2✔
2803
  ivector_reset(v);
2✔
2804

2805
  return not(l);
2✔
2806
}
2807

2808

2809
/*
2810
 * Convert (distinct t_1 ... t_n) to a literal
2811
 */
2812
static literal_t map_distinct_to_literal(context_t *ctx, composite_term_t *distinct) {
9✔
2813
  int32_t *a;
2814
  literal_t l;
2815
  uint32_t i, n;
2816

2817
  n = distinct->arity;
9✔
2818
  a = alloc_istack_array(&ctx->istack, n);
9✔
2819
  if (context_has_egraph(ctx)) {
9✔
2820
    // fail if arguments are functions and we don't support high-order terms
2821
    // checking the first argument is enough since they all have the same type
2822
    check_high_order_support(ctx, distinct->arg, 1);
6✔
2823

2824
    // default: translate to the egraph
2825
    for (i=0; i<n; i++) {
25✔
2826
      a[i] = internalize_to_eterm(ctx, distinct->arg[i]);
19✔
2827
    }
2828
    l = egraph_make_distinct(ctx->egraph, n, a);
6✔
2829

2830
  } else if (is_arithmetic_term(ctx->terms, distinct->arg[0])) {
3✔
2831
    // translate to arithmetic variables
2832
    for (i=0; i<n; i++) {
12✔
2833
      a[i] = internalize_to_arith(ctx, distinct->arg[i]);
9✔
2834
    }
2835
    l = make_arith_distinct(ctx, n, a);
3✔
2836

2837
  } else if (is_bitvector_term(ctx->terms, distinct->arg[0])) {
×
2838
    // translate to bitvector variables
2839
    for (i=0; i<n; i++) {
×
2840
      a[i] = internalize_to_bv(ctx, distinct->arg[i]);
×
2841
    }
2842
    l = make_bv_distinct(ctx, n, a);
×
2843

2844
  } else {
2845
    longjmp(ctx->env, uf_error_code(ctx, distinct->arg[0]));
×
2846
  }
2847

2848
  free_istack_array(&ctx->istack, a);
9✔
2849

2850
  return l;
9✔
2851
}
2852

2853

2854

2855
/*
2856
 * Arithmetic atom: p == 0
2857
 */
2858
static literal_t map_poly_eq_to_literal(context_t *ctx, polynomial_t *p) {
1,204✔
2859
  uint32_t i, n;
2860
  thvar_t *a;
2861
  literal_t l;
2862

2863
  n = p->nterms;
1,204✔
2864
  a = alloc_istack_array(&ctx->istack, n);
1,204✔
2865

2866
  // skip the constant if any
2867
  i = 0;
1,204✔
2868
  if (p->mono[0].var == const_idx) {
1,204✔
2869
    a[0] = null_thvar;
582✔
2870
    i ++;
582✔
2871
  }
2872

2873
  // deal with the non-constant monomials
2874
  while (i<n) {
4,190✔
2875
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
2,986✔
2876
    i ++;
2,986✔
2877
  }
2878

2879
  // build the atom
2880
  l = ctx->arith.create_poly_eq_atom(ctx->arith_solver, p, a);
1,204✔
2881
  free_istack_array(&ctx->istack, a);
1,204✔
2882

2883
  return l;
1,204✔
2884
}
2885

2886

2887
/*
2888
 * Arithmetic atom: (p >= 0)
2889
 */
2890
static literal_t map_poly_ge_to_literal(context_t *ctx, polynomial_t *p) {
33,497✔
2891
  uint32_t i, n;
2892
  thvar_t *a;
2893
  literal_t l;
2894

2895
  n = p->nterms;
33,497✔
2896
  a = alloc_istack_array(&ctx->istack, n);
33,497✔
2897

2898
  // skip the constant if any
2899
  i = 0;
33,497✔
2900
  if (p->mono[0].var == const_idx) {
33,497✔
2901
    a[0] = null_thvar;
26,320✔
2902
    i ++;
26,320✔
2903
  }
2904

2905
  // deal with the non-constant monomials
2906
  while (i<n) {
84,656✔
2907
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
51,159✔
2908
    i ++;
51,159✔
2909
  }
2910

2911
  // build the atom
2912
  l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, a);
33,497✔
2913
  free_istack_array(&ctx->istack, a);
33,497✔
2914

2915
  return l;
33,497✔
2916
}
2917

2918

2919
/*
2920
 * Arithmetic atom: (t >= 0)
2921
 */
2922
static literal_t map_arith_geq_to_literal(context_t *ctx, term_t t) {
33,845✔
2923
  term_table_t *terms;
2924
  thvar_t x;
2925
  literal_t l;
2926

2927
  terms = ctx->terms;
33,845✔
2928
  if (term_kind(terms, t) == ARITH_POLY) {
33,845✔
2929
    l = map_poly_ge_to_literal(ctx, poly_term_desc(terms, t));
33,497✔
2930
  } else {
2931
    x = internalize_to_arith(ctx, t);
348✔
2932
    l = ctx->arith.create_ge_atom(ctx->arith_solver, x);
348✔
2933
  }
2934

2935
  return l;
33,845✔
2936
}
2937

2938

2939

2940
/*
2941
 * Arithmetic equalities (eq t1 t2)
2942
 * 1) try to flatten the if-then-elses
2943
 * 2) also apply cheap lift-if rule: (eq (ite c t1 t2) u1) --> (ite c (eq t1 u1) (eq t2 u1))
2944
 */
2945
static literal_t map_arith_bineq(context_t *ctx, term_t t1, term_t u1);
2946

2947
/*
2948
 * Lift equality: (eq (ite c u1 u2) t) --> (ite c (eq u1 t) (eq u2 t))
2949
 */
2950
static literal_t map_ite_arith_bineq(context_t *ctx, composite_term_t *ite, term_t t) {
42,609✔
2951
  literal_t l1, l2, l3;
2952

2953
  assert(ite->arity == 3);
2954
  l1 = internalize_to_literal(ctx, ite->arg[0]);
42,609✔
2955
  if (l1 == true_literal) {
42,609✔
2956
    // (eq (ite true u1 u2) t) --> (eq u1 t)
2957
    return map_arith_bineq(ctx, ite->arg[1], t);
7✔
2958
  }
2959
  if (l1 == false_literal) {
42,602✔
2960
    // (eq (ite true u1 u2) t) --> (eq u2 t)
2961
    return map_arith_bineq(ctx, ite->arg[2], t);
109✔
2962
  }
2963

2964
  // apply lift-if here
2965
  l2 = map_arith_bineq(ctx, ite->arg[1], t);
42,493✔
2966
  l3 = map_arith_bineq(ctx, ite->arg[2], t);
42,493✔
2967

2968
  return mk_ite_gate(&ctx->gate_manager, l1, l2, l3);
42,493✔
2969
}
2970

2971
static literal_t map_arith_bineq_aux(context_t *ctx, term_t t1, term_t t2) {
53,504✔
2972
  term_table_t *terms;
2973
  thvar_t x, y;
2974
  occ_t u, v;
2975
  literal_t l;
2976

2977
  /*
2978
   * Try to apply lift-if rule: (eq (ite c u1 u2) t2) --> (ite c (eq u1 t2) (eq u2 t2))
2979
   * do this only if t2 is not an if-then-else term.
2980
   *
2981
   * Otherwise add the atom (eq t1 t2) to the egraph if possible
2982
   * or create (eq t1 t2) in the arithmetic solver.
2983
   */
2984
  terms = ctx->terms;
53,504✔
2985
  if (is_ite_term(terms, t1) && ! is_ite_term(terms, t2)) {
53,504✔
2986
    l = map_ite_arith_bineq(ctx, ite_term_desc(terms, t1), t2);
38,573✔
2987
  } else if (is_ite_term(terms, t2) && !is_ite_term(terms, t1)) {
14,931✔
2988
    l = map_ite_arith_bineq(ctx, ite_term_desc(terms, t2), t1);
4,036✔
2989
  } else if (context_has_egraph(ctx)) {
10,895✔
2990
    u = internalize_to_eterm(ctx, t1);
3,774✔
2991
    v = internalize_to_eterm(ctx, t2);
3,774✔
2992
    l = egraph_make_eq(ctx->egraph, u, v);
3,774✔
2993
  } else {
2994
    x = internalize_to_arith(ctx, t1);
7,121✔
2995
    y = internalize_to_arith(ctx, t2);
7,121✔
2996
    l = ctx->arith.create_vareq_atom(ctx->arith_solver, x, y);
7,121✔
2997
  }
2998

2999
  return l;
53,504✔
3000
}
3001

3002
static literal_t map_arith_bineq(context_t *ctx, term_t t1, term_t u1) {
95,361✔
3003
  ivector_t *v;
3004
  int32_t *a;
3005
  uint32_t i, n;
3006
  term_t t2, u2;
3007
  literal_t l;
3008

3009
  t1 = intern_tbl_get_root(&ctx->intern, t1);
95,361✔
3010
  u1 = intern_tbl_get_root(&ctx->intern, u1);
95,361✔
3011

3012
  if (t1 == u1) {
95,361✔
3013
    return true_literal;
3,222✔
3014
  }
3015

3016
  /*
3017
   * Check the cache
3018
   */
3019
  l = find_in_eq_cache(ctx, t1, u1);
92,139✔
3020
  if (l == null_literal) {
92,139✔
3021
    /*
3022
     * The pair (t1, u1) is not mapped already.
3023
     * Try to flatten the if-then-else equalities
3024
     */
3025
    v = &ctx->aux_vector;
53,431✔
3026
    assert(v->size == 0);
3027
    t2 = flatten_ite_equality(ctx, v, t1, u1);
53,431✔
3028
    u2 = flatten_ite_equality(ctx, v, u1, t2);
53,431✔
3029

3030
    /*
3031
     * (t1 == u1) is equivalent to (and (t2 == u2) v[0] ... v[n-1])
3032
     * where v[i] = element i of v
3033
     */
3034
    n = v->size;
53,431✔
3035
    if (n == 0) {
53,431✔
3036
      // empty v: return (t2 == u2)
3037
      assert(t1 == t2 && u1 == u2);
3038
      l = map_arith_bineq_aux(ctx, t2, u2);
10,680✔
3039

3040
    } else {
3041
      // build (and (t2 == u2) v[0] ... v[n-1])
3042
      // first make a copy of v into a[0 .. n-1]
3043
      a = alloc_istack_array(&ctx->istack, n+1);
42,751✔
3044
      for (i=0; i<n; i++) {
766,594✔
3045
        a[i] = v->data[i];
723,843✔
3046
      }
3047
      ivector_reset(v);
42,751✔
3048

3049
      // build the internalization of a[0 .. n-1]
3050
      for (i=0; i<n; i++) {
766,594✔
3051
        a[i] = internalize_to_literal(ctx, a[i]);
723,843✔
3052
      }
3053
      a[n] = map_arith_bineq_aux(ctx, t2, u2);
42,751✔
3054

3055
      // build (and a[0] ... a[n])
3056
      l = mk_and_gate(&ctx->gate_manager, n+1, a);
42,751✔
3057
      free_istack_array(&ctx->istack, a);
42,751✔
3058
    }
3059

3060
    /*
3061
     * Store the mapping (t1, u1) --> l in the cache
3062
     */
3063
    add_to_eq_cache(ctx, t1, u1, l);
53,431✔
3064
  }
3065

3066
  return l;
92,139✔
3067
}
3068

3069

3070
static inline literal_t map_arith_bineq_to_literal(context_t *ctx, composite_term_t *eq) {
8,967✔
3071
  assert(eq->arity == 2);
3072
  return map_arith_bineq(ctx, eq->arg[0], eq->arg[1]);
8,967✔
3073
}
3074

3075

3076

3077
/*
3078
 * Arithmetic atom: (t == 0)
3079
 */
3080
static literal_t map_arith_eq_to_literal(context_t *ctx, term_t t) {
2,261✔
3081
  term_table_t *terms;
3082
  thvar_t x;
3083
  literal_t l;
3084

3085
  terms = ctx->terms;
2,261✔
3086
  if (term_kind(terms, t) == ARITH_POLY) {
2,261✔
3087
    l = map_poly_eq_to_literal(ctx, poly_term_desc(terms, t));
1,204✔
3088
  } else if (is_ite_term(terms, t)) {
1,057✔
3089
    l = map_arith_bineq(ctx, t, zero_term);
426✔
3090
  } else {
3091
    x = internalize_to_arith(ctx, t);
631✔
3092
    l = ctx->arith.create_eq_atom(ctx->arith_solver, x);
631✔
3093
  }
3094
  return l;
2,261✔
3095
}
3096

3097

3098
/*
3099
 * DIVIDES AND IS_INT ATOMS
3100
 */
3101

3102
/*
3103
 * We use the rules
3104
 * - (is_int x)    <=> (x <= floor(x))
3105
 * - (divides k x) <=> (x <= k * div(x, k))
3106
 */
3107

3108
// atom (is_int t)
3109
static literal_t map_arith_is_int_to_literal(context_t *ctx, term_t t) {
×
3110
  polynomial_t *p;
3111
  thvar_t map[2];
3112
  thvar_t x, y;
3113
  literal_t l;
3114

3115
  x = internalize_to_arith(ctx, t);
×
3116
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
3117
    l = true_literal;
×
3118
  } else {
3119
    // we convert (is_int x) to (x <= floor(x))
3120
    y = get_floor(ctx, x); // y is floor x
×
3121
    p = context_get_aux_poly(ctx, 3);
×
3122
    context_store_diff_poly(p, map, y, x); // (p, map) := (y - x)
×
3123
    // atom (x <= y) is the same as (p >= 0)
3124
    l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, map);
×
3125
  }
3126

3127
  return l;
×
3128
}
3129

3130
// atom (divides k t)  we assume k != 0 and constant
3131
static literal_t map_arith_divides_const_to_literal(context_t *ctx, term_t d, term_t t) {
8✔
3132
  rational_t k;
3133
  polynomial_t *p;
3134
  thvar_t map[2];
3135
  thvar_t x, y;
3136
  literal_t l;
3137

3138
  assert(term_kind(ctx->terms, d) == ARITH_CONSTANT);
3139

3140
  // make a copy of the divider in k
3141
  q_init(&k);
8✔
3142
  q_set(&k, rational_term_desc(ctx->terms, d));
8✔
3143
  assert(q_is_nonzero(&k));
3144

3145
  x = internalize_to_arith(ctx, t); // this is t
8✔
3146
  y = get_div(ctx, x, &k);  // y := (div x k)
8✔
3147
  p = context_get_aux_poly(ctx, 3);
8✔
3148
  context_store_divides_constraint(p, map, x, y, &k); // p is (- x + k * y)
8✔
3149
  // atom (x <= k * y) is (p >= 0)
3150
  l = ctx->arith.create_poly_ge_atom(ctx->arith_solver, p, map);
8✔
3151

3152
  q_clear(&k);
8✔
3153

3154
  return l;
8✔
3155
}
3156

3157
// atom (divides k t)  we assume k != 0
3158
static literal_t map_arith_divides_to_literal(context_t *ctx, composite_term_t *divides) {
8✔
3159
  term_t d;
3160

3161
  assert(divides->arity == 2);
3162

3163
  d = divides->arg[0];
8✔
3164
  if (term_kind(ctx->terms, d) == ARITH_CONSTANT) {
8✔
3165
    return map_arith_divides_const_to_literal(ctx, d, divides->arg[1]);
8✔
3166
  } else {
3167
    // k is not a constant: not supported
3168
    longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
3169
  }
3170
}
3171

3172

3173
/*
3174
 * BITVECTOR ATOMS
3175
 */
3176

3177
/*
3178
 * Auxiliary function: atom for (t == 0)
3179
 */
3180
static literal_t map_bveq0_to_literal(context_t *ctx, term_t t) {
10✔
3181
  uint32_t n;
3182
  thvar_t x, y;
3183

3184
  t = intern_tbl_get_root(&ctx->intern, t);
10✔
3185
  n = term_bitsize(ctx->terms, t);
10✔
3186
  x = internalize_to_bv(ctx, t);
10✔
3187
  y = ctx->bv.create_zero(ctx->bv_solver, n);
10✔
3188

3189
  return ctx->bv.create_eq_atom(ctx->bv_solver, x, y);
10✔
3190
}
3191

3192
static literal_t map_bveq_to_literal(context_t *ctx, composite_term_t *eq) {
4,869✔
3193
  bveq_simp_t simp;
3194
  term_t t, t1, t2;
3195
  thvar_t x, y;
3196

3197
  assert(eq->arity == 2);
3198

3199
  /*
3200
   * Apply substitution then check for simplifications
3201
   */
3202
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
4,869✔
3203
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
4,869✔
3204
  t = simplify_bitvector_eq(ctx, t1, t2);
4,869✔
3205
  if (t != NULL_TERM) {
4,869✔
3206
    // (bveq t1 t2) is equivalent to t
3207
    return internalize_to_literal(ctx, t);
77✔
3208
  }
3209

3210
  /*
3211
   * More simplifications
3212
   */
3213
  try_arithmetic_bveq_simplification(ctx, &simp, t1, t2);
4,792✔
3214
  switch (simp.code) {
4,792✔
3215
  case BVEQ_CODE_TRUE:
×
3216
    return true_literal;
×
3217

3218
  case BVEQ_CODE_FALSE:
×
3219
    return false_literal;
×
3220

3221
  case BVEQ_CODE_REDUCED:
11✔
3222
    t1 = intern_tbl_get_root(&ctx->intern, simp.left);
11✔
3223
    t2 = intern_tbl_get_root(&ctx->intern, simp.right);
11✔
3224
    break;
11✔
3225

3226
  case BVEQ_CODE_REDUCED0:
10✔
3227
    // (t1 == t2) is reduced to (simp.left == 0)
3228
    // we create the atom directly here:
3229
    return map_bveq0_to_literal(ctx, simp.left);
10✔
3230

3231
  default:
4,771✔
3232
    break;
4,771✔
3233
  }
3234

3235
  if (equal_bitvector_factors(ctx, t1, t2)) {
4,782✔
3236
    return true_literal;
×
3237
  }
3238

3239
  /*
3240
   * NOTE: creating (eq t1 t2) in the egraph instead makes things worse
3241
   */
3242
  x = internalize_to_bv(ctx, t1);
4,782✔
3243
  y = internalize_to_bv(ctx, t2);
4,782✔
3244
  return ctx->bv.create_eq_atom(ctx->bv_solver, x, y);
4,782✔
3245
}
3246

3247
static literal_t map_bvge_to_literal(context_t *ctx, composite_term_t *ge) {
2,302✔
3248
  thvar_t x, y;
3249

3250
  assert(ge->arity == 2);
3251
  x = internalize_to_bv(ctx, ge->arg[0]);
2,302✔
3252
  y = internalize_to_bv(ctx, ge->arg[1]);
2,302✔
3253

3254
  return ctx->bv.create_ge_atom(ctx->bv_solver, x, y);
2,302✔
3255
}
3256

3257
static literal_t map_bvsge_to_literal(context_t *ctx, composite_term_t *sge) {
2,907✔
3258
  thvar_t x, y;
3259

3260
  assert(sge->arity == 2);
3261
  x = internalize_to_bv(ctx, sge->arg[0]);
2,907✔
3262
  y = internalize_to_bv(ctx, sge->arg[1]);
2,907✔
3263

3264
  return ctx->bv.create_sge_atom(ctx->bv_solver, x, y);
2,907✔
3265
}
3266

3267

3268
// Select bit
3269
static literal_t map_bit_select_to_literal(context_t *ctx, select_term_t *select) {
264,228✔
3270
  term_t t, s;
3271
  thvar_t x;
3272

3273
  /*
3274
   * Apply substitution then try to simplify
3275
   */
3276
  t = intern_tbl_get_root(&ctx->intern, select->arg);
264,228✔
3277
  s = extract_bit(ctx->terms, t, select->idx);
264,228✔
3278
  if (s != NULL_TERM) {
264,228✔
3279
    // (select t i) is s
3280
    return internalize_to_literal(ctx, s);
25,181✔
3281
  } else {
3282
    // no simplification
3283
    x = internalize_to_bv(ctx, t);
239,047✔
3284
    return ctx->bv.select_bit(ctx->bv_solver, x, select->idx);
239,047✔
3285
  }
3286
}
3287

3288

3289
/****************************************
3290
 *  INTERNALIZATION TO ETERM: TOPLEVEL  *
3291
 ***************************************/
3292

3293
static occ_t internalize_to_eterm(context_t *ctx, term_t t) {
103,355✔
3294
  term_table_t *terms;
3295
  term_t root;
3296
  term_t r;
3297
  uint32_t polarity;
3298
  int32_t code;
3299
  int32_t exception;
3300
  type_t tau;
3301
  occ_t u;
3302
  literal_t l;
3303
  thvar_t x;
3304

3305
  if (! context_has_egraph(ctx)) {
103,355✔
3306
    exception = uf_error_code(ctx, t);
×
3307
    goto abort;
×
3308
  }
3309

3310
  root = intern_tbl_get_root(&ctx->intern, t);
103,355✔
3311
  polarity = polarity_of(root);
103,355✔
3312
  root = unsigned_term(root);
103,355✔
3313
  r = root;
103,355✔
3314

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

3358
    if (is_boolean_type(tau)) {
38,373✔
3359
      l = internalize_to_literal(ctx, r);
38✔
3360
      u = egraph_literal2occ(ctx->egraph, l);
38✔
3361
      intern_tbl_remap_root(&ctx->intern, r, occ2code(u));
38✔
3362
    } else {
3363
      /*
3364
       * r is not a boolean term
3365
       */
3366
      assert(polarity == 0);
3367

3368
      switch (term_kind(terms, r)) {
38,335✔
3369
      case CONSTANT_TERM:
1,164✔
3370
        u = pos_occ(make_egraph_constant(ctx, tau, constant_term_index(terms, r)));
1,164✔
3371
        break;
1,164✔
3372

3373
      case ARITH_CONSTANT:
339✔
3374
        u = map_arith_constant_to_eterm(ctx, rational_term_desc(terms, r));
339✔
3375
        break;
339✔
3376

3377
      case BV64_CONSTANT:
808✔
3378
        u = map_bvconst64_to_eterm(ctx, bvconst64_term_desc(terms, r));
808✔
3379
        break;
808✔
3380

3381
      case BV_CONSTANT:
18✔
3382
        u = map_bvconst_to_eterm(ctx, bvconst_term_desc(terms, r));
18✔
3383
        break;
18✔
3384

3385
      case VARIABLE:
×
3386
        exception = FREE_VARIABLE_IN_FORMULA;
×
3387
        goto abort;
×
3388

3389
      case UNINTERPRETED_TERM:
12,051✔
3390
        u = pos_occ(make_egraph_variable(ctx, tau));
12,051✔
3391
        //        add_type_constraints(ctx, u, tau);
3392
        break;
12,051✔
3393

3394
      case ARITH_FLOOR:
×
3395
        assert(is_integer_type(tau));
3396
        x = map_floor_to_arith(ctx, arith_floor_arg(terms, r));
×
3397
        u = translate_arithvar_to_eterm(ctx, x);
×
3398
        break;
×
3399

3400
      case ARITH_CEIL:
×
3401
        assert(is_integer_type(tau));
3402
        x = map_ceil_to_arith(ctx, arith_ceil_arg(terms, r));
×
3403
        u = translate_arithvar_to_eterm(ctx, x);
×
3404
        break;
×
3405

3406
      case ARITH_ABS:
×
3407
        x = map_abs_to_arith(ctx, arith_abs_arg(terms, r));
×
3408
        u = translate_arithvar_to_eterm(ctx, x);
×
3409
        break;
×
3410

3411
      case ITE_TERM:
2,168✔
3412
      case ITE_SPECIAL:
3413
        u = map_ite_to_eterm(ctx, ite_term_desc(terms, r), tau);
2,168✔
3414
        break;
2,168✔
3415

3416
      case APP_TERM:
6,531✔
3417
        u = map_apply_to_eterm(ctx, app_term_desc(terms, r), tau);
6,531✔
3418
        break;
6,531✔
3419

3420
      case ARITH_RDIV:
×
3421
        assert(is_arithmetic_type(tau));
3422
        x = map_rdiv_to_arith(ctx, arith_rdiv_term_desc(terms, r));
×
3423
        u = translate_arithvar_to_eterm(ctx, x);
×
3424
        break;
×
3425

3426
      case ARITH_IDIV:
×
3427
        assert(is_integer_type(tau));
3428
        x = map_idiv_to_arith(ctx, arith_idiv_term_desc(terms, r));
×
3429
        u = translate_arithvar_to_eterm(ctx, x); // (div t u) has type int
×
3430
        break;
×
3431

3432
      case ARITH_MOD:
2✔
3433
        x = map_mod_to_arith(ctx, arith_mod_term_desc(terms, r));
2✔
3434
        u = translate_arithvar_to_eterm(ctx, x);
2✔
3435
        break;
2✔
3436

3437
      case TUPLE_TERM:
190✔
3438
        u = map_tuple_to_eterm(ctx, tuple_term_desc(terms, r), tau);
190✔
3439
        break;
190✔
3440

3441
      case SELECT_TERM:
245✔
3442
        u = map_select_to_eterm(ctx, select_term_desc(terms, r), tau);
245✔
3443
        break;
245✔
3444

3445
      case UPDATE_TERM:
11,470✔
3446
        u = map_update_to_eterm(ctx, update_term_desc(terms, r), tau);
11,470✔
3447
        break;
11,470✔
3448

3449
      case LAMBDA_TERM:
1✔
3450
        // not ready for lambda terms yet:
3451
        exception = LAMBDAS_NOT_SUPPORTED;
1✔
3452
        goto abort;
1✔
3453

3454
      case BV_ARRAY:
1,711✔
3455
        x = map_bvarray_to_bv(ctx, bvarray_term_desc(terms, r));
1,711✔
3456
        u = translate_thvar_to_eterm(ctx, x, tau);
1,711✔
3457
        break;
1,711✔
3458

3459
      case BV_DIV:
1✔
3460
        x = map_bvdiv_to_bv(ctx, bvdiv_term_desc(terms, r));
1✔
3461
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3462
        break;
1✔
3463

3464
      case BV_REM:
2✔
3465
        x = map_bvrem_to_bv(ctx, bvrem_term_desc(terms, r));
2✔
3466
        u = translate_thvar_to_eterm(ctx, x, tau);
2✔
3467
        break;
2✔
3468

3469
      case BV_SDIV:
1✔
3470
        x = map_bvsdiv_to_bv(ctx, bvsdiv_term_desc(terms, r));
1✔
3471
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3472
        break;
1✔
3473

3474
      case BV_SREM:
1✔
3475
        x = map_bvsrem_to_bv(ctx, bvsrem_term_desc(terms, r));
1✔
3476
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3477
        break;
1✔
3478

3479
      case BV_SMOD:
×
3480
        x = map_bvsmod_to_bv(ctx, bvsmod_term_desc(terms, r));
×
3481
        u = translate_thvar_to_eterm(ctx, x, tau);
×
3482
        break;
×
3483

3484
      case BV_SHL:
×
3485
        x = map_bvshl_to_bv(ctx, bvshl_term_desc(terms, r));
×
3486
        u = translate_thvar_to_eterm(ctx, x, tau);
×
3487
        break;
×
3488

3489
      case BV_LSHR:
1✔
3490
        x = map_bvlshr_to_bv(ctx, bvlshr_term_desc(terms, r));
1✔
3491
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3492
        break;
1✔
3493

3494
      case BV_ASHR:
1✔
3495
        x = map_bvashr_to_bv(ctx, bvashr_term_desc(terms, r));
1✔
3496
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3497
        break;
1✔
3498

3499
      case POWER_PRODUCT:
1✔
3500
        if (is_arithmetic_type(tau)) {
1✔
3501
          x = map_pprod_to_arith(ctx, pprod_term_desc(terms, r));
×
3502
        } else {
3503
          assert(is_bv_type(ctx->types, tau));
3504
          x = map_pprod_to_bv(ctx, pprod_term_desc(terms, r));
1✔
3505
        }
3506
        u = translate_thvar_to_eterm(ctx, x, tau);
1✔
3507
        break;
1✔
3508

3509
      case ARITH_POLY:
619✔
3510
        x = map_poly_to_arith(ctx, poly_term_desc(terms, r));
619✔
3511
        u = translate_thvar_to_eterm(ctx, x, tau);
619✔
3512
        break;
619✔
3513

3514
      case BV64_POLY:
1,008✔
3515
        x = map_bvpoly64_to_bv(ctx, bvpoly64_term_desc(terms, r));
1,008✔
3516
        u = translate_thvar_to_eterm(ctx, x, tau);
1,008✔
3517
        break;
1,008✔
3518

3519
      case BV_POLY:
2✔
3520
        x = map_bvpoly_to_bv(ctx, bvpoly_term_desc(terms, r));
2✔
3521
        u = translate_thvar_to_eterm(ctx, x, tau);
2✔
3522
        break;
2✔
3523

3524
      default:
×
3525
        exception = INTERNAL_ERROR;
×
3526
        goto abort;
×
3527
      }
3528

3529
      // store the mapping r --> u
3530
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
38,334✔
3531
    }
3532
  }
3533

3534
  // If we canonicalized root to a different unit-type representative r,
3535
  // remember that root internalizes to the same egraph occurrence.
3536
  if (root != r) {
103,353✔
3537
    if (intern_tbl_root_is_free(&ctx->intern, root)) {
1✔
3538
      intern_tbl_map_root(&ctx->intern, root, occ2code(u));
1✔
3539
    } else {
3540
      // If root was mapped during the recursive internalization of r (e.g.,
3541
      // because root was reached as a sub-term), the mapping must agree
3542
      // with the occurrence we are about to return.
3543
      assert(intern_tbl_map_of_root(&ctx->intern, root) == occ2code(u));  // LCOV_EXCL_LINE - consistency check, unreachable on well-formed inputs
3544
    }
3545
  }
3546

3547
  // fix the polarity
3548
  return u ^ polarity;
103,353✔
3549

3550
 abort:
1✔
3551
  longjmp(ctx->env, exception);
1✔
3552
}
3553

3554

3555

3556

3557
/****************************************
3558
 *  CONVERSION TO ARITHMETIC VARIABLES  *
3559
 ***************************************/
3560

3561
/*
3562
 * Translate internalization code x to an arithmetic variable
3563
 * - if the code is for an egraph term u, then we return the
3564
 *   theory variable attached to u in the egraph.
3565
 * - otherwise, x must be the code of an arithmetic variable v,
3566
 *   we return v.
3567
 */
3568
static thvar_t translate_code_to_arith(context_t *ctx, int32_t x) {
99,882✔
3569
  eterm_t u;
3570
  thvar_t v;
3571

3572
  assert(code_is_valid(x));
3573

3574
  if (code_is_eterm(x)) {
99,882✔
3575
    u = code2eterm(x);
6,521✔
3576
    assert(ctx->egraph != NULL && egraph_term_is_arith(ctx->egraph, u));
3577
    v = egraph_term_base_thvar(ctx->egraph, u);
6,521✔
3578
  } else {
3579
    v = code2thvar(x);
93,361✔
3580
  }
3581

3582
  assert(v != null_thvar);
3583
  return v;
99,882✔
3584
}
3585

3586

3587
static thvar_t internalize_to_arith(context_t *ctx, term_t t) {
120,807✔
3588
  term_table_t *terms;
3589
  int32_t exception;
3590
  int32_t code;
3591
  term_t r;
3592
  occ_t u;
3593
  thvar_t x;
3594

3595
  assert(is_arithmetic_term(ctx->terms, t));
3596

3597
  if (! context_has_arith_solver(ctx)) {
120,807✔
3598
    exception = ARITH_NOT_SUPPORTED;
×
3599
    goto abort;
×
3600
  }
3601

3602
  /*
3603
   * Apply term substitution: t --> r
3604
   */
3605
  r = intern_tbl_get_root(&ctx->intern, t);
120,807✔
3606
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
120,807✔
3607
    /*
3608
     * r already internalized
3609
     */
3610
    code = intern_tbl_map_of_root(&ctx->intern, r);
99,723✔
3611
    x = translate_code_to_arith(ctx, code);
99,723✔
3612

3613
  } else {
3614
    /*
3615
     * Compute the internalization
3616
     */
3617
    terms = ctx->terms;
21,084✔
3618

3619
    switch (term_kind(terms, r)) {
21,084✔
3620
    case ARITH_CONSTANT:
1,270✔
3621
      x = ctx->arith.create_const(ctx->arith_solver, rational_term_desc(terms, r));
1,270✔
3622
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
1,270✔
3623
      break;
1,270✔
3624

3625
    case UNINTERPRETED_TERM:
15,389✔
3626
      x = ctx->arith.create_var(ctx->arith_solver, is_integer_root(ctx, r));
15,389✔
3627
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
15,389✔
3628
      //      printf("mapping: %s --> i!%d\n", term_name(ctx->terms, r), (int) x);
3629
      //      fflush(stdout);
3630
      break;
15,389✔
3631

3632
    case ARITH_FLOOR:
×
3633
      x = map_floor_to_arith(ctx, arith_floor_arg(terms, r));
×
3634
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3635
      break;
×
3636

3637
    case ARITH_CEIL:
×
3638
      x = map_ceil_to_arith(ctx, arith_ceil_arg(terms, r));
×
3639
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3640
      break;
×
3641

3642
    case ARITH_ABS:
4✔
3643
      x = map_abs_to_arith(ctx, arith_abs_arg(terms, r));
4✔
3644
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
4✔
3645
      break;
4✔
3646

3647
    case ITE_TERM:
2,230✔
3648
      x = map_ite_to_arith(ctx, ite_term_desc(terms, r), is_integer_root(ctx, r));
2,230✔
3649
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
2,230✔
3650
      break;
2,230✔
3651

3652
    case ITE_SPECIAL:
793✔
3653
      x = map_ite_to_arith(ctx, ite_term_desc(terms, r), is_integer_root(ctx, r));
793✔
3654
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
793✔
3655
      if (context_ite_bounds_enabled(ctx)) {
793✔
3656
        assert_ite_bounds(ctx, r, x);
793✔
3657
      }
3658
      break;
793✔
3659

3660
    case APP_TERM:
702✔
3661
      u = map_apply_to_eterm(ctx, app_term_desc(terms, r), type_of_root(ctx, r));
702✔
3662
      assert(egraph_term_is_arith(ctx->egraph, term_of_occ(u)));
3663
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
702✔
3664
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
702✔
3665
      assert(x != null_thvar);
3666
      break;
702✔
3667

3668
    case ARITH_RDIV:
3✔
3669
      x = map_rdiv_to_arith(ctx, arith_rdiv_term_desc(terms, r));
3✔
3670
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3671
      break;
×
3672

3673
    case ARITH_IDIV:
6✔
3674
      x = map_idiv_to_arith(ctx, arith_idiv_term_desc(terms, r));
6✔
3675
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
6✔
3676
      break;
6✔
3677

3678
    case ARITH_MOD:
9✔
3679
      x = map_mod_to_arith(ctx, arith_mod_term_desc(terms, r));
9✔
3680
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
9✔
3681
      break;
9✔
3682

3683
    case SELECT_TERM:
×
3684
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), type_of_root(ctx, r));
×
3685
      assert(egraph_term_is_arith(ctx->egraph, term_of_occ(u)));
3686
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3687
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
×
3688
      assert(x != null_thvar);
3689
      break;
×
3690

3691
    case POWER_PRODUCT:
×
3692
      x = map_pprod_to_arith(ctx, pprod_term_desc(terms, r));
×
3693
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3694
      break;
×
3695

3696
    case ARITH_POLY:
678✔
3697
      x = map_poly_to_arith(ctx, poly_term_desc(terms, r));
678✔
3698
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
678✔
3699
      break;
678✔
3700

3701
    case VARIABLE:
×
3702
      exception = FREE_VARIABLE_IN_FORMULA;
×
3703
      goto abort;
×
3704

3705
    default:
×
3706
      exception = INTERNAL_ERROR;
×
3707
      goto abort;
×
3708
    }
3709

3710
  }
3711

3712
  if (ctx->mcsat_supplement && ctx->egraph != NULL &&
120,804✔
3713
      !context_is_mcsat_relax_abstraction(ctx, unsigned_term(r))) {
21✔
3714
    egraph_arith_observer_register_arith_term(ctx->egraph, x, unsigned_term(r));
5✔
3715
  }
3716

3717
  return x;
120,804✔
3718

3719
 abort:
×
3720
  longjmp(ctx->env, exception);
×
3721
}
3722

3723

3724

3725
/***************************************
3726
 *  CONVERSION TO BITVECTOR VARIABLES  *
3727
 **************************************/
3728

3729
/*
3730
 * Translate internalization code x to a bitvector variable
3731
 * - if x is for an egraph term u, then we return the theory variable
3732
 *   attached to u in the egraph.
3733
 * - otherwise, x must be the code of a bitvector variable v, so we return v.
3734
 */
3735
static thvar_t translate_code_to_bv(context_t *ctx, int32_t x) {
299,218✔
3736
  eterm_t u;
3737
  thvar_t v;
3738

3739
  assert(code_is_valid(x));
3740

3741
  if (code_is_eterm(x)) {
299,218✔
3742
    u = code2eterm(x);
29,164✔
3743
    assert(ctx->egraph != NULL && egraph_term_is_bv(ctx->egraph, u));
3744
    v = egraph_term_base_thvar(ctx->egraph, u);
29,164✔
3745
  } else {
3746
    v = code2thvar(x);
270,054✔
3747
  }
3748

3749
  assert(v != null_thvar);
3750

3751
  return v;
299,218✔
3752
}
3753

3754
/*
3755
 * Place holders for now
3756
 */
3757
static thvar_t internalize_to_bv(context_t *ctx, term_t t) {
376,326✔
3758
  term_table_t *terms;
3759
  int32_t exception;
3760
  int32_t code;
3761
  term_t r;
3762
  occ_t u;
3763
  thvar_t x;
3764

3765
  assert(is_bitvector_term(ctx->terms, t));
3766

3767
  if (! context_has_bv_solver(ctx)) {
376,326✔
3768
    exception = BV_NOT_SUPPORTED;
×
3769
    goto abort;
×
3770
  }
3771

3772
  /*
3773
   * Apply the term substitution: t --> r
3774
   */
3775
  r = intern_tbl_get_root(&ctx->intern, t);
376,326✔
3776
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
376,326✔
3777
    // r is already internalized
3778
    code = intern_tbl_map_of_root(&ctx->intern, r);
299,218✔
3779
    x = translate_code_to_bv(ctx, code);
299,218✔
3780
  } else {
3781
    // compute r's internalization
3782
    terms = ctx->terms;
77,108✔
3783

3784
    switch (term_kind(terms, r)) {
77,108✔
3785
    case BV64_CONSTANT:
7,020✔
3786
      x = ctx->bv.create_const64(ctx->bv_solver, bvconst64_term_desc(terms, r));
7,020✔
3787
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
7,020✔
3788
      break;
7,020✔
3789

3790
    case BV_CONSTANT:
440✔
3791
      x = ctx->bv.create_const(ctx->bv_solver, bvconst_term_desc(terms, r));
440✔
3792
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
440✔
3793
      break;
440✔
3794

3795
    case UNINTERPRETED_TERM:
16,445✔
3796
      x = ctx->bv.create_var(ctx->bv_solver, term_bitsize(terms, r));
16,445✔
3797
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
16,445✔
3798
      break;
16,445✔
3799

3800
    case ITE_TERM:
20,779✔
3801
    case ITE_SPECIAL:
3802
      x = map_ite_to_bv(ctx, ite_term_desc(terms, r));
20,779✔
3803
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
20,779✔
3804
      break;
20,779✔
3805

3806
    case APP_TERM:
2,452✔
3807
      u = map_apply_to_eterm(ctx, app_term_desc(terms, r), type_of_root(ctx, r));
2,452✔
3808
      assert(egraph_term_is_bv(ctx->egraph, term_of_occ(u)));
3809
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
2,452✔
3810
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
2,452✔
3811
      assert(x != null_thvar);
3812
      break;
2,452✔
3813

3814
    case BV_ARRAY:
15,326✔
3815
      x = map_bvarray_to_bv(ctx, bvarray_term_desc(terms, r));
15,326✔
3816
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
15,326✔
3817
      break;
15,326✔
3818

3819
    case BV_DIV:
96✔
3820
      x = map_bvdiv_to_bv(ctx, bvdiv_term_desc(terms, r));
96✔
3821
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
96✔
3822
      break;
96✔
3823

3824
    case BV_REM:
175✔
3825
      x = map_bvrem_to_bv(ctx, bvrem_term_desc(terms, r));
175✔
3826
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
175✔
3827
      break;
175✔
3828

3829
    case BV_SDIV:
86✔
3830
      x = map_bvsdiv_to_bv(ctx, bvsdiv_term_desc(terms, r));
86✔
3831
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
86✔
3832
      break;
86✔
3833

3834
    case BV_SREM:
76✔
3835
      x = map_bvsrem_to_bv(ctx, bvsrem_term_desc(terms, r));
76✔
3836
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
76✔
3837
      break;
76✔
3838

3839
    case BV_SMOD:
×
3840
      x = map_bvsmod_to_bv(ctx, bvsmod_term_desc(terms, r));
×
3841
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
×
3842
      break;
×
3843

3844
    case BV_SHL:
85✔
3845
      x = map_bvshl_to_bv(ctx, bvshl_term_desc(terms, r));
85✔
3846
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
85✔
3847
      break;
85✔
3848

3849
    case BV_LSHR:
1,427✔
3850
      x = map_bvlshr_to_bv(ctx, bvlshr_term_desc(terms, r));
1,427✔
3851
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
1,427✔
3852
      break;
1,427✔
3853

3854
    case BV_ASHR:
295✔
3855
      x = map_bvashr_to_bv(ctx, bvashr_term_desc(terms, r));
295✔
3856
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
295✔
3857
      break;
295✔
3858

3859
    case SELECT_TERM:
×
3860
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), type_of_root(ctx, r));
×
3861
      assert(egraph_term_is_bv(ctx->egraph, term_of_occ(u)));
3862
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
3863
      x = egraph_term_base_thvar(ctx->egraph, term_of_occ(u));
×
3864
      assert(x != null_thvar);
3865
      break;
×
3866

3867
    case POWER_PRODUCT:
584✔
3868
      x = map_pprod_to_bv(ctx, pprod_term_desc(terms, r));
584✔
3869
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
584✔
3870
      break;
584✔
3871

3872
    case BV64_POLY:
11,217✔
3873
      x = map_bvpoly64_to_bv(ctx, bvpoly64_term_desc(terms, r));
11,217✔
3874
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
11,217✔
3875
      break;
11,217✔
3876

3877
    case BV_POLY:
605✔
3878
      x = map_bvpoly_to_bv(ctx, bvpoly_term_desc(terms, r));
605✔
3879
      intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
605✔
3880
      break;
605✔
3881

3882
    case VARIABLE:
×
3883
      exception = FREE_VARIABLE_IN_FORMULA;
×
3884
      goto abort;
×
3885

3886
    default:
×
3887
      exception = INTERNAL_ERROR;
×
3888
      goto abort;
×
3889
    }
3890
  }
3891

3892
  return x;
376,326✔
3893

3894
 abort:
×
3895
  longjmp(ctx->env, exception);
×
3896
}
3897

3898

3899

3900

3901

3902

3903
/****************************
3904
 *  CONVERSION TO LITERALS  *
3905
 ***************************/
3906

3907
/*
3908
 * Translate an internalization code x to a literal
3909
 * - if x is the code of an egraph occurrence u, we return the
3910
 *   theory variable for u in the egraph
3911
 * - otherwise, x should be the code of a literal l in the core
3912
 */
3913
static literal_t translate_code_to_literal(context_t *ctx, int32_t x) {
1,397,372✔
3914
  occ_t u;
3915
  literal_t l;
3916

3917
  assert(code_is_valid(x));
3918
  if (code_is_eterm(x)) {
1,397,372✔
3919
    u = code2occ(x);
129,809✔
3920
    if (term_of_occ(u) == true_eterm) {
129,809✔
3921
      l = mk_lit(const_bvar, polarity_of(u));
129,809✔
3922

3923
      assert((u == true_occ && l == true_literal) ||
3924
             (u == false_occ && l == false_literal));
3925
    } else {
3926
      assert(ctx->egraph != NULL);
3927
      l = egraph_occ2literal(ctx->egraph, u);
×
3928
    }
3929
  } else {
3930
    l = code2literal(x);
1,267,563✔
3931
  }
3932

3933
  return l;
1,397,372✔
3934
}
3935

3936
static literal_t internalize_to_literal(context_t *ctx, term_t t) {
1,825,216✔
3937
  term_table_t *terms;
3938
  int32_t code;
3939
  uint32_t polarity;
3940
  term_t r;
3941
  literal_t l;
3942
  occ_t u;
3943

3944
  assert(is_boolean_term(ctx->terms, t));
3945

3946
  r = intern_tbl_get_root(&ctx->intern, t);
1,825,216✔
3947
  polarity = polarity_of(r);
1,825,216✔
3948
  r = unsigned_term(r);
1,825,216✔
3949

3950
  /*
3951
   * At this point:
3952
   * 1) r is a positive root in the internalization table
3953
   * 2) polarity is 1 or 0
3954
   * 3) if polarity is 0, then t is equal to r by substitution
3955
   *    if polarity is 1, then t is equal to (not r)
3956
   *
3957
   * We get l := internalization of r
3958
   * then return l or (not l) depending on polarity.
3959
   */
3960

3961
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
1,825,216✔
3962
    /*
3963
     * r already internalized
3964
     */
3965
    code = intern_tbl_map_of_root(&ctx->intern, r);
1,397,372✔
3966
    l = translate_code_to_literal(ctx, code);
1,397,372✔
3967

3968
  } else {
3969
    /*
3970
     * Recursively compute r's internalization
3971
     */
3972
    if (context_atom_requires_mcsat(ctx, r)) {
427,844✔
3973
      l = map_mcsat_atom_to_literal(ctx, r);
3✔
3974
      intern_tbl_map_root(&ctx->intern, r, literal2code(l));
3✔
3975
      goto done;
3✔
3976
    }
3977

3978
    terms = ctx->terms;
427,841✔
3979
    switch (term_kind(terms, r)) {
427,841✔
3980
    case CONSTANT_TERM:
×
3981
      assert(r == true_term);
3982
      l = true_literal;
×
3983
      break;
×
3984

3985
    case VARIABLE:
×
3986
      longjmp(ctx->env, FREE_VARIABLE_IN_FORMULA);
×
3987
      break;
3988

3989
    case UNINTERPRETED_TERM:
6,410✔
3990
      l = pos_lit(create_boolean_variable(ctx->core));
6,410✔
3991
      break;
6,410✔
3992

3993
    case ITE_TERM:
1,863✔
3994
    case ITE_SPECIAL:
3995
      l = map_ite_to_literal(ctx, ite_term_desc(terms, r));
1,863✔
3996
      break;
1,863✔
3997

3998
    case EQ_TERM:
14,519✔
3999
      l = map_eq_to_literal(ctx, eq_term_desc(terms, r));
14,519✔
4000
      break;
14,519✔
4001

4002
    case OR_TERM:
81,300✔
4003
      l = map_or_to_literal(ctx, or_term_desc(terms, r));
81,300✔
4004
      break;
81,300✔
4005

4006
    case XOR_TERM:
1✔
4007
      l = map_xor_to_literal(ctx, xor_term_desc(terms, r));
1✔
4008
      break;
1✔
4009

4010
    case ARITH_IS_INT_ATOM:
×
4011
      l = map_arith_is_int_to_literal(ctx, arith_is_int_arg(terms, r));
×
4012
      break;
×
4013

4014
    case ARITH_EQ_ATOM:
2,249✔
4015
      l = map_arith_eq_to_literal(ctx, arith_eq_arg(terms, r));
2,249✔
4016
      break;
2,249✔
4017

4018
    case ARITH_GE_ATOM:
33,841✔
4019
      l = map_arith_geq_to_literal(ctx, arith_ge_arg(terms, r));
33,841✔
4020
      break;
33,841✔
4021

4022
    case ARITH_BINEQ_ATOM:
8,967✔
4023
      l = map_arith_bineq_to_literal(ctx, arith_bineq_atom_desc(terms, r));
8,967✔
4024
      break;
8,967✔
4025

4026
    case ARITH_DIVIDES_ATOM:
8✔
4027
      l = map_arith_divides_to_literal(ctx, arith_divides_atom_desc(terms, r));
8✔
4028
      break;
8✔
4029

NEW
4030
    case ARITH_ROOT_ATOM:
×
NEW
4031
      longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
4032
      break;
4033

NEW
4034
    case ARITH_FF_EQ_ATOM:
×
4035
    case ARITH_FF_BINEQ_ATOM:
NEW
4036
      longjmp(ctx->env, CONTEXT_UNSUPPORTED_THEORY);
×
4037
      break;
4038

4039
    case APP_TERM:
4,368✔
4040
      l = map_apply_to_literal(ctx, app_term_desc(terms, r));
4,368✔
4041
      break;
4,368✔
4042

4043
    case SELECT_TERM:
×
4044
      u = map_select_to_eterm(ctx, select_term_desc(terms, r), bool_type(ctx->types));
×
4045
      assert(egraph_term_is_bool(ctx->egraph, term_of_occ(u)));
4046
      intern_tbl_map_root(&ctx->intern, r, occ2code(u));
×
4047
      l = egraph_occ2literal(ctx->egraph, u);
×
4048
      // we don't want to map r to l here
4049
      goto done;
×
4050

4051
    case DISTINCT_TERM:
9✔
4052
      l = map_distinct_to_literal(ctx, distinct_term_desc(terms, r));
9✔
4053
      break;
9✔
4054

4055
    case FORALL_TERM:
×
4056
      if (context_in_strict_mode(ctx)) {
×
4057
        longjmp(ctx->env, QUANTIFIERS_NOT_SUPPORTED);
×
4058
      }
4059
      // lax mode: turn forall into a proposition
4060
      l = pos_lit(create_boolean_variable(ctx->core));
×
4061
      break;
×
4062

4063
    case BIT_TERM:
264,228✔
4064
      l = map_bit_select_to_literal(ctx, bit_term_desc(terms, r));
264,228✔
4065
      break;
264,228✔
4066

4067
    case BV_EQ_ATOM:
4,869✔
4068
      l = map_bveq_to_literal(ctx, bveq_atom_desc(terms, r));
4,869✔
4069
      break;
4,869✔
4070

4071
    case BV_GE_ATOM:
2,302✔
4072
      l = map_bvge_to_literal(ctx, bvge_atom_desc(terms, r));
2,302✔
4073
      break;
2,302✔
4074

4075
    case BV_SGE_ATOM:
2,907✔
4076
      l = map_bvsge_to_literal(ctx, bvsge_atom_desc(terms, r));
2,907✔
4077
      break;
2,907✔
4078

4079
    default:
×
4080
      longjmp(ctx->env, INTERNAL_ERROR);
×
4081
      break;
4082
    }
4083

4084
    if (ctx->mcsat_supplement) {
427,841✔
4085
      context_observe_mcsat_atom(ctx, r, l);
4✔
4086
    }
4087

4088
    // map r to l in the internalization table
4089
    intern_tbl_map_root(&ctx->intern, r, literal2code(l));
427,841✔
4090
  }
4091

4092
 done:
1,825,216✔
4093
  return l ^ polarity;
1,825,216✔
4094
}
4095

4096

4097

4098
/******************************************************
4099
 *  TOP-LEVEL ASSERTIONS: TERMS ALREADY INTERNALIZED  *
4100
 *****************************************************/
4101

4102
/*
4103
 * Assert (x == tt) for an internalization code x
4104
 */
4105
static void assert_internalization_code(context_t *ctx, int32_t x, bool tt) {
926✔
4106
  occ_t g;
4107
  literal_t l;
4108

4109
  assert(code_is_valid(x));
4110

4111
  if (code_is_eterm(x)) {
926✔
4112
    // normalize to assertion (g == true)
4113
    g = code2occ(x);
10✔
4114
    if (! tt) g = opposite_occ(g);
10✔
4115

4116
    // We must deal with 'true_occ/false_occ' separately
4117
    // since they may be used even if there's no actual egraph.
4118
    if (g == false_occ) {
10✔
4119
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
4120
    } else if (g != true_occ) {
6✔
4121
      assert(ctx->egraph != NULL);
4122
      if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
×
4123
        egraph_assert_axiom(ctx->egraph, g);
×
4124
      } else {
4125
        l = egraph_make_eq(ctx->egraph, g, true_occ);
×
4126
        add_unit_clause(ctx->core, l);
×
4127
      }
4128
    }
4129
  } else {
4130
    l = code2literal(x);
916✔
4131
    if (! tt) l = not(l);
916✔
4132
    add_unit_clause(ctx->core, l);
916✔
4133
  }
4134
}
922✔
4135

4136
/*
4137
 * Assert t == true where t is a term that's already mapped
4138
 * either to a literal or to an egraph occurrence.
4139
 * - t must be a root in the internalization table
4140
 */
4141
static void assert_toplevel_intern(context_t *ctx, term_t t) {
739✔
4142
  int32_t code;
4143
  bool tt;
4144

4145
  assert(is_boolean_term(ctx->terms, t) &&
4146
         intern_tbl_is_root(&ctx->intern, t) &&
4147
         intern_tbl_root_is_mapped(&ctx->intern, t));
4148

4149
  tt = is_pos_term(t);
739✔
4150
  t = unsigned_term(t);
739✔
4151
  code = intern_tbl_map_of_root(&ctx->intern, t);
739✔
4152

4153
  assert_internalization_code(ctx, code, tt);
739✔
4154
}
739✔
4155

4156

4157

4158

4159

4160

4161

4162
/********************************
4163
 *   ARITHMETIC SUBSTITUTIONS   *
4164
 *******************************/
4165

4166
/*
4167
 * TODO: improve this in the integer case:
4168
 * - all_int is based on p's type in the term table and does
4169
 *   not take the context's substitutions into account.
4170
 * - integral_poly_after_div requires all coefficients
4171
 *   to be integer. This could be generalized to polynomials
4172
 *   with integer variables and rational coefficients.
4173
 */
4174

4175
/*
4176
 * Check whether term t can be eliminated by an arithmetic substitution
4177
 * - t's root must be uninterpreted and not internalized yet
4178
 */
4179
static bool is_elimination_candidate(context_t *ctx, term_t t) {
2,742✔
4180
  term_t r;
4181

4182
  r = intern_tbl_get_root(&ctx->intern, t);
2,742✔
4183
  return intern_tbl_root_is_free(&ctx->intern, r);
2,742✔
4184
}
4185

4186

4187
/*
4188
 * Replace every variable of t by the root of t in the internalization table
4189
 * - the result is stored in buffer
4190
 */
4191
static void apply_renaming_to_poly(context_t *ctx, polynomial_t *p,  poly_buffer_t *buffer) {
544✔
4192
  uint32_t i, n;
4193
  term_t t;
4194

4195
  reset_poly_buffer(buffer);
544✔
4196

4197
  assert(poly_buffer_is_zero(buffer));
4198

4199
  n = p->nterms;
544✔
4200
  for (i=0; i<n; i++) {
2,599✔
4201
    t = p->mono[i].var;
2,055✔
4202
    if (t == const_idx) {
2,055✔
4203
      poly_buffer_add_const(buffer, &p->mono[i].coeff);
180✔
4204
    } else {
4205
      // replace t by its root
4206
      t = intern_tbl_get_root(&ctx->intern, t);
1,875✔
4207
      poly_buffer_addmul_term(ctx->terms, buffer, t, &p->mono[i].coeff);
1,875✔
4208
    }
4209
  }
4210

4211
  normalize_poly_buffer(buffer);
544✔
4212
}
544✔
4213

4214

4215
/*
4216
 * Auxiliary function: check whether p/a is an integral polynomial
4217
 * assuming all variables and coefficients of p are integer.
4218
 * - check whether all coefficients are multiple of a
4219
 * - a must be non-zero
4220
 */
4221
static bool integralpoly_after_div(poly_buffer_t *buffer, rational_t *a) {
318✔
4222
  uint32_t i, n;
4223

4224
  if (q_is_one(a) || q_is_minus_one(a)) {
318✔
4225
    return true;
265✔
4226
  }
4227

4228
  n = buffer->nterms;
53✔
4229
  for (i=0; i<n; i++) {
64✔
4230
    if (! q_divides(a, &buffer->mono[i].coeff)) return false;
63✔
4231
  }
4232
  return true;
1✔
4233
}
4234

4235

4236
/*
4237
 * Check whether a top-level assertion (p == 0) can be
4238
 * rewritten (t == q) where t is not internalized yet.
4239
 * - all_int is true if p is an integer polynomial (i.e.,
4240
 *   all coefficients and all terms of p are integer).
4241
 * - p = input polynomial
4242
 * - return t or null_term if no adequate t is found
4243
 */
4244
static term_t try_poly_substitution(context_t *ctx, poly_buffer_t *buffer, bool all_int) {
544✔
4245
  uint32_t i, n;
4246
  term_t t;
4247

4248
  // check for a free variable in buffer
4249
  n = buffer->nterms;
544✔
4250
  for (i=0; i<n; i++) {
1,128✔
4251
    t = buffer->mono[i].var;
1,049✔
4252
    if (t != const_idx && is_elimination_candidate(ctx, t)) {
1,049✔
4253
      if (in_real_class(ctx, t) ||
518✔
4254
          (all_int && integralpoly_after_div(buffer, &buffer->mono[i].coeff))) {
318✔
4255
        // t is candidate for elimination
4256
        return t;
465✔
4257
      }
4258
    }
4259
  }
4260

4261
  return NULL_TERM;
79✔
4262
}
4263

4264

4265
/*
4266
 * Build polynomial - p/a + x in the context's aux_poly buffer
4267
 * where a = coefficient of x in p
4268
 * - x must occur in p
4269
 */
4270
static polynomial_t *build_poly_substitution(context_t *ctx, poly_buffer_t *buffer, term_t x) {
465✔
4271
  polynomial_t *q;
4272
  monomial_t *mono;
4273
  uint32_t i, n;
4274
  term_t y;
4275
  rational_t *a;
4276

4277
  n = buffer->nterms;
465✔
4278

4279
  // first get coefficient of x in buffer
4280
  a = NULL; // otherwise GCC complains
465✔
4281
  for (i=0; i<n; i++) {
2,283✔
4282
    y = buffer->mono[i].var;
1,818✔
4283
    if (y == x) {
1,818✔
4284
      a = &buffer->mono[i].coeff;
465✔
4285
    }
4286
  }
4287
  assert(a != NULL && n > 0);
4288

4289
  q = context_get_aux_poly(ctx, n);
465✔
4290
  q->nterms = n-1;
465✔
4291
  mono = q->mono;
465✔
4292

4293
  // compute - buffer/a (but skip monomial a.x)
4294
  for (i=0; i<n; i++) {
2,283✔
4295
    y = buffer->mono[i].var;
1,818✔
4296
    if (y != x) {
1,818✔
4297
      mono->var = y;
1,353✔
4298
      q_set_neg(&mono->coeff, &buffer->mono[i].coeff);
1,353✔
4299
      q_div(&mono->coeff, a);
1,353✔
4300
      mono ++;
1,353✔
4301
    }
4302
  }
4303

4304
  // end marker
4305
  mono->var = max_idx;
465✔
4306

4307
  return q;
465✔
4308
}
4309

4310

4311

4312
/*
4313
 * Try to eliminate a toplevel equality (p == 0) by variable substitution:
4314
 * - i.e., try to rewrite p == 0 into (x - q) == 0 where x is a free variable
4315
 *   then store the substitution x --> q in the internalization table.
4316
 * - all_int is true if p is an integer polynomial (i.e., all variables and all
4317
 *   coefficients of p are integer)
4318
 *
4319
 * - return true if the elimination succeeds
4320
 * - return false otherwise
4321
 */
4322
static bool try_arithvar_elim(context_t *ctx, polynomial_t *p, bool all_int) {
544✔
4323
  poly_buffer_t *buffer;
4324
  polynomial_t *q;
4325
  uint32_t i, n;
4326
  term_t t, u, r;
4327
  thvar_t x;
4328

4329
  /*
4330
   * First pass: internalize every term of p that's not a variable
4331
   * - we do that first to avoid circular substitutions (occurs-check)
4332
   */
4333
  n = p->nterms;
544✔
4334
  for (i=0; i<n; i++) {
2,599✔
4335
    t = p->mono[i].var;
2,055✔
4336
    if (t != const_idx && ! is_elimination_candidate(ctx, t)) {
2,055✔
4337
      (void) internalize_to_arith(ctx, t);
599✔
4338
    }
4339
  }
4340

4341

4342
  /*
4343
   * Apply variable renaming: this is to avoid circularities
4344
   * if p is of the form ... + a x + ... + b y + ...
4345
   * where both x and y are variables in the same class (i.e.,
4346
   * both are elimination candidates).
4347
   */
4348
  buffer = context_get_poly_buffer(ctx);
544✔
4349
  apply_renaming_to_poly(ctx, p, buffer);
544✔
4350

4351
  /*
4352
   * Search for a variable to substitute
4353
   */
4354
  u = try_poly_substitution(ctx, buffer, all_int);
544✔
4355
  if (u == NULL_TERM) {
544✔
4356
    return false; // no substitution found
79✔
4357
  }
4358

4359
  /*
4360
   * buffer is of the form a.u + p0, we rewrite (buffer == 0) to (u == q)
4361
   * where q = -1/a * p0
4362
   */
4363
  q = build_poly_substitution(ctx, buffer, u); // q is in ctx->aux_poly
465✔
4364

4365
  // convert q to a theory variable in the arithmetic solver
4366
  x = map_poly_to_arith(ctx, q);
465✔
4367

4368
  // map u (and its root) to x
4369
  r = intern_tbl_get_root(&ctx->intern, u);
465✔
4370
  assert(intern_tbl_root_is_free(&ctx->intern, r) && is_pos_term(r));
4371
  intern_tbl_map_root(&ctx->intern, r, thvar2code(x));
465✔
4372

4373
#if TRACE
4374
  printf("---> toplevel equality: ");
4375
  print_polynomial(stdout, p);
4376
  printf(" == 0\n");
4377
  printf("     simplified to ");
4378
  print_term(stdout, ctx->terms, u);
4379
  printf(" := ");
4380
  print_polynomial(stdout, q);
4381
  printf("\n");
4382
#endif
4383

4384
  return true;
465✔
4385
}
4386

4387

4388

4389

4390

4391

4392

4393
/******************************************************
4394
 *  TOP-LEVEL ARITHMETIC EQUALITIES OR DISEQUALITIES  *
4395
 *****************************************************/
4396

4397
static void assert_arith_bineq(context_t *ctx, term_t t1, term_t t2, bool tt);
4398

4399
/*
4400
 * Top-level equality: t == (ite c u1 u2) between arithmetic terms
4401
 * - apply lift-if rule: (t == (ite c u1 u2)) --> (ite c (t == u1) (t == u2)
4402
 * - if tt is true: assert the equality otherwise assert the disequality
4403
 */
4404
static void assert_ite_arith_bineq(context_t *ctx, composite_term_t *ite, term_t t, bool tt) {
451✔
4405
  literal_t l1, l2, l3;
4406

4407
  assert(ite->arity == 3);
4408

4409
  l1 = internalize_to_literal(ctx, ite->arg[0]);
451✔
4410
  if (l1 == true_literal) {
451✔
4411
    // (ite c u1 u2) --> u1
4412
    assert_arith_bineq(ctx, ite->arg[1], t, tt);
3✔
4413
  } else if (l1 == false_literal) {
448✔
4414
    // (ite c u1 u2) --> u2
4415
    assert_arith_bineq(ctx, ite->arg[2], t, tt);
15✔
4416
  } else {
4417
    l2 = map_arith_bineq(ctx, ite->arg[1], t); // (u1 == t)
433✔
4418
    l3 = map_arith_bineq(ctx, ite->arg[2], t); // (u2 == t)
433✔
4419
    assert_ite(&ctx->gate_manager, l1, l2, l3, tt);
433✔
4420
  }
4421
}
451✔
4422

4423

4424
/*
4425
 * Try substitution t1 := t2
4426
 * - both are arithmetic terms and roots in the internalization table
4427
 */
4428
static void try_arithvar_bineq_elim(context_t *ctx, term_t t1, term_t t2) {
172✔
4429
  intern_tbl_t *intern;
4430
  thvar_t x, y;
4431
  int32_t code;
4432

4433
  assert(is_pos_term(t1) && intern_tbl_is_root(&ctx->intern, t1) &&
4434
         intern_tbl_root_is_free(&ctx->intern, t1));
4435

4436
  intern = &ctx->intern;
172✔
4437

4438
  if (is_constant_term(ctx->terms, t2)) {
172✔
4439
    if (intern_tbl_valid_const_subst(intern, t1, t2)) {
10✔
4440
      intern_tbl_add_subst(intern, t1, t2);
10✔
4441
    } else {
4442
      // unsat by type incompatibility
4443
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4444
    }
4445

4446
  } else if (intern_tbl_sound_subst(intern, t1, t2)) {
162✔
4447
    /*
4448
     * Internalize t2 to x.
4449
     * If t1 is still free after that, we can map t1 to x
4450
     * otherwise, t2 depends on t1 so we can't substitute.
4451
     */
4452
    x = internalize_to_arith(ctx, t2);
161✔
4453
    if (intern_tbl_root_is_free(intern, t1)) {
161✔
4454
      intern_tbl_map_root(&ctx->intern, t1, thvar2code(x));
2✔
4455
    } else {
4456
      assert(intern_tbl_root_is_mapped(intern, t1));
4457
      code = intern_tbl_map_of_root(intern, t1);
159✔
4458
      y = translate_code_to_arith(ctx, code);
159✔
4459

4460
      // assert x == y in the arithmetic solver
4461
      ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, true);
159✔
4462
    }
4463
  } else {
4464
    x = internalize_to_arith(ctx, t1);
1✔
4465
    y = internalize_to_arith(ctx, t2);
1✔
4466
    ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, true);
1✔
4467
  }
4468
}
172✔
4469

4470

4471
/*
4472
 * Top-level arithmetic equality t1 == t2:
4473
 * - if tt is true: assert t1 == t2 otherwise assert (t1 != t2)
4474
 * - both t1 and t2 are arithmetic terms and roots in the internalization table
4475
 * - the equality (t1 == t2) is not reducible by if-then-else flattening
4476
 */
4477
static void assert_arith_bineq_aux(context_t *ctx, term_t t1, term_t t2, bool tt) {
3,343✔
4478
  term_table_t *terms;
4479
  intern_tbl_t *intern;;
4480
  bool free1, free2;
4481
  thvar_t x, y;
4482
  occ_t u, v;
4483

4484
  assert(is_pos_term(t1) && intern_tbl_is_root(&ctx->intern, t1) &&
4485
         is_pos_term(t2) && intern_tbl_is_root(&ctx->intern, t2));
4486

4487
  terms = ctx->terms;
3,343✔
4488
  if (is_ite_term(terms, t1) && !is_ite_term(terms, t2)) {
3,343✔
4489
    assert_ite_arith_bineq(ctx, ite_term_desc(terms, t1), t2, tt);
112✔
4490
    return;
112✔
4491
  }
4492

4493
  if (is_ite_term(terms, t2) && !is_ite_term(terms, t1)) {
3,231✔
4494
    assert_ite_arith_bineq(ctx, ite_term_desc(terms, t2), t1, tt);
339✔
4495
    return;
339✔
4496
  }
4497

4498
  if (tt && context_arith_elim_enabled(ctx)) {
2,892✔
4499
    /*
4500
     * try a substitution
4501
     */
4502
    intern = &ctx->intern;
348✔
4503
    free1 = intern_tbl_root_is_free(intern, t1);
348✔
4504
    free2 = intern_tbl_root_is_free(intern, t2);
348✔
4505

4506
    if (free1 && free2) {
348✔
4507
      if (t1 != t2) {
1✔
4508
        intern_tbl_merge_classes(intern, t1, t2);
1✔
4509
      }
4510
      return;
1✔
4511
    }
4512

4513
    if (free1) {
347✔
4514
      try_arithvar_bineq_elim(ctx, t1, t2);
164✔
4515
      return;
164✔
4516
    }
4517

4518
    if (free2) {
183✔
4519
      try_arithvar_bineq_elim(ctx, t2, t1);
8✔
4520
      return;
8✔
4521
    }
4522

4523
  }
4524

4525
  /*
4526
   * Default: assert the constraint in the egraph or in the arithmetic
4527
   * solver if there's no egraph.
4528
   */
4529
  if (context_has_egraph(ctx)) {
2,719✔
4530
    u = internalize_to_eterm(ctx, t1);
1,658✔
4531
    v = internalize_to_eterm(ctx, t2);
1,658✔
4532
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
1,658✔
4533
      if (tt) {
1,658✔
4534
        egraph_assert_eq_axiom(ctx->egraph, u, v);
162✔
4535
      } else {
4536
        egraph_assert_diseq_axiom(ctx->egraph, u, v);
1,496✔
4537
      }
4538
    } else {
4539
      literal_t l = egraph_make_eq(ctx->egraph, u, v);
×
4540
      if (tt) {
×
4541
        add_unit_clause(ctx->core, l);
×
4542
      } else {
4543
        add_unit_clause(ctx->core, not(l));
×
4544
      }
4545
    }
4546
  } else {
4547
    x = internalize_to_arith(ctx, t1);
1,061✔
4548
    y = internalize_to_arith(ctx, t2);
1,061✔
4549
    ctx->arith.assert_vareq_axiom(ctx->arith_solver, x, y, tt);
1,061✔
4550
  }
4551
}
4552

4553

4554

4555

4556
/*****************************************************
4557
 *  INTERNALIZATION OF TOP-LEVEL ATOMS AND FORMULAS  *
4558
 ****************************************************/
4559

4560
/*
4561
 * Recursive function: assert (t == tt) for a boolean term t
4562
 * - this is used when a toplevel formula simplifies to t
4563
 *   For example (ite c t u) --> t if c is true.
4564
 * - t is not necessarily a root in the internalization table
4565
 */
4566
static void assert_term(context_t *ctx, term_t t, bool tt);
4567

4568

4569
/*
4570
 * Top-level predicate: (p t_1 .. t_n)
4571
 * - if tt is true: assert (p t_1 ... t_n)
4572
 * - if tt is false: assert (not (p t_1 ... t_n))
4573
 */
4574
static void assert_toplevel_apply(context_t *ctx, composite_term_t *app, bool tt) {
252✔
4575
  occ_t *a;
4576
  uint32_t i, n;
4577

4578
  assert(app->arity > 0);
4579

4580
  n = app->arity;
252✔
4581

4582
  check_high_order_support(ctx, app->arg+1, n-1);
252✔
4583

4584
  a = alloc_istack_array(&ctx->istack, n);
252✔
4585
  for (i=0; i<n; i++) {
1,030✔
4586
    a[i] = internalize_to_eterm(ctx, app->arg[i]);
778✔
4587
  }
4588

4589
  if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
252✔
4590
    if (tt) {
242✔
4591
      egraph_assert_pred_axiom(ctx->egraph, a[0], n-1, a+1);
214✔
4592
    } else {
4593
      egraph_assert_notpred_axiom(ctx->egraph, a[0], n-1, a+1);
28✔
4594
    }
4595
  } else {
4596
    literal_t l = egraph_make_pred(ctx->egraph, a[0], n-1, a+1);
10✔
4597
    if (tt) {
10✔
4598
      add_unit_clause(ctx->core, l);
3✔
4599
    } else {
4600
      add_unit_clause(ctx->core, not(l));
7✔
4601
    }
4602
  }
4603

4604
  free_istack_array(&ctx->istack, a);
252✔
4605
}
252✔
4606

4607

4608
/*
4609
 * Top-level (select i t)
4610
 * - if tt is true: assert (select i t)
4611
 * - if tt is false: assert (not (select i t))
4612
 */
4613
static void assert_toplevel_select(context_t *ctx, select_term_t *select, bool tt) {
×
4614
  occ_t u;
4615

4616
  u = map_select_to_eterm(ctx, select, bool_type(ctx->types));
×
4617
  if (! tt) {
×
4618
    u = opposite_occ(u);
×
4619
  }
4620
  if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
×
4621
    egraph_assert_axiom(ctx->egraph, u);
×
4622
  } else {
4623
    literal_t l = egraph_make_eq(ctx->egraph, u, true_occ);
×
4624
    add_unit_clause(ctx->core, l);
×
4625
  }
4626
}
×
4627

4628

4629
/*
4630
 * Top-level equality between Boolean terms
4631
 * - if tt is true, assert t1 == t2
4632
 * - if tt is false, assert t1 != t2
4633
 */
4634
static void assert_toplevel_iff(context_t *ctx, term_t t1, term_t t2, bool tt) {
2,739✔
4635
  term_t t;
4636
  literal_t l1, l2;
4637

4638
  /*
4639
   * Apply substitution then try flattening
4640
   */
4641
  t1 = intern_tbl_get_root(&ctx->intern, t1);
2,739✔
4642
  t2 = intern_tbl_get_root(&ctx->intern, t2);
2,739✔
4643
  if (t1 == t2) {
2,739✔
4644
    // (eq t1 t2) is true
4645
    if (!tt) {
×
4646
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
4647
    }
4648
  }
4649
  // try simplification
4650
  t = simplify_bool_eq(ctx, t1, t2);
2,739✔
4651
  if (t != NULL_TERM) {
2,739✔
4652
    // (eq t1 t2) is equivalent to t
4653
    assert_term(ctx, t, tt) ;
17✔
4654
  } else {
4655
    // no simplification
4656
    l1 = internalize_to_literal(ctx, t1);
2,722✔
4657
    l2 = internalize_to_literal(ctx, t2);
2,722✔
4658
    assert_iff(&ctx->gate_manager, l1, l2, tt);
2,722✔
4659

4660
#if 0
4661
    if (tt) {
4662
      printf("top assert: (eq ");
4663
      print_literal(stdout, l1);
4664
      printf(" ");
4665
      print_literal(stdout, l2);
4666
      printf(")\n");
4667
    } else {
4668
      printf("top assert: (xor ");
4669
      print_literal(stdout, l1);
4670
      printf(" ");
4671
      print_literal(stdout, l2);
4672
      printf(")\n");
4673
    }
4674
#endif
4675
  }
4676
}
2,739✔
4677

4678
/*
4679
 * Top-level equality assertion (eq t1 t2):
4680
 * - if tt is true, assert (t1 == t2)
4681
 *   if tt is false, assert (t1 != t2)
4682
 */
4683
static void assert_toplevel_eq(context_t *ctx, composite_term_t *eq, bool tt) {
5,156✔
4684
  occ_t u1, u2;
4685

4686
  assert(eq->arity == 2);
4687

4688
  if (is_boolean_term(ctx->terms, eq->arg[0])) {
5,156✔
4689
    assert(is_boolean_term(ctx->terms, eq->arg[1]));
4690
    assert_toplevel_iff(ctx, eq->arg[0], eq->arg[1], tt);
2,739✔
4691
  } else {
4692
    // filter out high-order terms. It's enough to check eq->arg[0]
4693
    check_high_order_support(ctx, eq->arg, 1);
2,417✔
4694

4695
    u1 = internalize_to_eterm(ctx, eq->arg[0]);
2,416✔
4696
    u2 = internalize_to_eterm(ctx, eq->arg[1]);
2,416✔
4697
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
2,415✔
4698
      if (tt) {
2,401✔
4699
        egraph_assert_eq_axiom(ctx->egraph, u1, u2);
1,323✔
4700
      } else {
4701
        egraph_assert_diseq_axiom(ctx->egraph, u1, u2);
1,078✔
4702
      }
4703
    } else {
4704
      literal_t l = egraph_make_eq(ctx->egraph, u1, u2);
14✔
4705
      if (tt) {
14✔
4706
        add_unit_clause(ctx->core, l);
9✔
4707
      } else {
4708
        add_unit_clause(ctx->core, not(l));
5✔
4709
      }
4710
    }
4711
  }
4712
}
5,154✔
4713

4714

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

4722
  l = make_arith_distinct(ctx, n, a);
155✔
4723
  if (! tt) {
155✔
4724
    l = not(l);
4✔
4725
  }
4726
  add_unit_clause(ctx->core, l);
155✔
4727
}
155✔
4728

4729

4730
/*
4731
 * Assertion (distinct a[0] .... a[n-1]) == tt
4732
 * when a[0] ... a[n-1] are bitvector variables.
4733
 */
4734
static void assert_bv_distinct(context_t *ctx, uint32_t n, thvar_t *a, bool tt) {
2✔
4735
  literal_t l;
4736

4737
  l = make_bv_distinct(ctx, n, a);
2✔
4738
  if (! tt) {
2✔
4739
    l = not(l);
1✔
4740
  }
4741
  add_unit_clause(ctx->core, l);
2✔
4742
}
2✔
4743

4744

4745
/*
4746
 * Generic (distinct t1 .. t_n)
4747
 * - if tt: assert (distinct t_1 ... t_n)
4748
 * - otherwise: assert (not (distinct t_1 ... t_n))
4749
 */
4750
static void assert_toplevel_distinct(context_t *ctx, composite_term_t *distinct, bool tt) {
173✔
4751
  uint32_t i, n;
4752
  int32_t *a;
4753

4754
  n = distinct->arity;
173✔
4755
  assert(n >= 2);
4756

4757
  a = alloc_istack_array(&ctx->istack, n);
173✔
4758

4759
  if (context_has_egraph(ctx)) {
173✔
4760
    // fail if arguments have function types and we don't
4761
    // have a function/array solver
4762
    check_high_order_support(ctx, distinct->arg, 1);
16✔
4763

4764
    // forward the assertion to the egraph
4765
    for (i=0; i<n; i++) {
69✔
4766
      a[i] = internalize_to_eterm(ctx, distinct->arg[i]);
55✔
4767
    }
4768

4769
    if (!context_quant_enabled(ctx) || egraph_is_at_base_level(ctx->egraph)) {
14✔
4770
      if (tt) {
14✔
4771
        egraph_assert_distinct_axiom(ctx->egraph, n, a);
10✔
4772
      } else {
4773
        egraph_assert_notdistinct_axiom(ctx->egraph, n, a);
4✔
4774
      }
4775
    } else {
4776
      literal_t l = egraph_make_distinct(ctx->egraph, n, a);
×
4777
      if (tt) {
×
4778
        add_unit_clause(ctx->core, l);
×
4779
      } else {
4780
        add_unit_clause(ctx->core, not(l));
×
4781
      }
4782
    }
4783

4784
  } else if (is_arithmetic_term(ctx->terms, distinct->arg[0])) {
157✔
4785
    // translate to arithmetic then assert
4786
    for (i=0; i<n; i++) {
3,922✔
4787
      a[i] = internalize_to_arith(ctx, distinct->arg[i]);
3,767✔
4788
    }
4789
    assert_arith_distinct(ctx, n, a, tt);
155✔
4790

4791
  } else if (is_bitvector_term(ctx->terms, distinct->arg[0])) {
2✔
4792
    // translate to bitvectors then assert
4793
    for (i=0; i<n; i++) {
13✔
4794
      a[i] = internalize_to_bv(ctx, distinct->arg[i]);
11✔
4795
    }
4796
    assert_bv_distinct(ctx, n, a, tt);
2✔
4797

4798
  } else {
4799
    longjmp(ctx->env, uf_error_code(ctx, distinct->arg[0]));
×
4800
  }
4801

4802
  free_istack_array(&ctx->istack, a);
171✔
4803
}
171✔
4804

4805

4806

4807
/*
4808
 * Top-level arithmetic equality t1 == u1:
4809
 * - t1 and u1 are arithmetic terms
4810
 * - if tt is true assert (t1 == u1) otherwise assert (t1 != u1)
4811
 * - apply lift-if simplifications and variable elimination
4812
 */
4813
static void assert_arith_bineq(context_t *ctx, term_t t1, term_t u1, bool tt) {
3,416✔
4814
  ivector_t *v;
4815
  int32_t *a;
4816
  uint32_t i, n;
4817
  term_t t2, u2;
4818

4819
  /*
4820
   * Apply substitutions then try if-then-else flattening
4821
   */
4822
  t1 = intern_tbl_get_root(&ctx->intern, t1);
3,416✔
4823
  u1 = intern_tbl_get_root(&ctx->intern, u1);
3,416✔
4824

4825
  v = &ctx->aux_vector;
3,416✔
4826
  assert(v->size == 0);
4827
  t2 = flatten_ite_equality(ctx, v, t1, u1);
3,416✔
4828
  u2 = flatten_ite_equality(ctx, v, u1, t2);
3,416✔
4829

4830
  /*
4831
   * (t1 == u1) is now equivalent to
4832
   * the conjunction of (t2 == u2) and all the terms in v
4833
   */
4834
  n = v->size;
3,416✔
4835
  if (n == 0) {
3,416✔
4836
    /*
4837
     * The simple flattening did not work.
4838
     */
4839
    assert(t1 == t2 && u1 == u2);
4840
    assert_arith_bineq_aux(ctx, t2, u2, tt);
3,330✔
4841

4842
  } else {
4843
    // make a copy of v[0 ... n-1]
4844
    // and reserve a[n] for the literal (eq t2 u2)
4845
    a = alloc_istack_array(&ctx->istack, n+1);
86✔
4846
    for (i=0; i<n; i++) {
1,531✔
4847
      a[i] = v->data[i];
1,445✔
4848
    }
4849
    ivector_reset(v);
86✔
4850

4851
    if (tt) {
86✔
4852
      // assert (and a[0] ... a[n-1] (eq t2 u2))
4853
      for (i=0; i<n; i++) {
340✔
4854
        assert_term(ctx, a[i], true);
327✔
4855
      }
4856

4857
      /*
4858
       * The assertions a[0] ... a[n-1] may have
4859
       * caused roots to be merged. So we must
4860
       * apply term substitution again.
4861
       */
4862
      t2 = intern_tbl_get_root(&ctx->intern, t2);
13✔
4863
      u2 = intern_tbl_get_root(&ctx->intern, u2);
13✔
4864
      assert_arith_bineq_aux(ctx, t2, u2, true);
13✔
4865

4866
    } else {
4867
      // assert (or (not a[0]) ... (not a[n-1]) (not (eq t2 u2)))
4868
      for (i=0; i<n; i++) {
1,191✔
4869
        a[i] = not(internalize_to_literal(ctx, a[i]));
1,118✔
4870
      }
4871
      a[n] = not(map_arith_bineq_aux(ctx, t2, u2));
73✔
4872

4873
      add_clause(ctx->core, n+1, a);
73✔
4874
    }
4875

4876
    free_istack_array(&ctx->istack, a);
86✔
4877
  }
4878
}
3,416✔
4879

4880

4881
/*
4882
 * Top-level arithmetic assertion:
4883
 * - if tt is true, assert p == 0
4884
 * - if tt is false, assert p != 0
4885
 */
4886
static void assert_toplevel_poly_eq(context_t *ctx, polynomial_t *p, bool tt) {
1,273✔
4887
  uint32_t i, n;
4888
  thvar_t *a;
4889

4890
  n = p->nterms;
1,273✔
4891
  a = alloc_istack_array(&ctx->istack, n);;
1,273✔
4892
  // skip the constant if any
4893
  i = 0;
1,273✔
4894
  if (p->mono[0].var == const_idx) {
1,273✔
4895
    a[0] = null_thvar;
1,208✔
4896
    i ++;
1,208✔
4897
  }
4898

4899
  // deal with the non-constant monomials
4900
  while (i<n) {
3,928✔
4901
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
2,655✔
4902
    i ++;
2,655✔
4903
  }
4904

4905
  // assertion
4906
  ctx->arith.assert_poly_eq_axiom(ctx->arith_solver, p, a, tt);
1,273✔
4907
  free_istack_array(&ctx->istack, a);
1,273✔
4908
}
1,273✔
4909

4910

4911

4912
/*
4913
 * Top-level arithmetic equality:
4914
 * - t is an arithmetic term
4915
 * - if tt is true, assert (t == 0)
4916
 * - otherwise, assert (t != 0)
4917
 */
4918
static void assert_toplevel_arith_eq(context_t *ctx, term_t t, bool tt) {
2,270✔
4919
  term_table_t *terms;
4920
  polynomial_t *p;
4921
  bool all_int;
4922
  thvar_t x;
4923

4924
  assert(is_arithmetic_term(ctx->terms, t));
4925

4926
  terms = ctx->terms;
2,270✔
4927
  if (tt && context_arith_elim_enabled(ctx) && term_kind(terms, t) == ARITH_POLY) {
2,270✔
4928
    /*
4929
     * Polynomial equality: a_1 t_1 + ... + a_n t_n = 0
4930
     * attempt to eliminate one of t_1 ... t_n
4931
     */
4932
    p = poly_term_desc(terms, t);
544✔
4933
    all_int = is_integer_term(terms, t);
544✔
4934
    if (try_arithvar_elim(ctx, p, all_int)) { // elimination worked
544✔
4935
      return;
465✔
4936
    }
4937
  }
4938

4939
  // default
4940
  if (term_kind(terms, t) == ARITH_POLY) {
1,805✔
4941
    assert_toplevel_poly_eq(ctx, poly_term_desc(terms, t), tt);
1,273✔
4942
  } else if (is_ite_term(terms, t)) {
532✔
4943
    assert_arith_bineq(ctx, t, zero_term, tt);
8✔
4944
  } else {
4945
    x = internalize_to_arith(ctx, t);
524✔
4946
    ctx->arith.assert_eq_axiom(ctx->arith_solver, x, tt);
522✔
4947
  }
4948
}
4949

4950

4951

4952
/*
4953
 * Top-level arithmetic assertion:
4954
 * - if tt is true, assert p >= 0
4955
 * - if tt is false, assert p < 0
4956
 */
4957
static void assert_toplevel_poly_geq(context_t *ctx, polynomial_t *p, bool tt) {
25,932✔
4958
  uint32_t i, n;
4959
  thvar_t *a;
4960

4961
  n = p->nterms;
25,932✔
4962
  a = alloc_istack_array(&ctx->istack, n);;
25,932✔
4963
  // skip the constant if any
4964
  i = 0;
25,932✔
4965
  if (p->mono[0].var == const_idx) {
25,932✔
4966
    a[0] = null_thvar;
25,106✔
4967
    i ++;
25,106✔
4968
  }
4969

4970
  // deal with the non-constant monomials
4971
  while (i<n) {
55,607✔
4972
    a[i] = internalize_to_arith(ctx, p->mono[i].var);
29,676✔
4973
    i ++;
29,675✔
4974
  }
4975

4976
  // assertion
4977
  ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, a, tt);
25,931✔
4978
  free_istack_array(&ctx->istack, a);
25,931✔
4979
}
25,931✔
4980

4981

4982

4983
/*
4984
 * Top-level arithmetic inequality:
4985
 * - t is an arithmetic term
4986
 * - if tt is true, assert (t >= 0)
4987
 * - if tt is false, assert (t < 0)
4988
 */
4989
static void assert_toplevel_arith_geq(context_t *ctx, term_t t, bool tt) {
27,858✔
4990
  term_table_t *terms;
4991
  thvar_t x;
4992

4993
  assert(is_arithmetic_term(ctx->terms, t));
4994

4995
  terms = ctx->terms;
27,858✔
4996
  if (term_kind(terms, t) == ARITH_POLY) {
27,858✔
4997
    assert_toplevel_poly_geq(ctx, poly_term_desc(terms, t), tt);
25,932✔
4998
  } else {
4999
    x = internalize_to_arith(ctx, t);
1,926✔
5000
    ctx->arith.assert_ge_axiom(ctx->arith_solver, x, tt);
1,926✔
5001
  }
5002
}
27,857✔
5003

5004

5005
/*
5006
 * Top-level binary equality: (eq t u)
5007
 * - both t and u are arithmetic terms
5008
 * - if tt is true, assert (t == u)
5009
 * - if tt is false, assert (t != u)
5010
 */
5011
static void assert_toplevel_arith_bineq(context_t *ctx, composite_term_t *eq, bool tt) {
3,390✔
5012
  assert(eq->arity == 2);
5013
  assert_arith_bineq(ctx, eq->arg[0], eq->arg[1], tt);
3,390✔
5014
}
3,390✔
5015

5016

5017

5018
/*
5019
 * Top-level (is_int t)
5020
 * - t is an arithmetic term
5021
 * - if tt is true, assert (t <= (floor t))
5022
 * - if tt is false, asssert (t > (floor t))
5023
 *
5024
 * NOTE: instead of asserting (t <= (floor t)) we could create a fresh
5025
 * integer variable z and assert (t = z).
5026
 */
5027
static void assert_toplevel_arith_is_int(context_t *ctx, term_t t, bool tt) {
×
5028
  polynomial_t *p;
5029
  thvar_t map[2];
5030
  thvar_t x, y;
5031

5032
  x = internalize_to_arith(ctx, t);
×
5033
  if (ctx->arith.arith_var_is_int(ctx->arith_solver, x)) {
×
5034
    if (!tt) {
×
5035
      longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5036
    }
5037
  } else {
5038
    // x is not an integer variable
5039
    y = get_floor(ctx, x); // y := (floor x)
×
5040
    p = context_get_aux_poly(ctx, 3);
×
5041
    context_store_diff_poly(p, map, y, x); // (p, map) stores (y - x)
×
5042
    // assert either (p >= 0) --> (x <= floor(x))
5043
    // or (p < 0) --> (x > (floor x)
5044
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, tt);
×
5045
  }
5046
}
×
5047

5048

5049
/*
5050
 * Top-level (divides k t)
5051
 * - if tt is true, assert (t <= k * (div t k))
5052
 * - if tt is false, assert (t > k * (div t k))
5053
 *
5054
 * We assume (k != 0) since (divides 0 t) is rewritten to (t == 0) by
5055
 * the term manager.
5056
 *
5057
 * NOTE: instead of asserting (t <= k * (div t k)) we could create a fresh
5058
 * integer variable z and assert (t = k * z).
5059
 */
5060
static void assert_toplevel_arith_divides(context_t *ctx, composite_term_t *divides, bool tt) {
×
5061
  rational_t k;
5062
  polynomial_t *p;
5063
  thvar_t map[2];
5064
  thvar_t x, y;
5065
  term_t d;
5066

5067
  assert(divides->arity == 2);
5068

5069
  d = divides->arg[0];
×
5070
  if (term_kind(ctx->terms, d) == ARITH_CONSTANT) {
×
5071
    // copy the divider
5072
    q_init(&k);
×
5073
    q_set(&k, rational_term_desc(ctx->terms, d));
×
5074
    assert(q_is_nonzero(&k));
5075

5076
    x = internalize_to_arith(ctx, divides->arg[1]);
×
5077
    y = get_div(ctx, x, &k);  // y := (div x k);
×
5078
    p = context_get_aux_poly(ctx, 3);
×
5079
    context_store_divides_constraint(p, map, x, y, &k); // p is (- x + k * y)
×
5080

5081
    // if tt, assert (p >= 0) <=> x <= k * y
5082
    // if not tt, assert (p < 0) <=> x > k * y
5083
    ctx->arith.assert_poly_ge_axiom(ctx->arith_solver, p, map, tt);
×
5084

5085
    q_clear(&k);
×
5086
  } else {
5087
    // not a constant divider: not supported
5088
    longjmp(ctx->env, FORMULA_NOT_LINEAR);
×
5089
  }
5090
}
×
5091

5092

5093

5094

5095

5096

5097
/*
5098
 * Top-level conditional
5099
 * - c = conditional descriptor
5100
 * - if tt is true: assert c otherwise assert not c
5101
 *
5102
 * - c->nconds = number of clauses in the conditional
5103
 * - for each clause i: c->pair[i] = <cond, val>
5104
 * - c->defval = default value
5105
 */
5106
static void assert_toplevel_conditional(context_t *ctx, conditional_t *c, bool tt) {
13✔
5107
  uint32_t i, n;
5108
  literal_t *a;
5109
  literal_t l;
5110
  bool all_false;
5111
  term_t t;
5112

5113
#if 0
5114
  printf("---> toplevel conditional\n");
5115
#endif
5116

5117
  t = simplify_conditional(ctx, c);
13✔
5118
  if (t != NULL_TERM) {
13✔
5119
    assert_term(ctx, t, tt);
2✔
5120
    return;
2✔
5121
  }
5122

5123
  n = c->nconds;
11✔
5124
  a = alloc_istack_array(&ctx->istack, n + 1);
11✔
5125

5126
  all_false = true;
11✔
5127
  for (i=0; i<n; i++) {
72✔
5128
    // a[i] = condition for pair[i]
5129
    a[i] = internalize_to_literal(ctx, c->pair[i].cond);
62✔
5130
    if (a[i] == true_literal) {
62✔
5131
      // if a[i] is true, all other conditions must be false
5132
      assert_term(ctx, c->pair[i].val, tt);
1✔
5133
      goto done;
1✔
5134
    }
5135
    if (a[i] != false_literal) {
61✔
5136
      // l = value for pair[i]
5137
      l = signed_literal(internalize_to_literal(ctx, c->pair[i].val), tt);
58✔
5138
      add_binary_clause(ctx->core, not(a[i]), l); // a[i] => v[i]
58✔
5139
      all_false = false;
58✔
5140
    }
5141
  }
5142

5143
  if (all_false) {
10✔
5144
    // all a[i]s are false: no need for a clause
5145
    assert_term(ctx, c->defval, tt);
1✔
5146
    goto done;
1✔
5147
  }
5148

5149
  // last clause: (a[0] \/ .... \/ a[n] \/ +/-defval)
5150
  a[n] = signed_literal(internalize_to_literal(ctx, c->defval), tt);
9✔
5151
  add_clause(ctx->core, n+1, a);
9✔
5152

5153
  // cleanup
5154
 done:
11✔
5155
  free_istack_array(&ctx->istack, a);
11✔
5156
}
5157

5158

5159

5160
/*
5161
 * Top-level boolean if-then-else (ite c t1 t2)
5162
 * - if tt is true: assert (ite c t1 t2)
5163
 * - if tt is false: assert (not (ite c t1 t2))
5164
 */
5165
static void assert_toplevel_ite(context_t *ctx, composite_term_t *ite, bool tt) {
70✔
5166
  conditional_t *d;
5167
  literal_t l1, l2, l3;
5168

5169
  assert(ite->arity == 3);
5170

5171
  // high-order ite should work. See map_ite_to_eterm
5172

5173
  d = context_make_conditional(ctx, ite);
70✔
5174
  if (d != NULL) {
70✔
5175
    assert_toplevel_conditional(ctx, d, tt);
13✔
5176
    context_free_conditional(ctx, d);
13✔
5177
    return;
13✔
5178
  }
5179

5180
  l1 = internalize_to_literal(ctx, ite->arg[0]);
57✔
5181
  if (l1 == true_literal) {
57✔
5182
    assert_term(ctx, ite->arg[1], tt);
5✔
5183
  } else if (l1 == false_literal) {
52✔
5184
    assert_term(ctx, ite->arg[2], tt);
2✔
5185
  } else {
5186
    l2 = internalize_to_literal(ctx, ite->arg[1]);
50✔
5187
    l3 = internalize_to_literal(ctx, ite->arg[2]);
50✔
5188
    assert_ite(&ctx->gate_manager, l1, l2, l3, tt);
50✔
5189
  }
5190
}
5191

5192

5193
/*
5194
 * Top-level (or t1 ... t_n)
5195
 * - it tt is true: add a clause
5196
 * - it tt is false: assert (not t1) ... (not t_n)
5197
 */
5198
static void assert_toplevel_or(context_t *ctx, composite_term_t *or, bool tt) {
42,977✔
5199
  ivector_t *v;
5200
  int32_t *a;
5201
  uint32_t i, n;
5202

5203
  if (tt) {
42,977✔
5204
    if (context_flatten_or_enabled(ctx)) {
42,961✔
5205
      // Flatten into vector v
5206
      v = &ctx->aux_vector;
15,025✔
5207
      assert(v->size == 0);
5208
      flatten_or_term(ctx, v, or);
15,025✔
5209

5210
      // if v contains a true_term, ignore the clause
5211
      n = v->size;
15,025✔
5212
      if (disjunct_is_true(ctx, v->data, n)) {
15,025✔
5213
        ivector_reset(v);
971✔
5214
        return;
971✔
5215
      }
5216

5217
      // make a copy of v
5218
      a = alloc_istack_array(&ctx->istack, n);
14,054✔
5219
      for (i=0; i<n; i++) {
58,781✔
5220
        a[i] = v->data[i];
44,727✔
5221
      }
5222
      ivector_reset(v);
14,054✔
5223

5224
      for (i=0; i<n; i++) {
58,458✔
5225
        a[i] = internalize_to_literal(ctx, a[i]);
44,557✔
5226
        if (a[i] == true_literal) goto done;
44,557✔
5227
      }
5228

5229
    } else {
5230
      /*
5231
       * No flattening
5232
       */
5233
      n = or->arity;
27,936✔
5234
      if (disjunct_is_true(ctx, or->arg, n)) {
27,936✔
5235
        return;
2,503✔
5236
      }
5237

5238
      a = alloc_istack_array(&ctx->istack, n);
25,433✔
5239
      for (i=0; i<n; i++) {
143,590✔
5240
        a[i] = internalize_to_literal(ctx, or->arg[i]);
118,257✔
5241
        if (a[i] == true_literal) goto done;
118,257✔
5242
      }
5243
    }
5244

5245
    // assert (or a[0] ... a[n-1])
5246
    add_clause(ctx->core, n, a);
39,234✔
5247

5248
  done:
39,487✔
5249
    free_istack_array(&ctx->istack, a);
39,487✔
5250

5251
  } else {
5252
    /*
5253
     * Propagate to children:
5254
     *  (or t_0 ... t_n-1) is false
5255
     * so all children must be false too
5256
     */
5257
    n = or->arity;
16✔
5258
    for (i=0; i<n; i++) {
48✔
5259
      assert_term(ctx, or->arg[i], false);
32✔
5260
    }
5261
  }
5262

5263
}
5264

5265

5266
/*
5267
 * Top-level (xor t1 ... t_n) == tt
5268
 */
5269
static void assert_toplevel_xor(context_t *ctx, composite_term_t *xor, bool tt) {
7✔
5270
  int32_t *a;
5271
  uint32_t i, n;
5272

5273
  n = xor->arity;
7✔
5274
  a = alloc_istack_array(&ctx->istack, n);
7✔
5275
  for (i=0; i<n; i++) {
58✔
5276
    a[i] = internalize_to_literal(ctx, xor->arg[i]);
51✔
5277
  }
5278

5279
  assert_xor(&ctx->gate_manager, n, a, tt);
7✔
5280
  free_istack_array(&ctx->istack, a);
7✔
5281
}
7✔
5282

5283

5284

5285
/*
5286
 * Top-level bit select
5287
 */
5288
static void assert_toplevel_bit_select(context_t *ctx, select_term_t *select, bool tt) {
32,805✔
5289
  term_t t, s;
5290
  thvar_t x;
5291

5292
  /*
5293
   * Check for simplification
5294
   */
5295
  t = intern_tbl_get_root(&ctx->intern, select->arg);
32,805✔
5296
  s = extract_bit(ctx->terms, t, select->idx);
32,805✔
5297
  if (s != NULL_TERM) {
32,805✔
5298
    // (select t i) is s
5299
    assert_term(ctx, s, tt);
63✔
5300
  } else {
5301
    // no simplification
5302
    x = internalize_to_bv(ctx, select->arg);
32,742✔
5303
    ctx->bv.set_bit(ctx->bv_solver, x, select->idx, tt);
32,742✔
5304
  }
5305
}
32,804✔
5306

5307

5308
/*
5309
 * Top-level bitvector atoms
5310
 */
5311
// Auxiliary function: assert (t == 0) or (t != 0) depending on tt
5312
static void assert_toplevel_bveq0(context_t *ctx, term_t t, bool tt) {
41✔
5313
  uint32_t n;
5314
  thvar_t x, y;
5315

5316
  t = intern_tbl_get_root(&ctx->intern, t);
41✔
5317
  n = term_bitsize(ctx->terms, t);
41✔
5318
  x = internalize_to_bv(ctx, t);
41✔
5319
  y = ctx->bv.create_zero(ctx->bv_solver, n);
41✔
5320
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x, y, tt);
41✔
5321
}
41✔
5322

5323

5324
/*
5325
 * Experimental: when t1 and t2 have a common factor C:
5326
 *   t1 = C * u1
5327
 *   t2 = C * u2
5328
 * then we have (t1 /= t2) implies (u1 /= u2).
5329
 * So we can add (u1 /= u2) when (t1 /= t2) is asserted.
5330
 * This is redundant but it may help solving the problem, especially if C is a
5331
 * complex expression.
5332
 */
5333
static void assert_factored_inequality(context_t *ctx, bvfactoring_t *f) {
9✔
5334
  term_t u1, u2;
5335
  thvar_t x, y;
5336

5337
  assert(f->code == BVFACTOR_FOUND);
5338

5339
  //  printf("Asserting factored inequality\n\n");
5340

5341
  u1 = bitvector_factoring_left_term(ctx, f);
9✔
5342
  u2 = bitvector_factoring_right_term(ctx, f);
9✔
5343
  x = internalize_to_bv(ctx, u1);
9✔
5344
  y = internalize_to_bv(ctx, u2);
9✔
5345
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x,  y, false);
9✔
5346
}
9✔
5347

5348
static void assert_toplevel_bveq(context_t *ctx, composite_term_t *eq, bool tt) {
9,370✔
5349
  bveq_simp_t simp;
5350
  ivector_t *v;
5351
  int32_t *a;
5352
  term_t t, t1, t2;
5353
  thvar_t x, y;
5354
  uint32_t i, n;
5355

5356
  assert(eq->arity == 2);
5357

5358
  t1 = intern_tbl_get_root(&ctx->intern, eq->arg[0]);
9,370✔
5359
  t2 = intern_tbl_get_root(&ctx->intern, eq->arg[1]);
9,370✔
5360
  t = simplify_bitvector_eq(ctx, t1, t2);
9,370✔
5361
  if (t != NULL_TERM) {
9,370✔
5362
    // (bveq t1 t2) is equivalent to t
5363
    assert_term(ctx, t, tt);
18✔
5364
    return;
74✔
5365
  }
5366

5367
  if (tt) {
9,352✔
5368
    // try to flatten to a conjunction of terms
5369
    v = &ctx->aux_vector;
7,534✔
5370
    assert(v->size == 0);
5371
    if (bveq_flattens(ctx->terms, t1, t2, v)) {
7,534✔
5372
      /*
5373
       * (bveq t1 t2) is equivalent to (and v[0] ... v[k])
5374
       * (bveq t1 t2) is true at the toplevel so v[0] ... v[k] must all be true
5375
       */
5376

5377
      // make a copy of v
5378
      n = v->size;
19✔
5379
      a = alloc_istack_array(&ctx->istack, n);
19✔
5380
      for (i=0; i<n; i++) {
579✔
5381
        a[i] = v->data[i];
560✔
5382
      }
5383
      ivector_reset(v);
19✔
5384

5385
      // assert
5386
      for (i=0; i<n; i++) {
548✔
5387
        assert_term(ctx, a[i], true);
530✔
5388
      }
5389

5390
      free_istack_array(&ctx->istack, a);
18✔
5391
      return;
18✔
5392
    }
5393

5394
    // flattening failed
5395
    ivector_reset(v);
7,515✔
5396
  }
5397

5398
  /*
5399
   * Try more simplifications
5400
   */
5401
  try_arithmetic_bveq_simplification(ctx, &simp, t1, t2);
9,333✔
5402
  switch (simp.code) {
9,333✔
5403
  case BVEQ_CODE_TRUE:
×
5404
    if (!tt) longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5405
    break;
×
5406

5407
  case BVEQ_CODE_FALSE:
×
5408
    if (tt) longjmp(ctx->env, TRIVIALLY_UNSAT);
×
5409
    break;
×
5410

5411
  case BVEQ_CODE_REDUCED:
36✔
5412
    t1 = intern_tbl_get_root(&ctx->intern, simp.left);
36✔
5413
    t2 = intern_tbl_get_root(&ctx->intern, simp.right);
36✔
5414
    break;
36✔
5415

5416
  case BVEQ_CODE_REDUCED0:
41✔
5417
    // reduced to simp.left == 0
5418
    assert_toplevel_bveq0(ctx, simp.left, tt);
41✔
5419
    return;
41✔
5420

5421
  default:
9,256✔
5422
    break;
9,256✔
5423
  }
5424

5425
  /*
5426
   * Try Factoring
5427
   */
5428
  if (!tt) {
9,292✔
5429
    bvfactoring_t *factoring;
5430
    bool eq = false;
1,783✔
5431

5432
    factoring = objstack_alloc(&ctx->ostack, sizeof(bvfactoring_t), (cleaner_t) delete_bvfactoring);
1,783✔
5433
    init_bvfactoring(factoring);
1,783✔
5434

5435
    try_bitvector_factoring(ctx, factoring, t1, t2);
1,783✔
5436
    switch (factoring->code) {
1,783✔
5437
    case BVFACTOR_EQUAL:
4✔
5438
      eq = true;
4✔
5439
      break;
4✔
5440

5441
    case BVFACTOR_FOUND:
9✔
5442
      assert_factored_inequality(ctx, factoring);
9✔
5443
      break;
9✔
5444

5445
    default:
1,770✔
5446
      break;
1,770✔
5447
    }
5448
    // delete_bvfactoring(&factoring);
5449
    objstack_pop(&ctx->ostack);
1,783✔
5450

5451
    if (eq) {
1,783✔
5452
      longjmp(ctx->env, TRIVIALLY_UNSAT);
4✔
5453
    }
5454
  }
5455

5456
  /*
5457
   * NOTE: asserting (eq t1 t2) in the egraph instead makes things worse
5458
   */
5459
  x = internalize_to_bv(ctx, t1);
9,288✔
5460
  y = internalize_to_bv(ctx, t2);
9,288✔
5461
  ctx->bv.assert_eq_axiom(ctx->bv_solver, x,  y, tt);
9,288✔
5462
}
5463

5464
static void assert_toplevel_bvge(context_t *ctx, composite_term_t *ge, bool tt) {
1,488✔
5465
  thvar_t x, y;
5466

5467
  assert(ge->arity == 2);
5468

5469
  x = internalize_to_bv(ctx, ge->arg[0]);
1,488✔
5470
  y = internalize_to_bv(ctx, ge->arg[1]);
1,488✔
5471
  ctx->bv.assert_ge_axiom(ctx->bv_solver, x,  y, tt);
1,488✔
5472
}
1,488✔
5473

5474
static void assert_toplevel_bvsge(context_t *ctx, composite_term_t *sge, bool tt) {
459✔
5475
  thvar_t x, y;
5476

5477
  assert(sge->arity == 2);
5478

5479
  x = internalize_to_bv(ctx, sge->arg[0]);
459✔
5480
  y = internalize_to_bv(ctx, sge->arg[1]);
459✔
5481
  ctx->bv.assert_sge_axiom(ctx->bv_solver, x,  y, tt);
459✔
5482
}
459✔
5483

5484

5485

5486
/*
5487
 * Top-level formula t:
5488
 * - t is a boolean term (or the negation of a boolean term)
5489
 * - t must be a root in the internalization table and must be mapped to true
5490
 */
5491
static void assert_toplevel_formula(context_t *ctx, term_t t) {
125,465✔
5492
  term_table_t *terms;
5493
  int32_t code;
5494
  literal_t l;
5495
  bool tt;
5496

5497
  assert(is_boolean_term(ctx->terms, t) &&
5498
         intern_tbl_is_root(&ctx->intern, t) &&
5499
         term_is_true(ctx, t));
5500

5501
  tt = is_pos_term(t);
125,465✔
5502
  t = unsigned_term(t);
125,465✔
5503

5504
  /*
5505
   * Now: t is a root and has positive polarity
5506
   * - tt indicates whether we assert t or (not t):
5507
   *   tt true: assert t
5508
   *   tt false: assert (not t)
5509
   */
5510
  terms = ctx->terms;
125,465✔
5511
  if (context_atom_requires_mcsat(ctx, t)) {
125,465✔
5512
    l = map_mcsat_atom_to_literal(ctx, t);
16✔
5513
    code = literal2code(l);
16✔
5514
    /*
5515
     * Top-level formulas may already have a placeholder mapping from
5516
     * preprocessing, so overwrite it.  assert_term only maps unmapped roots.
5517
     */
5518
    intern_tbl_remap_root(&ctx->intern, t, code);
16✔
5519
    assert_internalization_code(ctx, code, tt);
16✔
5520
    return;
16✔
5521
  }
5522
  if (ctx->mcsat_supplement) {
125,449✔
5523
    context_observe_mcsat_atom(ctx, t, tt ? true_literal : false_literal);
18✔
5524
  }
5525

5526
  switch (term_kind(terms, t)) {
125,449✔
5527
  case CONSTANT_TERM:
×
5528
  case UNINTERPRETED_TERM:
5529
    // should be eliminated by flattening
5530
    code = INTERNAL_ERROR;
×
5531
    goto abort;
×
5532

5533
  case ITE_TERM:
68✔
5534
  case ITE_SPECIAL:
5535
    assert_toplevel_ite(ctx, ite_term_desc(terms, t), tt);
68✔
5536
    break;
68✔
5537

5538
  case OR_TERM:
42,946✔
5539
    assert_toplevel_or(ctx, or_term_desc(terms, t), tt);
42,946✔
5540
    break;
42,946✔
5541

5542
  case XOR_TERM:
7✔
5543
    assert_toplevel_xor(ctx, xor_term_desc(terms, t), tt);
7✔
5544
    break;
7✔
5545

5546
  case EQ_TERM:
5,145✔
5547
    assert_toplevel_eq(ctx, eq_term_desc(terms, t), tt);
5,145✔
5548
    break;
5,143✔
5549

5550
  case ARITH_IS_INT_ATOM:
×
5551
    assert_toplevel_arith_is_int(ctx, arith_is_int_arg(terms, t), tt);
×
5552
    break;
×
5553

5554
  case ARITH_EQ_ATOM:
2,266✔
5555
    assert_toplevel_arith_eq(ctx, arith_eq_arg(terms, t), tt);
2,266✔
5556
    break;
2,264✔
5557

5558
  case ARITH_GE_ATOM:
27,851✔
5559
    assert_toplevel_arith_geq(ctx, arith_ge_arg(terms, t), tt);
27,851✔
5560
    break;
27,850✔
5561

5562
  case ARITH_BINEQ_ATOM:
3,209✔
5563
    assert_toplevel_arith_bineq(ctx, arith_bineq_atom_desc(terms, t), tt);
3,209✔
5564
    break;
3,209✔
5565

5566
  case ARITH_DIVIDES_ATOM:
×
5567
    assert_toplevel_arith_divides(ctx, arith_divides_atom_desc(terms, t), tt);
×
5568
    break;
×
5569

5570
  case APP_TERM:
250✔
5571
    assert_toplevel_apply(ctx, app_term_desc(terms, t), tt);
250✔
5572
    break;
250✔
5573

5574
  case SELECT_TERM:
×
5575
    assert_toplevel_select(ctx, select_term_desc(terms, t), tt);
×
5576
    break;
×
5577

5578
  case DISTINCT_TERM:
173✔
5579
    assert_toplevel_distinct(ctx, distinct_term_desc(terms, t), tt);
173✔
5580
    break;
171✔
5581

5582
  case VARIABLE:
×
5583
    code = FREE_VARIABLE_IN_FORMULA;
×
5584
    goto abort;
×
5585

5586
  case FORALL_TERM:
×
5587
    if (context_in_strict_mode(ctx)) {
×
5588
      code = QUANTIFIERS_NOT_SUPPORTED;
×
5589
      goto abort;
×
5590
    }
5591
    break;
×
5592

5593
  case BIT_TERM:
32,262✔
5594
    assert_toplevel_bit_select(ctx, bit_term_desc(terms, t), tt);
32,262✔
5595
    break;
32,262✔
5596

5597
  case BV_EQ_ATOM:
9,331✔
5598
    assert_toplevel_bveq(ctx, bveq_atom_desc(terms, t), tt);
9,331✔
5599
    break;
9,323✔
5600

5601
  case BV_GE_ATOM:
1,486✔
5602
    assert_toplevel_bvge(ctx, bvge_atom_desc(terms, t), tt);
1,486✔
5603
    break;
1,486✔
5604

5605
  case BV_SGE_ATOM:
455✔
5606
    assert_toplevel_bvsge(ctx, bvsge_atom_desc(terms, t), tt);
455✔
5607
    break;
455✔
5608

5609
  default:
×
5610
    code = INTERNAL_ERROR;
×
5611
    goto abort;
×
5612
  }
5613

5614
  return;
125,434✔
5615

5616
 abort:
×
5617
  longjmp(ctx->env, code);
×
5618
}
5619

5620

5621

5622
/*
5623
 * Assert (t == tt) for a boolean term t:
5624
 * - if t is not internalized, record the mapping
5625
 *   (root t) --> tt in the internalization table
5626
 */
5627
static void assert_term(context_t *ctx, term_t t, bool tt) {
998✔
5628
  term_table_t *terms;
5629
  int32_t code;
5630
  literal_t l;
5631

5632
  assert(is_boolean_term(ctx->terms, t));
5633

5634
  /*
5635
   * Apply substitution + fix polarity
5636
   */
5637
  t = intern_tbl_get_root(&ctx->intern, t);
998✔
5638
  tt ^= is_neg_term(t);
998✔
5639
  t = unsigned_term(t);
998✔
5640

5641
  if (intern_tbl_root_is_mapped(&ctx->intern, t)) {
998✔
5642
    /*
5643
     * The root is already mapped:
5644
     * Either t is already internalized, or it occurs in
5645
     * one of the vectors top_eqs, top_atoms, top_formulas
5646
     * and it will be internalized/asserted later.
5647
     */
5648
    code = intern_tbl_map_of_root(&ctx->intern, t);
171✔
5649
    assert_internalization_code(ctx, code, tt);
171✔
5650

5651
  } else {
5652
    if (context_atom_requires_mcsat(ctx, t)) {
827✔
NEW
5653
      l = map_mcsat_atom_to_literal(ctx, t);
×
NEW
5654
      code = literal2code(l);
×
NEW
5655
      intern_tbl_map_root(&ctx->intern, t, code);
×
NEW
5656
      assert_internalization_code(ctx, code, tt);
×
NEW
5657
      return;
×
5658
    }
5659
    if (ctx->mcsat_supplement) {
827✔
NEW
5660
      context_observe_mcsat_atom(ctx, t, tt ? true_literal : false_literal);
×
5661
    }
5662

5663
    // store the mapping t --> tt
5664
    intern_tbl_map_root(&ctx->intern, t, bool2code(tt));
827✔
5665

5666
    // internalize and assert
5667
    terms = ctx->terms;
827✔
5668
    switch (term_kind(terms, t)) {
827✔
5669
    case CONSTANT_TERM:
×
5670
      // should always be internalized
5671
      code = INTERNAL_ERROR;
×
5672
      goto abort;
×
5673

5674
    case UNINTERPRETED_TERM:
1✔
5675
      // nothing to do: t --> true/false in the internalization table
5676
      break;
1✔
5677

5678
    case ITE_TERM:
2✔
5679
    case ITE_SPECIAL:
5680
      assert_toplevel_ite(ctx, ite_term_desc(terms, t), tt);
2✔
5681
      break;
2✔
5682

5683
    case OR_TERM:
31✔
5684
      assert_toplevel_or(ctx, or_term_desc(terms, t), tt);
31✔
5685
      break;
31✔
5686

5687
    case XOR_TERM:
×
5688
      assert_toplevel_xor(ctx, xor_term_desc(terms, t), tt);
×
5689
      break;
×
5690

5691
    case EQ_TERM:
11✔
5692
      assert_toplevel_eq(ctx, eq_term_desc(terms, t), tt);
11✔
5693
      break;
11✔
5694

5695
    case ARITH_IS_INT_ATOM:
×
5696
      assert_toplevel_arith_is_int(ctx, arith_is_int_arg(terms, t), tt);
×
5697
      break;
×
5698

5699
    case ARITH_EQ_ATOM:
4✔
5700
      assert_toplevel_arith_eq(ctx, arith_eq_arg(terms, t), tt);
4✔
5701
      break;
4✔
5702

5703
    case ARITH_GE_ATOM:
7✔
5704
      assert_toplevel_arith_geq(ctx, arith_ge_arg(terms, t), tt);
7✔
5705
      break;
7✔
5706

5707
    case ARITH_BINEQ_ATOM:
181✔
5708
      assert_toplevel_arith_bineq(ctx, arith_bineq_atom_desc(terms, t), tt);
181✔
5709
      break;
181✔
5710

5711
    case ARITH_DIVIDES_ATOM:
×
5712
      assert_toplevel_arith_divides(ctx, arith_divides_atom_desc(terms, t), tt);
×
5713
      break;
×
5714

5715
    case APP_TERM:
2✔
5716
      assert_toplevel_apply(ctx, app_term_desc(terms, t), tt);
2✔
5717
      break;
2✔
5718

5719
    case SELECT_TERM:
×
5720
      assert_toplevel_select(ctx, select_term_desc(terms, t), tt);
×
5721
      break;
×
5722

5723
    case DISTINCT_TERM:
×
5724
      assert_toplevel_distinct(ctx, distinct_term_desc(terms, t), tt);
×
5725
      break;
×
5726

5727
    case VARIABLE:
×
5728
      code = FREE_VARIABLE_IN_FORMULA;
×
5729
      goto abort;
×
5730

5731
    case FORALL_TERM:
×
5732
      if (context_in_strict_mode(ctx)) {
×
5733
        code = QUANTIFIERS_NOT_SUPPORTED;
×
5734
        goto abort;
×
5735
      }
5736
      break;
×
5737

5738
    case BIT_TERM:
543✔
5739
      assert_toplevel_bit_select(ctx, bit_term_desc(terms, t), tt);
543✔
5740
      break;
542✔
5741

5742
    case BV_EQ_ATOM:
39✔
5743
      assert_toplevel_bveq(ctx, bveq_atom_desc(terms, t), tt);
39✔
5744
      break;
39✔
5745

5746
    case BV_GE_ATOM:
2✔
5747
      assert_toplevel_bvge(ctx, bvge_atom_desc(terms, t), tt);
2✔
5748
      break;
2✔
5749

5750
    case BV_SGE_ATOM:
4✔
5751
      assert_toplevel_bvsge(ctx, bvsge_atom_desc(terms, t), tt);
4✔
5752
      break;
4✔
5753

5754
    default:
×
5755
      code = INTERNAL_ERROR;
×
5756
      goto abort;
×
5757
    }
5758
  }
5759

5760
  return;
993✔
5761

5762
 abort:
×
5763
  longjmp(ctx->env, code);
×
5764
}
5765

5766

5767

5768

5769
/************************
5770
 *  PARAMETERS/OPTIONS  *
5771
 ***********************/
5772

5773
/*
5774
 * Map architecture id to theories word
5775
 */
5776
static const uint32_t arch2theories[NUM_ARCH] = {
5777
  0,                           //  CTX_ARCH_NOSOLVERS --> empty theory
5778

5779
  UF_MASK,                     //  CTX_ARCH_EG
5780
  ARITH_MASK,                  //  CTX_ARCH_SPLX
5781
  IDL_MASK,                    //  CTX_ARCH_IFW
5782
  RDL_MASK,                    //  CTX_ARCH_RFW
5783
  BV_MASK,                     //  CTX_ARCH_BV
5784
  UF_MASK|FUN_MASK,            //  CTX_ARCH_EGFUN
5785
  UF_MASK|ARITH_MASK,          //  CTX_ARCH_EGSPLX
5786
  UF_MASK|BV_MASK,             //  CTX_ARCH_EGBV
5787
  UF_MASK|ARITH_MASK|FUN_MASK, //  CTX_ARCH_EGFUNSPLX
5788
  UF_MASK|BV_MASK|FUN_MASK,    //  CTX_ARCH_EGFUNBV
5789
  UF_MASK|BV_MASK|ARITH_MASK,  //  CTX_ARCH_EGSPLXBV
5790
  ALLTH_MASK,                  //  CTX_ARCH_EGFUNSPLXBV
5791

5792
  IDL_MASK,                    //  CTX_ARCH_AUTO_IDL
5793
  RDL_MASK,                    //  CTX_ARCH_AUTO_RDL
5794

5795
  UF_MASK|ARITH_MASK|FUN_MASK  //  CTX_ARCH_MCSAT
5796
};
5797

5798

5799
/*
5800
 * Each architecture has a fixed set of solver components:
5801
 * - the set of components is stored as a bit vector (on 8bits)
5802
 * - this uses the following bit-masks
5803
 * For the AUTO_xxx architecture, nothing is required initially,
5804
 * so the bitmask is 0.
5805
 */
5806
#define EGRPH  0x1
5807
#define SPLX   0x2
5808
#define IFW    0x4
5809
#define RFW    0x8
5810
#define BVSLVR 0x10
5811
#define FSLVR  0x20
5812
#define MCSAT  0x40
5813

5814
static const uint8_t arch_components[NUM_ARCH] = {
5815
  0,                        //  CTX_ARCH_NOSOLVERS
5816

5817
  EGRPH,                    //  CTX_ARCH_EG
5818
  SPLX,                     //  CTX_ARCH_SPLX
5819
  IFW,                      //  CTX_ARCH_IFW
5820
  RFW,                      //  CTX_ARCH_RFW
5821
  BVSLVR,                   //  CTX_ARCH_BV
5822
  EGRPH|FSLVR,              //  CTX_ARCH_EGFUN
5823
  EGRPH|SPLX,               //  CTX_ARCH_EGSPLX
5824
  EGRPH|BVSLVR,             //  CTX_ARCH_EGBV
5825
  EGRPH|SPLX|FSLVR,         //  CTX_ARCH_EGFUNSPLX
5826
  EGRPH|BVSLVR|FSLVR,       //  CTX_ARCH_EGFUNBV
5827
  EGRPH|SPLX|BVSLVR,        //  CTX_ARCH_EGSPLXBV
5828
  EGRPH|SPLX|BVSLVR|FSLVR,  //  CTX_ARCH_EGFUNSPLXBV
5829

5830
  0,                        //  CTX_ARCH_AUTO_IDL
5831
  0,                        //  CTX_ARCH_AUTO_RDL
5832

5833
  MCSAT                     //  CTX_ARCH_MCSAT
5834
};
5835

5836

5837
/*
5838
 * Smt mode for a context mode
5839
 */
5840
static const smt_mode_t core_mode[NUM_MODES] = {
5841
  SMT_MODE_BASIC,       // one check
5842
  SMT_MODE_BASIC,       // multichecks
5843
  SMT_MODE_PUSHPOP,     // push/pop
5844
  SMT_MODE_INTERACTIVE, // interactive
5845
};
5846

5847

5848
/*
5849
 * Flags for a context mode
5850
 */
5851
static const uint32_t mode2options[NUM_MODES] = {
5852
  0,
5853
  MULTICHECKS_OPTION_MASK,
5854
  MULTICHECKS_OPTION_MASK|PUSHPOP_OPTION_MASK,
5855
  MULTICHECKS_OPTION_MASK|PUSHPOP_OPTION_MASK|CLEANINT_OPTION_MASK,
5856
};
5857

5858

5859

5860

5861

5862

5863
/*
5864
 * SIMPLEX OPTIONS
5865
 */
5866

5867
/*
5868
 * Which version of the arithmetic solver is present
5869
 */
5870
bool context_has_idl_solver(context_t *ctx) {
8✔
5871
  uint8_t solvers;
5872
  solvers = arch_components[ctx->arch];
8✔
5873
  return ctx->arith_solver != NULL && (solvers & IFW);
8✔
5874
}
5875

5876
bool context_has_rdl_solver(context_t *ctx) {
×
5877
  uint8_t solvers;
5878
  solvers = arch_components[ctx->arch];
×
5879
  return ctx->arith_solver != NULL && (solvers & RFW);
×
5880
}
5881

5882
bool context_has_simplex_solver(context_t *ctx) {
45,898✔
5883
  uint8_t solvers;
5884
  solvers = arch_components[ctx->arch];
45,898✔
5885
  return ctx->arith_solver != NULL && (solvers & SPLX);
45,898✔
5886
}
5887

5888

5889
/*
5890
 * If the simplex solver already exists, the options are propagated.
5891
 * Otherwise, they are recorded into the option flags. They will
5892
 * be set up when the simplex solver is created.
5893
 */
5894
void enable_splx_eager_lemmas(context_t *ctx) {
180✔
5895
  ctx->options |= SPLX_EGRLMAS_OPTION_MASK;
180✔
5896
  if (context_has_simplex_solver(ctx)) {
180✔
5897
    simplex_enable_eager_lemmas(ctx->arith_solver);
180✔
5898
  }
5899
}
180✔
5900

5901
void disable_splx_eager_lemmas(context_t *ctx) {
×
5902
  ctx->options &= ~SPLX_EGRLMAS_OPTION_MASK;
×
5903
  if (context_has_simplex_solver(ctx)) {
×
5904
    simplex_disable_eager_lemmas(ctx->arith_solver);
×
5905
  }
5906
}
×
5907

5908

5909
void enable_splx_periodic_icheck(context_t *ctx) {
154✔
5910
  ctx->options |= SPLX_ICHECK_OPTION_MASK;
154✔
5911
  if (context_has_simplex_solver(ctx)) {
154✔
5912
    simplex_enable_periodic_icheck(ctx->arith_solver);
143✔
5913
  }
5914
}
154✔
5915

5916
void disable_splx_periodic_icheck(context_t *ctx) {
×
5917
  ctx->options &= ~SPLX_ICHECK_OPTION_MASK;
×
5918
  if (context_has_simplex_solver(ctx)) {
×
5919
    simplex_disable_periodic_icheck(ctx->arith_solver);
×
5920
  }
5921
}
×
5922

5923
void enable_splx_eqprop(context_t *ctx) {
79✔
5924
  ctx->options |= SPLX_EQPROP_OPTION_MASK;
79✔
5925
  if (context_has_simplex_solver(ctx)) {
79✔
5926
    simplex_enable_eqprop(ctx->arith_solver);
79✔
5927
  }
5928
}
79✔
5929

5930
void disable_splx_eqprop(context_t *ctx) {
×
5931
  ctx->options &= ~SPLX_EQPROP_OPTION_MASK;
×
5932
  if (context_has_simplex_solver(ctx)) {
×
5933
    simplex_disable_eqprop(ctx->arith_solver);
×
5934
  }
5935
}
×
5936

5937

5938

5939

5940
/******************
5941
 *  EMPTY SOLVER  *
5942
 *****************/
5943

5944
/*
5945
 * We need an empty theory solver for initializing
5946
 * the core if the architecture is NOSOLVERS.
5947
 */
5948
static void donothing(void *solver) {
2,610✔
5949
}
2,610✔
5950

5951
static void null_backtrack(void *solver, uint32_t backlevel) {
×
5952
}
×
5953

5954
static bool null_propagate(void *solver) {
×
5955
  return true;
×
5956
}
5957

5958
static fcheck_code_t null_final_check(void *solver) {
×
5959
  return FCHECK_SAT;
×
5960
}
5961

5962
static th_ctrl_interface_t null_ctrl = {
5963
  donothing,        // start_internalization
5964
  donothing,        // start_search
5965
  null_propagate,   // propagate
5966
  null_final_check, // final check
5967
  donothing,        // increase_decision_level
5968
  null_backtrack,   // backtrack
5969
  donothing,        // push
5970
  donothing,        // pop
5971
  donothing,        // reset
5972
  donothing,        // clear
5973
};
5974

5975

5976
// for the smt interface, nothing should be called since there are no atoms
5977
static th_smt_interface_t null_smt = {
5978
  NULL, NULL, NULL, NULL, NULL,
5979
};
5980

5981

5982

5983

5984
/****************************
5985
 *  ARCHITECTURE & SOLVERS  *
5986
 ***************************/
5987

5988
/*
5989
 * Check whether a given architecture includes a specific solver
5990
 */
5991
bool context_arch_has_egraph(context_arch_t arch) {
417✔
5992
  return arch_components[arch] & EGRPH;
417✔
5993
}
5994

5995
bool context_arch_has_bv(context_arch_t arch) {
×
5996
  return arch_components[arch] & BVSLVR;
×
5997
}
5998

5999
bool context_arch_has_fun(context_arch_t arch) {
×
6000
  return arch_components[arch] & FSLVR;
×
6001
}
6002

6003
bool context_arch_has_arith(context_arch_t arch) {
×
6004
  return arch_components[arch] & (SPLX|IFW|RFW);
×
6005
}
6006

6007
bool context_arch_has_mcsat(context_arch_t arch) {
×
6008
  return arch_components[arch] & MCSAT;
×
6009
}
6010

6011
bool context_arch_has_simplex(context_arch_t arch) {
×
6012
  return arch_components[arch] & SPLX;
×
6013
}
6014

6015
bool context_arch_has_ifw(context_arch_t arch) {
×
6016
  return arch_components[arch] & IFW;
×
6017
}
6018

6019
bool context_arch_has_rfw(context_arch_t arch) {
×
6020
  return arch_components[arch] & RFW;
×
6021
}
6022

6023

6024
/****************************
6025
 *  SOLVER INITIALIZATION   *
6026
 ***************************/
6027

6028
/*
6029
 * Create and initialize the egraph
6030
 * - the core must be created first
6031
 */
6032
static void create_egraph(context_t *ctx) {
4,796✔
6033
  egraph_t *egraph;
6034

6035
  assert(ctx->egraph == NULL);
6036

6037
  egraph = (egraph_t *) safe_malloc(sizeof(egraph_t));
4,796✔
6038
  init_egraph(egraph, ctx->types);
4,796✔
6039
  ctx->egraph = egraph;
4,796✔
6040
}
4,796✔
6041

6042

6043
/*
6044
 * Create and initialize the mcsat solver
6045
 */
6046
static void create_mcsat(context_t *ctx) {
749✔
6047
  assert(ctx->mcsat == NULL);
6048
  ctx->mcsat = mcsat_new(ctx);
749✔
6049
}
749✔
6050

6051

6052

6053
/*
6054
 * Create and initialize the idl solver and attach it to the core
6055
 * - there must be no other solvers and no egraph
6056
 * - if automatic is true, attach the solver to the core, otherwise
6057
 *   initialize the core
6058
 * - copy the solver's internalization interface into arith
6059
 */
6060
static void create_idl_solver(context_t *ctx, bool automatic) {
26✔
6061
  idl_solver_t *solver;
6062
  smt_mode_t cmode;
6063

6064
  assert(ctx->egraph == NULL && ctx->arith_solver == NULL && ctx->bv_solver == NULL &&
6065
         ctx->fun_solver == NULL && ctx->core != NULL);
6066

6067
  cmode = core_mode[ctx->mode];
26✔
6068
  solver = (idl_solver_t *) safe_malloc(sizeof(idl_solver_t));
26✔
6069
  init_idl_solver(solver, ctx->core, &ctx->gate_manager);
26✔
6070
  if (automatic) {
26✔
6071
    smt_core_reset_thsolver(ctx->core, solver, idl_ctrl_interface(solver),
26✔
6072
                            idl_smt_interface(solver));
6073
  } else {
6074
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, idl_ctrl_interface(solver),
×
6075
                  idl_smt_interface(solver), cmode);
6076
  }
6077
  idl_solver_init_jmpbuf(solver, &ctx->env);
26✔
6078
  ctx->arith_solver = solver;
26✔
6079
  ctx->arith = *idl_arith_interface(solver);
26✔
6080
}
26✔
6081

6082

6083
/*
6084
 * Create and initialize the rdl solver and attach it to the core.
6085
 * - there must be no other solvers and no egraph
6086
 * - if automatic is true, attach rdl to the core, otherwise
6087
 *   initialize the core
6088
 * - copy the solver's internalization interface in ctx->arith
6089
 */
6090
static void create_rdl_solver(context_t *ctx, bool automatic) {
8✔
6091
  rdl_solver_t *solver;
6092
  smt_mode_t cmode;
6093

6094
  assert(ctx->egraph == NULL && ctx->arith_solver == NULL && ctx->bv_solver == NULL &&
6095
         ctx->fun_solver == NULL && ctx->core != NULL);
6096

6097
  cmode = core_mode[ctx->mode];
8✔
6098
  solver = (rdl_solver_t *) safe_malloc(sizeof(rdl_solver_t));
8✔
6099
  init_rdl_solver(solver, ctx->core, &ctx->gate_manager);
8✔
6100
  if (automatic) {
8✔
6101
    smt_core_reset_thsolver(ctx->core, solver, rdl_ctrl_interface(solver),
8✔
6102
                            rdl_smt_interface(solver));
6103
  } else {
6104
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, rdl_ctrl_interface(solver),
×
6105
                  rdl_smt_interface(solver), cmode);
6106
  }
6107
  rdl_solver_init_jmpbuf(solver, &ctx->env);
8✔
6108
  ctx->arith_solver = solver;
8✔
6109
  ctx->arith = *rdl_arith_interface(solver);
8✔
6110
}
8✔
6111

6112

6113
/*
6114
 * Create an initialize the simplex solver and attach it to the core
6115
 * or to the egraph if the egraph exists.
6116
 * - if automatic is true, this is part of auto_idl or auto_rdl. So the
6117
 *   core is already initialized.
6118
 */
6119
static void create_simplex_solver(context_t *ctx, bool automatic) {
14,912✔
6120
  simplex_solver_t *solver;
6121
  smt_mode_t cmode;
6122

6123
  assert(ctx->arith_solver == NULL && ctx->core != NULL);
6124

6125
  cmode = core_mode[ctx->mode];
14,912✔
6126
  solver = (simplex_solver_t *) safe_malloc(sizeof(simplex_solver_t));
14,912✔
6127
  init_simplex_solver(solver, ctx->core, &ctx->gate_manager, ctx->egraph);
14,912✔
6128

6129
  // set simplex options
6130
  if (splx_eager_lemmas_enabled(ctx)) {
14,912✔
6131
    simplex_enable_eager_lemmas(solver);
×
6132
  }
6133
  if (splx_periodic_icheck_enabled(ctx)) {
14,912✔
6134
    simplex_enable_periodic_icheck(solver);
×
6135
  }
6136
  if (splx_eqprop_enabled(ctx)) {
14,912✔
6137
    simplex_enable_eqprop(solver);
×
6138
  }
6139

6140
  // row saving must be enabled unless we're in ONECHECK mode
6141
  if (ctx->mode != CTX_MODE_ONECHECK) {
14,912✔
6142
    simplex_enable_row_saving(solver);
14,759✔
6143
  }
6144

6145
  if (ctx->egraph != NULL) {
14,912✔
6146
    // attach the simplex solver as a satellite solver to the egraph
6147
    egraph_attach_arithsolver(ctx->egraph, solver, simplex_ctrl_interface(solver),
4,339✔
6148
                              simplex_smt_interface(solver), simplex_egraph_interface(solver),
6149
                              simplex_arith_egraph_interface(solver));
6150
  } else if (!automatic) {
10,573✔
6151
    // attach simplex to the core and initialize the core
6152
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, simplex_ctrl_interface(solver),
10,572✔
6153
                  simplex_smt_interface(solver), cmode);
6154
  } else {
6155
    // the core is already initialized: attach simplex
6156
    smt_core_reset_thsolver(ctx->core, solver, simplex_ctrl_interface(solver),
1✔
6157
                            simplex_smt_interface(solver));
6158
  }
6159

6160
  simplex_solver_init_jmpbuf(solver, &ctx->env);
14,912✔
6161
  ctx->arith_solver = solver;
14,912✔
6162
  ctx->arith = *simplex_arith_interface(solver);
14,912✔
6163
}
14,912✔
6164

6165

6166
/*
6167
 * Create IDL/SIMPLEX solver based on ctx->dl_profile
6168
 */
6169
static void create_auto_idl_solver(context_t *ctx) {
27✔
6170
  dl_data_t *profile;
6171
  int32_t bound;
6172
  double atom_density;
6173

6174
  assert(ctx->dl_profile != NULL);
6175
  profile = ctx->dl_profile;
27✔
6176

6177
  if (q_is_smallint(&profile->path_bound)) {
27✔
6178
    bound = q_get_smallint(&profile->path_bound);
26✔
6179
  } else {
6180
    bound = INT32_MAX;
1✔
6181
  }
6182

6183
  if (bound >= 1073741824) {
27✔
6184
    // simplex required because of arithmetic overflow
6185
    create_simplex_solver(ctx, true);
1✔
6186
    ctx->arch = CTX_ARCH_SPLX;
1✔
6187
  } else if (profile->num_vars >= 1000) {
26✔
6188
    // too many variables for FW
6189
    create_simplex_solver(ctx, true);
×
6190
    ctx->arch = CTX_ARCH_SPLX;
×
6191
  } else if (profile->num_vars <= 200 || profile->num_eqs == 0) {
26✔
6192
    // use FW for now, until we've tested SIMPLEX more
6193
    // 0 equalities usually means a scheduling problem
6194
    // --flatten works better on IDL/FW
6195
    create_idl_solver(ctx, true);
26✔
6196
    ctx->arch = CTX_ARCH_IFW;
26✔
6197
    enable_diseq_and_or_flattening(ctx);
26✔
6198

6199
  } else {
6200

6201
    // problem density
6202
    if (profile->num_vars > 0) {
×
6203
      atom_density = ((double) profile->num_atoms)/profile->num_vars;
×
6204
    } else {
6205
      atom_density = 0;
×
6206
    }
6207

6208
    if (atom_density >= 10.0) {
×
6209
      // high density: use FW
6210
      create_idl_solver(ctx, true);
×
6211
      ctx->arch = CTX_ARCH_IFW;
×
6212
      enable_diseq_and_or_flattening(ctx);
×
6213
    } else {
6214
      create_simplex_solver(ctx, true);
×
6215
      ctx->arch = CTX_ARCH_SPLX;
×
6216
    }
6217
  }
6218
}
27✔
6219

6220

6221
/*
6222
 * Create RDL/SIMPLEX solver based on ctx->dl_profile
6223
 */
6224
static void create_auto_rdl_solver(context_t *ctx) {
8✔
6225
  dl_data_t *profile;
6226
  double atom_density;
6227

6228
  assert(ctx->dl_profile != NULL);
6229
  profile = ctx->dl_profile;
8✔
6230

6231
  if (profile->num_vars >= 1000) {
8✔
6232
    create_simplex_solver(ctx, true);
×
6233
    ctx->arch = CTX_ARCH_SPLX;
×
6234
  } else if (profile->num_vars <= 200 || profile->num_eqs == 0) {
8✔
6235
    create_rdl_solver(ctx, true);
8✔
6236
    ctx->arch = CTX_ARCH_RFW;
8✔
6237
  } else {
6238
    // problem density
6239
    if (profile->num_vars > 0) {
×
6240
      atom_density = ((double) profile->num_atoms)/profile->num_vars;
×
6241
    } else {
6242
      atom_density = 0;
×
6243
    }
6244

6245
    if (atom_density >= 7.0) {
×
6246
      // high density: use FW
6247
      create_rdl_solver(ctx, true);
×
6248
      ctx->arch = CTX_ARCH_RFW;
×
6249
    } else {
6250
      // low-density: use SIMPLEX
6251
      create_simplex_solver(ctx, true);
×
6252
      ctx->arch = CTX_ARCH_SPLX;
×
6253
    }
6254
  }
6255
}
8✔
6256

6257

6258

6259
/*
6260
 * Create the bitvector solver
6261
 * - attach it to the egraph if there's an egraph
6262
 * - attach it to the core and initialize the core otherwise
6263
 */
6264
static void create_bv_solver(context_t *ctx) {
10,691✔
6265
  bv_solver_t *solver;
6266
  smt_mode_t cmode;
6267

6268
  assert(ctx->bv_solver == NULL && ctx->core != NULL);
6269

6270
  cmode = core_mode[ctx->mode];
10,691✔
6271
  solver = (bv_solver_t *) safe_malloc(sizeof(bv_solver_t));
10,691✔
6272
  init_bv_solver(solver, ctx->core, ctx->egraph);
10,691✔
6273

6274
  if (ctx->egraph != NULL) {
10,691✔
6275
    // attach as a satellite to the egraph
6276
    egraph_attach_bvsolver(ctx->egraph, solver, bv_solver_ctrl_interface(solver),
4,420✔
6277
                           bv_solver_smt_interface(solver), bv_solver_egraph_interface(solver),
6278
                           bv_solver_bv_egraph_interface(solver));
6279
  } else {
6280
    // attach to the core and initialize the core
6281
    init_smt_core(ctx->core, CTX_DEFAULT_CORE_SIZE, solver, bv_solver_ctrl_interface(solver),
6,271✔
6282
                  bv_solver_smt_interface(solver), cmode);
6283
  }
6284

6285
  // EXPERIMENT
6286
  //  smt_core_make_etable(ctx->core);
6287
  // END
6288

6289
  bv_solver_init_jmpbuf(solver, &ctx->env);
10,691✔
6290
  ctx->bv_solver = solver;
10,691✔
6291
  ctx->bv = *bv_solver_bv_interface(solver);
10,691✔
6292
}
10,691✔
6293

6294

6295
/*
6296
 * Create the array/function theory solver and attach it to the egraph
6297
 */
6298
static void create_fun_solver(context_t *ctx) {
4,427✔
6299
  fun_solver_t *solver;
6300

6301
  assert(ctx->egraph != NULL && ctx->fun_solver == NULL);
6302

6303
  solver = (fun_solver_t *) safe_malloc(sizeof(fun_solver_t));
4,427✔
6304
  init_fun_solver(solver, ctx->core, &ctx->gate_manager, ctx->egraph, ctx->types);
4,427✔
6305
  egraph_attach_funsolver(ctx->egraph, solver, fun_solver_ctrl_interface(solver),
4,427✔
6306
                          fun_solver_egraph_interface(solver),
6307
                          fun_solver_fun_egraph_interface(solver));
6308

6309
  ctx->fun_solver = solver;
4,427✔
6310
}
4,427✔
6311

6312

6313
/*
6314
 * Allocate and initialize solvers based on architecture and mode
6315
 * - core and gate manager must exist at this point
6316
 * - if the architecture is either AUTO_IDL or AUTO_RDL, no theory solver
6317
 *   is allocated yet, and the core is initialized for Boolean only
6318
 * - otherwise, all components are ready and initialized, including the core.
6319
 */
6320
static void init_solvers(context_t *ctx) {
22,424✔
6321
  uint8_t solvers;
6322
  smt_core_t *core;
6323
  smt_mode_t cmode;
6324
  egraph_t *egraph;
6325

6326
  solvers = arch_components[ctx->arch];
22,424✔
6327

6328
  ctx->egraph = NULL;
22,424✔
6329
  ctx->arith_solver = NULL;
22,424✔
6330
  ctx->bv_solver = NULL;
22,424✔
6331
  ctx->fun_solver = NULL;
22,424✔
6332
  ctx->quant_solver = NULL;
22,424✔
6333
  ctx->mcsat_supplement = false;
22,424✔
6334

6335
  // Create egraph first, then satellite solvers
6336
  if (solvers & EGRPH) {
22,424✔
6337
    create_egraph(ctx);
4,796✔
6338
  }
6339

6340
  // Create mcsat
6341
  if (solvers & MCSAT) {
22,424✔
6342
    create_mcsat(ctx);
749✔
6343
  }
6344

6345
  // Arithmetic solver
6346
  if (solvers & SPLX) {
22,424✔
6347
    create_simplex_solver(ctx, false);
14,911✔
6348
  } else if (solvers & IFW) {
7,513✔
6349
    create_idl_solver(ctx, false);
×
6350
  } else if (solvers & RFW) {
7,513✔
6351
    create_rdl_solver(ctx, false);
×
6352
  }
6353

6354
  // Bitvector solver
6355
  if (solvers & BVSLVR) {
22,424✔
6356
    create_bv_solver(ctx);
10,691✔
6357
  }
6358

6359
  // Array solver
6360
  if (solvers & FSLVR) {
22,424✔
6361
    create_fun_solver(ctx);
4,427✔
6362
  }
6363

6364
  /*
6365
   * At this point all solvers are ready and initialized, except the
6366
   * egraph and core if the egraph is present or the core if there are
6367
   * no solvers, or if arch is AUTO_IDL or AUTO_RDL.
6368
   */
6369
  cmode = core_mode[ctx->mode];   // initialization mode for the core
22,424✔
6370
  egraph = ctx->egraph;
22,424✔
6371
  core = ctx->core;
22,424✔
6372
  if (egraph != NULL) {
22,424✔
6373
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, egraph, egraph_ctrl_interface(egraph),
4,796✔
6374
                  egraph_smt_interface(egraph), cmode);
6375
    egraph_attach_core(egraph, core);
4,796✔
6376

6377
  } else if (solvers == 0) {
17,628✔
6378
    /*
6379
     * Boolean solver only. If arch if AUTO_IDL or AUTO_RDL, the
6380
     * theory solver will be changed later by create_auto_idl_solver
6381
     * or create_auto_rdl_solver.
6382
     */
6383
    assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL);
6384
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, NULL, &null_ctrl, &null_smt, cmode);
36✔
6385
  } else if (solvers == MCSAT) {
17,592✔
6386
    /*
6387
     * MCsat solver only, we create the core, but never use it.
6388
     */
6389
    assert(ctx->egraph == NULL && ctx->arith_solver == NULL &&
6390
           ctx->bv_solver == NULL && ctx->fun_solver == NULL);
6391
    init_smt_core(core, CTX_DEFAULT_CORE_SIZE, NULL, &null_ctrl, &null_smt, cmode);
749✔
6392
  }
6393

6394
  /*
6395
   * Optimization: if the arch is NOSOLVERS or BV then we set bool_only in the core
6396
   */
6397
  if (ctx->arch == CTX_ARCH_NOSOLVERS || ctx->arch == CTX_ARCH_BV) {
22,424✔
6398
    smt_core_set_bool_only(core);
6,271✔
6399
  }
6400
}
22,424✔
6401

6402

6403

6404

6405
/*
6406
 * Delete the arithmetic solver
6407
 */
6408
static void delete_arith_solver(context_t *ctx) {
14,945✔
6409
  uint8_t solvers;
6410

6411
  assert(ctx->arith_solver != NULL);
6412

6413
  solvers = arch_components[ctx->arch];
14,945✔
6414
  if (solvers & IFW) {
14,945✔
6415
    delete_idl_solver(ctx->arith_solver);
26✔
6416
  } else if (solvers & RFW) {
14,919✔
6417
    delete_rdl_solver(ctx->arith_solver);
8✔
6418
  } else if (solvers & SPLX) {
14,911✔
6419
    delete_simplex_solver(ctx->arith_solver);
14,911✔
6420
  }
6421
  safe_free(ctx->arith_solver);
14,945✔
6422
  ctx->arith_solver = NULL;
14,945✔
6423
}
14,945✔
6424

6425

6426

6427

6428
/*****************************
6429
 *  CONTEXT INITIALIZATION   *
6430
 ****************************/
6431

6432
/*
6433
 * Check mode and architecture
6434
 */
6435
#ifndef NDEBUG
6436
static inline bool valid_mode(context_mode_t mode) {
6437
  return CTX_MODE_ONECHECK <= mode && mode <= CTX_MODE_INTERACTIVE;
6438
}
6439

6440
static inline bool valid_arch(context_arch_t arch) {
6441
  return CTX_ARCH_NOSOLVERS <= arch && arch <= CTX_ARCH_MCSAT;
6442
}
6443
#endif
6444

6445

6446
/*
6447
 * Initialize ctx for the given mode and architecture
6448
 * - terms = term table for that context
6449
 * - qflag = true means quantifiers allowed
6450
 * - qflag = false means no quantifiers
6451
 */
6452
void init_context(context_t *ctx, term_table_t *terms, smt_logic_t logic,
22,424✔
6453
                  context_mode_t mode, context_arch_t arch, bool qflag) {
6454
  assert(valid_mode(mode) && valid_arch(arch));
6455

6456
  /*
6457
   * Set architecture and options
6458
   */
6459
  ctx->mode = mode;
22,424✔
6460
  ctx->arch = arch;
22,424✔
6461
  ctx->logic = logic;
22,424✔
6462
  ctx->sat_delegate = SAT_DELEGATE_NONE;
22,424✔
6463
  ctx->sat_delegate_incremental_mode = SAT_DELEGATE_MODE_REBUILD;
22,424✔
6464
  ctx->sat_delegate_incremental_mode_set = false;
22,424✔
6465
  ctx->theories = arch2theories[arch];
22,424✔
6466
  ctx->options = mode2options[mode];
22,424✔
6467
  if (qflag) {
22,424✔
6468
    // quantifiers require egraph
6469
    assert((ctx->theories & UF_MASK) != 0);
6470
    ctx->theories |= QUANT_MASK;
×
6471
  }
6472

6473
  ctx->base_level = 0;
22,424✔
6474
  context_reset_sat_delegate_stats(ctx);
22,424✔
6475

6476
  /*
6477
   * The core is always needed: allocate it here. It's not initialized yet.
6478
   * The other solver are optionals.
6479
   *
6480
   * TODO: we could skip this when we use MCSAT (since then the core is
6481
   * not needed).
6482
   */
6483
  ctx->core = (smt_core_t *) safe_malloc(sizeof(smt_core_t));
22,424✔
6484
  ctx->egraph = NULL;
22,424✔
6485
  ctx->mcsat = NULL;
22,424✔
6486
  ctx->arith_solver = NULL;
22,424✔
6487
  ctx->bv_solver = NULL;
22,424✔
6488
  ctx->fun_solver = NULL;
22,424✔
6489
  ctx->quant_solver = NULL;
22,424✔
6490

6491
  /*
6492
   * Global tables + gate manager
6493
   */
6494
  ctx->types = terms->types;
22,424✔
6495
  ctx->terms = terms;
22,424✔
6496
  init_gate_manager(&ctx->gate_manager, ctx->core);
22,424✔
6497

6498
  /*
6499
   * Simplification/internalization support
6500
   */
6501
  init_intern_tbl(&ctx->intern, 0, terms);
22,424✔
6502
  init_ivector(&ctx->top_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6503
  init_ivector(&ctx->top_atoms, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6504
  init_ivector(&ctx->top_formulas, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6505
  init_ivector(&ctx->top_interns, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6506

6507
  /*
6508
   * Force the internalization mapping for true and false
6509
   * - true  term --> true_occ
6510
   * - false term --> false_occ
6511
   * This mapping holds even if there's no egraph.
6512
   */
6513
  intern_tbl_map_root(&ctx->intern, true_term, bool2code(true));
22,424✔
6514

6515
  /*
6516
   * Auxiliary internalization buffers
6517
   */
6518
  init_ivector(&ctx->subst_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6519
  init_ivector(&ctx->aux_eqs, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6520
  init_ivector(&ctx->aux_atoms, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6521
  init_ivector(&ctx->aux_vector, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6522
  init_int_queue(&ctx->queue, 0);
22,424✔
6523
  init_istack(&ctx->istack);
22,424✔
6524
  init_objstack(&ctx->ostack);
22,424✔
6525
  init_sharing_map(&ctx->sharing, &ctx->intern);
22,424✔
6526
  init_objstore(&ctx->cstore, sizeof(conditional_t), 32);
22,424✔
6527
  init_assumption_stack(&ctx->assumptions);
22,424✔
6528

6529
  ctx->subst = NULL;
22,424✔
6530
  ctx->marks = NULL;
22,424✔
6531
  ctx->cache = NULL;
22,424✔
6532
  ctx->small_cache = NULL;
22,424✔
6533
  ctx->edge_map = NULL;
22,424✔
6534
  ctx->eq_cache = NULL;
22,424✔
6535
  ctx->divmod_table = NULL;
22,424✔
6536
  ctx->explorer = NULL;
22,424✔
6537
  ctx->unsat_core_cache = NULL;
22,424✔
6538
  ctx->sat_delegate_state = NULL;
22,424✔
6539

6540
  ctx->dl_profile = NULL;
22,424✔
6541
  ctx->arith_buffer = NULL;
22,424✔
6542
  ctx->poly_buffer = NULL;
22,424✔
6543
  ctx->aux_poly = NULL;
22,424✔
6544
  ctx->aux_poly_size = 0;
22,424✔
6545

6546
  ctx->bvpoly_buffer = NULL;
22,424✔
6547

6548
  q_init(&ctx->aux);
22,424✔
6549
  init_bvconstant(&ctx->bv_buffer);
22,424✔
6550

6551
  ctx->trace = NULL;
22,424✔
6552

6553
  // mcsat options default
6554
  init_mcsat_options(&ctx->mcsat_options);
22,424✔
6555
  init_ivector(&ctx->mcsat_var_order, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6556
  init_ivector(&ctx->mcsat_initial_var_order, CTX_DEFAULT_VECTOR_SIZE);
22,424✔
6557
  ctx->mcsat_relax_abstractions = NULL;
22,424✔
6558
  ctx->mcsat_relax_abstraction_terms = NULL;
22,424✔
6559
  ctx->mcsat_relax_manager = NULL;
22,424✔
6560
  /*
6561
   * Allocate and initialize the solvers and core
6562
   * NOTE: no theory solver yet if arch is AUTO_IDL or AUTO_RDL
6563
   */
6564
  init_solvers(ctx);
22,424✔
6565

6566
  ctx->en_quant = false;
22,424✔
6567
}
22,424✔
6568

6569

6570

6571

6572
/*
6573
 * Delete ctx
6574
 */
6575
void delete_context(context_t *ctx) {
22,423✔
6576
  context_sat_delegate_state_cleanup(ctx);
22,423✔
6577

6578
  if (ctx->core != NULL) {
22,423✔
6579
    delete_smt_core(ctx->core);
22,423✔
6580
    safe_free(ctx->core);
22,423✔
6581
    ctx->core = NULL;
22,423✔
6582
  }
6583

6584
  if (ctx->mcsat != NULL) {
22,423✔
6585
    mcsat_destruct(ctx->mcsat);
749✔
6586
    safe_free(ctx->mcsat);
749✔
6587
    ctx->mcsat = NULL;
749✔
6588
  }
6589

6590
  if (ctx->mcsat_supplement) {
22,423✔
6591
    context_disable_mcsat_supplement(ctx);
9✔
6592
  }
6593

6594
  if (ctx->egraph != NULL) {
22,423✔
6595
    delete_egraph(ctx->egraph);
4,795✔
6596
    safe_free(ctx->egraph);
4,795✔
6597
    ctx->egraph = NULL;
4,795✔
6598
  }
6599

6600
  if (ctx->arith_solver != NULL) {
22,423✔
6601
    delete_arith_solver(ctx);
14,945✔
6602
  }
6603

6604
  if (ctx->fun_solver != NULL) {
22,423✔
6605
    delete_fun_solver(ctx->fun_solver);
4,426✔
6606
    safe_free(ctx->fun_solver);
4,426✔
6607
    ctx->fun_solver = NULL;
4,426✔
6608
  }
6609

6610
  if (ctx->quant_solver != NULL) {
22,423✔
6611
    delete_quant_solver(ctx->quant_solver);
52✔
6612
    safe_free(ctx->quant_solver);
52✔
6613
    ctx->quant_solver = NULL;
52✔
6614
  }
6615

6616
  if (ctx->bv_solver != NULL) {
22,423✔
6617
    delete_bv_solver(ctx->bv_solver);
10,690✔
6618
    safe_free(ctx->bv_solver);
10,690✔
6619
    ctx->bv_solver = NULL;
10,690✔
6620
  }
6621

6622
  delete_gate_manager(&ctx->gate_manager);
22,423✔
6623
  /* delete_mcsat_options(&ctx->mcsat_options); // if used then the same memory is freed twice */
6624
  delete_ivector(&ctx->mcsat_var_order);
22,423✔
6625
  delete_ivector(&ctx->mcsat_initial_var_order);
22,423✔
6626
  context_delete_mcsat_relaxation(ctx);
22,423✔
6627

6628
  delete_intern_tbl(&ctx->intern);
22,423✔
6629
  delete_ivector(&ctx->top_eqs);
22,423✔
6630
  delete_ivector(&ctx->top_atoms);
22,423✔
6631
  delete_ivector(&ctx->top_formulas);
22,423✔
6632
  delete_ivector(&ctx->top_interns);
22,423✔
6633

6634
  delete_ivector(&ctx->subst_eqs);
22,423✔
6635
  delete_ivector(&ctx->aux_eqs);
22,423✔
6636
  delete_ivector(&ctx->aux_atoms);
22,423✔
6637
  delete_ivector(&ctx->aux_vector);
22,423✔
6638
  delete_int_queue(&ctx->queue);
22,423✔
6639
  delete_istack(&ctx->istack);
22,423✔
6640
  delete_objstack(&ctx->ostack);
22,423✔
6641
  delete_sharing_map(&ctx->sharing);
22,423✔
6642
  delete_objstore(&ctx->cstore);
22,423✔
6643
  delete_assumption_stack(&ctx->assumptions);
22,423✔
6644

6645
  context_free_subst(ctx);
22,423✔
6646
  context_free_marks(ctx);
22,423✔
6647
  context_free_cache(ctx);
22,423✔
6648
  context_free_small_cache(ctx);
22,423✔
6649
  context_free_eq_cache(ctx);
22,423✔
6650
  context_free_divmod_table(ctx);
22,423✔
6651
  context_free_explorer(ctx);
22,423✔
6652

6653
  context_free_dl_profile(ctx);
22,423✔
6654
  context_free_edge_map(ctx);
22,423✔
6655
  context_free_arith_buffer(ctx);
22,423✔
6656
  context_free_poly_buffer(ctx);
22,423✔
6657
  context_free_aux_poly(ctx);
22,423✔
6658

6659
  context_free_bvpoly_buffer(ctx);
22,423✔
6660
  context_invalidate_unsat_core_cache(ctx);
22,423✔
6661

6662
  q_clear(&ctx->aux);
22,423✔
6663
  delete_bvconstant(&ctx->bv_buffer);
22,423✔
6664
}
22,423✔
6665

6666
void context_invalidate_unsat_core_cache(context_t *ctx) {
88,245✔
6667
  if (ctx->unsat_core_cache != NULL) {
88,245✔
6668
    delete_ivector(ctx->unsat_core_cache);
2,741✔
6669
    safe_free(ctx->unsat_core_cache);
2,741✔
6670
    ctx->unsat_core_cache = NULL;
2,741✔
6671
  }
6672
}
88,245✔
6673

6674

6675

6676
/*
6677
 * Reset: remove all assertions and clear all internalization tables
6678
 */
6679
void reset_context(context_t *ctx) {
19✔
6680
  ctx->base_level = 0;
19✔
6681
  context_reset_sat_delegate_stats(ctx);
19✔
6682
  context_invalidate_unsat_core_cache(ctx);
19✔
6683
  context_sat_delegate_state_cleanup(ctx);
19✔
6684

6685
  reset_smt_core(ctx->core); // this propagates reset to all solvers
19✔
6686

6687
  if (ctx->mcsat != NULL) {
19✔
6688
    mcsat_reset(ctx->mcsat);
10✔
6689
  }
6690

6691
  reset_gate_manager(&ctx->gate_manager);
19✔
6692

6693
  ivector_reset(&ctx->mcsat_var_order);
19✔
6694
  ivector_reset(&ctx->mcsat_initial_var_order);
19✔
6695
  context_reset_mcsat_relaxation(ctx);
19✔
6696

6697
  reset_intern_tbl(&ctx->intern);
19✔
6698
  ivector_reset(&ctx->top_eqs);
19✔
6699
  ivector_reset(&ctx->top_atoms);
19✔
6700
  ivector_reset(&ctx->top_formulas);
19✔
6701
  ivector_reset(&ctx->top_interns);
19✔
6702

6703
  // Force the internalization mapping for true and false
6704
  intern_tbl_map_root(&ctx->intern, true_term, bool2code(true));
19✔
6705

6706
  ivector_reset(&ctx->subst_eqs);
19✔
6707
  ivector_reset(&ctx->aux_eqs);
19✔
6708
  ivector_reset(&ctx->aux_atoms);
19✔
6709
  ivector_reset(&ctx->aux_vector);
19✔
6710
  int_queue_reset(&ctx->queue);
19✔
6711
  reset_istack(&ctx->istack);
19✔
6712
  reset_objstack(&ctx->ostack);
19✔
6713
  reset_sharing_map(&ctx->sharing);
19✔
6714
  reset_objstore(&ctx->cstore);
19✔
6715
  reset_assumption_stack(&ctx->assumptions);
19✔
6716

6717
  context_free_subst(ctx);
19✔
6718
  context_free_marks(ctx);
19✔
6719
  context_reset_small_cache(ctx);
19✔
6720
  context_reset_eq_cache(ctx);
19✔
6721
  context_reset_divmod_table(ctx);
19✔
6722
  context_reset_explorer(ctx);
19✔
6723

6724
  context_free_arith_buffer(ctx);
19✔
6725
  context_reset_poly_buffer(ctx);
19✔
6726
  context_free_aux_poly(ctx);
19✔
6727
  context_free_dl_profile(ctx);
19✔
6728

6729
  context_free_bvpoly_buffer(ctx);
19✔
6730

6731
  q_clear(&ctx->aux);
19✔
6732
}
19✔
6733

6734

6735
/*
6736
 * Add tracer to ctx and ctx->core
6737
 */
6738
void context_set_trace(context_t *ctx, tracer_t *trace) {
285✔
6739
  assert(ctx->trace == NULL);
6740
  ctx->trace = trace;
285✔
6741
  smt_core_set_trace(ctx->core, trace);
285✔
6742
  if (ctx->mcsat != NULL) {
285✔
6743
    mcsat_set_tracer(ctx->mcsat, trace);
285✔
6744
  }
6745
  if (ctx->mcsat_supplement) {
285✔
NEW
6746
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
×
NEW
6747
    if (sat != NULL) {
×
NEW
6748
      mcsat_satellite_set_trace(sat, trace);
×
6749
    }
6750
  }
6751
}
285✔
6752

6753

6754
/*
6755
 * Push and pop
6756
 */
6757
void context_push(context_t *ctx) {
18,592✔
6758
  assert(context_supports_pushpop(ctx));
6759
  context_invalidate_unsat_core_cache(ctx);
18,592✔
6760
  smt_push(ctx->core);  // propagates to all solvers
18,592✔
6761
  if (ctx->mcsat != NULL) {
18,592✔
6762
    mcsat_push(ctx->mcsat);
1,342✔
6763
  }
6764
  intern_tbl_push(&ctx->intern);
18,592✔
6765
  assumption_stack_push(&ctx->assumptions);
18,592✔
6766
  context_eq_cache_push(ctx);
18,592✔
6767
  context_divmod_table_push(ctx);
18,592✔
6768

6769
  ctx->base_level ++;
18,592✔
6770
}
18,592✔
6771

6772
void context_pop(context_t *ctx) {
1,574✔
6773
  assert(context_supports_pushpop(ctx) && ctx->base_level > 0);
6774
  context_invalidate_unsat_core_cache(ctx);
1,574✔
6775
  smt_pop(ctx->core);   // propagates to all solvers
1,574✔
6776
  if (ctx->mcsat != NULL) {
1,574✔
6777
    mcsat_pop(ctx->mcsat);
1,258✔
6778
  }
6779
  intern_tbl_pop(&ctx->intern);
1,574✔
6780
  assumption_stack_pop(&ctx->assumptions);
1,574✔
6781
  context_eq_cache_pop(ctx);
1,574✔
6782
  context_divmod_table_pop(ctx);
1,574✔
6783

6784
  context_sat_delegate_state_pop(ctx, ctx->base_level);
1,574✔
6785

6786
  ctx->base_level --;
1,574✔
6787
}
1,574✔
6788

6789

6790

6791

6792

6793
/****************************
6794
 *   ASSERTIONS AND CHECK   *
6795
 ***************************/
6796

6797
/*
6798
 * Build the sharing data
6799
 * - processes all the assertions in vectors top_eqs, top_atoms, top_formulas
6800
 * - this function should be called after building the substitutions
6801
 */
6802
static void context_build_sharing_data(context_t *ctx) {
71,980✔
6803
  sharing_map_t *map;
6804

6805
  map = &ctx->sharing;
71,980✔
6806
  reset_sharing_map(map);
71,980✔
6807
  sharing_map_add_terms(map, ctx->top_eqs.data, ctx->top_eqs.size);
71,980✔
6808
  sharing_map_add_terms(map, ctx->top_atoms.data, ctx->top_atoms.size);
71,980✔
6809
  sharing_map_add_terms(map, ctx->top_formulas.data, ctx->top_formulas.size);
71,980✔
6810
}
71,980✔
6811

6812

6813
#if 0
6814
/*
6815
 * PROVISIONAL: SHOW ASSERTIONS
6816
 */
6817
static void context_show_assertions(const context_t *ctx, uint32_t n, const term_t *a) {
6818
  pp_area_t area;
6819
  yices_pp_t printer;
6820
  uint32_t i;
6821

6822
  area.width = 80;
6823
  area.height = UINT32_MAX;
6824
  area.offset = 0;
6825
  area.stretch = false;
6826
  area.truncate = false;
6827
  init_yices_pp(&printer, stdout, &area, PP_VMODE, 0);
6828

6829
  for (i=0; i<n; i++) {
6830
    pp_term_full(&printer, ctx->terms, a[i]);
6831
    flush_yices_pp(&printer);
6832
  }
6833
  delete_yices_pp(&printer, true);
6834
}
6835
#endif
6836

6837
/*
6838
 * Flatten and internalize assertions a[0 ... n-1]
6839
 * - all elements a[i] must be valid boolean term in ctx->terms
6840
 * - return code:
6841
 *   TRIVIALLY_UNSAT if there's an easy contradiction
6842
 *   CTX_NO_ERROR if the assertions were processed without error
6843
 *   a negative error code otherwise.
6844
 */
6845
static int32_t context_process_assertions(context_t *ctx, uint32_t n, const term_t *a) {
74,796✔
6846
  ivector_t *v;
6847
  uint32_t i;
6848
  int code;
6849

6850
  ivector_reset(&ctx->top_eqs);
74,796✔
6851
  ivector_reset(&ctx->top_atoms);
74,796✔
6852
  ivector_reset(&ctx->top_formulas);
74,796✔
6853
  ivector_reset(&ctx->top_interns);
74,796✔
6854
  ivector_reset(&ctx->subst_eqs);
74,796✔
6855
  ivector_reset(&ctx->aux_eqs);
74,796✔
6856
  ivector_reset(&ctx->aux_atoms);
74,796✔
6857

6858
  code = setjmp(ctx->env);
74,796✔
6859
  if (code == 0) {
75,194✔
6860

6861
    // If using MCSAT, just check and done
6862
    if (ctx->mcsat != NULL) {
74,796✔
6863
      // TBD: quant support
6864
      assert(!context_quant_enabled(ctx));
6865
      code = mcsat_assert_formulas(ctx->mcsat, n, a);
2,444✔
6866
      goto done;
2,433✔
6867
    }
6868

6869
#if 0
6870
    printf("\n=== Context: process assertions ===\n");
6871
    context_show_assertions(ctx, n, a);
6872
    printf("===\n\n");
6873
#endif
6874

6875
    // flatten
6876
    for (i=0; i<n; i++) {
195,783✔
6877
      flatten_assertion(ctx, a[i]);
123,802✔
6878
    }
6879

6880
    trace_printf(ctx->trace, 6, "(done flattening)\n");
71,981✔
6881

6882
    /*
6883
     * At this point, the assertions are stored into the vectors
6884
     * top_eqs, top_atoms, top_formulas, and top_interns
6885
     * - more top-level equalities may be in subst_eqs
6886
     * - ctx->intern stores the internalized terms and the variable
6887
     *   substitutions.
6888
     */
6889

6890
    switch (ctx->arch) {
71,981✔
6891
    // TBD: make sure following preprocessings work with quant enabled
6892
    case CTX_ARCH_EG:
3,329✔
6893
      /*
6894
       * UF problem: we must process subst_eqs last since the
6895
       * preprocessing may add new equalities in aux_eqs that may end
6896
       * up in subst_eqs after the call to process_aux_eqs.
6897
       */
6898
      if (context_breaksym_enabled(ctx)) {
3,329✔
6899
        break_uf_symmetries(ctx);
30✔
6900
      }
6901
      if (context_eq_abstraction_enabled(ctx)) {
3,329✔
6902
        analyze_uf(ctx);
64✔
6903
      }
6904
      if (ctx->aux_eqs.size > 0) {
3,329✔
6905
        process_aux_eqs(ctx);
6✔
6906
      }
6907
      if (ctx->subst_eqs.size > 0) {
3,328✔
6908
        context_process_candidate_subst(ctx);
10✔
6909
      }
6910
      break;
3,328✔
6911

6912
    case CTX_ARCH_AUTO_IDL:
27✔
6913
      /*
6914
       * For difference logic, we must process the subst_eqs first
6915
       * (otherwise analyze_diff_logic may give wrong results).
6916
       */
6917
      if (ctx->subst_eqs.size > 0) {
27✔
6918
        context_process_candidate_subst(ctx);
×
6919
      }
6920
      analyze_diff_logic(ctx, true);
27✔
6921
      create_auto_idl_solver(ctx);
27✔
6922
      break;
27✔
6923

6924
    case CTX_ARCH_AUTO_RDL:
8✔
6925
      /*
6926
       * Difference logic, we must process the subst_eqs first
6927
       */
6928
      trace_printf(ctx->trace, 6, "(auto-idl solver)\n");
8✔
6929
      if (ctx->subst_eqs.size > 0) {
8✔
6930
        context_process_candidate_subst(ctx);
×
6931
      }
6932
      analyze_diff_logic(ctx, false);
8✔
6933
      create_auto_rdl_solver(ctx);
8✔
6934
      break;
8✔
6935

6936
    case CTX_ARCH_SPLX:
30,674✔
6937
      /*
6938
       * Simplex, like EG, may add aux_atoms so we must process
6939
       * subst_eqs last here.
6940
       */
6941
      trace_printf(ctx->trace, 6, "(Simplex solver)\n");
30,674✔
6942
      // more optional processing
6943
      if (context_cond_def_preprocessing_enabled(ctx)) {
30,674✔
6944
        process_conditional_definitions(ctx);
52✔
6945
        if (ctx->aux_eqs.size > 0) {
52✔
6946
          process_aux_eqs(ctx);
2✔
6947
        }
6948
        if (ctx->aux_atoms.size > 0) {
52✔
6949
          process_aux_atoms(ctx);
3✔
6950
        }
6951
      }
6952
      if (ctx->subst_eqs.size > 0) {
30,674✔
6953
        context_process_candidate_subst(ctx);
16✔
6954
      }
6955
      break;
30,674✔
6956

6957
    default:
37,943✔
6958
      /*
6959
       * Process the candidate variable substitutions if any
6960
       */
6961
      if (ctx->subst_eqs.size > 0) {
37,943✔
6962
        context_process_candidate_subst(ctx);
2,749✔
6963
      }
6964
      break;
37,943✔
6965
    }
6966

6967
    /*
6968
     * Sharing
6969
     */
6970
    context_build_sharing_data(ctx);
71,980✔
6971

6972
    /*
6973
     * Notify the core + solver(s)
6974
     */
6975
    if (!context_quant_enabled(ctx)) {
71,980✔
6976
        // TBD: make sure this is correct
6977
      internalization_start(ctx->core);
69,447✔
6978
    }
6979

6980
    /*
6981
     * Assert top_eqs, top_atoms, top_formulas, top_interns
6982
     */
6983
    code = CTX_NO_ERROR;
71,980✔
6984

6985
    // first: all terms that are already internalized
6986
    v = &ctx->top_interns;
71,980✔
6987
    n = v->size;
71,980✔
6988
    if (n > 0) {
71,980✔
6989
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" existing terms)\n", n);
284✔
6990
      i = 0;
284✔
6991
      do {
6992
        assert_toplevel_intern(ctx, v->data[i]);
739✔
6993
        i ++;
739✔
6994
      } while (i < n);
739✔
6995

6996
      // one round of propagation
6997
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
284✔
6998
        code = TRIVIALLY_UNSAT;
11✔
6999
        goto done;
11✔
7000
      }
7001
    }
7002

7003
    // second: all top-level equalities
7004
    v = &ctx->top_eqs;
71,969✔
7005
    n = v->size;
71,969✔
7006
    if (n > 0) {
71,969✔
7007
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level equalities)\n", n);
6,783✔
7008
      i = 0;
6,783✔
7009
      do {
7010
        assert_toplevel_formula(ctx, v->data[i]);
10,845✔
7011
        i ++;
10,841✔
7012
      } while (i < n);
10,841✔
7013

7014
      // one round of propagation
7015
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
6,779✔
7016
        code = TRIVIALLY_UNSAT;
70✔
7017
        goto done;
70✔
7018
      }
7019
    }
7020

7021
    // third: all top-level atoms (other than equalities)
7022
    v = &ctx->top_atoms;
71,895✔
7023
    n = v->size;
71,895✔
7024
    if (n > 0) {
71,895✔
7025
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level atoms)\n", n);
15,581✔
7026
      i = 0;
15,581✔
7027
      do {
7028
        assert_toplevel_formula(ctx, v->data[i]);
68,867✔
7029
        i ++;
68,856✔
7030
      } while (i < n);
68,856✔
7031

7032
      // one round of propagation
7033
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
15,570✔
7034
        code = TRIVIALLY_UNSAT;
78✔
7035
        goto done;
78✔
7036
      }
7037
    }
7038

7039
    // last: all non-atomic, formulas
7040
    v =  &ctx->top_formulas;
71,806✔
7041
    n = v->size;
71,806✔
7042
    if (n > 0) {
71,806✔
7043
      trace_printf(ctx->trace, 6, "(asserting  %"PRIu32" top-level formulas)\n", n);
22,027✔
7044
      i = 0;
22,027✔
7045
      do {
7046
        assert_toplevel_formula(ctx, v->data[i]);
45,753✔
7047
        i ++;
45,753✔
7048
      } while (i < n);
45,753✔
7049

7050
      // one round of propagation
7051
      if (!context_quant_enabled(ctx) && ! base_propagate(ctx->core)) {
22,027✔
7052
        code = TRIVIALLY_UNSAT;
63✔
7053
        goto done;
63✔
7054
      }
7055
    }
7056

7057
  } else {
7058
    /*
7059
     * Exception: return from longjmp(ctx->env, code);
7060
     */
7061
    ivector_reset(&ctx->aux_vector);
398✔
7062
    reset_istack(&ctx->istack);
398✔
7063
    reset_objstack(&ctx->ostack);
398✔
7064
    int_queue_reset(&ctx->queue);
398✔
7065
    context_free_subst(ctx);
398✔
7066
    context_free_marks(ctx);
398✔
7067
  }
7068

7069
 done:
74,796✔
7070
  return code;
74,796✔
7071
}
7072

7073
/*
7074
 * Assert all formulas f[0] ... f[n-1]
7075
 * The context status must be IDLE.
7076
 *
7077
 * Return code:
7078
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
7079
 *   (in that case the context status is set to UNSAT)
7080
 * - CTX_NO_ERROR means no internalization error and status not
7081
 *   determined
7082
 * - otherwise, the code is negative to report an error.
7083
 */
7084
int32_t _o_assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
72,262✔
7085
  int32_t code;
7086

7087
  assert(ctx->arch == CTX_ARCH_AUTO_IDL ||
7088
         ctx->arch == CTX_ARCH_AUTO_RDL ||
7089
         smt_status(ctx->core) == YICES_STATUS_IDLE);
7090
  assert(!context_quant_enabled(ctx));
7091

7092
  code = context_process_assertions(ctx, n, f);
72,262✔
7093
  if (code == TRIVIALLY_UNSAT) {
72,262✔
7094
    if (ctx->arch == CTX_ARCH_AUTO_IDL || ctx->arch == CTX_ARCH_AUTO_RDL) {
601✔
7095
      // cleanup: reset arch/config to 'no theory'
7096
      assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL &&
7097
             ctx->mode == CTX_MODE_ONECHECK);
7098
      ctx->arch = CTX_ARCH_NOSOLVERS;
1✔
7099
      ctx->theories = 0;
1✔
7100
      ctx->options = 0;
1✔
7101
    }
7102

7103
    if( smt_status(ctx->core) != YICES_STATUS_UNSAT) {
601✔
7104
      // force UNSAT in the core
7105
      add_empty_clause(ctx->core);
379✔
7106
      ctx->core->status = YICES_STATUS_UNSAT;
379✔
7107
    }
7108
  }
7109

7110
  return code;
72,262✔
7111
}
7112

7113
/*
7114
 * Assert all formulas f[0] ... f[n-1] during quantifier instantiation
7115
 * The context status must be SEARCHING.
7116
 *
7117
 * Return code:
7118
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
7119
 *   (in that case the context status is set to UNSAT)
7120
 * - CTX_NO_ERROR means no internalization error and status not
7121
 *   determined
7122
 * - otherwise, the code is negative to report an error.
7123
 */
7124
int32_t quant_assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
2,534✔
7125
  int32_t code;
7126

7127
  assert(context_quant_enabled(ctx));
7128
  assert(smt_status(ctx->core) == YICES_STATUS_SEARCHING);
7129

7130
  code = context_process_assertions(ctx, n, f);
2,534✔
7131
  if (code == TRIVIALLY_UNSAT) {
2,534✔
7132
    if (ctx->arch == CTX_ARCH_AUTO_IDL || ctx->arch == CTX_ARCH_AUTO_RDL) {
1✔
7133
      // cleanup: reset arch/config to 'no theory'
7134
      assert(ctx->arith_solver == NULL && ctx->bv_solver == NULL && ctx->fun_solver == NULL &&
7135
      ctx->mode == CTX_MODE_ONECHECK);
7136
      ctx->arch = CTX_ARCH_NOSOLVERS;
×
7137
      ctx->theories = 0;
×
7138
      ctx->options = 0;
×
7139
    }
7140

7141
    if( smt_status(ctx->core) != YICES_STATUS_UNSAT) {
1✔
7142
      // force UNSAT in the core
7143
      add_empty_clause(ctx->core);
1✔
7144
      ctx->core->status = YICES_STATUS_UNSAT;
1✔
7145
    }
7146
  }
7147

7148
  return code;
2,534✔
7149
}
7150

7151
int32_t assert_formulas(context_t *ctx, uint32_t n, const term_t *f) {
18,470✔
7152
  MT_PROTECT(int32_t, __yices_globals.lock, _o_assert_formulas(ctx, n, f));
18,470✔
7153
}
7154

7155

7156

7157

7158
/*
7159
 * Assert a boolean formula f.
7160
 *
7161
 * The context status must be IDLE.
7162
 *
7163
 * Return code:
7164
 * - TRIVIALLY_UNSAT means that an inconsistency is detected
7165
 *   (in that case the context status is set to UNSAT)
7166
 * - CTX_NO_ERROR means no internalization error and status not
7167
 *   determined
7168
 * - otherwise, the code is negative. The assertion could
7169
 *   not be processed.
7170
 */
7171
int32_t _o_assert_formula(context_t *ctx, term_t f) {
53,792✔
7172
  return _o_assert_formulas(ctx, 1, &f);
53,792✔
7173
}
7174

7175
int32_t assert_formula(context_t *ctx, term_t f) {
49,307✔
7176
  MT_PROTECT(int32_t, __yices_globals.lock, _o_assert_formula(ctx, f));
49,307✔
7177
}
7178

7179

7180
/*
7181
 * Convert boolean term t to a literal l in context ctx
7182
 * - t must be a boolean term
7183
 * - return a negative code if there's an error
7184
 * - return a literal (l >= 0) otherwise.
7185
 */
7186
int32_t context_internalize(context_t *ctx, term_t t) {
87,725✔
7187
  int code;
7188
  literal_t l;
7189

7190
  ivector_reset(&ctx->top_eqs);
87,725✔
7191
  ivector_reset(&ctx->top_atoms);
87,725✔
7192
  ivector_reset(&ctx->top_formulas);
87,725✔
7193
  ivector_reset(&ctx->top_interns);
87,725✔
7194
  ivector_reset(&ctx->subst_eqs);
87,725✔
7195
  ivector_reset(&ctx->aux_eqs);
87,725✔
7196

7197
  code = setjmp(ctx->env);
87,725✔
7198
  if (code == 0) {
87,725✔
7199
    // we must call internalization start first
7200
    if (!context_quant_enabled(ctx)) {
87,725✔
7201
      // TBD: make sure this is correct
7202
      internalization_start(ctx->core);
87,621✔
7203
    }
7204
    l = internalize_to_literal(ctx, t);
87,725✔
7205
  } else {
7206
    assert(code < 0);
7207
    /*
7208
     * Clean up
7209
     */
7210
    ivector_reset(&ctx->aux_vector);
×
7211
    reset_istack(&ctx->istack);
×
7212
    int_queue_reset(&ctx->queue);
×
7213
    context_free_subst(ctx);
×
7214
    context_free_marks(ctx);
×
7215
    l = code;
×
7216
  }
7217

7218
  return l;
87,725✔
7219
}
7220

7221

7222
/*
7223
 * Build an assumption for Boolean term t:
7224
 * - this converts t to a literal l in context ctx
7225
 *   then create an indicator variable x in the core
7226
 *   and add the clause (x => l) in the core.
7227
 * - return a negative code if t can't be internalized
7228
 * - return the literal x otherwise (where x>=0).
7229
 */
7230
int32_t context_add_assumption(context_t *ctx, term_t t) {
87,630✔
7231
  int32_t l, x;
7232

7233
  // check if we already have an assumption literal for t
7234
  x = assumption_literal_for_term(&ctx->assumptions, t);
87,630✔
7235
  if (x < 0) {
87,630✔
7236
    l = context_internalize(ctx, t);
87,621✔
7237
    if (l < 0) return l; // error code
87,621✔
7238

7239
    x = pos_lit(create_boolean_variable(ctx->core));
87,621✔
7240
    add_binary_clause(ctx->core, not(x), l); // clause (x implies l)
87,621✔
7241

7242
    assumption_stack_add(&ctx->assumptions, t, x);
87,621✔
7243
  }
7244

7245
  return x;
87,630✔
7246
}
7247

7248

7249

7250
/*
7251
 * PROVISIONAL: FOR TESTING/DEBUGGING
7252
 */
7253

7254
/*
7255
 * Preprocess formula f or array of formulas f[0 ... n-1]
7256
 * - this does flattening + build substitutions
7257
 * - return code: as in assert_formulas
7258
 * - the result is stored in the internal vectors
7259
 *     ctx->top_interns
7260
 *     ctx->top_eqs
7261
 *     ctx->top_atoms
7262
 *     ctx->top_formulas
7263
 *   + ctx->intern stores substitutions
7264
 */
7265
int32_t context_process_formulas(context_t *ctx, uint32_t n, term_t *f) {
×
7266
  uint32_t i;
7267
  int code;
7268

7269
  ivector_reset(&ctx->top_eqs);
×
7270
  ivector_reset(&ctx->top_atoms);
×
7271
  ivector_reset(&ctx->top_formulas);
×
7272
  ivector_reset(&ctx->top_interns);
×
7273
  ivector_reset(&ctx->subst_eqs);
×
7274
  ivector_reset(&ctx->aux_eqs);
×
7275
  ivector_reset(&ctx->aux_atoms);
×
7276

7277
  code = setjmp(ctx->env);
×
7278
  if (code == 0) {
×
7279
    // flatten
7280
    for (i=0; i<n; i++) {
×
7281
      flatten_assertion(ctx, f[i]);
×
7282
    }
7283

7284
    /*
7285
     * At this point, the assertions are stored into the vectors
7286
     * top_eqs, top_atoms, top_formulas, and top_interns
7287
     * - more top-level equalities may be in subst_eqs
7288
     * - ctx->intern stores the internalized terms and the variable
7289
     *   substitutions.
7290
     */
7291

7292
    switch (ctx->arch) {
×
7293
    case CTX_ARCH_EG:
×
7294
      /*
7295
       * UF problem: we must process subst_eqs last since the
7296
       * preprocessing may add new equalities in aux_eqs that may end
7297
       * up in subst_eqs after the call to process_aux_eqs.
7298
       */
7299
      if (context_breaksym_enabled(ctx)) {
×
7300
        break_uf_symmetries(ctx);
×
7301
      }
7302
      if (context_eq_abstraction_enabled(ctx)) {
×
7303
        analyze_uf(ctx);
×
7304
      }
7305
      if (ctx->aux_eqs.size > 0) {
×
7306
        process_aux_eqs(ctx);
×
7307
      }
7308
      if (ctx->subst_eqs.size > 0) {
×
7309
        context_process_candidate_subst(ctx);
×
7310
      }
7311
      break;
×
7312

7313
    case CTX_ARCH_AUTO_IDL:
×
7314
      /*
7315
       * For difference logic, we must process the subst_eqs first
7316
       * (otherwise analyze_diff_logic may give wrong results).
7317
       */
7318
      if (ctx->subst_eqs.size > 0) {
×
7319
        context_process_candidate_subst(ctx);
×
7320
      }
7321
      analyze_diff_logic(ctx, true);
×
7322
      create_auto_idl_solver(ctx);
×
7323
      break;
×
7324

7325
    case CTX_ARCH_AUTO_RDL:
×
7326
      /*
7327
       * Difference logic, we must process the subst_eqs first
7328
       */
7329
      if (ctx->subst_eqs.size > 0) {
×
7330
        context_process_candidate_subst(ctx);
×
7331
      }
7332
      analyze_diff_logic(ctx, false);
×
7333
      create_auto_rdl_solver(ctx);
×
7334
      break;
×
7335

7336
    case CTX_ARCH_SPLX:
×
7337
      /*
7338
       * Simplex, like EG, may add aux_atoms so we must process
7339
       * subst_eqs last here.
7340
       */
7341
      // more optional processing
7342
      if (context_cond_def_preprocessing_enabled(ctx)) {
×
7343
        process_conditional_definitions(ctx);
×
7344
        if (ctx->aux_eqs.size > 0) {
×
7345
          process_aux_eqs(ctx);
×
7346
        }
7347
        if (ctx->aux_atoms.size > 0) {
×
7348
          process_aux_atoms(ctx);
×
7349
        }
7350
      }
7351
      if (ctx->subst_eqs.size > 0) {
×
7352
        context_process_candidate_subst(ctx);
×
7353
      }
7354
      break;
×
7355

7356
    default:
×
7357
      /*
7358
       * Process the candidate variable substitutions if any
7359
       */
7360
      if (ctx->subst_eqs.size > 0) {
×
7361
        context_process_candidate_subst(ctx);
×
7362
      }
7363
      break;
×
7364
    }
7365

7366
    /*
7367
     * Sharing
7368
     */
7369
    context_build_sharing_data(ctx);
×
7370

7371
    code = CTX_NO_ERROR;
×
7372

7373
  } else {
7374
    /*
7375
     * Exception: return from longjmp(ctx->env, code);
7376
     */
7377
    ivector_reset(&ctx->aux_vector);
×
7378
    reset_istack(&ctx->istack);
×
7379
    int_queue_reset(&ctx->queue);
×
7380
    context_free_subst(ctx);
×
7381
    context_free_marks(ctx);
×
7382
  }
7383

7384
  return code;
×
7385
}
7386

7387
int32_t context_process_formula(context_t *ctx, term_t f) {
×
7388
  return context_process_formulas(ctx, 1, &f);
×
7389
}
7390

7391

7392

7393
/*
7394
 * The search function 'check_context' is defined in context_solver.c
7395
 */
7396

7397

7398
/*
7399
 * Interrupt the search.
7400
 */
7401
void context_stop_search(context_t *ctx) {
3✔
7402
  if (ctx->mcsat == NULL) {
3✔
7403
    stop_search(ctx->core);
3✔
7404
    if (context_has_simplex_solver(ctx)) {
3✔
7405
      simplex_stop_search(ctx->arith_solver);
3✔
7406
    }
7407
  } else {
7408
    mcsat_stop_search(ctx->mcsat);
×
7409
  }
7410
}
3✔
7411

7412

7413

7414
/*
7415
 * Cleanup: restore ctx to a good state after check_context
7416
 * is interrupted.
7417
 */
7418
void context_cleanup(context_t *ctx) {
1✔
7419
  // restore the state to IDLE, propagate to all solvers (via pop)
7420
  assert(context_supports_cleaninterrupt(ctx));
7421
  context_invalidate_unsat_core_cache(ctx);
1✔
7422
  if (ctx->mcsat == NULL) {
1✔
7423
    smt_cleanup(ctx->core);
1✔
7424
  } else {
7425
    mcsat_clear(ctx->mcsat);
×
7426
  }
7427
}
1✔
7428

7429

7430

7431
/*
7432
 * Clear: prepare for more assertions and checks
7433
 * - free the boolean assignment
7434
 * - reset the status to IDLE
7435
 */
7436
void context_clear(context_t *ctx) {
42,259✔
7437
  assert(context_supports_multichecks(ctx));
7438
  context_invalidate_unsat_core_cache(ctx);
42,259✔
7439
  if (ctx->mcsat == NULL) {
42,259✔
7440
    smt_clear(ctx->core);
41,898✔
7441
  } else {
7442
    mcsat_clear(ctx->mcsat);
361✔
7443
  }
7444
}
42,259✔
7445

7446

7447

7448
/*
7449
 * Clear_unsat: prepare for pop if the status is UNSAT
7450
 * - remove assumptions if any
7451
 *
7452
 * - if clean interrupt is enabled, then there may be a mismatch between
7453
 *   the context's base_level and the core base_level.
7454
 * - it's possible to have ctx->core.base_level = ctx->base_level + 1
7455
 * - this happens because start_search in smt_core does an internal smt_push
7456
 *   to allow the core to be restored to a clean state if search is interrupted.
7457
 * - if search is not interrupted and the search returns UNSAT, then we're
7458
 *   in a state with core base level = context base level + 1.
7459
 */
7460
void context_clear_unsat(context_t *ctx) {
658✔
7461
  context_invalidate_unsat_core_cache(ctx);
658✔
7462
  if (ctx->mcsat == NULL) {
658✔
7463
    smt_clear_unsat(ctx->core);
422✔
7464
    assert(smt_base_level(ctx->core) == ctx->base_level);
7465
  } else {
7466
    mcsat_clear(ctx->mcsat);
236✔
7467
  }
7468
}
658✔
7469

7470

7471

7472
/*
7473
 * Add the blocking clause to ctx
7474
 * - ctx->status must be either SAT or UNKNOWN
7475
 * - this collects all decision literals in the current truth assignment
7476
 *   (say l_1, ..., l_k) then clears the current assignment and adds the
7477
 *  clause ((not l_1) \/ ... \/ (not l_k)).
7478
 *
7479
 * Return code:
7480
 * - TRIVIALLY_UNSAT: means that the blocking clause is empty (i.e., k = 0)
7481
 *   (in that case, the context status is set to UNSAT)
7482
 * - CTX_NO_ERROR: means that the blocking clause is not empty (i.e., k > 0)
7483
 *   (In this case, the context status is set to IDLE)
7484
 */
7485
int32_t assert_blocking_clause(context_t *ctx) {
24,855✔
7486
  ivector_t *v;
7487
  uint32_t i, n;
7488
  int32_t code;
7489

7490
  assert(smt_status(ctx->core) == YICES_STATUS_SAT ||
7491
         smt_status(ctx->core) == YICES_STATUS_UNKNOWN);
7492

7493
  // get decision literals and build the blocking clause
7494
  v = &ctx->aux_vector;
24,855✔
7495
  assert(v->size == 0);
7496
  collect_decision_literals(ctx->core, v);
24,855✔
7497
  n = v->size;
24,855✔
7498
  for (i=0; i<n; i++) {
36,264✔
7499
    v->data[i] = not(v->data[i]);
11,409✔
7500
  }
7501

7502
  // prepare for the new assertion + notify solvers of a new assertion
7503
  context_clear(ctx);
24,855✔
7504
  internalization_start(ctx->core);
24,855✔
7505

7506
  // add the blocking clause
7507
  add_clause(ctx->core, n, v->data);
24,855✔
7508
  ivector_reset(v);
24,855✔
7509

7510
  // force UNSAT if n = 0
7511
  code = CTX_NO_ERROR;
24,855✔
7512
  if (n == 0) {
24,855✔
7513
    code = TRIVIALLY_UNSAT;
16,817✔
7514
    ctx->core->status = YICES_STATUS_UNSAT;
16,817✔
7515
  }
7516

7517
  assert(n == 0 || smt_status(ctx->core) == YICES_STATUS_IDLE);
7518

7519
  return code;
24,855✔
7520
}
7521

7522

7523

7524

7525
/********************************
7526
 *  GARBAGE COLLECTION SUPPORT  *
7527
 *******************************/
7528

7529
/*
7530
 * Marker for all terms present in the eq_map
7531
 * - aux = the relevant term table.
7532
 * - each record p stores <k0, k1, val> where k0 and k1 are both
7533
 *   terms in aux and val is a literal in the core
7534
 */
7535
static void ctx_mark_eq(void *aux, const pmap2_rec_t *p) {
×
7536
  term_table_set_gc_mark(aux, index_of(p->k0));
×
7537
  term_table_set_gc_mark(aux, index_of(p->k1));
×
7538
}
×
7539

7540

7541
/*
7542
 * Go through all data structures in ctx and mark all terms and types
7543
 * that they use.
7544
 */
7545
void context_gc_mark(context_t *ctx) {
12✔
7546
  if (ctx->egraph != NULL) {
12✔
7547
    egraph_gc_mark(ctx->egraph);
1✔
7548
  }
7549
  if (ctx->fun_solver != NULL) {
12✔
7550
    fun_solver_gc_mark(ctx->fun_solver);
1✔
7551
  }
7552

7553
  intern_tbl_gc_mark(&ctx->intern);
12✔
7554

7555
  // empty all the term vectors to be safe
7556
  ivector_reset(&ctx->top_eqs);
12✔
7557
  ivector_reset(&ctx->top_atoms);
12✔
7558
  ivector_reset(&ctx->top_formulas);
12✔
7559
  ivector_reset(&ctx->top_interns);
12✔
7560
  ivector_reset(&ctx->subst_eqs);
12✔
7561
  ivector_reset(&ctx->aux_eqs);
12✔
7562

7563
  if (ctx->eq_cache != NULL) {
12✔
7564
    pmap2_iterate(ctx->eq_cache, ctx->terms, ctx_mark_eq);
×
7565
  }
7566

7567
  if (ctx->unsat_core_cache != NULL) {
12✔
7568
    uint32_t i, n;
7569
    n = ctx->unsat_core_cache->size;
×
7570
    for (i=0; i<n; i++) {
×
7571
      term_table_set_gc_mark(ctx->terms, index_of(ctx->unsat_core_cache->data[i]));
×
7572
    }
7573
  }
7574

7575
  if (ctx->mcsat != NULL) {
12✔
7576
    mcsat_gc_mark(ctx->mcsat);
11✔
7577
  }
7578
  if (ctx->mcsat_supplement) {
12✔
NEW
7579
    mcsat_satellite_t *sat = context_mcsat_satellite(ctx);
×
NEW
7580
    if (sat != NULL) {
×
NEW
7581
      mcsat_satellite_gc_mark(sat);
×
7582
    }
7583
  }
7584
}
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