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

SRI-CSL / yices2 / 12367760548

17 Dec 2024 06:41AM UTC coverage: 65.285% (-0.6%) from 65.92%
12367760548

push

github

web-flow
Fixes GitHub coverage issue (#544)

* Update action.yml

* Update action.yml

81020 of 124102 relevant lines covered (65.29%)

1509382.01 hits per line

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

69.64
/src/context/context_solver.c
1
/*
2
 * This file is part of the Yices SMT Solver.
3
 * Copyright (C) 2017 SRI International.
4
 *
5
 * Yices is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * Yices is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
/*
20
 * SEARCH AND SOLVING PROCEDURES
21
 *
22
 * This module implements the check_context function (and variants).
23
 * It also implements model construction.
24
 */
25

26
#include <stdbool.h>
27
#include <assert.h>
28
#include <stdint.h>
29
#include <inttypes.h>
30
#include <stdio.h>
31

32
#include "context/context.h"
33
#include "context/internalization_codes.h"
34
#include "model/models.h"
35
#include "solvers/bv/dimacs_printer.h"
36
#include "solvers/cdcl/delegate.h"
37
#include "solvers/funs/fun_solver.h"
38
#include "solvers/simplex/simplex.h"
39

40
#include "api/yices_globals.h"
41
#include "mt/thread_macros.h"
42

43

44

45
/*
46
 * TRACE FUNCTIONS
47
 */
48

49
/*
50
 * Basic statistics
51
 */
52
static void trace_stats(smt_core_t *core, const char *when, uint32_t level) {
55,270✔
53
  trace_printf(core->trace, level,
55,270✔
54
               "(%-10s %8"PRIu64" %10"PRIu64" %8"PRIu64" %8"PRIu32" %8"PRIu32" %8"PRIu64" %8"PRIu32" %8"PRIu64" %7.1f)\n",
55
               when, core->stats.conflicts, core->stats.decisions, core->stats.random_decisions,
56
               num_binary_clauses(core), num_prob_clauses(core), num_prob_literals(core),
57
               num_learned_clauses(core), num_learned_literals(core), avg_learned_clause_size(core));
58
#if 0
59
  fprintf(stderr,
60
          "(%-10s %8"PRIu64" %10"PRIu64" %8"PRIu64" %8"PRIu32" %8"PRIu32" %8"PRIu64" %8"PRIu32" %8"PRIu64" %7.1f)\n",
61
          when, core->stats.conflicts, core->stats.decisions, core->stats.random_decisions,
62
          num_binary_clauses(core), num_prob_clauses(core), num_prob_literals(core),
63
          num_learned_clauses(core), num_learned_literals(core), avg_learned_clause_size(core));
64
#endif
65
}
55,270✔
66

67
/*
68
 * On start_search
69
 */
70
static void trace_start(smt_core_t *core) {
26,364✔
71
  trace_stats(core, "start:", 1);
26,364✔
72
}
26,364✔
73

74

75
/*
76
 * On restart
77
 */
78
static void trace_restart(smt_core_t *core) {
2,271✔
79
  trace_stats(core, "restart:", 1);
2,271✔
80
}
2,271✔
81

82
static void trace_inner_restart(smt_core_t *core) {
93✔
83
  trace_stats(core, "inner restart:", 5);
93✔
84
}
93✔
85

86

87
/*
88
 * On reduce clause database
89
 */
90
static void trace_reduce(smt_core_t *core, uint64_t deleted) {
178✔
91
  trace_stats(core, "reduce:", 3);
178✔
92
  trace_printf(core->trace, 4, "(%"PRIu64" clauses deleted)\n", deleted);
178✔
93
}
178✔
94

95

96

97
/*
98
 * End of search
99
 */
100
static void trace_done(smt_core_t *core) {
26,364✔
101
  trace_stats(core, "done:", 1);
26,364✔
102
  trace_newline(core->trace, 1);
26,364✔
103
}
26,364✔
104

105

106

107
/*
108
 * PROCESS AN ASSUMPTION
109
 */
110

111
/*
112
 * l = assumption for the current decision level
113
 * If l is unassigned, we assign it and perform one round of propagation
114
 * If l is false, we record the conflict. The context is unsat under the
115
 * current set of assumptions.
116
 */
117
static void process_assumption(smt_core_t *core, literal_t l) {
110,418✔
118
  switch (literal_value(core, l)) {
110,418✔
119
  case VAL_UNDEF_FALSE:
106,888✔
120
  case VAL_UNDEF_TRUE:
121
    decide_literal(core, l);
106,888✔
122
    smt_process(core);
106,888✔
123
    break;
106,888✔
124

125
  case VAL_TRUE:
×
126
    break;
×
127

128
  case VAL_FALSE:
3,530✔
129
    save_conflicting_assumption(core, l);
3,530✔
130
    break;
3,530✔
131
  }
132
}
110,418✔
133

134

135
/*
136
 * MAIN SEARCH FUNCTIONS
137
 */
138

139
/*
140
 * Bounded search with the default branching heuristic (picosat-like)
141
 * - search until the conflict bound is reached or until the problem is solved.
142
 * - reduce_threshold: number of learned clauses above which reduce_clause_database is called
143
 * - r_factor = increment factor for reduce_threshold
144
 * - use the default branching heuristic implemented by the core
145
 */
146
static void search(smt_core_t *core, uint32_t conflict_bound, uint32_t *reduce_threshold, double r_factor) {
13,421✔
147
  uint64_t max_conflicts;
148
  uint64_t deletions;
149
  uint32_t r_threshold;
150
  literal_t l;
151

152
  assert(smt_status(core) == STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
153

154
  max_conflicts = num_conflicts(core) + conflict_bound;
13,421✔
155
  r_threshold = *reduce_threshold;
13,421✔
156

157
  smt_process(core);
13,421✔
158
  while (smt_status(core) == STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
6,295,986✔
159
    // reduce heuristic
160
    if (num_learned_clauses(core) >= r_threshold) {
6,282,565✔
161
      deletions = core->stats.learned_clauses_deleted;
67✔
162
      reduce_clause_database(core);
67✔
163
      r_threshold = (uint32_t) (r_threshold * r_factor);
67✔
164
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
67✔
165
    }
166

167
    // assumption
168
    if (core->has_assumptions) {
6,282,565✔
169
      l = get_next_assumption(core);
×
170
      if (l != null_literal) {
×
171
        process_assumption(core, l);
×
172
        continue;
×
173
      }
174
    }
175

176
    // decision
177
    l = select_unassigned_literal(core);
6,282,565✔
178
    if (l == null_literal) {
6,282,565✔
179
      // all variables assigned: Call final_check
180
      smt_final_check(core);
16,505✔
181
    } else {
182
      decide_literal(core, l);
6,266,060✔
183
      smt_process(core);
6,266,060✔
184
    }
185
  }
186

187
  *reduce_threshold = r_threshold;
13,421✔
188
}
13,421✔
189

190

191
/*
192
 * HACK: Variant for Luby restart:
193
 * - search until the conflict bound is reached or until the problem is solved.
194
 * - reduce_threshold: number of learned clauses above which reduce_clause_database is called
195
 * - r_factor = increment factor for reduce_threshold
196
 * - use the default branching heuristic implemented by the core
197
 *
198
 * This uses smt_bounded_process to force more frequent restarts.
199
 */
200
static void luby_search(smt_core_t *core, uint32_t conflict_bound, uint32_t *reduce_threshold, double r_factor) {
14,466✔
201
  uint64_t max_conflicts;
202
  uint64_t deletions;
203
  uint32_t r_threshold;
204
  literal_t l;
205

206
  assert(smt_status(core) == STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
207

208
  max_conflicts = num_conflicts(core) + conflict_bound;
14,466✔
209
  r_threshold = *reduce_threshold;
14,466✔
210

211
  smt_bounded_process(core, max_conflicts);
14,466✔
212
  while (smt_status(core) == STATUS_SEARCHING && num_conflicts(core) < max_conflicts) {
705,044✔
213
    // reduce heuristic
214
    if (num_learned_clauses(core) >= r_threshold) {
690,578✔
215
      deletions = core->stats.learned_clauses_deleted;
50✔
216
      reduce_clause_database(core);
50✔
217
      r_threshold = (uint32_t) (r_threshold * r_factor);
50✔
218
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
50✔
219
    }
220

221
    // assumption
222
    if (core->has_assumptions) {
690,578✔
223
      l = get_next_assumption(core);
120,791✔
224
      if (l != null_literal) {
120,791✔
225
        process_assumption(core, l);
110,418✔
226
        continue;
110,418✔
227
      }
228
    }
229

230
    // decision
231
    l = select_unassigned_literal(core);
580,160✔
232
    if (l == null_literal) {
580,160✔
233
      // all variables assigned: Call final_check
234
      smt_final_check(core);
8,778✔
235
    } else {
236
      decide_literal(core, l);
571,382✔
237
      smt_bounded_process(core, max_conflicts);
571,382✔
238
    }
239
  }
240

241
  *reduce_threshold = r_threshold;
14,466✔
242
}
14,466✔
243

244
/*
245
 * Polarity selection (implements branching heuristics)
246
 * - filter is given a literal l + core and must return either l or not l
247
 */
248
typedef literal_t (*branching_fun_t)(smt_core_t *core, literal_t l);
249

250

251
/*
252
 * Bounded search with a non-default branching heuristics
253
 * - search until the conflict bound is reached or until the problem is solved.
254
 * - reduce_threshold: number of learned clauses above which reduce_clause_database is called
255
 * - r_factor = increment factor for reduce_threshold
256
 * - use the branching heuristic implemented by branch
257
 */
258
static void special_search(smt_core_t *core, uint32_t conflict_bound, uint32_t *reduce_threshold,
841✔
259
                           double r_factor, branching_fun_t branch) {
260
  uint64_t max_conflicts;
261
  uint64_t deletions;
262
  uint32_t r_threshold;
263
  literal_t l;
264

265
  assert(smt_status(core) == STATUS_SEARCHING || smt_status(core) == YICES_STATUS_INTERRUPTED);
266

267
  max_conflicts = num_conflicts(core) + conflict_bound;
841✔
268
  r_threshold = *reduce_threshold;
841✔
269

270
  smt_process(core);
841✔
271
  while (smt_status(core) == STATUS_SEARCHING && num_conflicts(core) <= max_conflicts) {
562,690✔
272
    // reduce heuristic
273
    if (num_learned_clauses(core) >= r_threshold) {
561,849✔
274
      deletions = core->stats.learned_clauses_deleted;
61✔
275
      reduce_clause_database(core);
61✔
276
      r_threshold = (uint32_t) (r_threshold * r_factor);
61✔
277
      trace_reduce(core, core->stats.learned_clauses_deleted - deletions);
61✔
278
    }
279

280
    // assumption
281
    if (core->has_assumptions) {
561,849✔
282
      l = get_next_assumption(core);
×
283
      if (l != null_literal) {
×
284
        process_assumption(core, l);
×
285
        continue;
×
286
      }
287
    }
288

289
    // decision
290
    l = select_unassigned_literal(core);
561,849✔
291
    if (l == null_literal) {
561,849✔
292
      // all variables assigned: call final check
293
      smt_final_check(core);
2,254✔
294
    } else {
295
      // apply the branching heuristic
296
      l = branch(core, l);
559,595✔
297
      // propagation
298
      decide_literal(core, l);
559,595✔
299
      smt_process(core);
559,595✔
300
    }
301
  }
302

303
  *reduce_threshold = r_threshold;
841✔
304
}
841✔
305

306

307

308

309

310
/*
311
 * SUPPORTED BRANCHING
312
 */
313

314
/*
315
 * Simple branching heuristics:
316
 * - branch to the negative polarity
317
 * - branch to the positive polarity
318
 */
319
static literal_t negative_branch(smt_core_t *core, literal_t l) {
176,430✔
320
  return l | 1; // force the sign bit to 1
176,430✔
321
}
322

323
static literal_t positive_branch(smt_core_t *core, literal_t l) {
21,277✔
324
  return l & ~1; // force the sign bit to 0
21,277✔
325
}
326

327

328
/*
329
 * For literals with no atom, use the default, otherwise let the theory solver decide
330
 */
331
static literal_t theory_branch(smt_core_t *core, literal_t l) {
361,888✔
332
  if (bvar_has_atom(core, var_of(l))) {
361,888✔
333
    l =  core->th_smt.select_polarity(core->th_solver, get_bvar_atom(core, var_of(l)), l);
288,517✔
334
  }
335
  return l;
361,888✔
336
}
337

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

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

355

356

357

358

359
/*
360
 * CORE SOLVER
361
 */
362

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

375
  c_threshold = params->c_threshold;
26,364✔
376
  d_threshold = c_threshold; // required by trace_start in slow_restart mode
26,364✔
377
  luby = false;
26,364✔
378
  u = 1;
26,364✔
379
  v = 1;
26,364✔
380
  period = c_threshold;
26,364✔
381

382
  if (params->fast_restart) {
26,364✔
383
    d_threshold = params->d_threshold;
12,689✔
384
    // HACK to activate the Luby heuristic:
385
    // c_factor must be 0.0 and fast_restart must be true
386
    luby = params->c_factor == 0.0;
12,689✔
387
  }
388

389
  reduce_threshold = (uint32_t) (num_prob_clauses(core) * params->r_fraction);
26,364✔
390
  if (reduce_threshold < params->r_threshold) {
26,364✔
391
    reduce_threshold = params->r_threshold;
26,333✔
392
  }
393

394
  // initialize then do a propagation + simplification step.
395
  start_search(core, n, a);
26,364✔
396
  trace_start(core);
26,364✔
397
  if (smt_status(core) == STATUS_SEARCHING) {
26,364✔
398
    // loop
399
    for (;;) {
400
      switch (params->branching) {
28,728✔
401
      case BRANCHING_DEFAULT:
27,887✔
402
        if (luby) {
27,887✔
403
          luby_search(core, c_threshold, &reduce_threshold, params->r_factor);
14,466✔
404
        } else {
405
          search(core, c_threshold, &reduce_threshold, params->r_factor);
13,421✔
406
        }
407
        break;
27,887✔
408
      case BRANCHING_NEGATIVE:
175✔
409
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, negative_branch);
175✔
410
        break;
175✔
411
      case BRANCHING_POSITIVE:
182✔
412
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, positive_branch);
182✔
413
        break;
182✔
414
      case BRANCHING_THEORY:
484✔
415
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, theory_branch);
484✔
416
        break;
484✔
417
      case BRANCHING_TH_NEG:
×
418
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, theory_or_neg_branch);
×
419
        break;
×
420
      case BRANCHING_TH_POS:
×
421
        special_search(core, c_threshold, &reduce_threshold, params->r_factor, theory_or_pos_branch);
×
422
        break;
×
423
      }
424

425
      if (smt_status(core) != STATUS_SEARCHING) break;
28,728✔
426

427
      smt_restart(core);
2,364✔
428
      //      smt_partial_restart_var(core);
429

430
      if (luby) {
2,364✔
431
        // Luby-style restart
432
        if ((u & -u) == v) {
1,991✔
433
          u ++;
1,043✔
434
          v = 1;
1,043✔
435
        } else {
436
          v <<= 1;
948✔
437
        }
438
        c_threshold = v * period;
1,991✔
439
        trace_restart(core);
1,991✔
440

441
      } else {
442
        // Either Minisat or Picosat-like restart
443

444
        // inner restart: increase c_threshold
445
        c_threshold = (uint32_t) (c_threshold * params->c_factor);
373✔
446

447
        if (c_threshold >= d_threshold) {
373✔
448
          d_threshold = c_threshold; // Minisat-style
280✔
449
          if (params->fast_restart) {
280✔
450
            // Picosat style
451
            // outer restart: reset c_threshold and increase d_threshold
452
            c_threshold = params->c_threshold;
48✔
453
            d_threshold = (uint32_t) (d_threshold * params->d_factor);
48✔
454
          }
455
          trace_restart(core);
280✔
456
        } else {
457
          trace_inner_restart(core);
93✔
458
        }
459
      }
460
    }
461
  }
462

463
  trace_done(core);
26,364✔
464
}
26,364✔
465

466

467
/*
468
 * Initialize the search parameters based on params.
469
 */
470
static void context_set_search_parameters(context_t *ctx, const param_t *params) {
26,364✔
471
  smt_core_t *core;
472
  egraph_t *egraph;
473
  simplex_solver_t *simplex;
474
  fun_solver_t *fsolver;
475
  uint32_t quota;
476

477
  /*
478
   * Set core parameters
479
   */
480
  core = ctx->core;
26,364✔
481
  set_randomness(core, params->randomness);
26,364✔
482
  set_random_seed(core, params->random_seed);
26,364✔
483
  set_var_decay_factor(core, params->var_decay);
26,364✔
484
  set_clause_decay_factor(core, params->clause_decay);
26,364✔
485
  if (params->cache_tclauses) {
26,364✔
486
    enable_theory_cache(core, params->tclause_size);
13,655✔
487
  } else {
488
    disable_theory_cache(core);
12,709✔
489
  }
490

491
  /*
492
   * Set egraph parameters
493
   */
494
  egraph = ctx->egraph;
26,364✔
495
  if (egraph != NULL) {
26,364✔
496
    if (params->use_optimistic_fcheck) {
13,444✔
497
      egraph_enable_optimistic_final_check(egraph);
13,441✔
498
    } else {
499
      egraph_disable_optimistic_final_check(egraph);
3✔
500
    }
501
    if (params->use_dyn_ack) {
13,444✔
502
      egraph_enable_dyn_ackermann(egraph, params->max_ackermann);
13,249✔
503
      egraph_set_ackermann_threshold(egraph, params->dyn_ack_threshold);
13,249✔
504
    } else {
505
      egraph_disable_dyn_ackermann(egraph);
195✔
506
    }
507
    if (params->use_bool_dyn_ack) {
13,444✔
508
      egraph_enable_dyn_boolackermann(egraph, params->max_boolackermann);
13,249✔
509
      egraph_set_boolack_threshold(egraph, params->dyn_bool_ack_threshold);
13,249✔
510
    } else {
511
      egraph_disable_dyn_boolackermann(egraph);
195✔
512
    }
513
    quota = egraph_num_terms(egraph) * params->aux_eq_ratio;
13,444✔
514
    if (quota < params->aux_eq_quota) {
13,444✔
515
      quota = params->aux_eq_quota;
13,383✔
516
    }
517
    egraph_set_aux_eq_quota(egraph, quota);
13,444✔
518
    egraph_set_max_interface_eqs(egraph, params->max_interface_eqs);
13,444✔
519
  }
520

521
  /*
522
   * Set simplex parameters
523
   */
524
  if (context_has_simplex_solver(ctx)) {
26,364✔
525
    simplex = ctx->arith_solver;
13,218✔
526
    if (params->use_simplex_prop) {
13,218✔
527
      simplex_enable_propagation(simplex);
12,843✔
528
      simplex_set_prop_threshold(simplex, params->max_prop_row_size);
12,843✔
529
    }
530
    if (params->adjust_simplex_model) {
13,218✔
531
      simplex_enable_adjust_model(simplex);
12,801✔
532
    }
533
    simplex_set_bland_threshold(simplex, params->bland_threshold);
13,218✔
534
    if (params->integer_check) {
13,218✔
535
      simplex_enable_periodic_icheck(simplex);
×
536
      simplex_set_integer_check_period(simplex, params->integer_check_period);
×
537
    }
538
  }
539

540
  /*
541
   * Set array solver parameters
542
   */
543
  if (context_has_fun_solver(ctx)) {
26,364✔
544
    fsolver = ctx->fun_solver;
12,863✔
545
    fun_solver_set_max_update_conflicts(fsolver, params->max_update_conflicts);
12,863✔
546
    fun_solver_set_max_extensionality(fsolver, params->max_extensionality);
12,863✔
547
  }
548
}
26,364✔
549

550
static smt_status_t _o_call_mcsat_solver(context_t *ctx, const param_t *params) {
1,061✔
551
  mcsat_solve(ctx->mcsat, params, NULL, 0, NULL);
1,061✔
552
  return mcsat_status(ctx->mcsat);
1,061✔
553
}
554

555
static smt_status_t call_mcsat_solver(context_t *ctx, const param_t *params) {
1,061✔
556
  MT_PROTECT(smt_status_t, __yices_globals.lock, _o_call_mcsat_solver(ctx, params));
1,061✔
557
}
558

559
/*
560
 * Initialize search parameters then call solve
561
 * - if ctx->status is not IDLE, return the status.
562
 * - if params is NULL, we use default values.
563
 */
564
smt_status_t check_context(context_t *ctx, const param_t *params) {
30,593✔
565
  smt_core_t *core;
566
  smt_status_t stat;
567

568
  if (params == NULL) {
30,593✔
569
    params = get_default_params();
×
570
  }
571

572
  if (ctx->mcsat != NULL) {
30,593✔
573
    return call_mcsat_solver(ctx, params);
1,061✔
574
  }
575

576
  core = ctx->core;
29,532✔
577
  stat = smt_status(core);
29,532✔
578
  if (stat == STATUS_IDLE) {
29,532✔
579
    // clean state: the search can proceed
580
    context_set_search_parameters(ctx, params);
22,709✔
581
    solve(core, params, 0, NULL);
22,709✔
582
    stat = smt_status(core);
22,709✔
583
  }
584

585
  return stat;
29,532✔
586
}
587

588

589
/*
590
 * Check with assumptions a[0] ... a[n-1]
591
 * - if ctx->status is not IDLE, return the status.
592
 */
593
smt_status_t check_context_with_assumptions(context_t *ctx, const param_t *params, uint32_t n, const literal_t *a) {
3,655✔
594
  smt_core_t *core;
595
  smt_status_t stat;
596

597
  core = ctx->core;
3,655✔
598
  stat = smt_status(core);
3,655✔
599
  if (stat == STATUS_IDLE) {
3,655✔
600
    // clean state
601
    if (params == NULL) {
3,655✔
602
      params = get_default_params();
×
603
    }
604
    context_set_search_parameters(ctx, params);
3,655✔
605
    solve(core, params, n, a);
3,655✔
606
    stat = smt_status(core);
3,655✔
607
  }
608

609
  return stat;
3,655✔
610
}
611

612
/*
613
 * Check with given model
614
 * - if mcsat status is not IDLE, return the status
615
 */
616
smt_status_t check_context_with_model(context_t *ctx, const param_t *params, model_t* mdl, uint32_t n, const term_t t[]) {
126✔
617
  smt_status_t stat;
618

619
  assert(ctx->mcsat != NULL);
620

621
  stat = mcsat_status(ctx->mcsat);
126✔
622
  if (stat == STATUS_IDLE) {
126✔
623
    mcsat_solve(ctx->mcsat, params, mdl, n, t);
126✔
624
    stat = mcsat_status(ctx->mcsat);
126✔
625

626
    // BD: this looks wrong. We shouldn't call clear yet.
627
    // we want the status to remain STATUS_UNSAT until the next call to check or assert.
628
    //    if (n > 0 && stat == STATUS_UNSAT && context_supports_multichecks(ctx)) {
629
    //      context_clear(ctx);
630
    //    }
631
  }
632

633
  return stat;
126✔
634
}
635

636
/*
637
 * Check with given model and hints
638
 * - set the model hint and call check_context_with_model
639
 */
640
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) {
×
641
  assert(m <= n);
642

643
  mcsat_set_model_hint(ctx->mcsat, mdl, n, t);
×
644

645
  return check_context_with_model(ctx, params, mdl, m, t);
×
646
}
647

648

649
/*
650
 * Precheck: force generation of clauses and other stuff that's
651
 * constructed lazily by the solvers. For example, this
652
 * can be used to convert all the constraints asserted in the
653
 * bitvector to clauses so that we can export the result to DIMACS.
654
 *
655
 * If ctx status is IDLE:
656
 * - the function calls 'start_search' and does one round of propagation.
657
 * - if this results in UNSAT, the function returns UNSAT
658
 * - if the precheck is interrupted, the function returns INTERRUPTED
659
 * - otherwise the function returns UNKNOWN and sets the status to
660
 *   UNKNOWN.
661
 *
662
 * IMPORTANT: call smt_clear or smt_cleanup to restore the context to
663
 * IDLE before doing anything else with this context.
664
 *
665
 * If ctx status is not IDLE, the function returns it and does nothing
666
 * else.
667
 */
668
smt_status_t precheck_context(context_t *ctx) {
×
669
  smt_status_t stat;
670
  smt_core_t *core;
671

672
  core = ctx->core;
×
673

674
  stat = smt_status(core);
×
675
  if (stat == STATUS_IDLE) {
×
676
    start_search(core, 0, NULL);
×
677
    smt_process(core);
×
678
    stat = smt_status(core);
×
679

680
    assert(stat == STATUS_UNSAT || stat == STATUS_SEARCHING ||
681
           stat == YICES_STATUS_INTERRUPTED);
682

683
    if (stat == STATUS_SEARCHING) {
×
684
      end_search_unknown(core);
×
685
      stat = STATUS_UNKNOWN;
×
686
    }
687
  }
688

689
  return stat;
×
690
}
691

692

693

694
/*
695
 * Solve using another SAT solver
696
 * - sat_solver = name of the solver to use
697
 * - verbosity = verbosity level (0 means quiet)
698
 * - this may be used only for BV or pure SAT problems
699
 * - we perform one round of propagation to convert the problem to CNF
700
 * - then we call an external SAT solver on the CNF problem
701
 */
702
smt_status_t check_with_delegate(context_t *ctx, const char *sat_solver, uint32_t verbosity) {
×
703
  smt_status_t stat;
704
  smt_core_t *core;
705
  delegate_t delegate;
706
  bvar_t x;
707
  bval_t v;
708

709
  core = ctx->core;
×
710

711
  stat = smt_status(core);
×
712
  if (stat == STATUS_IDLE) {
×
713
    start_search(core, 0, NULL);
×
714
    smt_process(core);
×
715
    stat = smt_status(core);
×
716

717
    assert(stat == STATUS_UNSAT || stat == STATUS_SEARCHING ||
718
           stat == YICES_STATUS_INTERRUPTED);
719

720
    if (stat == STATUS_SEARCHING) {
×
721
      if (smt_easy_sat(core)) {
×
722
        stat = STATUS_SAT;
×
723
      } else {
724
        // call the delegate
725
        init_delegate(&delegate, sat_solver, num_vars(core));
×
726
        delegate_set_verbosity(&delegate, verbosity);
×
727

728
        stat = solve_with_delegate(&delegate, core);
×
729
        set_smt_status(core, stat);
×
730
        if (stat == STATUS_SAT) {
×
731
          for (x=0; x<num_vars(core); x++) {
×
732
            v = delegate_get_value(&delegate, x);
×
733
            set_bvar_value(core, x, v);
×
734
          }
735
        }
736
        delete_delegate(&delegate);
×
737
      }
738
    }
739
  }
740

741
  return stat;
×
742
}
743

744

745
/*
746
 * Bit-blast then export to DIMACS
747
 * - filename = name of the output file
748
 * - status = status of the context after bit-blasting
749
 *
750
 * If ctx status is IDLE
751
 * - perform one round of propagation to conver the problem to CNF
752
 * - export the CNF to DIMACS
753
 *
754
 * If ctx status is not IDLE,
755
 * - store the stauts in *status and do nothing else
756
 *
757
 * Return code:
758
 *  1 if the DIMACS file was created
759
 *  0 if the problem was solved by the propagation round
760
 * -1 if there was an error in creating or writing to the file.
761
 */
762
int32_t bitblast_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
763
  smt_core_t *core;
764
  FILE *f;
765
  smt_status_t stat;
766
  int32_t code;
767

768
  core = ctx->core;
×
769

770
  code = 0;
×
771
  stat = smt_status(core);
×
772
  if (stat == STATUS_IDLE) {
×
773
    start_search(core, 0, NULL);
×
774
    smt_process(core);
×
775
    stat = smt_status(core);
×
776

777
    assert(stat == STATUS_UNSAT || stat == STATUS_SEARCHING ||
778
           stat == YICES_STATUS_INTERRUPTED);
779

780
    if (stat == STATUS_SEARCHING) {
×
781
      code = 1;
×
782
      f = fopen(filename, "w");
×
783
      if (f == NULL) {
×
784
        code = -1;
×
785
      } else {
786
        dimacs_print_bvcontext(f, ctx);
×
787
        if (ferror(f)) code = -1;
×
788
        fclose(f);
×
789
      }
790
    }
791
  }
792

793
  *status = stat;
×
794

795
  return code;
×
796
}
797

798

799
/*
800
 * Simplify then export to Dimacs:
801
 * - filename = name of the output file
802
 * - status = status of the context after CNF conversion + preprocessing
803
 *
804
 * If ctx status is IDLE
805
 * - perform one round of propagation to convert the problem to CNF
806
 * - export the CNF to y2sat for extra preprocessing then export that to DIMACS
807
 *
808
 * If ctx status is not IDLE, the function stores that in *status
809
 * If y2sat preprocessing solves the formula, return the status also in *status
810
 *
811
 * Return code:
812
 *  1 if the DIMACS file was created
813
 *  0 if the problems was solved by preprocessing (or if ctx status is not IDLE)
814
 * -1 if there was an error creating or writing to the file.
815
 */
816
int32_t process_then_export_to_dimacs(context_t *ctx, const char *filename, smt_status_t *status) {
×
817
  smt_core_t *core;
818
  FILE *f;
819
  smt_status_t stat;
820
  delegate_t delegate;
821
  bvar_t x;
822
  bval_t v;
823
  int32_t code;
824

825
  core = ctx->core;
×
826

827
  code = 0;
×
828
  stat = smt_status(core);
×
829
  if (stat == STATUS_IDLE) {
×
830
    start_search(core, 0, NULL);
×
831
    smt_process(core);
×
832
    stat = smt_status(core);
×
833

834
    assert(stat == STATUS_UNSAT || stat == STATUS_SEARCHING ||
835
           stat == YICES_STATUS_INTERRUPTED);
836

837
    if (stat == STATUS_SEARCHING) {
×
838
      if (smt_easy_sat(core)) {
×
839
        stat = STATUS_SAT;
×
840
      } else {
841
        // call the delegate
842
        init_delegate(&delegate, "y2sat", num_vars(core));
×
843
        delegate_set_verbosity(&delegate, 0);
×
844

845
        stat = preprocess_with_delegate(&delegate, core);
×
846
        set_smt_status(core, stat);
×
847
        if (stat == STATUS_SAT) {
×
848
          for (x=0; x<num_vars(core); x++) {
×
849
            v = delegate_get_value(&delegate, x);
×
850
            set_bvar_value(core, x, v);
×
851
          }
852
        } else if (stat == STATUS_UNKNOWN) {
×
853
          code = 1;
×
854
          f = fopen(filename, "w");
×
855
          if (f == NULL) {
×
856
            code = -1;
×
857
          } else {
858
            export_to_dimacs_with_delegate(&delegate, f);
×
859
            if (ferror(f)) code = -1;
×
860
            fclose(f);
×
861
          }
862
        }
863

864
        delete_delegate(&delegate);
×
865
      }
866
    }
867
  }
868

869
  *status = stat;
×
870

871
  return code;
×
872
}
873

874

875

876
/*
877
 * MODEL CONSTRUCTION
878
 */
879

880
/*
881
 * Value of literal l in ctx->core
882
 */
883
static value_t bool_value(context_t *ctx, value_table_t *vtbl, literal_t l) {
65,201✔
884
  value_t v;
885

886
  v = null_value; // prevent GCC warning
65,201✔
887
  switch (literal_value(ctx->core, l)) {
65,201✔
888
  case VAL_FALSE:
38,577✔
889
    v = vtbl_mk_false(vtbl);
38,577✔
890
    break;
38,577✔
891
  case VAL_UNDEF_FALSE:
×
892
  case VAL_UNDEF_TRUE:
893
    v = vtbl_mk_unknown(vtbl);
×
894
    break;
×
895
  case VAL_TRUE:
26,624✔
896
    v = vtbl_mk_true(vtbl);
26,624✔
897
    break;
26,624✔
898
  }
899
  return v;
65,201✔
900
}
901

902

903
/*
904
 * Value of arithmetic variable x in ctx->arith_solver
905
 */
906
static value_t arith_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
2,589✔
907
  rational_t *a;
908
  value_t v;
909

910
  assert(context_has_arith_solver(ctx));
911

912
  a = &ctx->aux;
2,589✔
913
  if (ctx->arith.value_in_model(ctx->arith_solver, x, a)) {
2,589✔
914
    v = vtbl_mk_rational(vtbl, a);
2,589✔
915
  } else {
916
    v = vtbl_mk_unknown(vtbl);
×
917
  }
918

919
  return v;
2,589✔
920
}
921

922

923

924
/*
925
 * Value of bitvector variable x in ctx->bv_solver
926
 */
927
static value_t bv_value(context_t *ctx, value_table_t *vtbl, thvar_t x) {
18,133✔
928
  bvconstant_t *b;
929
  value_t v;
930

931
  assert(context_has_bv_solver(ctx));
932

933
  b = &ctx->bv_buffer;
18,133✔
934
  if (ctx->bv.value_in_model(ctx->bv_solver, x, b)) {
18,133✔
935
    v = vtbl_mk_bv_from_constant(vtbl, b);
18,133✔
936
  } else {
937
    v = vtbl_mk_unknown(vtbl);
×
938
  }
939

940
  return v;
18,133✔
941
}
942

943

944
/*
945
 * Get a value for term t in the solvers or egraph
946
 * - attach the mapping from t to that value in model
947
 * - if we don't have a concrete object for t but t is
948
 *   mapped to a term u and the model->has_alias is true,
949
 *   then we store the mapping [t --> u] in the model's
950
 *   alias map.
951
 */
952
static void build_term_value(context_t *ctx, model_t *model, term_t t) {
279,771✔
953
  value_table_t *vtbl;
954
  term_t r;
955
  uint32_t polarity;
956
  int32_t x;
957
  type_t tau;
958
  value_t v;
959

960
  /*
961
   * Get the root of t in the substitution table
962
   */
963
  r = intern_tbl_get_root(&ctx->intern, t);
279,771✔
964
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
279,771✔
965
    /*
966
     * r is mapped to some object x in egraph/core/or theory solvers
967
     * - keep track of polarity then force r to positive polarity
968
     */
969
    vtbl = model_get_vtbl(model);
90,693✔
970
    polarity = polarity_of(r);
90,693✔
971
    r = unsigned_term(r);
90,693✔
972

973
    /*
974
     * Convert x to a concrete value
975
     */
976
    x = intern_tbl_map_of_root(&ctx->intern, r);
90,693✔
977
    if (code_is_eterm(x)) {
90,693✔
978
      // x refers to an egraph object or true_occ/false_occ
979
      if (x == bool2code(true)) {
4,770✔
980
        v = vtbl_mk_true(vtbl);
475✔
981
      } else if (x == bool2code(false)) {
4,295✔
982
        v = vtbl_mk_false(vtbl);
1,420✔
983
      } else {
984
        assert(context_has_egraph(ctx));
985
        v = egraph_get_value(ctx->egraph, vtbl, code2occ(x));
2,875✔
986
      }
987

988
    } else {
989
      // x refers to a literal or a theory variable
990
      tau = term_type(ctx->terms, r);
85,923✔
991
      switch (type_kind(ctx->types, tau)) {
85,923✔
992
      case BOOL_TYPE:
65,201✔
993
        v = bool_value(ctx, vtbl, code2literal(x));
65,201✔
994
        break;
65,201✔
995

996
      case INT_TYPE:
2,589✔
997
      case REAL_TYPE:
998
        v = arith_value(ctx, vtbl, code2thvar(x));
2,589✔
999
        break;
2,589✔
1000

1001
      case BITVECTOR_TYPE:
18,133✔
1002
        v = bv_value(ctx, vtbl, code2thvar(x));
18,133✔
1003
        break;
18,133✔
1004

1005
      default:
×
1006
        /*
1007
         * This should never happen:
1008
         * scalar, uninterpreted, tuple, function terms
1009
         * are mapped to egraph terms.
1010
         */
1011
        assert(false);
1012
        v = vtbl_mk_unknown(vtbl); // prevent GCC warning
×
1013
        break;
×
1014
      }
1015
    }
1016

1017
    /*
1018
     * Restore polarity then add mapping [t --> v] in the model
1019
     */
1020
    if (! object_is_unknown(vtbl, v)) {
90,693✔
1021
      if (object_is_boolean(vtbl, v)) {
90,693✔
1022
        if (polarity) {
67,096✔
1023
          // negate the value
1024
          v = vtbl_mk_not(vtbl, v);
24✔
1025
        }
1026
      }
1027
      model_map_term(model, t, v);
90,693✔
1028
    }
1029

1030
  } else {
1031
    /*
1032
     * r is not mapped to anything:
1033
     *
1034
     * 1) If t == r and t is present in the internalization table
1035
     *    then t is relevant. So we should display its value
1036
     *    when we print the model. To do this, we assign an
1037
     *    arbitrary value v to t and store [t := v] in the map.
1038
     *
1039
     * 2) If t != r then we keep the mapping [t --> r] in
1040
     *    the alias table (provided the model supports aliases).
1041
     */
1042
    if (t == r) {
189,078✔
1043
      if (intern_tbl_term_present(&ctx->intern, t)) {
188,430✔
1044
        tau = term_type(ctx->terms, t);
×
1045
        vtbl = model_get_vtbl(model);
×
1046
        v = vtbl_make_object(vtbl, tau);
×
1047
        model_map_term(model, t, v);
×
1048
      }
1049
    } else if (model->has_alias) {
648✔
1050
      // t != r: keep the substitution [t --> r] in the model
1051
      model_add_substitution(model, t, r);
648✔
1052
    }
1053
  }
1054
}
279,771✔
1055

1056

1057

1058

1059
/*
1060
 * Build a model for the current context (including all satellite solvers)
1061
 * - the context status must be SAT (or UNKNOWN)
1062
 * - if model->has_alias is true, we store the term substitution
1063
 *   defined by ctx->intern_tbl into the model
1064
 * - cleanup of satellite models needed using clean_solver_models()
1065
 */
1066
void build_model(model_t *model, context_t *ctx) {
22,112✔
1067
  term_table_t *terms;
1068
  uint32_t i, n;
1069
  term_t t;
1070

1071
  assert(smt_status(ctx->core) == STATUS_SAT || smt_status(ctx->core) == STATUS_UNKNOWN || mcsat_status(ctx->mcsat) == STATUS_SAT);
1072

1073
  /*
1074
   * First build assignments in the satellite solvers
1075
   * and get the val_in_model functions for the egraph
1076
   */
1077
  if (context_has_arith_solver(ctx)) {
22,112✔
1078
    ctx->arith.build_model(ctx->arith_solver);
12,904✔
1079
  }
1080
  if (context_has_bv_solver(ctx)) {
22,112✔
1081
    ctx->bv.build_model(ctx->bv_solver);
21,399✔
1082
  }
1083

1084
  /*
1085
   * Construct the egraph model
1086
   */
1087
  if (context_has_egraph(ctx)) {
22,112✔
1088
    egraph_build_model(ctx->egraph, model_get_vtbl(model));
13,032✔
1089
  }
1090

1091
  /*
1092
   * Construct the mcsat model.
1093
   */
1094
  if (context_has_mcsat(ctx)) {
22,112✔
1095
    mcsat_build_model(ctx->mcsat, model);
23✔
1096
  }
1097

1098
  // scan the internalization table
1099
  terms = ctx->terms;
22,112✔
1100
  n = intern_tbl_num_terms(&ctx->intern);
22,112✔
1101
  for (i=1; i<n; i++) { // first real term has index 1 (i.e. true_term)
84,613,251✔
1102
    if (good_term_idx(terms, i)) {
84,591,139✔
1103
      t = pos_occ(i);
84,591,139✔
1104
      if (term_kind(terms, t) == UNINTERPRETED_TERM) {
84,591,139✔
1105
        build_term_value(ctx, model, t);
279,771✔
1106
      }
1107
    }
1108
  }
1109
}
22,112✔
1110

1111

1112
/*
1113
 * Cleanup solver models
1114
 */
1115
void clean_solver_models(context_t *ctx) {
22,112✔
1116
  if (context_has_arith_solver(ctx)) {
22,112✔
1117
    ctx->arith.free_model(ctx->arith_solver);
12,904✔
1118
  }
1119
  if (context_has_bv_solver(ctx)) {
22,112✔
1120
    ctx->bv.free_model(ctx->bv_solver);
21,399✔
1121
  }
1122
  if (context_has_egraph(ctx)) {
22,112✔
1123
    egraph_free_model(ctx->egraph);
13,032✔
1124
  }
1125
}
22,112✔
1126

1127

1128

1129
/*
1130
 * Build a model for the current context
1131
 * - the context status must be SAT (or UNKNOWN)
1132
 * - if model->has_alias is true, we store the term substitution
1133
 *   defined by ctx->intern_tbl into the model
1134
 */
1135
void context_build_model(model_t *model, context_t *ctx) {
212✔
1136
  // Build solver models and term values
1137
  build_model(model, ctx);
212✔
1138

1139
  // Cleanup
1140
  clean_solver_models(ctx);
212✔
1141
}
212✔
1142

1143

1144

1145
/*
1146
 * Read the value of a Boolean term t
1147
 * - return VAL_TRUE/VAL_FALSE or VAL_UNDEF_FALSE/VAL_UNDEF_TRUE if t's value is not known
1148
 */
1149
bval_t context_bool_term_value(context_t *ctx, term_t t) {
×
1150
  term_t r;
1151
  uint32_t polarity;
1152
  int32_t x;
1153
  bval_t v;
1154

1155
  assert(is_boolean_term(ctx->terms, t));
1156

1157
  // default value if t is not in the internalization table
1158
  v = VAL_UNDEF_FALSE;
×
1159
  r = intern_tbl_get_root(&ctx->intern, t);
×
1160
  if (intern_tbl_root_is_mapped(&ctx->intern, r)) {
×
1161
    // r is mapped to some object x
1162
    polarity = polarity_of(r);
×
1163
    r = unsigned_term(r);
×
1164

1165
    x  = intern_tbl_map_of_root(&ctx->intern, r);
×
1166
    if (code_is_eterm(x)) {
×
1167
      // x must be either true_occ or false_occ
1168
      if (x == bool2code(true)) {
×
1169
        v = VAL_TRUE;
×
1170
      } else {
1171
        assert(x == bool2code(false));
1172
        v = VAL_FALSE;
×
1173
      }
1174
    } else {
1175
      // x refers to a literal in the smt core
1176
      v = literal_value(ctx->core, code2literal(x));
×
1177
    }
1178

1179
    // negate v if polarity is 1 (cf. smt_core_base_types.h)
1180
    v ^= polarity;
×
1181
  }
1182

1183
  return v;
×
1184
}
1185

1186

1187
/*
1188
 * UNSAT CORE
1189
 */
1190

1191
/*
1192
 * Build an unsat core:
1193
 * - store the result in v
1194
 * - if there are no assumptions, return an empty core
1195
 */
1196
void context_build_unsat_core(context_t *ctx, ivector_t *v) {
3,755✔
1197
  smt_core_t *core;
1198
  uint32_t i, n;
1199
  term_t t;
1200

1201
  core = ctx->core;
3,755✔
1202
  assert(core != NULL && core->status == STATUS_UNSAT);
1203
  build_unsat_core(core, v);
3,755✔
1204

1205
  // convert from literals to terms
1206
  n = v->size;
3,755✔
1207
  for (i=0; i<n; i++) {
49,374✔
1208
    t = assumption_term_for_literal(&ctx->assumptions, v->data[i]);
45,619✔
1209
    assert(t >= 0);
1210
    v->data[i] = t;
45,619✔
1211
  }
1212
}
3,755✔
1213

1214

1215
/*
1216
 * MODEL INTERPOLANT
1217
 */
1218
term_t context_get_unsat_model_interpolant(context_t *ctx) {
45✔
1219
  assert(ctx->mcsat != NULL);
1220
  return mcsat_get_unsat_model_interpolant(ctx->mcsat);
45✔
1221
}
1222

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

© 2025 Coveralls, Inc