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

SRI-CSL / yices2 / 25567506028

08 May 2026 04:40PM UTC coverage: 67.254% (+0.03%) from 67.22%
25567506028

Pull #607

github

web-flow
Merge branch 'master' into context_delegates
Pull Request #607: QF_BV context delegates (#453): config/param selection, incremental state, assumptions, and delegate regressions

105 of 353 new or added lines in 7 files covered. (29.75%)

4 existing lines in 3 files now uncovered.

85236 of 126737 relevant lines covered (67.25%)

1627700.56 hits per line

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

57.7
/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) {
635,113✔
279
    // reduce heuristic
280
    if (num_learned_clauses(core) >= r_threshold) {
614,262✔
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) {
614,262✔
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);
614,260✔
298
    if (l == null_literal) {
614,260✔
299
      // all variables assigned: call final check
300
      smt_final_check(core);
22,631✔
301
    } else {
302
      // apply the branching heuristic
303
      l = branch(core, l);
591,629✔
304
      // propagation
305
      decide_literal(core, l);
591,629✔
306
      smt_process(core);
591,629✔
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) {
393,846✔
339
  if (bvar_has_atom(core, var_of(l))) {
393,846✔
340
    l =  core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
320,475✔
341
  }
342
  return l;
393,846✔
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
  bool selector_frames;
626
  uint64_t synced_mutation;
627
  uint32_t delegate_nvars;
628
  bvar_t next_selector_var;
629
  literal_t active_selector;
630
  ivector_t assumptions;
631
  ivector_t failed;
632
} delegate_state_t;
633

634
static const char *delegate_name(sat_delegate_t mode) {
2,643✔
635
  switch (mode) {
2,643✔
636
  case SAT_DELEGATE_Y2SAT:
1✔
637
    return "y2sat";
1✔
NEW
638
  case SAT_DELEGATE_CADICAL:
×
NEW
639
    return "cadical";
×
NEW
640
  case SAT_DELEGATE_CRYPTOMINISAT:
×
NEW
641
    return "cryptominisat";
×
NEW
642
  case SAT_DELEGATE_KISSAT:
×
NEW
643
    return "kissat";
×
644
  case SAT_DELEGATE_NONE:
2,642✔
645
  default:
646
    return NULL;
2,642✔
647
  }
648
}
649

650
static sat_delegate_t effective_delegate_mode(const context_t *ctx, const param_t *params, bool *one_shot) {
2,643✔
651
  sat_delegate_t req, cfg;
652

653
  req = SAT_DELEGATE_NONE;
2,643✔
654
  if (params != NULL) {
2,643✔
655
    req = params->delegate;
2,643✔
656
  }
657
  cfg = ctx->sat_delegate;
2,643✔
658

659
  if (req != SAT_DELEGATE_NONE) {
2,643✔
NEW
660
    if (one_shot != NULL) {
×
NEW
661
      *one_shot = (req != cfg || cfg == SAT_DELEGATE_NONE);
×
662
    }
NEW
663
    return req;
×
664
  }
665

666
  if (one_shot != NULL) {
2,643✔
667
    *one_shot = false;
2,643✔
668
  }
669
  return cfg;
2,643✔
670
}
671

672
void context_delegate_state_cleanup(context_t *ctx) {
22,314✔
673
  delegate_state_t *st;
674

675
  st = (delegate_state_t *) ctx->delegate_state;
22,314✔
676
  if (st == NULL) {
22,314✔
677
    return;
22,314✔
678
  }
679

NEW
680
  if (st->live) {
×
NEW
681
    delete_delegate(&st->delegate);
×
NEW
682
    st->live = false;
×
683
  }
NEW
684
  delete_ivector(&st->assumptions);
×
NEW
685
  delete_ivector(&st->failed);
×
NEW
686
  safe_free(st);
×
NEW
687
  ctx->delegate_state = NULL;
×
688
}
689

NEW
690
static delegate_state_t *context_get_delegate_state(context_t *ctx) {
×
691
  delegate_state_t *st;
692

NEW
693
  st = (delegate_state_t *) ctx->delegate_state;
×
NEW
694
  if (st == NULL) {
×
NEW
695
    st = (delegate_state_t *) safe_malloc(sizeof(delegate_state_t));
×
NEW
696
    st->mode = SAT_DELEGATE_NONE;
×
NEW
697
    st->live = false;
×
NEW
698
    st->selector_frames = false;
×
NEW
699
    st->synced_mutation = 0;
×
NEW
700
    st->delegate_nvars = 0;
×
NEW
701
    st->next_selector_var = 0;
×
NEW
702
    st->active_selector = true_literal;
×
NEW
703
    init_ivector(&st->assumptions, 0);
×
NEW
704
    init_ivector(&st->failed, 0);
×
NEW
705
    ctx->delegate_state = st;
×
706
  }
NEW
707
  return st;
×
708
}
709

NEW
710
static void context_import_delegate_model(smt_core_t *core, delegate_t *d) {
×
711
  bvar_t x;
712

NEW
713
  for (x=0; x<num_vars(core); x++) {
×
NEW
714
    set_bvar_value(core, x, delegate_get_value(d, x));
×
715
  }
NEW
716
}
×
717

NEW
718
static void set_delegate_assumption_state(smt_core_t *core, uint32_t n, const literal_t *assumptions,
×
719
                                          smt_status_t stat, const ivector_t *failed) {
NEW
720
  if (n == 0) {
×
NEW
721
    core->has_assumptions = false;
×
NEW
722
    core->num_assumptions = 0;
×
NEW
723
    core->assumption_index = 0;
×
NEW
724
    core->assumptions = NULL;
×
NEW
725
    core->bad_assumption = null_literal;
×
NEW
726
    return;
×
727
  }
728

NEW
729
  core->has_assumptions = true;
×
NEW
730
  core->num_assumptions = n;
×
NEW
731
  core->assumption_index = n;
×
NEW
732
  core->assumptions = assumptions;
×
NEW
733
  core->bad_assumption = null_literal;
×
734

NEW
735
  if (stat == YICES_STATUS_UNSAT && failed != NULL && failed->size > 0) {
×
NEW
736
    core->bad_assumption = failed->data[0];
×
737
  }
738
}
739

NEW
740
static bool context_prepare_incremental_delegate(context_t *ctx, delegate_state_t *st, const char *sat_solver,
×
741
                                                 uint32_t verbosity, bool selector_frames) {
742
  sat_delegate_t mode;
743
  smt_core_t *core;
744
  uint32_t nvars;
745
  literal_t guard;
746
  uint32_t nnew;
747

NEW
748
  core = ctx->core;
×
NEW
749
  nvars = num_vars(core);
×
NEW
750
  mode = effective_delegate_mode(ctx, NULL, NULL);
×
751
  (void) mode;
752

NEW
753
  if (st->live &&
×
NEW
754
      (st->mode != ctx->sat_delegate ||
×
NEW
755
       st->selector_frames != selector_frames)) {
×
NEW
756
    delete_delegate(&st->delegate);
×
NEW
757
    st->live = false;
×
758
  }
759

NEW
760
  if (!st->live) {
×
NEW
761
    if (!init_delegate(&st->delegate, sat_solver, nvars)) {
×
NEW
762
      return false;
×
763
    }
NEW
764
    delegate_set_verbosity(&st->delegate, verbosity);
×
NEW
765
    st->mode = ctx->sat_delegate;
×
NEW
766
    st->selector_frames = selector_frames;
×
NEW
767
    st->synced_mutation = 0;
×
NEW
768
    st->delegate_nvars = nvars;
×
NEW
769
    st->next_selector_var = nvars;
×
NEW
770
    st->active_selector = true_literal;
×
NEW
771
    st->live = true;
×
772
  }
773

NEW
774
  if (st->selector_frames && st->delegate_nvars < nvars) {
×
NEW
775
    nnew = nvars - st->delegate_nvars;
×
NEW
776
    delegate_add_vars(&st->delegate, nnew);
×
NEW
777
    st->delegate_nvars = nvars;
×
778
  }
779

NEW
780
  if (st->synced_mutation != ctx->mutation_count) {
×
NEW
781
    if (st->selector_frames) {
×
NEW
782
      if (st->next_selector_var >= st->delegate_nvars) {
×
NEW
783
        nnew = st->next_selector_var - st->delegate_nvars + 1;
×
NEW
784
        delegate_add_vars(&st->delegate, nnew);
×
NEW
785
        st->delegate_nvars += nnew;
×
786
      }
NEW
787
      guard = neg_lit(st->next_selector_var);
×
NEW
788
      add_problem_clauses_to_delegate(&st->delegate, core, guard);
×
NEW
789
      st->active_selector = pos_lit(st->next_selector_var);
×
NEW
790
      st->next_selector_var ++;
×
791
    } else {
NEW
792
      delete_delegate(&st->delegate);
×
NEW
793
      st->live = false;
×
NEW
794
      if (!init_delegate(&st->delegate, sat_solver, nvars)) {
×
NEW
795
        return false;
×
796
      }
NEW
797
      delegate_set_verbosity(&st->delegate, verbosity);
×
NEW
798
      add_problem_clauses_to_delegate(&st->delegate, core, true_literal);
×
NEW
799
      st->mode = ctx->sat_delegate;
×
NEW
800
      st->delegate_nvars = nvars;
×
NEW
801
      st->next_selector_var = nvars;
×
NEW
802
      st->active_selector = true_literal;
×
NEW
803
      st->live = true;
×
804
    }
NEW
805
    st->synced_mutation = ctx->mutation_count;
×
806
  }
807

NEW
808
  return true;
×
809
}
810

NEW
811
smt_status_t check_with_incremental_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
812
                                             bool selector_frames, uint32_t n, const literal_t *assumptions,
813
                                             ivector_t *failed) {
814
  smt_status_t stat;
815
  smt_core_t *core;
816
  delegate_state_t *st;
817
  uint32_t i;
818

NEW
819
  core = ctx->core;
×
NEW
820
  stat = smt_status(core);
×
NEW
821
  if (stat != YICES_STATUS_IDLE) {
×
NEW
822
    return stat;
×
823
  }
824

NEW
825
  start_search(core, 0, NULL);
×
NEW
826
  smt_process(core);
×
NEW
827
  stat = smt_status(core);
×
828

829
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
830
         stat == YICES_STATUS_INTERRUPTED);
831

NEW
832
  if (stat != YICES_STATUS_SEARCHING) {
×
NEW
833
    return stat;
×
834
  }
835

NEW
836
  if (n == 0 && smt_easy_sat(core)) {
×
NEW
837
    stat = YICES_STATUS_SAT;
×
NEW
838
    set_smt_status(core, stat);
×
NEW
839
    return stat;
×
840
  }
841

NEW
842
  st = context_get_delegate_state(ctx);
×
NEW
843
  if (!context_prepare_incremental_delegate(ctx, st, sat_solver, verbosity, selector_frames)) {
×
NEW
844
    return YICES_STATUS_UNKNOWN;
×
845
  }
846

NEW
847
  ivector_reset(&st->assumptions);
×
NEW
848
  if (st->selector_frames && st->active_selector != true_literal) {
×
NEW
849
    ivector_push(&st->assumptions, st->active_selector);
×
850
  }
NEW
851
  for (i=0; i<n; i++) {
×
NEW
852
    ivector_push(&st->assumptions, assumptions[i]);
×
853
  }
854

NEW
855
  if (st->assumptions.size == 0) {
×
NEW
856
    stat = st->delegate.check(st->delegate.solver);
×
NEW
857
  } else if (delegate_supports_assumptions(&st->delegate)) {
×
NEW
858
    stat = delegate_check_with_assumptions(&st->delegate, st->assumptions.size,
×
NEW
859
                                           (literal_t *) st->assumptions.data, &st->failed);
×
NEW
860
    if (stat == YICES_STATUS_UNSAT && failed != NULL) {
×
NEW
861
      ivector_reset(failed);
×
NEW
862
      for (i=0; i<st->failed.size; i++) {
×
NEW
863
        literal_t l = st->failed.data[i];
×
NEW
864
        if (l != st->active_selector) {
×
NEW
865
          ivector_push(failed, l);
×
866
        }
867
      }
868
    }
869
  } else {
NEW
870
    stat = YICES_STATUS_UNKNOWN;
×
871
  }
872

NEW
873
  set_smt_status(core, stat);
×
NEW
874
  set_delegate_assumption_state(core, n, assumptions, stat, &st->failed);
×
NEW
875
  if (stat == YICES_STATUS_SAT) {
×
NEW
876
    context_import_delegate_model(core, &st->delegate);
×
877
  }
878

NEW
879
  return stat;
×
880
}
881

882
/*
883
 * Explore term t and collect all Boolean atoms into atoms.
884
 */
885
static void collect_boolean_atoms(context_t *ctx, term_t t, int_hset_t *atoms, int_hset_t *visited) {
64✔
886
  term_table_t *terms;
887
  uint32_t i, nchildren;
888

889
  if (t < 0) {
64✔
890
    t = not(t);
×
891
  }
892

893
  if (int_hset_member(visited, t)) {
64✔
894
    return;
×
895
  }
896
  int_hset_add(visited, t);
64✔
897

898
  terms = ctx->terms;
64✔
899
  if (term_type(terms, t) == bool_type(terms->types)) {
64✔
900
    int_hset_add(atoms, t);
64✔
901
  }
902

903
  if (term_is_projection(terms, t)) {
64✔
904
    collect_boolean_atoms(ctx, proj_term_arg(terms, t), atoms, visited);
×
905
  } else if (term_is_sum(terms, t)) {
64✔
906
    nchildren = term_num_children(terms, t);
×
907
    for (i=0; i<nchildren; i++) {
×
908
      term_t child;
909
      mpq_t q;
910
      mpq_init(q);
×
911
      sum_term_component(terms, t, i, q, &child);
×
912
      collect_boolean_atoms(ctx, child, atoms, visited);
×
913
      mpq_clear(q);
×
914
    }
915
  } else if (term_is_bvsum(terms, t)) {
64✔
916
    uint32_t nbits = term_bitsize(terms, t);
×
917
    int32_t *aux = (int32_t*) safe_malloc(nbits * sizeof(int32_t));
×
918
    nchildren = term_num_children(terms, t);
×
919
    for (i=0; i<nchildren; i++) {
×
920
      term_t child;
921
      bvsum_term_component(terms, t, i, aux, &child);
×
922
      collect_boolean_atoms(ctx, child, atoms, visited);
×
923
    }
924
    safe_free(aux);
×
925
  } else if (term_is_product(terms, t)) {
64✔
926
    nchildren = term_num_children(terms, t);
×
927
    for (i=0; i<nchildren; i++) {
×
928
      term_t child;
929
      uint32_t exp;
930
      product_term_component(terms, t, i, &child, &exp);
×
931
      collect_boolean_atoms(ctx, child, atoms, visited);
×
932
    }
933
  } else if (term_is_composite(terms, t)) {
64✔
934
    nchildren = term_num_children(terms, t);
34✔
935
    for (i=0; i<nchildren; i++) {
89✔
936
      collect_boolean_atoms(ctx, term_child(terms, t, i), atoms, visited);
55✔
937
    }
938
  }
939
}
940

941
/*
942
 * Extract assumptions whose labels appear in term t.
943
 */
944
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✔
945
  int_hset_t atoms, visited;
946
  uint32_t i;
947

948
  init_int_hset(&atoms, 0);
9✔
949
  init_int_hset(&visited, 0);
9✔
950
  collect_boolean_atoms(ctx, t, &atoms, &visited);
9✔
951

952
  ivector_reset(core);
9✔
953
  for (i=0; i<labels->size; i++) {
83✔
954
    term_t label = labels->data[i];
74✔
955
    if (int_hset_member(&atoms, label)) {
74✔
956
      int_hmap_pair_t *p = int_hmap_find((int_hmap_t *) label_map, label);
30✔
957
      if (p != NULL) {
30✔
958
        ivector_push(core, p->val);
30✔
959
      }
960
    }
961
  }
962

963
  delete_int_hset(&visited);
9✔
964
  delete_int_hset(&atoms);
9✔
965
}
9✔
966

967
/*
968
 * Cache a core vector in the context.
969
 */
970
static void cache_unsat_core(context_t *ctx, const ivector_t *core) {
2,708✔
971
  if (ctx->unsat_core_cache == NULL) {
2,708✔
972
    ctx->unsat_core_cache = (ivector_t *) safe_malloc(sizeof(ivector_t));
2,708✔
973
    init_ivector(ctx->unsat_core_cache, core->size);
2,708✔
974
  } else {
975
    ivector_reset(ctx->unsat_core_cache);
×
976
  }
977
  ivector_copy(ctx->unsat_core_cache, core->data, core->size);
2,708✔
978
}
2,708✔
979

NEW
980
static void cache_failed_assumptions_core(context_t *ctx, uint32_t n, const term_t *a,
×
981
                                          const ivector_t *assumption_literals,
982
                                          const ivector_t *failed_literals) {
983
  ivector_t core_terms;
984
  int_hset_t failed;
985
  uint32_t i;
986

NEW
987
  init_ivector(&core_terms, 0);
×
NEW
988
  init_int_hset(&failed, 0);
×
NEW
989
  for (i=0; i<failed_literals->size; i++) {
×
NEW
990
    int_hset_add(&failed, failed_literals->data[i]);
×
991
  }
NEW
992
  for (i=0; i<n; i++) {
×
NEW
993
    if (int_hset_member(&failed, assumption_literals->data[i])) {
×
NEW
994
      ivector_push(&core_terms, a[i]);
×
995
    }
996
  }
NEW
997
  cache_unsat_core(ctx, &core_terms);
×
NEW
998
  delete_int_hset(&failed);
×
NEW
999
  delete_ivector(&core_terms);
×
NEW
1000
}
×
1001

1002
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
1003
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed);
1004

1005
/*
1006
 * MCSAT variant of check_context_with_term_assumptions.
1007
 * Caller must hold __yices_globals.lock.
1008
 */
1009
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✔
1010
  smt_status_t stat;
1011
  ivector_t assumptions;
1012
  uint32_t i;
1013

1014
  /*
1015
   * MCSAT: create fresh labels b_i, assert (b_i => a_i), then solve with model b_i=true.
1016
   * We extract interpolant/core before cleanup, then restore sticky UNSAT artifacts.
1017
   */
1018
  if (!context_supports_model_interpolation(ctx)) {
10✔
1019
    if (error != NULL) {
×
1020
      *error = CTX_OPERATION_NOT_SUPPORTED;
×
1021
    }
1022
    return YICES_STATUS_ERROR;
×
1023
  }
1024

1025
  {
1026
    model_t mdl;               // temporary model: sets all label terms b_i to true
1027
    int_hmap_t label_map;      // map label b_i -> original assumption a_i
1028
    ivector_t mapped_core;     // translated core over original assumptions
1029
    term_t interpolant = NULL_TERM; // raw/substituted interpolant for sticky UNSAT result
10✔
1030
    int32_t code;              // return code from assert_formula (negative on internalization error)
1031
    bool pushed;               // whether we pushed a temporary scope and must pop it
1032
    term_manager_t tm;
1033

1034
    init_model(&mdl, ctx->terms, true);
10✔
1035
    init_int_hmap(&label_map, 0);
10✔
1036
    init_ivector(&assumptions, n);
10✔
1037
    init_ivector(&mapped_core, 0);
10✔
1038
    init_term_manager(&tm, ctx->terms);
10✔
1039
    stat = YICES_STATUS_IDLE;
10✔
1040

1041
    pushed = false;
10✔
1042
    if (context_supports_pushpop(ctx)) {
10✔
1043
      context_push(ctx);
9✔
1044
      pushed = true;
9✔
1045
    }
1046

1047
    for (i=0; i<n; i++) {
85✔
1048
      term_t b = new_uninterpreted_term(ctx->terms, bool_id);
75✔
1049
      term_t implication = mk_implies(&tm, b, a[i]);
75✔
1050

1051
      int_hmap_add(&label_map, b, a[i]);
75✔
1052
      code = _o_assert_formula(ctx, implication);
75✔
1053
      if (code < 0) {
75✔
1054
        if (error != NULL) {
×
1055
          *error = code;
×
1056
        }
1057
        stat = YICES_STATUS_ERROR;
×
1058
        break;
×
1059
      }
1060
      model_map_term(&mdl, b, vtbl_mk_bool(&mdl.vtbl, true));
75✔
1061
      ivector_push(&assumptions, b);
75✔
1062
    }
1063

1064
    if (stat != YICES_STATUS_ERROR) {
10✔
1065
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
10✔
1066
      if (stat == YICES_STATUS_UNSAT) {
10✔
1067
        interpolant = context_get_unsat_model_interpolant(ctx);
9✔
1068
        assert(interpolant != NULL_TERM);
1069
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
9✔
1070
      }
1071
    }
1072

1073
    if (pushed) {
10✔
1074
      mcsat_cleanup_assumptions(ctx->mcsat);
9✔
1075
      context_pop(ctx);
9✔
1076
    }
1077
    if (stat == YICES_STATUS_UNSAT) {
10✔
1078
      mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, interpolant, n, assumptions.data, a);
9✔
1079
      cache_unsat_core(ctx, &mapped_core);
9✔
1080
    }
1081

1082
    delete_term_manager(&tm);
10✔
1083
    delete_ivector(&mapped_core);
10✔
1084
    delete_ivector(&assumptions);
10✔
1085
    delete_int_hmap(&label_map);
10✔
1086
    delete_model(&mdl);
10✔
1087

1088
    return stat;
10✔
1089
  }
1090
}
1091

1092
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✔
1093
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
10✔
1094
}
1095

1096
/*
1097
 * Check under assumptions given as terms.
1098
 * - if MCSAT is enabled, this uses temporary labels + model interpolation.
1099
 * - otherwise terms are converted to literals and handled by the CDCL(T) path.
1100
 *
1101
 * Preconditions:
1102
 * - context status must be IDLE.
1103
 */
1104
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✔
1105
  if (error != NULL) {
2,653✔
1106
    *error = CTX_NO_ERROR;
2,653✔
1107
  }
1108

1109
  context_invalidate_unsat_core_cache(ctx);
2,653✔
1110

1111
  if (ctx->mcsat == NULL) {
2,653✔
1112
    smt_status_t stat;
1113
    sat_delegate_t mode;
1114
    bool one_shot;
1115
    const char *delegate;
1116
    bool unknown;
1117
    ivector_t assumptions;
1118
    ivector_t failed;
1119
    uint32_t i;
1120
    literal_t l;
1121

1122
    init_ivector(&assumptions, n);
2,643✔
1123
    for (i=0; i<n; i++) {
90,110✔
1124
      l = context_add_assumption(ctx, a[i]);
87,467✔
1125
      if (l < 0) {
87,467✔
1126
        if (error != NULL) {
×
1127
          *error = l;
×
1128
        }
1129
        delete_ivector(&assumptions);
×
1130
        return YICES_STATUS_ERROR;
×
1131
      }
1132
      ivector_push(&assumptions, l);
87,467✔
1133
    }
1134

1135
    mode = effective_delegate_mode(ctx, params, &one_shot);
2,643✔
1136
    delegate = delegate_name(mode);
2,643✔
1137
    if (delegate == NULL) {
2,643✔
1138
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,642✔
1139
      delete_ivector(&assumptions);
2,642✔
1140
      return stat;
2,642✔
1141
    }
1142

1143
    if (ctx->logic != QF_BV) {
1✔
NEW
1144
      if (error != NULL) {
×
NEW
1145
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1146
      }
NEW
1147
      delete_ivector(&assumptions);
×
NEW
1148
      return YICES_STATUS_ERROR;
×
1149
    }
1150

1151
    if (!supported_delegate(delegate, &unknown)) {
1✔
NEW
1152
      if (error != NULL) {
×
NEW
1153
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1154
      }
NEW
1155
      delete_ivector(&assumptions);
×
NEW
1156
      return YICES_STATUS_ERROR;
×
1157
    }
1158

1159
    if (!incremental_delegate(delegate)) {
1✔
1160
      if (error != NULL) {
1✔
1161
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1162
      }
1163
      delete_ivector(&assumptions);
1✔
1164
      return YICES_STATUS_ERROR;
1✔
1165
    }
1166

NEW
1167
    init_ivector(&failed, 0);
×
NEW
1168
    if (one_shot) {
×
NEW
1169
      stat = check_with_delegate_assumptions(ctx, delegate, 0, n, assumptions.data, &failed);
×
1170
    } else {
NEW
1171
      stat = check_with_incremental_delegate(ctx, delegate, 0,
×
NEW
1172
                                             ctx->sat_delegate_selector_frames,
×
NEW
1173
                                             n, assumptions.data, &failed);
×
1174
    }
NEW
1175
    if (stat == YICES_STATUS_UNSAT) {
×
NEW
1176
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
×
1177
    }
NEW
1178
    delete_ivector(&failed);
×
UNCOV
1179
    delete_ivector(&assumptions);
×
UNCOV
1180
    return stat;
×
1181
  }
1182

1183
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1184
}
1185

1186
/*
1187
 * Check with given model
1188
 * - if mcsat status is not IDLE, return the status
1189
 */
1190
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✔
1191
  smt_status_t stat;
1192

1193
  assert(ctx->mcsat != NULL);
1194

1195
  stat = mcsat_status(ctx->mcsat);
161✔
1196
  if (stat == YICES_STATUS_IDLE) {
161✔
1197
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
161✔
1198
    stat = mcsat_status(ctx->mcsat);
161✔
1199

1200
    // BD: this looks wrong. We shouldn't call clear yet.
1201
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1202
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1203
    //      context_clear(ctx);
1204
    //    }
1205
  }
1206

1207
  return stat;
161✔
1208
}
1209

1210
/*
1211
 * Check with given model and hints
1212
 * - set the model hint and call check_context_with_model
1213
 */
1214
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✔
1215
  assert(m <= n);
1216

1217
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1218

1219
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1220
}
1221

1222

1223
/*
1224
 * Precheck: force generation of clauses and other stuff that's
1225
 * constructed lazily by the solvers. For example, this
1226
 * can be used to convert all the constraints asserted in the
1227
 * bitvector to clauses so that we can export the result to DIMACS.
1228
 *
1229
 * If ctx status is IDLE:
1230
 * - the function calls 'start_search' and does one round of propagation.
1231
 * - if this results in UNSAT, the function returns UNSAT
1232
 * - if the precheck is interrupted, the function returns INTERRUPTED
1233
 * - otherwise the function returns UNKNOWN and sets the status to
1234
 *   UNKNOWN.
1235
 *
1236
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
1237
 * IDLE before doing anything else with this context.
1238
 *
1239
 * If ctx status is not IDLE, the function returns it and does nothing
1240
 * else.
1241
 */
1242
smt_status_t precheck_context(context_t *ctx) {
×
1243
  smt_status_t stat;
1244
  smt_core_t *core;
1245

1246
  core = ctx->core;
×
1247

1248
  stat = smt_status(core);
×
1249
  if (stat == YICES_STATUS_IDLE) {
×
1250
    start_search(core, 0, NULL);
×
1251
    smt_process(core);
×
1252
    stat = smt_status(core);
×
1253

1254
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1255
           stat == YICES_STATUS_INTERRUPTED);
1256

1257
    if (stat == YICES_STATUS_SEARCHING) {
×
1258
      end_search_unknown(core);
×
1259
      stat = YICES_STATUS_UNKNOWN;
×
1260
    }
1261
  }
1262

1263
  return stat;
×
1264
}
1265

1266

1267

1268
/*
1269
 * Solve using another SAT solver
1270
 * - sat_solver = name of the solver to use
1271
 * - verbosity = verbosity level (0 means quiet)
1272
 * - this may be used only for BV or pure SAT problems
1273
 * - we perform one round of propagation to convert the problem to CNF
1274
 * - then we call an external SAT solver on the CNF problem
1275
 */
1276
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
16✔
1277
  smt_status_t stat;
1278
  smt_core_t *core;
1279
  delegate_t delegate;
1280
  bvar_t x;
1281
  bval_t v;
1282

1283
  core = ctx->core;
16✔
1284

1285
  stat = smt_status(core);
16✔
1286
  if (stat == YICES_STATUS_IDLE) {
16✔
1287
    start_search(core, 0, NULL);
16✔
1288
    smt_process(core);
16✔
1289
    stat = smt_status(core);
16✔
1290

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

1294
    if (stat == YICES_STATUS_SEARCHING) {
16✔
1295
      if (smt_easy_sat(core)) {
15✔
1296
        stat = YICES_STATUS_SAT;
15✔
1297
      } else {
1298
        // call the delegate
1299
        init_delegate(&delegate, sat_solver, num_vars(core));
×
1300
        delegate_set_verbosity(&delegate, verbosity);
×
1301

1302
        stat = solve_with_delegate(&delegate, core);
×
1303
        set_smt_status(core, stat);
×
1304
        if (stat == YICES_STATUS_SAT) {
×
1305
          for (x=0; x<num_vars(core); x++) {
×
1306
            v = delegate_get_value(&delegate, x);
×
1307
            set_bvar_value(core, x, v);
×
1308
          }
1309
        }
1310
        delete_delegate(&delegate);
×
1311
      }
1312
    }
1313
  }
1314

1315
  return stat;
16✔
1316
}
1317

1318
/*
1319
 * One-shot check with delegate and assumptions.
1320
 * - assumptions are literals in core encoding.
1321
 * - if failed != NULL and result is UNSAT, failed assumptions are appended to *failed.
1322
 */
NEW
1323
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
1324
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1325
  smt_status_t stat;
1326
  smt_core_t *core;
1327
  delegate_t delegate;
1328

NEW
1329
  core = ctx->core;
×
1330

NEW
1331
  stat = smt_status(core);
×
NEW
1332
  if (stat != YICES_STATUS_IDLE) {
×
NEW
1333
    return stat;
×
1334
  }
1335

NEW
1336
  start_search(core, 0, NULL);
×
NEW
1337
  smt_process(core);
×
NEW
1338
  stat = smt_status(core);
×
1339

1340
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1341
         stat == YICES_STATUS_INTERRUPTED);
1342

NEW
1343
  if (stat != YICES_STATUS_SEARCHING) {
×
NEW
1344
    return stat;
×
1345
  }
1346

NEW
1347
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
NEW
1348
    return YICES_STATUS_UNKNOWN;
×
1349
  }
NEW
1350
  delegate_set_verbosity(&delegate, verbosity);
×
1351

NEW
1352
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
NEW
1353
  set_smt_status(core, stat);
×
NEW
1354
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
NEW
1355
  if (stat == YICES_STATUS_SAT) {
×
NEW
1356
    context_import_delegate_model(core, &delegate);
×
1357
  }
1358

NEW
1359
  delete_delegate(&delegate);
×
NEW
1360
  return stat;
×
1361
}
1362

1363

1364
/*
1365
 * Bit-blast then export to DIMACS
1366
 * - filename = name of the output file
1367
 * - status = status of the context after bit-blasting
1368
 *
1369
 * If ctx status is IDLE
1370
 * - perform one round of propagation to conver the problem to CNF
1371
 * - export the CNF to DIMACS
1372
 *
1373
 * If ctx status is not IDLE,
1374
 * - store the stauts in *status and do nothing else
1375
 *
1376
 * Return code:
1377
 *  1 if the DIMACS file was created
1378
 *  0 if the problem was solved by the propagation round
1379
 * -1 if there was an error in creating or writing to the file.
1380
 */
1381
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1382
  smt_core_t *core;
1383
  FILE *f;
1384
  smt_status_t stat;
1385
  int32_t code;
1386

1387
  core = ctx->core;
×
1388

1389
  code = 0;
×
1390
  stat = smt_status(core);
×
1391
  if (stat == YICES_STATUS_IDLE) {
×
1392
    start_search(core, 0, NULL);
×
1393
    smt_process(core);
×
1394
    stat = smt_status(core);
×
1395

1396
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1397
           stat == YICES_STATUS_INTERRUPTED);
1398

1399
    if (stat == YICES_STATUS_SEARCHING) {
×
1400
      code = 1;
×
1401
      f = fopen(filename, "w");
×
1402
      if (f == NULL) {
×
1403
        code = -1;
×
1404
      } else {
1405
        dimacs_print_bvcontext(f, ctx);
×
1406
        if (ferror(f)) code = -1;
×
1407
        fclose(f);
×
1408
      }
1409
    }
1410
  }
1411

1412
  *status = stat;
×
1413

1414
  return code;
×
1415
}
1416

1417

1418
/*
1419
 * Simplify then export to Dimacs:
1420
 * - filename = name of the output file
1421
 * - status = status of the context after CNF conversion + preprocessing
1422
 *
1423
 * If ctx status is IDLE
1424
 * - perform one round of propagation to convert the problem to CNF
1425
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
1426
 *
1427
 * If ctx status is not IDLE, the function stores that in *status
1428
 * If y2sat preprocessing solves the formula, return the status also in *status
1429
 *
1430
 * Return code:
1431
 *  1 if the DIMACS file was created
1432
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
1433
 * -1 if there was an error creating or writing to the file.
1434
 */
1435
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1436
  smt_core_t *core;
1437
  FILE *f;
1438
  smt_status_t stat;
1439
  delegate_t delegate;
1440
  bvar_t x;
1441
  bval_t v;
1442
  int32_t code;
1443

1444
  core = ctx->core;
×
1445

1446
  code = 0;
×
1447
  stat = smt_status(core);
×
1448
  if (stat == YICES_STATUS_IDLE) {
×
1449
    start_search(core, 0, NULL);
×
1450
    smt_process(core);
×
1451
    stat = smt_status(core);
×
1452

1453
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1454
           stat == YICES_STATUS_INTERRUPTED);
1455

1456
    if (stat == YICES_STATUS_SEARCHING) {
×
1457
      if (smt_easy_sat(core)) {
×
1458
        stat = YICES_STATUS_SAT;
×
1459
      } else {
1460
        // call the delegate
1461
        init_delegate(&delegate, "y2sat", num_vars(core));
×
1462
        delegate_set_verbosity(&delegate, 0);
×
1463

1464
        stat = preprocess_with_delegate(&delegate, core);
×
1465
        set_smt_status(core, stat);
×
1466
        if (stat == YICES_STATUS_SAT) {
×
1467
          for (x=0; x<num_vars(core); x++) {
×
1468
            v = delegate_get_value(&delegate, x);
×
1469
            set_bvar_value(core, x, v);
×
1470
          }
1471
        } else if (stat == YICES_STATUS_UNKNOWN) {
×
1472
          code = 1;
×
1473
          f = fopen(filename, "w");
×
1474
          if (f == NULL) {
×
1475
            code = -1;
×
1476
          } else {
1477
            export_to_dimacs_with_delegate(&delegate, f);
×
1478
            if (ferror(f)) code = -1;
×
1479
            fclose(f);
×
1480
          }
1481
        }
1482

1483
        delete_delegate(&delegate);
×
1484
      }
1485
    }
1486
  }
1487

1488
  *status = stat;
×
1489

1490
  return code;
×
1491
}
1492

1493

1494

1495
/*
1496
 * MODEL CONSTRUCTION
1497
 */
1498

1499
/*
1500
 * Value of literal l in ctx->core
1501
 */
1502
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
1503
  value_t v;
1504

1505
  v = null_value; // prevent GCC warning
65,201✔
1506
  switch (literal_value(ctx->core, l)) {
65,201✔
1507
  case VAL_FALSE:
38,577✔
1508
    v = vtbl_mk_false(vtbl);
38,577✔
1509
    break;
38,577✔
1510
  case VAL_UNDEF_FALSE:
×
1511
  case VAL_UNDEF_TRUE:
1512
    v = vtbl_mk_unknown(vtbl);
×
1513
    break;
×
1514
  case VAL_TRUE:
26,624✔
1515
    v = vtbl_mk_true(vtbl);
26,624✔
1516
    break;
26,624✔
1517
  }
1518
  return v;
65,201✔
1519
}
1520

1521

1522
/*
1523
 * Value of arithmetic variable x in ctx->arith_solver
1524
 */
1525
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,590✔
1526
  rational_t *a;
1527
  value_t v;
1528

1529
  assert(context_has_arith_solver(ctx));
1530

1531
  a = &ctx->aux;
22,590✔
1532
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,590✔
1533
    v = vtbl_mk_rational(vtbl, a);
22,590✔
1534
  } else {
1535
    v = vtbl_mk_unknown(vtbl);
×
1536
  }
1537

1538
  return v;
22,590✔
1539
}
1540

1541

1542

1543
/*
1544
 * Value of bitvector variable x in ctx->bv_solver
1545
 */
1546
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,141✔
1547
  bvconstant_t *b;
1548
  value_t v;
1549

1550
  assert(context_has_bv_solver(ctx));
1551

1552
  b = &ctx->bv_buffer;
18,141✔
1553
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,141✔
1554
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,141✔
1555
  } else {
1556
    v = vtbl_mk_unknown(vtbl);
×
1557
  }
1558

1559
  return v;
18,141✔
1560
}
1561

1562

1563
/*
1564
 * Get a value for term t in the solvers or egraph
1565
 * - attach the mapping from t to that value in model
1566
 * - if we don't have a concrete object for t but t is
1567
 *   mapped to a term u and the model->has_alias is true,
1568
 *   then we store the mapping [t --> u] in the model's
1569
 *   alias map.
1570
 */
1571
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
319,875✔
1572
  value_table_t *vtbl;
1573
  term_t r;
1574
  uint32_t polarity;
1575
  int32_t x;
1576
  type_t tau;
1577
  value_t v;
1578

1579
  /*
1580
   * Get the root of t in the substitution table
1581
   */
1582
  r = intern_tbl_get_root(&ctx->intern, t);
319,875✔
1583
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
319,875✔
1584
    /*
1585
     * r is mapped to some object x in egraph/core/or theory solvers
1586
     * - keep track of polarity then force r to positive polarity
1587
     */
1588
    vtbl = model_get_vtbl(model);
110,706✔
1589
    polarity = polarity_of(r);
110,706✔
1590
    r = unsigned_term(r);
110,706✔
1591

1592
    /*
1593
     * Convert x to a concrete value
1594
     */
1595
    x = intern_tbl_map_of_root(&ctx->intern, r);
110,706✔
1596
    if (code_is_eterm(x)) {
110,706✔
1597
      // x refers to an egraph object or true_occ/false_occ
1598
      if (x == bool2code(true)) {
4,774✔
1599
        v = vtbl_mk_true(vtbl);
475✔
1600
      } else if (x == bool2code(false)) {
4,299✔
1601
        v = vtbl_mk_false(vtbl);
1,420✔
1602
      } else {
1603
        assert(context_has_egraph(ctx));
1604
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,879✔
1605
      }
1606

1607
    } else {
1608
      // x refers to a literal or a theory variable
1609
      tau = term_type(ctx->terms, r);
105,932✔
1610
      switch (type_kind(ctx->types, tau)) {
105,932✔
1611
      case BOOL_TYPE:
65,201✔
1612
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
1613
        break;
65,201✔
1614

1615
      case INT_TYPE:
22,590✔
1616
      case REAL_TYPE:
1617
        v = arith_value(ctx, vtbl, code2thvar(x));
22,590✔
1618
        break;
22,590✔
1619

1620
      case BITVECTOR_TYPE:
18,141✔
1621
        v = bv_value(ctx, vtbl, code2thvar(x));
18,141✔
1622
        break;
18,141✔
1623

1624
      default:
×
1625
        /*
1626
         * This should never happen:
1627
         * scalar, uninterpreted, tuple, function terms
1628
         * are mapped to egraph terms.
1629
         */
1630
        assert(false);
1631
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
1632
        break;
×
1633
      }
1634
    }
1635

1636
    /*
1637
     * Restore polarity then add mapping [t --> v] in the model
1638
     */
1639
    if (! object_is_unknown(vtbl, v)) {
110,706✔
1640
      if (object_is_boolean(vtbl, v)) {
110,706✔
1641
        if (polarity) {
67,096✔
1642
          // negate the value
1643
          v = vtbl_mk_not(vtbl, v);
24✔
1644
        }
1645
      }
1646
      model_map_term(model, t, v);
110,706✔
1647
    }
1648

1649
  } else {
1650
    /*
1651
     * r is not mapped to anything:
1652
     *
1653
     * 1) If t == r and t is present in the internalization table
1654
     *    then t is relevant. So we should display its value
1655
     *    when we print the model. To do this, we assign an
1656
     *    arbitrary value v to t and store [t := v] in the map.
1657
     *
1658
     * 2) If t != r then we keep the mapping [t --> r] in
1659
     *    the alias table (provided the model supports aliases).
1660
     */
1661
    if (t == r) {
209,169✔
1662
      if (intern_tbl_term_present(&ctx->intern, t)) {
208,519✔
1663
        tau = term_type(ctx->terms, t);
×
1664
        vtbl = model_get_vtbl(model);
×
1665
        v = vtbl_make_object(vtbl, tau);
×
1666
        model_map_term(model, t, v);
×
1667
      }
1668
    } else if (model->has_alias) {
650✔
1669
      // t != r: keep the substitution [t --> r] in the model
1670
      model_add_substitution(model, t, r);
650✔
1671
    }
1672
  }
1673
}
319,875✔
1674

1675

1676

1677

1678
/*
1679
 * Build a model for the current context (including all satellite solvers)
1680
 * - the context status must be SAT (or UNKNOWN)
1681
 * - if model->has_alias is true, we store the term substitution
1682
 *   defined by ctx->intern_tbl into the model
1683
 * - cleanup of satellite models needed using clean_solver_models()
1684
 */
1685
void build_model(model_t *model, context_t *ctx) {
42,152✔
1686
  term_table_t *terms;
1687
  uint32_t i, n;
1688
  term_t t;
1689

1690
  assert(smt_status(ctx->core) == YICES_STATUS_SAT || smt_status(ctx->core) == YICES_STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == YICES_STATUS_SAT);
1691

1692
  /*
1693
   * First build assignments in the satellite solvers
1694
   * and get the val_in_model functions for the egraph
1695
   */
1696
  if (context_has_arith_solver(ctx)) {
42,152✔
1697
    ctx->arith.build_model(ctx->arith_solver);
32,909✔
1698
  }
1699
  if (context_has_bv_solver(ctx)) {
42,152✔
1700
    ctx->bv.build_model(ctx->bv_solver);
21,409✔
1701
  }
1702

1703
  /*
1704
   * Construct the egraph model
1705
   */
1706
  if (context_has_egraph(ctx)) {
42,152✔
1707
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,035✔
1708
  }
1709

1710
  /*
1711
   * Construct the mcsat model.
1712
   */
1713
  if (context_has_mcsat(ctx)) {
42,152✔
1714
    mcsat_build_model(ctx->mcsat, model);
51✔
1715
  }
1716

1717
  // scan the internalization table
1718
  terms = ctx->terms;
42,152✔
1719
  n = intern_tbl_num_terms(&ctx->intern);
42,152✔
1720
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,096,241✔
1721
    if (good_term_idx(terms, i)) {
1,235,054,089✔
1722
      t = pos_occ(i);
1,235,054,089✔
1723
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,054,089✔
1724
        build_term_value(ctx, model, t);
319,875✔
1725
      }
1726
    }
1727
  }
1728
}
42,152✔
1729

1730

1731
/*
1732
 * Cleanup solver models
1733
 */
1734
void clean_solver_models(context_t *ctx) {
42,152✔
1735
  if (context_has_arith_solver(ctx)) {
42,152✔
1736
    ctx->arith.free_model(ctx->arith_solver);
32,909✔
1737
  }
1738
  if (context_has_bv_solver(ctx)) {
42,152✔
1739
    ctx->bv.free_model(ctx->bv_solver);
21,409✔
1740
  }
1741
  if (context_has_egraph(ctx)) {
42,152✔
1742
    egraph_free_model(ctx->egraph);
13,035✔
1743
  }
1744
}
42,152✔
1745

1746

1747

1748
/*
1749
 * Build a model for the current context
1750
 * - the context status must be SAT (or UNKNOWN)
1751
 * - if model->has_alias is true, we store the term substitution
1752
 *   defined by ctx->intern_tbl into the model
1753
 */
1754
void context_build_model(model_t *model, context_t *ctx) {
251✔
1755
  // Build solver models and term values
1756
  build_model(model, ctx);
251✔
1757

1758
  // Cleanup
1759
  clean_solver_models(ctx);
251✔
1760
}
251✔
1761

1762

1763

1764
/*
1765
 * Read the value of a Boolean term t
1766
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
1767
 */
1768
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
1769
  term_t r;
1770
  uint32_t polarity;
1771
  int32_t x;
1772
  bval_t v;
1773

1774
  assert(is_boolean_term(ctx->terms, t));
1775

1776
  // default value if t is not in the internalization table
1777
  v = VAL_UNDEF_FALSE;
×
1778
  r = intern_tbl_get_root(&ctx->intern, t);
×
1779
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
1780
    // r is mapped to some object x
1781
    polarity = polarity_of(r);
×
1782
    r = unsigned_term(r);
×
1783

1784
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
1785
    if (code_is_eterm(x)) {
×
1786
      // x must be either true_occ or false_occ
1787
      if (x == bool2code(true)) {
×
1788
        v = VAL_TRUE;
×
1789
      } else {
1790
        assert(x == bool2code(false));
1791
        v = VAL_FALSE;
×
1792
      }
1793
    } else {
1794
      // x refers to a literal in the smt core
1795
      v = literal_value(ctx->core, code2literal(x));
×
1796
    }
1797

1798
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
1799
    v ^= polarity;
×
1800
  }
1801

1802
  return v;
×
1803
}
1804

1805

1806
/*
1807
 * UNSAT CORE
1808
 */
1809

1810
/*
1811
 * Build an unsat core:
1812
 * - store the result in v
1813
 * - first reuse a cached term core if available.
1814
 * - otherwise:
1815
 *   CDCL(T): build from smt_core then cache as terms
1816
 *   MCSAT: return empty unless check-with-term-assumptions populated the cache.
1817
 */
1818
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
2,704✔
1819
  smt_core_t *core;
1820
  uint32_t i, n;
1821
  term_t t;
1822

1823
  if (ctx->unsat_core_cache != NULL) {
2,704✔
1824
    // Fast path: repeated get_unsat_core returns the cached term vector.
1825
    ivector_reset(v);
5✔
1826
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
5✔
1827
    return;
5✔
1828
  }
1829

1830
  if (ctx->mcsat != NULL) {
2,699✔
1831
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
1832
    // there is no generic context-level core structure to rebuild from here.
1833
    ivector_reset(v);
×
1834
    return;
×
1835
  }
1836

1837
  core = ctx->core;
2,699✔
1838
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
1839
  build_unsat_core(core, v);
2,699✔
1840

1841
  // convert from literals to terms
1842
  n = v->size;
2,699✔
1843
  for (i=0; i<n; i++) {
37,499✔
1844
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,800✔
1845
    assert(t >= 0);
1846
    v->data[i] = t;
34,800✔
1847
  }
1848

1849
  // Cache the converted term core for subsequent queries.
1850
  cache_unsat_core(ctx, v);
2,699✔
1851
}
1852

1853

1854
/*
1855
 * MODEL INTERPOLANT
1856
 */
1857
term_t context_get_unsat_model_interpolant(context_t *ctx) {
61✔
1858
  assert(ctx->mcsat != NULL);
1859
  return mcsat_get_unsat_model_interpolant(ctx->mcsat);
61✔
1860
}
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