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

SRI-CSL / yices2 / 25543525186

08 May 2026 07:38AM UTC coverage: 66.741% (+0.05%) from 66.687%
25543525186

Pull #607

github

disteph
Merge remote-tracking branch 'origin/context_delegates' 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.

83745 of 125478 relevant lines covered (66.74%)

1641484.41 hits per line

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

57.86
/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,220✔
60
  trace_printf(core->trace, level,
93,220✔
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,220✔
73

74
/*
75
 * On start_search
76
 */
77
static void trace_start(smt_core_t *core) {
45,366✔
78
  trace_stats(core, "start:", 1);
45,366✔
79
}
45,366✔
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,366✔
108
  trace_stats(core, "done:", 1);
45,366✔
109
  trace_newline(core->trace, 1);
45,366✔
110
}
45,366✔
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,436✔
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,436✔
162
  r_threshold = *reduce_threshold;
13,436✔
163

164
  smt_process(core);
13,436✔
165
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
6,297,752✔
166
    // reduce heuristic
167
    if (num_learned_clauses(core) >= r_threshold) {
6,284,316✔
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,316✔
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,313✔
185
    if (l == null_literal) {
6,284,313✔
186
      // all variables assigned: Call final_check
187
      smt_final_check(core);
16,599✔
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,436✔
195
}
13,436✔
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,626✔
279
    // reduce heuristic
280
    if (num_learned_clauses(core) >= r_threshold) {
612,775✔
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,775✔
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,773✔
298
    if (l == null_literal) {
612,773✔
299
      // all variables assigned: call final check
300
      smt_final_check(core);
22,624✔
301
    } else {
302
      // apply the branching heuristic
303
      l = branch(core, l);
590,149✔
304
      // propagation
305
      decide_literal(core, l);
590,149✔
306
      smt_process(core);
590,149✔
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,366✔
339
  if (bvar_has_atom(core, var_of(l))) {
392,366✔
340
    l =  core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
318,995✔
341
  }
342
  return l;
392,366✔
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,366✔
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,366✔
383
  d_threshold = c_threshold; // required by trace_start in slow_restart mode
45,366✔
384
  luby = false;
45,366✔
385
  u = 1;
45,366✔
386
  v = 1;
45,366✔
387
  period = c_threshold;
45,366✔
388

389
  if (params->fast_restart) {
45,366✔
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,366✔
397
  if (reduce_threshold < params->r_threshold) {
45,366✔
398
    reduce_threshold = params->r_threshold;
45,335✔
399
  }
400

401
  // initialize then do a propagation + simplification step.
402
  start_search(core, n, a);
45,366✔
403
  trace_start(core);
45,366✔
404
  if (smt_status(core) == YICES_STATUS_SEARCHING) {
45,366✔
405
    // loop
406
    for (;;) {
407
      switch (params->branching) {
47,676✔
408
      case BRANCHING_DEFAULT:
26,825✔
409
        if (luby) {
26,825✔
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,436✔
413
        }
414
        break;
26,825✔
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,676✔
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,366✔
471
}
45,366✔
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,366✔
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,366✔
488
  set_randomness(core, params->randomness);
45,366✔
489
  set_random_seed(core, params->random_seed);
45,366✔
490
  set_var_decay_factor(core, params->var_decay);
45,366✔
491
  set_clause_decay_factor(core, params->clause_decay);
45,366✔
492
  if (params->cache_tclauses) {
45,366✔
493
    enable_theory_cache(core, params->tclause_size);
33,670✔
494
  } else {
495
    disable_theory_cache(core);
11,696✔
496
  }
497

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

528
  /*
529
   * Set simplex parameters
530
   */
531
  if (context_has_simplex_solver(ctx)) {
45,366✔
532
    simplex = ctx->arith_solver;
33,232✔
533
    if (params->use_simplex_prop) {
33,232✔
534
      simplex_enable_propagation(simplex);
12,856✔
535
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,856✔
536
    }
537
    if (params->adjust_simplex_model) {
33,232✔
538
      simplex_enable_adjust_model(simplex);
12,810✔
539
    }
540
    simplex_set_bland_threshold(simplex, params->bland_threshold);
33,232✔
541
    if (params->integer_check) {
33,232✔
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,366✔
551
    fsolver = ctx->fun_solver;
12,871✔
552
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,871✔
553
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,871✔
554
  }
555
}
45,366✔
556

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

562
static smt_status_t call_mcsat_solver(context_t *ctx, const param_t *params) {
1,085✔
563
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_call_mcsat_solver(ctx, params));
1,085✔
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,633✔
572
  smt_core_t *core;
573
  smt_status_t stat;
574

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

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

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

592
  return stat;
59,548✔
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,213✔
673
  delegate_state_t *st;
674

675
  st = (delegate_state_t *) ctx->delegate_state;
22,213✔
676
  if (st == NULL) {
22,213✔
677
    return;
22,213✔
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) {
56✔
886
  term_table_t *terms;
887
  uint32_t i, nchildren;
888

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

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

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

903
  if (term_is_projection(terms, t)) {
56✔
904
    collect_boolean_atoms(ctx, proj_term_arg(terms, t), atoms, visited);
×
905
  } else if (term_is_sum(terms, t)) {
56✔
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)) {
56✔
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)) {
56✔
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)) {
56✔
934
    nchildren = term_num_children(terms, t);
30✔
935
    for (i=0; i<nchildren; i++) {
81✔
936
      collect_boolean_atoms(ctx, term_child(terms, t, i), atoms, visited);
51✔
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) {
5✔
945
  int_hset_t atoms, visited;
946
  uint32_t i;
947

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

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

963
  delete_int_hset(&visited);
5✔
964
  delete_int_hset(&atoms);
5✔
965
}
5✔
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,704✔
971
  if (ctx->unsat_core_cache == NULL) {
2,704✔
972
    ctx->unsat_core_cache = (ivector_t *) safe_malloc(sizeof(ivector_t));
2,704✔
973
    init_ivector(ctx->unsat_core_cache, core->size);
2,704✔
974
  } else {
975
    ivector_reset(ctx->unsat_core_cache);
×
976
  }
977
  ivector_copy(ctx->unsat_core_cache, core->data, core->size);
2,704✔
978
}
2,704✔
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) {
6✔
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)) {
6✔
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
6✔
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);
6✔
1035
    init_int_hmap(&label_map, 0);
6✔
1036
    init_ivector(&assumptions, n);
6✔
1037
    init_ivector(&mapped_core, 0);
6✔
1038
    init_term_manager(&tm, ctx->terms);
6✔
1039
    stat = YICES_STATUS_IDLE;
6✔
1040

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

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

1051
      int_hmap_add(&label_map, b, a[i]);
71✔
1052
      code = _o_assert_formula(ctx, implication);
71✔
1053
      if (code < 0) {
71✔
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));
71✔
1061
      ivector_push(&assumptions, b);
71✔
1062
    }
1063

1064
    if (stat != YICES_STATUS_ERROR) {
6✔
1065
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
6✔
1066
      if (stat == YICES_STATUS_UNSAT) {
6✔
1067
        term_subst_t subst;
1068

1069
        interpolant = context_get_unsat_model_interpolant(ctx);
5✔
1070
        assert(interpolant != NULL_TERM);
1071
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
5✔
1072

1073
        init_term_subst(&subst, &tm, n, assumptions.data, a);
5✔
1074
        interpolant = apply_term_subst(&subst, interpolant);
5✔
1075
        delete_term_subst(&subst);
5✔
1076
      }
1077
    }
1078

1079
    if (pushed) {
6✔
1080
      mcsat_cleanup_assumptions(ctx->mcsat);
5✔
1081
      context_pop(ctx);
5✔
1082
    }
1083
    if (stat == YICES_STATUS_UNSAT) {
6✔
1084
      mcsat_set_unsat_result(ctx->mcsat, interpolant);
5✔
1085
      cache_unsat_core(ctx, &mapped_core);
5✔
1086
    }
1087

1088
    delete_term_manager(&tm);
6✔
1089
    delete_ivector(&mapped_core);
6✔
1090
    delete_ivector(&assumptions);
6✔
1091
    delete_int_hmap(&label_map);
6✔
1092
    delete_model(&mdl);
6✔
1093

1094
    return stat;
6✔
1095
  }
1096
}
1097

1098
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) {
6✔
1099
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
6✔
1100
}
1101

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

1115
  context_invalidate_unsat_core_cache(ctx);
2,649✔
1116

1117
  if (ctx->mcsat == NULL) {
2,649✔
1118
    smt_status_t stat;
1119
    sat_delegate_t mode;
1120
    bool one_shot;
1121
    const char *delegate;
1122
    bool unknown;
1123
    ivector_t assumptions;
1124
    ivector_t failed;
1125
    uint32_t i;
1126
    literal_t l;
1127

1128
    init_ivector(&assumptions, n);
2,643✔
1129
    for (i=0; i<n; i++) {
90,110✔
1130
      l = context_add_assumption(ctx, a[i]);
87,467✔
1131
      if (l < 0) {
87,467✔
1132
        if (error != NULL) {
×
1133
          *error = l;
×
1134
        }
1135
        delete_ivector(&assumptions);
×
1136
        return YICES_STATUS_ERROR;
×
1137
      }
1138
      ivector_push(&assumptions, l);
87,467✔
1139
    }
1140

1141
    mode = effective_delegate_mode(ctx, params, &one_shot);
2,643✔
1142
    delegate = delegate_name(mode);
2,643✔
1143
    if (delegate == NULL) {
2,643✔
1144
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,642✔
1145
      delete_ivector(&assumptions);
2,642✔
1146
      return stat;
2,642✔
1147
    }
1148

1149
    if (ctx->logic != QF_BV) {
1✔
NEW
1150
      if (error != NULL) {
×
NEW
1151
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1152
      }
NEW
1153
      delete_ivector(&assumptions);
×
NEW
1154
      return YICES_STATUS_ERROR;
×
1155
    }
1156

1157
    if (!supported_delegate(delegate, &unknown)) {
1✔
NEW
1158
      if (error != NULL) {
×
NEW
1159
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1160
      }
NEW
1161
      delete_ivector(&assumptions);
×
NEW
1162
      return YICES_STATUS_ERROR;
×
1163
    }
1164

1165
    if (!incremental_delegate(delegate)) {
1✔
1166
      if (error != NULL) {
1✔
1167
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1168
      }
1169
      delete_ivector(&assumptions);
1✔
1170
      return YICES_STATUS_ERROR;
1✔
1171
    }
1172

NEW
1173
    init_ivector(&failed, 0);
×
NEW
1174
    if (one_shot) {
×
NEW
1175
      stat = check_with_delegate_assumptions(ctx, delegate, 0, n, assumptions.data, &failed);
×
1176
    } else {
NEW
1177
      stat = check_with_incremental_delegate(ctx, delegate, 0,
×
NEW
1178
                                             ctx->sat_delegate_selector_frames,
×
NEW
1179
                                             n, assumptions.data, &failed);
×
1180
    }
NEW
1181
    if (stat == YICES_STATUS_UNSAT) {
×
NEW
1182
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
×
1183
    }
NEW
1184
    delete_ivector(&failed);
×
UNCOV
1185
    delete_ivector(&assumptions);
×
UNCOV
1186
    return stat;
×
1187
  }
1188

1189
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
6✔
1190
}
1191

1192
/*
1193
 * Check with given model
1194
 * - if mcsat status is not IDLE, return the status
1195
 */
1196
smt_status_t check_context_with_model(context_t *ctx, const param_t *params, model_t* mdl, uint32_t n, const term_t t[]) {
144✔
1197
  smt_status_t stat;
1198

1199
  assert(ctx->mcsat != NULL);
1200

1201
  stat = mcsat_status(ctx->mcsat);
144✔
1202
  if (stat == YICES_STATUS_IDLE) {
144✔
1203
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
144✔
1204
    stat = mcsat_status(ctx->mcsat);
144✔
1205

1206
    // BD: this looks wrong. We shouldn't call clear yet.
1207
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1208
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1209
    //      context_clear(ctx);
1210
    //    }
1211
  }
1212

1213
  return stat;
144✔
1214
}
1215

1216
/*
1217
 * Check with given model and hints
1218
 * - set the model hint and call check_context_with_model
1219
 */
1220
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) {
12✔
1221
  assert(m <= n);
1222

1223
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
12✔
1224

1225
  return check_context_with_model(ctx, params, mdl, m, t);
12✔
1226
}
1227

1228

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

1252
  core = ctx->core;
×
1253

1254
  stat = smt_status(core);
×
1255
  if (stat == YICES_STATUS_IDLE) {
×
1256
    start_search(core, 0, NULL);
×
1257
    smt_process(core);
×
1258
    stat = smt_status(core);
×
1259

1260
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1261
           stat == YICES_STATUS_INTERRUPTED);
1262

1263
    if (stat == YICES_STATUS_SEARCHING) {
×
1264
      end_search_unknown(core);
×
1265
      stat = YICES_STATUS_UNKNOWN;
×
1266
    }
1267
  }
1268

1269
  return stat;
×
1270
}
1271

1272

1273

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

1289
  core = ctx->core;
16✔
1290

1291
  stat = smt_status(core);
16✔
1292
  if (stat == YICES_STATUS_IDLE) {
16✔
1293
    start_search(core, 0, NULL);
16✔
1294
    smt_process(core);
16✔
1295
    stat = smt_status(core);
16✔
1296

1297
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1298
           stat == YICES_STATUS_INTERRUPTED);
1299

1300
    if (stat == YICES_STATUS_SEARCHING) {
16✔
1301
      if (smt_easy_sat(core)) {
15✔
1302
        stat = YICES_STATUS_SAT;
15✔
1303
      } else {
1304
        // call the delegate
1305
        init_delegate(&delegate, sat_solver, num_vars(core));
×
1306
        delegate_set_verbosity(&delegate, verbosity);
×
1307

1308
        stat = solve_with_delegate(&delegate, core);
×
1309
        set_smt_status(core, stat);
×
1310
        if (stat == YICES_STATUS_SAT) {
×
1311
          for (x=0; x<num_vars(core); x++) {
×
1312
            v = delegate_get_value(&delegate, x);
×
1313
            set_bvar_value(core, x, v);
×
1314
          }
1315
        }
1316
        delete_delegate(&delegate);
×
1317
      }
1318
    }
1319
  }
1320

1321
  return stat;
16✔
1322
}
1323

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

NEW
1335
  core = ctx->core;
×
1336

NEW
1337
  stat = smt_status(core);
×
NEW
1338
  if (stat != YICES_STATUS_IDLE) {
×
NEW
1339
    return stat;
×
1340
  }
1341

NEW
1342
  start_search(core, 0, NULL);
×
NEW
1343
  smt_process(core);
×
NEW
1344
  stat = smt_status(core);
×
1345

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

NEW
1349
  if (stat != YICES_STATUS_SEARCHING) {
×
NEW
1350
    return stat;
×
1351
  }
1352

NEW
1353
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
NEW
1354
    return YICES_STATUS_UNKNOWN;
×
1355
  }
NEW
1356
  delegate_set_verbosity(&delegate, verbosity);
×
1357

NEW
1358
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
NEW
1359
  set_smt_status(core, stat);
×
NEW
1360
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
NEW
1361
  if (stat == YICES_STATUS_SAT) {
×
NEW
1362
    context_import_delegate_model(core, &delegate);
×
1363
  }
1364

NEW
1365
  delete_delegate(&delegate);
×
NEW
1366
  return stat;
×
1367
}
1368

1369

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

1393
  core = ctx->core;
×
1394

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

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

1405
    if (stat == YICES_STATUS_SEARCHING) {
×
1406
      code = 1;
×
1407
      f = fopen(filename, "w");
×
1408
      if (f == NULL) {
×
1409
        code = -1;
×
1410
      } else {
1411
        dimacs_print_bvcontext(f, ctx);
×
1412
        if (ferror(f)) code = -1;
×
1413
        fclose(f);
×
1414
      }
1415
    }
1416
  }
1417

1418
  *status = stat;
×
1419

1420
  return code;
×
1421
}
1422

1423

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

1450
  core = ctx->core;
×
1451

1452
  code = 0;
×
1453
  stat = smt_status(core);
×
1454
  if (stat == YICES_STATUS_IDLE) {
×
1455
    start_search(core, 0, NULL);
×
1456
    smt_process(core);
×
1457
    stat = smt_status(core);
×
1458

1459
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1460
           stat == YICES_STATUS_INTERRUPTED);
1461

1462
    if (stat == YICES_STATUS_SEARCHING) {
×
1463
      if (smt_easy_sat(core)) {
×
1464
        stat = YICES_STATUS_SAT;
×
1465
      } else {
1466
        // call the delegate
1467
        init_delegate(&delegate, "y2sat", num_vars(core));
×
1468
        delegate_set_verbosity(&delegate, 0);
×
1469

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

1489
        delete_delegate(&delegate);
×
1490
      }
1491
    }
1492
  }
1493

1494
  *status = stat;
×
1495

1496
  return code;
×
1497
}
1498

1499

1500

1501
/*
1502
 * MODEL CONSTRUCTION
1503
 */
1504

1505
/*
1506
 * Value of literal l in ctx->core
1507
 */
1508
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
1509
  value_t v;
1510

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

1527

1528
/*
1529
 * Value of arithmetic variable x in ctx->arith_solver
1530
 */
1531
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,590✔
1532
  rational_t *a;
1533
  value_t v;
1534

1535
  assert(context_has_arith_solver(ctx));
1536

1537
  a = &ctx->aux;
22,590✔
1538
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,590✔
1539
    v = vtbl_mk_rational(vtbl, a);
22,590✔
1540
  } else {
1541
    v = vtbl_mk_unknown(vtbl);
×
1542
  }
1543

1544
  return v;
22,590✔
1545
}
1546

1547

1548

1549
/*
1550
 * Value of bitvector variable x in ctx->bv_solver
1551
 */
1552
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,141✔
1553
  bvconstant_t *b;
1554
  value_t v;
1555

1556
  assert(context_has_bv_solver(ctx));
1557

1558
  b = &ctx->bv_buffer;
18,141✔
1559
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,141✔
1560
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,141✔
1561
  } else {
1562
    v = vtbl_mk_unknown(vtbl);
×
1563
  }
1564

1565
  return v;
18,141✔
1566
}
1567

1568

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

1585
  /*
1586
   * Get the root of t in the substitution table
1587
   */
1588
  r = intern_tbl_get_root(&ctx->intern, t);
319,818✔
1589
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
319,818✔
1590
    /*
1591
     * r is mapped to some object x in egraph/core/or theory solvers
1592
     * - keep track of polarity then force r to positive polarity
1593
     */
1594
    vtbl = model_get_vtbl(model);
110,704✔
1595
    polarity = polarity_of(r);
110,704✔
1596
    r = unsigned_term(r);
110,704✔
1597

1598
    /*
1599
     * Convert x to a concrete value
1600
     */
1601
    x = intern_tbl_map_of_root(&ctx->intern, r);
110,704✔
1602
    if (code_is_eterm(x)) {
110,704✔
1603
      // x refers to an egraph object or true_occ/false_occ
1604
      if (x == bool2code(true)) {
4,772✔
1605
        v = vtbl_mk_true(vtbl);
475✔
1606
      } else if (x == bool2code(false)) {
4,297✔
1607
        v = vtbl_mk_false(vtbl);
1,420✔
1608
      } else {
1609
        assert(context_has_egraph(ctx));
1610
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,877✔
1611
      }
1612

1613
    } else {
1614
      // x refers to a literal or a theory variable
1615
      tau = term_type(ctx->terms, r);
105,932✔
1616
      switch (type_kind(ctx->types, tau)) {
105,932✔
1617
      case BOOL_TYPE:
65,201✔
1618
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
1619
        break;
65,201✔
1620

1621
      case INT_TYPE:
22,590✔
1622
      case REAL_TYPE:
1623
        v = arith_value(ctx, vtbl, code2thvar(x));
22,590✔
1624
        break;
22,590✔
1625

1626
      case BITVECTOR_TYPE:
18,141✔
1627
        v = bv_value(ctx, vtbl, code2thvar(x));
18,141✔
1628
        break;
18,141✔
1629

1630
      default:
×
1631
        /*
1632
         * This should never happen:
1633
         * scalar, uninterpreted, tuple, function terms
1634
         * are mapped to egraph terms.
1635
         */
1636
        assert(false);
1637
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
1638
        break;
×
1639
      }
1640
    }
1641

1642
    /*
1643
     * Restore polarity then add mapping [t --> v] in the model
1644
     */
1645
    if (! object_is_unknown(vtbl, v)) {
110,704✔
1646
      if (object_is_boolean(vtbl, v)) {
110,704✔
1647
        if (polarity) {
67,096✔
1648
          // negate the value
1649
          v = vtbl_mk_not(vtbl, v);
24✔
1650
        }
1651
      }
1652
      model_map_term(model, t, v);
110,704✔
1653
    }
1654

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

1681

1682

1683

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

1696
  assert(smt_status(ctx->core) == YICES_STATUS_SAT || smt_status(ctx->core) == YICES_STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == YICES_STATUS_SAT);
1697

1698
  /*
1699
   * First build assignments in the satellite solvers
1700
   * and get the val_in_model functions for the egraph
1701
   */
1702
  if (context_has_arith_solver(ctx)) {
42,133✔
1703
    ctx->arith.build_model(ctx->arith_solver);
32,908✔
1704
  }
1705
  if (context_has_bv_solver(ctx)) {
42,133✔
1706
    ctx->bv.build_model(ctx->bv_solver);
21,408✔
1707
  }
1708

1709
  /*
1710
   * Construct the egraph model
1711
   */
1712
  if (context_has_egraph(ctx)) {
42,133✔
1713
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,034✔
1714
  }
1715

1716
  /*
1717
   * Construct the mcsat model.
1718
   */
1719
  if (context_has_mcsat(ctx)) {
42,133✔
1720
    mcsat_build_model(ctx->mcsat, model);
33✔
1721
  }
1722

1723
  // scan the internalization table
1724
  terms = ctx->terms;
42,133✔
1725
  n = intern_tbl_num_terms(&ctx->intern);
42,133✔
1726
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,096,072✔
1727
    if (good_term_idx(terms, i)) {
1,235,053,939✔
1728
      t = pos_occ(i);
1,235,053,939✔
1729
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,053,939✔
1730
        build_term_value(ctx, model, t);
319,818✔
1731
      }
1732
    }
1733
  }
1734
}
42,133✔
1735

1736

1737
/*
1738
 * Cleanup solver models
1739
 */
1740
void clean_solver_models(context_t *ctx) {
42,133✔
1741
  if (context_has_arith_solver(ctx)) {
42,133✔
1742
    ctx->arith.free_model(ctx->arith_solver);
32,908✔
1743
  }
1744
  if (context_has_bv_solver(ctx)) {
42,133✔
1745
    ctx->bv.free_model(ctx->bv_solver);
21,408✔
1746
  }
1747
  if (context_has_egraph(ctx)) {
42,133✔
1748
    egraph_free_model(ctx->egraph);
13,034✔
1749
  }
1750
}
42,133✔
1751

1752

1753

1754
/*
1755
 * Build a model for the current context
1756
 * - the context status must be SAT (or UNKNOWN)
1757
 * - if model->has_alias is true, we store the term substitution
1758
 *   defined by ctx->intern_tbl into the model
1759
 */
1760
void context_build_model(model_t *model, context_t *ctx) {
232✔
1761
  // Build solver models and term values
1762
  build_model(model, ctx);
232✔
1763

1764
  // Cleanup
1765
  clean_solver_models(ctx);
232✔
1766
}
232✔
1767

1768

1769

1770
/*
1771
 * Read the value of a Boolean term t
1772
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
1773
 */
1774
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
1775
  term_t r;
1776
  uint32_t polarity;
1777
  int32_t x;
1778
  bval_t v;
1779

1780
  assert(is_boolean_term(ctx->terms, t));
1781

1782
  // default value if t is not in the internalization table
1783
  v = VAL_UNDEF_FALSE;
×
1784
  r = intern_tbl_get_root(&ctx->intern, t);
×
1785
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
1786
    // r is mapped to some object x
1787
    polarity = polarity_of(r);
×
1788
    r = unsigned_term(r);
×
1789

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

1804
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
1805
    v ^= polarity;
×
1806
  }
1807

1808
  return v;
×
1809
}
1810

1811

1812
/*
1813
 * UNSAT CORE
1814
 */
1815

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

1829
  if (ctx->unsat_core_cache != NULL) {
2,704✔
1830
    // Fast path: repeated get_unsat_core returns the cached term vector.
1831
    ivector_reset(v);
5✔
1832
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
5✔
1833
    return;
5✔
1834
  }
1835

1836
  if (ctx->mcsat != NULL) {
2,699✔
1837
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
1838
    // there is no generic context-level core structure to rebuild from here.
1839
    ivector_reset(v);
×
1840
    return;
×
1841
  }
1842

1843
  core = ctx->core;
2,699✔
1844
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
1845
  build_unsat_core(core, v);
2,699✔
1846

1847
  // convert from literals to terms
1848
  n = v->size;
2,699✔
1849
  for (i=0; i<n; i++) {
37,499✔
1850
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,800✔
1851
    assert(t >= 0);
1852
    v->data[i] = t;
34,800✔
1853
  }
1854

1855
  // Cache the converted term core for subsequent queries.
1856
  cache_unsat_core(ctx, v);
2,699✔
1857
}
1858

1859

1860
/*
1861
 * MODEL INTERPOLANT
1862
 */
1863
term_t context_get_unsat_model_interpolant(context_t *ctx) {
51✔
1864
  assert(ctx->mcsat != NULL);
1865
  return mcsat_get_unsat_model_interpolant(ctx->mcsat);
51✔
1866
}
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