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

SRI-CSL / yices2 / 26675300141

29 May 2026 08:46PM UTC coverage: 68.798% (+3.4%) from 65.375%
26675300141

push

github

ahmed-irfan
Rework clause-deletion heuristic to CaDiCaL-style schedule

Replace the geometric, learned-clause-count-triggered reduce schedule
with a CaDiCaL-style one: trigger on conflict count and rebase the
reduction bound to num_conflicts + r-interval * sqrt(num_conflicts).

- context_solver.c: factor the reduce step into try_reduce_heuristic();
  trigger on num_conflicts instead of num_learned_clauses; widen the
  running reduce_threshold to uint64_t (conflict count is unbounded).
- search_parameters: drop r-threshold/r-fraction/r-factor, add
  r-initial-threshold and r-interval (defaults 300 / 25, matching
  CaDiCaL's reduceinit / reduceint).
- Update doc/YICES-LANGUAGE, doc/sphinx parameters table, and the
  interactive (help ...) entries for the renamed parameters.

10 of 10 new or added lines in 1 file covered. (100.0%)

8005 existing lines in 44 files now uncovered.

87475 of 127148 relevant lines covered (68.8%)

1646632.75 hits per line

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

78.2
/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 <math.h>
32
#include <string.h>
33

34
#include "context/context.h"
35
#include "context/internalization_codes.h"
36
#include "model/models.h"
37
#include "mcsat/solver.h"
38
#include "solvers/bv/dimacs_printer.h"
39
#include "solvers/cdcl/delegate.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,466✔
63
  trace_printf(core->trace, level,
93,466✔
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,466✔
76

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

84

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

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

96

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

105

106

107
/*
108
 * End of search
109
 */
110
static void trace_done(smt_core_t *core) {
45,406✔
111
  trace_stats(core, "done:", 1);
45,406✔
112
  trace_newline(core->trace, 1);
45,406✔
113
}
45,406✔
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,507✔
128
  switch (literal_value(core, l)) {
86,507✔
129
  case VAL_UNDEF_FALSE:
83,966✔
130
  case VAL_UNDEF_TRUE:
131
    decide_literal(core, l);
83,966✔
132
    smt_process(core);
83,966✔
133
    break;
83,966✔
134

UNCOV
135
  case VAL_TRUE:
×
UNCOV
136
    break;
×
137

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

144

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

149
/*
150
 * Handle the reduce heuristic (CaDiCaL-style):
151
 * - if the number of conflicts has reached the threshold, reduce the clause database
152
 * - set the next threshold to num_conflicts + r_interval * sqrt(num_conflicts)
153
 */
154
static inline void try_reduce_heuristic(smt_core_t *core, uint64_t *r_threshold, uint32_t r_interval) {
7,506,129✔
155
  uint64_t conflicts, deletions;
156

157
  conflicts = num_conflicts(core);
7,506,129✔
158
  if (conflicts >= *r_threshold) {
7,506,129✔
159
    deletions = core->stats.learned_clauses_deleted;
215✔
160
    reduce_clause_database(core);
215✔
161
    *r_threshold = conflicts + (uint64_t) (r_interval * sqrt((double) conflicts));
215✔
162
    trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
215✔
163
  }
164
}
7,506,129✔
165

166
/*
167
 * Bounded search with the default branching heuristic (picosat-like)
168
 * - search until the conflict bound is reached or until the problem is solved.
169
 * - reduce_threshold: conflict count above which reduce_clause_database is called
170
 * - r_interval = increment factor for reduce_threshold
171
 * - use the default branching heuristic implemented by the core
172
 */
173
static void search(smt_core_t *core, uint32_t conflict_bound, uint64_t *reduce_threshold, uint32_t r_interval) {
13,439✔
174
  uint64_t max_conflicts;
175
  literal_t l;
176

177
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
178

179
  max_conflicts = num_conflicts(core) + conflict_bound;
13,439✔
180

181
  smt_process(core);
13,439✔
182
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
6,253,570✔
183
    // reduce heuristic
184
    try_reduce_heuristic(core, reduce_threshold, r_interval);
6,240,131✔
185

186
    // assumption
187
    if (core->has_assumptions) {
6,240,131✔
188
      l = get_next_assumption(core);
10✔
189
      if (l != null_literal) {
10✔
190
        process_assumption(core, l);
3✔
191
        continue;
3✔
192
      }
193
    }
194

195
    // decision
196
    l = select_unassigned_literal(core);
6,240,128✔
197
    if (l == null_literal) {
6,240,128✔
198
      // all variables assigned: Call final_check
199
      smt_final_check(core);
16,697✔
200
    } else {
201
      decide_literal(core, l);
6,223,431✔
202
      smt_process(core);
6,223,431✔
203
    }
204
  }
205
}
13,439✔
206

207

208
/*
209
 * HACK: Variant for Luby restart:
210
 * - search until the conflict bound is reached or until the problem is solved.
211
 * - reduce_threshold: conflict count above which reduce_clause_database is called
212
 * - r_interval = increment factor for reduce_threshold
213
 * - use the default branching heuristic implemented by the core
214
 *
215
 * This uses smt_bounded_process to force more frequent restarts.
216
 */
217
static void luby_search(smt_core_t *core, uint32_t conflict_bound, uint64_t *reduce_threshold, uint32_t r_interval) {
13,548✔
218
  uint64_t max_conflicts;
219
  literal_t l;
220

221
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
222

223
  max_conflicts = num_conflicts(core) + conflict_bound;
13,548✔
224
  smt_bounded_process(core, max_conflicts);
13,548✔
225
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) < max_conflicts) {
689,502✔
226
    // reduce heuristic
227
    try_reduce_heuristic(core, reduce_threshold, r_interval);
675,954✔
228

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

238
    // decision
239
    l = select_unassigned_literal(core);
589,452✔
240
    if (l == null_literal) {
589,452✔
241
      // all variables assigned: Call final_check
242
      smt_final_check(core);
8,803✔
243
    } else {
244
      decide_literal(core, l);
580,649✔
245
      smt_bounded_process(core, max_conflicts);
580,649✔
246
    }
247
  }
248
}
13,548✔
249

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

256

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

269
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
270

271
  max_conflicts = num_conflicts(core) + conflict_bound;
20,858✔
272
  smt_process(core);
20,858✔
273
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
610,902✔
274
    // reduce heuristic
275
    try_reduce_heuristic(core, reduce_threshold, r_interval);
590,044✔
276

277
    // assumption
278
    if (core->has_assumptions) {
590,044✔
279
      l = get_next_assumption(core);
2✔
280
      if (l != null_literal) {
2✔
281
        process_assumption(core, l);
2✔
282
        continue;
2✔
283
      }
284
    }
285

286
    // decision
287
    l = select_unassigned_literal(core);
590,042✔
288
    if (l == null_literal) {
590,042✔
289
      // all variables assigned: call final check
290
      smt_final_check(core);
22,605✔
291
    } else {
292
      // apply the branching heuristic
293
      l = branch(core, l);
567,437✔
294
      // propagation
295
      decide_literal(core, l);
567,437✔
296
      smt_process(core);
567,437✔
297
    }
298
  }
299
}
20,858✔
300

301

302

303

304

305
/*
306
 * SUPPORTED BRANCHING
307
 */
308

309
/*
310
 * Simple branching heuristics:
311
 * - branch to the negative polarity
312
 * - branch to the positive polarity
313
 */
314
static literal_t negative_branch(smt_core_t *core, literal_t l) {
150,837✔
315
  return l | 1; // force the sign bit to 1
150,837✔
316
}
317

318
static literal_t positive_branch(smt_core_t *core, literal_t l) {
61,788✔
319
  return l & ~1; // force the sign bit to 0
61,788✔
320
}
321

322

323
/*
324
 * For literals with no atom, use the default, otherwise let the theory solver decide
325
 */
326
static literal_t theory_branch(smt_core_t *core, literal_t l) {
354,812✔
327
  if (bvar_has_atom(core, var_of(l))) {
354,812✔
328
    l =  core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
291,321✔
329
  }
330
  return l;
354,812✔
331
}
332

333
// variants
334
static literal_t theory_or_neg_branch(smt_core_t *core, literal_t l) {
×
335
  if (bvar_has_atom(core, var_of(l))) {
×
UNCOV
336
    return core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
×
337
  } else {
UNCOV
338
    return l | 1;
×
339
  }
340
}
341

UNCOV
342
static literal_t theory_or_pos_branch(smt_core_t *core, literal_t l) {
×
UNCOV
343
  if (bvar_has_atom(core, var_of(l))) {
×
UNCOV
344
    return core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
×
345
  } else {
UNCOV
346
    return l & ~1;
×
347
  }
348
}
349

350

351

352

353

354
/*
355
 * CORE SOLVER
356
 */
357

358
/*
359
 * Full solver:
360
 * - params: heuristic parameters.
361
 * - n = number of assumptions
362
 * - a = array of n assumptions: a[0 ... n-1] must all be literals
363
 */
364
static void solve(smt_core_t *core, const param_t *params, uint32_t n, const literal_t *a) {
45,406✔
365
  bool luby;
366
  uint32_t c_threshold, d_threshold; // Picosat-style
367
  uint32_t u, v, period;             // for Luby-style
368
  uint64_t reduce_threshold;
369

370
  c_threshold = params->c_threshold;
45,406✔
371
  d_threshold = c_threshold; // required by trace_start in slow_restart mode
45,406✔
372
  luby = false;
45,406✔
373
  u = 1;
45,406✔
374
  v = 1;
45,406✔
375
  period = c_threshold;
45,406✔
376

377
  if (params->fast_restart) {
45,406✔
378
    d_threshold = params->d_threshold;
11,701✔
379
    // HACK to activate the Luby heuristic:
380
    // c_factor must be 0.0 and fast_restart must be true
381
    luby = params->c_factor == 0.0;
11,701✔
382
  }
383

384
  reduce_threshold = params->r_initial_threshold;
45,406✔
385

386
  // initialize then do a propagation + simplification step.
387
  start_search(core, n, a);
45,406✔
388
  trace_start(core);
45,406✔
389
  if (smt_status(core) == YICES_STATUS_SEARCHING) {
45,406✔
390
    // loop
391
    for (;;) {
392
      switch (params->branching) {
47,845✔
393
      case BRANCHING_DEFAULT:
26,987✔
394
        if (luby) {
26,987✔
395
          luby_search(core, c_threshold, &reduce_threshold, params->r_interval);
13,548✔
396
        } else {
397
          search(core, c_threshold, &reduce_threshold, params->r_interval);
13,439✔
398
        }
399
        break;
26,987✔
400
      case BRANCHING_NEGATIVE:
188✔
401
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, negative_branch);
188✔
402
        break;
188✔
403
      case BRANCHING_POSITIVE:
175✔
404
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, positive_branch);
175✔
405
        break;
175✔
406
      case BRANCHING_THEORY:
20,495✔
407
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, theory_branch);
20,495✔
408
        break;
20,495✔
UNCOV
409
      case BRANCHING_TH_NEG:
×
UNCOV
410
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, theory_or_neg_branch);
×
UNCOV
411
        break;
×
UNCOV
412
      case BRANCHING_TH_POS:
×
UNCOV
413
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, theory_or_pos_branch);
×
UNCOV
414
        break;
×
415
      }
416

417
      if (smt_status(core) != YICES_STATUS_SEARCHING) break;
47,845✔
418

419
      smt_restart(core);
2,439✔
420
      //      smt_partial_restart_var(core);
421

422
      if (luby) {
2,439✔
423
        // Luby-style restart
424
        if ((u & -u) == v) {
2,063✔
425
          u ++;
1,111✔
426
          v = 1;
1,111✔
427
        } else {
428
          v <<= 1;
952✔
429
        }
430
        c_threshold = v * period;
2,063✔
431
        trace_restart(core);
2,063✔
432

433
      } else {
434
        // Either Minisat or Picosat-like restart
435

436
        // inner restart: increase c_threshold
437
        c_threshold = (uint32_t) (c_threshold * params->c_factor);
376✔
438

439
        if (c_threshold >= d_threshold) {
376✔
440
          d_threshold = c_threshold; // Minisat-style
290✔
441
          if (params->fast_restart) {
290✔
442
            // Picosat style
443
            // outer restart: reset c_threshold and increase d_threshold
444
            c_threshold = params->c_threshold;
49✔
445
            d_threshold = (uint32_t) (d_threshold * params->d_factor);
49✔
446
          }
447
          trace_restart(core);
290✔
448
        } else {
449
          trace_inner_restart(core);
86✔
450
        }
451
      }
452
    }
453
  }
454

455
  trace_done(core);
45,406✔
456
}
45,406✔
457

458

459
/*
460
 * Initialize the search parameters based on params.
461
 */
462
static void context_set_search_parameters(context_t *ctx, const param_t *params) {
45,406✔
463
  smt_core_t *core;
464
  egraph_t *egraph;
465
  simplex_solver_t *simplex;
466
  fun_solver_t *fsolver;
467
  uint32_t quota;
468

469
  /*
470
   * Set core parameters
471
   */
472
  core = ctx->core;
45,406✔
473
  set_randomness(core, params->randomness);
45,406✔
474
  set_random_seed(core, params->random_seed);
45,406✔
475
  set_var_decay_factor(core, params->var_decay);
45,406✔
476
  set_clause_decay_factor(core, params->clause_decay);
45,406✔
477
  if (params->cache_tclauses) {
45,406✔
478
    enable_theory_cache(core, params->tclause_size);
33,685✔
479
  } else {
480
    disable_theory_cache(core);
11,721✔
481
  }
482

483
  /*
484
   * Set egraph parameters
485
   */
486
  egraph = ctx->egraph;
45,406✔
487
  if (egraph != NULL) {
45,406✔
488
    if (params->use_optimistic_fcheck) {
13,471✔
489
      egraph_enable_optimistic_final_check(egraph);
13,468✔
490
    } else {
491
      egraph_disable_optimistic_final_check(egraph);
3✔
492
    }
493
    if (params->use_dyn_ack) {
13,471✔
494
      egraph_enable_dyn_ackermann(egraph, params->max_ackermann);
13,274✔
495
      egraph_set_ackermann_threshold(egraph, params->dyn_ack_threshold);
13,274✔
496
    } else {
497
      egraph_disable_dyn_ackermann(egraph);
197✔
498
    }
499
    if (params->use_bool_dyn_ack) {
13,471✔
500
      egraph_enable_dyn_boolackermann(egraph, params->max_boolackermann);
13,274✔
501
      egraph_set_boolack_threshold(egraph, params->dyn_bool_ack_threshold);
13,274✔
502
    } else {
503
      egraph_disable_dyn_boolackermann(egraph);
197✔
504
    }
505
    quota = egraph_num_terms(egraph) * params->aux_eq_ratio;
13,471✔
506
    if (quota < params->aux_eq_quota) {
13,471✔
507
      quota = params->aux_eq_quota;
13,410✔
508
    }
509
    egraph_set_aux_eq_quota(egraph, quota);
13,471✔
510
    egraph_set_max_interface_eqs(egraph, params->max_interface_eqs);
13,471✔
511
  }
512

513
  /*
514
   * Set simplex parameters
515
   */
516
  if (context_has_simplex_solver(ctx)) {
45,406✔
517
    simplex = ctx->arith_solver;
33,247✔
518
    if (params->use_simplex_prop) {
33,247✔
519
      simplex_enable_propagation(simplex);
12,871✔
520
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,871✔
521
    }
522
    if (params->adjust_simplex_model) {
33,247✔
523
      simplex_enable_adjust_model(simplex);
12,825✔
524
    }
525
    simplex_set_bland_threshold(simplex, params->bland_threshold);
33,247✔
526
    if (params->integer_check) {
33,247✔
UNCOV
527
      simplex_enable_periodic_icheck(simplex);
×
UNCOV
528
      simplex_set_integer_check_period(simplex, params->integer_check_period);
×
529
    }
530
  }
531

532
  /*
533
   * Set array solver parameters
534
   */
535
  if (context_has_fun_solver(ctx)) {
45,406✔
536
    fsolver = ctx->fun_solver;
12,886✔
537
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,886✔
538
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,886✔
539
  }
540
}
45,406✔
541

542
static smt_status_t _o_call_mcsat_solver(context_t *ctx, const param_t *params) {
1,136✔
543
  mcsat_solve(ctx->mcsat, params, NULL, 0, NULL);
1,136✔
544
  return mcsat_status(ctx->mcsat);
1,136✔
545
}
546

547
static smt_status_t call_mcsat_solver(context_t *ctx, const param_t *params) {
1,136✔
548
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_call_mcsat_solver(ctx, params));
1,136✔
549
}
550

551
/*
552
 * Initialize search parameters then call solve
553
 * - if ctx->status is not IDLE, return the status.
554
 * - if params is NULL, we use default values.
555
 */
556
smt_status_t check_context(context_t *ctx, const param_t *params) {
60,724✔
557
  smt_core_t *core;
558
  smt_status_t stat;
559

560
  if (params == NULL) {
60,724✔
UNCOV
561
    params = get_default_params();
×
562
  }
563

564
  if (ctx->mcsat != NULL) {
60,724✔
565
    return call_mcsat_solver(ctx, params);
1,136✔
566
  }
567

568
  core = ctx->core;
59,588✔
569
  stat = smt_status(core);
59,588✔
570
  if (stat == YICES_STATUS_IDLE) {
59,588✔
571
    // clean state: the search can proceed
572
    context_set_search_parameters(ctx, params);
42,764✔
573
    solve(core, params, 0, NULL);
42,764✔
574
    stat = smt_status(core);
42,764✔
575
  }
576

577
  return stat;
59,588✔
578
}
579

580

581
/*
582
 * Check with assumptions a[0] ... a[n-1]
583
 * - if ctx->status is not IDLE, return the status.
584
 */
585
smt_status_t check_context_with_assumptions(context_t *ctx, const param_t *params, uint32_t n, const literal_t *a) {
2,642✔
586
  smt_core_t *core;
587
  smt_status_t stat;
588

589
  assert(ctx->mcsat == NULL);
590

591
  core = ctx->core;
2,642✔
592
  stat = smt_status(core);
2,642✔
593
  if (stat == YICES_STATUS_IDLE) {
2,642✔
594
    // clean state
595
    if (params == NULL) {
2,642✔
UNCOV
596
      params = get_default_params();
×
597
    }
598
    context_set_search_parameters(ctx, params);
2,642✔
599
    solve(core, params, n, a);
2,642✔
600
    stat = smt_status(core);
2,642✔
601
  }
602

603
  return stat;
2,642✔
604
}
605

606
typedef struct sat_delegate_state_s {
607
  delegate_t delegate;
608
  sat_delegate_t mode;
609
  sat_delegate_incremental_mode_t exec_mode;
610
  bool live;
611
  bool stale;
612
  bool true_forwarded;
613
  bool checked_once;
614
  uint32_t delegate_nvars;
615
  uint32_t size;
616
  bvar_t *act_var;
617
  uint32_t *fwd_units;
618
  uint32_t *fwd_bins;
619
  uint32_t *fwd_clauses;
620
  ivector_t assumptions;
621
  ivector_t failed;
622
} sat_delegate_state_t;
623

624
void context_reset_sat_delegate_stats(context_t *ctx) {
22,371✔
625
  ctx->sat_delegate_stats.rebuild_checks = 0;
22,371✔
626
  ctx->sat_delegate_stats.append_checks = 0;
22,371✔
627
  ctx->sat_delegate_stats.selector_frame_checks = 0;
22,371✔
628
  ctx->sat_delegate_stats.delegate_initializations = 0;
22,371✔
629
  ctx->sat_delegate_stats.delegate_reinitializations = 0;
22,371✔
630
  ctx->sat_delegate_stats.selector_variables = 0;
22,371✔
631
  ctx->sat_delegate_stats.selector_assumptions = 0;
22,371✔
632
  ctx->sat_delegate_stats.selector_retirements = 0;
22,371✔
633
  ctx->sat_delegate_stats.post_check_clause_forwards = 0;
22,371✔
634
}
22,371✔
635

636
void context_get_sat_delegate_stats(const context_t *ctx, sat_delegate_stats_t *stats) {
12✔
637
  *stats = ctx->sat_delegate_stats;
12✔
638
}
12✔
639

640
void context_sat_delegate_state_cleanup(context_t *ctx) {
22,370✔
641
  sat_delegate_state_t *st;
642

643
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
22,370✔
644
  if (st == NULL) {
22,370✔
645
    return;
22,361✔
646
  }
647

648
  if (st->live) {
9✔
649
    delete_delegate(&st->delegate);
9✔
650
    st->live = false;
9✔
651
  }
652
  safe_free(st->act_var);
9✔
653
  safe_free(st->fwd_units);
9✔
654
  safe_free(st->fwd_bins);
9✔
655
  safe_free(st->fwd_clauses);
9✔
656
  delete_ivector(&st->assumptions);
9✔
657
  delete_ivector(&st->failed);
9✔
658
  safe_free(st);
9✔
659
  ctx->sat_delegate_state = NULL;
9✔
660
}
661

662
static sat_delegate_state_t *context_get_sat_delegate_state(context_t *ctx) {
42✔
663
  sat_delegate_state_t *st;
664

665
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
42✔
666
  if (st == NULL) {
42✔
667
    st = (sat_delegate_state_t *) safe_malloc(sizeof(sat_delegate_state_t));
9✔
668
    st->mode = SAT_DELEGATE_NONE;
9✔
669
    st->exec_mode = SAT_DELEGATE_MODE_REBUILD;
9✔
670
    st->live = false;
9✔
671
    st->stale = false;
9✔
672
    st->true_forwarded = false;
9✔
673
    st->checked_once = false;
9✔
674
    st->delegate_nvars = 0;
9✔
675
    st->size = 0;
9✔
676
    st->act_var = NULL;
9✔
677
    st->fwd_units = NULL;
9✔
678
    st->fwd_bins = NULL;
9✔
679
    st->fwd_clauses = NULL;
9✔
680
    init_ivector(&st->assumptions, 0);
9✔
681
    init_ivector(&st->failed, 0);
9✔
682
    ctx->sat_delegate_state = st;
9✔
683
  }
684
  return st;
42✔
685
}
686

687
static void sat_delegate_state_reset_cursors(sat_delegate_state_t *st) {
11✔
688
  uint32_t i;
689

690
  st->true_forwarded = false;
11✔
691
  for (i=0; i<st->size; i++) {
99✔
692
    st->act_var[i] = 0;
88✔
693
    st->fwd_units[i] = 0;
88✔
694
    st->fwd_bins[i] = 0;
88✔
695
    st->fwd_clauses[i] = 0;
88✔
696
  }
697
}
11✔
698

699
static void sat_delegate_state_grow(sat_delegate_state_t *st, uint32_t min_size) {
52✔
700
  uint32_t old_size, new_size, i;
701

702
  if (st->size > min_size) {
52✔
703
    return;
43✔
704
  }
705

706
  old_size = st->size;
9✔
707
  new_size = old_size == 0 ? 8 : old_size;
9✔
708
  while (new_size <= min_size) {
9✔
709
    new_size <<= 1;
×
710
  }
711

712
  st->act_var = (bvar_t *) safe_realloc(st->act_var, new_size * sizeof(bvar_t));
9✔
713
  st->fwd_units = (uint32_t *) safe_realloc(st->fwd_units, new_size * sizeof(uint32_t));
9✔
714
  st->fwd_bins = (uint32_t *) safe_realloc(st->fwd_bins, new_size * sizeof(uint32_t));
9✔
715
  st->fwd_clauses = (uint32_t *) safe_realloc(st->fwd_clauses, new_size * sizeof(uint32_t));
9✔
716
  for (i=old_size; i<new_size; i++) {
81✔
717
    st->act_var[i] = 0;
72✔
718
    st->fwd_units[i] = 0;
72✔
719
    st->fwd_bins[i] = 0;
72✔
720
    st->fwd_clauses[i] = 0;
72✔
721
  }
722
  st->size = new_size;
9✔
723
}
724

725
static void context_import_delegate_model(smt_core_t *core, delegate_t *d) {
37✔
726
  bvar_t x;
727

728
  for (x=0; x<num_vars(core); x++) {
1,088✔
729
    set_bvar_value(core, x, delegate_get_value(d, x));
1,051✔
730
  }
731
}
37✔
732

733
static void set_delegate_assumption_state(smt_core_t *core, uint32_t n, const literal_t *assumptions,
42✔
734
                                          smt_status_t stat, const ivector_t *failed) {
735
  if (n == 0) {
42✔
736
    core->has_assumptions = false;
3✔
737
    core->num_assumptions = 0;
3✔
738
    core->assumption_index = 0;
3✔
739
    core->assumptions = NULL;
3✔
740
    core->bad_assumption = null_literal;
3✔
741
    return;
3✔
742
  }
743

744
  core->has_assumptions = true;
39✔
745
  core->num_assumptions = n;
39✔
746
  core->assumption_index = n;
39✔
747
  core->assumptions = NULL;
39✔
748
  core->bad_assumption = null_literal;
39✔
749

750
  if (stat == YICES_STATUS_UNSAT && failed != NULL && failed->size > 0) {
39✔
751
    core->bad_assumption = failed->data[0];
5✔
752
  }
753
}
754

755
static void delegate_add_clause_with_guard(delegate_t *delegate, const clause_t *c, literal_t guard) {
10✔
756
  uint32_t i;
757
  literal_t l;
758

759
  ivector_reset(&delegate->buffer);
10✔
760
  if (guard != true_literal) {
10✔
UNCOV
761
    ivector_push(&delegate->buffer, guard);
×
762
  }
763
  i = 0;
10✔
764
  l = c->cl[0];
10✔
765
  while (l >= 0) {
76✔
766
    ivector_push(&delegate->buffer, l);
66✔
767
    i ++;
66✔
768
    l = c->cl[i];
66✔
769
  }
770
  delegate->add_clause(delegate->solver, delegate->buffer.size, delegate->buffer.data);
10✔
771
}
10✔
772

773
static void delegate_forward_clause_range(sat_delegate_state_t *st, smt_core_t *core, sat_delegate_stats_t *stats,
71✔
774
                                          uint32_t level,
775
                                          uint32_t end_units, uint32_t end_bins, uint32_t end_clauses,
776
                                          literal_t guard) {
777
  uint32_t i;
778
  bool forwarded;
779

780
  if (!st->true_forwarded) {
71✔
781
    st->delegate.add_unit_clause(st->delegate.solver, true_literal);
10✔
782
    st->true_forwarded = true;
10✔
783
  }
784

UNCOV
785
  forwarded = (core->inconsistent && st->fwd_units[level] == 0 && st->fwd_bins[level] == 0 && st->fwd_clauses[level] == 0) ||
×
786
              st->fwd_units[level] < end_units ||
71✔
787
              st->fwd_bins[level] < end_bins ||
175✔
788
              st->fwd_clauses[level] < end_clauses;
33✔
789
  if (st->checked_once && forwarded) {
71✔
790
    stats->post_check_clause_forwards ++;
29✔
791
  }
792

793
  if (core->inconsistent && st->fwd_units[level] == 0 && st->fwd_bins[level] == 0 && st->fwd_clauses[level] == 0) {
71✔
UNCOV
794
    if (guard == true_literal) {
×
UNCOV
795
      st->delegate.add_empty_clause(st->delegate.solver);
×
796
    } else {
UNCOV
797
      st->delegate.add_unit_clause(st->delegate.solver, guard);
×
798
    }
799
  }
800

801
  for (i=st->fwd_units[level]; i<end_units; i++) {
333✔
802
    if (guard == true_literal) {
262✔
803
      st->delegate.add_unit_clause(st->delegate.solver, core->stack.lit[i]);
41✔
804
    } else {
805
      st->delegate.add_binary_clause(st->delegate.solver, guard, core->stack.lit[i]);
221✔
806
    }
807
  }
808
  st->fwd_units[level] = end_units;
71✔
809

810
  for (i=st->fwd_bins[level]; i<end_bins; i += 2) {
401✔
811
    if (guard == true_literal) {
330✔
812
      st->delegate.add_binary_clause(st->delegate.solver, core->binary_clauses.data[i], core->binary_clauses.data[i+1]);
97✔
813
    } else {
814
      st->delegate.add_ternary_clause(st->delegate.solver, guard, core->binary_clauses.data[i], core->binary_clauses.data[i+1]);
233✔
815
    }
816
  }
817
  st->fwd_bins[level] = end_bins;
71✔
818

819
  if (level == 0 && st->fwd_clauses[level] > end_clauses) {
71✔
820
    st->fwd_clauses[level] = end_clauses;
×
821
  }
822
  for (i=st->fwd_clauses[level]; i<end_clauses; i++) {
81✔
823
    delegate_add_clause_with_guard(&st->delegate, core->problem_clauses[i], guard);
10✔
824
  }
825
  st->fwd_clauses[level] = end_clauses;
71✔
826
}
71✔
827

828
static void sat_delegate_state_close(sat_delegate_state_t *st) {
1✔
829
  if (st->live) {
1✔
830
    delete_delegate(&st->delegate);
1✔
831
    st->live = false;
1✔
832
  }
833
  st->mode = SAT_DELEGATE_NONE;
1✔
834
  st->exec_mode = SAT_DELEGATE_MODE_REBUILD;
1✔
835
  st->stale = false;
1✔
836
  st->checked_once = false;
1✔
837
  st->delegate_nvars = 0;
1✔
838
  sat_delegate_state_reset_cursors(st);
1✔
839
}
1✔
840

841
static bool context_prepare_append_delegate(context_t *ctx, sat_delegate_state_t *st, const char *sat_solver,
8✔
842
                                            uint32_t verbosity) {
843
  smt_core_t *core;
844
  uint32_t nvars;
845
  uint32_t nnew;
846

847
  core = ctx->core;
8✔
848
  nvars = num_vars(core);
8✔
849

850
  if (st->live && (st->mode != ctx->sat_delegate || st->exec_mode != SAT_DELEGATE_MODE_APPEND)) {
8✔
UNCOV
851
    sat_delegate_state_close(st);
×
852
  }
853

854
  if (!st->live || st->stale) {
8✔
855
    if (st->live) {
5✔
856
      ctx->sat_delegate_stats.delegate_reinitializations ++;
1✔
857
      sat_delegate_state_close(st);
1✔
858
    }
859
    sat_delegate_state_grow(st, 0);
5✔
860
    if (!init_delegate_incremental(&st->delegate, sat_solver, nvars)) {
5✔
UNCOV
861
      return false;
×
862
    }
863
    ctx->sat_delegate_stats.delegate_initializations ++;
5✔
864
    delegate_set_verbosity(&st->delegate, verbosity);
5✔
865
    st->mode = ctx->sat_delegate;
5✔
866
    st->exec_mode = SAT_DELEGATE_MODE_APPEND;
5✔
867
    st->stale = false;
5✔
868
    st->delegate_nvars = nvars;
5✔
869
    st->live = true;
5✔
870
    sat_delegate_state_reset_cursors(st);
5✔
871
  }
872

873
  if (st->delegate_nvars < nvars) {
8✔
874
    nnew = nvars - st->delegate_nvars;
2✔
875
    delegate_add_vars(&st->delegate, nnew);
2✔
876
    st->delegate_nvars = nvars;
2✔
877
  }
878

879
  sat_delegate_state_grow(st, 0);
8✔
880
  delegate_forward_clause_range(st, core, &ctx->sat_delegate_stats, 0, core->nb_unit_clauses,
8✔
881
                                (uint32_t) core->binary_clauses.size,
8✔
882
                                (uint32_t) get_cv_size(core->problem_clauses),
8✔
883
                                true_literal);
884

885
  return true;
8✔
886
}
887

888
static bool context_prepare_selector_delegate(context_t *ctx, sat_delegate_state_t *st, const char *sat_solver,
34✔
889
                                              uint32_t verbosity) {
890
  smt_core_t *core;
891
  uint32_t d, k, nvars, nnew;
892
  uint32_t end_units, end_bins, end_clauses;
893
  trail_t *trail_data;
894
  literal_t guard;
895

896
  core = ctx->core;
34✔
897
  nvars = num_vars(core);
34✔
898
  d = smt_base_level(core);
34✔
899
  trail_data = core->trail_stack.data;
34✔
900

901
  if (st->live && (st->mode != ctx->sat_delegate || st->exec_mode != SAT_DELEGATE_MODE_SELECTOR_FRAMES)) {
34✔
UNCOV
902
    sat_delegate_state_close(st);
×
903
  }
904

905
  if (!st->live) {
34✔
906
    sat_delegate_state_grow(st, d);
5✔
907
    if (!init_delegate_incremental(&st->delegate, sat_solver, nvars)) {
5✔
UNCOV
908
      return false;
×
909
    }
910
    ctx->sat_delegate_stats.delegate_initializations ++;
5✔
911
    delegate_set_verbosity(&st->delegate, verbosity);
5✔
912
    st->mode = ctx->sat_delegate;
5✔
913
    st->exec_mode = SAT_DELEGATE_MODE_SELECTOR_FRAMES;
5✔
914
    st->stale = false;
5✔
915
    st->delegate_nvars = nvars;
5✔
916
    st->live = true;
5✔
917
    sat_delegate_state_reset_cursors(st);
5✔
918
  }
919

920
  if (st->delegate_nvars < nvars) {
34✔
921
    nnew = nvars - st->delegate_nvars;
2✔
922
    delegate_add_vars(&st->delegate, nnew);
2✔
923
    st->delegate_nvars = nvars;
2✔
924
  }
925

926
  sat_delegate_state_grow(st, d);
34✔
927
  for (k=1; k<=d; k++) {
63✔
928
    if (st->act_var[k] == 0) {
29✔
929
      /*
930
       * Selectors must live in the SMT core's variable namespace too:
931
       * otherwise a later bit-blasted assertion could reuse the same bvar.
932
       */
933
      do {
934
        st->act_var[k] = create_boolean_variable(core);
303✔
935
      } while (st->act_var[k] < st->delegate_nvars);
303✔
936
      delegate_add_vars(&st->delegate, st->act_var[k] + 1 - st->delegate_nvars);
27✔
937
      delegate_freeze_literal(&st->delegate, pos_lit(st->act_var[k]));
27✔
938
      ctx->sat_delegate_stats.selector_variables ++;
27✔
939
      st->delegate_nvars = st->act_var[k] + 1;
27✔
940
      st->fwd_units[k] = trail_data[k-1].nunits;
27✔
941
      st->fwd_bins[k] = trail_data[k-1].nbins;
27✔
942
      st->fwd_clauses[k] = trail_data[k-1].nclauses;
27✔
943
    }
944
  }
945

946
  for (k=0; k<=d; k++) {
97✔
947
    guard = (k == 0) ? true_literal : neg_lit(st->act_var[k]);
63✔
948
    end_units = (k < d) ? trail_data[k].nunits : core->nb_unit_clauses;
63✔
949
    end_bins = (k < d) ? trail_data[k].nbins : (uint32_t) core->binary_clauses.size;
63✔
950
    end_clauses = (k < d) ? trail_data[k].nclauses : (uint32_t) get_cv_size(core->problem_clauses);
63✔
951
    delegate_forward_clause_range(st, core, &ctx->sat_delegate_stats, k, end_units, end_bins, end_clauses, guard);
63✔
952
  }
953

954
  return true;
34✔
955
}
956

957
void context_sat_delegate_state_pop(context_t *ctx, uint32_t level) {
1,573✔
958
  sat_delegate_state_t *st;
959

960
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
1,573✔
961
  if (st == NULL || !st->live) {
1,573✔
962
    return;
1,547✔
963
  }
964

965
  if (st->exec_mode == SAT_DELEGATE_MODE_APPEND) {
26✔
966
    st->stale = true;
1✔
967
  } else if (st->exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES) {
25✔
968
    if (level < st->size && st->act_var[level] != 0) {
25✔
969
      delegate_melt_literal(&st->delegate, pos_lit(st->act_var[level]));
25✔
970
      st->delegate.add_unit_clause(st->delegate.solver, neg_lit(st->act_var[level]));
25✔
971
      ctx->sat_delegate_stats.selector_retirements ++;
25✔
972
      st->act_var[level] = 0;
25✔
973
    }
974
  }
975
}
976

977
static smt_status_t check_with_persistent_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity,
60✔
978
                                                   sat_delegate_incremental_mode_t exec_mode,
979
                                                   uint32_t n, const literal_t *assumptions, ivector_t *failed) {
980
  smt_status_t stat;
981
  smt_core_t *core;
982
  sat_delegate_state_t *st;
983
  ivector_t visible_failed;
984
  uint32_t i;
985

986
  core = ctx->core;
60✔
987
  stat = smt_status(core);
60✔
988
  if (stat != YICES_STATUS_IDLE) {
60✔
UNCOV
989
    return stat;
×
990
  }
991

992
  start_search(core, 0, NULL);
60✔
993
  smt_process(core);
60✔
994
  stat = smt_status(core);
60✔
995

996
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
997
         stat == YICES_STATUS_INTERRUPTED);
998

999
  if (stat != YICES_STATUS_SEARCHING) {
60✔
UNCOV
1000
    return stat;
×
1001
  }
1002

1003
  if (n == 0 && smt_easy_sat(core)) {
60✔
1004
    stat = YICES_STATUS_SAT;
18✔
1005
    set_smt_status(core, stat);
18✔
1006
    return stat;
18✔
1007
  }
1008

1009
  st = context_get_sat_delegate_state(ctx);
42✔
1010
  if (exec_mode == SAT_DELEGATE_MODE_APPEND) {
42✔
1011
    if (!context_prepare_append_delegate(ctx, st, sat_solver, verbosity)) {
8✔
UNCOV
1012
      return YICES_STATUS_UNKNOWN;
×
1013
    }
1014
  } else {
1015
    assert(exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES);
1016
    if (!context_prepare_selector_delegate(ctx, st, sat_solver, verbosity)) {
34✔
UNCOV
1017
      return YICES_STATUS_UNKNOWN;
×
1018
    }
1019
  }
1020

1021
  if (n > 0 && !delegate_supports_assumptions(&st->delegate)) {
42✔
UNCOV
1022
    return YICES_STATUS_UNKNOWN;
×
1023
  }
1024

1025
  init_ivector(&visible_failed, 0);
42✔
1026
  ivector_reset(&st->assumptions);
42✔
1027
  ivector_reset(&st->failed);
42✔
1028
  if (exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES) {
42✔
1029
    uint32_t k, d;
1030
    d = smt_base_level(core);
34✔
1031
    for (k=1; k<=d; k++) {
63✔
1032
      if (k < st->size && st->act_var[k] != 0) {
29✔
1033
        ivector_push(&st->assumptions, pos_lit(st->act_var[k]));
29✔
1034
        ctx->sat_delegate_stats.selector_assumptions ++;
29✔
1035
      }
1036
    }
1037
  }
1038
  for (i=0; i<n; i++) {
82✔
1039
    ivector_push(&st->assumptions, assumptions[i]);
40✔
1040
  }
1041

1042
  if (st->assumptions.size == 0) {
42✔
1043
    stat = st->delegate.check(st->delegate.solver);
3✔
1044
  } else if (delegate_supports_assumptions(&st->delegate)) {
39✔
1045
    stat = delegate_check_with_assumptions(&st->delegate, st->assumptions.size,
39✔
1046
                                           (literal_t *) st->assumptions.data, &st->failed);
39✔
1047
    if (stat == YICES_STATUS_UNSAT) {
39✔
1048
      for (i=0; i<st->failed.size; i++) {
14✔
1049
        literal_t l = st->failed.data[i];
9✔
1050
        uint32_t j;
1051
        for (j=0; j<n; j++) {
13✔
1052
          if (l == assumptions[j]) {
10✔
1053
            ivector_push(&visible_failed, l);
6✔
1054
            break;
6✔
1055
          }
1056
        }
1057
      }
1058
      if (failed != NULL) {
5✔
1059
        ivector_reset(failed);
5✔
1060
        ivector_add(failed, visible_failed.data, visible_failed.size);
5✔
1061
      }
1062
    }
1063
  } else {
UNCOV
1064
    stat = YICES_STATUS_UNKNOWN;
×
1065
  }
1066

1067
  set_smt_status(core, stat);
42✔
1068
  set_delegate_assumption_state(core, n, assumptions, stat, &visible_failed);
42✔
1069
  if (stat == YICES_STATUS_SAT) {
42✔
1070
    context_import_delegate_model(core, &st->delegate);
37✔
1071
  }
1072
  st->checked_once = true;
42✔
1073

1074
  delete_ivector(&visible_failed);
42✔
1075
  return stat;
42✔
1076
}
1077

1078
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
1079
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed);
1080

1081
smt_status_t check_with_sat_delegate(context_t *ctx, const char *sat_solver,
98✔
1082
                                     sat_delegate_incremental_mode_t mode,
1083
                                     uint32_t verbosity, uint32_t n,
1084
                                     const literal_t *assumptions, ivector_t *failed) {
1085
  switch (mode) {
98✔
1086
  case SAT_DELEGATE_MODE_REBUILD:
38✔
1087
    ctx->sat_delegate_stats.rebuild_checks ++;
38✔
1088
    if (n == 0) {
38✔
1089
      return check_with_delegate(ctx, sat_solver, verbosity);
38✔
1090
    } else {
UNCOV
1091
      return check_with_delegate_assumptions(ctx, sat_solver, verbosity, n, assumptions, failed);
×
1092
    }
1093

1094
  case SAT_DELEGATE_MODE_APPEND:
18✔
1095
    ctx->sat_delegate_stats.append_checks ++;
18✔
1096
    return check_with_persistent_delegate(ctx, sat_solver, verbosity, SAT_DELEGATE_MODE_APPEND,
18✔
1097
                                          n, assumptions, failed);
1098

1099
  case SAT_DELEGATE_MODE_SELECTOR_FRAMES:
42✔
1100
    ctx->sat_delegate_stats.selector_frame_checks ++;
42✔
1101
    return check_with_persistent_delegate(ctx, sat_solver, verbosity, SAT_DELEGATE_MODE_SELECTOR_FRAMES,
42✔
1102
                                          n, assumptions, failed);
1103

UNCOV
1104
  default:
×
UNCOV
1105
    return YICES_STATUS_UNKNOWN;
×
1106
  }
1107
}
1108

1109
/*
1110
 * Explore term t and collect all Boolean atoms into atoms.
1111
 */
1112
static void collect_boolean_atoms(context_t *ctx, term_t t, int_hset_t *atoms, int_hset_t *visited) {
64✔
1113
  term_table_t *terms;
1114
  uint32_t i, nchildren;
1115

1116
  if (t < 0) {
64✔
UNCOV
1117
    t = not(t);
×
1118
  }
1119

1120
  if (int_hset_member(visited, t)) {
64✔
UNCOV
1121
    return;
×
1122
  }
1123
  int_hset_add(visited, t);
64✔
1124

1125
  terms = ctx->terms;
64✔
1126
  if (term_type(terms, t) == bool_type(terms->types)) {
64✔
1127
    int_hset_add(atoms, t);
64✔
1128
  }
1129

1130
  if (term_is_projection(terms, t)) {
64✔
UNCOV
1131
    collect_boolean_atoms(ctx, proj_term_arg(terms, t), atoms, visited);
×
1132
  } else if (term_is_sum(terms, t)) {
64✔
UNCOV
1133
    nchildren = term_num_children(terms, t);
×
UNCOV
1134
    for (i=0; i<nchildren; i++) {
×
1135
      term_t child;
1136
      mpq_t q;
UNCOV
1137
      mpq_init(q);
×
UNCOV
1138
      sum_term_component(terms, t, i, q, &child);
×
UNCOV
1139
      collect_boolean_atoms(ctx, child, atoms, visited);
×
UNCOV
1140
      mpq_clear(q);
×
1141
    }
1142
  } else if (term_is_bvsum(terms, t)) {
64✔
1143
    uint32_t nbits = term_bitsize(terms, t);
×
UNCOV
1144
    int32_t *aux = (int32_t*) safe_malloc(nbits * sizeof(int32_t));
×
1145
    nchildren = term_num_children(terms, t);
×
1146
    for (i=0; i<nchildren; i++) {
×
1147
      term_t child;
1148
      bvsum_term_component(terms, t, i, aux, &child);
×
1149
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1150
    }
1151
    safe_free(aux);
×
1152
  } else if (term_is_product(terms, t)) {
64✔
UNCOV
1153
    nchildren = term_num_children(terms, t);
×
UNCOV
1154
    for (i=0; i<nchildren; i++) {
×
1155
      term_t child;
1156
      uint32_t exp;
UNCOV
1157
      product_term_component(terms, t, i, &child, &exp);
×
UNCOV
1158
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1159
    }
1160
  } else if (term_is_composite(terms, t)) {
64✔
1161
    nchildren = term_num_children(terms, t);
34✔
1162
    for (i=0; i<nchildren; i++) {
89✔
1163
      collect_boolean_atoms(ctx, term_child(terms, t, i), atoms, visited);
55✔
1164
    }
1165
  }
1166
}
1167

1168
/*
1169
 * Extract assumptions whose labels appear in term t.
1170
 */
1171
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✔
1172
  int_hset_t atoms, visited;
1173
  uint32_t i;
1174

1175
  init_int_hset(&atoms, 0);
9✔
1176
  init_int_hset(&visited, 0);
9✔
1177
  collect_boolean_atoms(ctx, t, &atoms, &visited);
9✔
1178

1179
  ivector_reset(core);
9✔
1180
  for (i=0; i<labels->size; i++) {
83✔
1181
    term_t label = labels->data[i];
74✔
1182
    if (int_hset_member(&atoms, label)) {
74✔
1183
      int_hmap_pair_t *p = int_hmap_find((int_hmap_t *) label_map, label);
30✔
1184
      if (p != NULL) {
30✔
1185
        ivector_push(core, p->val);
30✔
1186
      }
1187
    }
1188
  }
1189

1190
  delete_int_hset(&visited);
9✔
1191
  delete_int_hset(&atoms);
9✔
1192
}
9✔
1193

1194
/*
1195
 * Cache a core vector in the context.
1196
 */
1197
static void cache_unsat_core(context_t *ctx, const ivector_t *core) {
2,713✔
1198
  if (ctx->unsat_core_cache == NULL) {
2,713✔
1199
    ctx->unsat_core_cache = (ivector_t *) safe_malloc(sizeof(ivector_t));
2,713✔
1200
    init_ivector(ctx->unsat_core_cache, core->size);
2,713✔
1201
  } else {
UNCOV
1202
    ivector_reset(ctx->unsat_core_cache);
×
1203
  }
1204
  ivector_copy(ctx->unsat_core_cache, core->data, core->size);
2,713✔
1205
}
2,713✔
1206

1207
static void cache_failed_assumptions_core(context_t *ctx, uint32_t n, const term_t *a,
5✔
1208
                                          const ivector_t *assumption_literals,
1209
                                          const ivector_t *failed_literals) {
1210
  ivector_t core_terms;
1211
  int_hset_t failed;
1212
  uint32_t i;
1213

1214
  init_ivector(&core_terms, 0);
5✔
1215
  init_int_hset(&failed, 0);
5✔
1216
  for (i=0; i<failed_literals->size; i++) {
11✔
1217
    int_hset_add(&failed, failed_literals->data[i]);
6✔
1218
  }
1219
  for (i=0; i<n; i++) {
11✔
1220
    if (int_hset_member(&failed, assumption_literals->data[i])) {
6✔
1221
      ivector_push(&core_terms, a[i]);
6✔
1222
    }
1223
  }
1224
  cache_unsat_core(ctx, &core_terms);
5✔
1225
  delete_int_hset(&failed);
5✔
1226
  delete_ivector(&core_terms);
5✔
1227
}
5✔
1228

1229
/*
1230
 * MCSAT variant of check_context_with_term_assumptions.
1231
 * Caller must hold __yices_globals.lock.
1232
 */
1233
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✔
1234
  smt_status_t stat;
1235
  ivector_t assumptions;
1236
  uint32_t i;
1237

1238
  /*
1239
   * MCSAT: create fresh labels b_i, assert (b_i => a_i), then solve with model b_i=true.
1240
   * We extract interpolant/core before cleanup, then restore sticky UNSAT artifacts.
1241
   */
1242
  if (!context_supports_model_interpolation(ctx)) {
10✔
UNCOV
1243
    if (error != NULL) {
×
UNCOV
1244
      *error = CTX_OPERATION_NOT_SUPPORTED;
×
1245
    }
UNCOV
1246
    return YICES_STATUS_ERROR;
×
1247
  }
1248

1249
  {
1250
    model_t mdl;               // temporary model: sets all label terms b_i to true
1251
    int_hmap_t label_map;      // map label b_i -> original assumption a_i
1252
    ivector_t mapped_core;     // translated core over original assumptions
1253
    term_t interpolant = NULL_TERM; // raw/substituted interpolant for sticky UNSAT result
10✔
1254
    int32_t code;              // return code from assert_formula (negative on internalization error)
1255
    bool pushed;               // whether we pushed a temporary scope and must pop it
1256
    term_manager_t tm;
1257

1258
    init_model(&mdl, ctx->terms, true);
10✔
1259
    init_int_hmap(&label_map, 0);
10✔
1260
    init_ivector(&assumptions, n);
10✔
1261
    init_ivector(&mapped_core, 0);
10✔
1262
    init_term_manager(&tm, ctx->terms);
10✔
1263
    stat = YICES_STATUS_IDLE;
10✔
1264

1265
    pushed = false;
10✔
1266
    if (context_supports_pushpop(ctx)) {
10✔
1267
      context_push(ctx);
9✔
1268
      pushed = true;
9✔
1269
    }
1270

1271
    for (i=0; i<n; i++) {
85✔
1272
      term_t b = new_uninterpreted_term(ctx->terms, bool_id);
75✔
1273
      term_t implication = mk_implies(&tm, b, a[i]);
75✔
1274

1275
      int_hmap_add(&label_map, b, a[i]);
75✔
1276
      code = _o_assert_formula(ctx, implication);
75✔
1277
      if (code < 0) {
75✔
UNCOV
1278
        if (error != NULL) {
×
UNCOV
1279
          *error = code;
×
1280
        }
UNCOV
1281
        stat = YICES_STATUS_ERROR;
×
UNCOV
1282
        break;
×
1283
      }
1284
      model_map_term(&mdl, b, vtbl_mk_bool(&mdl.vtbl, true));
75✔
1285
      ivector_push(&assumptions, b);
75✔
1286
    }
1287

1288
    if (stat != YICES_STATUS_ERROR) {
10✔
1289
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
10✔
1290
      if (stat == YICES_STATUS_UNSAT) {
10✔
1291
        interpolant = context_get_unsat_model_interpolant(ctx);
9✔
1292
        assert(interpolant != NULL_TERM);
1293
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
9✔
1294
      }
1295
    }
1296

1297
    if (pushed) {
10✔
1298
      mcsat_cleanup_assumptions(ctx->mcsat);
9✔
1299
      context_pop(ctx);
9✔
1300
    }
1301
    if (stat == YICES_STATUS_UNSAT) {
10✔
1302
      mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, interpolant, n, assumptions.data, a);
9✔
1303
      cache_unsat_core(ctx, &mapped_core);
9✔
1304
    }
1305

1306
    delete_term_manager(&tm);
10✔
1307
    delete_ivector(&mapped_core);
10✔
1308
    delete_ivector(&assumptions);
10✔
1309
    delete_int_hmap(&label_map);
10✔
1310
    delete_model(&mdl);
10✔
1311

1312
    return stat;
10✔
1313
  }
1314
}
1315

1316
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✔
1317
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
10✔
1318
}
1319

1320
/*
1321
 * Check under assumptions given as terms.
1322
 * - if MCSAT is enabled, this uses temporary labels + model interpolation.
1323
 * - otherwise terms are converted to literals and handled by the CDCL(T) path.
1324
 *
1325
 * Preconditions:
1326
 * - context status must be IDLE.
1327
 */
1328
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,692✔
1329
  if (error != NULL) {
2,692✔
1330
    *error = CTX_NO_ERROR;
2,692✔
1331
  }
1332

1333
  /*
1334
   * Clear any prior term-assumption core before all paths below. Delegate
1335
   * checks cache a new core only on UNSAT.
1336
   */
1337
  context_invalidate_unsat_core_cache(ctx);
2,692✔
1338

1339
  if (ctx->mcsat == NULL) {
2,692✔
1340
    smt_status_t stat;
1341
    sat_delegate_t mode;
1342
    sat_delegate_incremental_mode_t exec_mode;
1343
    bool one_shot;
1344
    const char *delegate;
1345
    bool unknown;
1346
    ivector_t assumptions;
1347
    ivector_t failed;
1348
    uint32_t i;
1349
    literal_t l;
1350

1351
    init_ivector(&assumptions, n);
2,682✔
1352
    for (i=0; i<n; i++) {
90,189✔
1353
      l = context_add_assumption(ctx, a[i]);
87,507✔
1354
      if (l < 0) {
87,507✔
UNCOV
1355
        if (error != NULL) {
×
UNCOV
1356
          *error = l;
×
1357
        }
UNCOV
1358
        delete_ivector(&assumptions);
×
UNCOV
1359
        return YICES_STATUS_ERROR;
×
1360
      }
1361
      ivector_push(&assumptions, l);
87,507✔
1362
    }
1363

1364
    mode = effective_sat_delegate_mode(ctx->sat_delegate, params, &one_shot);
2,682✔
1365
    delegate = sat_delegate_name(mode);
2,682✔
1366
    if (delegate == NULL) {
2,682✔
1367
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,642✔
1368
      delete_ivector(&assumptions);
2,642✔
1369
      return stat;
2,642✔
1370
    }
1371

1372
    if (ctx->logic != QF_BV) {
40✔
UNCOV
1373
      if (error != NULL) {
×
UNCOV
1374
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1375
      }
UNCOV
1376
      delete_ivector(&assumptions);
×
UNCOV
1377
      return YICES_STATUS_ERROR;
×
1378
    }
1379

1380
    if (!supported_delegate(delegate, &unknown)) {
40✔
UNCOV
1381
      if (error != NULL) {
×
UNCOV
1382
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1383
      }
UNCOV
1384
      delete_ivector(&assumptions);
×
UNCOV
1385
      return YICES_STATUS_ERROR;
×
1386
    }
1387

1388
    if (!delegate_supports_assumptions_name(delegate)) {
40✔
1389
      if (error != NULL) {
1✔
1390
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1391
      }
1392
      delete_ivector(&assumptions);
1✔
1393
      return YICES_STATUS_ERROR;
1✔
1394
    }
1395

1396
    init_ivector(&failed, 0);
39✔
1397
    if (!effective_sat_delegate_incremental_mode(mode, ctx->sat_delegate_incremental_mode,
39✔
1398
                                                ctx->sat_delegate_incremental_mode_set,
39✔
1399
                                                ctx->mode == CTX_MODE_ONECHECK,
39✔
1400
                                                one_shot, &exec_mode)) {
UNCOV
1401
      if (error != NULL) {
×
UNCOV
1402
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1403
      }
UNCOV
1404
      delete_ivector(&failed);
×
UNCOV
1405
      delete_ivector(&assumptions);
×
UNCOV
1406
      return YICES_STATUS_ERROR;
×
1407
    }
1408
    stat = check_with_sat_delegate(ctx, delegate, exec_mode, 0, n, assumptions.data, &failed);
39✔
1409
    if (stat == YICES_STATUS_UNSAT) {
39✔
1410
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
5✔
1411
    }
1412
    delete_ivector(&failed);
39✔
1413
    delete_ivector(&assumptions);
39✔
1414
    return stat;
39✔
1415
  }
1416

1417
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1418
}
1419

1420
/*
1421
 * Check with given model
1422
 * - if mcsat status is not IDLE, return the status
1423
 */
1424
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✔
1425
  smt_status_t stat;
1426

1427
  assert(ctx->mcsat != NULL);
1428

1429
  stat = mcsat_status(ctx->mcsat);
161✔
1430
  if (stat == YICES_STATUS_IDLE) {
161✔
1431
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
161✔
1432
    stat = mcsat_status(ctx->mcsat);
161✔
1433

1434
    // BD: this looks wrong. We shouldn't call clear yet.
1435
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1436
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1437
    //      context_clear(ctx);
1438
    //    }
1439
  }
1440

1441
  return stat;
161✔
1442
}
1443

1444
/*
1445
 * Check with given model and hints
1446
 * - set the model hint and call check_context_with_model
1447
 */
1448
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✔
1449
  assert(m <= n);
1450

1451
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1452

1453
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1454
}
1455

1456

1457
/*
1458
 * Precheck: force generation of clauses and other stuff that's
1459
 * constructed lazily by the solvers. For example, this
1460
 * can be used to convert all the constraints asserted in the
1461
 * bitvector to clauses so that we can export the result to DIMACS.
1462
 *
1463
 * If ctx status is IDLE:
1464
 * - the function calls 'start_search' and does one round of propagation.
1465
 * - if this results in UNSAT, the function returns UNSAT
1466
 * - if the precheck is interrupted, the function returns INTERRUPTED
1467
 * - otherwise the function returns UNKNOWN and sets the status to
1468
 *   UNKNOWN.
1469
 *
1470
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
1471
 * IDLE before doing anything else with this context.
1472
 *
1473
 * If ctx status is not IDLE, the function returns it and does nothing
1474
 * else.
1475
 */
UNCOV
1476
smt_status_t precheck_context(context_t *ctx) {
×
1477
  smt_status_t stat;
1478
  smt_core_t *core;
1479

UNCOV
1480
  core = ctx->core;
×
1481

UNCOV
1482
  stat = smt_status(core);
×
UNCOV
1483
  if (stat == YICES_STATUS_IDLE) {
×
UNCOV
1484
    start_search(core, 0, NULL);
×
UNCOV
1485
    smt_process(core);
×
UNCOV
1486
    stat = smt_status(core);
×
1487

1488
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1489
           stat == YICES_STATUS_INTERRUPTED);
1490

UNCOV
1491
    if (stat == YICES_STATUS_SEARCHING) {
×
UNCOV
1492
      end_search_unknown(core);
×
UNCOV
1493
      stat = YICES_STATUS_UNKNOWN;
×
1494
    }
1495
  }
1496

UNCOV
1497
  return stat;
×
1498
}
1499

1500

1501

1502
/*
1503
 * Solve using another SAT solver
1504
 * - sat_solver = name of the solver to use
1505
 * - verbosity = verbosity level (0 means quiet)
1506
 * - this may be used only for BV or pure SAT problems
1507
 * - we perform one round of propagation to convert the problem to CNF
1508
 * - then we call an external SAT solver on the CNF problem
1509
 */
1510
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
38✔
1511
  smt_status_t stat;
1512
  smt_core_t *core;
1513
  delegate_t delegate;
1514
  bvar_t x;
1515
  bval_t v;
1516

1517
  core = ctx->core;
38✔
1518

1519
  stat = smt_status(core);
38✔
1520
  if (stat == YICES_STATUS_IDLE) {
38✔
1521
    start_search(core, 0, NULL);
38✔
1522
    smt_process(core);
38✔
1523
    stat = smt_status(core);
38✔
1524

1525
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1526
           stat == YICES_STATUS_INTERRUPTED);
1527

1528
    if (stat == YICES_STATUS_SEARCHING) {
38✔
1529
      if (smt_easy_sat(core)) {
36✔
1530
        stat = YICES_STATUS_SAT;
36✔
1531
      } else {
1532
        // call the delegate
UNCOV
1533
        init_delegate(&delegate, sat_solver, num_vars(core));
×
UNCOV
1534
        ctx->sat_delegate_stats.delegate_initializations ++;
×
UNCOV
1535
        delegate_set_verbosity(&delegate, verbosity);
×
1536

UNCOV
1537
        stat = solve_with_delegate(&delegate, core);
×
UNCOV
1538
        set_smt_status(core, stat);
×
UNCOV
1539
        if (stat == YICES_STATUS_SAT) {
×
UNCOV
1540
          for (x=0; x<num_vars(core); x++) {
×
UNCOV
1541
            v = delegate_get_value(&delegate, x);
×
UNCOV
1542
            set_bvar_value(core, x, v);
×
1543
          }
1544
        }
UNCOV
1545
        delete_delegate(&delegate);
×
1546
      }
1547
    }
1548
  }
1549

1550
  return stat;
38✔
1551
}
1552

1553
/*
1554
 * One-shot check with delegate and assumptions.
1555
 * - assumptions are literals in core encoding.
1556
 * - if failed != NULL and result is UNSAT, failed assumptions are appended to *failed.
1557
 */
UNCOV
1558
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
1559
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1560
  smt_status_t stat;
1561
  smt_core_t *core;
1562
  delegate_t delegate;
1563

UNCOV
1564
  core = ctx->core;
×
1565

UNCOV
1566
  stat = smt_status(core);
×
UNCOV
1567
  if (stat != YICES_STATUS_IDLE) {
×
UNCOV
1568
    return stat;
×
1569
  }
1570

UNCOV
1571
  start_search(core, 0, NULL);
×
UNCOV
1572
  smt_process(core);
×
UNCOV
1573
  stat = smt_status(core);
×
1574

1575
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1576
         stat == YICES_STATUS_INTERRUPTED);
1577

UNCOV
1578
  if (stat != YICES_STATUS_SEARCHING) {
×
UNCOV
1579
    return stat;
×
1580
  }
1581

UNCOV
1582
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
UNCOV
1583
    return YICES_STATUS_UNKNOWN;
×
1584
  }
UNCOV
1585
  ctx->sat_delegate_stats.delegate_initializations ++;
×
UNCOV
1586
  delegate_set_verbosity(&delegate, verbosity);
×
1587

UNCOV
1588
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
UNCOV
1589
  set_smt_status(core, stat);
×
UNCOV
1590
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
UNCOV
1591
  if (stat == YICES_STATUS_SAT) {
×
UNCOV
1592
    context_import_delegate_model(core, &delegate);
×
1593
  }
1594

UNCOV
1595
  delete_delegate(&delegate);
×
UNCOV
1596
  return stat;
×
1597
}
1598

1599

1600
/*
1601
 * Bit-blast then export to DIMACS
1602
 * - filename = name of the output file
1603
 * - status = status of the context after bit-blasting
1604
 *
1605
 * If ctx status is IDLE
1606
 * - perform one round of propagation to conver the problem to CNF
1607
 * - export the CNF to DIMACS
1608
 *
1609
 * If ctx status is not IDLE,
1610
 * - store the stauts in *status and do nothing else
1611
 *
1612
 * Return code:
1613
 *  1 if the DIMACS file was created
1614
 *  0 if the problem was solved by the propagation round
1615
 * -1 if there was an error in creating or writing to the file.
1616
 */
UNCOV
1617
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1618
  smt_core_t *core;
1619
  FILE *f;
1620
  smt_status_t stat;
1621
  int32_t code;
1622

UNCOV
1623
  core = ctx->core;
×
1624

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

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

UNCOV
1635
    if (stat == YICES_STATUS_SEARCHING) {
×
UNCOV
1636
      code = 1;
×
UNCOV
1637
      f = fopen(filename, "w");
×
UNCOV
1638
      if (f == NULL) {
×
UNCOV
1639
        code = -1;
×
1640
      } else {
UNCOV
1641
        dimacs_print_bvcontext(f, ctx);
×
UNCOV
1642
        if (ferror(f)) code = -1;
×
UNCOV
1643
        fclose(f);
×
1644
      }
1645
    }
1646
  }
1647

UNCOV
1648
  *status = stat;
×
1649

UNCOV
1650
  return code;
×
1651
}
1652

1653

1654
/*
1655
 * Simplify then export to Dimacs:
1656
 * - filename = name of the output file
1657
 * - status = status of the context after CNF conversion + preprocessing
1658
 *
1659
 * If ctx status is IDLE
1660
 * - perform one round of propagation to convert the problem to CNF
1661
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
1662
 *
1663
 * If ctx status is not IDLE, the function stores that in *status
1664
 * If y2sat preprocessing solves the formula, return the status also in *status
1665
 *
1666
 * Return code:
1667
 *  1 if the DIMACS file was created
1668
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
1669
 * -1 if there was an error creating or writing to the file.
1670
 */
UNCOV
1671
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1672
  smt_core_t *core;
1673
  FILE *f;
1674
  smt_status_t stat;
1675
  delegate_t delegate;
1676
  bvar_t x;
1677
  bval_t v;
1678
  int32_t code;
1679

UNCOV
1680
  core = ctx->core;
×
1681

UNCOV
1682
  code = 0;
×
UNCOV
1683
  stat = smt_status(core);
×
UNCOV
1684
  if (stat == YICES_STATUS_IDLE) {
×
UNCOV
1685
    start_search(core, 0, NULL);
×
UNCOV
1686
    smt_process(core);
×
UNCOV
1687
    stat = smt_status(core);
×
1688

1689
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1690
           stat == YICES_STATUS_INTERRUPTED);
1691

UNCOV
1692
    if (stat == YICES_STATUS_SEARCHING) {
×
UNCOV
1693
      if (smt_easy_sat(core)) {
×
UNCOV
1694
        stat = YICES_STATUS_SAT;
×
1695
      } else {
1696
        // call the delegate
UNCOV
1697
        init_delegate(&delegate, "y2sat", num_vars(core));
×
UNCOV
1698
        delegate_set_verbosity(&delegate, 0);
×
1699

UNCOV
1700
        stat = preprocess_with_delegate(&delegate, core);
×
UNCOV
1701
        set_smt_status(core, stat);
×
UNCOV
1702
        if (stat == YICES_STATUS_SAT) {
×
UNCOV
1703
          for (x=0; x<num_vars(core); x++) {
×
UNCOV
1704
            v = delegate_get_value(&delegate, x);
×
UNCOV
1705
            set_bvar_value(core, x, v);
×
1706
          }
UNCOV
1707
        } else if (stat == YICES_STATUS_UNKNOWN) {
×
UNCOV
1708
          code = 1;
×
UNCOV
1709
          f = fopen(filename, "w");
×
UNCOV
1710
          if (f == NULL) {
×
UNCOV
1711
            code = -1;
×
1712
          } else {
UNCOV
1713
            export_to_dimacs_with_delegate(&delegate, f);
×
UNCOV
1714
            if (ferror(f)) code = -1;
×
UNCOV
1715
            fclose(f);
×
1716
          }
1717
        }
1718

UNCOV
1719
        delete_delegate(&delegate);
×
1720
      }
1721
    }
1722
  }
1723

UNCOV
1724
  *status = stat;
×
1725

UNCOV
1726
  return code;
×
1727
}
1728

1729

1730

1731
/*
1732
 * MODEL CONSTRUCTION
1733
 */
1734

1735
/*
1736
 * Value of literal l in ctx->core
1737
 */
1738
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,420✔
1739
  value_t v;
1740

1741
  v = null_value; // prevent GCC warning
65,420✔
1742
  switch (literal_value(ctx->core, l)) {
65,420✔
1743
  case VAL_FALSE:
38,901✔
1744
    v = vtbl_mk_false(vtbl);
38,901✔
1745
    break;
38,901✔
UNCOV
1746
  case VAL_UNDEF_FALSE:
×
1747
  case VAL_UNDEF_TRUE:
UNCOV
1748
    v = vtbl_mk_unknown(vtbl);
×
UNCOV
1749
    break;
×
1750
  case VAL_TRUE:
26,519✔
1751
    v = vtbl_mk_true(vtbl);
26,519✔
1752
    break;
26,519✔
1753
  }
1754
  return v;
65,420✔
1755
}
1756

1757

1758
/*
1759
 * Value of arithmetic variable x in ctx->arith_solver
1760
 */
1761
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,590✔
1762
  rational_t *a;
1763
  value_t v;
1764

1765
  assert(context_has_arith_solver(ctx));
1766

1767
  a = &ctx->aux;
22,590✔
1768
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,590✔
1769
    v = vtbl_mk_rational(vtbl, a);
22,590✔
1770
  } else {
UNCOV
1771
    v = vtbl_mk_unknown(vtbl);
×
1772
  }
1773

1774
  return v;
22,590✔
1775
}
1776

1777

1778

1779
/*
1780
 * Value of bitvector variable x in ctx->bv_solver
1781
 */
1782
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,168✔
1783
  bvconstant_t *b;
1784
  value_t v;
1785

1786
  assert(context_has_bv_solver(ctx));
1787

1788
  b = &ctx->bv_buffer;
18,168✔
1789
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,168✔
1790
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,168✔
1791
  } else {
UNCOV
1792
    v = vtbl_mk_unknown(vtbl);
×
1793
  }
1794

1795
  return v;
18,168✔
1796
}
1797

1798

1799
/*
1800
 * Get a value for term t in the solvers or egraph
1801
 * - attach the mapping from t to that value in model
1802
 * - if we don't have a concrete object for t but t is
1803
 *   mapped to a term u and the model->has_alias is true,
1804
 *   then we store the mapping [t --> u] in the model's
1805
 *   alias map.
1806
 */
1807
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
322,453✔
1808
  value_table_t *vtbl;
1809
  term_t r;
1810
  uint32_t polarity;
1811
  int32_t x;
1812
  type_t tau;
1813
  value_t v;
1814

1815
  /*
1816
   * Get the root of t in the substitution table
1817
   */
1818
  r = intern_tbl_get_root(&ctx->intern, t);
322,453✔
1819
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
322,453✔
1820
    /*
1821
     * r is mapped to some object x in egraph/core/or theory solvers
1822
     * - keep track of polarity then force r to positive polarity
1823
     */
1824
    vtbl = model_get_vtbl(model);
111,018✔
1825
    polarity = polarity_of(r);
111,018✔
1826
    r = unsigned_term(r);
111,018✔
1827

1828
    /*
1829
     * Convert x to a concrete value
1830
     */
1831
    x = intern_tbl_map_of_root(&ctx->intern, r);
111,018✔
1832
    if (code_is_eterm(x)) {
111,018✔
1833
      // x refers to an egraph object or true_occ/false_occ
1834
      if (x == bool2code(true)) {
4,840✔
1835
        v = vtbl_mk_true(vtbl);
475✔
1836
      } else if (x == bool2code(false)) {
4,365✔
1837
        v = vtbl_mk_false(vtbl);
1,480✔
1838
      } else {
1839
        assert(context_has_egraph(ctx));
1840
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,885✔
1841
      }
1842

1843
    } else {
1844
      // x refers to a literal or a theory variable
1845
      tau = term_type(ctx->terms, r);
106,178✔
1846
      switch (type_kind(ctx->types, tau)) {
106,178✔
1847
      case BOOL_TYPE:
65,420✔
1848
        v = bool_value(ctx, vtbl, code2literal(x));
65,420✔
1849
        break;
65,420✔
1850

1851
      case INT_TYPE:
22,590✔
1852
      case REAL_TYPE:
1853
        v = arith_value(ctx, vtbl, code2thvar(x));
22,590✔
1854
        break;
22,590✔
1855

1856
      case BITVECTOR_TYPE:
18,168✔
1857
        v = bv_value(ctx, vtbl, code2thvar(x));
18,168✔
1858
        break;
18,168✔
1859

UNCOV
1860
      default:
×
1861
        /*
1862
         * This should never happen:
1863
         * scalar, uninterpreted, tuple, function terms
1864
         * are mapped to egraph terms.
1865
         */
1866
        assert(false);
UNCOV
1867
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
UNCOV
1868
        break;
×
1869
      }
1870
    }
1871

1872
    /*
1873
     * Restore polarity then add mapping [t --> v] in the model
1874
     */
1875
    if (! object_is_unknown(vtbl, v)) {
111,018✔
1876
      if (object_is_boolean(vtbl, v)) {
111,018✔
1877
        if (polarity) {
67,375✔
1878
          // negate the value
1879
          v = vtbl_mk_not(vtbl, v);
24✔
1880
        }
1881
      }
1882
      model_map_term(model, t, v);
111,018✔
1883
    }
1884

1885
  } else {
1886
    /*
1887
     * r is not mapped to anything:
1888
     *
1889
     * 1) If t == r and t is present in the internalization table
1890
     *    then t is relevant. So we should display its value
1891
     *    when we print the model. To do this, we assign an
1892
     *    arbitrary value v to t and store [t := v] in the map.
1893
     *
1894
     * 2) If t != r then we keep the mapping [t --> r] in
1895
     *    the alias table (provided the model supports aliases).
1896
     */
1897
    if (t == r) {
211,435✔
1898
      if (intern_tbl_term_present(&ctx->intern, t)) {
210,781✔
UNCOV
1899
        tau = term_type(ctx->terms, t);
×
UNCOV
1900
        vtbl = model_get_vtbl(model);
×
UNCOV
1901
        v = vtbl_make_object(vtbl, tau);
×
UNCOV
1902
        model_map_term(model, t, v);
×
1903
      }
1904
    } else if (model->has_alias) {
654✔
1905
      // t != r: keep the substitution [t --> r] in the model
1906
      model_add_substitution(model, t, r);
654✔
1907
    }
1908
  }
1909
}
322,453✔
1910

1911

1912

1913

1914
/*
1915
 * Build a model for the current context (including all satellite solvers)
1916
 * - the context status must be SAT (or UNKNOWN)
1917
 * - if model->has_alias is true, we store the term substitution
1918
 *   defined by ctx->intern_tbl into the model
1919
 * - cleanup of satellite models needed using clean_solver_models()
1920
 */
1921
void build_model(model_t *model, context_t *ctx) {
42,177✔
1922
  term_table_t *terms;
1923
  uint32_t i, n;
1924
  term_t t;
1925

1926
  assert(smt_status(ctx->core) == YICES_STATUS_SAT || smt_status(ctx->core) == YICES_STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == YICES_STATUS_SAT);
1927

1928
  /*
1929
   * First build assignments in the satellite solvers
1930
   * and get the val_in_model functions for the egraph
1931
   */
1932
  if (context_has_arith_solver(ctx)) {
42,177✔
1933
    ctx->arith.build_model(ctx->arith_solver);
32,921✔
1934
  }
1935
  if (context_has_bv_solver(ctx)) {
42,177✔
1936
    ctx->bv.build_model(ctx->bv_solver);
21,428✔
1937
  }
1938

1939
  /*
1940
   * Construct the egraph model
1941
   */
1942
  if (context_has_egraph(ctx)) {
42,177✔
1943
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,047✔
1944
  }
1945

1946
  /*
1947
   * Construct the mcsat model.
1948
   */
1949
  if (context_has_mcsat(ctx)) {
42,177✔
1950
    mcsat_build_model(ctx->mcsat, model);
51✔
1951
  }
1952

1953
  // scan the internalization table
1954
  terms = ctx->terms;
42,177✔
1955
  n = intern_tbl_num_terms(&ctx->intern);
42,177✔
1956
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,180,457✔
1957
    if (good_term_idx(terms, i)) {
1,235,138,280✔
1958
      t = pos_occ(i);
1,235,138,280✔
1959
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,138,280✔
1960
        build_term_value(ctx, model, t);
322,453✔
1961
      }
1962
    }
1963
  }
1964
}
42,177✔
1965

1966

1967
/*
1968
 * Cleanup solver models
1969
 */
1970
void clean_solver_models(context_t *ctx) {
42,177✔
1971
  if (context_has_arith_solver(ctx)) {
42,177✔
1972
    ctx->arith.free_model(ctx->arith_solver);
32,921✔
1973
  }
1974
  if (context_has_bv_solver(ctx)) {
42,177✔
1975
    ctx->bv.free_model(ctx->bv_solver);
21,428✔
1976
  }
1977
  if (context_has_egraph(ctx)) {
42,177✔
1978
    egraph_free_model(ctx->egraph);
13,047✔
1979
  }
1980
}
42,177✔
1981

1982

1983

1984
/*
1985
 * Build a model for the current context
1986
 * - the context status must be SAT (or UNKNOWN)
1987
 * - if model->has_alias is true, we store the term substitution
1988
 *   defined by ctx->intern_tbl into the model
1989
 */
1990
void context_build_model(model_t *model, context_t *ctx) {
270✔
1991
  // Build solver models and term values
1992
  build_model(model, ctx);
270✔
1993

1994
  // Cleanup
1995
  clean_solver_models(ctx);
270✔
1996
}
270✔
1997

1998

1999

2000
/*
2001
 * Read the value of a Boolean term t
2002
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
2003
 */
UNCOV
2004
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
2005
  term_t r;
2006
  uint32_t polarity;
2007
  int32_t x;
2008
  bval_t v;
2009

2010
  assert(is_boolean_term(ctx->terms, t));
2011

2012
  // default value if t is not in the internalization table
UNCOV
2013
  v = VAL_UNDEF_FALSE;
×
UNCOV
2014
  r = intern_tbl_get_root(&ctx->intern, t);
×
UNCOV
2015
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
2016
    // r is mapped to some object x
UNCOV
2017
    polarity = polarity_of(r);
×
UNCOV
2018
    r = unsigned_term(r);
×
2019

UNCOV
2020
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
UNCOV
2021
    if (code_is_eterm(x)) {
×
2022
      // x must be either true_occ or false_occ
UNCOV
2023
      if (x == bool2code(true)) {
×
UNCOV
2024
        v = VAL_TRUE;
×
2025
      } else {
2026
        assert(x == bool2code(false));
UNCOV
2027
        v = VAL_FALSE;
×
2028
      }
2029
    } else {
2030
      // x refers to a literal in the smt core
UNCOV
2031
      v = literal_value(ctx->core, code2literal(x));
×
2032
    }
2033

2034
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
UNCOV
2035
    v ^= polarity;
×
2036
  }
2037

UNCOV
2038
  return v;
×
2039
}
2040

2041

2042
/*
2043
 * UNSAT CORE
2044
 */
2045

2046
/*
2047
 * Build an unsat core:
2048
 * - store the result in v
2049
 * - first reuse a cached term core if available.
2050
 * - otherwise:
2051
 *   CDCL(T): build from smt_core then cache as terms
2052
 *   MCSAT: return empty unless check-with-term-assumptions populated the cache.
2053
 */
2054
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
2,709✔
2055
  smt_core_t *core;
2056
  uint32_t i, n;
2057
  term_t t;
2058

2059
  if (ctx->unsat_core_cache != NULL) {
2,709✔
2060
    // Fast path: repeated get_unsat_core returns the cached term vector.
2061
    ivector_reset(v);
10✔
2062
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
10✔
2063
    return;
10✔
2064
  }
2065

2066
  if (ctx->mcsat != NULL) {
2,699✔
2067
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
2068
    // there is no generic context-level core structure to rebuild from here.
UNCOV
2069
    ivector_reset(v);
×
UNCOV
2070
    return;
×
2071
  }
2072

2073
  core = ctx->core;
2,699✔
2074
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
2075
  build_unsat_core(core, v);
2,699✔
2076

2077
  // convert from literals to terms
2078
  n = v->size;
2,699✔
2079
  for (i=0; i<n; i++) {
37,499✔
2080
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,800✔
2081
    assert(t >= 0);
2082
    v->data[i] = t;
34,800✔
2083
  }
2084

2085
  // Cache the converted term core for subsequent queries.
2086
  cache_unsat_core(ctx, v);
2,699✔
2087
}
2088

2089

2090
/*
2091
 * MODEL INTERPOLANT
2092
 */
2093
term_t context_get_unsat_model_interpolant(context_t *ctx) {
61✔
2094
  assert(ctx->mcsat != NULL);
2095
  return mcsat_get_unsat_model_interpolant(ctx->mcsat);
61✔
2096
}
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