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

SRI-CSL / yices2 / 27077167677

06 Jun 2026 11:44PM UTC coverage: 69.027% (+0.009%) from 69.018%
27077167677

Pull #636

github

web-flow
Merge 892c40b1c into d00adb6a8
Pull Request #636: New ReduceDB cdclt

44 of 73 new or added lines in 5 files covered. (60.27%)

8 existing lines in 5 files now uncovered.

88165 of 127725 relevant lines covered (69.03%)

1718769.18 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) {
95,711✔
63
  trace_printf(core->trace, level,
95,711✔
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
}
95,711✔
76

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

84

85
/*
86
 * On restart
87
 */
88
static void trace_restart(smt_core_t *core) {
2,525✔
89
  trace_stats(core, "restart:", 1);
2,525✔
90
}
2,525✔
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) {
226✔
101
  trace_stats(core, "reduce:", 3);
226✔
102
  trace_printf(core->trace, 4, "(%"PRIu64" clauses deleted)\n", deleted);
226✔
103
}
226✔
104

105

106

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

135
  case VAL_TRUE:
×
136
    break;
×
137

138
  case VAL_FALSE:
3,549✔
139
    save_conflicting_assumption(core, l);
3,549✔
140
    break;
3,549✔
141
  }
142
}
108,611✔
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,547,002✔
155
  uint64_t conflicts, deletions;
156

157
  assert(r_interval > 0);
158

159
  conflicts = num_conflicts(core);
7,547,002✔
160
  if (conflicts >= *r_threshold) {
7,547,002✔
161
    deletions = core->stats.learned_clauses_deleted;
226✔
162
    reduce_clause_database(core);
226✔
163
    *r_threshold = conflicts + (uint64_t) (r_interval * sqrt((double) conflicts));
226✔
164
    trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
226✔
165
  }
166
}
7,547,002✔
167

168
/*
169
 * Bounded search with the default branching heuristic (picosat-like)
170
 * - search until the conflict bound is reached or until the problem is solved.
171
 * - reduce_threshold: conflict count above which reduce_clause_database is called
172
 * - r_interval = coefficient in threshold update: next = conflicts + r_interval * sqrt(conflicts)
173
 * - use the default branching heuristic implemented by the core
174
 */
175
static void search(smt_core_t *core, uint32_t conflict_bound, uint64_t *reduce_threshold, uint32_t r_interval) {
13,451✔
176
  uint64_t max_conflicts;
177
  literal_t l;
178

179
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
180

181
  max_conflicts = num_conflicts(core) + conflict_bound;
13,451✔
182

183
  smt_process(core);
13,451✔
184
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
6,265,611✔
185
    // reduce heuristic
186
    try_reduce_heuristic(core, reduce_threshold, r_interval);
6,252,160✔
187

188
    // assumption
189
    if (core->has_assumptions) {
6,252,160✔
190
      l = get_next_assumption(core);
10✔
191
      if (l != null_literal) {
10✔
192
        process_assumption(core, l);
3✔
193
        continue;
3✔
194
      }
195
    }
196

197
    // decision
198
    l = select_unassigned_literal(core);
6,252,157✔
199
    if (l == null_literal) {
6,252,157✔
200
      // all variables assigned: Call final_check
201
      smt_final_check(core);
16,595✔
202
    } else {
203
      decide_literal(core, l);
6,235,562✔
204
      smt_process(core);
6,235,562✔
205
    }
206
  }
207
}
13,451✔
208

209

210
/*
211
 * HACK: Variant for Luby restart:
212
 * - search until the conflict bound is reached or until the problem is solved.
213
 * - reduce_threshold: conflict count above which reduce_clause_database is called
214
 * - r_interval = coefficient in threshold update: next = conflicts + r_interval * sqrt(conflicts)
215
 * - use the default branching heuristic implemented by the core
216
 *
217
 * This uses smt_bounded_process to force more frequent restarts.
218
 */
219
static void luby_search(smt_core_t *core, uint32_t conflict_bound, uint64_t *reduce_threshold, uint32_t r_interval) {
14,729✔
220
  uint64_t max_conflicts;
221
  literal_t l;
222

223
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
224

225
  max_conflicts = num_conflicts(core) + conflict_bound;
14,729✔
226
  smt_bounded_process(core, max_conflicts);
14,729✔
227
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) < max_conflicts) {
701,714✔
228
    // reduce heuristic
229
    try_reduce_heuristic(core, reduce_threshold, r_interval);
686,985✔
230

231
    // assumption
232
    if (core->has_assumptions) {
686,985✔
233
      l = get_next_assumption(core);
119,882✔
234
      if (l != null_literal) {
119,882✔
235
        process_assumption(core, l);
108,606✔
236
        continue;
108,606✔
237
      }
238
    }
239

240
    // decision
241
    l = select_unassigned_literal(core);
578,379✔
242
    if (l == null_literal) {
578,379✔
243
      // all variables assigned: Call final_check
244
      smt_final_check(core);
8,803✔
245
    } else {
246
      decide_literal(core, l);
569,576✔
247
      smt_bounded_process(core, max_conflicts);
569,576✔
248
    }
249
  }
250
}
14,729✔
251

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

258

259
/*
260
 * Bounded search with a non-default branching heuristics
261
 * - search until the conflict bound is reached or until the problem is solved.
262
 * - reduce_threshold: conflict count above which reduce_clause_database is called
263
 * - r_interval = coefficient in threshold update: next = conflicts + r_interval * sqrt(conflicts)
264
 * - use the branching heuristic implemented by branch
265
 */
266
static void special_search(smt_core_t *core, uint32_t conflict_bound, uint64_t *reduce_threshold,
20,868✔
267
                           uint32_t r_interval, branching_fun_t branch) {
268
  uint64_t max_conflicts;
269
  literal_t l;
270

271
  assert(smt_status(core) == YICES_STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
272

273
  max_conflicts = num_conflicts(core) + conflict_bound;
20,868✔
274
  smt_process(core);
20,868✔
275
  while (smt_status(core) == YICES_STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
628,725✔
276
    // reduce heuristic
277
    try_reduce_heuristic(core, reduce_threshold, r_interval);
607,857✔
278

279
    // assumption
280
    if (core->has_assumptions) {
607,857✔
281
      l = get_next_assumption(core);
2✔
282
      if (l != null_literal) {
2✔
283
        process_assumption(core, l);
2✔
284
        continue;
2✔
285
      }
286
    }
287

288
    // decision
289
    l = select_unassigned_literal(core);
607,855✔
290
    if (l == null_literal) {
607,855✔
291
      // all variables assigned: call final check
292
      smt_final_check(core);
22,620✔
293
    } else {
294
      // apply the branching heuristic
295
      l = branch(core, l);
585,235✔
296
      // propagation
297
      decide_literal(core, l);
585,235✔
298
      smt_process(core);
585,235✔
299
    }
300
  }
301
}
20,868✔
302

303

304

305

306

307
/*
308
 * SUPPORTED BRANCHING
309
 */
310

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

320
static literal_t positive_branch(smt_core_t *core, literal_t l) {
26,776✔
321
  return l & ~1; // force the sign bit to 0
26,776✔
322
}
323

324

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

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

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

352

353

354

355

356
/*
357
 * CORE SOLVER
358
 */
359

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

372
  c_threshold = params->c_threshold;
46,437✔
373
  d_threshold = c_threshold; // required by trace_start in slow_restart mode
46,437✔
374
  luby = false;
46,437✔
375
  u = 1;
46,437✔
376
  v = 1;
46,437✔
377
  period = c_threshold;
46,437✔
378

379
  if (params->fast_restart) {
46,437✔
380
    d_threshold = params->d_threshold;
12,724✔
381
    // HACK to activate the Luby heuristic:
382
    // c_factor must be 0.0 and fast_restart must be true
383
    luby = params->c_factor == 0.0;
12,724✔
384
  }
385

386
  reduce_threshold = params->r_initial_threshold;
46,437✔
387

388
  // initialize then do a propagation + simplification step.
389
  start_search(core, n, a);
46,437✔
390
  trace_start(core);
46,437✔
391
  if (smt_status(core) == YICES_STATUS_SEARCHING) {
46,437✔
392
    // loop
393
    for (;;) {
394
      switch (params->branching) {
49,048✔
395
      case BRANCHING_DEFAULT:
28,180✔
396
        if (luby) {
28,180✔
397
          luby_search(core, c_threshold, &reduce_threshold, params->r_interval);
14,729✔
398
        } else {
399
          search(core, c_threshold, &reduce_threshold, params->r_interval);
13,451✔
400
        }
401
        break;
28,180✔
402
      case BRANCHING_NEGATIVE:
188✔
403
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, negative_branch);
188✔
404
        break;
188✔
405
      case BRANCHING_POSITIVE:
176✔
406
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, positive_branch);
176✔
407
        break;
176✔
408
      case BRANCHING_THEORY:
20,504✔
409
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, theory_branch);
20,504✔
410
        break;
20,504✔
411
      case BRANCHING_TH_NEG:
×
NEW
412
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, theory_or_neg_branch);
×
413
        break;
×
414
      case BRANCHING_TH_POS:
×
NEW
415
        special_search(core, c_threshold, &reduce_threshold, params->r_interval, theory_or_pos_branch);
×
416
        break;
×
417
      }
418

419
      if (smt_status(core) != YICES_STATUS_SEARCHING) break;
49,048✔
420

421
      smt_restart(core);
2,611✔
422
      //      smt_partial_restart_var(core);
423

424
      if (luby) {
2,611✔
425
        // Luby-style restart
426
        if ((u & -u) == v) {
2,221✔
427
          u ++;
1,198✔
428
          v = 1;
1,198✔
429
        } else {
430
          v <<= 1;
1,023✔
431
        }
432
        c_threshold = v * period;
2,221✔
433
        trace_restart(core);
2,221✔
434

435
      } else {
436
        // Either Minisat or Picosat-like restart
437

438
        // inner restart: increase c_threshold
439
        c_threshold = (uint32_t) (c_threshold * params->c_factor);
390✔
440

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

457
  trace_done(core);
46,437✔
458
}
46,437✔
459

460

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

471
  /*
472
   * Set core parameters
473
   */
474
  core = ctx->core;
46,437✔
475
  set_randomness(core, params->randomness);
46,437✔
476
  set_random_seed(core, params->random_seed);
46,437✔
477
  set_var_decay_factor(core, params->var_decay);
46,437✔
478
  set_clause_decay_factor(core, params->clause_decay);
46,437✔
479
  if (params->cache_tclauses) {
46,437✔
480
    enable_theory_cache(core, params->tclause_size);
33,693✔
481
  } else {
482
    disable_theory_cache(core);
12,744✔
483
  }
484

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

515
  /*
516
   * Set simplex parameters
517
   */
518
  if (context_has_simplex_solver(ctx)) {
46,437✔
519
    simplex = ctx->arith_solver;
33,255✔
520
    if (params->use_simplex_prop) {
33,255✔
521
      simplex_enable_propagation(simplex);
12,869✔
522
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,869✔
523
    }
524
    if (params->adjust_simplex_model) {
33,255✔
525
      simplex_enable_adjust_model(simplex);
12,823✔
526
    }
527
    simplex_set_bland_threshold(simplex, params->bland_threshold);
33,255✔
528
    if (params->integer_check) {
33,255✔
529
      simplex_enable_periodic_icheck(simplex);
×
530
      simplex_set_integer_check_period(simplex, params->integer_check_period);
×
531
    }
532
  }
533

534
  /*
535
   * Set array solver parameters
536
   */
537
  if (context_has_fun_solver(ctx)) {
46,437✔
538
    fsolver = ctx->fun_solver;
12,884✔
539
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,884✔
540
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,884✔
541
  }
542
}
46,437✔
543

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

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

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

562
  if (params == NULL) {
60,732✔
563
    params = get_default_params();
×
564
  }
565

566
  if (ctx->mcsat != NULL) {
60,732✔
567
    return call_mcsat_solver(ctx, params);
1,136✔
568
  }
569

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

579
  return stat;
59,596✔
580
}
581

582

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

591
  assert(ctx->mcsat == NULL);
592

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

605
  return stat;
3,665✔
606
}
607

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

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

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

642
void context_sat_delegate_state_cleanup(context_t *ctx) {
23,422✔
643
  sat_delegate_state_t *st;
644

645
  st = (sat_delegate_state_t *) ctx->sat_delegate_state;
23,422✔
646
  if (st == NULL) {
23,422✔
647
    return;
23,413✔
648
  }
649

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

664
static sat_delegate_state_t *context_get_sat_delegate_state(context_t *ctx) {
42✔
665
  sat_delegate_state_t *st;
666

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

689
static void sat_delegate_state_reset_cursors(sat_delegate_state_t *st) {
11✔
690
  uint32_t i;
691

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

849
  core = ctx->core;
8✔
850
  nvars = num_vars(core);
8✔
851

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

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

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

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

887
  return true;
8✔
888
}
889

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

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

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

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

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

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

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

956
  return true;
34✔
957
}
958

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

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

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

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

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

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

998
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
999
         stat == YICES_STATUS_INTERRUPTED);
1000

1001
  if (stat != YICES_STATUS_SEARCHING) {
60✔
1002
    return stat;
×
1003
  }
1004

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

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

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

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

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

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

1076
  delete_ivector(&visible_failed);
42✔
1077
  return stat;
42✔
1078
}
1079

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

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

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

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

1106
  default:
×
1107
    return YICES_STATUS_UNKNOWN;
×
1108
  }
1109
}
1110

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

1118
  if (t < 0) {
64✔
1119
    t = not(t);
×
1120
  }
1121

1122
  if (int_hset_member(visited, t)) {
64✔
1123
    return;
×
1124
  }
1125
  int_hset_add(visited, t);
64✔
1126

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

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

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

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

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

1192
  delete_int_hset(&visited);
9✔
1193
  delete_int_hset(&atoms);
9✔
1194
}
9✔
1195

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

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

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

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

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

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

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

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

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

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

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

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

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

1314
    return stat;
10✔
1315
  }
1316
}
1317

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

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

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

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

1353
    init_ivector(&assumptions, n);
3,705✔
1354
    for (i=0; i<n; i++) {
113,578✔
1355
      l = context_add_assumption(ctx, a[i]);
109,873✔
1356
      if (l < 0) {
109,873✔
1357
        if (error != NULL) {
×
1358
          *error = l;
×
1359
        }
1360
        delete_ivector(&assumptions);
×
1361
        return YICES_STATUS_ERROR;
×
1362
      }
1363
      ivector_push(&assumptions, l);
109,873✔
1364
    }
1365

1366
    mode = effective_sat_delegate_mode(ctx->sat_delegate, params, &one_shot);
3,705✔
1367
    delegate = sat_delegate_name(mode);
3,705✔
1368
    if (delegate == NULL) {
3,705✔
1369
      stat = check_context_with_assumptions(ctx, params, n, assumptions.data);
3,665✔
1370
      delete_ivector(&assumptions);
3,665✔
1371
      return stat;
3,665✔
1372
    }
1373

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

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

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

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

1419
  return check_context_with_term_assumptions_mcsat(ctx, params, n, a, error);
10✔
1420
}
1421

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

1429
  assert(ctx->mcsat != NULL);
1430

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

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

1443
  return stat;
161✔
1444
}
1445

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

1453
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
14✔
1454

1455
  return check_context_with_model(ctx, params, mdl, m, t);
14✔
1456
}
1457

1458

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

1482
  core = ctx->core;
×
1483

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

1490
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1491
           stat == YICES_STATUS_INTERRUPTED);
1492

1493
    if (stat == YICES_STATUS_SEARCHING) {
×
1494
      end_search_unknown(core);
×
1495
      stat = YICES_STATUS_UNKNOWN;
×
1496
    }
1497
  }
1498

1499
  return stat;
×
1500
}
1501

1502

1503

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

1519
  core = ctx->core;
38✔
1520

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

1527
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1528
           stat == YICES_STATUS_INTERRUPTED);
1529

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

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

1552
  return stat;
38✔
1553
}
1554

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

1566
  core = ctx->core;
×
1567

1568
  stat = smt_status(core);
×
1569
  if (stat != YICES_STATUS_IDLE) {
×
1570
    return stat;
×
1571
  }
1572

1573
  start_search(core, 0, NULL);
×
1574
  smt_process(core);
×
1575
  stat = smt_status(core);
×
1576

1577
  assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1578
         stat == YICES_STATUS_INTERRUPTED);
1579

1580
  if (stat != YICES_STATUS_SEARCHING) {
×
1581
    return stat;
×
1582
  }
1583

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

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

1597
  delete_delegate(&delegate);
×
1598
  return stat;
×
1599
}
1600

1601

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

1625
  core = ctx->core;
×
1626

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

1634
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1635
           stat == YICES_STATUS_INTERRUPTED);
1636

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

1650
  *status = stat;
×
1651

1652
  return code;
×
1653
}
1654

1655

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

1682
  core = ctx->core;
×
1683

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

1691
    assert(stat == YICES_STATUS_UNSAT || stat == YICES_STATUS_SEARCHING ||
1692
           stat == YICES_STATUS_INTERRUPTED);
1693

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

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

1721
        delete_delegate(&delegate);
×
1722
      }
1723
    }
1724
  }
1725

1726
  *status = stat;
×
1727

1728
  return code;
×
1729
}
1730

1731

1732

1733
/*
1734
 * MODEL CONSTRUCTION
1735
 */
1736

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

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

1759

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

1767
  assert(context_has_arith_solver(ctx));
1768

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

1776
  return v;
22,634✔
1777
}
1778

1779

1780

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

1788
  assert(context_has_bv_solver(ctx));
1789

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

1797
  return v;
18,168✔
1798
}
1799

1800

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

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

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

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

1853
      case INT_TYPE:
22,634✔
1854
      case REAL_TYPE:
1855
        v = arith_value(ctx, vtbl, code2thvar(x));
22,634✔
1856
        break;
22,634✔
1857

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

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

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

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

1913

1914

1915

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

1928
  assert(smt_status(ctx->core) == YICES_STATUS_SAT || smt_status(ctx->core) == YICES_STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == YICES_STATUS_SAT);
1929

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

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

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

1955
  // scan the internalization table
1956
  terms = ctx->terms;
42,186✔
1957
  n = intern_tbl_num_terms(&ctx->intern);
42,186✔
1958
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
1,235,191,275✔
1959
    if (good_term_idx(terms, i)) {
1,235,149,089✔
1960
      t = pos_occ(i);
1,235,149,089✔
1961
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
1,235,149,089✔
1962
        build_term_value(ctx, model, t);
322,634✔
1963
      }
1964
    }
1965
  }
1966
}
42,186✔
1967

1968

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

1984

1985

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

1996
  // Cleanup
1997
  clean_solver_models(ctx);
279✔
1998
}
279✔
1999

2000

2001

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

2012
  assert(is_boolean_term(ctx->terms, t));
2013

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

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

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

2040
  return v;
×
2041
}
2042

2043

2044
/*
2045
 * UNSAT CORE
2046
 */
2047

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

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

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

2075
  core = ctx->core;
3,734✔
2076
  assert(core != NULL && core->status == YICES_STATUS_UNSAT);
2077
  build_unsat_core(core, v);
3,734✔
2078

2079
  // convert from literals to terms
2080
  n = v->size;
3,734✔
2081
  for (i=0; i<n; i++) {
53,819✔
2082
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
50,085✔
2083
    assert(t >= 0);
2084
    v->data[i] = t;
50,085✔
2085
  }
2086

2087
  // Cache the converted term core for subsequent queries.
2088
  cache_unsat_core(ctx, v);
3,734✔
2089
}
2090

2091

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