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

SRI-CSL / yices2 / 25576430637

08 May 2026 07:52PM UTC coverage: 67.401% (+0.1%) from 67.254%
25576430637

Pull #611

github

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

682 of 994 new or added lines in 15 files covered. (68.61%)

2 existing lines in 2 files now uncovered.

86053 of 127673 relevant lines covered (67.4%)

1616259.22 hits per line

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

59.61
/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/mcsat_satellite.h"
39
#include "solvers/funs/fun_solver.h"
40
#include "solvers/simplex/simplex.h"
41
#include "terms/term_explorer.h"
42
#include "terms/term_manager.h"
43
#include "terms/term_substitution.h"
44
#include "utils/int_hash_map.h"
45
#include "utils/int_hash_sets.h"
46

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

51

52

53
/*
54
 * TRACE FUNCTIONS
55
 */
56

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

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

82

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

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

94

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

103

104

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

113

114

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

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

133
  case VAL_TRUE:
×
134
    break;
×
135

136
  case VAL_FALSE:
2,543✔
137
    save_conflicting_assumption(core, l);
2,543✔
138
    break;
2,543✔
139
  }
140
}
86,472✔
141

142

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

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

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

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

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

175
    // assumption
176
    if (core->has_assumptions) {
6,284,320✔
177
      l = get_next_assumption(core);
12✔
178
      if (l != null_literal) {
12✔
179
        process_assumption(core, l);
5✔
180
        continue;
5✔
181
      }
182
    }
183

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

195
  *reduce_threshold = r_threshold;
13,439✔
196
}
13,439✔
197

198

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

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

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

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

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

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

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

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

258

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

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

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

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

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

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

311
  *reduce_threshold = r_threshold;
20,855✔
312
}
20,855✔
313

314

315

316

317

318
/*
319
 * SUPPORTED BRANCHING
320
 */
321

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

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

335

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

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

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

363

364

365

366

367
/*
368
 * CORE SOLVER
369
 */
370

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

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

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

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

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

433
      if (smt_status(core) != YICES_STATUS_SEARCHING) break;
47,683✔
434

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

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

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

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

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

471
  trace_done(core);
45,373✔
472
}
45,373✔
473

474

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

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

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

529
  if (ctx->mcsat_supplement_active && egraph != NULL && egraph->th[ETYPE_MCSAT] != NULL) {
45,373✔
530
    mcsat_satellite_set_search_parameters((mcsat_satellite_t *) egraph->th[ETYPE_MCSAT], params);
6✔
531
  }
532

533
  /*
534
   * Set simplex parameters
535
   */
536
  if (context_has_simplex_solver(ctx)) {
45,373✔
537
    simplex = ctx->arith_solver;
33,239✔
538
    if (params->use_simplex_prop) {
33,239✔
539
      simplex_enable_propagation(simplex);
12,863✔
540
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,863✔
541
    }
542
    if (params->adjust_simplex_model) {
33,239✔
543
      simplex_enable_adjust_model(simplex);
12,817✔
544
    }
545
    simplex_set_bland_threshold(simplex, params->bland_threshold);
33,239✔
546
    if (params->integer_check) {
33,239✔
547
      simplex_enable_periodic_icheck(simplex);
×
548
      simplex_set_integer_check_period(simplex, params->integer_check_period);
×
549
    }
550
  }
551

552
  /*
553
   * Set array solver parameters
554
   */
555
  if (context_has_fun_solver(ctx)) {
45,373✔
556
    fsolver = ctx->fun_solver;
12,874✔
557
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,874✔
558
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,874✔
559
  }
560
}
45,373✔
561

562
static smt_status_t _o_call_mcsat_solver(context_t *ctx, const param_t *params) {
1,124✔
563
  smt_status_t stat;
564

565
  mcsat_solve(ctx->mcsat, params, NULL, 0, NULL);
1,124✔
566
  stat = mcsat_status(ctx->mcsat);
1,124✔
567

568
  /*
569
   * For plain UNSAT results (without explicit model assumptions), keep the
570
   * interpolant API usable by providing the canonical false interpolant.
571
   */
572
  if (stat == YICES_STATUS_UNSAT &&
1,434✔
573
      context_supports_model_interpolation(ctx) &&
319✔
574
      mcsat_get_unsat_model_interpolant(ctx->mcsat) == NULL_TERM) {
9✔
NEW
575
    mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, false_term, 0, NULL, NULL);
×
576
  }
577

578
  return stat;
1,124✔
579
}
580

581
static smt_status_t call_mcsat_solver(context_t *ctx, const param_t *params) {
1,124✔
582
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_call_mcsat_solver(ctx, params));
1,124✔
583
}
584

585
/*
586
 * Initialize search parameters then call solve
587
 * - if ctx->status is not IDLE, return the status.
588
 * - if params is NULL, we use default values.
589
 */
590
smt_status_t check_context(context_t *ctx, const param_t *params) {
60,677✔
591
  smt_core_t *core;
592
  smt_status_t stat;
593
  mcsat_satellite_t *sat;
594

595
  if (params == NULL) {
60,677✔
596
    params = get_default_params();
×
597
  }
598

599
  if (ctx->mcsat != NULL) {
60,677✔
600
    return call_mcsat_solver(ctx, params);
1,124✔
601
  }
602

603
  core = ctx->core;
59,553✔
604
  stat = smt_status(core);
59,553✔
605
  if (stat == YICES_STATUS_IDLE) {
59,553✔
606
    // clean state: the search can proceed
607
    context_set_search_parameters(ctx, params);
42,729✔
608
    solve(core, params, 0, NULL);
42,729✔
609
    stat = smt_status(core);
42,729✔
610
  }
611

612
  sat = NULL;
59,553✔
613
  if (ctx->mcsat_supplement_active &&
59,553✔
614
      ctx->egraph != NULL &&
4✔
615
      ctx->egraph->th[ETYPE_MCSAT] != NULL) {
4✔
616
    sat = (mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT];
4✔
617
  }
618
  if (stat == YICES_STATUS_UNSAT &&
59,553✔
NEW
619
      sat != NULL &&
×
NEW
620
      context_supports_model_interpolation(ctx) &&
×
NEW
621
      mcsat_satellite_get_unsat_model_interpolant(sat) == NULL_TERM) {
×
NEW
622
    mcsat_satellite_set_unsat_model_interpolant(sat, false_term);
×
623
  }
624

625
  return stat;
59,553✔
626
}
627

628

629
/*
630
 * Check with assumptions a[0] ... a[n-1]
631
 * - if ctx->status is not IDLE, return the status.
632
 */
633
smt_status_t check_context_with_assumptions(context_t *ctx, const param_t *params, uint32_t n, const literal_t *a) {
2,644✔
634
  smt_core_t *core;
635
  smt_status_t stat;
636
  mcsat_satellite_t *sat;
637

638
  assert(ctx->mcsat == NULL);
639

640
  core = ctx->core;
2,644✔
641
  stat = smt_status(core);
2,644✔
642
  if (stat == YICES_STATUS_IDLE) {
2,644✔
643
    // clean state
644
    if (params == NULL) {
2,644✔
645
      params = get_default_params();
×
646
    }
647
    context_set_search_parameters(ctx, params);
2,644✔
648
    solve(core, params, n, a);
2,644✔
649
    stat = smt_status(core);
2,644✔
650
  }
651

652
  sat = NULL;
2,644✔
653
  if (ctx->mcsat_supplement_active &&
2,644✔
654
      ctx->egraph != NULL &&
2✔
655
      ctx->egraph->th[ETYPE_MCSAT] != NULL) {
2✔
656
    sat = (mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT];
2✔
657
  }
658
  if (stat == YICES_STATUS_UNSAT &&
2,644✔
659
      sat != NULL &&
2✔
660
      context_supports_model_interpolation(ctx) &&
2✔
NEW
661
      mcsat_satellite_get_unsat_model_interpolant(sat) == NULL_TERM) {
×
NEW
662
    mcsat_satellite_set_unsat_model_interpolant(sat, false_term);
×
663
  }
664

665
  return stat;
2,644✔
666
}
667

668
typedef struct delegate_state_s {
669
  delegate_t delegate;
670
  sat_delegate_t mode;
671
  bool live;
672
  uint64_t synced_mutation;
673
  uint32_t delegate_nvars;
674
  bvar_t next_selector_var;
675
  literal_t active_selector;
676
  ivector_t assumptions;
677
  ivector_t failed;
678
} delegate_state_t;
679

680
void context_delegate_state_cleanup(context_t *ctx) {
22,356✔
681
  delegate_state_t *st;
682

683
  st = (delegate_state_t *) ctx->delegate_state;
22,356✔
684
  if (st == NULL) {
22,356✔
685
    return;
22,356✔
686
  }
687

688
  if (st->live) {
×
689
    delete_delegate(&st->delegate);
×
690
    st->live = false;
×
691
  }
692
  delete_ivector(&st->assumptions);
×
693
  delete_ivector(&st->failed);
×
694
  safe_free(st);
×
695
  ctx->delegate_state = NULL;
×
696
}
697

698
static delegate_state_t *context_get_delegate_state(context_t *ctx) {
×
699
  delegate_state_t *st;
700

701
  st = (delegate_state_t *) ctx->delegate_state;
×
702
  if (st == NULL) {
×
703
    st = (delegate_state_t *) safe_malloc(sizeof(delegate_state_t));
×
704
    st->mode = SAT_DELEGATE_NONE;
×
705
    st->live = false;
×
706
    st->synced_mutation = 0;
×
707
    st->delegate_nvars = 0;
×
708
    st->next_selector_var = 0;
×
709
    st->active_selector = true_literal;
×
710
    init_ivector(&st->assumptions, 0);
×
711
    init_ivector(&st->failed, 0);
×
712
    ctx->delegate_state = st;
×
713
  }
714
  return st;
×
715
}
716

717
static void context_import_delegate_model(smt_core_t *core, delegate_t *d) {
×
718
  bvar_t x;
719

720
  for (x=0; x<num_vars(core); x++) {
×
721
    set_bvar_value(core, x, delegate_get_value(d, x));
×
722
  }
723
}
×
724

725
static void set_delegate_assumption_state(smt_core_t *core, uint32_t n, const literal_t *assumptions,
×
726
                                          smt_status_t stat, const ivector_t *failed) {
727
  if (n == 0) {
×
728
    core->has_assumptions = false;
×
729
    core->num_assumptions = 0;
×
730
    core->assumption_index = 0;
×
731
    core->assumptions = NULL;
×
732
    core->bad_assumption = null_literal;
×
733
    return;
×
734
  }
735

736
  core->has_assumptions = true;
×
737
  core->num_assumptions = n;
×
738
  core->assumption_index = n;
×
739
  core->assumptions = assumptions;
×
740
  core->bad_assumption = null_literal;
×
741

742
  if (stat == YICES_STATUS_UNSAT && failed != NULL && failed->size > 0) {
×
743
    core->bad_assumption = failed->data[0];
×
744
  }
745
}
746

747
static bool context_prepare_incremental_delegate(context_t *ctx, delegate_state_t *st, const char *sat_solver,
×
748
                                                 uint32_t verbosity) {
749
  smt_core_t *core;
750
  uint32_t nvars;
751
  literal_t guard;
752
  uint32_t nnew;
753

754
  core = ctx->core;
×
755
  nvars = num_vars(core);
×
756

757
  if (st->live && st->mode != ctx->sat_delegate) {
×
758
    delete_delegate(&st->delegate);
×
759
    st->live = false;
×
760
  }
761

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

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

781
  if (st->synced_mutation != ctx->mutation_count) {
×
782
    if (st->next_selector_var < st->delegate_nvars) {
×
783
      st->next_selector_var = st->delegate_nvars;
×
784
    }
785
    if (st->next_selector_var >= st->delegate_nvars) {
×
786
      nnew = st->next_selector_var - st->delegate_nvars + 1;
×
787
      delegate_add_vars(&st->delegate, nnew);
×
788
      st->delegate_nvars += nnew;
×
789
    }
790
    guard = neg_lit(st->next_selector_var);
×
791
    add_problem_clauses_to_delegate(&st->delegate, core, guard);
×
792
    st->active_selector = pos_lit(st->next_selector_var);
×
793
    st->next_selector_var ++;
×
794
    st->synced_mutation = ctx->mutation_count;
×
795
  }
796

797
  return true;
×
798
}
799

800
smt_status_t check_with_incremental_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
801
                                             uint32_t n, const literal_t *assumptions, ivector_t *failed) {
802
  smt_status_t stat;
803
  smt_core_t *core;
804
  delegate_state_t *st;
805
  ivector_t visible_failed;
806
  uint32_t i;
807

808
  core = ctx->core;
×
809
  stat = smt_status(core);
×
810
  if (stat != YICES_STATUS_IDLE) {
×
811
    return stat;
×
812
  }
813

814
  start_search(core, 0, NULL);
×
815
  smt_process(core);
×
816
  stat = smt_status(core);
×
817

818
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
819
         stat == YICES_STATUS_INTERRUPTED);
820

821
  if (stat != YICES_STATUS_SEARCHING) {
×
822
    return stat;
×
823
  }
824

825
  if (n == 0 && smt_easy_sat(core)) {
×
826
    stat = YICES_STATUS_SAT;
×
827
    set_smt_status(core, stat);
×
828
    return stat;
×
829
  }
830

831
  st = context_get_delegate_state(ctx);
×
832
  if (!context_prepare_incremental_delegate(ctx, st, sat_solver, verbosity)) {
×
833
    return YICES_STATUS_UNKNOWN;
×
834
  }
835

836
  init_ivector(&visible_failed, 0);
×
837
  ivector_reset(&st->assumptions);
×
838
  ivector_reset(&st->failed);
×
839
  if (st->active_selector != true_literal) {
×
840
    ivector_push(&st->assumptions, st->active_selector);
×
841
  }
842
  for (i=0; i<n; i++) {
×
843
    ivector_push(&st->assumptions, assumptions[i]);
×
844
  }
845

846
  if (st->assumptions.size == 0) {
×
847
    stat = st->delegate.check(st->delegate.solver);
×
848
  } else if (delegate_supports_assumptions(&st->delegate)) {
×
849
    stat = delegate_check_with_assumptions(&st->delegate, st->assumptions.size,
×
850
                                           (literal_t *) st->assumptions.data, &st->failed);
×
851
    if (stat == YICES_STATUS_UNSAT) {
×
852
      for (i=0; i<st->failed.size; i++) {
×
853
        literal_t l = st->failed.data[i];
×
854
        if (l != st->active_selector) {
×
855
          ivector_push(&visible_failed, l);
×
856
        }
857
      }
858
      if (failed != NULL) {
×
859
        ivector_reset(failed);
×
860
        ivector_add(failed, visible_failed.data, visible_failed.size);
×
861
      }
862
    }
863
  } else {
864
    stat = YICES_STATUS_UNKNOWN;
×
865
  }
866

867
  set_smt_status(core, stat);
×
868
  set_delegate_assumption_state(core, n, assumptions, stat, &visible_failed);
×
869
  if (stat == YICES_STATUS_SAT) {
×
870
    context_import_delegate_model(core, &st->delegate);
×
871
  }
872

873
  delete_ivector(&visible_failed);
×
874
  return stat;
×
875
}
876

877
/*
878
 * Explore term t and collect all Boolean atoms into atoms.
879
 */
880
static void collect_boolean_atoms(context_t *ctx, term_t t, int_hset_t *atoms, int_hset_t *visited) {
64✔
881
  term_table_t *terms;
882
  uint32_t i, nchildren;
883

884
  if (t < 0) {
64✔
885
    t = not(t);
×
886
  }
887

888
  if (int_hset_member(visited, t)) {
64✔
889
    return;
×
890
  }
891
  int_hset_add(visited, t);
64✔
892

893
  terms = ctx->terms;
64✔
894
  if (term_type(terms, t) == bool_type(terms->types)) {
64✔
895
    int_hset_add(atoms, t);
64✔
896
  }
897

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

936
/*
937
 * Extract assumptions whose labels appear in term t.
938
 */
939
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✔
940
  int_hset_t atoms, visited;
941
  uint32_t i;
942

943
  init_int_hset(&atoms, 0);
9✔
944
  init_int_hset(&visited, 0);
9✔
945
  collect_boolean_atoms(ctx, t, &atoms, &visited);
9✔
946

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

958
  delete_int_hset(&visited);
9✔
959
  delete_int_hset(&atoms);
9✔
960
}
9✔
961

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

975
static void cache_failed_assumptions_core(context_t *ctx, uint32_t n, const term_t *a,
×
976
                                          const ivector_t *assumption_literals,
977
                                          const ivector_t *failed_literals) {
978
  ivector_t core_terms;
979
  int_hset_t failed;
980
  uint32_t i;
981

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

997
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
998
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed);
999

1000
/*
1001
 * MCSAT variant of check_context_with_term_assumptions.
1002
 * Caller must hold __yices_globals.lock.
1003
 */
1004
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✔
1005
  smt_status_t stat;
1006
  ivector_t assumptions;
1007
  uint32_t i;
1008

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

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

1029
    init_model(&mdl, ctx->terms, true);
10✔
1030
    init_int_hmap(&label_map, 0);
10✔
1031
    init_ivector(&assumptions, n);
10✔
1032
    init_ivector(&mapped_core, 0);
10✔
1033
    init_term_manager(&tm, ctx->terms);
10✔
1034
    stat = YICES_STATUS_IDLE;
10✔
1035

1036
    pushed = false;
10✔
1037
    if (context_supports_pushpop(ctx)) {
10✔
1038
      context_push(ctx);
9✔
1039
      pushed = true;
9✔
1040
    }
1041

1042
    for (i=0; i<n; i++) {
85✔
1043
      term_t b = new_uninterpreted_term(ctx->terms, bool_id);
75✔
1044
      term_t implication = mk_implies(&tm, b, a[i]);
75✔
1045

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

1059
    if (stat != YICES_STATUS_ERROR) {
10✔
1060
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
10✔
1061
      if (stat == YICES_STATUS_UNSAT) {
10✔
1062
        interpolant = context_get_unsat_model_interpolant(ctx);
9✔
1063
        assert(interpolant != NULL_TERM);
1064
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
9✔
1065
      }
1066
    }
1067

1068
    if (pushed) {
10✔
1069
      mcsat_cleanup_assumptions(ctx->mcsat);
9✔
1070
      context_pop(ctx);
9✔
1071
    }
1072
    if (stat == YICES_STATUS_UNSAT) {
10✔
1073
      mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, interpolant, n, assumptions.data, a);
9✔
1074
      cache_unsat_core(ctx, &mapped_core);
9✔
1075
    }
1076

1077
    delete_term_manager(&tm);
10✔
1078
    delete_ivector(&mapped_core);
10✔
1079
    delete_ivector(&assumptions);
10✔
1080
    delete_int_hmap(&label_map);
10✔
1081
    delete_model(&mdl);
10✔
1082

1083
    return stat;
10✔
1084
  }
1085
}
1086

1087
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✔
1088
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
10✔
1089
}
1090

1091
/*
1092
 * Supplemental-MCSAT variant for term assumptions in CDCL(T) mode.
1093
 * We encode assumptions via fresh labels b_i with implications (b_i => a_i),
1094
 * then solve under assumptions b_i = true.
1095
 *
1096
 * Labels are kept in the context (no push/pop) so the regular context status
1097
 * and multicheck protocol remain unchanged.
1098
 */
1099
static smt_status_t _o_check_context_with_term_assumptions_supplement(context_t *ctx, const param_t *params, uint32_t n, const term_t *a, int32_t *error) {
2✔
1100
  smt_status_t stat;
1101
  ivector_t assumptions;
1102
  term_t interpolant;
1103
  uint32_t i;
1104
  literal_t l;
1105
  mcsat_satellite_t *sat;
1106

1107
  init_ivector(&assumptions, n);
2✔
1108

1109
  stat = YICES_STATUS_IDLE;
2✔
1110
  interpolant = NULL_TERM;
2✔
1111
  sat = NULL;
2✔
1112

1113
  if (ctx->mcsat_supplement_active &&
2✔
1114
      ctx->egraph != NULL &&
2✔
1115
      ctx->egraph->th[ETYPE_MCSAT] != NULL) {
2✔
1116
    sat = (mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT];
2✔
1117
  }
1118

1119
  for (i=0; i<n; i++) {
6✔
1120
    l = context_add_assumption(ctx, a[i]);
4✔
1121
    if (l < 0) {
4✔
NEW
1122
      if (error != NULL) {
×
NEW
1123
        *error = l;
×
1124
      }
NEW
1125
      stat = YICES_STATUS_ERROR;
×
NEW
1126
      break;
×
1127
    }
1128

1129
    ivector_push(&assumptions, l);
4✔
1130
  }
1131

1132
  if (stat != YICES_STATUS_ERROR) {
2✔
1133
    stat = check_context_with_assumptions(ctx, params, assumptions.size, (const literal_t *) assumptions.data);
2✔
1134
    if (stat == YICES_STATUS_UNSAT) {
2✔
1135
      if (sat != NULL) {
2✔
1136
        interpolant = mcsat_satellite_compute_unsat_model_interpolant(sat, params, n, a);
2✔
1137
      }
1138
      if (interpolant == NULL_TERM && context_supports_model_interpolation(ctx)) {
2✔
NEW
1139
        interpolant = context_get_unsat_model_interpolant(ctx);
×
1140
      }
1141
      if (interpolant == NULL_TERM && context_supports_model_interpolation(ctx)) {
2✔
NEW
1142
        interpolant = false_term;
×
1143
      }
1144
    }
1145
  }
1146

1147
  if (stat == YICES_STATUS_UNSAT && interpolant != NULL_TERM && sat != NULL) {
2✔
1148
    mcsat_satellite_set_unsat_model_interpolant(sat, interpolant);
2✔
1149
  }
1150

1151
  delete_ivector(&assumptions);
2✔
1152

1153
  return stat;
2✔
1154
}
1155

1156
static smt_status_t check_context_with_term_assumptions_supplement(context_t *ctx, const param_t *params, uint32_t n, const term_t *a, int32_t *error) {
2✔
1157
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_supplement(ctx, params, n, a, error));
2✔
1158
}
1159

1160
/*
1161
 * Check under assumptions given as terms.
1162
 * - if MCSAT is enabled, this uses temporary labels + model interpolation.
1163
 * - otherwise terms are converted to literals and handled by the CDCL(T) path.
1164
 *
1165
 * Preconditions:
1166
 * - context status must be IDLE.
1167
 */
1168
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,655✔
1169
  smt_status_t stat;
1170
  sat_delegate_t mode;
1171
  bool one_shot;
1172
  const char *delegate;
1173
  bool unknown;
1174
  ivector_t assumptions;
1175
  ivector_t failed;
1176
  uint32_t i;
1177
  literal_t l;
1178

1179
  if (error != NULL) {
2,655✔
1180
    *error = CTX_NO_ERROR;
2,655✔
1181
  }
1182

1183
  /*
1184
   * Clear any prior term-assumption core before all paths below. Delegate
1185
   * checks cache a new core only on UNSAT.
1186
   */
1187
  context_invalidate_unsat_core_cache(ctx);
2,655✔
1188

1189
  if (ctx->mcsat == NULL) {
2,655✔
1190
    if (ctx->mcsat_supplement_active) {
2,645✔
1191
      return check_context_with_term_assumptions_supplement(ctx, params, n, a, error);
2✔
1192
    }
1193

1194
    init_ivector(&assumptions, n);
2,643✔
1195
    for (i=0; i<n; i++) {
90,110✔
1196
      l = context_add_assumption(ctx, a[i]);
87,467✔
1197
      if (l < 0) {
87,467✔
1198
        if (error != NULL) {
×
1199
          *error = l;
×
1200
        }
1201
        delete_ivector(&assumptions);
×
1202
        return YICES_STATUS_ERROR;
×
1203
      }
1204
      ivector_push(&assumptions, l);
87,467✔
1205
    }
1206

1207
    mode = effective_sat_delegate_mode(ctx->sat_delegate, params, &one_shot);
2,643✔
1208
    delegate = sat_delegate_name(mode);
2,643✔
1209
    if (delegate == NULL) {
2,643✔
1210
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,642✔
1211
      delete_ivector(&assumptions);
2,642✔
1212
      return stat;
2,642✔
1213
    }
1214

1215
    if (ctx->logic != QF_BV) {
1✔
1216
      if (error != NULL) {
×
1217
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1218
      }
1219
      delete_ivector(&assumptions);
×
1220
      return YICES_STATUS_ERROR;
×
1221
    }
1222

1223
    if (!supported_delegate(delegate, &unknown)) {
1✔
1224
      if (error != NULL) {
×
1225
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1226
      }
1227
      delete_ivector(&assumptions);
×
1228
      return YICES_STATUS_ERROR;
×
1229
    }
1230

1231
    if (!incremental_delegate(delegate)) {
1✔
1232
      if (error != NULL) {
1✔
1233
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1234
      }
1235
      delete_ivector(&assumptions);
1✔
1236
      return YICES_STATUS_ERROR;
1✔
1237
    }
1238

1239
    init_ivector(&failed, 0);
×
1240
    if (one_shot || !ctx->sat_delegate_selector_frames) {
×
1241
      stat = check_with_delegate_assumptions(ctx, delegate, 0, n, assumptions.data, &failed);
×
1242
    } else {
1243
      stat = check_with_incremental_delegate(ctx, delegate, 0, n, assumptions.data, &failed);
×
1244
    }
1245
    if (stat == YICES_STATUS_UNSAT) {
×
1246
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
×
1247
    }
1248
    delete_ivector(&failed);
×
1249
    delete_ivector(&assumptions);
×
1250
    return stat;
×
1251
  }
1252

1253
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1254
}
1255

1256
/*
1257
 * Check with given model
1258
 * - if mcsat status is not IDLE, return the status
1259
 */
1260
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✔
1261
  smt_status_t stat;
1262

1263
  assert(ctx->mcsat != NULL);
1264

1265
  stat = mcsat_status(ctx->mcsat);
161✔
1266
  if (stat == YICES_STATUS_IDLE) {
161✔
1267
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
161✔
1268
    stat = mcsat_status(ctx->mcsat);
161✔
1269

1270
    // BD: this looks wrong. We shouldn't call clear yet.
1271
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1272
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1273
    //      context_clear(ctx);
1274
    //    }
1275
  }
1276

1277
  return stat;
161✔
1278
}
1279

1280
/*
1281
 * Check with given model and hints
1282
 * - set the model hint and call check_context_with_model
1283
 */
1284
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✔
1285
  assert(m <= n);
1286

1287
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1288

1289
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1290
}
1291

1292

1293
/*
1294
 * Precheck: force generation of clauses and other stuff that's
1295
 * constructed lazily by the solvers. For example, this
1296
 * can be used to convert all the constraints asserted in the
1297
 * bitvector to clauses so that we can export the result to DIMACS.
1298
 *
1299
 * If ctx status is IDLE:
1300
 * - the function calls 'start_search' and does one round of propagation.
1301
 * - if this results in UNSAT, the function returns UNSAT
1302
 * - if the precheck is interrupted, the function returns INTERRUPTED
1303
 * - otherwise the function returns UNKNOWN and sets the status to
1304
 *   UNKNOWN.
1305
 *
1306
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
1307
 * IDLE before doing anything else with this context.
1308
 *
1309
 * If ctx status is not IDLE, the function returns it and does nothing
1310
 * else.
1311
 */
1312
smt_status_t precheck_context(context_t *ctx) {
×
1313
  smt_status_t stat;
1314
  smt_core_t *core;
1315

1316
  core = ctx->core;
×
1317

1318
  stat = smt_status(core);
×
1319
  if (stat == YICES_STATUS_IDLE) {
×
1320
    start_search(core, 0, NULL);
×
1321
    smt_process(core);
×
1322
    stat = smt_status(core);
×
1323

1324
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1325
           stat == YICES_STATUS_INTERRUPTED);
1326

1327
    if (stat == YICES_STATUS_SEARCHING) {
×
1328
      end_search_unknown(core);
×
1329
      stat = YICES_STATUS_UNKNOWN;
×
1330
    }
1331
  }
1332

1333
  return stat;
×
1334
}
1335

1336

1337

1338
/*
1339
 * Solve using another SAT solver
1340
 * - sat_solver = name of the solver to use
1341
 * - verbosity = verbosity level (0 means quiet)
1342
 * - this may be used only for BV or pure SAT problems
1343
 * - we perform one round of propagation to convert the problem to CNF
1344
 * - then we call an external SAT solver on the CNF problem
1345
 */
1346
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
18✔
1347
  smt_status_t stat;
1348
  smt_core_t *core;
1349
  delegate_t delegate;
1350
  bvar_t x;
1351
  bval_t v;
1352

1353
  core = ctx->core;
18✔
1354

1355
  stat = smt_status(core);
18✔
1356
  if (stat == YICES_STATUS_IDLE) {
18✔
1357
    start_search(core, 0, NULL);
18✔
1358
    smt_process(core);
18✔
1359
    stat = smt_status(core);
18✔
1360

1361
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1362
           stat == YICES_STATUS_INTERRUPTED);
1363

1364
    if (stat == YICES_STATUS_SEARCHING) {
18✔
1365
      if (smt_easy_sat(core)) {
17✔
1366
        stat = YICES_STATUS_SAT;
17✔
1367
      } else {
1368
        // call the delegate
1369
        init_delegate(&delegate, sat_solver, num_vars(core));
×
1370
        delegate_set_verbosity(&delegate, verbosity);
×
1371

1372
        stat = solve_with_delegate(&delegate, core);
×
1373
        set_smt_status(core, stat);
×
1374
        if (stat == YICES_STATUS_SAT) {
×
1375
          for (x=0; x<num_vars(core); x++) {
×
1376
            v = delegate_get_value(&delegate, x);
×
1377
            set_bvar_value(core, x, v);
×
1378
          }
1379
        }
1380
        delete_delegate(&delegate);
×
1381
      }
1382
    }
1383
  }
1384

1385
  return stat;
18✔
1386
}
1387

1388
/*
1389
 * One-shot check with delegate and assumptions.
1390
 * - assumptions are literals in core encoding.
1391
 * - if failed != NULL and result is UNSAT, failed assumptions are appended to *failed.
1392
 */
1393
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
1394
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1395
  smt_status_t stat;
1396
  smt_core_t *core;
1397
  delegate_t delegate;
1398

1399
  core = ctx->core;
×
1400

1401
  stat = smt_status(core);
×
1402
  if (stat != YICES_STATUS_IDLE) {
×
1403
    return stat;
×
1404
  }
1405

1406
  start_search(core, 0, NULL);
×
1407
  smt_process(core);
×
1408
  stat = smt_status(core);
×
1409

1410
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1411
         stat == YICES_STATUS_INTERRUPTED);
1412

1413
  if (stat != YICES_STATUS_SEARCHING) {
×
1414
    return stat;
×
1415
  }
1416

1417
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
1418
    return YICES_STATUS_UNKNOWN;
×
1419
  }
1420
  delegate_set_verbosity(&delegate, verbosity);
×
1421

1422
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
1423
  set_smt_status(core, stat);
×
1424
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
1425
  if (stat == YICES_STATUS_SAT) {
×
1426
    context_import_delegate_model(core, &delegate);
×
1427
  }
1428

1429
  delete_delegate(&delegate);
×
1430
  return stat;
×
1431
}
1432

1433

1434
/*
1435
 * Bit-blast then export to DIMACS
1436
 * - filename = name of the output file
1437
 * - status = status of the context after bit-blasting
1438
 *
1439
 * If ctx status is IDLE
1440
 * - perform one round of propagation to conver the problem to CNF
1441
 * - export the CNF to DIMACS
1442
 *
1443
 * If ctx status is not IDLE,
1444
 * - store the stauts in *status and do nothing else
1445
 *
1446
 * Return code:
1447
 *  1 if the DIMACS file was created
1448
 *  0 if the problem was solved by the propagation round
1449
 * -1 if there was an error in creating or writing to the file.
1450
 */
1451
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1452
  smt_core_t *core;
1453
  FILE *f;
1454
  smt_status_t stat;
1455
  int32_t code;
1456

1457
  core = ctx->core;
×
1458

1459
  code = 0;
×
1460
  stat = smt_status(core);
×
1461
  if (stat == YICES_STATUS_IDLE) {
×
1462
    start_search(core, 0, NULL);
×
1463
    smt_process(core);
×
1464
    stat = smt_status(core);
×
1465

1466
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1467
           stat == YICES_STATUS_INTERRUPTED);
1468

1469
    if (stat == YICES_STATUS_SEARCHING) {
×
1470
      code = 1;
×
1471
      f = fopen(filename, "w");
×
1472
      if (f == NULL) {
×
1473
        code = -1;
×
1474
      } else {
1475
        dimacs_print_bvcontext(f, ctx);
×
1476
        if (ferror(f)) code = -1;
×
1477
        fclose(f);
×
1478
      }
1479
    }
1480
  }
1481

1482
  *status = stat;
×
1483

1484
  return code;
×
1485
}
1486

1487

1488
/*
1489
 * Simplify then export to Dimacs:
1490
 * - filename = name of the output file
1491
 * - status = status of the context after CNF conversion + preprocessing
1492
 *
1493
 * If ctx status is IDLE
1494
 * - perform one round of propagation to convert the problem to CNF
1495
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
1496
 *
1497
 * If ctx status is not IDLE, the function stores that in *status
1498
 * If y2sat preprocessing solves the formula, return the status also in *status
1499
 *
1500
 * Return code:
1501
 *  1 if the DIMACS file was created
1502
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
1503
 * -1 if there was an error creating or writing to the file.
1504
 */
1505
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1506
  smt_core_t *core;
1507
  FILE *f;
1508
  smt_status_t stat;
1509
  delegate_t delegate;
1510
  bvar_t x;
1511
  bval_t v;
1512
  int32_t code;
1513

1514
  core = ctx->core;
×
1515

1516
  code = 0;
×
1517
  stat = smt_status(core);
×
1518
  if (stat == YICES_STATUS_IDLE) {
×
1519
    start_search(core, 0, NULL);
×
1520
    smt_process(core);
×
1521
    stat = smt_status(core);
×
1522

1523
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1524
           stat == YICES_STATUS_INTERRUPTED);
1525

1526
    if (stat == YICES_STATUS_SEARCHING) {
×
1527
      if (smt_easy_sat(core)) {
×
1528
        stat = YICES_STATUS_SAT;
×
1529
      } else {
1530
        // call the delegate
1531
        init_delegate(&delegate, "y2sat", num_vars(core));
×
1532
        delegate_set_verbosity(&delegate, 0);
×
1533

1534
        stat = preprocess_with_delegate(&delegate, core);
×
1535
        set_smt_status(core, stat);
×
1536
        if (stat == YICES_STATUS_SAT) {
×
1537
          for (x=0; x<num_vars(core); x++) {
×
1538
            v = delegate_get_value(&delegate, x);
×
1539
            set_bvar_value(core, x, v);
×
1540
          }
1541
        } else if (stat == YICES_STATUS_UNKNOWN) {
×
1542
          code = 1;
×
1543
          f = fopen(filename, "w");
×
1544
          if (f == NULL) {
×
1545
            code = -1;
×
1546
          } else {
1547
            export_to_dimacs_with_delegate(&delegate, f);
×
1548
            if (ferror(f)) code = -1;
×
1549
            fclose(f);
×
1550
          }
1551
        }
1552

1553
        delete_delegate(&delegate);
×
1554
      }
1555
    }
1556
  }
1557

1558
  *status = stat;
×
1559

1560
  return code;
×
1561
}
1562

1563

1564

1565
/*
1566
 * MODEL CONSTRUCTION
1567
 */
1568

1569
/*
1570
 * Value of literal l in ctx->core
1571
 */
1572
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
1573
  value_t v;
1574

1575
  v = null_value; // prevent GCC warning
65,201✔
1576
  switch (literal_value(ctx->core, l)) {
65,201✔
1577
  case VAL_FALSE:
38,577✔
1578
    v = vtbl_mk_false(vtbl);
38,577✔
1579
    break;
38,577✔
1580
  case VAL_UNDEF_FALSE:
×
1581
  case VAL_UNDEF_TRUE:
1582
    v = vtbl_mk_unknown(vtbl);
×
1583
    break;
×
1584
  case VAL_TRUE:
26,624✔
1585
    v = vtbl_mk_true(vtbl);
26,624✔
1586
    break;
26,624✔
1587
  }
1588
  return v;
65,201✔
1589
}
1590

1591

1592
/*
1593
 * Value of arithmetic variable x in ctx->arith_solver
1594
 */
1595
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,590✔
1596
  rational_t *a;
1597
  value_t v;
1598

1599
  assert(context_has_arith_solver(ctx));
1600

1601
  a = &ctx->aux;
22,590✔
1602
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,590✔
1603
    v = vtbl_mk_rational(vtbl, a);
22,590✔
1604
  } else {
1605
    v = vtbl_mk_unknown(vtbl);
×
1606
  }
1607

1608
  return v;
22,590✔
1609
}
1610

1611

1612

1613
/*
1614
 * Value of bitvector variable x in ctx->bv_solver
1615
 */
1616
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,141✔
1617
  bvconstant_t *b;
1618
  value_t v;
1619

1620
  assert(context_has_bv_solver(ctx));
1621

1622
  b = &ctx->bv_buffer;
18,141✔
1623
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,141✔
1624
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,141✔
1625
  } else {
1626
    v = vtbl_mk_unknown(vtbl);
×
1627
  }
1628

1629
  return v;
18,141✔
1630
}
1631

1632

1633
/*
1634
 * Get a value for term t in the solvers or egraph
1635
 * - attach the mapping from t to that value in model
1636
 * - if we don't have a concrete object for t but t is
1637
 *   mapped to a term u and the model->has_alias is true,
1638
 *   then we store the mapping [t --> u] in the model's
1639
 *   alias map.
1640
 */
1641
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
319,935✔
1642
  value_table_t *vtbl;
1643
  term_t r;
1644
  uint32_t polarity;
1645
  int32_t x;
1646
  type_t tau;
1647
  value_t v;
1648

1649
  /*
1650
   * Get the root of t in the substitution table
1651
   */
1652
  r = intern_tbl_get_root(&ctx->intern, t);
319,935✔
1653
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
319,935✔
1654
    /*
1655
     * r is mapped to some object x in egraph/core/or theory solvers
1656
     * - keep track of polarity then force r to positive polarity
1657
     */
1658
    vtbl = model_get_vtbl(model);
110,706✔
1659
    polarity = polarity_of(r);
110,706✔
1660
    r = unsigned_term(r);
110,706✔
1661

1662
    /*
1663
     * Convert x to a concrete value
1664
     */
1665
    x = intern_tbl_map_of_root(&ctx->intern, r);
110,706✔
1666
    if (code_is_eterm(x)) {
110,706✔
1667
      // x refers to an egraph object or true_occ/false_occ
1668
      if (x == bool2code(true)) {
4,774✔
1669
        v = vtbl_mk_true(vtbl);
475✔
1670
      } else if (x == bool2code(false)) {
4,299✔
1671
        v = vtbl_mk_false(vtbl);
1,420✔
1672
      } else {
1673
        assert(context_has_egraph(ctx));
1674
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,879✔
1675
      }
1676

1677
    } else {
1678
      // x refers to a literal or a theory variable
1679
      tau = term_type(ctx->terms, r);
105,932✔
1680
      switch (type_kind(ctx->types, tau)) {
105,932✔
1681
      case BOOL_TYPE:
65,201✔
1682
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
1683
        break;
65,201✔
1684

1685
      case INT_TYPE:
22,590✔
1686
      case REAL_TYPE:
1687
        v = arith_value(ctx, vtbl, code2thvar(x));
22,590✔
1688
        break;
22,590✔
1689

1690
      case BITVECTOR_TYPE:
18,141✔
1691
        v = bv_value(ctx, vtbl, code2thvar(x));
18,141✔
1692
        break;
18,141✔
1693

1694
      default:
×
1695
        /*
1696
         * This should never happen:
1697
         * scalar, uninterpreted, tuple, function terms
1698
         * are mapped to egraph terms.
1699
         */
1700
        assert(false);
1701
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
1702
        break;
×
1703
      }
1704
    }
1705

1706
    /*
1707
     * Restore polarity then add mapping [t --> v] in the model
1708
     */
1709
    if (! object_is_unknown(vtbl, v)) {
110,706✔
1710
      if (object_is_boolean(vtbl, v)) {
110,706✔
1711
        if (polarity) {
67,096✔
1712
          // negate the value
1713
          v = vtbl_mk_not(vtbl, v);
24✔
1714
        }
1715
      }
1716
      model_map_term(model, t, v);
110,706✔
1717
    }
1718

1719
  } else {
1720
    /*
1721
     * r is not mapped to anything:
1722
     *
1723
     * 1) If t == r and t is present in the internalization table
1724
     *    then t is relevant. So we should display its value
1725
     *    when we print the model. To do this, we assign an
1726
     *    arbitrary value v to t and store [t := v] in the map.
1727
     *
1728
     * 2) If t != r then we keep the mapping [t --> r] in
1729
     *    the alias table (provided the model supports aliases).
1730
     */
1731
    if (t == r) {
209,229✔
1732
      if (intern_tbl_term_present(&ctx->intern, t)) {
208,577✔
1733
        tau = term_type(ctx->terms, t);
×
1734
        vtbl = model_get_vtbl(model);
×
1735
        v = vtbl_make_object(vtbl, tau);
×
1736
        model_map_term(model, t, v);
×
1737
      }
1738
    } else if (model->has_alias) {
652✔
1739
      // t != r: keep the substitution [t --> r] in the model
1740
      model_add_substitution(model, t, r);
652✔
1741
    }
1742
  }
1743
}
319,935✔
1744

1745

1746

1747

1748
/*
1749
 * Build a model for the current context (including all satellite solvers)
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
 * - cleanup of satellite models needed using clean_solver_models()
1754
 */
1755
void build_model(model_t *model, context_t *ctx) {
42,155✔
1756
  term_table_t *terms;
1757
  uint32_t i, n;
1758
  term_t t;
1759

1760
  assert(smt_status(ctx->core) == YICES_STATUS_SAT ||
1761
         smt_status(ctx->core) == YICES_STATUS_UNKNOWN ||
1762
         (context_has_mcsat(ctx) && mcsat_status(ctx->mcsat) == YICES_STATUS_SAT));
1763

1764
  /*
1765
   * First build assignments in the satellite solvers
1766
   * and get the val_in_model functions for the egraph
1767
   */
1768
  if (context_has_arith_solver(ctx)) {
42,155✔
1769
    ctx->arith.build_model(ctx->arith_solver);
32,912✔
1770
  }
1771
  if (context_has_bv_solver(ctx)) {
42,155✔
1772
    ctx->bv.build_model(ctx->bv_solver);
21,410✔
1773
  }
1774

1775
  /*
1776
   * Construct the egraph model
1777
   */
1778
  if (context_has_egraph(ctx)) {
42,155✔
1779
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,038✔
1780
  }
1781

1782
  /*
1783
   * Construct the mcsat model.
1784
   */
1785
  if (context_has_mcsat(ctx)) {
42,155✔
1786
    mcsat_build_model(ctx->mcsat, model);
51✔
1787
  }
1788

1789
  // scan the internalization table
1790
  terms = ctx->terms;
42,155✔
1791
  n = intern_tbl_num_terms(&ctx->intern);
42,155✔
1792
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,096,441✔
1793
    if (good_term_idx(terms, i)) {
1,235,054,286✔
1794
      t = pos_occ(i);
1,235,054,286✔
1795
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,054,286✔
1796
        build_term_value(ctx, model, t);
319,935✔
1797
      }
1798
    }
1799
  }
1800

1801
  /*
1802
   * Supplemental MCSAT values are an overlay: apply them after the regular
1803
   * CDCL(T) model is fully built so nonlinear/FF values are not overwritten.
1804
   */
1805
  if (ctx->mcsat_supplement_active && context_has_egraph(ctx) && ctx->egraph->th[ETYPE_MCSAT] != NULL) {
42,155✔
1806
    mcsat_satellite_build_model((mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT], model);
3✔
1807
  }
1808
}
42,155✔
1809

1810

1811
/*
1812
 * Cleanup solver models
1813
 */
1814
void clean_solver_models(context_t *ctx) {
42,155✔
1815
  if (context_has_arith_solver(ctx)) {
42,155✔
1816
    ctx->arith.free_model(ctx->arith_solver);
32,912✔
1817
  }
1818
  if (context_has_bv_solver(ctx)) {
42,155✔
1819
    ctx->bv.free_model(ctx->bv_solver);
21,410✔
1820
  }
1821
  if (context_has_egraph(ctx)) {
42,155✔
1822
    egraph_free_model(ctx->egraph);
13,038✔
1823
  }
1824
}
42,155✔
1825

1826

1827

1828
/*
1829
 * Build a model for the current context
1830
 * - the context status must be SAT (or UNKNOWN)
1831
 * - if model->has_alias is true, we store the term substitution
1832
 *   defined by ctx->intern_tbl into the model
1833
 */
1834
void context_build_model(model_t *model, context_t *ctx) {
254✔
1835
  // Build solver models and term values
1836
  build_model(model, ctx);
254✔
1837

1838
  // Cleanup
1839
  clean_solver_models(ctx);
254✔
1840
}
254✔
1841

1842

1843

1844
/*
1845
 * Read the value of a Boolean term t
1846
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
1847
 */
1848
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
1849
  term_t r;
1850
  uint32_t polarity;
1851
  int32_t x;
1852
  bval_t v;
1853

1854
  assert(is_boolean_term(ctx->terms, t));
1855

1856
  // default value if t is not in the internalization table
1857
  v = VAL_UNDEF_FALSE;
×
1858
  r = intern_tbl_get_root(&ctx->intern, t);
×
1859
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
1860
    // r is mapped to some object x
1861
    polarity = polarity_of(r);
×
1862
    r = unsigned_term(r);
×
1863

1864
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
1865
    if (code_is_eterm(x)) {
×
1866
      // x must be either true_occ or false_occ
1867
      if (x == bool2code(true)) {
×
1868
        v = VAL_TRUE;
×
1869
      } else {
1870
        assert(x == bool2code(false));
1871
        v = VAL_FALSE;
×
1872
      }
1873
    } else {
1874
      // x refers to a literal in the smt core
1875
      v = literal_value(ctx->core, code2literal(x));
×
1876
    }
1877

1878
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
1879
    v ^= polarity;
×
1880
  }
1881

1882
  return v;
×
1883
}
1884

1885

1886
/*
1887
 * UNSAT CORE
1888
 */
1889

1890
/*
1891
 * Build an unsat core:
1892
 * - store the result in v
1893
 * - first reuse a cached term core if available.
1894
 * - otherwise:
1895
 *   CDCL(T): build from smt_core then cache as terms
1896
 *   MCSAT: return empty unless check-with-term-assumptions populated the cache.
1897
 */
1898
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
2,706✔
1899
  smt_core_t *core;
1900
  uint32_t i, n;
1901
  term_t t;
1902

1903
  if (ctx->unsat_core_cache != NULL) {
2,706✔
1904
    // Fast path: repeated get_unsat_core returns the cached term vector.
1905
    ivector_reset(v);
5✔
1906
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
5✔
1907
    return;
5✔
1908
  }
1909

1910
  if (ctx->mcsat != NULL) {
2,701✔
1911
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
1912
    // there is no generic context-level core structure to rebuild from here.
1913
    ivector_reset(v);
×
1914
    return;
×
1915
  }
1916

1917
  core = ctx->core;
2,701✔
1918
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
1919
  build_unsat_core(core, v);
2,701✔
1920

1921
  // convert from literals to terms
1922
  n = v->size;
2,701✔
1923
  for (i=0; i<n; i++) {
37,505✔
1924
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,804✔
1925
    assert(t >= 0);
1926
    v->data[i] = t;
34,804✔
1927
  }
1928

1929
  // Cache the converted term core for subsequent queries.
1930
  cache_unsat_core(ctx, v);
2,701✔
1931
}
1932

1933

1934
/*
1935
 * MODEL INTERPOLANT
1936
 */
1937
term_t context_get_unsat_model_interpolant(context_t *ctx) {
61✔
1938
  if (ctx->mcsat != NULL) {
61✔
1939
    return mcsat_get_unsat_model_interpolant(ctx->mcsat);
61✔
1940
  }
1941

NEW
1942
  if (ctx->mcsat_supplement_active && ctx->egraph != NULL && ctx->egraph->th[ETYPE_MCSAT] != NULL) {
×
NEW
1943
    return mcsat_satellite_get_unsat_model_interpolant((mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT]);
×
1944
  }
1945

NEW
1946
  if (context_supports_model_interpolation(ctx) &&
×
NEW
1947
      ctx->core != NULL &&
×
NEW
1948
      smt_status(ctx->core) == YICES_STATUS_UNSAT) {
×
NEW
1949
    return false_term;
×
1950
  }
1951

NEW
1952
  return NULL_TERM;
×
1953
}
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