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

SRI-CSL / yices2 / 25574532210

08 May 2026 07:12PM UTC coverage: 67.254% (+0.03%) from 67.22%
25574532210

push

github

web-flow
Merge pull request #607 from SRI-CSL/context_delegates

QF_BV context delegates (#453): config/param selection, incremental state, assumptions, and delegate regressions

84 of 307 new or added lines in 7 files covered. (27.36%)

4 existing lines in 3 files now uncovered.

85205 of 126691 relevant lines covered (67.25%)

1626652.44 hits per line

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

5.84
/src/solvers/cdcl/delegate.c
1
/*
2
 * This file is part of the Yices SMT Solver.
3
 * Copyright (C) 2018 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
#include <assert.h>
20
#include <string.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23

24
#ifdef HAVE_CADICAL
25
#include "ccadical.h"
26
#endif
27

28
#ifdef HAVE_CRYPTOMINISAT
29
#include "cryptominisat5/cmsat_c.h"
30
#endif
31

32
#ifdef HAVE_KISSAT
33
#include "kissat.h"
34
#endif
35

36
#include "solvers/cdcl/delegate.h"
37
#include "solvers/cdcl/new_sat_solver.h"
38
#include "utils/memalloc.h"
39

40

41

42
/*
43
 * WRAPPERS FOR THE YICES SAT_SOLVER
44
 */
45
static void ysat_add_empty_clause(void *solver) {
×
46
  nsat_solver_simplify_and_add_clause(solver, 0, NULL);
×
47
}
×
48

49
static void ysat_add_unit_clause(void *solver, literal_t l) {
×
50
  nsat_solver_simplify_and_add_clause(solver, 1, &l);
×
51
}
×
52

53
static void ysat_add_binary_clause(void *solver, literal_t l1, literal_t l2) {
×
54
  literal_t a[2];
55

56
  a[0] = l1;
×
57
  a[1] = l2;
×
58
  nsat_solver_simplify_and_add_clause(solver, 2, a);
×
59
}
×
60

61
static void ysat_add_ternary_clause(void *solver, literal_t l1, literal_t l2, literal_t l3) {
×
62
  literal_t a[3];
63

64
  a[0] = l1;
×
65
  a[1] = l2;
×
66
  a[2] = l3;
×
67
  nsat_solver_simplify_and_add_clause(solver, 3, a);
×
68
}
×
69

70
static void ysat_add_clause(void *solver, uint32_t n, literal_t *a) {
×
71
  nsat_solver_simplify_and_add_clause(solver, n, a);
×
72
}
×
73

74
static smt_status_t ysat_check(void *solver) {
×
75
  // use new sat solver
76
  switch (nsat_solve(solver)) {
×
77
  case STAT_SAT: return YICES_STATUS_SAT;
×
78
  case STAT_UNSAT: return YICES_STATUS_UNSAT;
×
79
  default: return YICES_STATUS_UNKNOWN;
×
80
  }
81
}
82

83
static smt_status_t ysat_preprocess(void *solver) {
×
84
  // use new sat solver
85
  switch (nsat_apply_preprocessing(solver)) {
×
86
  case STAT_SAT: return YICES_STATUS_SAT;
×
87
  case STAT_UNSAT: return YICES_STATUS_UNSAT;
×
88
  default: return YICES_STATUS_UNKNOWN;
×
89
  }
90
}
91

92
static void ysat_export_to_dimacs(void *solver, FILE *f) {
×
93
  nsat_export_to_dimacs(f, solver);
×
94
}
×
95

96
static bval_t ysat_get_value(void *solver, bvar_t x) {
×
97
  return var_value(solver, x);
×
98
}
99

100
static void ysat_set_verbosity(void *solver, uint32_t level) {
×
101
  nsat_set_verbosity(solver, level);
×
102
}
×
103

NEW
104
static void ysat_add_vars(void *solver, uint32_t n) {
×
NEW
105
  nsat_solver_add_vars(solver, n);
×
NEW
106
}
×
107

108
static void ysat_delete(void *solver) {
×
109
  delete_nsat_solver(solver);
×
110
  safe_free(solver);
×
111
}
×
112

113
#if 0
114
static void ysat_keep_var(void *solver, bvar_t x) {
115
  nsat_solver_keep_var(solver, x);
116
}
117
#endif
118

119
#define USE_CUTS 1
120

121
#if USE_CUTS
122
static void ysat_var_def2(void *solver, bvar_t x, uint32_t b, literal_t l1, literal_t l2) {
×
123
  nsat_solver_add_def2(solver, x, b, l1, l2);
×
124
}
×
125

126
static void ysat_var_def3(void *solver, bvar_t x, uint32_t b, literal_t l1, literal_t l2, literal_t l3) {
×
127
  nsat_solver_add_def3(solver, x, b, l1, l2, l3);
×
128
}
×
129
#endif
130

131
static void ysat_as_delegate(delegate_t *d, uint32_t nvars) {
×
132
  d->solver = (sat_solver_t *) safe_malloc(sizeof(sat_solver_t));
×
133
  init_nsat_solver(d->solver, nvars, true); // with preprocessing
×
134
  // init_nsat_solver(d->solver, nvars, false); // without preprocessing
135
  nsat_set_randomness(d->solver, 0.01);
×
136
  nsat_set_reduce_fraction(d->solver, 12);
×
137
  nsat_set_res_clause_limit(d->solver, 300);   // more agressive var elimination
×
138
  nsat_set_res_extra(d->solver, 20);
×
139
  nsat_set_simplify_subst_delta(d->solver, 30);
×
140
  nsat_solver_add_vars(d->solver, nvars);
×
141
  //
142
  init_ivector(&d->buffer, 0);
×
143
  d->add_empty_clause = ysat_add_empty_clause;
×
144
  d->add_unit_clause = ysat_add_unit_clause;
×
145
  d->add_binary_clause = ysat_add_binary_clause;
×
146
  d->add_ternary_clause = ysat_add_ternary_clause;
×
147
  d->add_clause = ysat_add_clause;
×
148
  d->check = ysat_check;
×
NEW
149
  d->check_assuming = NULL;
×
NEW
150
  d->collect_failed_assumptions = NULL;
×
151
  d->get_value = ysat_get_value;
×
152
  d->set_verbosity = ysat_set_verbosity;
×
153
  d->delete = ysat_delete;
×
NEW
154
  d->add_vars = ysat_add_vars;
×
155

156
  // experimental
157
  //  d->keep_var = ysat_keep_var;
158
  d->keep_var = NULL; // don't use
×
159

160
#if USE_CUTS
161
  // with cut enumeration
162
  d->var_def2 = ysat_var_def2;
×
163
  d->var_def3 = ysat_var_def3;
×
164
#else
165
  // without
166
  d->var_def2 = NULL;
167
  d->var_def3 = NULL;
168
#endif
169
  // more experimental functions
170
  d->preprocess = ysat_preprocess;
×
171
  d->export = ysat_export_to_dimacs;
×
172
}
×
173

174

175
#if HAVE_CADICAL || HAVE_KISSAT
176
/*
177
 * Conversion from literal_t to dimacs:
178
 * - in Yices, variables are indexed from 0 to nvars-1.
179
 *   variable x has two literals: pos_lit(x) = 2x and neg_lit(x) = 2x + 1
180
 *   variable 0 is special: pos_lit(0) is true_literal, neg_lit(0) is false_literal.
181
 * - in Dimacs, variables are indexed from 1 to nvars
182
 *   variable x has two literal: pos_lit(x) = +x and neg_lit(x) = -x
183
 *   0 is a terminator (end of clause).
184
 */
185
static inline int lit2dimacs(literal_t l) {
186
  int x = var_of(l) + 1;
187
  return is_pos(l) ? x : - x;
188
}
189
#endif
190

191
/*
192
 * WRAPPERS FOR CADICAL
193
 */
194

195
#if HAVE_CADICAL
196
static void cadical_add_empty_clause(void *solver) {
197
  ccadical_add(solver, 0);
198
}
199

200
static void cadical_add_unit_clause(void *solver, literal_t l) {
201
  ccadical_add(solver, lit2dimacs(l));
202
  ccadical_add(solver, 0);
203
}
204

205
static void cadical_add_binary_clause(void *solver, literal_t l1, literal_t l2) {
206
  ccadical_add(solver, lit2dimacs(l1));
207
  ccadical_add(solver, lit2dimacs(l2));
208
  ccadical_add(solver, 0);
209
}
210

211
static void cadical_add_ternary_clause(void *solver, literal_t l1, literal_t l2, literal_t l3) {
212
  ccadical_add(solver, lit2dimacs(l1));
213
  ccadical_add(solver, lit2dimacs(l2));
214
  ccadical_add(solver, lit2dimacs(l3));
215
  ccadical_add(solver, 0);
216
}
217

218
static void cadical_add_clause(void *solver, uint32_t n, literal_t *a) {
219
  uint32_t i;
220

221
  for (i=0; i<n; i++) {
222
    ccadical_add(solver, lit2dimacs(a[i]));
223
  }
224
  ccadical_add(solver, 0);
225
}
226

227
static smt_status_t cadical_check(void *solver) {
228
  switch (ccadical_sat(solver)) {
229
  case 10: return YICES_STATUS_SAT;
230
  case 20: return YICES_STATUS_UNSAT;
231
  default: return YICES_STATUS_UNKNOWN;
232
  }
233
}
234

235
static smt_status_t cadical_check_assuming(void *solver, uint32_t n, const literal_t *a) {
236
  uint32_t i;
237

238
  for (i=0; i<n; i++) {
239
    ccadical_assume(solver, lit2dimacs(a[i]));
240
  }
241
  return cadical_check(solver);
242
}
243

244
static void cadical_collect_failed_assumptions(void *solver, uint32_t n, const literal_t *a, ivector_t *out) {
245
  uint32_t i;
246

247
  for (i=0; i<n; i++) {
248
    if (ccadical_failed(solver, lit2dimacs(a[i])) != 0) {
249
      ivector_push(out, a[i]);
250
    }
251
  }
252
}
253

254

255
/*
256
 * Important: the rest of Yices (including the bit-vector solver)
257
 * assumes that the backend SAT solver assign a value to all variables.
258
 * cadical does not do this. It may return that variable x has
259
 * value "unknown". This means that 'x' does not occur in any clause
260
 * sent to cadical.
261
 * We convert  unknown to VAL_FALSE here.
262
 */
263
static bval_t cadical_get_value(void *solver, bvar_t x) {
264
  int v;
265

266
  v = ccadical_deref(solver, x + 1); // x+1 = variable in cadical = positive literal
267
  // v = value assigned in cadical: -1 means false, +1 means true, 0 means unknown
268

269
  return (v <= 0) ? VAL_FALSE : VAL_TRUE;
270
}
271

272
static void cadical_set_verbosity(void *solver, uint32_t level) {
273
  // verbosity 0 --> nothing (quiet = true)
274
  // verbosity 1 --> normal cadical output (quiet = false)
275
  // verbosity 2 --> cadical verbosity 1
276
  // verbosity 3 --> cadical verbosity 2
277
  //
278
  // With cadical 1.2.0:
279
  // - we must set option 'report' to true otherwise
280
  //   nothing is printed at verbosity level < 2
281
  // 
282
  if (level == 0) {
283
    ccadical_set_option(solver, "quiet", 1);
284
  } else {
285
    ccadical_set_option(solver, "quiet", 0);
286
    ccadical_set_option(solver, "report", 1);
287
    if (level == 2) {
288
      ccadical_set_option(solver, "verbose", 1);
289
    } else if (level >= 3) {
290
      ccadical_set_option(solver, "verbose", 2);
291
    }
292
  }
293
}
294

295
static void cadical_delete(void *solver) {
296
  ccadical_reset(solver);
297
}
298

299
static void cadical_add_vars(void *solver, uint32_t n) {
300
  if (n > 0) {
301
    ccadical_declare_more_variables(solver, (int32_t) n);
302
  }
303
}
304

305
static void cadical_as_delegate(delegate_t *d, uint32_t nvars) {
306
  d->solver = ccadical_init();
307
  ccadical_set_option(d->solver, "quiet", 1); // no output from cadical by default
308
  init_ivector(&d->buffer, 0); // not used
309

310
  // fine tuning
311
  ccadical_set_option(d->solver, "walk", 0);
312
  ccadical_set_option(d->solver, "lucky", 0);
313
  ccadical_set_option(d->solver, "chrono", 0);
314
  ccadical_set_option(d->solver, "elimands", 0);
315
  ccadical_set_option(d->solver, "elimites", 0);
316
  ccadical_set_option(d->solver, "elimxors", 0);
317
  // end of fine tuning
318

319
  cadical_add_vars(d->solver, nvars);
320
  d->add_empty_clause = cadical_add_empty_clause;
321
  d->add_unit_clause = cadical_add_unit_clause;
322
  d->add_binary_clause = cadical_add_binary_clause;
323
  d->add_ternary_clause = cadical_add_ternary_clause;
324
  d->add_clause = cadical_add_clause;
325
  d->check = cadical_check;
326
  d->check_assuming = cadical_check_assuming;
327
  d->collect_failed_assumptions = cadical_collect_failed_assumptions;
328
  d->get_value = cadical_get_value;
329
  d->set_verbosity = cadical_set_verbosity;
330
  d->delete = cadical_delete;
331
  d->add_vars = cadical_add_vars;
332
  d->keep_var = NULL;
333
  d->var_def2 = NULL;
334
  d->var_def3 = NULL;
335
  d->preprocess = NULL;
336
  d->export = NULL;
337
}
338

339
#endif
340

341

342

343
/*
344
 * WRAPPERS FOR CRYPTOMINISAT
345
 */
346

347
#if HAVE_CRYPTOMINISAT
348
static void cryptominisat_add_empty_clause(void *solver) {
349
  cmsat_add_clause(solver, NULL, 0);
350
}
351

352
static void cryptominisat_add_unit_clause(void *solver, literal_t l) {
353
  uint32_t c[1];
354

355
  assert(l >= 0);
356
  c[0] = l;
357
  cmsat_add_clause(solver, c, 1);
358
}
359

360
static void cryptominisat_add_binary_clause(void *solver, literal_t l1, literal_t l2) {
361
  uint32_t c[2];
362

363
  assert(l1 >= 0 && l2 >= 0);
364
  c[0] = l1;
365
  c[1] = l2;
366
  cmsat_add_clause(solver, c, 2);
367
}
368

369
static void cryptominisat_add_ternary_clause(void *solver, literal_t l1, literal_t l2, literal_t l3) {
370
  uint32_t c[3];
371

372
  assert(l1 >= 0 && l2 >= 0 && l3 >= 0);
373
  c[0] = l1;
374
  c[1] = l2;
375
  c[2] = l3;
376
  cmsat_add_clause(solver, c, 3);
377
}
378

379
static void cryptominisat_add_clause(void *solver, uint32_t n, literal_t *a) {
380
  cmsat_add_clause(solver, (uint32_t*) a, n);
381
}
382

383
static smt_status_t cryptominisat_check(void *solver) {
384
  switch (cmsat_solve(solver)) {
385
  case CMSAT_SAT: return YICES_STATUS_SAT;
386
  case CMSAT_UNSAT: return YICES_STATUS_UNSAT;
387
  default: return YICES_STATUS_UNKNOWN;
388
  }
389
}
390

391
static smt_status_t cryptominisat_check_assuming(void *solver, uint32_t n, const literal_t *a) {
392
  switch (cmsat_solve_with_assumptions(solver, (uint32_t *) a, n)) {
393
  case CMSAT_SAT: return YICES_STATUS_SAT;
394
  case CMSAT_UNSAT: return YICES_STATUS_UNSAT;
395
  default: return YICES_STATUS_UNKNOWN;
396
  }
397
}
398

399
static void cryptominisat_collect_failed_assumptions(void *solver, uint32_t n, const literal_t *a, ivector_t *out) {
400
  cmsat_lit_vector_t conflict;
401
  uint32_t i, j;
402
  literal_t lit, neg_lit, c;
403

404
  conflict.lit = NULL;
405
  conflict.nlits = 0;
406
  cmsat_get_conflict(solver, &conflict);
407

408
  /*
409
   * CryptoMiniSat may return assumptions in negated form.
410
   * Normalize to Yices assumption literals so callers can map back cleanly.
411
   */
412
  for (i=0; i<n; i++) {
413
    lit = a[i];
414
    neg_lit = lit ^ 1;
415
    for (j=0; j<conflict.nlits; j++) {
416
      c = (literal_t) conflict.lit[j];
417
      if (c == lit || c == neg_lit) {
418
        ivector_push(out, lit);
419
        break;
420
      }
421
    }
422
  }
423

424
  if (conflict.lit != NULL) {
425
    /*
426
     * The supported CryptoMiniSat C API allocates this vector with malloc
427
     * and does not provide a vector-specific deallocator.
428
     */
429
    free(conflict.lit);
430
  }
431
}
432

433

434
/*
435
 * We convert  unknown to VAL_FALSE here to be safe, but it seems
436
 * that cryptominisat always produces a full truth assignment.
437
 */
438
static bval_t cryptominisat_get_value(void *solver, bvar_t x) {
439
  switch (cmsat_var_value(solver, x)) {
440
  case CMSAT_VAL_TRUE:
441
    return VAL_TRUE;
442

443
  case CMSAT_VAL_FALSE:
444
  default:
445
    return VAL_FALSE;
446
  }
447
}
448

449
static void cryptominisat_set_verbosity(void *solver, uint32_t level) {
450
  // verbosity 0 --> quiet (this is the default)
451
  cmsat_set_verbosity(solver, level);
452
}
453

454
static void cryptominisat_delete(void *solver) {
455
  cmsat_free_solver(solver);
456
}
457

458
static void cryptominisat_add_vars(void *solver, uint32_t n) {
459
  if (n > 0) {
460
    cmsat_new_vars(solver, n);
461
  }
462
}
463

464
static void cryptominisat_as_delegate(delegate_t *d, uint32_t nvars) {
465
  d->solver = cmsat_new_solver();
466
  cryptominisat_add_vars(d->solver, nvars);
467
  init_ivector(&d->buffer, 0); // not used
468
  d->add_empty_clause = cryptominisat_add_empty_clause;
469
  d->add_unit_clause = cryptominisat_add_unit_clause;
470
  d->add_binary_clause = cryptominisat_add_binary_clause;
471
  d->add_ternary_clause = cryptominisat_add_ternary_clause;
472
  d->add_clause = cryptominisat_add_clause;
473
  d->check = cryptominisat_check;
474
  d->check_assuming = cryptominisat_check_assuming;
475
  d->collect_failed_assumptions = cryptominisat_collect_failed_assumptions;
476
  d->get_value = cryptominisat_get_value;
477
  d->set_verbosity = cryptominisat_set_verbosity;
478
  d->delete = cryptominisat_delete;
479
  d->add_vars = cryptominisat_add_vars;
480
  d->keep_var = NULL;
481
  d->var_def2 = NULL;
482
  d->var_def3 = NULL;
483
  d->preprocess = NULL;
484
  d->export = NULL;
485
}
486

487
#endif
488

489

490
/*
491
 * WRAPPERS FOR KISSAT
492
 */
493
#if HAVE_KISSAT
494
static void kissat_add_empty_clause(void *solver) {
495
  kissat_add(solver, 0);
496
}
497

498
static void kissat_add_unit_clause(void *solver, literal_t l) {
499
  kissat_add(solver, lit2dimacs(l));
500
  kissat_add(solver, 0);
501
}
502

503
static void kissat_add_binary_clause(void *solver, literal_t l1, literal_t l2) {
504
  kissat_add(solver, lit2dimacs(l1));
505
  kissat_add(solver, lit2dimacs(l2));
506
  kissat_add(solver, 0);
507
}
508

509
static void kissat_add_ternary_clause(void *solver, literal_t l1, literal_t l2, literal_t l3) {
510
  kissat_add(solver, lit2dimacs(l1));
511
  kissat_add(solver, lit2dimacs(l2));
512
  kissat_add(solver, lit2dimacs(l3));
513
  kissat_add(solver, 0);
514
}
515

516
static void kissat_add_clause(void *solver, uint32_t n, literal_t *a) {
517
  uint32_t i;
518

519
  for (i=0; i<n; i++) {
520
    kissat_add(solver, lit2dimacs(a[i]));
521
  }
522
  kissat_add(solver, 0);
523
}
524

525
static smt_status_t kissat_check(void *solver) {
526
  switch (kissat_solve(solver)) {
527
  case 10: return YICES_STATUS_SAT;
528
  case 20: return YICES_STATUS_UNSAT;
529
  default: return YICES_STATUS_UNKNOWN;
530
  }
531
}
532

533

534
/*
535
 * Important: the rest of Yices (including the bit-vector solver)
536
 * assumes that the backend SAT solver assign a value to all variables.
537
 * kissat does not do this. It may return that variable x has
538
 * value "unknown". This means that 'x' does not occur in any clause
539
 * sent to kissat.
540
 * We convert  unknown to VAL_FALSE here.
541
 */
542
static bval_t kissat_get_value(void *solver, bvar_t x) {
543
  int v;
544

545
  v = kissat_value(solver, x + 1); // x+1 = variable in kissat = positive literal
546
  // v = value assigned in kissat: -1 means false, +1 means true, 0 means unknown
547

548
  return (v <= 0) ? VAL_FALSE : VAL_TRUE;
549
}
550

551
static void kissat_set_verbosity(void *solver, uint32_t level) {
552
  // verbosity 0 --> nothing (quiet = true)
553
  // verbosity 1 --> normal kissat output (quiet = false)
554
  // verbosity 2 --> kissat verbosity 1
555
  // verbosity 3 --> kissat verbosity 2
556
  if (level == 0) {
557
    kissat_set_option(solver, "quiet", 1);
558
  } else {
559
    kissat_set_option(solver, "quiet", 0);
560
    if (level == 2) {
561
      kissat_set_option(solver, "verbose", 1);
562
    } else if (level >= 3) {
563
      kissat_set_option(solver, "verbose", 2);
564
    }
565
  }
566
}
567

568
static void kissat_delete(void *solver) {
569
  kissat_release(solver);
570
}
571

572
static void kissat_as_delegate(delegate_t *d, uint32_t nvars) {
573
  d->solver = kissat_init();
574
  kissat_set_option(d->solver, "quiet", 1); // no output from kissat by default
575
  init_ivector(&d->buffer, 0); // not used
576
  d->add_empty_clause = kissat_add_empty_clause;
577
  d->add_unit_clause = kissat_add_unit_clause;
578
  d->add_binary_clause = kissat_add_binary_clause;
579
  d->add_ternary_clause = kissat_add_ternary_clause;
580
  d->add_clause = kissat_add_clause;
581
  d->check = kissat_check;
582
  d->check_assuming = NULL;
583
  d->collect_failed_assumptions = NULL;
584
  d->get_value = kissat_get_value;
585
  d->set_verbosity = kissat_set_verbosity;
586
  d->delete = kissat_delete;
587
  d->add_vars = NULL;
588
  d->keep_var = NULL;
589
  d->var_def2 = NULL;
590
  d->var_def3 = NULL;
591
  d->preprocess = NULL;
592
  d->export = NULL;
593
}
594

595
#endif
596

597

598
/*
599
 * Create and initialize a delegate structure
600
 * - solver_name specifies the external solver to use
601
 * - nvars = number of variables
602
 * - return true if that worked, false is the solver_name is not supported
603
 *   or if something else goes wrong.
604
 * - allowed values for solver_name: TBD
605
 */
606
bool init_delegate(delegate_t *d, const char *solver_name, uint32_t nvars) {
×
607
  if (strcmp("y2sat", solver_name) == 0) {
×
608
    ysat_as_delegate(d, nvars);
×
609
    return true;
×
610
#if HAVE_CADICAL
611
  } else if (strcmp("cadical", solver_name) == 0) {
612
    cadical_as_delegate(d, nvars);
613
    return true;
614
#endif
615
#if HAVE_CRYPTOMINISAT
616
  } else if (strcmp("cryptominisat", solver_name) == 0) {
617
    cryptominisat_as_delegate(d, nvars);
618
    return true;
619
#endif
620
#if HAVE_KISSAT
621
  } else if (strcmp("kissat", solver_name) == 0) {
622
    kissat_as_delegate(d, nvars);
623
    return true;
624
#endif
625
  }
626
  return false;
×
627
}
628

629

630

631
/*
632
 * Test whether a solver is known and supported.
633
 * - solver_name = external solver to use
634
 * - return true if this solver is supported (i.e., can be used in init_delegate).
635
 * - return false otherwise.
636
 * - extra information is returned in *unknown:
637
 *   if we don't support the solver at all, *unknown is set to true
638
 *   if we have optional support (but not compiled), *unknown is set to fasle.
639
 */
640
bool supported_delegate(const char *solver_name, bool *unknown) {
28✔
641
  if (strcmp("y2sat", solver_name) == 0) {
28✔
642
    *unknown = false;
23✔
643
    return true;
23✔
644
  }
645

646
  if (strcmp("cadical", solver_name) == 0) {
5✔
647
    *unknown = false;
3✔
648
#if HAVE_CADICAL
649
    return true;
650
#else
651
    return false;
3✔
652
#endif
653
  }
654

655
  if (strcmp("cryptominisat", solver_name) == 0) {
2✔
656
    *unknown = false;
1✔
657
#if HAVE_CRYPTOMINISAT
658
    return true;
659
#else
660
    return false;
1✔
661
#endif
662
  }
663

664
  if (strcmp("kissat", solver_name) == 0) {
1✔
665
    *unknown = false;
1✔
666
#if HAVE_KISSAT
667
    return true;
668
#else
669
    return false;
1✔
670
#endif
671
  }
672

673
  *unknown = true;
×
674
  return false;
×
675
}
676

677
bool incremental_delegate(const char *solver_name) {
2✔
678
  return strcmp("cadical", solver_name) == 0 || strcmp("cryptominisat", solver_name) == 0;
2✔
679
}
680

681

682
/*
683
 * Delete the solver and free memory
684
 */
685
void delete_delegate(delegate_t *d) {
×
686
  d->delete(d->solver);
×
687
  delete_ivector(&d->buffer);
×
688
  d->solver = NULL;
×
689
}
×
690

691

692
/*
693
 * NOTE: the copy functions below assume that literals in the core
694
 * and in the sat_solver use the same encoding:
695
 * - 0 is true_literal
696
 *   1 is false_literal
697
 * - for a boolean variable x:
698
 *     2x     --> positive literal pos_lit(x)
699
 *     2x + 1 --> negative literal neg_lit(x)
700
 *
701
 * This is OK for y2sat.
702
 */
703

704
/*
705
 * Transfer unit clauses from core to delegate
706
 */
NEW
707
static void copy_unit_clauses(delegate_t *d, smt_core_t *core, literal_t g) {
×
708
  prop_stack_t *stack;
709
  uint32_t i, n;
710

NEW
711
  if (g == true_literal) {
×
NEW
712
    d->add_unit_clause(d->solver, true_literal); // CHECK THIS
×
713
  }
714

715
  n = core->nb_unit_clauses;
×
716
  stack = &core->stack;
×
717
  for (i=0; i<n; i++) {
×
NEW
718
    if (g == true_literal) {
×
NEW
719
      d->add_unit_clause(d->solver, stack->lit[i]);
×
720
    } else {
NEW
721
      d->add_binary_clause(d->solver, g, stack->lit[i]);
×
722
    }
723
  }
724
}
×
725

726
/*
727
 * Transfer binary clauses
728
 */
NEW
729
static void copy_binary_clauses(delegate_t *d, smt_core_t *core, literal_t g) {
×
730
  int32_t n;
731
  literal_t l1, l2;
732
  literal_t *bin;
733

734
  n = core->nlits;
×
735
  for (l1=0; l1<n; l1++) {
×
736
    bin = core->bin[l1];
×
737
    if (bin != NULL) {
×
738
      for (;;) {
739
        l2 = *bin ++;
×
740
        if (l2 < 0) break;
×
741
        if (l1 <= l2) {
×
NEW
742
          if (g == true_literal) {
×
NEW
743
            d->add_binary_clause(d->solver, l1, l2);
×
744
          } else {
NEW
745
            d->add_ternary_clause(d->solver, g, l1, l2);
×
746
          }
747
        }
748
      }
749
    }
750
  }
751
}
×
752

753
/*
754
 * Copy one clause c:
755
 * - we make an intermediate copy in d->vector in case the 
756
 *   SAT solver modifies the input array
757
 */
NEW
758
static void copy_clause(delegate_t *d, const clause_t *c, literal_t g) {
×
759
  uint32_t i;
760
  literal_t l;
761
  
762
  ivector_reset(&d->buffer);
×
NEW
763
  if (g != true_literal) {
×
NEW
764
    ivector_push(&d->buffer, g);
×
765
  }
766
  i = 0;
×
767
  l = c->cl[0];
×
768
  while (l >= 0) {
×
769
    ivector_push(&d->buffer, l);
×
770
    i ++;
×
771
    l = c->cl[i];
×
772
  }
773
  d->add_clause(d->solver, d->buffer.size, d->buffer.data);
×
774
}
×
775

776
/*
777
 * Copy the clauses from a vector
778
 */
NEW
779
static void copy_clause_vector(delegate_t *d, clause_t **vector, literal_t g) {
×
780
  uint32_t i, n;
781

782
  if (vector != NULL) {
×
783
    n = get_cv_size(vector);
×
784
    for (i=0; i<n; i++) {
×
NEW
785
      copy_clause(d, vector[i], g);
×
786
    }
787
  }
788
}
×
789

790
/*
791
 * Copy all the problem clauses from core to d
792
 */
NEW
793
void add_problem_clauses_to_delegate(delegate_t *d, smt_core_t *core, literal_t g) {
×
794
  if (core->inconsistent) {
×
NEW
795
    if (g == true_literal) {
×
NEW
796
      d->add_empty_clause(d->solver);
×
797
    } else {
NEW
798
      d->add_unit_clause(d->solver, g);
×
799
    }
800
  }
NEW
801
  copy_unit_clauses(d, core, g);
×
NEW
802
  copy_binary_clauses(d, core, g);
×
NEW
803
  copy_clause_vector(d, core->problem_clauses, g);
×
UNCOV
804
}
×
805

806

807
/*
808
 * Mark all variables with atoms as variables to keep
809
 */
810
static void mark_atom_variables(delegate_t *d, smt_core_t *core) {
×
811
  uint32_t x, n;
812

813
  n = num_vars(core);
×
814
  for (x=0; x<n; x++) {
×
815
    if (bvar_has_atom(core, x)) {
×
816
      d->keep_var(d->solver, x);
×
817
    }
818
  }
819
}
×
820

821

822
/*
823
 * Process a gate definition g
824
 */
825
// definition l := f(l1, l2)
826
static void add_binary_gate(delegate_t *d, uint32_t b, literal_t l, literal_t l1, literal_t l2) {
×
827
  bvar_t x;
828

829
  // normalize to a positive l
830
  // l can be true_literal or false_literal, in which case we skip this gate
831
  x = var_of(l);
×
832
  if (x != const_bvar) {
×
833
    if (is_neg(l)) { b = ~b; }
×
834
    d->var_def2(d->solver, x, b, l1, l2);
×
835
  }
836
}
×
837

838
// definition l := f(l1, l2, l3)
839
static void add_ternary_gate(delegate_t *d, uint32_t b, literal_t l, literal_t l1, literal_t l2, literal_t l3) {
×
840
  bvar_t x;
841

842
  // normalize to a positive l
843
  // l can be true_literal or false_literal, in which case we skip this gate
844
  x = var_of(l);
×
845
  if (x != const_bvar) {
×
846
    if (is_neg(l)) { b = ~b; }
×
847
    d->var_def3(d->solver, x, b, l1, l2, l3);
×
848
  }
849
}
×
850

851
static void export_gate(delegate_t *d, const boolgate_t *g) {
×
852
  uint32_t n;
853

854
  switch (tag_combinator(g->tag)) {
×
855
  case XOR_GATE:
×
856
    assert(tag_outdegree(g->tag) == 1);
857
    n = tag_indegree(g->tag);
×
858
    if (n == 2) {
×
859
      // output is g->lit[2], inputs are g->lit[0] and g->lit[1]
860
      add_binary_gate(d, 0x3c, g->lit[2], g->lit[0], g->lit[1]);
×
861
    } else if (n == 3) {
×
862
      // output is g->lit[3], inputs are g->lit[0 .. 2]
863
      add_ternary_gate(d, 0x96, g->lit[3], g->lit[0], g->lit[1], g->lit[2]);
×
864
    }
865
    break;
×
866

867
  case OR_GATE:
×
868
    assert(tag_outdegree(g->tag) == 1);
869
    n = tag_indegree(g->tag);
×
870
    if (n == 2) {
×
871
      // output is g->lit[2], inputs are g->lit[0] and g->lit[1]
872
      add_binary_gate(d, 0xfc, g->lit[2], g->lit[0], g->lit[1]);
×
873
    } else if (n == 3) {
×
874
      // output is g->lit[3], inputs are g->lit[0 .. 2]
875
      add_ternary_gate(d, 0xfe, g->lit[3], g->lit[0], g->lit[1], g->lit[2]);
×
876
    }
877
    break;
×
878

879
  case ITE_GATE:
×
880
    assert(tag_indegree(g->tag) == 3 && tag_outdegree(g->tag) == 1);
881
     add_ternary_gate(d, 0xca, g->lit[3], g->lit[0], g->lit[1], g->lit[2]);
×
882
    break;
×
883

884
  case CMP_GATE:
×
885
    assert(tag_indegree(g->tag) == 3 && tag_outdegree(g->tag) == 1);
886
    add_ternary_gate(d, 0xb2, g->lit[3], g->lit[0], g->lit[1], g->lit[2]);
×
887
    break;
×
888

889
  case HALFADD_GATE:
×
890
    assert(tag_indegree(g->tag) == 2 && tag_outdegree(g->tag) == 2);
891
    // g->lit[2] = (xor g->lit[0] g->lit[1])
892
    // g->lit[3] = (and g->lit[0] g->lit[1])
893
    add_binary_gate(d, 0x3c, g->lit[2], g->lit[0], g->lit[1]);
×
894
    add_binary_gate(d, 0xc0, g->lit[3], g->lit[0], g->lit[1]);
×
895
    break;
×
896

897
   case FULLADD_GATE:
×
898
    // g->lit[3] = (xor g->lit[0] g->lit[1] g->lit[2])
899
    // g->lit[4] = (maj g->lit[0] g->lit[1] g->lit[2])
900
    assert(tag_indegree(g->tag) == 3 && tag_outdegree(g->tag) == 2);
901
    add_ternary_gate(d, 0x96, g->lit[3], g->lit[0], g->lit[1], g->lit[2]);
×
902
    add_ternary_gate(d, 0xe8, g->lit[4], g->lit[0], g->lit[1], g->lit[2]);
×
903
    break;
×
904
  }
905
}
×
906

907
extern void show_all_var_defs(const sat_solver_t *solver);
908

909
/*
910
 * Export gate definitions from the core to the sat solver
911
 */
912
static void export_gate_definitions(delegate_t *d, smt_core_t *core) {
×
913
  gate_table_t *gates;
914
  boolgate_t *g;
915
  uint32_t scan_index;
916

917
  gates = get_gate_table(core);
×
918

919
  scan_index = 0;
×
920
  g = gate_table_next(gates, &scan_index);
×
921
  while (g != NULL) {
×
922
    export_gate(d, g);
×
923
    g = gate_table_next(gates, &scan_index);
×
924
  }
925

926
  //  show_all_var_defs(d->solver);
927
}
×
928

929
/*
930
 * Copy all clauses of core to a delegate d then call the delegate's solver
931
 */
932
smt_status_t solve_with_delegate(delegate_t *d, smt_core_t *core) {
×
NEW
933
  add_problem_clauses_to_delegate(d, core, true_literal);
×
934
  if (d->keep_var != NULL) {
×
935
    mark_atom_variables(d, core);
×
936
  }
937
  if (d->var_def2 != NULL && d->var_def3 != NULL) {
×
938
    export_gate_definitions(d, core);
×
939
  }
940
  return d->check(d->solver);
×
941
}
942

943

944
/*
945
 * Copy all the clauses of core to delegate d then call the delegate's preprocessor
946
 */
947
smt_status_t preprocess_with_delegate(delegate_t *d, smt_core_t *core) {
×
948
  if (d->preprocess == NULL) return YICES_STATUS_UNKNOWN; // not supported
×
949

NEW
950
  add_problem_clauses_to_delegate(d, core, true_literal);
×
951
  if (d->keep_var != NULL) {
×
952
    mark_atom_variables(d, core);
×
953
  }
954
  if (d->var_def2 != NULL && d->var_def3 != NULL) {
×
955
    export_gate_definitions(d, core);
×
956
  }
957
  return d->preprocess(d->solver);
×
958
}
959

960

961
/*
962
 * Export to DIMACS (do nothing if that's not supported by the delegate)
963
 */
964
void export_to_dimacs_with_delegate(delegate_t *d, FILE *f) {
×
965
  if (d->export != NULL) {
×
966
    d->export(d->solver, f);
×
967
  }
968
}
×
969

970

971
/*
972
 * Value assigned to variable x in the delegate
973
 */
974
bval_t delegate_get_value(delegate_t *d, bvar_t x) {
×
975
  return d->get_value(d->solver, x);
×
976
}
977

978
/*
979
 * Set verbosity level
980
 */
981
void delegate_set_verbosity(delegate_t *d, uint32_t level) {
×
982
  d->set_verbosity(d->solver, level);
×
983
}
×
984

NEW
985
void delegate_add_vars(delegate_t *d, uint32_t n) {
×
NEW
986
  if (d->add_vars != NULL && n > 0) {
×
NEW
987
    d->add_vars(d->solver, n);
×
988
  }
NEW
989
}
×
990

NEW
991
bool delegate_supports_assumptions(const delegate_t *d) {
×
NEW
992
  return d->check_assuming != NULL;
×
993
}
994

NEW
995
smt_status_t delegate_check_with_assumptions(delegate_t *d, uint32_t n, const literal_t *a, ivector_t *failed) {
×
996
  smt_status_t stat;
997

NEW
998
  if (d->check_assuming == NULL) {
×
NEW
999
    return YICES_STATUS_UNKNOWN;
×
1000
  }
1001

NEW
1002
  stat = d->check_assuming(d->solver, n, a);
×
NEW
1003
  if (stat == YICES_STATUS_UNSAT && failed != NULL && d->collect_failed_assumptions != NULL) {
×
NEW
1004
    ivector_reset(failed);
×
NEW
1005
    d->collect_failed_assumptions(d->solver, n, a, failed);
×
1006
  }
1007

NEW
1008
  return stat;
×
1009
}
1010

NEW
1011
smt_status_t solve_with_delegate_assumptions(delegate_t *d, smt_core_t *core, uint32_t n, const literal_t *a,
×
1012
                                             ivector_t *failed) {
NEW
1013
  add_problem_clauses_to_delegate(d, core, true_literal);
×
NEW
1014
  if (d->keep_var != NULL) {
×
NEW
1015
    mark_atom_variables(d, core);
×
1016
  }
NEW
1017
  if (d->var_def2 != NULL && d->var_def3 != NULL) {
×
NEW
1018
    export_gate_definitions(d, core);
×
1019
  }
NEW
1020
  return delegate_check_with_assumptions(d, n, a, failed);
×
1021
}
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