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

SRI-CSL / yices2 / 25574532210

08 May 2026 07:12PM UTC coverage: 67.254% (+0.03%) from 67.22%
25574532210

push

github

web-flow
Merge pull request #607 from SRI-CSL/context_delegates

QF_BV context delegates (#453): config/param selection, incremental state, assumptions, and delegate regressions

84 of 307 new or added lines in 7 files covered. (27.36%)

4 existing lines in 3 files now uncovered.

85205 of 126691 relevant lines covered (67.25%)

1626652.44 hits per line

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

58.47
/src/context/context_solver.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
 * SEARCH AND SOLVING PROCEDURES
21
 *
22
 * This module implements the check_context function (and variants).
23
 * It also implements model construction.
24
 */
25

26
#include <stdbool.h>
27
#include <assert.h>
28
#include <stdint.h>
29
#include <inttypes.h>
30
#include <stdio.h>
31

32
#include "context/context.h"
33
#include "context/internalization_codes.h"
34
#include "model/models.h"
35
#include "mcsat/solver.h"
36
#include "solvers/bv/dimacs_printer.h"
37
#include "solvers/cdcl/delegate.h"
38
#include "solvers/funs/fun_solver.h"
39
#include "solvers/simplex/simplex.h"
40
#include "terms/term_explorer.h"
41
#include "terms/term_manager.h"
42
#include "terms/term_substitution.h"
43
#include "utils/int_hash_map.h"
44
#include "utils/int_hash_sets.h"
45

46
#include "api/yices_globals.h"
47
#include "api/yices_api_lock_free.h"
48
#include "mt/thread_macros.h"
49

50

51

52
/*
53
 * TRACE FUNCTIONS
54
 */
55

56
/*
57
 * Basic statistics
58
 */
59
static void trace_stats(smt_core_t *core, const char *when, uint32_t level) {
93,222✔
60
  trace_printf(core->trace, level,
93,222✔
61
               "(%-10s %8"PRIu64" %10"PRIu64" %8"PRIu64" %8"PRIu32" %8"PRIu32" %8"PRIu64" %8"PRIu32" %8"PRIu64" %7.1f)\n",
62
               when, core->stats.conflicts, core->stats.decisions, core->stats.random_decisions,
63
               num_binary_clauses(core), num_prob_clauses(core), num_prob_literals(core),
64
               num_learned_clauses(core), num_learned_literals(core), avg_learned_clause_size(core));
65
#if 0
66
  fprintf(stderr,
67
          "(%-10s %8"PRIu64" %10"PRIu64" %8"PRIu64" %8"PRIu32" %8"PRIu32" %8"PRIu64" %8"PRIu32" %8"PRIu64" %7.1f)\n",
68
          when, core->stats.conflicts, core->stats.decisions, core->stats.random_decisions,
69
          num_binary_clauses(core), num_prob_clauses(core), num_prob_literals(core),
70
          num_learned_clauses(core), num_learned_literals(core), avg_learned_clause_size(core));
71
#endif
72
}
93,222✔
73

74
/*
75
 * On start_search
76
 */
77
static void trace_start(smt_core_t *core) {
45,367✔
78
  trace_stats(core, "start:", 1);
45,367✔
79
}
45,367✔
80

81

82
/*
83
 * On restart
84
 */
85
static void trace_restart(smt_core_t *core) {
2,217✔
86
  trace_stats(core, "restart:", 1);
2,217✔
87
}
2,217✔
88

89
static void trace_inner_restart(smt_core_t *core) {
93✔
90
  trace_stats(core, "inner restart:", 5);
93✔
91
}
93✔
92

93

94
/*
95
 * On reduce clause database
96
 */
97
static void trace_reduce(smt_core_t *core, uint64_t deleted) {
178✔
98
  trace_stats(core, "reduce:", 3);
178✔
99
  trace_printf(core->trace, 4, "(%"PRIu64" clauses deleted)\n", deleted);
178✔
100
}
178✔
101

102

103

104
/*
105
 * End of search
106
 */
107
static void trace_done(smt_core_t *core) {
45,367✔
108
  trace_stats(core, "done:", 1);
45,367✔
109
  trace_newline(core->trace, 1);
45,367✔
110
}
45,367✔
111

112

113

114
/*
115
 * PROCESS AN ASSUMPTION
116
 */
117

118
/*
119
 * l = assumption for the current decision level
120
 * If l is unassigned, we assign it and perform one round of propagation
121
 * If l is false, we record the conflict. The context is unsat under the
122
 * current set of assumptions.
123
 */
124
static void process_assumption(smt_core_t *core, literal_t l) {
86,467✔
125
  switch (literal_value(core, l)) {
86,467✔
126
  case VAL_UNDEF_FALSE:
83,926✔
127
  case VAL_UNDEF_TRUE:
128
    decide_literal(core, l);
83,926✔
129
    smt_process(core);
83,926✔
130
    break;
83,926✔
131

132
  case VAL_TRUE:
×
133
    break;
×
134

135
  case VAL_FALSE:
2,541✔
136
    save_conflicting_assumption(core, l);
2,541✔
137
    break;
2,541✔
138
  }
139
}
86,467✔
140

141

142
/*
143
 * MAIN SEARCH FUNCTIONS
144
 */
145

146
/*
147
 * Bounded search with the default branching heuristic (picosat-like)
148
 * - search until the conflict bound is reached or until the problem is solved.
149
 * - reduce_threshold: number of learned clauses above which reduce_clause_database is called
150
 * - r_factor = increment factor for reduce_threshold
151
 * - use the default branching heuristic implemented by the core
152
 */
153
static void search(smt_core_t *core, uint32_t conflict_bound, uint32_t *reduce_threshold, double r_factor) {
13,437✔
154
  uint64_t max_conflicts;
155
  uint64_t deletions;
156
  uint32_t r_threshold;
157
  literal_t l;
158

159
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
160

161
  max_conflicts = num_conflicts(core) + conflict_bound;
13,437✔
162
  r_threshold = *reduce_threshold;
13,437✔
163

164
  smt_process(core);
13,437✔
165
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
6,297,754✔
166
    // reduce heuristic
167
    if (num_learned_clauses(core) >= r_threshold) {
6,284,317✔
168
      deletions = core->stats.learned_clauses_deleted;
67✔
169
      reduce_clause_database(core);
67✔
170
      r_threshold = (uint32_t) (r_threshold * r_factor);
67✔
171
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
67✔
172
    }
173

174
    // assumption
175
    if (core->has_assumptions) {
6,284,317✔
176
      l = get_next_assumption(core);
10✔
177
      if (l != null_literal) {
10✔
178
        process_assumption(core, l);
3✔
179
        continue;
3✔
180
      }
181
    }
182

183
    // decision
184
    l = select_unassigned_literal(core);
6,284,314✔
185
    if (l == null_literal) {
6,284,314✔
186
      // all variables assigned: Call final_check
187
      smt_final_check(core);
16,600✔
188
    } else {
189
      decide_literal(core, l);
6,267,714✔
190
      smt_process(core);
6,267,714✔
191
    }
192
  }
193

194
  *reduce_threshold = r_threshold;
13,437✔
195
}
13,437✔
196

197

198
/*
199
 * HACK: Variant for Luby restart:
200
 * - search until the conflict bound is reached or until the problem is solved.
201
 * - reduce_threshold: number of learned clauses above which reduce_clause_database is called
202
 * - r_factor = increment factor for reduce_threshold
203
 * - use the default branching heuristic implemented by the core
204
 *
205
 * This uses smt_bounded_process to force more frequent restarts.
206
 */
207
static void luby_search(smt_core_t *core, uint32_t conflict_bound, uint32_t *reduce_threshold, double r_factor) {
13,389✔
208
  uint64_t max_conflicts;
209
  uint64_t deletions;
210
  uint32_t r_threshold;
211
  literal_t l;
212

213
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
214

215
  max_conflicts = num_conflicts(core) + conflict_bound;
13,389✔
216
  r_threshold = *reduce_threshold;
13,389✔
217

218
  smt_bounded_process(core, max_conflicts);
13,389✔
219
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) < max_conflicts) {
678,690✔
220
    // reduce heuristic
221
    if (num_learned_clauses(core) >= r_threshold) {
665,301✔
222
      deletions = core->stats.learned_clauses_deleted;
50✔
223
      reduce_clause_database(core);
50✔
224
      r_threshold = (uint32_t) (r_threshold * r_factor);
50✔
225
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
50✔
226
    }
227

228
    // assumption
229
    if (core->has_assumptions) {
665,301✔
230
      l = get_next_assumption(core);
97,255✔
231
      if (l != null_literal) {
97,255✔
232
        process_assumption(core, l);
86,462✔
233
        continue;
86,462✔
234
      }
235
    }
236

237
    // decision
238
    l = select_unassigned_literal(core);
578,839✔
239
    if (l == null_literal) {
578,839✔
240
      // all variables assigned: Call final_check
241
      smt_final_check(core);
8,780✔
242
    } else {
243
      decide_literal(core, l);
570,059✔
244
      smt_bounded_process(core, max_conflicts);
570,059✔
245
    }
246
  }
247

248
  *reduce_threshold = r_threshold;
13,389✔
249
}
13,389✔
250

251
/*
252
 * Polarity selection (implements branching heuristics)
253
 * - filter is given a literal l + core and must return either l or not l
254
 */
255
typedef literal_t (*branching_fun_t)(smt_core_t *core, literal_t l);
256

257

258
/*
259
 * Bounded search with a non-default branching heuristics
260
 * - search until the conflict bound is reached or until the problem is solved.
261
 * - reduce_threshold: number of learned clauses above which reduce_clause_database is called
262
 * - r_factor = increment factor for reduce_threshold
263
 * - use the branching heuristic implemented by branch
264
 */
265
static void special_search(smt_core_t *core, uint32_t conflict_bound, uint32_t *reduce_threshold,
20,851✔
266
                           double r_factor, branching_fun_t branch) {
267
  uint64_t max_conflicts;
268
  uint64_t deletions;
269
  uint32_t r_threshold;
270
  literal_t l;
271

272
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
273

274
  max_conflicts = num_conflicts(core) + conflict_bound;
20,851✔
275
  r_threshold = *reduce_threshold;
20,851✔
276

277
  smt_process(core);
20,851✔
278
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
633,555✔
279
    // reduce heuristic
280
    if (num_learned_clauses(core) >= r_threshold) {
612,704✔
281
      deletions = core->stats.learned_clauses_deleted;
61✔
282
      reduce_clause_database(core);
61✔
283
      r_threshold = (uint32_t) (r_threshold * r_factor);
61✔
284
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
61✔
285
    }
286

287
    // assumption
288
    if (core->has_assumptions) {
612,704✔
289
      l = get_next_assumption(core);
2✔
290
      if (l != null_literal) {
2✔
291
        process_assumption(core, l);
2✔
292
        continue;
2✔
293
      }
294
    }
295

296
    // decision
297
    l = select_unassigned_literal(core);
612,702✔
298
    if (l == null_literal) {
612,702✔
299
      // all variables assigned: call final check
300
      smt_final_check(core);
22,623✔
301
    } else {
302
      // apply the branching heuristic
303
      l = branch(core, l);
590,079✔
304
      // propagation
305
      decide_literal(core, l);
590,079✔
306
      smt_process(core);
590,079✔
307
    }
308
  }
309

310
  *reduce_threshold = r_threshold;
20,851✔
311
}
20,851✔
312

313

314

315

316

317
/*
318
 * SUPPORTED BRANCHING
319
 */
320

321
/*
322
 * Simple branching heuristics:
323
 * - branch to the negative polarity
324
 * - branch to the positive polarity
325
 */
326
static literal_t negative_branch(smt_core_t *core, literal_t l) {
176,506✔
327
  return l | 1; // force the sign bit to 1
176,506✔
328
}
329

330
static literal_t positive_branch(smt_core_t *core, literal_t l) {
21,277✔
331
  return l & ~1; // force the sign bit to 0
21,277✔
332
}
333

334

335
/*
336
 * For literals with no atom, use the default, otherwise let the theory solver decide
337
 */
338
static literal_t theory_branch(smt_core_t *core, literal_t l) {
392,296✔
339
  if (bvar_has_atom(core, var_of(l))) {
392,296✔
340
    l =  core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
318,925✔
341
  }
342
  return l;
392,296✔
343
}
344

345
// variants
346
static literal_t theory_or_neg_branch(smt_core_t *core, literal_t l) {
×
347
  if (bvar_has_atom(core, var_of(l))) {
×
348
    return core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
×
349
  } else {
350
    return l | 1;
×
351
  }
352
}
353

354
static literal_t theory_or_pos_branch(smt_core_t *core, literal_t l) {
×
355
  if (bvar_has_atom(core, var_of(l))) {
×
356
    return core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
×
357
  } else {
358
    return l & ~1;
×
359
  }
360
}
361

362

363

364

365

366
/*
367
 * CORE SOLVER
368
 */
369

370
/*
371
 * Full solver:
372
 * - params: heuristic parameters.
373
 * - n = number of assumptions
374
 * - a = array of n assumptions: a[0 ... n-1] must all be literals
375
 */
376
static void solve(smt_core_t *core, const param_t *params, uint32_t n, const literal_t *a) {
45,367✔
377
  bool luby;
378
  uint32_t c_threshold, d_threshold; // Picosat-style
379
  uint32_t u, v, period;             // for Luby-style
380
  uint32_t reduce_threshold;
381

382
  c_threshold = params->c_threshold;
45,367✔
383
  d_threshold = c_threshold; // required by trace_start in slow_restart mode
45,367✔
384
  luby = false;
45,367✔
385
  u = 1;
45,367✔
386
  v = 1;
45,367✔
387
  period = c_threshold;
45,367✔
388

389
  if (params->fast_restart) {
45,367✔
390
    d_threshold = params->d_threshold;
11,676✔
391
    // HACK to activate the Luby heuristic:
392
    // c_factor must be 0.0 and fast_restart must be true
393
    luby = params->c_factor == 0.0;
11,676✔
394
  }
395

396
  reduce_threshold = (uint32_t) (num_prob_clauses(core) * params->r_fraction);
45,367✔
397
  if (reduce_threshold < params->r_threshold) {
45,367✔
398
    reduce_threshold = params->r_threshold;
45,336✔
399
  }
400

401
  // initialize then do a propagation + simplification step.
402
  start_search(core, n, a);
45,367✔
403
  trace_start(core);
45,367✔
404
  if (smt_status(core) == YICES_STATUS_SEARCHING) {
45,367✔
405
    // loop
406
    for (;;) {
407
      switch (params->branching) {
47,677✔
408
      case BRANCHING_DEFAULT:
26,826✔
409
        if (luby) {
26,826✔
410
          luby_search(core, c_threshold, &reduce_threshold, params->r_factor);
13,389✔
411
        } else {
412
          search(core, c_threshold, &reduce_threshold, params->r_factor);
13,437✔
413
        }
414
        break;
26,826✔
415
      case BRANCHING_NEGATIVE:
180✔
416
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, negative_branch);
180✔
417
        break;
180✔
418
      case BRANCHING_POSITIVE:
182✔
419
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, positive_branch);
182✔
420
        break;
182✔
421
      case BRANCHING_THEORY:
20,489✔
422
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, theory_branch);
20,489✔
423
        break;
20,489✔
424
      case BRANCHING_TH_NEG:
×
425
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, theory_or_neg_branch);
×
426
        break;
×
427
      case BRANCHING_TH_POS:
×
428
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, theory_or_pos_branch);
×
429
        break;
×
430
      }
431

432
      if (smt_status(core) != YICES_STATUS_SEARCHING) break;
47,677✔
433

434
      smt_restart(core);
2,310✔
435
      //      smt_partial_restart_var(core);
436

437
      if (luby) {
2,310✔
438
        // Luby-style restart
439
        if ((u & -u) == v) {
1,929✔
440
          u ++;
1,041✔
441
          v = 1;
1,041✔
442
        } else {
443
          v <<= 1;
888✔
444
        }
445
        c_threshold = v * period;
1,929✔
446
        trace_restart(core);
1,929✔
447

448
      } else {
449
        // Either Minisat or Picosat-like restart
450

451
        // inner restart: increase c_threshold
452
        c_threshold = (uint32_t) (c_threshold * params->c_factor);
381✔
453

454
        if (c_threshold >= d_threshold) {
381✔
455
          d_threshold = c_threshold; // Minisat-style
288✔
456
          if (params->fast_restart) {
288✔
457
            // Picosat style
458
            // outer restart: reset c_threshold and increase d_threshold
459
            c_threshold = params->c_threshold;
48✔
460
            d_threshold = (uint32_t) (d_threshold * params->d_factor);
48✔
461
          }
462
          trace_restart(core);
288✔
463
        } else {
464
          trace_inner_restart(core);
93✔
465
        }
466
      }
467
    }
468
  }
469

470
  trace_done(core);
45,367✔
471
}
45,367✔
472

473

474
/*
475
 * Initialize the search parameters based on params.
476
 */
477
static void context_set_search_parameters(context_t *ctx, const param_t *params) {
45,367✔
478
  smt_core_t *core;
479
  egraph_t *egraph;
480
  simplex_solver_t *simplex;
481
  fun_solver_t *fsolver;
482
  uint32_t quota;
483

484
  /*
485
   * Set core parameters
486
   */
487
  core = ctx->core;
45,367✔
488
  set_randomness(core, params->randomness);
45,367✔
489
  set_random_seed(core, params->random_seed);
45,367✔
490
  set_var_decay_factor(core, params->var_decay);
45,367✔
491
  set_clause_decay_factor(core, params->clause_decay);
45,367✔
492
  if (params->cache_tclauses) {
45,367✔
493
    enable_theory_cache(core, params->tclause_size);
33,671✔
494
  } else {
495
    disable_theory_cache(core);
11,696✔
496
  }
497

498
  /*
499
   * Set egraph parameters
500
   */
501
  egraph = ctx->egraph;
45,367✔
502
  if (egraph != NULL) {
45,367✔
503
    if (params->use_optimistic_fcheck) {
13,457✔
504
      egraph_enable_optimistic_final_check(egraph);
13,454✔
505
    } else {
506
      egraph_disable_optimistic_final_check(egraph);
3✔
507
    }
508
    if (params->use_dyn_ack) {
13,457✔
509
      egraph_enable_dyn_ackermann(egraph, params->max_ackermann);
13,260✔
510
      egraph_set_ackermann_threshold(egraph, params->dyn_ack_threshold);
13,260✔
511
    } else {
512
      egraph_disable_dyn_ackermann(egraph);
197✔
513
    }
514
    if (params->use_bool_dyn_ack) {
13,457✔
515
      egraph_enable_dyn_boolackermann(egraph, params->max_boolackermann);
13,260✔
516
      egraph_set_boolack_threshold(egraph, params->dyn_bool_ack_threshold);
13,260✔
517
    } else {
518
      egraph_disable_dyn_boolackermann(egraph);
197✔
519
    }
520
    quota = egraph_num_terms(egraph) * params->aux_eq_ratio;
13,457✔
521
    if (quota < params->aux_eq_quota) {
13,457✔
522
      quota = params->aux_eq_quota;
13,396✔
523
    }
524
    egraph_set_aux_eq_quota(egraph, quota);
13,457✔
525
    egraph_set_max_interface_eqs(egraph, params->max_interface_eqs);
13,457✔
526
  }
527

528
  /*
529
   * Set simplex parameters
530
   */
531
  if (context_has_simplex_solver(ctx)) {
45,367✔
532
    simplex = ctx->arith_solver;
33,233✔
533
    if (params->use_simplex_prop) {
33,233✔
534
      simplex_enable_propagation(simplex);
12,857✔
535
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,857✔
536
    }
537
    if (params->adjust_simplex_model) {
33,233✔
538
      simplex_enable_adjust_model(simplex);
12,811✔
539
    }
540
    simplex_set_bland_threshold(simplex, params->bland_threshold);
33,233✔
541
    if (params->integer_check) {
33,233✔
542
      simplex_enable_periodic_icheck(simplex);
×
543
      simplex_set_integer_check_period(simplex, params->integer_check_period);
×
544
    }
545
  }
546

547
  /*
548
   * Set array solver parameters
549
   */
550
  if (context_has_fun_solver(ctx)) {
45,367✔
551
    fsolver = ctx->fun_solver;
12,872✔
552
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,872✔
553
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,872✔
554
  }
555
}
45,367✔
556

557
static smt_status_t _o_call_mcsat_solver(context_t *ctx, const param_t *params) {
1,124✔
558
  mcsat_solve(ctx->mcsat, params, NULL, 0, NULL);
1,124✔
559
  return mcsat_status(ctx->mcsat);
1,124✔
560
}
561

562
static smt_status_t call_mcsat_solver(context_t *ctx, const param_t *params) {
1,124✔
563
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_call_mcsat_solver(ctx, params));
1,124✔
564
}
565

566
/*
567
 * Initialize search parameters then call solve
568
 * - if ctx->status is not IDLE, return the status.
569
 * - if params is NULL, we use default values.
570
 */
571
smt_status_t check_context(context_t *ctx, const param_t *params) {
60,673✔
572
  smt_core_t *core;
573
  smt_status_t stat;
574

575
  if (params == NULL) {
60,673✔
576
    params = get_default_params();
×
577
  }
578

579
  if (ctx->mcsat != NULL) {
60,673✔
580
    return call_mcsat_solver(ctx, params);
1,124✔
581
  }
582

583
  core = ctx->core;
59,549✔
584
  stat = smt_status(core);
59,549✔
585
  if (stat == YICES_STATUS_IDLE) {
59,549✔
586
    // clean state: the search can proceed
587
    context_set_search_parameters(ctx, params);
42,725✔
588
    solve(core, params, 0, NULL);
42,725✔
589
    stat = smt_status(core);
42,725✔
590
  }
591

592
  return stat;
59,549✔
593
}
594

595

596
/*
597
 * Check with assumptions a[0] ... a[n-1]
598
 * - if ctx->status is not IDLE, return the status.
599
 */
600
smt_status_t check_context_with_assumptions(context_t *ctx, const param_t *params, uint32_t n, const literal_t *a) {
2,642✔
601
  smt_core_t *core;
602
  smt_status_t stat;
603

604
  assert(ctx->mcsat == NULL);
605

606
  core = ctx->core;
2,642✔
607
  stat = smt_status(core);
2,642✔
608
  if (stat == YICES_STATUS_IDLE) {
2,642✔
609
    // clean state
610
    if (params == NULL) {
2,642✔
611
      params = get_default_params();
×
612
    }
613
    context_set_search_parameters(ctx, params);
2,642✔
614
    solve(core, params, n, a);
2,642✔
615
    stat = smt_status(core);
2,642✔
616
  }
617

618
  return stat;
2,642✔
619
}
620

621
typedef struct delegate_state_s {
622
  delegate_t delegate;
623
  sat_delegate_t mode;
624
  bool live;
625
  uint64_t synced_mutation;
626
  uint32_t delegate_nvars;
627
  bvar_t next_selector_var;
628
  literal_t active_selector;
629
  ivector_t assumptions;
630
  ivector_t failed;
631
} delegate_state_t;
632

633
void context_delegate_state_cleanup(context_t *ctx) {
22,315✔
634
  delegate_state_t *st;
635

636
  st = (delegate_state_t *) ctx->delegate_state;
22,315✔
637
  if (st == NULL) {
22,315✔
638
    return;
22,315✔
639
  }
640

NEW
641
  if (st->live) {
×
NEW
642
    delete_delegate(&st->delegate);
×
NEW
643
    st->live = false;
×
644
  }
NEW
645
  delete_ivector(&st->assumptions);
×
NEW
646
  delete_ivector(&st->failed);
×
NEW
647
  safe_free(st);
×
NEW
648
  ctx->delegate_state = NULL;
×
649
}
650

NEW
651
static delegate_state_t *context_get_delegate_state(context_t *ctx) {
×
652
  delegate_state_t *st;
653

NEW
654
  st = (delegate_state_t *) ctx->delegate_state;
×
NEW
655
  if (st == NULL) {
×
NEW
656
    st = (delegate_state_t *) safe_malloc(sizeof(delegate_state_t));
×
NEW
657
    st->mode = SAT_DELEGATE_NONE;
×
NEW
658
    st->live = false;
×
NEW
659
    st->synced_mutation = 0;
×
NEW
660
    st->delegate_nvars = 0;
×
NEW
661
    st->next_selector_var = 0;
×
NEW
662
    st->active_selector = true_literal;
×
NEW
663
    init_ivector(&st->assumptions, 0);
×
NEW
664
    init_ivector(&st->failed, 0);
×
NEW
665
    ctx->delegate_state = st;
×
666
  }
NEW
667
  return st;
×
668
}
669

NEW
670
static void context_import_delegate_model(smt_core_t *core, delegate_t *d) {
×
671
  bvar_t x;
672

NEW
673
  for (x=0; x<num_vars(core); x++) {
×
NEW
674
    set_bvar_value(core, x, delegate_get_value(d, x));
×
675
  }
NEW
676
}
×
677

NEW
678
static void set_delegate_assumption_state(smt_core_t *core, uint32_t n, const literal_t *assumptions,
×
679
                                          smt_status_t stat, const ivector_t *failed) {
NEW
680
  if (n == 0) {
×
NEW
681
    core->has_assumptions = false;
×
NEW
682
    core->num_assumptions = 0;
×
NEW
683
    core->assumption_index = 0;
×
NEW
684
    core->assumptions = NULL;
×
NEW
685
    core->bad_assumption = null_literal;
×
NEW
686
    return;
×
687
  }
688

NEW
689
  core->has_assumptions = true;
×
NEW
690
  core->num_assumptions = n;
×
NEW
691
  core->assumption_index = n;
×
NEW
692
  core->assumptions = assumptions;
×
NEW
693
  core->bad_assumption = null_literal;
×
694

NEW
695
  if (stat == YICES_STATUS_UNSAT && failed != NULL && failed->size > 0) {
×
NEW
696
    core->bad_assumption = failed->data[0];
×
697
  }
698
}
699

NEW
700
static bool context_prepare_incremental_delegate(context_t *ctx, delegate_state_t *st, const char *sat_solver,
×
701
                                                 uint32_t verbosity) {
702
  smt_core_t *core;
703
  uint32_t nvars;
704
  literal_t guard;
705
  uint32_t nnew;
706

NEW
707
  core = ctx->core;
×
NEW
708
  nvars = num_vars(core);
×
709

NEW
710
  if (st->live && st->mode != ctx->sat_delegate) {
×
NEW
711
    delete_delegate(&st->delegate);
×
NEW
712
    st->live = false;
×
713
  }
714

NEW
715
  if (!st->live) {
×
NEW
716
    if (!init_delegate(&st->delegate, sat_solver, nvars)) {
×
NEW
717
      return false;
×
718
    }
NEW
719
    delegate_set_verbosity(&st->delegate, verbosity);
×
NEW
720
    st->mode = ctx->sat_delegate;
×
NEW
721
    st->synced_mutation = 0;
×
NEW
722
    st->delegate_nvars = nvars;
×
NEW
723
    st->next_selector_var = nvars;
×
NEW
724
    st->active_selector = true_literal;
×
NEW
725
    st->live = true;
×
726
  }
727

NEW
728
  if (st->delegate_nvars < nvars) {
×
NEW
729
    nnew = nvars - st->delegate_nvars;
×
NEW
730
    delegate_add_vars(&st->delegate, nnew);
×
NEW
731
    st->delegate_nvars = nvars;
×
732
  }
733

NEW
734
  if (st->synced_mutation != ctx->mutation_count) {
×
NEW
735
    if (st->next_selector_var < st->delegate_nvars) {
×
NEW
736
      st->next_selector_var = st->delegate_nvars;
×
737
    }
NEW
738
    if (st->next_selector_var >= st->delegate_nvars) {
×
NEW
739
      nnew = st->next_selector_var - st->delegate_nvars + 1;
×
NEW
740
      delegate_add_vars(&st->delegate, nnew);
×
NEW
741
      st->delegate_nvars += nnew;
×
742
    }
NEW
743
    guard = neg_lit(st->next_selector_var);
×
NEW
744
    add_problem_clauses_to_delegate(&st->delegate, core, guard);
×
NEW
745
    st->active_selector = pos_lit(st->next_selector_var);
×
NEW
746
    st->next_selector_var ++;
×
NEW
747
    st->synced_mutation = ctx->mutation_count;
×
748
  }
749

NEW
750
  return true;
×
751
}
752

NEW
753
smt_status_t check_with_incremental_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
754
                                             uint32_t n, const literal_t *assumptions, ivector_t *failed) {
755
  smt_status_t stat;
756
  smt_core_t *core;
757
  delegate_state_t *st;
758
  ivector_t visible_failed;
759
  uint32_t i;
760

NEW
761
  core = ctx->core;
×
NEW
762
  stat = smt_status(core);
×
NEW
763
  if (stat != YICES_STATUS_IDLE) {
×
NEW
764
    return stat;
×
765
  }
766

NEW
767
  start_search(core, 0, NULL);
×
NEW
768
  smt_process(core);
×
NEW
769
  stat = smt_status(core);
×
770

771
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
772
         stat == YICES_STATUS_INTERRUPTED);
773

NEW
774
  if (stat != YICES_STATUS_SEARCHING) {
×
NEW
775
    return stat;
×
776
  }
777

NEW
778
  if (n == 0 && smt_easy_sat(core)) {
×
NEW
779
    stat = YICES_STATUS_SAT;
×
NEW
780
    set_smt_status(core, stat);
×
NEW
781
    return stat;
×
782
  }
783

NEW
784
  st = context_get_delegate_state(ctx);
×
NEW
785
  if (!context_prepare_incremental_delegate(ctx, st, sat_solver, verbosity)) {
×
NEW
786
    return YICES_STATUS_UNKNOWN;
×
787
  }
788

NEW
789
  init_ivector(&visible_failed, 0);
×
NEW
790
  ivector_reset(&st->assumptions);
×
NEW
791
  ivector_reset(&st->failed);
×
NEW
792
  if (st->active_selector != true_literal) {
×
NEW
793
    ivector_push(&st->assumptions, st->active_selector);
×
794
  }
NEW
795
  for (i=0; i<n; i++) {
×
NEW
796
    ivector_push(&st->assumptions, assumptions[i]);
×
797
  }
798

NEW
799
  if (st->assumptions.size == 0) {
×
NEW
800
    stat = st->delegate.check(st->delegate.solver);
×
NEW
801
  } else if (delegate_supports_assumptions(&st->delegate)) {
×
NEW
802
    stat = delegate_check_with_assumptions(&st->delegate, st->assumptions.size,
×
NEW
803
                                           (literal_t *) st->assumptions.data, &st->failed);
×
NEW
804
    if (stat == YICES_STATUS_UNSAT) {
×
NEW
805
      for (i=0; i<st->failed.size; i++) {
×
NEW
806
        literal_t l = st->failed.data[i];
×
NEW
807
        if (l != st->active_selector) {
×
NEW
808
          ivector_push(&visible_failed, l);
×
809
        }
810
      }
NEW
811
      if (failed != NULL) {
×
NEW
812
        ivector_reset(failed);
×
NEW
813
        ivector_add(failed, visible_failed.data, visible_failed.size);
×
814
      }
815
    }
816
  } else {
NEW
817
    stat = YICES_STATUS_UNKNOWN;
×
818
  }
819

NEW
820
  set_smt_status(core, stat);
×
NEW
821
  set_delegate_assumption_state(core, n, assumptions, stat, &visible_failed);
×
NEW
822
  if (stat == YICES_STATUS_SAT) {
×
NEW
823
    context_import_delegate_model(core, &st->delegate);
×
824
  }
825

NEW
826
  delete_ivector(&visible_failed);
×
NEW
827
  return stat;
×
828
}
829

830
/*
831
 * Explore term t and collect all Boolean atoms into atoms.
832
 */
833
static void collect_boolean_atoms(context_t *ctx, term_t t, int_hset_t *atoms, int_hset_t *visited) {
64✔
834
  term_table_t *terms;
835
  uint32_t i, nchildren;
836

837
  if (t < 0) {
64✔
838
    t = not(t);
×
839
  }
840

841
  if (int_hset_member(visited, t)) {
64✔
842
    return;
×
843
  }
844
  int_hset_add(visited, t);
64✔
845

846
  terms = ctx->terms;
64✔
847
  if (term_type(terms, t) == bool_type(terms->types)) {
64✔
848
    int_hset_add(atoms, t);
64✔
849
  }
850

851
  if (term_is_projection(terms, t)) {
64✔
852
    collect_boolean_atoms(ctx, proj_term_arg(terms, t), atoms, visited);
×
853
  } else if (term_is_sum(terms, t)) {
64✔
854
    nchildren = term_num_children(terms, t);
×
855
    for (i=0; i<nchildren; i++) {
×
856
      term_t child;
857
      mpq_t q;
858
      mpq_init(q);
×
859
      sum_term_component(terms, t, i, q, &child);
×
860
      collect_boolean_atoms(ctx, child, atoms, visited);
×
861
      mpq_clear(q);
×
862
    }
863
  } else if (term_is_bvsum(terms, t)) {
64✔
864
    uint32_t nbits = term_bitsize(terms, t);
×
865
    int32_t *aux = (int32_t*) safe_malloc(nbits * sizeof(int32_t));
×
866
    nchildren = term_num_children(terms, t);
×
867
    for (i=0; i<nchildren; i++) {
×
868
      term_t child;
869
      bvsum_term_component(terms, t, i, aux, &child);
×
870
      collect_boolean_atoms(ctx, child, atoms, visited);
×
871
    }
872
    safe_free(aux);
×
873
  } else if (term_is_product(terms, t)) {
64✔
874
    nchildren = term_num_children(terms, t);
×
875
    for (i=0; i<nchildren; i++) {
×
876
      term_t child;
877
      uint32_t exp;
878
      product_term_component(terms, t, i, &child, &exp);
×
879
      collect_boolean_atoms(ctx, child, atoms, visited);
×
880
    }
881
  } else if (term_is_composite(terms, t)) {
64✔
882
    nchildren = term_num_children(terms, t);
34✔
883
    for (i=0; i<nchildren; i++) {
89✔
884
      collect_boolean_atoms(ctx, term_child(terms, t, i), atoms, visited);
55✔
885
    }
886
  }
887
}
888

889
/*
890
 * Extract assumptions whose labels appear in term t.
891
 */
892
static void core_from_labeled_interpolant(context_t *ctx, term_t t, const ivector_t *labels, const int_hmap_t *label_map, ivector_t *core) {
9✔
893
  int_hset_t atoms, visited;
894
  uint32_t i;
895

896
  init_int_hset(&atoms, 0);
9✔
897
  init_int_hset(&visited, 0);
9✔
898
  collect_boolean_atoms(ctx, t, &atoms, &visited);
9✔
899

900
  ivector_reset(core);
9✔
901
  for (i=0; i<labels->size; i++) {
83✔
902
    term_t label = labels->data[i];
74✔
903
    if (int_hset_member(&atoms, label)) {
74✔
904
      int_hmap_pair_t *p = int_hmap_find((int_hmap_t *) label_map, label);
30✔
905
      if (p != NULL) {
30✔
906
        ivector_push(core, p->val);
30✔
907
      }
908
    }
909
  }
910

911
  delete_int_hset(&visited);
9✔
912
  delete_int_hset(&atoms);
9✔
913
}
9✔
914

915
/*
916
 * Cache a core vector in the context.
917
 */
918
static void cache_unsat_core(context_t *ctx, const ivector_t *core) {
2,708✔
919
  if (ctx->unsat_core_cache == NULL) {
2,708✔
920
    ctx->unsat_core_cache = (ivector_t *) safe_malloc(sizeof(ivector_t));
2,708✔
921
    init_ivector(ctx->unsat_core_cache, core->size);
2,708✔
922
  } else {
923
    ivector_reset(ctx->unsat_core_cache);
×
924
  }
925
  ivector_copy(ctx->unsat_core_cache, core->data, core->size);
2,708✔
926
}
2,708✔
927

NEW
928
static void cache_failed_assumptions_core(context_t *ctx, uint32_t n, const term_t *a,
×
929
                                          const ivector_t *assumption_literals,
930
                                          const ivector_t *failed_literals) {
931
  ivector_t core_terms;
932
  int_hset_t failed;
933
  uint32_t i;
934

NEW
935
  init_ivector(&core_terms, 0);
×
NEW
936
  init_int_hset(&failed, 0);
×
NEW
937
  for (i=0; i<failed_literals->size; i++) {
×
NEW
938
    int_hset_add(&failed, failed_literals->data[i]);
×
939
  }
NEW
940
  for (i=0; i<n; i++) {
×
NEW
941
    if (int_hset_member(&failed, assumption_literals->data[i])) {
×
NEW
942
      ivector_push(&core_terms, a[i]);
×
943
    }
944
  }
NEW
945
  cache_unsat_core(ctx, &core_terms);
×
NEW
946
  delete_int_hset(&failed);
×
NEW
947
  delete_ivector(&core_terms);
×
NEW
948
}
×
949

950
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
951
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed);
952

953
/*
954
 * MCSAT variant of check_context_with_term_assumptions.
955
 * Caller must hold __yices_globals.lock.
956
 */
957
static smt_status_t _o_check_context_with_term_assumptions_mcsat(context_t *ctx, const param_t *params, uint32_t n, const term_t *a, int32_t *error) {
10✔
958
  smt_status_t stat;
959
  ivector_t assumptions;
960
  uint32_t i;
961

962
  /*
963
   * MCSAT: create fresh labels b_i, assert (b_i => a_i), then solve with model b_i=true.
964
   * We extract interpolant/core before cleanup, then restore sticky UNSAT artifacts.
965
   */
966
  if (!context_supports_model_interpolation(ctx)) {
10✔
967
    if (error != NULL) {
×
968
      *error = CTX_OPERATION_NOT_SUPPORTED;
×
969
    }
970
    return YICES_STATUS_ERROR;
×
971
  }
972

973
  {
974
    model_t mdl;               // temporary model: sets all label terms b_i to true
975
    int_hmap_t label_map;      // map label b_i -> original assumption a_i
976
    ivector_t mapped_core;     // translated core over original assumptions
977
    term_t interpolant = NULL_TERM; // raw/substituted interpolant for sticky UNSAT result
10✔
978
    int32_t code;              // return code from assert_formula (negative on internalization error)
979
    bool pushed;               // whether we pushed a temporary scope and must pop it
980
    term_manager_t tm;
981

982
    init_model(&mdl, ctx->terms, true);
10✔
983
    init_int_hmap(&label_map, 0);
10✔
984
    init_ivector(&assumptions, n);
10✔
985
    init_ivector(&mapped_core, 0);
10✔
986
    init_term_manager(&tm, ctx->terms);
10✔
987
    stat = YICES_STATUS_IDLE;
10✔
988

989
    pushed = false;
10✔
990
    if (context_supports_pushpop(ctx)) {
10✔
991
      context_push(ctx);
9✔
992
      pushed = true;
9✔
993
    }
994

995
    for (i=0; i<n; i++) {
85✔
996
      term_t b = new_uninterpreted_term(ctx->terms, bool_id);
75✔
997
      term_t implication = mk_implies(&tm, b, a[i]);
75✔
998

999
      int_hmap_add(&label_map, b, a[i]);
75✔
1000
      code = _o_assert_formula(ctx, implication);
75✔
1001
      if (code < 0) {
75✔
1002
        if (error != NULL) {
×
1003
          *error = code;
×
1004
        }
1005
        stat = YICES_STATUS_ERROR;
×
1006
        break;
×
1007
      }
1008
      model_map_term(&mdl, b, vtbl_mk_bool(&mdl.vtbl, true));
75✔
1009
      ivector_push(&assumptions, b);
75✔
1010
    }
1011

1012
    if (stat != YICES_STATUS_ERROR) {
10✔
1013
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
10✔
1014
      if (stat == YICES_STATUS_UNSAT) {
10✔
1015
        interpolant = context_get_unsat_model_interpolant(ctx);
9✔
1016
        assert(interpolant != NULL_TERM);
1017
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
9✔
1018
      }
1019
    }
1020

1021
    if (pushed) {
10✔
1022
      mcsat_cleanup_assumptions(ctx->mcsat);
9✔
1023
      context_pop(ctx);
9✔
1024
    }
1025
    if (stat == YICES_STATUS_UNSAT) {
10✔
1026
      mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, interpolant, n, assumptions.data, a);
9✔
1027
      cache_unsat_core(ctx, &mapped_core);
9✔
1028
    }
1029

1030
    delete_term_manager(&tm);
10✔
1031
    delete_ivector(&mapped_core);
10✔
1032
    delete_ivector(&assumptions);
10✔
1033
    delete_int_hmap(&label_map);
10✔
1034
    delete_model(&mdl);
10✔
1035

1036
    return stat;
10✔
1037
  }
1038
}
1039

1040
static smt_status_t check_context_with_term_assumptions_mcsat(context_t *ctx, const param_t *params, uint32_t n, const term_t *a, int32_t *error) {
10✔
1041
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
10✔
1042
}
1043

1044
/*
1045
 * Check under assumptions given as terms.
1046
 * - if MCSAT is enabled, this uses temporary labels + model interpolation.
1047
 * - otherwise terms are converted to literals and handled by the CDCL(T) path.
1048
 *
1049
 * Preconditions:
1050
 * - context status must be IDLE.
1051
 */
1052
smt_status_t check_context_with_term_assumptions(context_t *ctx, const param_t *params, uint32_t n, const term_t *a, int32_t *error) {
2,653✔
1053
  if (error != NULL) {
2,653✔
1054
    *error = CTX_NO_ERROR;
2,653✔
1055
  }
1056

1057
  /*
1058
   * Clear any prior term-assumption core before all paths below. Delegate
1059
   * checks cache a new core only on UNSAT.
1060
   */
1061
  context_invalidate_unsat_core_cache(ctx);
2,653✔
1062

1063
  if (ctx->mcsat == NULL) {
2,653✔
1064
    smt_status_t stat;
1065
    sat_delegate_t mode;
1066
    bool one_shot;
1067
    const char *delegate;
1068
    bool unknown;
1069
    ivector_t assumptions;
1070
    ivector_t failed;
1071
    uint32_t i;
1072
    literal_t l;
1073

1074
    init_ivector(&assumptions, n);
2,643✔
1075
    for (i=0; i<n; i++) {
90,110✔
1076
      l = context_add_assumption(ctx, a[i]);
87,467✔
1077
      if (l < 0) {
87,467✔
1078
        if (error != NULL) {
×
1079
          *error = l;
×
1080
        }
1081
        delete_ivector(&assumptions);
×
1082
        return YICES_STATUS_ERROR;
×
1083
      }
1084
      ivector_push(&assumptions, l);
87,467✔
1085
    }
1086

1087
    mode = effective_sat_delegate_mode(ctx->sat_delegate, params, &one_shot);
2,643✔
1088
    delegate = sat_delegate_name(mode);
2,643✔
1089
    if (delegate == NULL) {
2,643✔
1090
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,642✔
1091
      delete_ivector(&assumptions);
2,642✔
1092
      return stat;
2,642✔
1093
    }
1094

1095
    if (ctx->logic != QF_BV) {
1✔
NEW
1096
      if (error != NULL) {
×
NEW
1097
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1098
      }
NEW
1099
      delete_ivector(&assumptions);
×
NEW
1100
      return YICES_STATUS_ERROR;
×
1101
    }
1102

1103
    if (!supported_delegate(delegate, &unknown)) {
1✔
NEW
1104
      if (error != NULL) {
×
NEW
1105
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1106
      }
NEW
1107
      delete_ivector(&assumptions);
×
NEW
1108
      return YICES_STATUS_ERROR;
×
1109
    }
1110

1111
    if (!incremental_delegate(delegate)) {
1✔
1112
      if (error != NULL) {
1✔
1113
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1114
      }
1115
      delete_ivector(&assumptions);
1✔
1116
      return YICES_STATUS_ERROR;
1✔
1117
    }
1118

NEW
1119
    init_ivector(&failed, 0);
×
NEW
1120
    if (one_shot || !ctx->sat_delegate_selector_frames) {
×
NEW
1121
      stat = check_with_delegate_assumptions(ctx, delegate, 0, n, assumptions.data, &failed);
×
1122
    } else {
NEW
1123
      stat = check_with_incremental_delegate(ctx, delegate, 0, n, assumptions.data, &failed);
×
1124
    }
NEW
1125
    if (stat == YICES_STATUS_UNSAT) {
×
NEW
1126
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
×
1127
    }
NEW
1128
    delete_ivector(&failed);
×
UNCOV
1129
    delete_ivector(&assumptions);
×
UNCOV
1130
    return stat;
×
1131
  }
1132

1133
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1134
}
1135

1136
/*
1137
 * Check with given model
1138
 * - if mcsat status is not IDLE, return the status
1139
 */
1140
smt_status_t check_context_with_model(context_t *ctx, const param_t *params, model_t* mdl, uint32_t n, const term_t t[]) {
161✔
1141
  smt_status_t stat;
1142

1143
  assert(ctx->mcsat != NULL);
1144

1145
  stat = mcsat_status(ctx->mcsat);
161✔
1146
  if (stat == YICES_STATUS_IDLE) {
161✔
1147
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
161✔
1148
    stat = mcsat_status(ctx->mcsat);
161✔
1149

1150
    // BD: this looks wrong. We shouldn't call clear yet.
1151
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1152
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1153
    //      context_clear(ctx);
1154
    //    }
1155
  }
1156

1157
  return stat;
161✔
1158
}
1159

1160
/*
1161
 * Check with given model and hints
1162
 * - set the model hint and call check_context_with_model
1163
 */
1164
smt_status_t check_context_with_model_and_hint(context_t *ctx, const param_t *params, model_t* mdl, uint32_t n, const term_t t[], uint32_t m) {
14✔
1165
  assert(m <= n);
1166

1167
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1168

1169
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1170
}
1171

1172

1173
/*
1174
 * Precheck: force generation of clauses and other stuff that's
1175
 * constructed lazily by the solvers. For example, this
1176
 * can be used to convert all the constraints asserted in the
1177
 * bitvector to clauses so that we can export the result to DIMACS.
1178
 *
1179
 * If ctx status is IDLE:
1180
 * - the function calls 'start_search' and does one round of propagation.
1181
 * - if this results in UNSAT, the function returns UNSAT
1182
 * - if the precheck is interrupted, the function returns INTERRUPTED
1183
 * - otherwise the function returns UNKNOWN and sets the status to
1184
 *   UNKNOWN.
1185
 *
1186
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
1187
 * IDLE before doing anything else with this context.
1188
 *
1189
 * If ctx status is not IDLE, the function returns it and does nothing
1190
 * else.
1191
 */
1192
smt_status_t precheck_context(context_t *ctx) {
×
1193
  smt_status_t stat;
1194
  smt_core_t *core;
1195

1196
  core = ctx->core;
×
1197

1198
  stat = smt_status(core);
×
1199
  if (stat == YICES_STATUS_IDLE) {
×
1200
    start_search(core, 0, NULL);
×
1201
    smt_process(core);
×
1202
    stat = smt_status(core);
×
1203

1204
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1205
           stat == YICES_STATUS_INTERRUPTED);
1206

1207
    if (stat == YICES_STATUS_SEARCHING) {
×
1208
      end_search_unknown(core);
×
1209
      stat = YICES_STATUS_UNKNOWN;
×
1210
    }
1211
  }
1212

1213
  return stat;
×
1214
}
1215

1216

1217

1218
/*
1219
 * Solve using another SAT solver
1220
 * - sat_solver = name of the solver to use
1221
 * - verbosity = verbosity level (0 means quiet)
1222
 * - this may be used only for BV or pure SAT problems
1223
 * - we perform one round of propagation to convert the problem to CNF
1224
 * - then we call an external SAT solver on the CNF problem
1225
 */
1226
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
18✔
1227
  smt_status_t stat;
1228
  smt_core_t *core;
1229
  delegate_t delegate;
1230
  bvar_t x;
1231
  bval_t v;
1232

1233
  core = ctx->core;
18✔
1234

1235
  stat = smt_status(core);
18✔
1236
  if (stat == YICES_STATUS_IDLE) {
18✔
1237
    start_search(core, 0, NULL);
18✔
1238
    smt_process(core);
18✔
1239
    stat = smt_status(core);
18✔
1240

1241
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1242
           stat == YICES_STATUS_INTERRUPTED);
1243

1244
    if (stat == YICES_STATUS_SEARCHING) {
18✔
1245
      if (smt_easy_sat(core)) {
17✔
1246
        stat = YICES_STATUS_SAT;
17✔
1247
      } else {
1248
        // call the delegate
1249
        init_delegate(&delegate, sat_solver, num_vars(core));
×
1250
        delegate_set_verbosity(&delegate, verbosity);
×
1251

1252
        stat = solve_with_delegate(&delegate, core);
×
1253
        set_smt_status(core, stat);
×
1254
        if (stat == YICES_STATUS_SAT) {
×
1255
          for (x=0; x<num_vars(core); x++) {
×
1256
            v = delegate_get_value(&delegate, x);
×
1257
            set_bvar_value(core, x, v);
×
1258
          }
1259
        }
1260
        delete_delegate(&delegate);
×
1261
      }
1262
    }
1263
  }
1264

1265
  return stat;
18✔
1266
}
1267

1268
/*
1269
 * One-shot check with delegate and assumptions.
1270
 * - assumptions are literals in core encoding.
1271
 * - if failed != NULL and result is UNSAT, failed assumptions are appended to *failed.
1272
 */
NEW
1273
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
1274
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1275
  smt_status_t stat;
1276
  smt_core_t *core;
1277
  delegate_t delegate;
1278

NEW
1279
  core = ctx->core;
×
1280

NEW
1281
  stat = smt_status(core);
×
NEW
1282
  if (stat != YICES_STATUS_IDLE) {
×
NEW
1283
    return stat;
×
1284
  }
1285

NEW
1286
  start_search(core, 0, NULL);
×
NEW
1287
  smt_process(core);
×
NEW
1288
  stat = smt_status(core);
×
1289

1290
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1291
         stat == YICES_STATUS_INTERRUPTED);
1292

NEW
1293
  if (stat != YICES_STATUS_SEARCHING) {
×
NEW
1294
    return stat;
×
1295
  }
1296

NEW
1297
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
NEW
1298
    return YICES_STATUS_UNKNOWN;
×
1299
  }
NEW
1300
  delegate_set_verbosity(&delegate, verbosity);
×
1301

NEW
1302
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
NEW
1303
  set_smt_status(core, stat);
×
NEW
1304
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
NEW
1305
  if (stat == YICES_STATUS_SAT) {
×
NEW
1306
    context_import_delegate_model(core, &delegate);
×
1307
  }
1308

NEW
1309
  delete_delegate(&delegate);
×
NEW
1310
  return stat;
×
1311
}
1312

1313

1314
/*
1315
 * Bit-blast then export to DIMACS
1316
 * - filename = name of the output file
1317
 * - status = status of the context after bit-blasting
1318
 *
1319
 * If ctx status is IDLE
1320
 * - perform one round of propagation to conver the problem to CNF
1321
 * - export the CNF to DIMACS
1322
 *
1323
 * If ctx status is not IDLE,
1324
 * - store the stauts in *status and do nothing else
1325
 *
1326
 * Return code:
1327
 *  1 if the DIMACS file was created
1328
 *  0 if the problem was solved by the propagation round
1329
 * -1 if there was an error in creating or writing to the file.
1330
 */
1331
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1332
  smt_core_t *core;
1333
  FILE *f;
1334
  smt_status_t stat;
1335
  int32_t code;
1336

1337
  core = ctx->core;
×
1338

1339
  code = 0;
×
1340
  stat = smt_status(core);
×
1341
  if (stat == YICES_STATUS_IDLE) {
×
1342
    start_search(core, 0, NULL);
×
1343
    smt_process(core);
×
1344
    stat = smt_status(core);
×
1345

1346
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1347
           stat == YICES_STATUS_INTERRUPTED);
1348

1349
    if (stat == YICES_STATUS_SEARCHING) {
×
1350
      code = 1;
×
1351
      f = fopen(filename, "w");
×
1352
      if (f == NULL) {
×
1353
        code = -1;
×
1354
      } else {
1355
        dimacs_print_bvcontext(f, ctx);
×
1356
        if (ferror(f)) code = -1;
×
1357
        fclose(f);
×
1358
      }
1359
    }
1360
  }
1361

1362
  *status = stat;
×
1363

1364
  return code;
×
1365
}
1366

1367

1368
/*
1369
 * Simplify then export to Dimacs:
1370
 * - filename = name of the output file
1371
 * - status = status of the context after CNF conversion + preprocessing
1372
 *
1373
 * If ctx status is IDLE
1374
 * - perform one round of propagation to convert the problem to CNF
1375
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
1376
 *
1377
 * If ctx status is not IDLE, the function stores that in *status
1378
 * If y2sat preprocessing solves the formula, return the status also in *status
1379
 *
1380
 * Return code:
1381
 *  1 if the DIMACS file was created
1382
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
1383
 * -1 if there was an error creating or writing to the file.
1384
 */
1385
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1386
  smt_core_t *core;
1387
  FILE *f;
1388
  smt_status_t stat;
1389
  delegate_t delegate;
1390
  bvar_t x;
1391
  bval_t v;
1392
  int32_t code;
1393

1394
  core = ctx->core;
×
1395

1396
  code = 0;
×
1397
  stat = smt_status(core);
×
1398
  if (stat == YICES_STATUS_IDLE) {
×
1399
    start_search(core, 0, NULL);
×
1400
    smt_process(core);
×
1401
    stat = smt_status(core);
×
1402

1403
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1404
           stat == YICES_STATUS_INTERRUPTED);
1405

1406
    if (stat == YICES_STATUS_SEARCHING) {
×
1407
      if (smt_easy_sat(core)) {
×
1408
        stat = YICES_STATUS_SAT;
×
1409
      } else {
1410
        // call the delegate
1411
        init_delegate(&delegate, "y2sat", num_vars(core));
×
1412
        delegate_set_verbosity(&delegate, 0);
×
1413

1414
        stat = preprocess_with_delegate(&delegate, core);
×
1415
        set_smt_status(core, stat);
×
1416
        if (stat == YICES_STATUS_SAT) {
×
1417
          for (x=0; x<num_vars(core); x++) {
×
1418
            v = delegate_get_value(&delegate, x);
×
1419
            set_bvar_value(core, x, v);
×
1420
          }
1421
        } else if (stat == YICES_STATUS_UNKNOWN) {
×
1422
          code = 1;
×
1423
          f = fopen(filename, "w");
×
1424
          if (f == NULL) {
×
1425
            code = -1;
×
1426
          } else {
1427
            export_to_dimacs_with_delegate(&delegate, f);
×
1428
            if (ferror(f)) code = -1;
×
1429
            fclose(f);
×
1430
          }
1431
        }
1432

1433
        delete_delegate(&delegate);
×
1434
      }
1435
    }
1436
  }
1437

1438
  *status = stat;
×
1439

1440
  return code;
×
1441
}
1442

1443

1444

1445
/*
1446
 * MODEL CONSTRUCTION
1447
 */
1448

1449
/*
1450
 * Value of literal l in ctx->core
1451
 */
1452
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
1453
  value_t v;
1454

1455
  v = null_value; // prevent GCC warning
65,201✔
1456
  switch (literal_value(ctx->core, l)) {
65,201✔
1457
  case VAL_FALSE:
38,577✔
1458
    v = vtbl_mk_false(vtbl);
38,577✔
1459
    break;
38,577✔
1460
  case VAL_UNDEF_FALSE:
×
1461
  case VAL_UNDEF_TRUE:
1462
    v = vtbl_mk_unknown(vtbl);
×
1463
    break;
×
1464
  case VAL_TRUE:
26,624✔
1465
    v = vtbl_mk_true(vtbl);
26,624✔
1466
    break;
26,624✔
1467
  }
1468
  return v;
65,201✔
1469
}
1470

1471

1472
/*
1473
 * Value of arithmetic variable x in ctx->arith_solver
1474
 */
1475
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,590✔
1476
  rational_t *a;
1477
  value_t v;
1478

1479
  assert(context_has_arith_solver(ctx));
1480

1481
  a = &ctx->aux;
22,590✔
1482
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,590✔
1483
    v = vtbl_mk_rational(vtbl, a);
22,590✔
1484
  } else {
1485
    v = vtbl_mk_unknown(vtbl);
×
1486
  }
1487

1488
  return v;
22,590✔
1489
}
1490

1491

1492

1493
/*
1494
 * Value of bitvector variable x in ctx->bv_solver
1495
 */
1496
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,141✔
1497
  bvconstant_t *b;
1498
  value_t v;
1499

1500
  assert(context_has_bv_solver(ctx));
1501

1502
  b = &ctx->bv_buffer;
18,141✔
1503
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,141✔
1504
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,141✔
1505
  } else {
1506
    v = vtbl_mk_unknown(vtbl);
×
1507
  }
1508

1509
  return v;
18,141✔
1510
}
1511

1512

1513
/*
1514
 * Get a value for term t in the solvers or egraph
1515
 * - attach the mapping from t to that value in model
1516
 * - if we don't have a concrete object for t but t is
1517
 *   mapped to a term u and the model->has_alias is true,
1518
 *   then we store the mapping [t --> u] in the model's
1519
 *   alias map.
1520
 */
1521
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
319,875✔
1522
  value_table_t *vtbl;
1523
  term_t r;
1524
  uint32_t polarity;
1525
  int32_t x;
1526
  type_t tau;
1527
  value_t v;
1528

1529
  /*
1530
   * Get the root of t in the substitution table
1531
   */
1532
  r = intern_tbl_get_root(&ctx->intern, t);
319,875✔
1533
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
319,875✔
1534
    /*
1535
     * r is mapped to some object x in egraph/core/or theory solvers
1536
     * - keep track of polarity then force r to positive polarity
1537
     */
1538
    vtbl = model_get_vtbl(model);
110,706✔
1539
    polarity = polarity_of(r);
110,706✔
1540
    r = unsigned_term(r);
110,706✔
1541

1542
    /*
1543
     * Convert x to a concrete value
1544
     */
1545
    x = intern_tbl_map_of_root(&ctx->intern, r);
110,706✔
1546
    if (code_is_eterm(x)) {
110,706✔
1547
      // x refers to an egraph object or true_occ/false_occ
1548
      if (x == bool2code(true)) {
4,774✔
1549
        v = vtbl_mk_true(vtbl);
475✔
1550
      } else if (x == bool2code(false)) {
4,299✔
1551
        v = vtbl_mk_false(vtbl);
1,420✔
1552
      } else {
1553
        assert(context_has_egraph(ctx));
1554
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,879✔
1555
      }
1556

1557
    } else {
1558
      // x refers to a literal or a theory variable
1559
      tau = term_type(ctx->terms, r);
105,932✔
1560
      switch (type_kind(ctx->types, tau)) {
105,932✔
1561
      case BOOL_TYPE:
65,201✔
1562
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
1563
        break;
65,201✔
1564

1565
      case INT_TYPE:
22,590✔
1566
      case REAL_TYPE:
1567
        v = arith_value(ctx, vtbl, code2thvar(x));
22,590✔
1568
        break;
22,590✔
1569

1570
      case BITVECTOR_TYPE:
18,141✔
1571
        v = bv_value(ctx, vtbl, code2thvar(x));
18,141✔
1572
        break;
18,141✔
1573

1574
      default:
×
1575
        /*
1576
         * This should never happen:
1577
         * scalar, uninterpreted, tuple, function terms
1578
         * are mapped to egraph terms.
1579
         */
1580
        assert(false);
1581
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
1582
        break;
×
1583
      }
1584
    }
1585

1586
    /*
1587
     * Restore polarity then add mapping [t --> v] in the model
1588
     */
1589
    if (! object_is_unknown(vtbl, v)) {
110,706✔
1590
      if (object_is_boolean(vtbl, v)) {
110,706✔
1591
        if (polarity) {
67,096✔
1592
          // negate the value
1593
          v = vtbl_mk_not(vtbl, v);
24✔
1594
        }
1595
      }
1596
      model_map_term(model, t, v);
110,706✔
1597
    }
1598

1599
  } else {
1600
    /*
1601
     * r is not mapped to anything:
1602
     *
1603
     * 1) If t == r and t is present in the internalization table
1604
     *    then t is relevant. So we should display its value
1605
     *    when we print the model. To do this, we assign an
1606
     *    arbitrary value v to t and store [t := v] in the map.
1607
     *
1608
     * 2) If t != r then we keep the mapping [t --> r] in
1609
     *    the alias table (provided the model supports aliases).
1610
     */
1611
    if (t == r) {
209,169✔
1612
      if (intern_tbl_term_present(&ctx->intern, t)) {
208,519✔
1613
        tau = term_type(ctx->terms, t);
×
1614
        vtbl = model_get_vtbl(model);
×
1615
        v = vtbl_make_object(vtbl, tau);
×
1616
        model_map_term(model, t, v);
×
1617
      }
1618
    } else if (model->has_alias) {
650✔
1619
      // t != r: keep the substitution [t --> r] in the model
1620
      model_add_substitution(model, t, r);
650✔
1621
    }
1622
  }
1623
}
319,875✔
1624

1625

1626

1627

1628
/*
1629
 * Build a model for the current context (including all satellite solvers)
1630
 * - the context status must be SAT (or UNKNOWN)
1631
 * - if model->has_alias is true, we store the term substitution
1632
 *   defined by ctx->intern_tbl into the model
1633
 * - cleanup of satellite models needed using clean_solver_models()
1634
 */
1635
void build_model(model_t *model, context_t *ctx) {
42,152✔
1636
  term_table_t *terms;
1637
  uint32_t i, n;
1638
  term_t t;
1639

1640
  assert(smt_status(ctx->core) == YICES_STATUS_SAT || smt_status(ctx->core) == YICES_STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == YICES_STATUS_SAT);
1641

1642
  /*
1643
   * First build assignments in the satellite solvers
1644
   * and get the val_in_model functions for the egraph
1645
   */
1646
  if (context_has_arith_solver(ctx)) {
42,152✔
1647
    ctx->arith.build_model(ctx->arith_solver);
32,909✔
1648
  }
1649
  if (context_has_bv_solver(ctx)) {
42,152✔
1650
    ctx->bv.build_model(ctx->bv_solver);
21,409✔
1651
  }
1652

1653
  /*
1654
   * Construct the egraph model
1655
   */
1656
  if (context_has_egraph(ctx)) {
42,152✔
1657
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,035✔
1658
  }
1659

1660
  /*
1661
   * Construct the mcsat model.
1662
   */
1663
  if (context_has_mcsat(ctx)) {
42,152✔
1664
    mcsat_build_model(ctx->mcsat, model);
51✔
1665
  }
1666

1667
  // scan the internalization table
1668
  terms = ctx->terms;
42,152✔
1669
  n = intern_tbl_num_terms(&ctx->intern);
42,152✔
1670
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,096,241✔
1671
    if (good_term_idx(terms, i)) {
1,235,054,089✔
1672
      t = pos_occ(i);
1,235,054,089✔
1673
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,054,089✔
1674
        build_term_value(ctx, model, t);
319,875✔
1675
      }
1676
    }
1677
  }
1678
}
42,152✔
1679

1680

1681
/*
1682
 * Cleanup solver models
1683
 */
1684
void clean_solver_models(context_t *ctx) {
42,152✔
1685
  if (context_has_arith_solver(ctx)) {
42,152✔
1686
    ctx->arith.free_model(ctx->arith_solver);
32,909✔
1687
  }
1688
  if (context_has_bv_solver(ctx)) {
42,152✔
1689
    ctx->bv.free_model(ctx->bv_solver);
21,409✔
1690
  }
1691
  if (context_has_egraph(ctx)) {
42,152✔
1692
    egraph_free_model(ctx->egraph);
13,035✔
1693
  }
1694
}
42,152✔
1695

1696

1697

1698
/*
1699
 * Build a model for the current context
1700
 * - the context status must be SAT (or UNKNOWN)
1701
 * - if model->has_alias is true, we store the term substitution
1702
 *   defined by ctx->intern_tbl into the model
1703
 */
1704
void context_build_model(model_t *model, context_t *ctx) {
251✔
1705
  // Build solver models and term values
1706
  build_model(model, ctx);
251✔
1707

1708
  // Cleanup
1709
  clean_solver_models(ctx);
251✔
1710
}
251✔
1711

1712

1713

1714
/*
1715
 * Read the value of a Boolean term t
1716
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
1717
 */
1718
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
1719
  term_t r;
1720
  uint32_t polarity;
1721
  int32_t x;
1722
  bval_t v;
1723

1724
  assert(is_boolean_term(ctx->terms, t));
1725

1726
  // default value if t is not in the internalization table
1727
  v = VAL_UNDEF_FALSE;
×
1728
  r = intern_tbl_get_root(&ctx->intern, t);
×
1729
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
1730
    // r is mapped to some object x
1731
    polarity = polarity_of(r);
×
1732
    r = unsigned_term(r);
×
1733

1734
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
1735
    if (code_is_eterm(x)) {
×
1736
      // x must be either true_occ or false_occ
1737
      if (x == bool2code(true)) {
×
1738
        v = VAL_TRUE;
×
1739
      } else {
1740
        assert(x == bool2code(false));
1741
        v = VAL_FALSE;
×
1742
      }
1743
    } else {
1744
      // x refers to a literal in the smt core
1745
      v = literal_value(ctx->core, code2literal(x));
×
1746
    }
1747

1748
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
1749
    v ^= polarity;
×
1750
  }
1751

1752
  return v;
×
1753
}
1754

1755

1756
/*
1757
 * UNSAT CORE
1758
 */
1759

1760
/*
1761
 * Build an unsat core:
1762
 * - store the result in v
1763
 * - first reuse a cached term core if available.
1764
 * - otherwise:
1765
 *   CDCL(T): build from smt_core then cache as terms
1766
 *   MCSAT: return empty unless check-with-term-assumptions populated the cache.
1767
 */
1768
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
2,704✔
1769
  smt_core_t *core;
1770
  uint32_t i, n;
1771
  term_t t;
1772

1773
  if (ctx->unsat_core_cache != NULL) {
2,704✔
1774
    // Fast path: repeated get_unsat_core returns the cached term vector.
1775
    ivector_reset(v);
5✔
1776
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
5✔
1777
    return;
5✔
1778
  }
1779

1780
  if (ctx->mcsat != NULL) {
2,699✔
1781
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
1782
    // there is no generic context-level core structure to rebuild from here.
1783
    ivector_reset(v);
×
1784
    return;
×
1785
  }
1786

1787
  core = ctx->core;
2,699✔
1788
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
1789
  build_unsat_core(core, v);
2,699✔
1790

1791
  // convert from literals to terms
1792
  n = v->size;
2,699✔
1793
  for (i=0; i<n; i++) {
37,499✔
1794
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,800✔
1795
    assert(t >= 0);
1796
    v->data[i] = t;
34,800✔
1797
  }
1798

1799
  // Cache the converted term core for subsequent queries.
1800
  cache_unsat_core(ctx, v);
2,699✔
1801
}
1802

1803

1804
/*
1805
 * MODEL INTERPOLANT
1806
 */
1807
term_t context_get_unsat_model_interpolant(context_t *ctx) {
61✔
1808
  assert(ctx->mcsat != NULL);
1809
  return mcsat_get_unsat_model_interpolant(ctx->mcsat);
61✔
1810
}
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