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

SRI-CSL / yices2 / 26234961786

21 May 2026 03:14PM UTC coverage: 67.559% (+0.1%) from 67.453%
26234961786

Pull #611

github

disteph
Serialize supplemental MCSAT satellite entry points

Supported by Codex/GPT5.5 and Windsurf/Opus4.7
Pull Request #611: Wrap MCSAT as a Nelson-Oppen theory solver in CDCL(T) architecture

903 of 1349 new or added lines in 17 files covered. (66.94%)

2 existing lines in 2 files now uncovered.

86771 of 128437 relevant lines covered (67.56%)

1608322.57 hits per line

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

77.41
/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
#include <string.h>
32

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

49
#include "api/yices_globals.h"
50
#include "api/yices_api_lock_free.h"
51
#include "mt/thread_macros.h"
52

53

54

55
/*
56
 * TRACE FUNCTIONS
57
 */
58

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

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

84

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

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

96

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

105

106

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

115

116

117
/*
118
 * PROCESS AN ASSUMPTION
119
 */
120

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

135
  case VAL_TRUE:
×
136
    break;
×
137

138
  case VAL_FALSE:
2,567✔
139
    save_conflicting_assumption(core, l);
2,567✔
140
    break;
2,567✔
141
  }
142
}
86,740✔
143

144

145
/*
146
 * MAIN SEARCH FUNCTIONS
147
 */
148

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

162
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
163

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

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

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

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

197
  *reduce_threshold = r_threshold;
13,439✔
198
}
13,439✔
199

200

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

216
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
217

218
  max_conflicts = num_conflicts(core) + conflict_bound;
13,462✔
219
  r_threshold = *reduce_threshold;
13,462✔
220

221
  smt_bounded_process(core, max_conflicts);
13,462✔
222
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) < max_conflicts) {
679,643✔
223
    // reduce heuristic
224
    if (num_learned_clauses(core) >= r_threshold) {
666,181✔
225
      deletions = core->stats.learned_clauses_deleted;
50✔
226
      reduce_clause_database(core);
50✔
227
      r_threshold = (uint32_t) (r_threshold * r_factor);
50✔
228
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
50✔
229
    }
230

231
    // assumption
232
    if (core->has_assumptions) {
666,181✔
233
      l = get_next_assumption(core);
97,964✔
234
      if (l != null_literal) {
97,964✔
235
        process_assumption(core, l);
86,731✔
236
        continue;
86,731✔
237
      }
238
    }
239

240
    // decision
241
    l = select_unassigned_literal(core);
579,450✔
242
    if (l == null_literal) {
579,450✔
243
      // all variables assigned: Call final_check
244
      smt_final_check(core);
8,803✔
245
    } else {
246
      decide_literal(core, l);
570,647✔
247
      smt_bounded_process(core, max_conflicts);
570,647✔
248
    }
249
  }
250

251
  *reduce_threshold = r_threshold;
13,462✔
252
}
13,462✔
253

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

260

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

275
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
276

277
  max_conflicts = num_conflicts(core) + conflict_bound;
20,857✔
278
  r_threshold = *reduce_threshold;
20,857✔
279

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

290
    // assumption
291
    if (core->has_assumptions) {
612,379✔
292
      l = get_next_assumption(core);
4✔
293
      if (l != null_literal) {
4✔
294
        process_assumption(core, l);
4✔
295
        continue;
4✔
296
      }
297
    }
298

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

313
  *reduce_threshold = r_threshold;
20,857✔
314
}
20,857✔
315

316

317

318

319

320
/*
321
 * SUPPORTED BRANCHING
322
 */
323

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

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

337

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

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

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

365

366

367

368

369
/*
370
 * CORE SOLVER
371
 */
372

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

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

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

399
  reduce_threshold = (uint32_t) (num_prob_clauses(core) * params->r_fraction);
45,424✔
400
  if (reduce_threshold < params->r_threshold) {
45,424✔
401
    reduce_threshold = params->r_threshold;
45,393✔
402
  }
403

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

435
      if (smt_status(core) != YICES_STATUS_SEARCHING) break;
47,758✔
436

437
      smt_restart(core);
2,334✔
438
      //      smt_partial_restart_var(core);
439

440
      if (luby) {
2,334✔
441
        // Luby-style restart
442
        if ((u & -u) == v) {
1,953✔
443
          u ++;
1,057✔
444
          v = 1;
1,057✔
445
        } else {
446
          v <<= 1;
896✔
447
        }
448
        c_threshold = v * period;
1,953✔
449
        trace_restart(core);
1,953✔
450

451
      } else {
452
        // Either Minisat or Picosat-like restart
453

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

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

473
  trace_done(core);
45,424✔
474
}
45,424✔
475

476

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

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

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

531
  if (ctx->mcsat_supplement && egraph != NULL && egraph->th[ETYPE_MCSAT] != NULL) {
45,424✔
532
    mcsat_satellite_set_search_parameters((mcsat_satellite_t *) egraph->th[ETYPE_MCSAT], params);
8✔
533
  }
534

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

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

564
static smt_status_t _o_call_mcsat_solver(context_t *ctx, const param_t *params) {
1,138✔
565
  smt_status_t stat;
566

567
  mcsat_solve(ctx->mcsat, params, NULL, 0, NULL);
1,138✔
568
  stat = mcsat_status(ctx->mcsat);
1,138✔
569

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

580
  return stat;
1,138✔
581
}
582

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

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

597
  if (params == NULL) {
60,718✔
598
    params = get_default_params();
×
599
  }
600

601
  if (ctx->mcsat != NULL) {
60,718✔
602
    return call_mcsat_solver(ctx, params);
1,138✔
603
  }
604

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

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

627
  return stat;
59,580✔
628
}
629

630

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

640
  assert(ctx->mcsat == NULL);
641

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

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

667
  return stat;
2,669✔
668
}
669

670
typedef struct sat_delegate_state_s {
671
  delegate_t delegate;
672
  sat_delegate_t mode;
673
  sat_delegate_incremental_mode_t exec_mode;
674
  bool live;
675
  bool stale;
676
  bool true_forwarded;
677
  bool checked_once;
678
  uint32_t delegate_nvars;
679
  uint32_t size;
680
  bvar_t *act_var;
681
  uint32_t *fwd_units;
682
  uint32_t *fwd_bins;
683
  uint32_t *fwd_clauses;
684
  ivector_t assumptions;
685
  ivector_t failed;
686
} sat_delegate_state_t;
687

688
void context_reset_sat_delegate_stats(context_t *ctx) {
22,435✔
689
  ctx->sat_delegate_stats.rebuild_checks = 0;
22,435✔
690
  ctx->sat_delegate_stats.append_checks = 0;
22,435✔
691
  ctx->sat_delegate_stats.selector_frame_checks = 0;
22,435✔
692
  ctx->sat_delegate_stats.delegate_initializations = 0;
22,435✔
693
  ctx->sat_delegate_stats.delegate_reinitializations = 0;
22,435✔
694
  ctx->sat_delegate_stats.selector_variables = 0;
22,435✔
695
  ctx->sat_delegate_stats.selector_assumptions = 0;
22,435✔
696
  ctx->sat_delegate_stats.selector_retirements = 0;
22,435✔
697
  ctx->sat_delegate_stats.post_check_clause_forwards = 0;
22,435✔
698
}
22,435✔
699

700
void context_get_sat_delegate_stats(const context_t *ctx, sat_delegate_stats_t *stats) {
10✔
701
  *stats = ctx->sat_delegate_stats;
10✔
702
}
10✔
703

704
void context_sat_delegate_state_cleanup(context_t *ctx) {
22,434✔
705
  sat_delegate_state_t *st;
706

707
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
22,434✔
708
  if (st == NULL) {
22,434✔
709
    return;
22,427✔
710
  }
711

712
  if (st->live) {
7✔
713
    delete_delegate(&st->delegate);
7✔
714
    st->live = false;
7✔
715
  }
716
  safe_free(st->act_var);
7✔
717
  safe_free(st->fwd_units);
7✔
718
  safe_free(st->fwd_bins);
7✔
719
  safe_free(st->fwd_clauses);
7✔
720
  delete_ivector(&st->assumptions);
7✔
721
  delete_ivector(&st->failed);
7✔
722
  safe_free(st);
7✔
723
  ctx->sat_delegate_state = NULL;
7✔
724
}
725

726
static sat_delegate_state_t *context_get_sat_delegate_state(context_t *ctx) {
39✔
727
  sat_delegate_state_t *st;
728

729
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
39✔
730
  if (st == NULL) {
39✔
731
    st = (sat_delegate_state_t *) safe_malloc(sizeof(sat_delegate_state_t));
7✔
732
    st->mode = SAT_DELEGATE_NONE;
7✔
733
    st->exec_mode = SAT_DELEGATE_MODE_REBUILD;
7✔
734
    st->live = false;
7✔
735
    st->stale = false;
7✔
736
    st->true_forwarded = false;
7✔
737
    st->checked_once = false;
7✔
738
    st->delegate_nvars = 0;
7✔
739
    st->size = 0;
7✔
740
    st->act_var = NULL;
7✔
741
    st->fwd_units = NULL;
7✔
742
    st->fwd_bins = NULL;
7✔
743
    st->fwd_clauses = NULL;
7✔
744
    init_ivector(&st->assumptions, 0);
7✔
745
    init_ivector(&st->failed, 0);
7✔
746
    ctx->sat_delegate_state = st;
7✔
747
  }
748
  return st;
39✔
749
}
750

751
static void sat_delegate_state_reset_cursors(sat_delegate_state_t *st) {
9✔
752
  uint32_t i;
753

754
  st->true_forwarded = false;
9✔
755
  for (i=0; i<st->size; i++) {
81✔
756
    st->act_var[i] = 0;
72✔
757
    st->fwd_units[i] = 0;
72✔
758
    st->fwd_bins[i] = 0;
72✔
759
    st->fwd_clauses[i] = 0;
72✔
760
  }
761
}
9✔
762

763
static void sat_delegate_state_grow(sat_delegate_state_t *st, uint32_t min_size) {
47✔
764
  uint32_t old_size, new_size, i;
765

766
  if (st->size > min_size) {
47✔
767
    return;
40✔
768
  }
769

770
  old_size = st->size;
7✔
771
  new_size = old_size == 0 ? 8 : old_size;
7✔
772
  while (new_size <= min_size) {
7✔
773
    new_size <<= 1;
×
774
  }
775

776
  st->act_var = (bvar_t *) safe_realloc(st->act_var, new_size * sizeof(bvar_t));
7✔
777
  st->fwd_units = (uint32_t *) safe_realloc(st->fwd_units, new_size * sizeof(uint32_t));
7✔
778
  st->fwd_bins = (uint32_t *) safe_realloc(st->fwd_bins, new_size * sizeof(uint32_t));
7✔
779
  st->fwd_clauses = (uint32_t *) safe_realloc(st->fwd_clauses, new_size * sizeof(uint32_t));
7✔
780
  for (i=old_size; i<new_size; i++) {
63✔
781
    st->act_var[i] = 0;
56✔
782
    st->fwd_units[i] = 0;
56✔
783
    st->fwd_bins[i] = 0;
56✔
784
    st->fwd_clauses[i] = 0;
56✔
785
  }
786
  st->size = new_size;
7✔
787
}
788

789
static void context_import_delegate_model(smt_core_t *core, delegate_t *d) {
34✔
790
  bvar_t x;
791

792
  for (x=0; x<num_vars(core); x++) {
1,010✔
793
    set_bvar_value(core, x, delegate_get_value(d, x));
976✔
794
  }
795
}
34✔
796

797
static void set_delegate_assumption_state(smt_core_t *core, uint32_t n, const literal_t *assumptions,
39✔
798
                                          smt_status_t stat, const ivector_t *failed) {
799
  if (n == 0) {
39✔
800
    core->has_assumptions = false;
×
801
    core->num_assumptions = 0;
×
802
    core->assumption_index = 0;
×
803
    core->assumptions = NULL;
×
804
    core->bad_assumption = null_literal;
×
805
    return;
×
806
  }
807

808
  core->has_assumptions = true;
39✔
809
  core->num_assumptions = n;
39✔
810
  core->assumption_index = n;
39✔
811
  core->assumptions = NULL;
39✔
812
  core->bad_assumption = null_literal;
39✔
813

814
  if (stat == YICES_STATUS_UNSAT && failed != NULL && failed->size > 0) {
39✔
815
    core->bad_assumption = failed->data[0];
5✔
816
  }
817
}
818

819
static void delegate_add_clause_with_guard(delegate_t *delegate, const clause_t *c, literal_t guard) {
1✔
820
  uint32_t i;
821
  literal_t l;
822

823
  ivector_reset(&delegate->buffer);
1✔
824
  if (guard != true_literal) {
1✔
825
    ivector_push(&delegate->buffer, guard);
×
826
  }
827
  i = 0;
1✔
828
  l = c->cl[0];
1✔
829
  while (l >= 0) {
10✔
830
    ivector_push(&delegate->buffer, l);
9✔
831
    i ++;
9✔
832
    l = c->cl[i];
9✔
833
  }
834
  delegate->add_clause(delegate->solver, delegate->buffer.size, delegate->buffer.data);
1✔
835
}
1✔
836

837
static void delegate_forward_clause_range(sat_delegate_state_t *st, smt_core_t *core, sat_delegate_stats_t *stats,
68✔
838
                                          uint32_t level,
839
                                          uint32_t end_units, uint32_t end_bins, uint32_t end_clauses,
840
                                          literal_t guard) {
841
  uint32_t i;
842
  bool forwarded;
843

844
  if (!st->true_forwarded) {
68✔
845
    st->delegate.add_unit_clause(st->delegate.solver, true_literal);
8✔
846
    st->true_forwarded = true;
8✔
847
  }
848

849
  forwarded = (core->inconsistent && st->fwd_units[level] == 0 && st->fwd_bins[level] == 0 && st->fwd_clauses[level] == 0) ||
×
850
              st->fwd_units[level] < end_units ||
68✔
851
              st->fwd_bins[level] < end_bins ||
168✔
852
              st->fwd_clauses[level] < end_clauses;
32✔
853
  if (st->checked_once && forwarded) {
68✔
854
    stats->post_check_clause_forwards ++;
28✔
855
  }
856

857
  if (core->inconsistent && st->fwd_units[level] == 0 && st->fwd_bins[level] == 0 && st->fwd_clauses[level] == 0) {
68✔
858
    if (guard == true_literal) {
×
859
      st->delegate.add_empty_clause(st->delegate.solver);
×
860
    } else {
861
      st->delegate.add_unit_clause(st->delegate.solver, guard);
×
862
    }
863
  }
864

865
  for (i=st->fwd_units[level]; i<end_units; i++) {
330✔
866
    if (guard == true_literal) {
262✔
867
      st->delegate.add_unit_clause(st->delegate.solver, core->stack.lit[i]);
41✔
868
    } else {
869
      st->delegate.add_binary_clause(st->delegate.solver, guard, core->stack.lit[i]);
221✔
870
    }
871
  }
872
  st->fwd_units[level] = end_units;
68✔
873

874
  for (i=st->fwd_bins[level]; i<end_bins; i += 2) {
356✔
875
    if (guard == true_literal) {
288✔
876
      st->delegate.add_binary_clause(st->delegate.solver, core->binary_clauses.data[i], core->binary_clauses.data[i+1]);
55✔
877
    } else {
878
      st->delegate.add_ternary_clause(st->delegate.solver, guard, core->binary_clauses.data[i], core->binary_clauses.data[i+1]);
233✔
879
    }
880
  }
881
  st->fwd_bins[level] = end_bins;
68✔
882

883
  if (level == 0 && st->fwd_clauses[level] > end_clauses) {
68✔
884
    st->fwd_clauses[level] = end_clauses;
×
885
  }
886
  for (i=st->fwd_clauses[level]; i<end_clauses; i++) {
69✔
887
    delegate_add_clause_with_guard(&st->delegate, core->problem_clauses[i], guard);
1✔
888
  }
889
  st->fwd_clauses[level] = end_clauses;
68✔
890
}
68✔
891

892
static void sat_delegate_state_close(sat_delegate_state_t *st) {
1✔
893
  if (st->live) {
1✔
894
    delete_delegate(&st->delegate);
1✔
895
    st->live = false;
1✔
896
  }
897
  st->mode = SAT_DELEGATE_NONE;
1✔
898
  st->exec_mode = SAT_DELEGATE_MODE_REBUILD;
1✔
899
  st->stale = false;
1✔
900
  st->checked_once = false;
1✔
901
  st->delegate_nvars = 0;
1✔
902
  sat_delegate_state_reset_cursors(st);
1✔
903
}
1✔
904

905
static bool context_prepare_append_delegate(context_t *ctx, sat_delegate_state_t *st, const char *sat_solver,
5✔
906
                                            uint32_t verbosity) {
907
  smt_core_t *core;
908
  uint32_t nvars;
909
  uint32_t nnew;
910

911
  core = ctx->core;
5✔
912
  nvars = num_vars(core);
5✔
913

914
  if (st->live && (st->mode != ctx->sat_delegate || st->exec_mode != SAT_DELEGATE_MODE_APPEND)) {
5✔
915
    sat_delegate_state_close(st);
×
916
  }
917

918
  if (!st->live || st->stale) {
5✔
919
    if (st->live) {
3✔
920
      ctx->sat_delegate_stats.delegate_reinitializations ++;
1✔
921
      sat_delegate_state_close(st);
1✔
922
    }
923
    sat_delegate_state_grow(st, 0);
3✔
924
    if (!init_delegate_incremental(&st->delegate, sat_solver, nvars)) {
3✔
925
      return false;
×
926
    }
927
    ctx->sat_delegate_stats.delegate_initializations ++;
3✔
928
    delegate_set_verbosity(&st->delegate, verbosity);
3✔
929
    st->mode = ctx->sat_delegate;
3✔
930
    st->exec_mode = SAT_DELEGATE_MODE_APPEND;
3✔
931
    st->stale = false;
3✔
932
    st->delegate_nvars = nvars;
3✔
933
    st->live = true;
3✔
934
    sat_delegate_state_reset_cursors(st);
3✔
935
  }
936

937
  if (st->delegate_nvars < nvars) {
5✔
938
    nnew = nvars - st->delegate_nvars;
2✔
939
    delegate_add_vars(&st->delegate, nnew);
2✔
940
    st->delegate_nvars = nvars;
2✔
941
  }
942

943
  sat_delegate_state_grow(st, 0);
5✔
944
  delegate_forward_clause_range(st, core, &ctx->sat_delegate_stats, 0, core->nb_unit_clauses,
5✔
945
                                (uint32_t) core->binary_clauses.size,
5✔
946
                                (uint32_t) get_cv_size(core->problem_clauses),
5✔
947
                                true_literal);
948

949
  return true;
5✔
950
}
951

952
static bool context_prepare_selector_delegate(context_t *ctx, sat_delegate_state_t *st, const char *sat_solver,
34✔
953
                                              uint32_t verbosity) {
954
  smt_core_t *core;
955
  uint32_t d, k, nvars, nnew;
956
  uint32_t end_units, end_bins, end_clauses;
957
  trail_t *trail_data;
958
  literal_t guard;
959

960
  core = ctx->core;
34✔
961
  nvars = num_vars(core);
34✔
962
  d = smt_base_level(core);
34✔
963
  trail_data = core->trail_stack.data;
34✔
964

965
  if (st->live && (st->mode != ctx->sat_delegate || st->exec_mode != SAT_DELEGATE_MODE_SELECTOR_FRAMES)) {
34✔
966
    sat_delegate_state_close(st);
×
967
  }
968

969
  if (!st->live) {
34✔
970
    sat_delegate_state_grow(st, d);
5✔
971
    if (!init_delegate_incremental(&st->delegate, sat_solver, nvars)) {
5✔
972
      return false;
×
973
    }
974
    ctx->sat_delegate_stats.delegate_initializations ++;
5✔
975
    delegate_set_verbosity(&st->delegate, verbosity);
5✔
976
    st->mode = ctx->sat_delegate;
5✔
977
    st->exec_mode = SAT_DELEGATE_MODE_SELECTOR_FRAMES;
5✔
978
    st->stale = false;
5✔
979
    st->delegate_nvars = nvars;
5✔
980
    st->live = true;
5✔
981
    sat_delegate_state_reset_cursors(st);
5✔
982
  }
983

984
  if (st->delegate_nvars < nvars) {
34✔
985
    nnew = nvars - st->delegate_nvars;
2✔
986
    delegate_add_vars(&st->delegate, nnew);
2✔
987
    st->delegate_nvars = nvars;
2✔
988
  }
989

990
  sat_delegate_state_grow(st, d);
34✔
991
  for (k=1; k<=d; k++) {
63✔
992
    if (st->act_var[k] == 0) {
29✔
993
      /*
994
       * Selectors must live in the SMT core's variable namespace too:
995
       * otherwise a later bit-blasted assertion could reuse the same bvar.
996
       */
997
      do {
998
        st->act_var[k] = create_boolean_variable(core);
303✔
999
      } while (st->act_var[k] < st->delegate_nvars);
303✔
1000
      delegate_add_vars(&st->delegate, st->act_var[k] + 1 - st->delegate_nvars);
27✔
1001
      delegate_freeze_literal(&st->delegate, pos_lit(st->act_var[k]));
27✔
1002
      ctx->sat_delegate_stats.selector_variables ++;
27✔
1003
      st->delegate_nvars = st->act_var[k] + 1;
27✔
1004
      st->fwd_units[k] = trail_data[k-1].nunits;
27✔
1005
      st->fwd_bins[k] = trail_data[k-1].nbins;
27✔
1006
      st->fwd_clauses[k] = trail_data[k-1].nclauses;
27✔
1007
    }
1008
  }
1009

1010
  for (k=0; k<=d; k++) {
97✔
1011
    guard = (k == 0) ? true_literal : neg_lit(st->act_var[k]);
63✔
1012
    end_units = (k < d) ? trail_data[k].nunits : core->nb_unit_clauses;
63✔
1013
    end_bins = (k < d) ? trail_data[k].nbins : (uint32_t) core->binary_clauses.size;
63✔
1014
    end_clauses = (k < d) ? trail_data[k].nclauses : (uint32_t) get_cv_size(core->problem_clauses);
63✔
1015
    delegate_forward_clause_range(st, core, &ctx->sat_delegate_stats, k, end_units, end_bins, end_clauses, guard);
63✔
1016
  }
1017

1018
  return true;
34✔
1019
}
1020

1021
void context_sat_delegate_state_pop(context_t *ctx, uint32_t level) {
1,574✔
1022
  sat_delegate_state_t *st;
1023

1024
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
1,574✔
1025
  if (st == NULL || !st->live) {
1,574✔
1026
    return;
1,548✔
1027
  }
1028

1029
  if (st->exec_mode == SAT_DELEGATE_MODE_APPEND) {
26✔
1030
    st->stale = true;
1✔
1031
  } else if (st->exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES) {
25✔
1032
    if (level < st->size && st->act_var[level] != 0) {
25✔
1033
      delegate_melt_literal(&st->delegate, pos_lit(st->act_var[level]));
25✔
1034
      st->delegate.add_unit_clause(st->delegate.solver, neg_lit(st->act_var[level]));
25✔
1035
      ctx->sat_delegate_stats.selector_retirements ++;
25✔
1036
      st->act_var[level] = 0;
25✔
1037
    }
1038
  }
1039
}
1040

1041
static smt_status_t check_with_persistent_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity,
54✔
1042
                                                   sat_delegate_incremental_mode_t exec_mode,
1043
                                                   uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1044
  smt_status_t stat;
1045
  smt_core_t *core;
1046
  sat_delegate_state_t *st;
1047
  ivector_t visible_failed;
1048
  uint32_t i;
1049

1050
  core = ctx->core;
54✔
1051
  stat = smt_status(core);
54✔
1052
  if (stat != YICES_STATUS_IDLE) {
54✔
1053
    return stat;
×
1054
  }
1055

1056
  start_search(core, 0, NULL);
54✔
1057
  smt_process(core);
54✔
1058
  stat = smt_status(core);
54✔
1059

1060
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1061
         stat == YICES_STATUS_INTERRUPTED);
1062

1063
  if (stat != YICES_STATUS_SEARCHING) {
54✔
1064
    return stat;
×
1065
  }
1066

1067
  if (n == 0 && smt_easy_sat(core)) {
54✔
1068
    stat = YICES_STATUS_SAT;
15✔
1069
    set_smt_status(core, stat);
15✔
1070
    return stat;
15✔
1071
  }
1072

1073
  st = context_get_sat_delegate_state(ctx);
39✔
1074
  if (exec_mode == SAT_DELEGATE_MODE_APPEND) {
39✔
1075
    if (!context_prepare_append_delegate(ctx, st, sat_solver, verbosity)) {
5✔
1076
      return YICES_STATUS_UNKNOWN;
×
1077
    }
1078
  } else {
1079
    assert(exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES);
1080
    if (!context_prepare_selector_delegate(ctx, st, sat_solver, verbosity)) {
34✔
1081
      return YICES_STATUS_UNKNOWN;
×
1082
    }
1083
  }
1084

1085
  if (n > 0 && !delegate_supports_assumptions(&st->delegate)) {
39✔
1086
    return YICES_STATUS_UNKNOWN;
×
1087
  }
1088

1089
  init_ivector(&visible_failed, 0);
39✔
1090
  ivector_reset(&st->assumptions);
39✔
1091
  ivector_reset(&st->failed);
39✔
1092
  if (exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES) {
39✔
1093
    uint32_t k, d;
1094
    d = smt_base_level(core);
34✔
1095
    for (k=1; k<=d; k++) {
63✔
1096
      if (k < st->size && st->act_var[k] != 0) {
29✔
1097
        ivector_push(&st->assumptions, pos_lit(st->act_var[k]));
29✔
1098
        ctx->sat_delegate_stats.selector_assumptions ++;
29✔
1099
      }
1100
    }
1101
  }
1102
  for (i=0; i<n; i++) {
79✔
1103
    ivector_push(&st->assumptions, assumptions[i]);
40✔
1104
  }
1105

1106
  if (st->assumptions.size == 0) {
39✔
1107
    stat = st->delegate.check(st->delegate.solver);
×
1108
  } else if (delegate_supports_assumptions(&st->delegate)) {
39✔
1109
    stat = delegate_check_with_assumptions(&st->delegate, st->assumptions.size,
39✔
1110
                                           (literal_t *) st->assumptions.data, &st->failed);
39✔
1111
    if (stat == YICES_STATUS_UNSAT) {
39✔
1112
      for (i=0; i<st->failed.size; i++) {
14✔
1113
        literal_t l = st->failed.data[i];
9✔
1114
        uint32_t j;
1115
        for (j=0; j<n; j++) {
13✔
1116
          if (l == assumptions[j]) {
10✔
1117
            ivector_push(&visible_failed, l);
6✔
1118
            break;
6✔
1119
          }
1120
        }
1121
      }
1122
      if (failed != NULL) {
5✔
1123
        ivector_reset(failed);
5✔
1124
        ivector_add(failed, visible_failed.data, visible_failed.size);
5✔
1125
      }
1126
    }
1127
  } else {
1128
    stat = YICES_STATUS_UNKNOWN;
×
1129
  }
1130

1131
  set_smt_status(core, stat);
39✔
1132
  set_delegate_assumption_state(core, n, assumptions, stat, &visible_failed);
39✔
1133
  if (stat == YICES_STATUS_SAT) {
39✔
1134
    context_import_delegate_model(core, &st->delegate);
34✔
1135
  }
1136
  st->checked_once = true;
39✔
1137

1138
  delete_ivector(&visible_failed);
39✔
1139
  return stat;
39✔
1140
}
1141

1142
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
1143
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed);
1144

1145
smt_status_t check_with_sat_delegate(context_t *ctx, const char *sat_solver,
92✔
1146
                                     sat_delegate_incremental_mode_t mode,
1147
                                     uint32_t verbosity, uint32_t n,
1148
                                     const literal_t *assumptions, ivector_t *failed) {
1149
  switch (mode) {
92✔
1150
  case SAT_DELEGATE_MODE_REBUILD:
38✔
1151
    ctx->sat_delegate_stats.rebuild_checks ++;
38✔
1152
    if (n == 0) {
38✔
1153
      return check_with_delegate(ctx, sat_solver, verbosity);
38✔
1154
    } else {
1155
      return check_with_delegate_assumptions(ctx, sat_solver, verbosity, n, assumptions, failed);
×
1156
    }
1157

1158
  case SAT_DELEGATE_MODE_APPEND:
12✔
1159
    ctx->sat_delegate_stats.append_checks ++;
12✔
1160
    return check_with_persistent_delegate(ctx, sat_solver, verbosity, SAT_DELEGATE_MODE_APPEND,
12✔
1161
                                          n, assumptions, failed);
1162

1163
  case SAT_DELEGATE_MODE_SELECTOR_FRAMES:
42✔
1164
    ctx->sat_delegate_stats.selector_frame_checks ++;
42✔
1165
    return check_with_persistent_delegate(ctx, sat_solver, verbosity, SAT_DELEGATE_MODE_SELECTOR_FRAMES,
42✔
1166
                                          n, assumptions, failed);
1167

1168
  default:
×
1169
    return YICES_STATUS_UNKNOWN;
×
1170
  }
1171
}
1172

1173
/*
1174
 * Explore term t and collect all Boolean atoms into atoms.
1175
 */
1176
static void collect_boolean_atoms(context_t *ctx, term_t t, int_hset_t *atoms, int_hset_t *visited) {
64✔
1177
  term_table_t *terms;
1178
  uint32_t i, nchildren;
1179

1180
  if (t < 0) {
64✔
1181
    t = not(t);
×
1182
  }
1183

1184
  if (int_hset_member(visited, t)) {
64✔
1185
    return;
×
1186
  }
1187
  int_hset_add(visited, t);
64✔
1188

1189
  terms = ctx->terms;
64✔
1190
  if (term_type(terms, t) == bool_type(terms->types)) {
64✔
1191
    int_hset_add(atoms, t);
64✔
1192
  }
1193

1194
  if (term_is_projection(terms, t)) {
64✔
1195
    collect_boolean_atoms(ctx, proj_term_arg(terms, t), atoms, visited);
×
1196
  } else if (term_is_sum(terms, t)) {
64✔
1197
    nchildren = term_num_children(terms, t);
×
1198
    for (i=0; i<nchildren; i++) {
×
1199
      term_t child;
1200
      mpq_t q;
1201
      mpq_init(q);
×
1202
      sum_term_component(terms, t, i, q, &child);
×
1203
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1204
      mpq_clear(q);
×
1205
    }
1206
  } else if (term_is_bvsum(terms, t)) {
64✔
1207
    uint32_t nbits = term_bitsize(terms, t);
×
1208
    int32_t *aux = (int32_t*) safe_malloc(nbits * sizeof(int32_t));
×
1209
    nchildren = term_num_children(terms, t);
×
1210
    for (i=0; i<nchildren; i++) {
×
1211
      term_t child;
1212
      bvsum_term_component(terms, t, i, aux, &child);
×
1213
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1214
    }
1215
    safe_free(aux);
×
1216
  } else if (term_is_product(terms, t)) {
64✔
1217
    nchildren = term_num_children(terms, t);
×
1218
    for (i=0; i<nchildren; i++) {
×
1219
      term_t child;
1220
      uint32_t exp;
1221
      product_term_component(terms, t, i, &child, &exp);
×
1222
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1223
    }
1224
  } else if (term_is_composite(terms, t)) {
64✔
1225
    nchildren = term_num_children(terms, t);
34✔
1226
    for (i=0; i<nchildren; i++) {
89✔
1227
      collect_boolean_atoms(ctx, term_child(terms, t, i), atoms, visited);
55✔
1228
    }
1229
  }
1230
}
1231

1232
/*
1233
 * Extract assumptions whose labels appear in term t.
1234
 */
1235
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✔
1236
  int_hset_t atoms, visited;
1237
  uint32_t i;
1238

1239
  init_int_hset(&atoms, 0);
9✔
1240
  init_int_hset(&visited, 0);
9✔
1241
  collect_boolean_atoms(ctx, t, &atoms, &visited);
9✔
1242

1243
  ivector_reset(core);
9✔
1244
  for (i=0; i<labels->size; i++) {
83✔
1245
    term_t label = labels->data[i];
74✔
1246
    if (int_hset_member(&atoms, label)) {
74✔
1247
      int_hmap_pair_t *p = int_hmap_find((int_hmap_t *) label_map, label);
30✔
1248
      if (p != NULL) {
30✔
1249
        ivector_push(core, p->val);
30✔
1250
      }
1251
    }
1252
  }
1253

1254
  delete_int_hset(&visited);
9✔
1255
  delete_int_hset(&atoms);
9✔
1256
}
9✔
1257

1258
/*
1259
 * Cache a core vector in the context.
1260
 */
1261
static void cache_unsat_core(context_t *ctx, const ivector_t *core) {
2,741✔
1262
  if (ctx->unsat_core_cache == NULL) {
2,741✔
1263
    ctx->unsat_core_cache = (ivector_t *) safe_malloc(sizeof(ivector_t));
2,741✔
1264
    init_ivector(ctx->unsat_core_cache, core->size);
2,741✔
1265
  } else {
1266
    ivector_reset(ctx->unsat_core_cache);
×
1267
  }
1268
  ivector_copy(ctx->unsat_core_cache, core->data, core->size);
2,741✔
1269
}
2,741✔
1270

1271
static void cache_failed_assumptions_core(context_t *ctx, uint32_t n, const term_t *a,
5✔
1272
                                          const ivector_t *assumption_literals,
1273
                                          const ivector_t *failed_literals) {
1274
  ivector_t core_terms;
1275
  int_hset_t failed;
1276
  uint32_t i;
1277

1278
  init_ivector(&core_terms, 0);
5✔
1279
  init_int_hset(&failed, 0);
5✔
1280
  for (i=0; i<failed_literals->size; i++) {
11✔
1281
    int_hset_add(&failed, failed_literals->data[i]);
6✔
1282
  }
1283
  for (i=0; i<n; i++) {
11✔
1284
    if (int_hset_member(&failed, assumption_literals->data[i])) {
6✔
1285
      ivector_push(&core_terms, a[i]);
6✔
1286
    }
1287
  }
1288
  cache_unsat_core(ctx, &core_terms);
5✔
1289
  delete_int_hset(&failed);
5✔
1290
  delete_ivector(&core_terms);
5✔
1291
}
5✔
1292

1293
/*
1294
 * MCSAT variant of check_context_with_term_assumptions.
1295
 * Caller must hold __yices_globals.lock.
1296
 */
1297
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✔
1298
  smt_status_t stat;
1299
  ivector_t assumptions;
1300
  uint32_t i;
1301

1302
  /*
1303
   * MCSAT: create fresh labels b_i, assert (b_i => a_i), then solve with model b_i=true.
1304
   * We extract interpolant/core before cleanup, then restore sticky UNSAT artifacts.
1305
   */
1306
  if (!context_supports_model_interpolation(ctx)) {
10✔
1307
    if (error != NULL) {
×
1308
      *error = CTX_OPERATION_NOT_SUPPORTED;
×
1309
    }
1310
    return YICES_STATUS_ERROR;
×
1311
  }
1312

1313
  {
1314
    model_t mdl;               // temporary model: sets all label terms b_i to true
1315
    int_hmap_t label_map;      // map label b_i -> original assumption a_i
1316
    ivector_t mapped_core;     // translated core over original assumptions
1317
    term_t interpolant = NULL_TERM; // raw/substituted interpolant for sticky UNSAT result
10✔
1318
    int32_t code;              // return code from assert_formula (negative on internalization error)
1319
    bool pushed;               // whether we pushed a temporary scope and must pop it
1320
    term_manager_t tm;
1321

1322
    init_model(&mdl, ctx->terms, true);
10✔
1323
    init_int_hmap(&label_map, 0);
10✔
1324
    init_ivector(&assumptions, n);
10✔
1325
    init_ivector(&mapped_core, 0);
10✔
1326
    init_term_manager(&tm, ctx->terms);
10✔
1327
    stat = YICES_STATUS_IDLE;
10✔
1328

1329
    pushed = false;
10✔
1330
    if (context_supports_pushpop(ctx)) {
10✔
1331
      context_push(ctx);
9✔
1332
      pushed = true;
9✔
1333
    }
1334

1335
    for (i=0; i<n; i++) {
85✔
1336
      term_t b = new_uninterpreted_term(ctx->terms, bool_id);
75✔
1337
      term_t implication = mk_implies(&tm, b, a[i]);
75✔
1338

1339
      int_hmap_add(&label_map, b, a[i]);
75✔
1340
      code = _o_assert_formula(ctx, implication);
75✔
1341
      if (code < 0) {
75✔
1342
        if (error != NULL) {
×
1343
          *error = code;
×
1344
        }
1345
        stat = YICES_STATUS_ERROR;
×
1346
        break;
×
1347
      }
1348
      model_map_term(&mdl, b, vtbl_mk_bool(&mdl.vtbl, true));
75✔
1349
      ivector_push(&assumptions, b);
75✔
1350
    }
1351

1352
    if (stat != YICES_STATUS_ERROR) {
10✔
1353
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
10✔
1354
      if (stat == YICES_STATUS_UNSAT) {
10✔
1355
        interpolant = context_get_unsat_model_interpolant(ctx);
9✔
1356
        assert(interpolant != NULL_TERM);
1357
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
9✔
1358
      }
1359
    }
1360

1361
    if (pushed) {
10✔
1362
      mcsat_cleanup_assumptions(ctx->mcsat);
9✔
1363
      context_pop(ctx);
9✔
1364
    }
1365
    if (stat == YICES_STATUS_UNSAT) {
10✔
1366
      mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, interpolant, n, assumptions.data, a);
9✔
1367
      cache_unsat_core(ctx, &mapped_core);
9✔
1368
    }
1369

1370
    delete_term_manager(&tm);
10✔
1371
    delete_ivector(&mapped_core);
10✔
1372
    delete_ivector(&assumptions);
10✔
1373
    delete_int_hmap(&label_map);
10✔
1374
    delete_model(&mdl);
10✔
1375

1376
    return stat;
10✔
1377
  }
1378
}
1379

1380
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✔
1381
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
10✔
1382
}
1383

1384
/*
1385
 * Supplemental-MCSAT variant for term assumptions in CDCL(T) mode.
1386
 * We encode assumptions via fresh labels b_i with implications (b_i => a_i),
1387
 * then solve under assumptions b_i = true.
1388
 *
1389
 * Labels are kept in the context (no push/pop) so the regular context status
1390
 * and multicheck protocol remain unchanged.
1391
 */
1392
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✔
1393
  smt_status_t stat;
1394
  ivector_t assumptions;
1395
  term_t interpolant;
1396
  uint32_t i;
1397
  literal_t l;
1398
  mcsat_satellite_t *sat;
1399

1400
  init_ivector(&assumptions, n);
2✔
1401

1402
  stat = YICES_STATUS_IDLE;
2✔
1403
  interpolant = NULL_TERM;
2✔
1404
  sat = NULL;
2✔
1405

1406
  if (ctx->mcsat_supplement &&
2✔
1407
      ctx->egraph != NULL &&
2✔
1408
      ctx->egraph->th[ETYPE_MCSAT] != NULL) {
2✔
1409
    sat = (mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT];
2✔
1410
  }
1411

1412
  for (i=0; i<n; i++) {
6✔
1413
    l = context_add_assumption(ctx, a[i]);
4✔
1414
    if (l < 0) {
4✔
NEW
1415
      if (error != NULL) {
×
NEW
1416
        *error = l;
×
1417
      }
NEW
1418
      stat = YICES_STATUS_ERROR;
×
NEW
1419
      break;
×
1420
    }
1421

1422
    ivector_push(&assumptions, l);
4✔
1423
  }
1424

1425
  if (stat != YICES_STATUS_ERROR) {
2✔
1426
    stat = check_context_with_assumptions(ctx, params, assumptions.size, (const literal_t *) assumptions.data);
2✔
1427
    if (stat == YICES_STATUS_UNSAT) {
2✔
1428
      if (sat != NULL) {
2✔
1429
        interpolant = mcsat_satellite_compute_unsat_model_interpolant(sat, params, n, a);
2✔
1430
      }
1431
      if (interpolant == NULL_TERM && context_supports_model_interpolation(ctx)) {
2✔
NEW
1432
        interpolant = context_get_unsat_model_interpolant(ctx);
×
1433
      }
1434
      if (interpolant == NULL_TERM && context_supports_model_interpolation(ctx)) {
2✔
NEW
1435
        interpolant = false_term;
×
1436
      }
1437
    }
1438
  }
1439

1440
  if (stat == YICES_STATUS_UNSAT && interpolant != NULL_TERM && sat != NULL) {
2✔
NEW
1441
    mcsat_satellite_set_unsat_model_interpolant(sat, interpolant);
×
1442
  }
1443

1444
  delete_ivector(&assumptions);
2✔
1445

1446
  return stat;
2✔
1447
}
1448

1449
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✔
1450
  return _o_check_context_with_term_assumptions_supplement(ctx, params, n, a, error);
2✔
1451
}
1452

1453
/*
1454
 * Check under assumptions given as terms.
1455
 * - if MCSAT is enabled, this uses temporary labels + model interpolation.
1456
 * - otherwise terms are converted to literals and handled by the CDCL(T) path.
1457
 *
1458
 * Preconditions:
1459
 * - context status must be IDLE.
1460
 */
1461
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,719✔
1462
  if (error != NULL) {
2,719✔
1463
    *error = CTX_NO_ERROR;
2,719✔
1464
  }
1465

1466
  /*
1467
   * Clear any prior term-assumption core before all paths below. Delegate
1468
   * checks cache a new core only on UNSAT.
1469
   */
1470
  context_invalidate_unsat_core_cache(ctx);
2,719✔
1471

1472
  if (ctx->mcsat == NULL) {
2,719✔
1473
    if (ctx->mcsat_supplement) {
2,709✔
1474
      return check_context_with_term_assumptions_supplement(ctx, params, n, a, error);
2✔
1475
    }
1476
    smt_status_t stat;
1477
    sat_delegate_t mode;
1478
    sat_delegate_incremental_mode_t exec_mode;
1479
    bool one_shot;
1480
    const char *delegate;
1481
    bool unknown;
1482
    ivector_t assumptions;
1483
    ivector_t failed;
1484
    uint32_t i;
1485
    literal_t l;
1486

1487
    init_ivector(&assumptions, n);
2,707✔
1488
    for (i=0; i<n; i++) {
90,333✔
1489
      l = context_add_assumption(ctx, a[i]);
87,626✔
1490
      if (l < 0) {
87,626✔
1491
        if (error != NULL) {
×
1492
          *error = l;
×
1493
        }
1494
        delete_ivector(&assumptions);
×
1495
        return YICES_STATUS_ERROR;
×
1496
      }
1497
      ivector_push(&assumptions, l);
87,626✔
1498
    }
1499

1500
    mode = effective_sat_delegate_mode(ctx->sat_delegate, params, &one_shot);
2,707✔
1501
    delegate = sat_delegate_name(mode);
2,707✔
1502
    if (delegate == NULL) {
2,707✔
1503
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,667✔
1504
      delete_ivector(&assumptions);
2,667✔
1505
      return stat;
2,667✔
1506
    }
1507

1508
    if (ctx->logic != QF_BV) {
40✔
1509
      if (error != NULL) {
×
1510
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1511
      }
1512
      delete_ivector(&assumptions);
×
1513
      return YICES_STATUS_ERROR;
×
1514
    }
1515

1516
    if (!supported_delegate(delegate, &unknown)) {
40✔
1517
      if (error != NULL) {
×
1518
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1519
      }
1520
      delete_ivector(&assumptions);
×
1521
      return YICES_STATUS_ERROR;
×
1522
    }
1523

1524
    if (!delegate_supports_assumptions_name(delegate)) {
40✔
1525
      if (error != NULL) {
1✔
1526
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1527
      }
1528
      delete_ivector(&assumptions);
1✔
1529
      return YICES_STATUS_ERROR;
1✔
1530
    }
1531

1532
    init_ivector(&failed, 0);
39✔
1533
    if (!effective_sat_delegate_incremental_mode(mode, ctx->sat_delegate_incremental_mode,
39✔
1534
                                                ctx->sat_delegate_incremental_mode_set,
39✔
1535
                                                ctx->mode == CTX_MODE_ONECHECK,
39✔
1536
                                                one_shot, &exec_mode)) {
1537
      if (error != NULL) {
×
1538
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1539
      }
1540
      delete_ivector(&failed);
×
1541
      delete_ivector(&assumptions);
×
1542
      return YICES_STATUS_ERROR;
×
1543
    }
1544
    stat = check_with_sat_delegate(ctx, delegate, exec_mode, 0, n, assumptions.data, &failed);
39✔
1545
    if (stat == YICES_STATUS_UNSAT) {
39✔
1546
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
5✔
1547
    }
1548
    delete_ivector(&failed);
39✔
1549
    delete_ivector(&assumptions);
39✔
1550
    return stat;
39✔
1551
  }
1552

1553
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1554
}
1555

1556
/*
1557
 * Check with given model
1558
 * - if mcsat status is not IDLE, return the status
1559
 */
1560
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✔
1561
  smt_status_t stat;
1562

1563
  assert(ctx->mcsat != NULL);
1564

1565
  stat = mcsat_status(ctx->mcsat);
161✔
1566
  if (stat == YICES_STATUS_IDLE) {
161✔
1567
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
161✔
1568
    stat = mcsat_status(ctx->mcsat);
161✔
1569

1570
    // BD: this looks wrong. We shouldn't call clear yet.
1571
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1572
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1573
    //      context_clear(ctx);
1574
    //    }
1575
  }
1576

1577
  if (stat == YICES_STATUS_UNSAT && n == 0 &&
165✔
1578
      context_supports_model_interpolation(ctx) &&
6✔
1579
      mcsat_get_unsat_model_interpolant(ctx->mcsat) == NULL_TERM) {
2✔
1580
    // With no model assumptions, false is the canonical interpolant.
NEW
1581
    mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, false_term, 0, NULL, NULL);
×
1582
  }
1583

1584
  return stat;
161✔
1585
}
1586

1587
/*
1588
 * Check with given model and hints
1589
 * - set the model hint and call check_context_with_model
1590
 */
1591
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✔
1592
  assert(m <= n);
1593

1594
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1595

1596
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1597
}
1598

1599

1600
/*
1601
 * Precheck: force generation of clauses and other stuff that's
1602
 * constructed lazily by the solvers. For example, this
1603
 * can be used to convert all the constraints asserted in the
1604
 * bitvector to clauses so that we can export the result to DIMACS.
1605
 *
1606
 * If ctx status is IDLE:
1607
 * - the function calls 'start_search' and does one round of propagation.
1608
 * - if this results in UNSAT, the function returns UNSAT
1609
 * - if the precheck is interrupted, the function returns INTERRUPTED
1610
 * - otherwise the function returns UNKNOWN and sets the status to
1611
 *   UNKNOWN.
1612
 *
1613
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
1614
 * IDLE before doing anything else with this context.
1615
 *
1616
 * If ctx status is not IDLE, the function returns it and does nothing
1617
 * else.
1618
 */
1619
smt_status_t precheck_context(context_t *ctx) {
×
1620
  smt_status_t stat;
1621
  smt_core_t *core;
1622

1623
  core = ctx->core;
×
1624

1625
  stat = smt_status(core);
×
1626
  if (stat == YICES_STATUS_IDLE) {
×
1627
    start_search(core, 0, NULL);
×
1628
    smt_process(core);
×
1629
    stat = smt_status(core);
×
1630

1631
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1632
           stat == YICES_STATUS_INTERRUPTED);
1633

1634
    if (stat == YICES_STATUS_SEARCHING) {
×
1635
      end_search_unknown(core);
×
1636
      stat = YICES_STATUS_UNKNOWN;
×
1637
    }
1638
  }
1639

1640
  return stat;
×
1641
}
1642

1643

1644

1645
/*
1646
 * Solve using another SAT solver
1647
 * - sat_solver = name of the solver to use
1648
 * - verbosity = verbosity level (0 means quiet)
1649
 * - this may be used only for BV or pure SAT problems
1650
 * - we perform one round of propagation to convert the problem to CNF
1651
 * - then we call an external SAT solver on the CNF problem
1652
 */
1653
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
38✔
1654
  smt_status_t stat;
1655
  smt_core_t *core;
1656
  delegate_t delegate;
1657
  bvar_t x;
1658
  bval_t v;
1659

1660
  core = ctx->core;
38✔
1661

1662
  stat = smt_status(core);
38✔
1663
  if (stat == YICES_STATUS_IDLE) {
38✔
1664
    start_search(core, 0, NULL);
38✔
1665
    smt_process(core);
38✔
1666
    stat = smt_status(core);
38✔
1667

1668
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1669
           stat == YICES_STATUS_INTERRUPTED);
1670

1671
    if (stat == YICES_STATUS_SEARCHING) {
38✔
1672
      if (smt_easy_sat(core)) {
36✔
1673
        stat = YICES_STATUS_SAT;
36✔
1674
      } else {
1675
        // call the delegate
1676
        init_delegate(&delegate, sat_solver, num_vars(core));
×
1677
        ctx->sat_delegate_stats.delegate_initializations ++;
×
1678
        delegate_set_verbosity(&delegate, verbosity);
×
1679

1680
        stat = solve_with_delegate(&delegate, core);
×
1681
        set_smt_status(core, stat);
×
1682
        if (stat == YICES_STATUS_SAT) {
×
1683
          for (x=0; x<num_vars(core); x++) {
×
1684
            v = delegate_get_value(&delegate, x);
×
1685
            set_bvar_value(core, x, v);
×
1686
          }
1687
        }
1688
        delete_delegate(&delegate);
×
1689
      }
1690
    }
1691
  }
1692

1693
  return stat;
38✔
1694
}
1695

1696
/*
1697
 * One-shot check with delegate and assumptions.
1698
 * - assumptions are literals in core encoding.
1699
 * - if failed != NULL and result is UNSAT, failed assumptions are appended to *failed.
1700
 */
1701
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
1702
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1703
  smt_status_t stat;
1704
  smt_core_t *core;
1705
  delegate_t delegate;
1706

1707
  core = ctx->core;
×
1708

1709
  stat = smt_status(core);
×
1710
  if (stat != YICES_STATUS_IDLE) {
×
1711
    return stat;
×
1712
  }
1713

1714
  start_search(core, 0, NULL);
×
1715
  smt_process(core);
×
1716
  stat = smt_status(core);
×
1717

1718
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1719
         stat == YICES_STATUS_INTERRUPTED);
1720

1721
  if (stat != YICES_STATUS_SEARCHING) {
×
1722
    return stat;
×
1723
  }
1724

1725
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
1726
    return YICES_STATUS_UNKNOWN;
×
1727
  }
1728
  ctx->sat_delegate_stats.delegate_initializations ++;
×
1729
  delegate_set_verbosity(&delegate, verbosity);
×
1730

1731
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
1732
  set_smt_status(core, stat);
×
1733
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
1734
  if (stat == YICES_STATUS_SAT) {
×
1735
    context_import_delegate_model(core, &delegate);
×
1736
  }
1737

1738
  delete_delegate(&delegate);
×
1739
  return stat;
×
1740
}
1741

1742

1743
/*
1744
 * Bit-blast then export to DIMACS
1745
 * - filename = name of the output file
1746
 * - status = status of the context after bit-blasting
1747
 *
1748
 * If ctx status is IDLE
1749
 * - perform one round of propagation to conver the problem to CNF
1750
 * - export the CNF to DIMACS
1751
 *
1752
 * If ctx status is not IDLE,
1753
 * - store the stauts in *status and do nothing else
1754
 *
1755
 * Return code:
1756
 *  1 if the DIMACS file was created
1757
 *  0 if the problem was solved by the propagation round
1758
 * -1 if there was an error in creating or writing to the file.
1759
 */
1760
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1761
  smt_core_t *core;
1762
  FILE *f;
1763
  smt_status_t stat;
1764
  int32_t code;
1765

1766
  core = ctx->core;
×
1767

1768
  code = 0;
×
1769
  stat = smt_status(core);
×
1770
  if (stat == YICES_STATUS_IDLE) {
×
1771
    start_search(core, 0, NULL);
×
1772
    smt_process(core);
×
1773
    stat = smt_status(core);
×
1774

1775
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1776
           stat == YICES_STATUS_INTERRUPTED);
1777

1778
    if (stat == YICES_STATUS_SEARCHING) {
×
1779
      code = 1;
×
1780
      f = fopen(filename, "w");
×
1781
      if (f == NULL) {
×
1782
        code = -1;
×
1783
      } else {
1784
        dimacs_print_bvcontext(f, ctx);
×
1785
        if (ferror(f)) code = -1;
×
1786
        fclose(f);
×
1787
      }
1788
    }
1789
  }
1790

1791
  *status = stat;
×
1792

1793
  return code;
×
1794
}
1795

1796

1797
/*
1798
 * Simplify then export to Dimacs:
1799
 * - filename = name of the output file
1800
 * - status = status of the context after CNF conversion + preprocessing
1801
 *
1802
 * If ctx status is IDLE
1803
 * - perform one round of propagation to convert the problem to CNF
1804
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
1805
 *
1806
 * If ctx status is not IDLE, the function stores that in *status
1807
 * If y2sat preprocessing solves the formula, return the status also in *status
1808
 *
1809
 * Return code:
1810
 *  1 if the DIMACS file was created
1811
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
1812
 * -1 if there was an error creating or writing to the file.
1813
 */
1814
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1815
  smt_core_t *core;
1816
  FILE *f;
1817
  smt_status_t stat;
1818
  delegate_t delegate;
1819
  bvar_t x;
1820
  bval_t v;
1821
  int32_t code;
1822

1823
  core = ctx->core;
×
1824

1825
  code = 0;
×
1826
  stat = smt_status(core);
×
1827
  if (stat == YICES_STATUS_IDLE) {
×
1828
    start_search(core, 0, NULL);
×
1829
    smt_process(core);
×
1830
    stat = smt_status(core);
×
1831

1832
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1833
           stat == YICES_STATUS_INTERRUPTED);
1834

1835
    if (stat == YICES_STATUS_SEARCHING) {
×
1836
      if (smt_easy_sat(core)) {
×
1837
        stat = YICES_STATUS_SAT;
×
1838
      } else {
1839
        // call the delegate
1840
        init_delegate(&delegate, "y2sat", num_vars(core));
×
1841
        delegate_set_verbosity(&delegate, 0);
×
1842

1843
        stat = preprocess_with_delegate(&delegate, core);
×
1844
        set_smt_status(core, stat);
×
1845
        if (stat == YICES_STATUS_SAT) {
×
1846
          for (x=0; x<num_vars(core); x++) {
×
1847
            v = delegate_get_value(&delegate, x);
×
1848
            set_bvar_value(core, x, v);
×
1849
          }
1850
        } else if (stat == YICES_STATUS_UNKNOWN) {
×
1851
          code = 1;
×
1852
          f = fopen(filename, "w");
×
1853
          if (f == NULL) {
×
1854
            code = -1;
×
1855
          } else {
1856
            export_to_dimacs_with_delegate(&delegate, f);
×
1857
            if (ferror(f)) code = -1;
×
1858
            fclose(f);
×
1859
          }
1860
        }
1861

1862
        delete_delegate(&delegate);
×
1863
      }
1864
    }
1865
  }
1866

1867
  *status = stat;
×
1868

1869
  return code;
×
1870
}
1871

1872

1873

1874
/*
1875
 * MODEL CONSTRUCTION
1876
 */
1877

1878
/*
1879
 * Value of literal l in ctx->core
1880
 */
1881
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
1882
  value_t v;
1883

1884
  v = null_value; // prevent GCC warning
65,201✔
1885
  switch (literal_value(ctx->core, l)) {
65,201✔
1886
  case VAL_FALSE:
38,577✔
1887
    v = vtbl_mk_false(vtbl);
38,577✔
1888
    break;
38,577✔
1889
  case VAL_UNDEF_FALSE:
×
1890
  case VAL_UNDEF_TRUE:
1891
    v = vtbl_mk_unknown(vtbl);
×
1892
    break;
×
1893
  case VAL_TRUE:
26,624✔
1894
    v = vtbl_mk_true(vtbl);
26,624✔
1895
    break;
26,624✔
1896
  }
1897
  return v;
65,201✔
1898
}
1899

1900

1901
/*
1902
 * Value of arithmetic variable x in ctx->arith_solver
1903
 */
1904
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,593✔
1905
  rational_t *a;
1906
  value_t v;
1907

1908
  assert(context_has_arith_solver(ctx));
1909

1910
  a = &ctx->aux;
22,593✔
1911
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,593✔
1912
    v = vtbl_mk_rational(vtbl, a);
22,593✔
1913
  } else {
1914
    v = vtbl_mk_unknown(vtbl);
×
1915
  }
1916

1917
  return v;
22,593✔
1918
}
1919

1920

1921

1922
/*
1923
 * Value of bitvector variable x in ctx->bv_solver
1924
 */
1925
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,153✔
1926
  bvconstant_t *b;
1927
  value_t v;
1928

1929
  assert(context_has_bv_solver(ctx));
1930

1931
  b = &ctx->bv_buffer;
18,153✔
1932
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,153✔
1933
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,153✔
1934
  } else {
1935
    v = vtbl_mk_unknown(vtbl);
×
1936
  }
1937

1938
  return v;
18,153✔
1939
}
1940

1941

1942
/*
1943
 * Get a value for term t in the solvers or egraph
1944
 * - attach the mapping from t to that value in model
1945
 * - if we don't have a concrete object for t but t is
1946
 *   mapped to a term u and the model->has_alias is true,
1947
 *   then we store the mapping [t --> u] in the model's
1948
 *   alias map.
1949
 */
1950
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
320,262✔
1951
  value_table_t *vtbl;
1952
  term_t r;
1953
  uint32_t polarity;
1954
  int32_t x;
1955
  type_t tau;
1956
  value_t v;
1957

1958
  /*
1959
   * Get the root of t in the substitution table
1960
   */
1961
  r = intern_tbl_get_root(&ctx->intern, t);
320,262✔
1962
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
320,262✔
1963
    /*
1964
     * r is mapped to some object x in egraph/core/or theory solvers
1965
     * - keep track of polarity then force r to positive polarity
1966
     */
1967
    vtbl = model_get_vtbl(model);
110,721✔
1968
    polarity = polarity_of(r);
110,721✔
1969
    r = unsigned_term(r);
110,721✔
1970

1971
    /*
1972
     * Convert x to a concrete value
1973
     */
1974
    x = intern_tbl_map_of_root(&ctx->intern, r);
110,721✔
1975
    if (code_is_eterm(x)) {
110,721✔
1976
      // x refers to an egraph object or true_occ/false_occ
1977
      if (x == bool2code(true)) {
4,774✔
1978
        v = vtbl_mk_true(vtbl);
475✔
1979
      } else if (x == bool2code(false)) {
4,299✔
1980
        v = vtbl_mk_false(vtbl);
1,420✔
1981
      } else {
1982
        assert(context_has_egraph(ctx));
1983
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,879✔
1984
      }
1985

1986
    } else {
1987
      // x refers to a literal or a theory variable
1988
      tau = term_type(ctx->terms, r);
105,947✔
1989
      switch (type_kind(ctx->types, tau)) {
105,947✔
1990
      case BOOL_TYPE:
65,201✔
1991
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
1992
        break;
65,201✔
1993

1994
      case INT_TYPE:
22,593✔
1995
      case REAL_TYPE:
1996
        v = arith_value(ctx, vtbl, code2thvar(x));
22,593✔
1997
        break;
22,593✔
1998

1999
      case BITVECTOR_TYPE:
18,153✔
2000
        v = bv_value(ctx, vtbl, code2thvar(x));
18,153✔
2001
        break;
18,153✔
2002

2003
      default:
×
2004
        /*
2005
         * This should never happen:
2006
         * scalar, uninterpreted, tuple, function terms
2007
         * are mapped to egraph terms.
2008
         */
2009
        assert(false);
2010
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
2011
        break;
×
2012
      }
2013
    }
2014

2015
    /*
2016
     * Restore polarity then add mapping [t --> v] in the model
2017
     */
2018
    if (! object_is_unknown(vtbl, v)) {
110,721✔
2019
      if (object_is_boolean(vtbl, v)) {
110,721✔
2020
        if (polarity) {
67,096✔
2021
          // negate the value
2022
          v = vtbl_mk_not(vtbl, v);
24✔
2023
        }
2024
      }
2025
      model_map_term(model, t, v);
110,721✔
2026
    }
2027

2028
  } else {
2029
    /*
2030
     * r is not mapped to anything:
2031
     *
2032
     * 1) If t == r and t is present in the internalization table
2033
     *    then t is relevant. So we should display its value
2034
     *    when we print the model. To do this, we assign an
2035
     *    arbitrary value v to t and store [t := v] in the map.
2036
     *
2037
     * 2) If t != r then we keep the mapping [t --> r] in
2038
     *    the alias table (provided the model supports aliases).
2039
     */
2040
    if (t == r) {
209,541✔
2041
      if (intern_tbl_term_present(&ctx->intern, t)) {
208,885✔
2042
        tau = term_type(ctx->terms, t);
×
2043
        vtbl = model_get_vtbl(model);
×
2044
        v = vtbl_make_object(vtbl, tau);
×
2045
        model_map_term(model, t, v);
×
2046
      }
2047
    } else if (model->has_alias) {
656✔
2048
      // t != r: keep the substitution [t --> r] in the model
2049
      model_add_substitution(model, t, r);
656✔
2050
    }
2051
  }
2052
}
320,262✔
2053

2054

2055

2056

2057
/*
2058
 * Build a model for the current context (including all satellite solvers)
2059
 * - the context status must be SAT (or UNKNOWN)
2060
 * - if model->has_alias is true, we store the term substitution
2061
 *   defined by ctx->intern_tbl into the model
2062
 * - cleanup of satellite models needed using clean_solver_models()
2063
 */
2064
void build_model(model_t *model, context_t *ctx) {
42,165✔
2065
  term_table_t *terms;
2066
  uint32_t i, n;
2067
  term_t t;
2068

2069
  assert(smt_status(ctx->core) == YICES_STATUS_SAT ||
2070
         smt_status(ctx->core) == YICES_STATUS_UNKNOWN ||
2071
         (context_has_mcsat(ctx) && mcsat_status(ctx->mcsat) == YICES_STATUS_SAT));
2072

2073
  /*
2074
   * First build assignments in the satellite solvers
2075
   * and get the val_in_model functions for the egraph
2076
   */
2077
  if (context_has_arith_solver(ctx)) {
42,165✔
2078
    ctx->arith.build_model(ctx->arith_solver);
32,913✔
2079
  }
2080
  if (context_has_bv_solver(ctx)) {
42,165✔
2081
    ctx->bv.build_model(ctx->bv_solver);
21,419✔
2082
  }
2083

2084
  /*
2085
   * Construct the egraph model
2086
   */
2087
  if (context_has_egraph(ctx)) {
42,165✔
2088
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,039✔
2089
  }
2090

2091
  /*
2092
   * Construct the mcsat model.
2093
   */
2094
  if (context_has_mcsat(ctx)) {
42,165✔
2095
    mcsat_build_model(ctx->mcsat, model);
51✔
2096
  }
2097

2098
  // scan the internalization table
2099
  terms = ctx->terms;
42,165✔
2100
  n = intern_tbl_num_terms(&ctx->intern);
42,165✔
2101
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,098,210✔
2102
    if (good_term_idx(terms, i)) {
1,235,056,045✔
2103
      t = pos_occ(i);
1,235,056,045✔
2104
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,056,045✔
2105
        build_term_value(ctx, model, t);
320,262✔
2106
      }
2107
    }
2108
  }
2109

2110
  /*
2111
   * Supplemental MCSAT values are an overlay: apply them after the regular
2112
   * CDCL(T) model is fully built so nonlinear/FF values are not overwritten.
2113
   */
2114
  if (ctx->mcsat_supplement && context_has_egraph(ctx) && ctx->egraph->th[ETYPE_MCSAT] != NULL) {
42,165✔
2115
    mcsat_satellite_build_model((mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT], model);
4✔
2116
  }
2117
}
42,165✔
2118

2119

2120
/*
2121
 * Cleanup solver models
2122
 */
2123
void clean_solver_models(context_t *ctx) {
42,165✔
2124
  if (context_has_arith_solver(ctx)) {
42,165✔
2125
    ctx->arith.free_model(ctx->arith_solver);
32,913✔
2126
  }
2127
  if (context_has_bv_solver(ctx)) {
42,165✔
2128
    ctx->bv.free_model(ctx->bv_solver);
21,419✔
2129
  }
2130
  if (context_has_egraph(ctx)) {
42,165✔
2131
    egraph_free_model(ctx->egraph);
13,039✔
2132
  }
2133
}
42,165✔
2134

2135

2136

2137
/*
2138
 * Build a model for the current context
2139
 * - the context status must be SAT (or UNKNOWN)
2140
 * - if model->has_alias is true, we store the term substitution
2141
 *   defined by ctx->intern_tbl into the model
2142
 */
2143
void context_build_model(model_t *model, context_t *ctx) {
264✔
2144
  // Build solver models and term values
2145
  build_model(model, ctx);
264✔
2146

2147
  // Cleanup
2148
  clean_solver_models(ctx);
264✔
2149
}
264✔
2150

2151

2152

2153
/*
2154
 * Read the value of a Boolean term t
2155
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
2156
 */
2157
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
2158
  term_t r;
2159
  uint32_t polarity;
2160
  int32_t x;
2161
  bval_t v;
2162

2163
  assert(is_boolean_term(ctx->terms, t));
2164

2165
  // default value if t is not in the internalization table
2166
  v = VAL_UNDEF_FALSE;
×
2167
  r = intern_tbl_get_root(&ctx->intern, t);
×
2168
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
2169
    // r is mapped to some object x
2170
    polarity = polarity_of(r);
×
2171
    r = unsigned_term(r);
×
2172

2173
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
2174
    if (code_is_eterm(x)) {
×
2175
      // x must be either true_occ or false_occ
2176
      if (x == bool2code(true)) {
×
2177
        v = VAL_TRUE;
×
2178
      } else {
2179
        assert(x == bool2code(false));
2180
        v = VAL_FALSE;
×
2181
      }
2182
    } else {
2183
      // x refers to a literal in the smt core
2184
      v = literal_value(ctx->core, code2literal(x));
×
2185
    }
2186

2187
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
2188
    v ^= polarity;
×
2189
  }
2190

2191
  return v;
×
2192
}
2193

2194

2195
/*
2196
 * UNSAT CORE
2197
 */
2198

2199
/*
2200
 * Build an unsat core:
2201
 * - store the result in v
2202
 * - first reuse a cached term core if available.
2203
 * - otherwise:
2204
 *   CDCL(T): build from smt_core then cache as terms
2205
 *   MCSAT: return empty unless check-with-term-assumptions populated the cache.
2206
 */
2207
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
2,737✔
2208
  smt_core_t *core;
2209
  uint32_t i, n;
2210
  term_t t;
2211

2212
  if (ctx->unsat_core_cache != NULL) {
2,737✔
2213
    // Fast path: repeated get_unsat_core returns the cached term vector.
2214
    ivector_reset(v);
10✔
2215
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
10✔
2216
    return;
10✔
2217
  }
2218

2219
  if (ctx->mcsat != NULL) {
2,727✔
2220
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
2221
    // there is no generic context-level core structure to rebuild from here.
2222
    ivector_reset(v);
×
2223
    return;
×
2224
  }
2225

2226
  core = ctx->core;
2,727✔
2227
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
2228
  build_unsat_core(core, v);
2,727✔
2229

2230
  // convert from literals to terms
2231
  n = v->size;
2,727✔
2232
  for (i=0; i<n; i++) {
37,642✔
2233
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,915✔
2234
    assert(t >= 0);
2235
    v->data[i] = t;
34,915✔
2236
  }
2237

2238
  // Cache the converted term core for subsequent queries.
2239
  cache_unsat_core(ctx, v);
2,727✔
2240
}
2241

2242

2243
/*
2244
 * MODEL INTERPOLANT
2245
 */
2246
term_t context_get_unsat_model_interpolant(context_t *ctx) {
61✔
2247
  if (ctx->mcsat != NULL) {
61✔
2248
    return mcsat_get_unsat_model_interpolant(ctx->mcsat);
61✔
2249
  }
2250

NEW
2251
  if (ctx->mcsat_supplement && ctx->egraph != NULL && ctx->egraph->th[ETYPE_MCSAT] != NULL) {
×
NEW
2252
    return mcsat_satellite_get_unsat_model_interpolant((mcsat_satellite_t *) ctx->egraph->th[ETYPE_MCSAT]);
×
2253
  }
2254

NEW
2255
  if (context_supports_model_interpolation(ctx) &&
×
NEW
2256
      ctx->core != NULL &&
×
NEW
2257
      smt_status(ctx->core) == YICES_STATUS_UNSAT) {
×
NEW
2258
    return false_term;
×
2259
  }
2260

NEW
2261
  return NULL_TERM;
×
2262
}
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