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

SRI-CSL / yices2 / 25787884743

13 May 2026 08:33AM UTC coverage: 67.451% (+0.2%) from 67.254%
25787884743

push

github

web-flow
Merge pull request #629 from SRI-CSL/incr-cadical

New version of delegates for contexts, with smarter handling of multichecks and push-pop modes

355 of 433 new or added lines in 8 files covered. (81.99%)

19 existing lines in 5 files now uncovered.

85741 of 127116 relevant lines covered (67.45%)

1625604.15 hits per line

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

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

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

52

53

54
/*
55
 * TRACE FUNCTIONS
56
 */
57

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

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

83

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

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

95

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

104

105

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

114

115

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

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

134
  case VAL_TRUE:
×
135
    break;
×
136

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

143

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

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

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

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

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

176
    // assumption
177
    if (core->has_assumptions) {
6,284,317✔
178
      l = get_next_assumption(core);
10✔
179
      if (l != null_literal) {
10✔
180
        process_assumption(core, l);
3✔
181
        continue;
3✔
182
      }
183
    }
184

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

196
  *reduce_threshold = r_threshold;
13,437✔
197
}
13,437✔
198

199

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

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

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

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

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

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

250
  *reduce_threshold = r_threshold;
13,414✔
251
}
13,414✔
252

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

259

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

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

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

279
  smt_process(core);
20,851✔
280
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
634,993✔
281
    // reduce heuristic
282
    if (num_learned_clauses(core) >= r_threshold) {
614,142✔
283
      deletions = core->stats.learned_clauses_deleted;
61✔
284
      reduce_clause_database(core);
61✔
285
      r_threshold = (uint32_t) (r_threshold * r_factor);
61✔
286
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
61✔
287
    }
288

289
    // assumption
290
    if (core->has_assumptions) {
614,142✔
291
      l = get_next_assumption(core);
2✔
292
      if (l != null_literal) {
2✔
293
        process_assumption(core, l);
2✔
294
        continue;
2✔
295
      }
296
    }
297

298
    // decision
299
    l = select_unassigned_literal(core);
614,140✔
300
    if (l == null_literal) {
614,140✔
301
      // all variables assigned: call final check
302
      smt_final_check(core);
22,623✔
303
    } else {
304
      // apply the branching heuristic
305
      l = branch(core, l);
591,517✔
306
      // propagation
307
      decide_literal(core, l);
591,517✔
308
      smt_process(core);
591,517✔
309
    }
310
  }
311

312
  *reduce_threshold = r_threshold;
20,851✔
313
}
20,851✔
314

315

316

317

318

319
/*
320
 * SUPPORTED BRANCHING
321
 */
322

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

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

336

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

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

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

364

365

366

367

368
/*
369
 * CORE SOLVER
370
 */
371

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

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

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

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

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

434
      if (smt_status(core) != YICES_STATUS_SEARCHING) break;
47,702✔
435

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

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

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

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

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

472
  trace_done(core);
45,392✔
473
}
45,392✔
474

475

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

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

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

530
  /*
531
   * Set simplex parameters
532
   */
533
  if (context_has_simplex_solver(ctx)) {
45,392✔
534
    simplex = ctx->arith_solver;
33,233✔
535
    if (params->use_simplex_prop) {
33,233✔
536
      simplex_enable_propagation(simplex);
12,857✔
537
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,857✔
538
    }
539
    if (params->adjust_simplex_model) {
33,233✔
540
      simplex_enable_adjust_model(simplex);
12,811✔
541
    }
542
    simplex_set_bland_threshold(simplex, params->bland_threshold);
33,233✔
543
    if (params->integer_check) {
33,233✔
544
      simplex_enable_periodic_icheck(simplex);
×
545
      simplex_set_integer_check_period(simplex, params->integer_check_period);
×
546
    }
547
  }
548

549
  /*
550
   * Set array solver parameters
551
   */
552
  if (context_has_fun_solver(ctx)) {
45,392✔
553
    fsolver = ctx->fun_solver;
12,872✔
554
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,872✔
555
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,872✔
556
  }
557
}
45,392✔
558

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

564
static smt_status_t call_mcsat_solver(context_t *ctx, const param_t *params) {
1,124✔
565
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_call_mcsat_solver(ctx, params));
1,124✔
566
}
567

568
/*
569
 * Initialize search parameters then call solve
570
 * - if ctx->status is not IDLE, return the status.
571
 * - if params is NULL, we use default values.
572
 */
573
smt_status_t check_context(context_t *ctx, const param_t *params) {
60,698✔
574
  smt_core_t *core;
575
  smt_status_t stat;
576

577
  if (params == NULL) {
60,698✔
578
    params = get_default_params();
×
579
  }
580

581
  if (ctx->mcsat != NULL) {
60,698✔
582
    return call_mcsat_solver(ctx, params);
1,124✔
583
  }
584

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

594
  return stat;
59,574✔
595
}
596

597

598
/*
599
 * Check with assumptions a[0] ... a[n-1]
600
 * - if ctx->status is not IDLE, return the status.
601
 */
602
smt_status_t check_context_with_assumptions(context_t *ctx, const param_t *params, uint32_t n, const literal_t *a) {
2,642✔
603
  smt_core_t *core;
604
  smt_status_t stat;
605

606
  assert(ctx->mcsat == NULL);
607

608
  core = ctx->core;
2,642✔
609
  stat = smt_status(core);
2,642✔
610
  if (stat == YICES_STATUS_IDLE) {
2,642✔
611
    // clean state
612
    if (params == NULL) {
2,642✔
613
      params = get_default_params();
×
614
    }
615
    context_set_search_parameters(ctx, params);
2,642✔
616
    solve(core, params, n, a);
2,642✔
617
    stat = smt_status(core);
2,642✔
618
  }
619

620
  return stat;
2,642✔
621
}
622

623
typedef struct sat_delegate_state_s {
624
  delegate_t delegate;
625
  sat_delegate_t mode;
626
  sat_delegate_incremental_mode_t exec_mode;
627
  bool live;
628
  bool stale;
629
  bool true_forwarded;
630
  bool checked_once;
631
  uint32_t delegate_nvars;
632
  uint32_t size;
633
  bvar_t *act_var;
634
  uint32_t *fwd_units;
635
  uint32_t *fwd_bins;
636
  uint32_t *fwd_clauses;
637
  ivector_t assumptions;
638
  ivector_t failed;
639
} sat_delegate_state_t;
640

641
void context_reset_sat_delegate_stats(context_t *ctx) {
22,349✔
642
  ctx->sat_delegate_stats.rebuild_checks = 0;
22,349✔
643
  ctx->sat_delegate_stats.append_checks = 0;
22,349✔
644
  ctx->sat_delegate_stats.selector_frame_checks = 0;
22,349✔
645
  ctx->sat_delegate_stats.delegate_initializations = 0;
22,349✔
646
  ctx->sat_delegate_stats.delegate_reinitializations = 0;
22,349✔
647
  ctx->sat_delegate_stats.selector_variables = 0;
22,349✔
648
  ctx->sat_delegate_stats.selector_assumptions = 0;
22,349✔
649
  ctx->sat_delegate_stats.selector_retirements = 0;
22,349✔
650
  ctx->sat_delegate_stats.post_check_clause_forwards = 0;
22,349✔
651
}
22,349✔
652

653
void context_get_sat_delegate_stats(const context_t *ctx, sat_delegate_stats_t *stats) {
10✔
654
  *stats = ctx->sat_delegate_stats;
10✔
655
}
10✔
656

657
void context_sat_delegate_state_cleanup(context_t *ctx) {
22,348✔
658
  sat_delegate_state_t *st;
659

660
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
22,348✔
661
  if (st == NULL) {
22,348✔
662
    return;
22,341✔
663
  }
664

665
  if (st->live) {
7✔
666
    delete_delegate(&st->delegate);
7✔
667
    st->live = false;
7✔
668
  }
669
  safe_free(st->act_var);
7✔
670
  safe_free(st->fwd_units);
7✔
671
  safe_free(st->fwd_bins);
7✔
672
  safe_free(st->fwd_clauses);
7✔
673
  delete_ivector(&st->assumptions);
7✔
674
  delete_ivector(&st->failed);
7✔
675
  safe_free(st);
7✔
676
  ctx->sat_delegate_state = NULL;
7✔
677
}
678

679
static sat_delegate_state_t *context_get_sat_delegate_state(context_t *ctx) {
39✔
680
  sat_delegate_state_t *st;
681

682
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
39✔
683
  if (st == NULL) {
39✔
684
    st = (sat_delegate_state_t *) safe_malloc(sizeof(sat_delegate_state_t));
7✔
685
    st->mode = SAT_DELEGATE_NONE;
7✔
686
    st->exec_mode = SAT_DELEGATE_MODE_REBUILD;
7✔
687
    st->live = false;
7✔
688
    st->stale = false;
7✔
689
    st->true_forwarded = false;
7✔
690
    st->checked_once = false;
7✔
691
    st->delegate_nvars = 0;
7✔
692
    st->size = 0;
7✔
693
    st->act_var = NULL;
7✔
694
    st->fwd_units = NULL;
7✔
695
    st->fwd_bins = NULL;
7✔
696
    st->fwd_clauses = NULL;
7✔
697
    init_ivector(&st->assumptions, 0);
7✔
698
    init_ivector(&st->failed, 0);
7✔
699
    ctx->sat_delegate_state = st;
7✔
700
  }
701
  return st;
39✔
702
}
703

704
static void sat_delegate_state_reset_cursors(sat_delegate_state_t *st) {
9✔
705
  uint32_t i;
706

707
  st->true_forwarded = false;
9✔
708
  for (i=0; i<st->size; i++) {
81✔
709
    st->act_var[i] = 0;
72✔
710
    st->fwd_units[i] = 0;
72✔
711
    st->fwd_bins[i] = 0;
72✔
712
    st->fwd_clauses[i] = 0;
72✔
713
  }
714
}
9✔
715

716
static void sat_delegate_state_grow(sat_delegate_state_t *st, uint32_t min_size) {
47✔
717
  uint32_t old_size, new_size, i;
718

719
  if (st->size > min_size) {
47✔
720
    return;
40✔
721
  }
722

723
  old_size = st->size;
7✔
724
  new_size = old_size == 0 ? 8 : old_size;
7✔
725
  while (new_size <= min_size) {
7✔
NEW
726
    new_size <<= 1;
×
727
  }
728

729
  st->act_var = (bvar_t *) safe_realloc(st->act_var, new_size * sizeof(bvar_t));
7✔
730
  st->fwd_units = (uint32_t *) safe_realloc(st->fwd_units, new_size * sizeof(uint32_t));
7✔
731
  st->fwd_bins = (uint32_t *) safe_realloc(st->fwd_bins, new_size * sizeof(uint32_t));
7✔
732
  st->fwd_clauses = (uint32_t *) safe_realloc(st->fwd_clauses, new_size * sizeof(uint32_t));
7✔
733
  for (i=old_size; i<new_size; i++) {
63✔
734
    st->act_var[i] = 0;
56✔
735
    st->fwd_units[i] = 0;
56✔
736
    st->fwd_bins[i] = 0;
56✔
737
    st->fwd_clauses[i] = 0;
56✔
738
  }
739
  st->size = new_size;
7✔
740
}
741

742
static void context_import_delegate_model(smt_core_t *core, delegate_t *d) {
34✔
743
  bvar_t x;
744

745
  for (x=0; x<num_vars(core); x++) {
1,010✔
746
    set_bvar_value(core, x, delegate_get_value(d, x));
976✔
747
  }
748
}
34✔
749

750
static void set_delegate_assumption_state(smt_core_t *core, uint32_t n, const literal_t *assumptions,
39✔
751
                                          smt_status_t stat, const ivector_t *failed) {
752
  if (n == 0) {
39✔
753
    core->has_assumptions = false;
×
754
    core->num_assumptions = 0;
×
755
    core->assumption_index = 0;
×
756
    core->assumptions = NULL;
×
757
    core->bad_assumption = null_literal;
×
758
    return;
×
759
  }
760

761
  core->has_assumptions = true;
39✔
762
  core->num_assumptions = n;
39✔
763
  core->assumption_index = n;
39✔
764
  core->assumptions = NULL;
39✔
765
  core->bad_assumption = null_literal;
39✔
766

767
  if (stat == YICES_STATUS_UNSAT && failed != NULL && failed->size > 0) {
39✔
768
    core->bad_assumption = failed->data[0];
5✔
769
  }
770
}
771

772
static void delegate_add_clause_with_guard(delegate_t *delegate, const clause_t *c, literal_t guard) {
1✔
773
  uint32_t i;
774
  literal_t l;
775

776
  ivector_reset(&delegate->buffer);
1✔
777
  if (guard != true_literal) {
1✔
NEW
778
    ivector_push(&delegate->buffer, guard);
×
779
  }
780
  i = 0;
1✔
781
  l = c->cl[0];
1✔
782
  while (l >= 0) {
10✔
783
    ivector_push(&delegate->buffer, l);
9✔
784
    i ++;
9✔
785
    l = c->cl[i];
9✔
786
  }
787
  delegate->add_clause(delegate->solver, delegate->buffer.size, delegate->buffer.data);
1✔
788
}
1✔
789

790
static void delegate_forward_clause_range(sat_delegate_state_t *st, smt_core_t *core, sat_delegate_stats_t *stats,
68✔
791
                                          uint32_t level,
792
                                          uint32_t end_units, uint32_t end_bins, uint32_t end_clauses,
793
                                          literal_t guard) {
794
  uint32_t i;
795
  bool forwarded;
796

797
  if (!st->true_forwarded) {
68✔
798
    st->delegate.add_unit_clause(st->delegate.solver, true_literal);
8✔
799
    st->true_forwarded = true;
8✔
800
  }
801

NEW
802
  forwarded = (core->inconsistent && st->fwd_units[level] == 0 && st->fwd_bins[level] == 0 && st->fwd_clauses[level] == 0) ||
×
803
              st->fwd_units[level] < end_units ||
68✔
804
              st->fwd_bins[level] < end_bins ||
168✔
805
              st->fwd_clauses[level] < end_clauses;
32✔
806
  if (st->checked_once && forwarded) {
68✔
807
    stats->post_check_clause_forwards ++;
28✔
808
  }
809

810
  if (core->inconsistent && st->fwd_units[level] == 0 && st->fwd_bins[level] == 0 && st->fwd_clauses[level] == 0) {
68✔
NEW
811
    if (guard == true_literal) {
×
NEW
812
      st->delegate.add_empty_clause(st->delegate.solver);
×
813
    } else {
NEW
814
      st->delegate.add_unit_clause(st->delegate.solver, guard);
×
815
    }
816
  }
817

818
  for (i=st->fwd_units[level]; i<end_units; i++) {
330✔
819
    if (guard == true_literal) {
262✔
820
      st->delegate.add_unit_clause(st->delegate.solver, core->stack.lit[i]);
41✔
821
    } else {
822
      st->delegate.add_binary_clause(st->delegate.solver, guard, core->stack.lit[i]);
221✔
823
    }
824
  }
825
  st->fwd_units[level] = end_units;
68✔
826

827
  for (i=st->fwd_bins[level]; i<end_bins; i += 2) {
356✔
828
    if (guard == true_literal) {
288✔
829
      st->delegate.add_binary_clause(st->delegate.solver, core->binary_clauses.data[i], core->binary_clauses.data[i+1]);
55✔
830
    } else {
831
      st->delegate.add_ternary_clause(st->delegate.solver, guard, core->binary_clauses.data[i], core->binary_clauses.data[i+1]);
233✔
832
    }
833
  }
834
  st->fwd_bins[level] = end_bins;
68✔
835

836
  if (level == 0 && st->fwd_clauses[level] > end_clauses) {
68✔
NEW
837
    st->fwd_clauses[level] = end_clauses;
×
838
  }
839
  for (i=st->fwd_clauses[level]; i<end_clauses; i++) {
69✔
840
    delegate_add_clause_with_guard(&st->delegate, core->problem_clauses[i], guard);
1✔
841
  }
842
  st->fwd_clauses[level] = end_clauses;
68✔
843
}
68✔
844

845
static void sat_delegate_state_close(sat_delegate_state_t *st) {
1✔
846
  if (st->live) {
1✔
847
    delete_delegate(&st->delegate);
1✔
848
    st->live = false;
1✔
849
  }
850
  st->mode = SAT_DELEGATE_NONE;
1✔
851
  st->exec_mode = SAT_DELEGATE_MODE_REBUILD;
1✔
852
  st->stale = false;
1✔
853
  st->checked_once = false;
1✔
854
  st->delegate_nvars = 0;
1✔
855
  sat_delegate_state_reset_cursors(st);
1✔
856
}
1✔
857

858
static bool context_prepare_append_delegate(context_t *ctx, sat_delegate_state_t *st, const char *sat_solver,
5✔
859
                                            uint32_t verbosity) {
860
  smt_core_t *core;
861
  uint32_t nvars;
862
  uint32_t nnew;
863

864
  core = ctx->core;
5✔
865
  nvars = num_vars(core);
5✔
866

867
  if (st->live && (st->mode != ctx->sat_delegate || st->exec_mode != SAT_DELEGATE_MODE_APPEND)) {
5✔
NEW
868
    sat_delegate_state_close(st);
×
869
  }
870

871
  if (!st->live || st->stale) {
5✔
872
    if (st->live) {
3✔
873
      ctx->sat_delegate_stats.delegate_reinitializations ++;
1✔
874
      sat_delegate_state_close(st);
1✔
875
    }
876
    sat_delegate_state_grow(st, 0);
3✔
877
    if (!init_delegate_incremental(&st->delegate, sat_solver, nvars)) {
3✔
UNCOV
878
      return false;
×
879
    }
880
    ctx->sat_delegate_stats.delegate_initializations ++;
3✔
881
    delegate_set_verbosity(&st->delegate, verbosity);
3✔
882
    st->mode = ctx->sat_delegate;
3✔
883
    st->exec_mode = SAT_DELEGATE_MODE_APPEND;
3✔
884
    st->stale = false;
3✔
885
    st->delegate_nvars = nvars;
3✔
886
    st->live = true;
3✔
887
    sat_delegate_state_reset_cursors(st);
3✔
888
  }
889

890
  if (st->delegate_nvars < nvars) {
5✔
891
    nnew = nvars - st->delegate_nvars;
2✔
892
    delegate_add_vars(&st->delegate, nnew);
2✔
893
    st->delegate_nvars = nvars;
2✔
894
  }
895

896
  sat_delegate_state_grow(st, 0);
5✔
897
  delegate_forward_clause_range(st, core, &ctx->sat_delegate_stats, 0, core->nb_unit_clauses,
5✔
898
                                (uint32_t) core->binary_clauses.size,
5✔
899
                                (uint32_t) get_cv_size(core->problem_clauses),
5✔
900
                                true_literal);
901

902
  return true;
5✔
903
}
904

905
static bool context_prepare_selector_delegate(context_t *ctx, sat_delegate_state_t *st, const char *sat_solver,
34✔
906
                                              uint32_t verbosity) {
907
  smt_core_t *core;
908
  uint32_t d, k, nvars, nnew;
909
  uint32_t end_units, end_bins, end_clauses;
910
  trail_t *trail_data;
911
  literal_t guard;
912

913
  core = ctx->core;
34✔
914
  nvars = num_vars(core);
34✔
915
  d = smt_base_level(core);
34✔
916
  trail_data = core->trail_stack.data;
34✔
917

918
  if (st->live && (st->mode != ctx->sat_delegate || st->exec_mode != SAT_DELEGATE_MODE_SELECTOR_FRAMES)) {
34✔
NEW
919
    sat_delegate_state_close(st);
×
920
  }
921

922
  if (!st->live) {
34✔
923
    sat_delegate_state_grow(st, d);
5✔
924
    if (!init_delegate_incremental(&st->delegate, sat_solver, nvars)) {
5✔
NEW
925
      return false;
×
926
    }
927
    ctx->sat_delegate_stats.delegate_initializations ++;
5✔
928
    delegate_set_verbosity(&st->delegate, verbosity);
5✔
929
    st->mode = ctx->sat_delegate;
5✔
930
    st->exec_mode = SAT_DELEGATE_MODE_SELECTOR_FRAMES;
5✔
931
    st->stale = false;
5✔
932
    st->delegate_nvars = nvars;
5✔
933
    st->live = true;
5✔
934
    sat_delegate_state_reset_cursors(st);
5✔
935
  }
936

937
  if (st->delegate_nvars < nvars) {
34✔
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, d);
34✔
944
  for (k=1; k<=d; k++) {
63✔
945
    if (st->act_var[k] == 0) {
29✔
946
      /*
947
       * Selectors must live in the SMT core's variable namespace too:
948
       * otherwise a later bit-blasted assertion could reuse the same bvar.
949
       */
950
      do {
951
        st->act_var[k] = create_boolean_variable(core);
303✔
952
      } while (st->act_var[k] < st->delegate_nvars);
303✔
953
      delegate_add_vars(&st->delegate, st->act_var[k] + 1 - st->delegate_nvars);
27✔
954
      delegate_freeze_literal(&st->delegate, pos_lit(st->act_var[k]));
27✔
955
      ctx->sat_delegate_stats.selector_variables ++;
27✔
956
      st->delegate_nvars = st->act_var[k] + 1;
27✔
957
      st->fwd_units[k] = trail_data[k-1].nunits;
27✔
958
      st->fwd_bins[k] = trail_data[k-1].nbins;
27✔
959
      st->fwd_clauses[k] = trail_data[k-1].nclauses;
27✔
960
    }
961
  }
962

963
  for (k=0; k<=d; k++) {
97✔
964
    guard = (k == 0) ? true_literal : neg_lit(st->act_var[k]);
63✔
965
    end_units = (k < d) ? trail_data[k].nunits : core->nb_unit_clauses;
63✔
966
    end_bins = (k < d) ? trail_data[k].nbins : (uint32_t) core->binary_clauses.size;
63✔
967
    end_clauses = (k < d) ? trail_data[k].nclauses : (uint32_t) get_cv_size(core->problem_clauses);
63✔
968
    delegate_forward_clause_range(st, core, &ctx->sat_delegate_stats, k, end_units, end_bins, end_clauses, guard);
63✔
969
  }
970

971
  return true;
34✔
972
}
973

974
void context_sat_delegate_state_pop(context_t *ctx, uint32_t level) {
1,566✔
975
  sat_delegate_state_t *st;
976

977
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
1,566✔
978
  if (st == NULL || !st->live) {
1,566✔
979
    return;
1,540✔
980
  }
981

982
  if (st->exec_mode == SAT_DELEGATE_MODE_APPEND) {
26✔
983
    st->stale = true;
1✔
984
  } else if (st->exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES) {
25✔
985
    if (level < st->size && st->act_var[level] != 0) {
25✔
986
      delegate_melt_literal(&st->delegate, pos_lit(st->act_var[level]));
25✔
987
      st->delegate.add_unit_clause(st->delegate.solver, neg_lit(st->act_var[level]));
25✔
988
      ctx->sat_delegate_stats.selector_retirements ++;
25✔
989
      st->act_var[level] = 0;
25✔
990
    }
991
  }
992
}
993

994
static smt_status_t check_with_persistent_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity,
54✔
995
                                                   sat_delegate_incremental_mode_t exec_mode,
996
                                                   uint32_t n, const literal_t *assumptions, ivector_t *failed) {
997
  smt_status_t stat;
998
  smt_core_t *core;
999
  sat_delegate_state_t *st;
1000
  ivector_t visible_failed;
1001
  uint32_t i;
1002

1003
  core = ctx->core;
54✔
1004
  stat = smt_status(core);
54✔
1005
  if (stat != YICES_STATUS_IDLE) {
54✔
1006
    return stat;
×
1007
  }
1008

1009
  start_search(core, 0, NULL);
54✔
1010
  smt_process(core);
54✔
1011
  stat = smt_status(core);
54✔
1012

1013
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1014
         stat == YICES_STATUS_INTERRUPTED);
1015

1016
  if (stat != YICES_STATUS_SEARCHING) {
54✔
1017
    return stat;
×
1018
  }
1019

1020
  if (n == 0 && smt_easy_sat(core)) {
54✔
1021
    stat = YICES_STATUS_SAT;
15✔
1022
    set_smt_status(core, stat);
15✔
1023
    return stat;
15✔
1024
  }
1025

1026
  st = context_get_sat_delegate_state(ctx);
39✔
1027
  if (exec_mode == SAT_DELEGATE_MODE_APPEND) {
39✔
1028
    if (!context_prepare_append_delegate(ctx, st, sat_solver, verbosity)) {
5✔
NEW
1029
      return YICES_STATUS_UNKNOWN;
×
1030
    }
1031
  } else {
1032
    assert(exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES);
1033
    if (!context_prepare_selector_delegate(ctx, st, sat_solver, verbosity)) {
34✔
NEW
1034
      return YICES_STATUS_UNKNOWN;
×
1035
    }
1036
  }
1037

1038
  if (n > 0 && !delegate_supports_assumptions(&st->delegate)) {
39✔
UNCOV
1039
    return YICES_STATUS_UNKNOWN;
×
1040
  }
1041

1042
  init_ivector(&visible_failed, 0);
39✔
1043
  ivector_reset(&st->assumptions);
39✔
1044
  ivector_reset(&st->failed);
39✔
1045
  if (exec_mode == SAT_DELEGATE_MODE_SELECTOR_FRAMES) {
39✔
1046
    uint32_t k, d;
1047
    d = smt_base_level(core);
34✔
1048
    for (k=1; k<=d; k++) {
63✔
1049
      if (k < st->size && st->act_var[k] != 0) {
29✔
1050
        ivector_push(&st->assumptions, pos_lit(st->act_var[k]));
29✔
1051
        ctx->sat_delegate_stats.selector_assumptions ++;
29✔
1052
      }
1053
    }
1054
  }
1055
  for (i=0; i<n; i++) {
79✔
1056
    ivector_push(&st->assumptions, assumptions[i]);
40✔
1057
  }
1058

1059
  if (st->assumptions.size == 0) {
39✔
1060
    stat = st->delegate.check(st->delegate.solver);
×
1061
  } else if (delegate_supports_assumptions(&st->delegate)) {
39✔
1062
    stat = delegate_check_with_assumptions(&st->delegate, st->assumptions.size,
39✔
1063
                                           (literal_t *) st->assumptions.data, &st->failed);
39✔
1064
    if (stat == YICES_STATUS_UNSAT) {
39✔
1065
      for (i=0; i<st->failed.size; i++) {
14✔
1066
        literal_t l = st->failed.data[i];
9✔
1067
        uint32_t j;
1068
        for (j=0; j<n; j++) {
13✔
1069
          if (l == assumptions[j]) {
10✔
1070
            ivector_push(&visible_failed, l);
6✔
1071
            break;
6✔
1072
          }
1073
        }
1074
      }
1075
      if (failed != NULL) {
5✔
1076
        ivector_reset(failed);
5✔
1077
        ivector_add(failed, visible_failed.data, visible_failed.size);
5✔
1078
      }
1079
    }
1080
  } else {
1081
    stat = YICES_STATUS_UNKNOWN;
×
1082
  }
1083

1084
  set_smt_status(core, stat);
39✔
1085
  set_delegate_assumption_state(core, n, assumptions, stat, &visible_failed);
39✔
1086
  if (stat == YICES_STATUS_SAT) {
39✔
1087
    context_import_delegate_model(core, &st->delegate);
34✔
1088
  }
1089
  st->checked_once = true;
39✔
1090

1091
  delete_ivector(&visible_failed);
39✔
1092
  return stat;
39✔
1093
}
1094

1095
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
1096
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed);
1097

1098
smt_status_t check_with_sat_delegate(context_t *ctx, const char *sat_solver,
92✔
1099
                                     sat_delegate_incremental_mode_t mode,
1100
                                     uint32_t verbosity, uint32_t n,
1101
                                     const literal_t *assumptions, ivector_t *failed) {
1102
  switch (mode) {
92✔
1103
  case SAT_DELEGATE_MODE_REBUILD:
38✔
1104
    ctx->sat_delegate_stats.rebuild_checks ++;
38✔
1105
    if (n == 0) {
38✔
1106
      return check_with_delegate(ctx, sat_solver, verbosity);
38✔
1107
    } else {
NEW
1108
      return check_with_delegate_assumptions(ctx, sat_solver, verbosity, n, assumptions, failed);
×
1109
    }
1110

1111
  case SAT_DELEGATE_MODE_APPEND:
12✔
1112
    ctx->sat_delegate_stats.append_checks ++;
12✔
1113
    return check_with_persistent_delegate(ctx, sat_solver, verbosity, SAT_DELEGATE_MODE_APPEND,
12✔
1114
                                          n, assumptions, failed);
1115

1116
  case SAT_DELEGATE_MODE_SELECTOR_FRAMES:
42✔
1117
    ctx->sat_delegate_stats.selector_frame_checks ++;
42✔
1118
    return check_with_persistent_delegate(ctx, sat_solver, verbosity, SAT_DELEGATE_MODE_SELECTOR_FRAMES,
42✔
1119
                                          n, assumptions, failed);
1120

NEW
1121
  default:
×
NEW
1122
    return YICES_STATUS_UNKNOWN;
×
1123
  }
1124
}
1125

1126
/*
1127
 * Explore term t and collect all Boolean atoms into atoms.
1128
 */
1129
static void collect_boolean_atoms(context_t *ctx, term_t t, int_hset_t *atoms, int_hset_t *visited) {
64✔
1130
  term_table_t *terms;
1131
  uint32_t i, nchildren;
1132

1133
  if (t < 0) {
64✔
1134
    t = not(t);
×
1135
  }
1136

1137
  if (int_hset_member(visited, t)) {
64✔
1138
    return;
×
1139
  }
1140
  int_hset_add(visited, t);
64✔
1141

1142
  terms = ctx->terms;
64✔
1143
  if (term_type(terms, t) == bool_type(terms->types)) {
64✔
1144
    int_hset_add(atoms, t);
64✔
1145
  }
1146

1147
  if (term_is_projection(terms, t)) {
64✔
1148
    collect_boolean_atoms(ctx, proj_term_arg(terms, t), atoms, visited);
×
1149
  } else if (term_is_sum(terms, t)) {
64✔
1150
    nchildren = term_num_children(terms, t);
×
1151
    for (i=0; i<nchildren; i++) {
×
1152
      term_t child;
1153
      mpq_t q;
1154
      mpq_init(q);
×
1155
      sum_term_component(terms, t, i, q, &child);
×
1156
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1157
      mpq_clear(q);
×
1158
    }
1159
  } else if (term_is_bvsum(terms, t)) {
64✔
1160
    uint32_t nbits = term_bitsize(terms, t);
×
1161
    int32_t *aux = (int32_t*) safe_malloc(nbits * sizeof(int32_t));
×
1162
    nchildren = term_num_children(terms, t);
×
1163
    for (i=0; i<nchildren; i++) {
×
1164
      term_t child;
1165
      bvsum_term_component(terms, t, i, aux, &child);
×
1166
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1167
    }
1168
    safe_free(aux);
×
1169
  } else if (term_is_product(terms, t)) {
64✔
1170
    nchildren = term_num_children(terms, t);
×
1171
    for (i=0; i<nchildren; i++) {
×
1172
      term_t child;
1173
      uint32_t exp;
1174
      product_term_component(terms, t, i, &child, &exp);
×
1175
      collect_boolean_atoms(ctx, child, atoms, visited);
×
1176
    }
1177
  } else if (term_is_composite(terms, t)) {
64✔
1178
    nchildren = term_num_children(terms, t);
34✔
1179
    for (i=0; i<nchildren; i++) {
89✔
1180
      collect_boolean_atoms(ctx, term_child(terms, t, i), atoms, visited);
55✔
1181
    }
1182
  }
1183
}
1184

1185
/*
1186
 * Extract assumptions whose labels appear in term t.
1187
 */
1188
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✔
1189
  int_hset_t atoms, visited;
1190
  uint32_t i;
1191

1192
  init_int_hset(&atoms, 0);
9✔
1193
  init_int_hset(&visited, 0);
9✔
1194
  collect_boolean_atoms(ctx, t, &atoms, &visited);
9✔
1195

1196
  ivector_reset(core);
9✔
1197
  for (i=0; i<labels->size; i++) {
83✔
1198
    term_t label = labels->data[i];
74✔
1199
    if (int_hset_member(&atoms, label)) {
74✔
1200
      int_hmap_pair_t *p = int_hmap_find((int_hmap_t *) label_map, label);
30✔
1201
      if (p != NULL) {
30✔
1202
        ivector_push(core, p->val);
30✔
1203
      }
1204
    }
1205
  }
1206

1207
  delete_int_hset(&visited);
9✔
1208
  delete_int_hset(&atoms);
9✔
1209
}
9✔
1210

1211
/*
1212
 * Cache a core vector in the context.
1213
 */
1214
static void cache_unsat_core(context_t *ctx, const ivector_t *core) {
2,713✔
1215
  if (ctx->unsat_core_cache == NULL) {
2,713✔
1216
    ctx->unsat_core_cache = (ivector_t *) safe_malloc(sizeof(ivector_t));
2,713✔
1217
    init_ivector(ctx->unsat_core_cache, core->size);
2,713✔
1218
  } else {
1219
    ivector_reset(ctx->unsat_core_cache);
×
1220
  }
1221
  ivector_copy(ctx->unsat_core_cache, core->data, core->size);
2,713✔
1222
}
2,713✔
1223

1224
static void cache_failed_assumptions_core(context_t *ctx, uint32_t n, const term_t *a,
5✔
1225
                                          const ivector_t *assumption_literals,
1226
                                          const ivector_t *failed_literals) {
1227
  ivector_t core_terms;
1228
  int_hset_t failed;
1229
  uint32_t i;
1230

1231
  init_ivector(&core_terms, 0);
5✔
1232
  init_int_hset(&failed, 0);
5✔
1233
  for (i=0; i<failed_literals->size; i++) {
11✔
1234
    int_hset_add(&failed, failed_literals->data[i]);
6✔
1235
  }
1236
  for (i=0; i<n; i++) {
11✔
1237
    if (int_hset_member(&failed, assumption_literals->data[i])) {
6✔
1238
      ivector_push(&core_terms, a[i]);
6✔
1239
    }
1240
  }
1241
  cache_unsat_core(ctx, &core_terms);
5✔
1242
  delete_int_hset(&failed);
5✔
1243
  delete_ivector(&core_terms);
5✔
1244
}
5✔
1245

1246
/*
1247
 * MCSAT variant of check_context_with_term_assumptions.
1248
 * Caller must hold __yices_globals.lock.
1249
 */
1250
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✔
1251
  smt_status_t stat;
1252
  ivector_t assumptions;
1253
  uint32_t i;
1254

1255
  /*
1256
   * MCSAT: create fresh labels b_i, assert (b_i => a_i), then solve with model b_i=true.
1257
   * We extract interpolant/core before cleanup, then restore sticky UNSAT artifacts.
1258
   */
1259
  if (!context_supports_model_interpolation(ctx)) {
10✔
1260
    if (error != NULL) {
×
1261
      *error = CTX_OPERATION_NOT_SUPPORTED;
×
1262
    }
1263
    return YICES_STATUS_ERROR;
×
1264
  }
1265

1266
  {
1267
    model_t mdl;               // temporary model: sets all label terms b_i to true
1268
    int_hmap_t label_map;      // map label b_i -> original assumption a_i
1269
    ivector_t mapped_core;     // translated core over original assumptions
1270
    term_t interpolant = NULL_TERM; // raw/substituted interpolant for sticky UNSAT result
10✔
1271
    int32_t code;              // return code from assert_formula (negative on internalization error)
1272
    bool pushed;               // whether we pushed a temporary scope and must pop it
1273
    term_manager_t tm;
1274

1275
    init_model(&mdl, ctx->terms, true);
10✔
1276
    init_int_hmap(&label_map, 0);
10✔
1277
    init_ivector(&assumptions, n);
10✔
1278
    init_ivector(&mapped_core, 0);
10✔
1279
    init_term_manager(&tm, ctx->terms);
10✔
1280
    stat = YICES_STATUS_IDLE;
10✔
1281

1282
    pushed = false;
10✔
1283
    if (context_supports_pushpop(ctx)) {
10✔
1284
      context_push(ctx);
9✔
1285
      pushed = true;
9✔
1286
    }
1287

1288
    for (i=0; i<n; i++) {
85✔
1289
      term_t b = new_uninterpreted_term(ctx->terms, bool_id);
75✔
1290
      term_t implication = mk_implies(&tm, b, a[i]);
75✔
1291

1292
      int_hmap_add(&label_map, b, a[i]);
75✔
1293
      code = _o_assert_formula(ctx, implication);
75✔
1294
      if (code < 0) {
75✔
1295
        if (error != NULL) {
×
1296
          *error = code;
×
1297
        }
1298
        stat = YICES_STATUS_ERROR;
×
1299
        break;
×
1300
      }
1301
      model_map_term(&mdl, b, vtbl_mk_bool(&mdl.vtbl, true));
75✔
1302
      ivector_push(&assumptions, b);
75✔
1303
    }
1304

1305
    if (stat != YICES_STATUS_ERROR) {
10✔
1306
      stat = check_context_with_model(ctx, params, &mdl, n, assumptions.data);
10✔
1307
      if (stat == YICES_STATUS_UNSAT) {
10✔
1308
        interpolant = context_get_unsat_model_interpolant(ctx);
9✔
1309
        assert(interpolant != NULL_TERM);
1310
        core_from_labeled_interpolant(ctx, interpolant, &assumptions, &label_map, &mapped_core);
9✔
1311
      }
1312
    }
1313

1314
    if (pushed) {
10✔
1315
      mcsat_cleanup_assumptions(ctx->mcsat);
9✔
1316
      context_pop(ctx);
9✔
1317
    }
1318
    if (stat == YICES_STATUS_UNSAT) {
10✔
1319
      mcsat_set_unsat_result_from_labeled_interpolant(ctx->mcsat, interpolant, n, assumptions.data, a);
9✔
1320
      cache_unsat_core(ctx, &mapped_core);
9✔
1321
    }
1322

1323
    delete_term_manager(&tm);
10✔
1324
    delete_ivector(&mapped_core);
10✔
1325
    delete_ivector(&assumptions);
10✔
1326
    delete_int_hmap(&label_map);
10✔
1327
    delete_model(&mdl);
10✔
1328

1329
    return stat;
10✔
1330
  }
1331
}
1332

1333
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✔
1334
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_check_context_with_term_assumptions_mcsat(ctx, params, n, a, error));
10✔
1335
}
1336

1337
/*
1338
 * Check under assumptions given as terms.
1339
 * - if MCSAT is enabled, this uses temporary labels + model interpolation.
1340
 * - otherwise terms are converted to literals and handled by the CDCL(T) path.
1341
 *
1342
 * Preconditions:
1343
 * - context status must be IDLE.
1344
 */
1345
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✔
1346
  if (error != NULL) {
2,692✔
1347
    *error = CTX_NO_ERROR;
2,692✔
1348
  }
1349

1350
  /*
1351
   * Clear any prior term-assumption core before all paths below. Delegate
1352
   * checks cache a new core only on UNSAT.
1353
   */
1354
  context_invalidate_unsat_core_cache(ctx);
2,692✔
1355

1356
  if (ctx->mcsat == NULL) {
2,692✔
1357
    smt_status_t stat;
1358
    sat_delegate_t mode;
1359
    sat_delegate_incremental_mode_t exec_mode;
1360
    bool one_shot;
1361
    const char *delegate;
1362
    bool unknown;
1363
    ivector_t assumptions;
1364
    ivector_t failed;
1365
    uint32_t i;
1366
    literal_t l;
1367

1368
    init_ivector(&assumptions, n);
2,682✔
1369
    for (i=0; i<n; i++) {
90,189✔
1370
      l = context_add_assumption(ctx, a[i]);
87,507✔
1371
      if (l < 0) {
87,507✔
1372
        if (error != NULL) {
×
1373
          *error = l;
×
1374
        }
1375
        delete_ivector(&assumptions);
×
1376
        return YICES_STATUS_ERROR;
×
1377
      }
1378
      ivector_push(&assumptions, l);
87,507✔
1379
    }
1380

1381
    mode = effective_sat_delegate_mode(ctx->sat_delegate, params, &one_shot);
2,682✔
1382
    delegate = sat_delegate_name(mode);
2,682✔
1383
    if (delegate == NULL) {
2,682✔
1384
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
2,642✔
1385
      delete_ivector(&assumptions);
2,642✔
1386
      return stat;
2,642✔
1387
    }
1388

1389
    if (ctx->logic != QF_BV) {
40✔
1390
      if (error != NULL) {
×
1391
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1392
      }
1393
      delete_ivector(&assumptions);
×
1394
      return YICES_STATUS_ERROR;
×
1395
    }
1396

1397
    if (!supported_delegate(delegate, &unknown)) {
40✔
1398
      if (error != NULL) {
×
1399
        *error = unknown ? CTX_UNKNOWN_DELEGATE : CTX_DELEGATE_NOT_AVAILABLE;
×
1400
      }
1401
      delete_ivector(&assumptions);
×
1402
      return YICES_STATUS_ERROR;
×
1403
    }
1404

1405
    if (!delegate_supports_assumptions_name(delegate)) {
40✔
1406
      if (error != NULL) {
1✔
1407
        *error = CTX_OPERATION_NOT_SUPPORTED;
1✔
1408
      }
1409
      delete_ivector(&assumptions);
1✔
1410
      return YICES_STATUS_ERROR;
1✔
1411
    }
1412

1413
    init_ivector(&failed, 0);
39✔
1414
    if (!effective_sat_delegate_incremental_mode(mode, ctx->sat_delegate_incremental_mode,
39✔
1415
                                                ctx->sat_delegate_incremental_mode_set,
39✔
1416
                                                ctx->mode == CTX_MODE_ONECHECK,
39✔
1417
                                                one_shot, &exec_mode)) {
NEW
1418
      if (error != NULL) {
×
NEW
1419
        *error = CTX_OPERATION_NOT_SUPPORTED;
×
1420
      }
NEW
1421
      delete_ivector(&failed);
×
NEW
1422
      delete_ivector(&assumptions);
×
NEW
1423
      return YICES_STATUS_ERROR;
×
1424
    }
1425
    stat = check_with_sat_delegate(ctx, delegate, exec_mode, 0, n, assumptions.data, &failed);
39✔
1426
    if (stat == YICES_STATUS_UNSAT) {
39✔
1427
      cache_failed_assumptions_core(ctx, n, a, &assumptions, &failed);
5✔
1428
    }
1429
    delete_ivector(&failed);
39✔
1430
    delete_ivector(&assumptions);
39✔
1431
    return stat;
39✔
1432
  }
1433

1434
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1435
}
1436

1437
/*
1438
 * Check with given model
1439
 * - if mcsat status is not IDLE, return the status
1440
 */
1441
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✔
1442
  smt_status_t stat;
1443

1444
  assert(ctx->mcsat != NULL);
1445

1446
  stat = mcsat_status(ctx->mcsat);
161✔
1447
  if (stat == YICES_STATUS_IDLE) {
161✔
1448
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
161✔
1449
    stat = mcsat_status(ctx->mcsat);
161✔
1450

1451
    // BD: this looks wrong. We shouldn't call clear yet.
1452
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
1453
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
1454
    //      context_clear(ctx);
1455
    //    }
1456
  }
1457

1458
  return stat;
161✔
1459
}
1460

1461
/*
1462
 * Check with given model and hints
1463
 * - set the model hint and call check_context_with_model
1464
 */
1465
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✔
1466
  assert(m <= n);
1467

1468
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1469

1470
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1471
}
1472

1473

1474
/*
1475
 * Precheck: force generation of clauses and other stuff that's
1476
 * constructed lazily by the solvers. For example, this
1477
 * can be used to convert all the constraints asserted in the
1478
 * bitvector to clauses so that we can export the result to DIMACS.
1479
 *
1480
 * If ctx status is IDLE:
1481
 * - the function calls 'start_search' and does one round of propagation.
1482
 * - if this results in UNSAT, the function returns UNSAT
1483
 * - if the precheck is interrupted, the function returns INTERRUPTED
1484
 * - otherwise the function returns UNKNOWN and sets the status to
1485
 *   UNKNOWN.
1486
 *
1487
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
1488
 * IDLE before doing anything else with this context.
1489
 *
1490
 * If ctx status is not IDLE, the function returns it and does nothing
1491
 * else.
1492
 */
1493
smt_status_t precheck_context(context_t *ctx) {
×
1494
  smt_status_t stat;
1495
  smt_core_t *core;
1496

1497
  core = ctx->core;
×
1498

1499
  stat = smt_status(core);
×
1500
  if (stat == YICES_STATUS_IDLE) {
×
1501
    start_search(core, 0, NULL);
×
1502
    smt_process(core);
×
1503
    stat = smt_status(core);
×
1504

1505
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1506
           stat == YICES_STATUS_INTERRUPTED);
1507

1508
    if (stat == YICES_STATUS_SEARCHING) {
×
1509
      end_search_unknown(core);
×
1510
      stat = YICES_STATUS_UNKNOWN;
×
1511
    }
1512
  }
1513

1514
  return stat;
×
1515
}
1516

1517

1518

1519
/*
1520
 * Solve using another SAT solver
1521
 * - sat_solver = name of the solver to use
1522
 * - verbosity = verbosity level (0 means quiet)
1523
 * - this may be used only for BV or pure SAT problems
1524
 * - we perform one round of propagation to convert the problem to CNF
1525
 * - then we call an external SAT solver on the CNF problem
1526
 */
1527
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
38✔
1528
  smt_status_t stat;
1529
  smt_core_t *core;
1530
  delegate_t delegate;
1531
  bvar_t x;
1532
  bval_t v;
1533

1534
  core = ctx->core;
38✔
1535

1536
  stat = smt_status(core);
38✔
1537
  if (stat == YICES_STATUS_IDLE) {
38✔
1538
    start_search(core, 0, NULL);
38✔
1539
    smt_process(core);
38✔
1540
    stat = smt_status(core);
38✔
1541

1542
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1543
           stat == YICES_STATUS_INTERRUPTED);
1544

1545
    if (stat == YICES_STATUS_SEARCHING) {
38✔
1546
      if (smt_easy_sat(core)) {
36✔
1547
        stat = YICES_STATUS_SAT;
36✔
1548
      } else {
1549
        // call the delegate
1550
        init_delegate(&delegate, sat_solver, num_vars(core));
×
NEW
1551
        ctx->sat_delegate_stats.delegate_initializations ++;
×
UNCOV
1552
        delegate_set_verbosity(&delegate, verbosity);
×
1553

1554
        stat = solve_with_delegate(&delegate, core);
×
1555
        set_smt_status(core, stat);
×
1556
        if (stat == YICES_STATUS_SAT) {
×
1557
          for (x=0; x<num_vars(core); x++) {
×
1558
            v = delegate_get_value(&delegate, x);
×
1559
            set_bvar_value(core, x, v);
×
1560
          }
1561
        }
1562
        delete_delegate(&delegate);
×
1563
      }
1564
    }
1565
  }
1566

1567
  return stat;
38✔
1568
}
1569

1570
/*
1571
 * One-shot check with delegate and assumptions.
1572
 * - assumptions are literals in core encoding.
1573
 * - if failed != NULL and result is UNSAT, failed assumptions are appended to *failed.
1574
 */
1575
static smt_status_t check_with_delegate_assumptions(context_t *ctx, const char *sat_solver, uint32_t verbosity,
×
1576
                                                    uint32_t n, const literal_t *assumptions, ivector_t *failed) {
1577
  smt_status_t stat;
1578
  smt_core_t *core;
1579
  delegate_t delegate;
1580

1581
  core = ctx->core;
×
1582

1583
  stat = smt_status(core);
×
1584
  if (stat != YICES_STATUS_IDLE) {
×
1585
    return stat;
×
1586
  }
1587

1588
  start_search(core, 0, NULL);
×
1589
  smt_process(core);
×
1590
  stat = smt_status(core);
×
1591

1592
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1593
         stat == YICES_STATUS_INTERRUPTED);
1594

1595
  if (stat != YICES_STATUS_SEARCHING) {
×
1596
    return stat;
×
1597
  }
1598

1599
  if (!init_delegate(&delegate, sat_solver, num_vars(core))) {
×
1600
    return YICES_STATUS_UNKNOWN;
×
1601
  }
NEW
1602
  ctx->sat_delegate_stats.delegate_initializations ++;
×
UNCOV
1603
  delegate_set_verbosity(&delegate, verbosity);
×
1604

1605
  stat = solve_with_delegate_assumptions(&delegate, core, n, assumptions, failed);
×
1606
  set_smt_status(core, stat);
×
1607
  set_delegate_assumption_state(core, n, assumptions, stat, failed);
×
1608
  if (stat == YICES_STATUS_SAT) {
×
1609
    context_import_delegate_model(core, &delegate);
×
1610
  }
1611

1612
  delete_delegate(&delegate);
×
1613
  return stat;
×
1614
}
1615

1616

1617
/*
1618
 * Bit-blast then export to DIMACS
1619
 * - filename = name of the output file
1620
 * - status = status of the context after bit-blasting
1621
 *
1622
 * If ctx status is IDLE
1623
 * - perform one round of propagation to conver the problem to CNF
1624
 * - export the CNF to DIMACS
1625
 *
1626
 * If ctx status is not IDLE,
1627
 * - store the stauts in *status and do nothing else
1628
 *
1629
 * Return code:
1630
 *  1 if the DIMACS file was created
1631
 *  0 if the problem was solved by the propagation round
1632
 * -1 if there was an error in creating or writing to the file.
1633
 */
1634
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1635
  smt_core_t *core;
1636
  FILE *f;
1637
  smt_status_t stat;
1638
  int32_t code;
1639

1640
  core = ctx->core;
×
1641

1642
  code = 0;
×
1643
  stat = smt_status(core);
×
1644
  if (stat == YICES_STATUS_IDLE) {
×
1645
    start_search(core, 0, NULL);
×
1646
    smt_process(core);
×
1647
    stat = smt_status(core);
×
1648

1649
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1650
           stat == YICES_STATUS_INTERRUPTED);
1651

1652
    if (stat == YICES_STATUS_SEARCHING) {
×
1653
      code = 1;
×
1654
      f = fopen(filename, "w");
×
1655
      if (f == NULL) {
×
1656
        code = -1;
×
1657
      } else {
1658
        dimacs_print_bvcontext(f, ctx);
×
1659
        if (ferror(f)) code = -1;
×
1660
        fclose(f);
×
1661
      }
1662
    }
1663
  }
1664

1665
  *status = stat;
×
1666

1667
  return code;
×
1668
}
1669

1670

1671
/*
1672
 * Simplify then export to Dimacs:
1673
 * - filename = name of the output file
1674
 * - status = status of the context after CNF conversion + preprocessing
1675
 *
1676
 * If ctx status is IDLE
1677
 * - perform one round of propagation to convert the problem to CNF
1678
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
1679
 *
1680
 * If ctx status is not IDLE, the function stores that in *status
1681
 * If y2sat preprocessing solves the formula, return the status also in *status
1682
 *
1683
 * Return code:
1684
 *  1 if the DIMACS file was created
1685
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
1686
 * -1 if there was an error creating or writing to the file.
1687
 */
1688
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
1689
  smt_core_t *core;
1690
  FILE *f;
1691
  smt_status_t stat;
1692
  delegate_t delegate;
1693
  bvar_t x;
1694
  bval_t v;
1695
  int32_t code;
1696

1697
  core = ctx->core;
×
1698

1699
  code = 0;
×
1700
  stat = smt_status(core);
×
1701
  if (stat == YICES_STATUS_IDLE) {
×
1702
    start_search(core, 0, NULL);
×
1703
    smt_process(core);
×
1704
    stat = smt_status(core);
×
1705

1706
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1707
           stat == YICES_STATUS_INTERRUPTED);
1708

1709
    if (stat == YICES_STATUS_SEARCHING) {
×
1710
      if (smt_easy_sat(core)) {
×
1711
        stat = YICES_STATUS_SAT;
×
1712
      } else {
1713
        // call the delegate
1714
        init_delegate(&delegate, "y2sat", num_vars(core));
×
1715
        delegate_set_verbosity(&delegate, 0);
×
1716

1717
        stat = preprocess_with_delegate(&delegate, core);
×
1718
        set_smt_status(core, stat);
×
1719
        if (stat == YICES_STATUS_SAT) {
×
1720
          for (x=0; x<num_vars(core); x++) {
×
1721
            v = delegate_get_value(&delegate, x);
×
1722
            set_bvar_value(core, x, v);
×
1723
          }
1724
        } else if (stat == YICES_STATUS_UNKNOWN) {
×
1725
          code = 1;
×
1726
          f = fopen(filename, "w");
×
1727
          if (f == NULL) {
×
1728
            code = -1;
×
1729
          } else {
1730
            export_to_dimacs_with_delegate(&delegate, f);
×
1731
            if (ferror(f)) code = -1;
×
1732
            fclose(f);
×
1733
          }
1734
        }
1735

1736
        delete_delegate(&delegate);
×
1737
      }
1738
    }
1739
  }
1740

1741
  *status = stat;
×
1742

1743
  return code;
×
1744
}
1745

1746

1747

1748
/*
1749
 * MODEL CONSTRUCTION
1750
 */
1751

1752
/*
1753
 * Value of literal l in ctx->core
1754
 */
1755
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
1756
  value_t v;
1757

1758
  v = null_value; // prevent GCC warning
65,201✔
1759
  switch (literal_value(ctx->core, l)) {
65,201✔
1760
  case VAL_FALSE:
38,577✔
1761
    v = vtbl_mk_false(vtbl);
38,577✔
1762
    break;
38,577✔
1763
  case VAL_UNDEF_FALSE:
×
1764
  case VAL_UNDEF_TRUE:
1765
    v = vtbl_mk_unknown(vtbl);
×
1766
    break;
×
1767
  case VAL_TRUE:
26,624✔
1768
    v = vtbl_mk_true(vtbl);
26,624✔
1769
    break;
26,624✔
1770
  }
1771
  return v;
65,201✔
1772
}
1773

1774

1775
/*
1776
 * Value of arithmetic variable x in ctx->arith_solver
1777
 */
1778
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
22,590✔
1779
  rational_t *a;
1780
  value_t v;
1781

1782
  assert(context_has_arith_solver(ctx));
1783

1784
  a = &ctx->aux;
22,590✔
1785
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
22,590✔
1786
    v = vtbl_mk_rational(vtbl, a);
22,590✔
1787
  } else {
1788
    v = vtbl_mk_unknown(vtbl);
×
1789
  }
1790

1791
  return v;
22,590✔
1792
}
1793

1794

1795

1796
/*
1797
 * Value of bitvector variable x in ctx->bv_solver
1798
 */
1799
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,153✔
1800
  bvconstant_t *b;
1801
  value_t v;
1802

1803
  assert(context_has_bv_solver(ctx));
1804

1805
  b = &ctx->bv_buffer;
18,153✔
1806
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,153✔
1807
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,153✔
1808
  } else {
1809
    v = vtbl_mk_unknown(vtbl);
×
1810
  }
1811

1812
  return v;
18,153✔
1813
}
1814

1815

1816
/*
1817
 * Get a value for term t in the solvers or egraph
1818
 * - attach the mapping from t to that value in model
1819
 * - if we don't have a concrete object for t but t is
1820
 *   mapped to a term u and the model->has_alias is true,
1821
 *   then we store the mapping [t --> u] in the model's
1822
 *   alias map.
1823
 */
1824
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
320,101✔
1825
  value_table_t *vtbl;
1826
  term_t r;
1827
  uint32_t polarity;
1828
  int32_t x;
1829
  type_t tau;
1830
  value_t v;
1831

1832
  /*
1833
   * Get the root of t in the substitution table
1834
   */
1835
  r = intern_tbl_get_root(&ctx->intern, t);
320,101✔
1836
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
320,101✔
1837
    /*
1838
     * r is mapped to some object x in egraph/core/or theory solvers
1839
     * - keep track of polarity then force r to positive polarity
1840
     */
1841
    vtbl = model_get_vtbl(model);
110,718✔
1842
    polarity = polarity_of(r);
110,718✔
1843
    r = unsigned_term(r);
110,718✔
1844

1845
    /*
1846
     * Convert x to a concrete value
1847
     */
1848
    x = intern_tbl_map_of_root(&ctx->intern, r);
110,718✔
1849
    if (code_is_eterm(x)) {
110,718✔
1850
      // x refers to an egraph object or true_occ/false_occ
1851
      if (x == bool2code(true)) {
4,774✔
1852
        v = vtbl_mk_true(vtbl);
475✔
1853
      } else if (x == bool2code(false)) {
4,299✔
1854
        v = vtbl_mk_false(vtbl);
1,420✔
1855
      } else {
1856
        assert(context_has_egraph(ctx));
1857
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,879✔
1858
      }
1859

1860
    } else {
1861
      // x refers to a literal or a theory variable
1862
      tau = term_type(ctx->terms, r);
105,944✔
1863
      switch (type_kind(ctx->types, tau)) {
105,944✔
1864
      case BOOL_TYPE:
65,201✔
1865
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
1866
        break;
65,201✔
1867

1868
      case INT_TYPE:
22,590✔
1869
      case REAL_TYPE:
1870
        v = arith_value(ctx, vtbl, code2thvar(x));
22,590✔
1871
        break;
22,590✔
1872

1873
      case BITVECTOR_TYPE:
18,153✔
1874
        v = bv_value(ctx, vtbl, code2thvar(x));
18,153✔
1875
        break;
18,153✔
1876

1877
      default:
×
1878
        /*
1879
         * This should never happen:
1880
         * scalar, uninterpreted, tuple, function terms
1881
         * are mapped to egraph terms.
1882
         */
1883
        assert(false);
1884
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
1885
        break;
×
1886
      }
1887
    }
1888

1889
    /*
1890
     * Restore polarity then add mapping [t --> v] in the model
1891
     */
1892
    if (! object_is_unknown(vtbl, v)) {
110,718✔
1893
      if (object_is_boolean(vtbl, v)) {
110,718✔
1894
        if (polarity) {
67,096✔
1895
          // negate the value
1896
          v = vtbl_mk_not(vtbl, v);
24✔
1897
        }
1898
      }
1899
      model_map_term(model, t, v);
110,718✔
1900
    }
1901

1902
  } else {
1903
    /*
1904
     * r is not mapped to anything:
1905
     *
1906
     * 1) If t == r and t is present in the internalization table
1907
     *    then t is relevant. So we should display its value
1908
     *    when we print the model. To do this, we assign an
1909
     *    arbitrary value v to t and store [t := v] in the map.
1910
     *
1911
     * 2) If t != r then we keep the mapping [t --> r] in
1912
     *    the alias table (provided the model supports aliases).
1913
     */
1914
    if (t == r) {
209,383✔
1915
      if (intern_tbl_term_present(&ctx->intern, t)) {
208,731✔
1916
        tau = term_type(ctx->terms, t);
×
1917
        vtbl = model_get_vtbl(model);
×
1918
        v = vtbl_make_object(vtbl, tau);
×
1919
        model_map_term(model, t, v);
×
1920
      }
1921
    } else if (model->has_alias) {
652✔
1922
      // t != r: keep the substitution [t --> r] in the model
1923
      model_add_substitution(model, t, r);
652✔
1924
    }
1925
  }
1926
}
320,101✔
1927

1928

1929

1930

1931
/*
1932
 * Build a model for the current context (including all satellite solvers)
1933
 * - the context status must be SAT (or UNKNOWN)
1934
 * - if model->has_alias is true, we store the term substitution
1935
 *   defined by ctx->intern_tbl into the model
1936
 * - cleanup of satellite models needed using clean_solver_models()
1937
 */
1938
void build_model(model_t *model, context_t *ctx) {
42,161✔
1939
  term_table_t *terms;
1940
  uint32_t i, n;
1941
  term_t t;
1942

1943
  assert(smt_status(ctx->core) == YICES_STATUS_SAT || smt_status(ctx->core) == YICES_STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == YICES_STATUS_SAT);
1944

1945
  /*
1946
   * First build assignments in the satellite solvers
1947
   * and get the val_in_model functions for the egraph
1948
   */
1949
  if (context_has_arith_solver(ctx)) {
42,161✔
1950
    ctx->arith.build_model(ctx->arith_solver);
32,909✔
1951
  }
1952
  if (context_has_bv_solver(ctx)) {
42,161✔
1953
    ctx->bv.build_model(ctx->bv_solver);
21,418✔
1954
  }
1955

1956
  /*
1957
   * Construct the egraph model
1958
   */
1959
  if (context_has_egraph(ctx)) {
42,161✔
1960
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,035✔
1961
  }
1962

1963
  /*
1964
   * Construct the mcsat model.
1965
   */
1966
  if (context_has_mcsat(ctx)) {
42,161✔
1967
    mcsat_build_model(ctx->mcsat, model);
51✔
1968
  }
1969

1970
  // scan the internalization table
1971
  terms = ctx->terms;
42,161✔
1972
  n = intern_tbl_num_terms(&ctx->intern);
42,161✔
1973
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,097,690✔
1974
    if (good_term_idx(terms, i)) {
1,235,055,529✔
1975
      t = pos_occ(i);
1,235,055,529✔
1976
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,055,529✔
1977
        build_term_value(ctx, model, t);
320,101✔
1978
      }
1979
    }
1980
  }
1981
}
42,161✔
1982

1983

1984
/*
1985
 * Cleanup solver models
1986
 */
1987
void clean_solver_models(context_t *ctx) {
42,161✔
1988
  if (context_has_arith_solver(ctx)) {
42,161✔
1989
    ctx->arith.free_model(ctx->arith_solver);
32,909✔
1990
  }
1991
  if (context_has_bv_solver(ctx)) {
42,161✔
1992
    ctx->bv.free_model(ctx->bv_solver);
21,418✔
1993
  }
1994
  if (context_has_egraph(ctx)) {
42,161✔
1995
    egraph_free_model(ctx->egraph);
13,035✔
1996
  }
1997
}
42,161✔
1998

1999

2000

2001
/*
2002
 * Build a model for the current context
2003
 * - the context status must be SAT (or UNKNOWN)
2004
 * - if model->has_alias is true, we store the term substitution
2005
 *   defined by ctx->intern_tbl into the model
2006
 */
2007
void context_build_model(model_t *model, context_t *ctx) {
260✔
2008
  // Build solver models and term values
2009
  build_model(model, ctx);
260✔
2010

2011
  // Cleanup
2012
  clean_solver_models(ctx);
260✔
2013
}
260✔
2014

2015

2016

2017
/*
2018
 * Read the value of a Boolean term t
2019
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
2020
 */
2021
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
2022
  term_t r;
2023
  uint32_t polarity;
2024
  int32_t x;
2025
  bval_t v;
2026

2027
  assert(is_boolean_term(ctx->terms, t));
2028

2029
  // default value if t is not in the internalization table
2030
  v = VAL_UNDEF_FALSE;
×
2031
  r = intern_tbl_get_root(&ctx->intern, t);
×
2032
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
2033
    // r is mapped to some object x
2034
    polarity = polarity_of(r);
×
2035
    r = unsigned_term(r);
×
2036

2037
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
2038
    if (code_is_eterm(x)) {
×
2039
      // x must be either true_occ or false_occ
2040
      if (x == bool2code(true)) {
×
2041
        v = VAL_TRUE;
×
2042
      } else {
2043
        assert(x == bool2code(false));
2044
        v = VAL_FALSE;
×
2045
      }
2046
    } else {
2047
      // x refers to a literal in the smt core
2048
      v = literal_value(ctx->core, code2literal(x));
×
2049
    }
2050

2051
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
2052
    v ^= polarity;
×
2053
  }
2054

2055
  return v;
×
2056
}
2057

2058

2059
/*
2060
 * UNSAT CORE
2061
 */
2062

2063
/*
2064
 * Build an unsat core:
2065
 * - store the result in v
2066
 * - first reuse a cached term core if available.
2067
 * - otherwise:
2068
 *   CDCL(T): build from smt_core then cache as terms
2069
 *   MCSAT: return empty unless check-with-term-assumptions populated the cache.
2070
 */
2071
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
2,709✔
2072
  smt_core_t *core;
2073
  uint32_t i, n;
2074
  term_t t;
2075

2076
  if (ctx->unsat_core_cache != NULL) {
2,709✔
2077
    // Fast path: repeated get_unsat_core returns the cached term vector.
2078
    ivector_reset(v);
10✔
2079
    ivector_copy(v, ctx->unsat_core_cache->data, ctx->unsat_core_cache->size);
10✔
2080
    return;
10✔
2081
  }
2082

2083
  if (ctx->mcsat != NULL) {
2,699✔
2084
    // MCSAT core extraction is done in check-with-term-assumptions; without cache
2085
    // there is no generic context-level core structure to rebuild from here.
2086
    ivector_reset(v);
×
2087
    return;
×
2088
  }
2089

2090
  core = ctx->core;
2,699✔
2091
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
2092
  build_unsat_core(core, v);
2,699✔
2093

2094
  // convert from literals to terms
2095
  n = v->size;
2,699✔
2096
  for (i=0; i<n; i++) {
37,499✔
2097
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
34,800✔
2098
    assert(t >= 0);
2099
    v->data[i] = t;
34,800✔
2100
  }
2101

2102
  // Cache the converted term core for subsequent queries.
2103
  cache_unsat_core(ctx, v);
2,699✔
2104
}
2105

2106

2107
/*
2108
 * MODEL INTERPOLANT
2109
 */
2110
term_t context_get_unsat_model_interpolant(context_t *ctx) {
61✔
2111
  assert(ctx->mcsat != NULL);
2112
  return mcsat_get_unsat_model_interpolant(ctx->mcsat);
61✔
2113
}
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