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

SRI-CSL / yices2 / 26675300141

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

push

github

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

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

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

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

8005 existing lines in 44 files now uncovered.

87475 of 127148 relevant lines covered (68.8%)

1646632.75 hits per line

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

81.73
/src/mcsat/preprocessor.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
#if defined(CYGWIN) || defined(MINGW)
20
#ifndef __YICES_DLLSPEC__
21
#define __YICES_DLLSPEC__ __declspec(dllexport)
22
#endif
23
#endif
24

25
#include "mcsat/preprocessor.h"
26
#include "mcsat/tracing.h"
27

28
#include "terms/term_explorer.h"
29
#include "terms/term_substitution.h"
30
#include "terms/bvarith64_buffer_terms.h"
31
#include "terms/bvarith_buffer_terms.h"
32

33
#include "model/models.h"
34
#include "model/model_eval.h"
35
#include "model/model_queries.h"
36
#include "model/concrete_values.h"
37

38
#include "context/context_types.h"
39

40
#include "yices.h"
41
#include "api/yices_api_lock_free.h"
42

43
void preprocessor_construct(preprocessor_t* pre, term_table_t* terms, jmp_buf* handler, const mcsat_options_t* options) {
740✔
44
  pre->terms = terms;
740✔
45
  init_term_manager(&pre->tm, terms);
740✔
46
  init_int_hmap(&pre->preprocess_map, 0);
740✔
47
  init_ivector(&pre->preprocess_map_list, 0);
740✔
48
  init_int_hmap(&pre->tuple_blast_map, 0);
740✔
49
  init_ivector(&pre->tuple_blast_data, 0);
740✔
50
  init_ivector(&pre->tuple_blast_list, 0);
740✔
51
  init_ivector(&pre->tuple_blast_atoms, 0);
740✔
52
  init_int_hmap(&pre->type_is_tuple_free_cache, 0);
740✔
53
  init_int_hmap(&pre->type_leaf_count_cache, 0);
740✔
54
  init_int_hmap(&pre->term_has_tuples_cache, 0);
740✔
55
  init_int_hmap(&pre->purification_map, 0);
740✔
56
  init_ivector(&pre->purification_map_list, 0);
740✔
57
  init_ivector(&pre->preprocessing_stack, 0);
740✔
58
  init_int_hmap(&pre->equalities, 0);
740✔
59
  init_ivector(&pre->equalities_list, 0);
740✔
60
  pre->tracer = NULL;
740✔
61
  pre->exception = handler;
740✔
62
  pre->options = options;
740✔
63
  scope_holder_construct(&pre->scope);
740✔
64
}
740✔
65

66
void preprocessor_set_tracer(preprocessor_t* pre, tracer_t* tracer) {
284✔
67
  pre->tracer = tracer;
284✔
68
}
284✔
69

70
void preprocessor_destruct(preprocessor_t* pre) {
740✔
71
  delete_int_hmap(&pre->purification_map);
740✔
72
  delete_ivector(&pre->purification_map_list);
740✔
73
  delete_int_hmap(&pre->tuple_blast_map);
740✔
74
  delete_ivector(&pre->tuple_blast_data);
740✔
75
  delete_ivector(&pre->tuple_blast_list);
740✔
76
  delete_ivector(&pre->tuple_blast_atoms);
740✔
77
  delete_int_hmap(&pre->type_is_tuple_free_cache);
740✔
78
  delete_int_hmap(&pre->type_leaf_count_cache);
740✔
79
  delete_int_hmap(&pre->term_has_tuples_cache);
740✔
80
  delete_int_hmap(&pre->preprocess_map);
740✔
81
  delete_ivector(&pre->preprocess_map_list);
740✔
82
  delete_ivector(&pre->preprocessing_stack);
740✔
83
  delete_int_hmap(&pre->equalities);
740✔
84
  delete_ivector(&pre->equalities_list);
740✔
85
  delete_term_manager(&pre->tm);
740✔
86
  scope_holder_destruct(&pre->scope);
740✔
87
}
740✔
88

89
static
90
term_t preprocessor_get(preprocessor_t* pre, term_t t) {
1,603,450✔
91
  int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
1,603,450✔
92
  if (find == NULL) {
1,603,450✔
93
    return NULL_TERM;
869,348✔
94
  } else {
95
    return find->val;
734,102✔
96
  }
97
}
98

99
static
100
void preprocessor_set(preprocessor_t* pre, term_t t, term_t t_pre) {
336,750✔
101
  assert(preprocessor_get(pre, t) == NULL_TERM);
102
  int_hmap_add(&pre->preprocess_map, t, t_pre);
336,750✔
103
  ivector_push(&pre->preprocess_map_list, t);
336,750✔
104
}
336,750✔
105

106
static
107
bool type_is_tuple_free(preprocessor_t* pre, type_t tau) {
411,144✔
108
  int_hmap_pair_t* rec = int_hmap_find(&pre->type_is_tuple_free_cache, tau);
411,144✔
109
  if (rec != NULL) {
411,144✔
110
    return rec->val != 0;
409,023✔
111
  }
112

113
  type_table_t* types = pre->terms->types;
2,121✔
114
  type_kind_t kind = type_kind(types, tau);
2,121✔
115
  uint32_t i;
116
  bool result;
117
  switch (kind) {
2,121✔
118
  case BOOL_TYPE:
1,864✔
119
  case INT_TYPE:
120
  case REAL_TYPE:
121
  case BITVECTOR_TYPE:
122
  case SCALAR_TYPE:
123
  case UNINTERPRETED_TYPE:
124
  case FF_TYPE:
125
    result = true;
1,864✔
126
    break;
1,864✔
127
  case TUPLE_TYPE:
53✔
128
    result = false;
53✔
129
    break;
53✔
130
  case FUNCTION_TYPE: {
204✔
131
    function_type_t* fun = function_type_desc(types, tau);
204✔
132
    result = type_is_tuple_free(pre, fun->range);
204✔
133
    for (i = 0; result && i < fun->ndom; ++i) {
475✔
134
      if (!type_is_tuple_free(pre, fun->domain[i])) {
271✔
135
        result = false;
3✔
136
      }
137
    }
138
    break;
204✔
139
  }
UNCOV
140
  default:
×
UNCOV
141
    result = false;
×
UNCOV
142
    break;
×
143
  }
144

145
  int_hmap_add(&pre->type_is_tuple_free_cache, tau, result ? 1 : 0);
2,121✔
146
  return result;
2,121✔
147
}
148

149
static
150
uint32_t type_leaf_count(preprocessor_t* pre, type_t tau) {
150✔
151
  int_hmap_pair_t* rec = int_hmap_find(&pre->type_leaf_count_cache, tau);
150✔
152
  if (rec != NULL) {
150✔
153
    return (uint32_t) rec->val;
66✔
154
  }
155

156
  type_table_t* types = pre->terms->types;
84✔
157
  tuple_type_t* tuple;
158
  uint32_t i, count;
159
  switch (type_kind(types, tau)) {
84✔
160
  case TUPLE_TYPE:
10✔
161
    tuple = tuple_type_desc(types, tau);
10✔
162
    count = 0;
10✔
163
    for (i = 0; i < tuple->nelem; ++i) {
30✔
164
      count += type_leaf_count(pre, tuple->elem[i]);
20✔
165
    }
166
    break;
10✔
167
  case FUNCTION_TYPE:
10✔
168
    count = type_leaf_count(pre, function_type_desc(types, tau)->range);
10✔
169
    break;
10✔
170
  default:
64✔
171
    count = 1;
64✔
172
    break;
64✔
173
  }
174

175
  int_hmap_add(&pre->type_leaf_count_cache, tau, (int32_t) count);
84✔
176
  return count;
84✔
177
}
178

179
static void function_type_collect_blasted(type_table_t* types, type_t tau, ivector_t* out);
180

181
static
182
void type_collect_flat(type_table_t* types, type_t tau, ivector_t* flat) {
245✔
183
  tuple_type_t* tuple;
184
  uint32_t i;
185

186
  switch (type_kind(types, tau)) {
245✔
187
  case TUPLE_TYPE:
77✔
188
    tuple = tuple_type_desc(types, tau);
77✔
189
    for (i = 0; i < tuple->nelem; ++i) {
234✔
190
      type_collect_flat(types, tuple->elem[i], flat);
157✔
191
    }
192
    break;
77✔
193

194
  case FUNCTION_TYPE:
11✔
195
    function_type_collect_blasted(types, tau, flat);
11✔
196
    break;
11✔
197

198
  default:
157✔
199
    ivector_push(flat, tau);
157✔
200
    break;
157✔
201
  }
202
}
245✔
203

204
static
205
void function_type_collect_blasted(type_table_t* types, type_t tau, ivector_t* out) {
20✔
206
  function_type_t* fun;
207
  ivector_t dom_flat;
208
  ivector_t codom_leaf;
209
  uint32_t i;
210

211
  assert(type_kind(types, tau) == FUNCTION_TYPE);
212
  fun = function_type_desc(types, tau);
20✔
213

214
  init_ivector(&dom_flat, 0);
20✔
215
  for (i = 0; i < fun->ndom; ++i) {
40✔
216
    type_collect_flat(types, fun->domain[i], &dom_flat);
20✔
217
  }
218

219
  init_ivector(&codom_leaf, 0);
20✔
220
  type_collect_flat(types, fun->range, &codom_leaf);
20✔
221
  for (i = 0; i < codom_leaf.size; ++i) {
57✔
222
    type_t ft = function_type(types, codom_leaf.data[i], dom_flat.size, (type_t*) dom_flat.data);
37✔
223
    ivector_push(out, ft);
37✔
224
  }
225

226
  delete_ivector(&codom_leaf);
20✔
227
  delete_ivector(&dom_flat);
20✔
228
}
20✔
229

230
static
231
void type_collect_blasted_atom_types(type_table_t* types, type_t tau, ivector_t* out) {
47✔
232
  switch (type_kind(types, tau)) {
47✔
233
  case TUPLE_TYPE:
43✔
234
    type_collect_flat(types, tau, out);
43✔
235
    break;
43✔
236
  case FUNCTION_TYPE:
4✔
237
    function_type_collect_blasted(types, tau, out);
4✔
238
    break;
4✔
UNCOV
239
  default:
×
UNCOV
240
    ivector_push(out, tau);
×
UNCOV
241
    break;
×
242
  }
243
}
47✔
244

245
static
246
int_hmap_pair_t* tuple_blast_find(preprocessor_t* pre, term_t t) {
82,272✔
247
  return int_hmap_find(&pre->tuple_blast_map, t);
82,272✔
248
}
249

250
static
251
bool tuple_blast_done(preprocessor_t* pre, term_t t) {
41,926✔
252
  return tuple_blast_find(pre, t) != NULL;
41,926✔
253
}
254

255
static
256
void tuple_blast_set(preprocessor_t* pre, term_t t, const ivector_t* terms) {
39,287✔
257
  int_hmap_pair_t* rec = int_hmap_get(&pre->tuple_blast_map, t);
39,287✔
258
  assert(rec->val < 0);
259
  rec->val = pre->tuple_blast_data.size;
39,287✔
260
  ivector_push(&pre->tuple_blast_data, terms->size);
39,287✔
261
  ivector_add(&pre->tuple_blast_data, terms->data, terms->size);
39,287✔
262
  ivector_push(&pre->tuple_blast_list, t);
39,287✔
263
}
39,287✔
264

265
static
266
void tuple_blast_get(preprocessor_t* pre, term_t t, ivector_t* out) {
39,976✔
267
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
39,976✔
268
  assert(rec != NULL);
269
  uint32_t offset = rec->val;
39,976✔
270
  uint32_t n = pre->tuple_blast_data.data[offset];
39,976✔
271
  ivector_reset(out);
39,976✔
272
  ivector_add(out, pre->tuple_blast_data.data + offset + 1, n);
39,976✔
273
}
39,976✔
274

275
/*
276
 * Zero-copy read of the blasted leaves for t. Returns pointers directly
277
 * into tuple_blast_data, so the caller MUST NOT hold the returned pointer
278
 * across any operation that can grow tuple_blast_data -- most notably a
279
 * subsequent tuple_blast_term call. Intended for read-only hot paths
280
 * (NOT, SELECT, EQ, ITE, DISTINCT, OR/XOR, POWER_PRODUCT, *_POLY,
281
 * generic-composite combine, tuple_blast_collect_arg) where the
282
 * ivector-based tuple_blast_get would pay a malloc + memcpy per sub-term.
283
 * Use tuple_blast_get when the snapshot must outlive a subsequent
284
 * tuple_blast_term call (APP, UPDATE, top-level substitution, model
285
 * reconstruction).
286
 */
287
static
288
void tuple_blast_peek(preprocessor_t* pre, term_t t, const term_t** data_out, uint32_t* n_out) {
370✔
289
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
370✔
290
  assert(rec != NULL);
291
  uint32_t offset = rec->val;
370✔
292
  *n_out = pre->tuple_blast_data.data[offset];
370✔
293
  *data_out = (const term_t*) (pre->tuple_blast_data.data + offset + 1);
370✔
294
}
370✔
295

296
static
297
void tuple_blast_term(preprocessor_t* pre, term_t t);
298
static
299
void tuple_blast_term_body(preprocessor_t* pre, term_t t);
300
static composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t);
301
static term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children);
302

303
/**
304
 * Collect the direct sub-terms of t that must be blasted before t can be
305
 * combined. The set returned here MUST cover every sub-term that
306
 * tuple_blast_term_body recursively blasts for kind(t); otherwise the
307
 * iterative driver tuple_blast_term will deadlock (children never blasted)
308
 * or compute a wrong combine.
309
 */
310
static
311
void tuple_blast_children(preprocessor_t* pre, term_t t, ivector_t* out) {
411,027✔
312
  if (is_neg_term(t)) {
411,027✔
313
    ivector_push(out, unsigned_term(t));
41,578✔
314
    return;
41,578✔
315
  }
316

317
  term_table_t* terms = pre->terms;
369,449✔
318
  term_kind_t kind = term_kind(terms, t);
369,449✔
319
  uint32_t i;
320
  switch (kind) {
369,449✔
321
  case TUPLE_TERM: {
57✔
322
    composite_term_t* c = tuple_term_desc(terms, t);
57✔
323
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
171✔
324
    break;
57✔
325
  }
326
  case SELECT_TERM:
213✔
327
    ivector_push(out, select_term_desc(terms, t)->arg);
213✔
328
    break;
213✔
329
  case EQ_TERM: {
20,263✔
330
    composite_term_t* c = eq_term_desc(terms, t);
20,263✔
331
    ivector_push(out, c->arg[0]);
20,263✔
332
    ivector_push(out, c->arg[1]);
20,263✔
333
    break;
20,263✔
334
  }
335
  case DISTINCT_TERM: {
30✔
336
    composite_term_t* c = distinct_term_desc(terms, t);
30✔
337
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
150✔
338
    break;
30✔
339
  }
340
  case ITE_TERM:
20,651✔
341
  case ITE_SPECIAL: {
342
    composite_term_t* c = ite_term_desc(terms, t);
20,651✔
343
    for (i = 0; i < 3; ++i) ivector_push(out, c->arg[i]);
82,604✔
344
    break;
20,651✔
345
  }
346
  case APP_TERM: {
4,606✔
347
    composite_term_t* c = app_term_desc(terms, t);
4,606✔
348
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
15,106✔
349
    break;
4,606✔
350
  }
351
  case UPDATE_TERM: {
1,416✔
352
    composite_term_t* c = update_term_desc(terms, t);
1,416✔
353
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
5,680✔
354
    break;
1,416✔
355
  }
356
  case OR_TERM: {
58,708✔
357
    composite_term_t* c = or_term_desc(terms, t);
58,708✔
358
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
226,723✔
359
    break;
58,708✔
360
  }
361
  case XOR_TERM: {
30✔
362
    composite_term_t* c = xor_term_desc(terms, t);
30✔
363
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
156✔
364
    break;
30✔
365
  }
366
  case POWER_PRODUCT: {
1,676✔
367
    pprod_t* pp = pprod_term_desc(terms, t);
1,676✔
368
    for (i = 0; i < pp->len; ++i) ivector_push(out, pp->prod[i].var);
5,319✔
369
    break;
1,676✔
370
  }
371
  case ARITH_POLY: {
6,744✔
372
    polynomial_t* p = poly_term_desc(terms, t);
6,744✔
373
    for (i = 0; i < p->nterms; ++i) {
26,247✔
374
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
19,503✔
375
    }
376
    break;
6,744✔
377
  }
378
  case ARITH_FF_POLY: {
150✔
379
    polynomial_t* p = finitefield_poly_term_desc(terms, t);
150✔
380
    for (i = 0; i < p->nterms; ++i) {
1,068✔
381
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
918✔
382
    }
383
    break;
150✔
384
  }
385
  case BV64_POLY: {
2,575✔
386
    bvpoly64_t* p = bvpoly64_term_desc(terms, t);
2,575✔
387
    for (i = 0; i < p->nterms; ++i) {
9,833✔
388
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
7,258✔
389
    }
390
    break;
2,575✔
391
  }
392
  case BV_POLY: {
33✔
393
    bvpoly_t* p = bvpoly_term_desc(terms, t);
33✔
394
    for (i = 0; i < p->nterms; ++i) {
84✔
395
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
51✔
396
    }
397
    break;
33✔
398
  }
399
  case ARITH_EQ_ATOM:
98,775✔
400
  case ARITH_GE_ATOM:
401
  case ARITH_BINEQ_ATOM:
402
  case ARITH_RDIV:
403
  case ARITH_IDIV:
404
  case ARITH_MOD:
405
  case BV_ARRAY:
406
  case BV_DIV:
407
  case BV_REM:
408
  case BV_SDIV:
409
  case BV_SREM:
410
  case BV_SMOD:
411
  case BV_SHL:
412
  case BV_LSHR:
413
  case BV_ASHR:
414
  case BV_EQ_ATOM:
415
  case BV_GE_ATOM:
416
  case BV_SGE_ATOM: {
417
    composite_term_t* c = get_composite(terms, kind, t);
98,775✔
418
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
584,614✔
419
    break;
98,775✔
420
  }
421
  case BIT_TERM:
112,749✔
422
    /* (bit i e) where e is a bv-typed term. Recurse into e so a tuple
423
     * select inside e is blasted away before we rebuild. */
424
    ivector_push(out, bit_term_arg(terms, t));
112,749✔
425
    break;
112,749✔
426
  case ARITH_IS_INT_ATOM:
2✔
427
    ivector_push(out, arith_is_int_arg(terms, t));
2✔
428
    break;
2✔
429
  case ARITH_FLOOR:
9✔
430
    ivector_push(out, arith_floor_arg(terms, t));
9✔
431
    break;
9✔
432
  case ARITH_CEIL:
5✔
433
    ivector_push(out, arith_ceil_arg(terms, t));
5✔
434
    break;
5✔
435
  case ARITH_ABS:
12✔
436
    ivector_push(out, arith_abs_arg(terms, t));
12✔
437
    break;
12✔
438
  case ARITH_FF_EQ_ATOM:
155✔
439
    ivector_push(out, arith_ff_eq_arg(terms, t));
155✔
440
    break;
155✔
441
  case ARITH_FF_BINEQ_ATOM: {
12✔
442
    composite_term_t* c = arith_ff_bineq_atom_desc(terms, t);
12✔
443
    ivector_push(out, c->arg[0]);
12✔
444
    ivector_push(out, c->arg[1]);
12✔
445
    break;
12✔
446
  }
447
  default:
40,578✔
448
    /* Truly atomic kinds (CONSTANT_TERM, UNINTERPRETED_TERM, VARIABLE,
449
     * arithmetic/BV constants, etc.) have no children to blast first. */
450
    break;
40,578✔
451
  }
452
}
453

454
/**
455
 * Memoized: does the DAG rooted at t contain any tuple type?
456
 * Walks the DAG iteratively so deep DAGs don't blow the C stack. The
457
 * answer is polarity-insensitive (cached per index_of(t)) and covers
458
 * t's own type plus the types of every reachable sub-term.
459
 */
460
static
461
bool term_has_tuples_in_subdag(preprocessor_t* pre, term_t t) {
39,591✔
462
  int32_t t_idx = index_of(t);
39,591✔
463
  int_hmap_pair_t* rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
39,591✔
464
  if (rec != NULL) {
39,591✔
465
    return rec->val != 0;
1,963✔
466
  }
467

468
  term_table_t* terms = pre->terms;
37,628✔
469
  ivector_t stack;
470
  init_ivector(&stack, 0);
37,628✔
471
  ivector_push(&stack, t);
37,628✔
472

473
  uint64_t safety = 0;
37,628✔
474
  while (stack.size > 0) {
520,646✔
475
    /* Hard upper bound: 2 * (term-table size) is a generous loose bound on
476
     * the number of distinct (term, polarity) revisits we should ever see
477
     * here. Aborting on overflow is far better than hanging a debug build. */
478
    assert(++safety < ((uint64_t) 1 << 28));
479
    (void) safety;
480

481
    term_t current = stack.data[stack.size - 1];
483,018✔
482
    int32_t cur_idx = index_of(current);
483,018✔
483
    int_hmap_pair_t* crec = int_hmap_find(&pre->term_has_tuples_cache, cur_idx);
483,018✔
484
    if (crec != NULL) {
483,018✔
485
      ivector_pop(&stack);
72,396✔
486
      continue;
197,562✔
487
    }
488

489
    if (!type_is_tuple_free(pre, term_type(terms, current))) {
410,622✔
490
      int_hmap_add(&pre->term_has_tuples_cache, cur_idx, 1);
104✔
491
      ivector_pop(&stack);
104✔
492
      continue;
104✔
493
    }
494

495
    ivector_t children;
496
    init_ivector(&children, 0);
410,518✔
497
    tuple_blast_children(pre, current, &children);
410,518✔
498
    bool any_true = false;
410,518✔
499
    bool all_done = true;
410,518✔
500
    for (uint32_t i = 0; i < children.size; ++i) {
1,362,831✔
501
      int32_t c_idx = index_of(children.data[i]);
952,313✔
502
      int_hmap_pair_t* crec2 = int_hmap_find(&pre->term_has_tuples_cache, c_idx);
952,313✔
503
      if (crec2 == NULL) {
952,313✔
504
        ivector_push(&stack, children.data[i]);
320,328✔
505
        all_done = false;
320,328✔
506
      } else if (crec2->val != 0) {
631,985✔
507
        any_true = true;
222✔
508
      }
509
    }
510
    delete_ivector(&children);
410,518✔
511
    if (!all_done) continue;
410,518✔
512

513
    int_hmap_add(&pre->term_has_tuples_cache, cur_idx, any_true ? 1 : 0);
285,456✔
514
    ivector_pop(&stack);
285,456✔
515
  }
516

517
  delete_ivector(&stack);
37,628✔
518

519
  rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
37,628✔
520
  assert(rec != NULL);
521
  return rec->val != 0;
37,628✔
522
}
523

524
static
525
void tuple_blast_collect_arg(preprocessor_t* pre, term_t t, ivector_t* out) {
73✔
526
  const term_t* data;
527
  uint32_t n;
528
  tuple_blast_term(pre, t);
73✔
529
  /* Peek is safe here: we do not call tuple_blast_term between the peek
530
   * and the ivector_add below, so the backing tuple_blast_data cannot be
531
   * grown (and therefore cannot be reallocated) while `data` is live. */
532
  tuple_blast_peek(pre, t, &data, &n);
73✔
533
  ivector_add(out, (int32_t*) data, n);
73✔
534
}
73✔
535

536
static
537
term_t tuple_blast_eq_vector(term_manager_t* tm, const term_t* a, const term_t* b, uint32_t n) {
23✔
538
  assert(n > 0);
539
  if (n == 1) {
23✔
540
    return mk_eq(tm, a[0], b[0]);
3✔
541
  } else {
542
    ivector_t eqs;
543
    uint32_t i;
544
    init_ivector(&eqs, n);
20✔
545
    for (i = 0; i < n; ++i) {
61✔
546
      ivector_push(&eqs, mk_eq(tm, a[i], b[i]));
41✔
547
    }
548
    term_t result = mk_and(tm, eqs.size, eqs.data);
20✔
549
    delete_ivector(&eqs);
20✔
550
    return result;
20✔
551
  }
552
}
553

554
/*
555
 * Per-term combine. Computes blast(t) assuming the iterative driver
556
 * tuple_blast_term has already blasted every direct child returned by
557
 * tuple_blast_children. The recursive tuple_blast_term(pre, child) calls in
558
 * the body therefore bottom out at the early-return in the driver and do
559
 * not grow the C stack.
560
 */
561
static
562
void tuple_blast_term_body(preprocessor_t* pre, term_t t) {
308✔
563
  term_table_t* terms = pre->terms;
308✔
564
  type_table_t* types = terms->types;
308✔
565
  term_manager_t* tm = &pre->tm;
308✔
566

567
  if (tuple_blast_done(pre, t)) {
308✔
568
    return;
22✔
569
  }
570

571
  ivector_t result;
572
  init_ivector(&result, 0);
308✔
573

574
  if (is_neg_term(t)) {
308✔
575
    term_t c = unsigned_term(t);
22✔
576
    const term_t* c_data;
577
    uint32_t c_n;
578
    tuple_blast_term(pre, c);
22✔
579
    tuple_blast_peek(pre, c, &c_data, &c_n);
22✔
580
    if (c_n != 1) {
22✔
UNCOV
581
      delete_ivector(&result);
×
UNCOV
582
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
583
    }
584
    ivector_push(&result, opposite_term(c_data[0]));
22✔
585
    tuple_blast_set(pre, t, &result);
22✔
586
    delete_ivector(&result);
22✔
587
    return;
22✔
588
  }
589

590
  term_kind_t kind = term_kind(terms, t);
286✔
591
  type_t tau = term_type(terms, t);
286✔
592
  switch (kind) {
286✔
UNCOV
593
  case CONSTANT_TERM:
×
594
  case ARITH_CONSTANT:
595
  case ARITH_FF_CONSTANT:
596
  case BV64_CONSTANT:
597
  case BV_CONSTANT:
UNCOV
598
    ivector_push(&result, t);
×
UNCOV
599
    break;
×
600

601
  case UNINTERPRETED_TERM:
47✔
602
  case VARIABLE: {
603
    if (type_is_tuple_free(pre, tau)) {
47✔
UNCOV
604
      ivector_push(&result, t);
×
605
    } else {
606
      ivector_t atom_types;
607
      uint32_t i;
608
      init_ivector(&atom_types, 0);
47✔
609
      type_collect_blasted_atom_types(types, tau, &atom_types);
47✔
610
      for (i = 0; i < atom_types.size; ++i) {
154✔
611
        term_t v = new_uninterpreted_term(terms, atom_types.data[i]);
107✔
612
        ivector_push(&result, v);
107✔
613
      }
614
      ivector_push(&pre->tuple_blast_atoms, t);
47✔
615
      delete_ivector(&atom_types);
47✔
616
    }
617
    break;
47✔
618
  }
619

620
  case TUPLE_TERM: {
30✔
621
    composite_term_t* tuple = tuple_term_desc(terms, t);
30✔
622
    uint32_t i;
623
    for (i = 0; i < tuple->arity; ++i) {
90✔
624
      tuple_blast_collect_arg(pre, tuple->arg[i], &result);
60✔
625
    }
626
    break;
30✔
627
  }
628

629
  case SELECT_TERM: {
79✔
630
    select_term_t* sel = select_term_desc(terms, t);
79✔
631
    const term_t* arg_data;
632
    uint32_t arg_n;
633
    tuple_type_t* tuple_type;
634
    uint32_t i, start, len;
635
    type_t arg_type = term_type(terms, sel->arg);
79✔
636
    if (type_kind(types, arg_type) != TUPLE_TYPE) {
79✔
UNCOV
637
      delete_ivector(&result);
×
UNCOV
638
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
639
    }
640
    tuple_blast_term(pre, sel->arg);
79✔
641
    tuple_blast_peek(pre, sel->arg, &arg_data, &arg_n);
79✔
642
    tuple_type = tuple_type_desc(types, arg_type);
79✔
643
    start = 0;
79✔
644
    for (i = 0; i < sel->idx; ++i) {
117✔
645
      start += type_leaf_count(pre, tuple_type->elem[i]);
38✔
646
    }
647
    len = type_leaf_count(pre, tuple_type->elem[sel->idx]);
79✔
648
    if (start + len > arg_n) {
79✔
UNCOV
649
      delete_ivector(&result);
×
UNCOV
650
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
651
    }
652
    ivector_add(&result, (int32_t*) (arg_data + start), len);
79✔
653
    break;
79✔
654
  }
655

656
  case EQ_TERM: {
23✔
657
    composite_term_t* eq = eq_term_desc(terms, t);
23✔
658
    const term_t *lhs, *rhs;
659
    uint32_t lhs_n, rhs_n;
660
    /* Both tuple_blast_term calls precede both peeks; tuple_blast_eq_vector
661
     * and ivector_push do not grow tuple_blast_data, so the peeked
662
     * pointers stay live for the duration of this block. */
663
    tuple_blast_term(pre, eq->arg[0]);
23✔
664
    tuple_blast_term(pre, eq->arg[1]);
23✔
665
    tuple_blast_peek(pre, eq->arg[0], &lhs, &lhs_n);
23✔
666
    tuple_blast_peek(pre, eq->arg[1], &rhs, &rhs_n);
23✔
667
    if (lhs_n != rhs_n || lhs_n == 0) {
23✔
UNCOV
668
      delete_ivector(&result);
×
UNCOV
669
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
670
    }
671
    ivector_push(&result, tuple_blast_eq_vector(tm, lhs, rhs, lhs_n));
23✔
672
    break;
23✔
673
  }
674

UNCOV
675
  case DISTINCT_TERM: {
×
UNCOV
676
    composite_term_t* d = distinct_term_desc(terms, t);
×
677
    ivector_t conjuncts;
678
    uint32_t i, j;
UNCOV
679
    init_ivector(&conjuncts, 0);
×
UNCOV
680
    for (i = 0; i < d->arity; ++i) {
×
UNCOV
681
      for (j = i + 1; j < d->arity; ++j) {
×
682
        const term_t *ti_data, *tj_data;
683
        uint32_t ti_n, tj_n;
684
        ivector_t disj;
685
        uint32_t k;
686
        /* Both tuple_blast_term calls complete before the peeks; after
687
         * the peeks we only call mk_eq / opposite_term / mk_or and push
688
         * into local ivectors, none of which grow tuple_blast_data. */
UNCOV
689
        tuple_blast_term(pre, d->arg[i]);
×
UNCOV
690
        tuple_blast_term(pre, d->arg[j]);
×
UNCOV
691
        tuple_blast_peek(pre, d->arg[i], &ti_data, &ti_n);
×
UNCOV
692
        tuple_blast_peek(pre, d->arg[j], &tj_data, &tj_n);
×
UNCOV
693
        if (ti_n != tj_n || ti_n == 0) {
×
UNCOV
694
          delete_ivector(&conjuncts);
×
UNCOV
695
          delete_ivector(&result);
×
UNCOV
696
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
697
        }
UNCOV
698
        init_ivector(&disj, ti_n);
×
UNCOV
699
        for (k = 0; k < ti_n; ++k) {
×
UNCOV
700
          ivector_push(&disj, opposite_term(mk_eq(tm, ti_data[k], tj_data[k])));
×
701
        }
UNCOV
702
        ivector_push(&conjuncts, mk_or(tm, disj.size, disj.data));
×
UNCOV
703
        delete_ivector(&disj);
×
704
      }
705
    }
UNCOV
706
    ivector_push(&result, mk_and(tm, conjuncts.size, conjuncts.data));
×
UNCOV
707
    delete_ivector(&conjuncts);
×
UNCOV
708
    break;
×
709
  }
710

711
  case ITE_TERM:
3✔
712
  case ITE_SPECIAL: {
713
    composite_term_t* ite = ite_term_desc(terms, t);
3✔
714
    const term_t *c_data, *t_data, *e_data;
715
    uint32_t c_n, t_n, e_n;
716
    uint32_t i;
717
    /* All three tuple_blast_term calls complete before any peek, so the
718
     * peeked pointers remain valid for the rest of this block: the only
719
     * calls after the peeks are term-manager operations (super_type,
720
     * term_type, mk_ite) plus ivector_push(&result, ...), none of which
721
     * grow tuple_blast_data. */
722
    tuple_blast_term(pre, ite->arg[0]);
3✔
723
    tuple_blast_term(pre, ite->arg[1]);
3✔
724
    tuple_blast_term(pre, ite->arg[2]);
3✔
725
    tuple_blast_peek(pre, ite->arg[0], &c_data, &c_n);
3✔
726
    tuple_blast_peek(pre, ite->arg[1], &t_data, &t_n);
3✔
727
    tuple_blast_peek(pre, ite->arg[2], &e_data, &e_n);
3✔
728
    if (c_n != 1 || t_n != e_n || t_n == 0) {
3✔
UNCOV
729
      delete_ivector(&result);
×
UNCOV
730
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
731
    }
732
    for (i = 0; i < t_n; ++i) {
10✔
733
      type_t ty = super_type(types, term_type(terms, t_data[i]), term_type(terms, e_data[i]));
7✔
734
      if (ty == NULL_TYPE) {
7✔
UNCOV
735
        delete_ivector(&result);
×
UNCOV
736
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
737
      }
738
      ivector_push(&result, mk_ite(tm, c_data[0], t_data[i], e_data[i], ty));
7✔
739
    }
740
    if (result.size == 1 &&
3✔
UNCOV
741
        c_data[0] == ite->arg[0] &&
×
UNCOV
742
        t_data[0] == ite->arg[1] &&
×
UNCOV
743
        e_data[0] == ite->arg[2]) {
×
UNCOV
744
      ivector_reset(&result);
×
UNCOV
745
      ivector_push(&result, t);
×
746
    }
747
    break;
3✔
748
  }
749

750
  case APP_TERM: {
13✔
751
    composite_term_t* app = app_term_desc(terms, t);
13✔
752
    ivector_t f_blast;
753
    ivector_t args_flat;
754
    uint32_t i;
755
    bool changed;
756
    tuple_blast_term(pre, app->arg[0]);
13✔
757
    init_ivector(&f_blast, 0);
13✔
758
    tuple_blast_get(pre, app->arg[0], &f_blast);
13✔
759
    init_ivector(&args_flat, 0);
13✔
760
    for (i = 1; i < app->arity; ++i) {
26✔
761
      tuple_blast_collect_arg(pre, app->arg[i], &args_flat);
13✔
762
    }
763
    changed = f_blast.size != 1 || f_blast.data[0] != app->arg[0] || args_flat.size != app->arity - 1;
13✔
764
    for (i = 1; !changed && i < app->arity; ++i) {
13✔
UNCOV
765
      changed = args_flat.data[i - 1] != app->arg[i];
×
766
    }
767
    if (!changed) {
13✔
UNCOV
768
      ivector_push(&result, t);
×
UNCOV
769
      delete_ivector(&args_flat);
×
UNCOV
770
      delete_ivector(&f_blast);
×
UNCOV
771
      break;
×
772
    }
773
    for (i = 0; i < f_blast.size; ++i) {
37✔
774
      term_t app_i = mk_application(tm, f_blast.data[i], args_flat.size, args_flat.data);
24✔
775
      if (app_i == NULL_TERM) {
24✔
UNCOV
776
        delete_ivector(&args_flat);
×
UNCOV
777
        delete_ivector(&f_blast);
×
778
        delete_ivector(&result);
×
779
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
780
      }
781
      ivector_push(&result, app_i);
24✔
782
    }
783
    delete_ivector(&args_flat);
13✔
784
    delete_ivector(&f_blast);
13✔
785
    break;
13✔
786
  }
787

UNCOV
788
  case UPDATE_TERM: {
×
UNCOV
789
    composite_term_t* upd = update_term_desc(terms, t);
×
790
    ivector_t f_blast;
791
    ivector_t idx_flat;
792
    ivector_t v_blast;
793
    uint32_t i;
794
    bool changed;
UNCOV
795
    tuple_blast_term(pre, upd->arg[0]);
×
UNCOV
796
    init_ivector(&f_blast, 0);
×
UNCOV
797
    tuple_blast_get(pre, upd->arg[0], &f_blast);
×
UNCOV
798
    init_ivector(&idx_flat, 0);
×
UNCOV
799
    for (i = 1; i + 1 < upd->arity; ++i) {
×
UNCOV
800
      tuple_blast_collect_arg(pre, upd->arg[i], &idx_flat);
×
801
    }
UNCOV
802
    tuple_blast_term(pre, upd->arg[upd->arity - 1]);
×
UNCOV
803
    init_ivector(&v_blast, 0);
×
UNCOV
804
    tuple_blast_get(pre, upd->arg[upd->arity - 1], &v_blast);
×
UNCOV
805
    if (v_blast.size != 1 && v_blast.size != f_blast.size) {
×
UNCOV
806
      delete_ivector(&f_blast);
×
UNCOV
807
      delete_ivector(&idx_flat);
×
UNCOV
808
      delete_ivector(&v_blast);
×
UNCOV
809
      delete_ivector(&result);
×
UNCOV
810
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
811
    }
UNCOV
812
    changed = f_blast.size != 1 || f_blast.data[0] != upd->arg[0] || idx_flat.size != upd->arity - 2 ||
×
UNCOV
813
              v_blast.size != 1 || v_blast.data[0] != upd->arg[upd->arity - 1];
×
UNCOV
814
    for (i = 1; !changed && i + 1 < upd->arity; ++i) {
×
UNCOV
815
      changed = idx_flat.data[i - 1] != upd->arg[i];
×
816
    }
UNCOV
817
    if (!changed) {
×
UNCOV
818
      ivector_push(&result, t);
×
UNCOV
819
      delete_ivector(&f_blast);
×
UNCOV
820
      delete_ivector(&idx_flat);
×
UNCOV
821
      delete_ivector(&v_blast);
×
UNCOV
822
      break;
×
823
    }
UNCOV
824
    for (i = 0; i < f_blast.size; ++i) {
×
UNCOV
825
      term_t vi = v_blast.size == 1 ? v_blast.data[0] : v_blast.data[i];
×
UNCOV
826
      term_t upd_i = mk_update(tm, f_blast.data[i], idx_flat.size, idx_flat.data, vi);
×
UNCOV
827
      if (upd_i == NULL_TERM) {
×
UNCOV
828
        delete_ivector(&f_blast);
×
UNCOV
829
        delete_ivector(&idx_flat);
×
UNCOV
830
        delete_ivector(&v_blast);
×
UNCOV
831
        delete_ivector(&result);
×
UNCOV
832
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
833
      }
UNCOV
834
      ivector_push(&result, upd_i);
×
835
    }
UNCOV
836
    delete_ivector(&f_blast);
×
UNCOV
837
    delete_ivector(&idx_flat);
×
UNCOV
838
    delete_ivector(&v_blast);
×
UNCOV
839
    break;
×
840
  }
841

842
  case OR_TERM:
4✔
843
  case XOR_TERM: {
844
    composite_term_t* c = (kind == OR_TERM) ? or_term_desc(terms, t) : xor_term_desc(terms, t);
4✔
845
    ivector_t args;
846
    uint32_t i;
847
    init_ivector(&args, c->arity);
4✔
848
    for (i = 0; i < c->arity; ++i) {
12✔
849
      const term_t* child_data;
850
      uint32_t child_n;
851
      tuple_blast_term(pre, c->arg[i]);
8✔
852
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
8✔
853
      if (child_n != 1) {
8✔
UNCOV
854
        delete_ivector(&args);
×
UNCOV
855
        delete_ivector(&result);
×
UNCOV
856
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
857
      }
858
      ivector_push(&args, child_data[0]);
8✔
859
    }
860
    ivector_push(&result, kind == OR_TERM ? mk_or(tm, args.size, args.data) : mk_xor(tm, args.size, args.data));
4✔
861
    delete_ivector(&args);
4✔
862
    break;
4✔
863
  }
864

865
  case POWER_PRODUCT: {
2✔
866
    pprod_t* pp = pprod_term_desc(terms, t);
2✔
867
    term_t args[pp->len];
2✔
868
    uint32_t i;
869
    bool changed = false;
2✔
870

871
    for (i = 0; i < pp->len; ++i) {
6✔
872
      const term_t* child_data;
873
      uint32_t child_n;
874
      tuple_blast_term(pre, pp->prod[i].var);
4✔
875
      tuple_blast_peek(pre, pp->prod[i].var, &child_data, &child_n);
4✔
876
      if (child_n != 1) {
4✔
UNCOV
877
        delete_ivector(&result);
×
UNCOV
878
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
879
      }
880
      args[i] = child_data[0];
4✔
881
      changed |= args[i] != pp->prod[i].var;
4✔
882
    }
883
    ivector_push(&result, changed ? mk_pprod(tm, pp, pp->len, args) : t);
2✔
884
    break;
2✔
885
  }
886

887
  case ARITH_POLY: {
18✔
888
    polynomial_t* p = poly_term_desc(terms, t);
18✔
889
    term_t args[p->nterms];
18✔
890
    uint32_t i;
891
    bool changed = false;
18✔
892

893
    for (i = 0; i < p->nterms; ++i) {
53✔
894
      term_t x = p->mono[i].var;
35✔
895
      if (x == const_idx) {
35✔
896
        args[i] = const_idx;
13✔
897
      } else {
898
        const term_t* child_data;
899
        uint32_t child_n;
900
        tuple_blast_term(pre, x);
22✔
901
        tuple_blast_peek(pre, x, &child_data, &child_n);
22✔
902
        if (child_n != 1) {
22✔
UNCOV
903
          delete_ivector(&result);
×
UNCOV
904
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
905
        }
906
        args[i] = child_data[0];
22✔
907
        changed |= args[i] != x;
22✔
908
      }
909
    }
910
    ivector_push(&result, changed ? mk_arith_poly(tm, p, p->nterms, args) : t);
18✔
911
    break;
18✔
912
  }
913

UNCOV
914
  case ARITH_FF_POLY: {
×
UNCOV
915
    polynomial_t* p = finitefield_poly_term_desc(terms, t);
×
UNCOV
916
    const rational_t* mod = finitefield_term_order(terms, t);
×
UNCOV
917
    term_t args[p->nterms];
×
918
    uint32_t i;
UNCOV
919
    bool changed = false;
×
920

UNCOV
921
    for (i = 0; i < p->nterms; ++i) {
×
UNCOV
922
      term_t x = p->mono[i].var;
×
UNCOV
923
      if (x == const_idx) {
×
UNCOV
924
        args[i] = const_idx;
×
925
      } else {
926
        const term_t* child_data;
927
        uint32_t child_n;
UNCOV
928
        tuple_blast_term(pre, x);
×
UNCOV
929
        tuple_blast_peek(pre, x, &child_data, &child_n);
×
UNCOV
930
        if (child_n != 1) {
×
UNCOV
931
          delete_ivector(&result);
×
UNCOV
932
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
933
        }
UNCOV
934
        args[i] = child_data[0];
×
UNCOV
935
        changed |= args[i] != x;
×
936
      }
937
    }
UNCOV
938
    ivector_push(&result, changed ? mk_arith_ff_poly(tm, p, p->nterms, args, mod) : t);
×
UNCOV
939
    break;
×
940
  }
941

942
  case BV64_POLY: {
2✔
943
    bvpoly64_t* p = bvpoly64_term_desc(terms, t);
2✔
944
    term_t args[p->nterms];
2✔
945
    uint32_t i;
946
    bool changed = false;
2✔
947

948
    for (i = 0; i < p->nterms; ++i) {
6✔
949
      term_t x = p->mono[i].var;
4✔
950
      if (x == const_idx) {
4✔
951
        args[i] = const_idx;
2✔
952
      } else {
953
        const term_t* child_data;
954
        uint32_t child_n;
955
        tuple_blast_term(pre, x);
2✔
956
        tuple_blast_peek(pre, x, &child_data, &child_n);
2✔
957
        if (child_n != 1) {
2✔
UNCOV
958
          delete_ivector(&result);
×
UNCOV
959
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
960
        }
961
        args[i] = child_data[0];
2✔
962
        changed |= args[i] != x;
2✔
963
      }
964
    }
965
    ivector_push(&result, changed ? mk_bvarith64_poly(tm, p, p->nterms, args) : t);
2✔
966
    break;
2✔
967
  }
968

UNCOV
969
  case BV_POLY: {
×
UNCOV
970
    bvpoly_t* p = bvpoly_term_desc(terms, t);
×
971
    term_t args[p->nterms];
×
972
    uint32_t i;
UNCOV
973
    bool changed = false;
×
974

UNCOV
975
    for (i = 0; i < p->nterms; ++i) {
×
UNCOV
976
      term_t x = p->mono[i].var;
×
UNCOV
977
      if (x == const_idx) {
×
UNCOV
978
        args[i] = const_idx;
×
979
      } else {
980
        const term_t* child_data;
981
        uint32_t child_n;
982
        tuple_blast_term(pre, x);
×
UNCOV
983
        tuple_blast_peek(pre, x, &child_data, &child_n);
×
UNCOV
984
        if (child_n != 1) {
×
UNCOV
985
          delete_ivector(&result);
×
UNCOV
986
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
987
        }
UNCOV
988
        args[i] = child_data[0];
×
UNCOV
989
        changed |= args[i] != x;
×
990
      }
991
    }
UNCOV
992
    ivector_push(&result, changed ? mk_bvarith_poly(tm, p, p->nterms, args) : t);
×
UNCOV
993
    break;
×
994
  }
995

996
  case ARITH_EQ_ATOM:
57✔
997
  case ARITH_GE_ATOM:
998
  case ARITH_BINEQ_ATOM:
999
  case ARITH_RDIV:
1000
  case ARITH_IDIV:
1001
  case ARITH_MOD:
1002
  case BV_ARRAY:
1003
  case BV_DIV:
1004
  case BV_REM:
1005
  case BV_SDIV:
1006
  case BV_SREM:
1007
  case BV_SMOD:
1008
  case BV_SHL:
1009
  case BV_LSHR:
1010
  case BV_ASHR:
1011
  case BV_EQ_ATOM:
1012
  case BV_GE_ATOM:
1013
  case BV_SGE_ATOM: {
57✔
1014
    composite_term_t* c = get_composite(terms, kind, t);
57✔
1015
    term_t args[c->arity];
57✔
1016
    uint32_t i;
1017
    bool changed = false;
57✔
1018

1019
    for (i = 0; i < c->arity; ++i) {
154✔
1020
      const term_t* child_data;
1021
      uint32_t child_n;
1022
      tuple_blast_term(pre, c->arg[i]);
97✔
1023
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
97✔
1024
      if (child_n != 1) {
97✔
UNCOV
1025
        delete_ivector(&result);
×
UNCOV
1026
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1027
      }
1028
      args[i] = child_data[0];
97✔
1029
      changed |= args[i] != c->arg[i];
97✔
1030
    }
1031

1032
    term_t rebuilt = changed ? mk_composite(pre, kind, c->arity, args) : t;
57✔
1033
    if (rebuilt == NULL_TERM) {
57✔
UNCOV
1034
      delete_ivector(&result);
×
UNCOV
1035
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1036
    }
1037
    ivector_push(&result, rebuilt);
57✔
1038
    break;
57✔
1039
  }
1040

1041
  /*
1042
   * Unary kinds that take a single arithmetic / FF / BV operand and
1043
   * produce one scalar result. They are not handled by mk_composite, so
1044
   * we rebuild via the dedicated term_manager builder for each kind.
1045
   * If the underlying operand expands to more than one blasted leaf
1046
   * (i.e. it is itself tuple-typed), the operator does not make sense
1047
   * and we report an unsupported-theory error -- the same convention as
1048
   * the composite cluster above.
1049
   */
1050
  case BIT_TERM: {
4✔
1051
    term_t arg = bit_term_arg(terms, t);
4✔
1052
    uint32_t idx = bit_term_index(terms, t);
4✔
1053
    const term_t* child_data;
1054
    uint32_t child_n;
1055
    tuple_blast_term(pre, arg);
4✔
1056
    tuple_blast_peek(pre, arg, &child_data, &child_n);
4✔
1057
    if (child_n != 1) {
4✔
UNCOV
1058
      delete_ivector(&result);
×
UNCOV
1059
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1060
    }
1061
    term_t rebuilt = (child_data[0] == arg) ? t :
4✔
1062
                     mk_bitextract(&pre->tm, child_data[0], idx);
4✔
1063
    if (rebuilt == NULL_TERM) {
4✔
UNCOV
1064
      delete_ivector(&result);
×
UNCOV
1065
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1066
    }
1067
    ivector_push(&result, rebuilt);
4✔
1068
    break;
4✔
1069
  }
1070
  case ARITH_IS_INT_ATOM:
4✔
1071
  case ARITH_FLOOR:
1072
  case ARITH_CEIL:
1073
  case ARITH_ABS: {
1074
    term_t arg;
1075
    switch (kind) {
4✔
1076
    case ARITH_IS_INT_ATOM: arg = arith_is_int_arg(terms, t); break;
1✔
1077
    case ARITH_FLOOR:       arg = arith_floor_arg(terms, t);  break;
1✔
1078
    case ARITH_CEIL:        arg = arith_ceil_arg(terms, t);   break;
1✔
1079
    case ARITH_ABS:         arg = arith_abs_arg(terms, t);    break;
1✔
UNCOV
1080
    default: assert(false); arg = NULL_TERM;
×
1081
    }
1082
    const term_t* child_data;
1083
    uint32_t child_n;
1084
    tuple_blast_term(pre, arg);
4✔
1085
    tuple_blast_peek(pre, arg, &child_data, &child_n);
4✔
1086
    if (child_n != 1) {
4✔
1087
      delete_ivector(&result);
×
1088
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1089
    }
1090
    term_t rebuilt;
1091
    if (child_data[0] == arg) {
4✔
UNCOV
1092
      rebuilt = t;
×
1093
    } else {
1094
      switch (kind) {
4✔
1095
      case ARITH_IS_INT_ATOM: rebuilt = mk_arith_is_int(&pre->tm, child_data[0]); break;
1✔
1096
      case ARITH_FLOOR:       rebuilt = mk_arith_floor(&pre->tm, child_data[0]);  break;
1✔
1097
      case ARITH_CEIL:        rebuilt = mk_arith_ceil(&pre->tm, child_data[0]);   break;
1✔
1098
      case ARITH_ABS:         rebuilt = mk_arith_abs(&pre->tm, child_data[0]);    break;
1✔
UNCOV
1099
      default: assert(false); rebuilt = NULL_TERM;
×
1100
      }
1101
    }
1102
    if (rebuilt == NULL_TERM) {
4✔
UNCOV
1103
      delete_ivector(&result);
×
UNCOV
1104
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1105
    }
1106
    ivector_push(&result, rebuilt);
4✔
1107
    break;
4✔
1108
  }
UNCOV
1109
  case ARITH_FF_EQ_ATOM: {
×
UNCOV
1110
    term_t arg = arith_ff_eq_arg(terms, t);
×
1111
    const term_t* child_data;
1112
    uint32_t child_n;
UNCOV
1113
    tuple_blast_term(pre, arg);
×
UNCOV
1114
    tuple_blast_peek(pre, arg, &child_data, &child_n);
×
UNCOV
1115
    if (child_n != 1) {
×
UNCOV
1116
      delete_ivector(&result);
×
UNCOV
1117
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1118
    }
UNCOV
1119
    term_t rebuilt = (child_data[0] == arg) ? t :
×
UNCOV
1120
                     mk_arith_ff_term_eq0(&pre->tm, child_data[0]);
×
UNCOV
1121
    if (rebuilt == NULL_TERM) {
×
UNCOV
1122
      delete_ivector(&result);
×
UNCOV
1123
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1124
    }
UNCOV
1125
    ivector_push(&result, rebuilt);
×
UNCOV
1126
    break;
×
1127
  }
UNCOV
1128
  case ARITH_FF_BINEQ_ATOM: {
×
UNCOV
1129
    composite_term_t* c = arith_ff_bineq_atom_desc(terms, t);
×
1130
    term_t args[2];
UNCOV
1131
    bool changed = false;
×
1132
    uint32_t i;
UNCOV
1133
    for (i = 0; i < 2; ++i) {
×
1134
      const term_t* child_data;
1135
      uint32_t child_n;
UNCOV
1136
      tuple_blast_term(pre, c->arg[i]);
×
UNCOV
1137
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
×
UNCOV
1138
      if (child_n != 1) {
×
UNCOV
1139
        delete_ivector(&result);
×
UNCOV
1140
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1141
      }
UNCOV
1142
      args[i] = child_data[0];
×
UNCOV
1143
      changed |= args[i] != c->arg[i];
×
1144
    }
UNCOV
1145
    term_t rebuilt = changed ? mk_arith_ff_eq(&pre->tm, args[0], args[1]) : t;
×
UNCOV
1146
    if (rebuilt == NULL_TERM) {
×
UNCOV
1147
      delete_ivector(&result);
×
1148
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1149
    }
1150
    ivector_push(&result, rebuilt);
×
UNCOV
1151
    break;
×
1152
  }
1153

UNCOV
1154
  default:
×
UNCOV
1155
    ivector_push(&result, t);
×
UNCOV
1156
    break;
×
1157
  }
1158

1159
  tuple_blast_set(pre, t, &result);
286✔
1160
  delete_ivector(&result);
286✔
1161
}
1162

1163
/*
1164
 * Iterative bottom-up driver for tuple-blasting.
1165
 *  - C stack depth is O(1) regardless of input DAG depth (M4).
1166
 *  - Sub-DAGs that contain no tuple type anywhere are identity-blasted in
1167
 *    one step without descending into them, using the memoized
1168
 *    term_has_tuples_in_subdag (M3).
1169
 *  - For each not-yet-blasted term on the work stack we either (a) push
1170
 *    its un-blasted children, or (b) all children are blasted and we run
1171
 *    tuple_blast_term_body once. Children come from tuple_blast_children
1172
 *    which mirrors exactly the recursive descent in tuple_blast_term_body.
1173
 */
1174
static
1175
void tuple_blast_term(preprocessor_t* pre, term_t t) {
40,321✔
1176
  if (tuple_blast_done(pre, t)) {
40,321✔
1177
    return;
40,218✔
1178
  }
1179

1180
  if (!term_has_tuples_in_subdag(pre, t)) {
38,993✔
1181
    ivector_t result;
1182
    init_ivector(&result, 0);
38,890✔
1183
    ivector_push(&result, t);
38,890✔
1184
    tuple_blast_set(pre, t, &result);
38,890✔
1185
    delete_ivector(&result);
38,890✔
1186
    return;
38,890✔
1187
  }
1188

1189
  ivector_t stack;
1190
  init_ivector(&stack, 0);
103✔
1191
  ivector_push(&stack, t);
103✔
1192

1193
  uint64_t safety = 0;
103✔
1194
  while (stack.size > 0) {
702✔
1195
    /* Defensive bound. Real workloads visit each term O(1) times; 2^28
1196
     * iterations is far more than any reachable DAG should ever need. */
1197
    assert(++safety < ((uint64_t) 1 << 28));
1198
    (void) safety;
1199

1200
    term_t current = stack.data[stack.size - 1];
599✔
1201

1202
    if (tuple_blast_done(pre, current)) {
599✔
1203
      ivector_pop(&stack);
1✔
1204
      continue;
291✔
1205
    }
1206

1207
    if (!term_has_tuples_in_subdag(pre, current)) {
598✔
1208
      ivector_t result;
1209
      init_ivector(&result, 0);
89✔
1210
      ivector_push(&result, current);
89✔
1211
      tuple_blast_set(pre, current, &result);
89✔
1212
      delete_ivector(&result);
89✔
1213
      ivector_pop(&stack);
89✔
1214
      continue;
89✔
1215
    }
1216

1217
    ivector_t children;
1218
    init_ivector(&children, 0);
509✔
1219
    tuple_blast_children(pre, current, &children);
509✔
1220
    bool all_done = true;
509✔
1221
    for (uint32_t i = 0; i < children.size; ++i) {
1,207✔
1222
      if (!tuple_blast_done(pre, children.data[i])) {
698✔
1223
        ivector_push(&stack, children.data[i]);
295✔
1224
        all_done = false;
295✔
1225
      }
1226
    }
1227
    delete_ivector(&children);
509✔
1228
    if (!all_done) continue;
509✔
1229

1230
    tuple_blast_term_body(pre, current);
308✔
1231
    ivector_pop(&stack);
308✔
1232
  }
1233

1234
  delete_ivector(&stack);
103✔
1235
}
1236

1237
typedef struct composite_term1_s {
1238
  uint32_t arity;  // number of subterms
1239
  term_t arg[1];  // real size = arity
1240
} composite_term1_t;
1241

1242
static
1243
composite_term1_t composite_for_noncomposite;
1244

1245
static
1246
composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t) {
306,688✔
1247
  assert(term_is_composite(terms, t));
1248
  assert(term_kind(terms, t) == kind);
1249
  assert(is_pos_term(t));
1250

1251
  switch (kind) {
306,688✔
1252
  case ITE_TERM:           // if-then-else
20,874✔
1253
  case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1254
    return ite_term_desc(terms, t);
20,874✔
1255
  case EQ_TERM:            // equality
20,753✔
1256
    return eq_term_desc(terms, t);
20,753✔
1257
  case OR_TERM:            // n-ary OR
62,270✔
1258
    return or_term_desc(terms, t);
62,270✔
1259
  case XOR_TERM:           // n-ary XOR
30✔
1260
    return xor_term_desc(terms, t);
30✔
1261
  case ARITH_BINEQ_ATOM:   // equality: (t1 == t2)  (between two arithmetic terms)
7,967✔
1262
    return arith_bineq_atom_desc(terms, t);
7,967✔
1263
  case ARITH_EQ_ATOM: {
7,284✔
1264
    composite_for_noncomposite.arity = 1;
7,284✔
1265
    composite_for_noncomposite.arg[0] = arith_eq_arg(terms, t);
7,284✔
1266
    return (composite_term_t*)&composite_for_noncomposite;
7,284✔
1267
  }
1268
  case ARITH_GE_ATOM: {
16,300✔
1269
    composite_for_noncomposite.arity = 1;
16,300✔
1270
    composite_for_noncomposite.arg[0] = arith_ge_arg(terms, t);
16,300✔
1271
    return (composite_term_t*)&composite_for_noncomposite;
16,300✔
1272
  }
1273
  case ARITH_FF_BINEQ_ATOM:
12✔
1274
    return arith_ff_bineq_atom_desc(terms, t);
12✔
1275
  case ARITH_FF_EQ_ATOM: {
155✔
1276
    composite_for_noncomposite.arity = 1;
155✔
1277
    composite_for_noncomposite.arg[0] = arith_ff_eq_arg(terms, t);
155✔
1278
    return (composite_term_t*)&composite_for_noncomposite;
155✔
1279
  }
1280
  case APP_TERM:           // application of an uninterpreted function
5,843✔
1281
    return app_term_desc(terms, t);
5,843✔
1282
  case ARITH_RDIV:          // division: (/ x y)
116✔
1283
    return arith_rdiv_term_desc(terms, t);
116✔
1284
  case ARITH_IDIV:          // division: (div x y) as defined in SMT-LIB 2
178✔
1285
    return arith_idiv_term_desc(terms, t);
178✔
1286
  case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
296✔
1287
    return arith_mod_term_desc(terms, t);
296✔
1288
  case UPDATE_TERM:
2,501✔
1289
    return update_term_desc(terms, t);
2,501✔
1290
  case DISTINCT_TERM:
27✔
1291
    return distinct_term_desc(terms, t);
27✔
1292
  case BV_ARRAY:
34,821✔
1293
    return bvarray_term_desc(terms, t);
34,821✔
1294
  case BV_DIV:
186✔
1295
    return bvdiv_term_desc(terms, t);
186✔
1296
  case BV_REM:
424✔
1297
    return bvrem_term_desc(terms, t);
424✔
1298
  case BV_SDIV:
40✔
1299
    return bvsdiv_term_desc(terms, t);
40✔
1300
  case BV_SREM:
42✔
1301
    return bvsrem_term_desc(terms, t);
42✔
1302
  case BV_SMOD:
12✔
1303
    return bvsmod_term_desc(terms, t);
12✔
1304
  case BV_SHL:
286✔
1305
    return bvshl_term_desc(terms, t);
286✔
1306
  case BV_LSHR:
558✔
1307
    return bvlshr_term_desc(terms, t);
558✔
1308
  case BV_ASHR:
42✔
1309
    return bvashr_term_desc(terms, t);
42✔
1310
  case BV_EQ_ATOM:
118,837✔
1311
    return bveq_atom_desc(terms, t);
118,837✔
1312
  case BV_GE_ATOM:
5,550✔
1313
    return bvge_atom_desc(terms, t);
5,550✔
1314
  case BV_SGE_ATOM:
1,284✔
1315
    return bvsge_atom_desc(terms, t);
1,284✔
UNCOV
1316
  default:
×
1317
    assert(false);
UNCOV
1318
    return NULL;
×
1319
  }
1320
}
1321

1322
static bool type_needs_function_diseq_guard(type_table_t* types, type_t tau) {
24,790✔
1323
  uint32_t i, n;
1324

1325
  switch (type_kind(types, tau)) {
24,790✔
1326
  case FUNCTION_TYPE:
1,977✔
1327
    if (type_has_finite_domain(types, tau) ||
3,944✔
1328
        is_unit_type(types, function_type_range(types, tau))) {
1,967✔
1329
      return true;
11✔
1330
    }
1331

1332
    n = function_type_arity(types, tau);
1,966✔
1333
    for (i = 0; i < n; ++ i) {
3,936✔
1334
      if (type_needs_function_diseq_guard(types, function_type_domain(types, tau, i))) {
1,972✔
1335
        return true;
2✔
1336
      }
1337
    }
1338

1339
    return type_needs_function_diseq_guard(types, function_type_range(types, tau));
1,964✔
1340

UNCOV
1341
  case TUPLE_TYPE:
×
UNCOV
1342
    n = tuple_type_arity(types, tau);
×
UNCOV
1343
    for (i = 0; i < n; ++ i) {
×
UNCOV
1344
      if (type_needs_function_diseq_guard(types, tuple_type_component(types, tau, i))) {
×
UNCOV
1345
        return true;
×
1346
      }
1347
    }
UNCOV
1348
    return false;
×
1349

UNCOV
1350
  case INSTANCE_TYPE:
×
UNCOV
1351
    n = instance_type_arity(types, tau);
×
UNCOV
1352
    for (i = 0; i < n; ++ i) {
×
UNCOV
1353
      if (type_needs_function_diseq_guard(types, instance_type_param(types, tau, i))) {
×
UNCOV
1354
        return true;
×
1355
      }
1356
    }
UNCOV
1357
    return false;
×
1358

1359
  default:
22,813✔
1360
    return false;
22,813✔
1361
  }
1362
}
1363

1364
static bool term_needs_function_diseq_guard(term_table_t* terms, term_t t) {
20,854✔
1365
  return type_needs_function_diseq_guard(terms->types, term_type(terms, t));
20,854✔
1366
}
1367

1368
static
1369
term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children) {
46,644✔
1370
  term_manager_t* tm = &pre->tm;
46,644✔
1371
  term_table_t* terms = pre->terms;
46,644✔
1372

1373
  switch (kind) {
46,644✔
1374
  case ITE_TERM:           // if-then-else
12,893✔
1375
  case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1376
  {
1377
    assert(n == 3);
1378
    term_t type = super_type(pre->terms->types, term_type(terms, children[1]), term_type(terms, children[2]));
12,893✔
1379
    assert(type != NULL_TYPE);
1380
    return mk_ite(tm, children[0], children[1], children[2], type);
12,893✔
1381
  }
1382
  case EQ_TERM:            // equality
3,577✔
1383
    assert(n == 2);
1384
    return mk_eq(tm, children[0], children[1]);
3,577✔
1385
  case OR_TERM:            // n-ary OR
12,120✔
1386
    assert(n > 1);
1387
    return mk_or(tm, n, children);
12,120✔
1388
  case XOR_TERM:           // n-ary XOR
3✔
1389
    return mk_xor(tm, n, children);
3✔
1390
  case ARITH_EQ_ATOM:
71✔
1391
    assert(n == 1);
1392
    return mk_arith_eq(tm, children[0], zero_term);
71✔
1393
  case ARITH_GE_ATOM:
434✔
1394
    assert(n == 1);
1395
    return mk_arith_geq(tm, children[0], zero_term);
434✔
1396
  case ARITH_BINEQ_ATOM:   // equality: (t1 == t2)  (between two arithmetic terms)
263✔
1397
    assert(n == 2);
1398
    return mk_arith_eq(tm, children[0], children[1]);
263✔
1399
  case APP_TERM:           // application of an uninterpreted function
877✔
1400
    assert(n > 1);
1401
    return mk_application(tm, children[0], n-1, children + 1);
877✔
1402
  case ARITH_RDIV:
21✔
1403
    assert(n == 2);
1404
    return mk_arith_rdiv(tm, children[0], children[1]);
21✔
1405
  case ARITH_IDIV:          // division: (div x y) as defined in SMT-LIB 2
19✔
1406
    assert(n == 2);
1407
    return mk_arith_idiv(tm, children[0], children[1]);
19✔
1408
  case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
21✔
1409
    assert(n == 2);
1410
    return mk_arith_mod(tm, children[0], children[1]);
21✔
1411
  case UPDATE_TERM:
497✔
1412
    assert(n > 2);
1413
    return mk_update(tm, children[0], n-2, children + 1, children[n-1]);
497✔
1414
  case BV_ARRAY:
6,955✔
1415
    assert(n >= 1);
1416
    return mk_bvarray(tm, n, children);
6,955✔
1417
  case BV_DIV:
63✔
1418
    assert(n == 2);
1419
    return mk_bvdiv(tm, children[0], children[1]);
63✔
1420
  case BV_REM:
18✔
1421
    assert(n == 2);
1422
    return mk_bvrem(tm, children[0], children[1]);
18✔
UNCOV
1423
  case BV_SDIV:
×
1424
    assert(n == 2);
UNCOV
1425
    return mk_bvsdiv(tm, children[0], children[1]);
×
UNCOV
1426
  case BV_SREM:
×
1427
    assert(n == 2);
UNCOV
1428
    return mk_bvsrem(tm, children[0], children[1]);
×
1429
  case BV_SMOD:
2✔
1430
    assert(n == 2);
1431
    return mk_bvsmod(tm, children[0], children[1]);
2✔
1432
  case BV_SHL:
108✔
1433
    assert(n == 2);
1434
    return mk_bvshl(tm, children[0], children[1]);
108✔
1435
  case BV_LSHR:
135✔
1436
    assert(n == 2);
1437
    return mk_bvlshr(tm, children[0], children[1]);
135✔
1438
  case BV_ASHR:
3✔
1439
    assert(n == 2);
1440
    return mk_bvashr(tm, children[0], children[1]);
3✔
1441
  case BV_EQ_ATOM:
6,486✔
1442
    assert(n == 2);
1443
    return mk_bveq(tm, children[0], children[1]);
6,486✔
1444
  case BV_GE_ATOM:
1,797✔
1445
    assert(n == 2);
1446
    return mk_bvge(tm, children[0], children[1]);
1,797✔
1447
  case BV_SGE_ATOM:
281✔
1448
    assert(n == 2);
1449
    return mk_bvsge(tm, children[0], children[1]);
281✔
UNCOV
1450
  default:
×
1451
    assert(false);
UNCOV
1452
    return NULL_TERM;
×
1453
  }
1454
}
1455

1456
/**
1457
 * Returns purified version of t if we should purify t as an argument of a function.
1458
 * Any new equalities are added to output.
1459
 */
1460
static inline
1461
term_t preprocessor_purify(preprocessor_t* pre, term_t t, ivector_t* out) {
52,851✔
1462

1463
  term_table_t* terms = pre->terms;
52,851✔
1464

1465
  // Negated terms must be purified
1466
  if (is_pos_term(t)) {
52,851✔
1467
    // We don't purify variables
1468
    switch (term_kind(terms, t)) {
17,085✔
1469
    case UNINTERPRETED_TERM:
10,827✔
1470
      // Variables are already pure
1471
      return t;
10,827✔
1472
    case CONSTANT_TERM:
15✔
1473
      return t;
15✔
1474
    case ARITH_CONSTANT:
1,700✔
1475
    case ARITH_FF_CONSTANT:
1476
    case BV64_CONSTANT:
1477
    case BV_CONSTANT:
1478
      // Constants are also pure (except for false)
1479
      return t;
1,700✔
1480
    case APP_TERM:
1,685✔
1481
      // Uninterpreted functions are also already purified
1482
      return t;
1,685✔
1483
    case UPDATE_TERM:
1,680✔
1484
      return t;
1,680✔
1485
    default:
1,178✔
1486
      break;
1,178✔
1487
    }
1488
  }
1489

1490
  // Everything else gets purified. Check if in the cache
1491
  int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
36,944✔
1492
  if (find != NULL) {
36,944✔
1493
    return find->val;
36,376✔
1494
  } else {
1495
    // Make the variable
1496
    type_t t_type = term_type(terms, t);
568✔
1497
    term_t x = new_uninterpreted_term(terms, t_type);
568✔
1498
    // Remember for later
1499
    int_hmap_add(&pre->purification_map, t, x);
568✔
1500
    ivector_push(&pre->purification_map_list, t);
568✔
1501
    // Also add the variable to the pre-processor
1502
    preprocessor_set(pre, x, x);
568✔
1503
    // Add equality to output
1504
    term_t eq = mk_eq(&pre->tm, x, t);
568✔
1505
    ivector_push(out, eq);
568✔
1506

1507
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
568✔
UNCOV
1508
      mcsat_trace_printf(pre->tracer, "adding lemma = ");
×
UNCOV
1509
      trace_term_ln(pre->tracer, terms, eq);
×
1510
    }
1511

1512
    // Return the purified version
1513
    return x;
568✔
1514
  }
1515
}
1516

1517
static inline
1518
term_t mk_bvneg(term_manager_t* tm, term_t t) {
92✔
1519
  term_table_t* terms = tm->terms;
92✔
1520
  if (term_bitsize(terms,t) <= 64) {
92✔
1521
    bvarith64_buffer_t *buffer = term_manager_get_bvarith64_buffer(tm);
76✔
1522
    bvarith64_buffer_set_term(buffer, terms, t);
76✔
1523
    bvarith64_buffer_negate(buffer);
76✔
1524
    return mk_bvarith64_term(tm, buffer);
76✔
1525
  } else {
1526
    bvarith_buffer_t *buffer = term_manager_get_bvarith_buffer(tm);
16✔
1527
    bvarith_buffer_set_term(buffer, terms, t);
16✔
1528
    bvarith_buffer_negate(buffer);
16✔
1529
    return mk_bvarith_term(tm, buffer);
16✔
1530
  }
1531
}
1532

1533
// Mark equality eq: (var = t) for solving
1534
static
1535
void preprocessor_mark_eq(preprocessor_t* pre, term_t eq, term_t var) {
24,876✔
1536
  assert(is_pos_term(eq));
1537
  assert(is_pos_term(var));
1538
  assert(term_kind(pre->terms, var) == UNINTERPRETED_TERM);
1539

1540
  // Mark the equality
1541
  int_hmap_pair_t* find = int_hmap_get(&pre->equalities, eq);
24,876✔
1542
  assert(find->val == -1);
1543
  find->val = var;
24,876✔
1544
  ivector_push(&pre->equalities_list, eq);
24,876✔
1545
}
24,876✔
1546

1547
static
1548
term_t preprocessor_get_eq_solved_var(const preprocessor_t* pre, term_t eq) {
47,735✔
1549
  assert(is_pos_term(eq));
1550
  int_hmap_pair_t* find = int_hmap_find((int_hmap_t*) &pre->equalities, eq);
47,735✔
1551
  if (find != NULL) {
47,735✔
1552
    return find->val;
20,012✔
1553
  } else {
1554
    return NULL_TERM;
27,723✔
1555
  }
1556
}
1557

1558
term_t preprocessor_apply(preprocessor_t* pre, term_t t, ivector_t* out, bool is_assertion) {
39,926✔
1559

1560
  term_table_t* terms = pre->terms;
39,926✔
1561
  term_manager_t* tm = &pre->tm;
39,926✔
1562

1563
  uint32_t i, j, n;
1564
  ivector_t t_blast;
1565

1566
  tuple_blast_term(pre, t);
39,926✔
1567
  init_ivector(&t_blast, 0);
39,926✔
1568
  tuple_blast_get(pre, t, &t_blast);
39,926✔
1569
  if (t_blast.size != 1) {
39,926✔
UNCOV
1570
    delete_ivector(&t_blast);
×
UNCOV
1571
    longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1572
  }
1573
  t = t_blast.data[0];
39,926✔
1574
  delete_ivector(&t_blast);
39,926✔
1575

1576
  // Check if already preprocessed;
1577
  term_t t_pre = preprocessor_get(pre, t);
39,926✔
1578
  if (t_pre != NULL_TERM) {
39,926✔
1579
    return t_pre;
1,667✔
1580
  }
1581

1582
// Note: negative affect on general performance due to solved/substituted
1583
//       terms being to complex for explainers.
1584
//
1585
//  // First, if the assertion is a conjunction, just expand
1586
//  if (is_assertion && is_neg_term(t) && term_kind(terms, t) == OR_TERM) {
1587
//    // !(or t1 ... tn) -> !t1 && ... && !tn
1588
//    composite_term_t* t_desc = composite_term_desc(terms, t);
1589
//    for (i = 0; i < t_desc->arity; ++ i) {
1590
//      ivector_push(out, opposite_term(t_desc->arg[i]));
1591
//    }
1592
//    return true_term;
1593
//  }
1594
//
1595
  // Start
1596
  ivector_t* pre_stack = &pre->preprocessing_stack;
38,259✔
1597
  ivector_reset(pre_stack);
38,259✔
1598
  ivector_push(pre_stack, t);
38,259✔
1599

1600
  // Preprocess
1601
  while (pre_stack->size) {
506,581✔
1602
    // Current term
1603
    term_t current = ivector_last(pre_stack);
468,333✔
1604

1605
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
468,333✔
UNCOV
1606
      mcsat_trace_printf(pre->tracer, "current = ");
×
UNCOV
1607
      trace_term_ln(pre->tracer, terms, current);
×
1608
    }
1609

1610
    // If preprocessed already, done
1611
    term_t current_pre = preprocessor_get(pre, current);
468,333✔
1612
    if (current_pre != NULL_TERM) {
468,333✔
1613
      ivector_pop(pre_stack);
31,304✔
1614
      continue;
31,304✔
1615
    }
1616

1617
    // Negation
1618
    if (is_neg_term(current)) {
437,029✔
1619
      term_t child = unsigned_term(current);
89,049✔
1620
      term_t child_pre = preprocessor_get(pre, child);
89,049✔
1621
      if (child_pre == NULL_TERM) {
89,049✔
1622
        ivector_push(pre_stack, child);
42,050✔
1623
        continue;
42,050✔
1624
      } else {
1625
        ivector_pop(pre_stack);
46,999✔
1626
        current_pre = opposite_term(child_pre);
46,999✔
1627
        preprocessor_set(pre, current, current_pre);
46,999✔
1628
        continue;
46,999✔
1629
      }
1630
    }
1631

1632
    // Check for supported types
1633
    type_kind_t type = term_type_kind(terms, current);
347,980✔
1634
    switch (type) {
347,980✔
1635
    case BOOL_TYPE:
347,980✔
1636
    case INT_TYPE:
1637
    case REAL_TYPE:
1638
    case FF_TYPE:
1639
    case UNINTERPRETED_TYPE:
1640
    case FUNCTION_TYPE:
1641
    case BITVECTOR_TYPE:
1642
    case SCALAR_TYPE:
1643
      break;
347,980✔
UNCOV
1644
    default:
×
UNCOV
1645
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1646
    }
1647

1648
    // Kind of term
1649
    term_kind_t current_kind = term_kind(terms, current);
347,980✔
1650

1651
    switch(current_kind) {
347,980✔
1652
    case CONSTANT_TERM:    // constant of uninterpreted/scalar/boolean types
1,856✔
1653
    case BV64_CONSTANT:    // compact bitvector constant (64 bits at most)
1654
    case BV_CONSTANT:      // generic bitvector constant (more than 64 bits)
1655
    case ARITH_CONSTANT:   // rational constant
1656
    case ARITH_FF_CONSTANT:   // finite field constant
1657
      current_pre = current;
1,856✔
1658
      break;
1,856✔
1659

1660
    case UNINTERPRETED_TERM:  // (i.e., global variables, can't be bound).
14,106✔
1661
      current_pre = current;
14,106✔
1662
      // Unless we want special slicing
1663
      if (type == BITVECTOR_TYPE) {
14,106✔
1664
        if (pre->options->bv_var_size > 0) {
4,236✔
1665
          uint32_t size = term_bitsize(terms, current);
23✔
1666
          uint32_t var_size = pre->options->bv_var_size;
23✔
1667
          if (size > var_size) {
23✔
1668
            uint32_t n_vars = (size - 1) / var_size + 1;
2✔
1669
            term_t vars[n_vars];
2✔
1670
            for (i = n_vars - 1; size > 0; i--) {
8✔
1671
              if (size >= var_size) {
6✔
1672
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, var_size));
4✔
1673
                size -= var_size;
4✔
1674
              } else {
1675
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, size));
2✔
1676
                size = 0;
2✔
1677
              }
1678
            }
1679
            current_pre = _o_yices_bvconcat(n_vars, vars);
2✔
1680
            term_t eq = _o_yices_eq(current, current_pre);
2✔
1681
            preprocessor_mark_eq(pre, eq, current);
2✔
1682
          }
1683
        }
1684
      }
1685
      break;
14,106✔
1686

1687
    case ITE_TERM:           // if-then-else
181,585✔
1688
    case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1689
    case EQ_TERM:            // equality
1690
    case OR_TERM:            // n-ary OR
1691
    case XOR_TERM:           // n-ary XOR
1692
    case ARITH_EQ_ATOM:      // equality (t == 0)
1693
    case ARITH_BINEQ_ATOM:   // equality (t1 == t2)  (between two arithmetic terms)
1694
    case ARITH_GE_ATOM:      // inequality (t >= 0)
1695
    case ARITH_FF_EQ_ATOM:   // finite field equality (t == 0)
1696
    case ARITH_FF_BINEQ_ATOM: // finite field equality (t1 == t2)  (between two arithmetic terms)
1697
    case BV_DIV:
1698
    case BV_REM:
1699
    case BV_SMOD:
1700
    case BV_SHL:
1701
    case BV_LSHR:
1702
    case BV_ASHR:
1703
    case BV_EQ_ATOM:
1704
    case BV_GE_ATOM:
1705
    case BV_SGE_ATOM:
1706
    {
1707
      composite_term_t* desc = get_composite(terms, current_kind, current);
181,585✔
1708
      bool children_done = true;
181,585✔
1709
      bool children_same = true;
181,585✔
1710

1711
      n = desc->arity;
181,585✔
1712

1713
      // MCSAT does not yet enforce all extensionality/cardinality constraints
1714
      // for function-sort disequalities. Reject equality atoms whose type needs
1715
      // that monitoring; the Boolean abstraction may assert them either way.
1716
      if (current_kind == EQ_TERM && term_needs_function_diseq_guard(terms, desc->arg[0])) {
181,585✔
1717
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
8✔
1718
      }
1719

1720
      // Is this a top-level equality assertion
1721
      bool is_equality =
181,577✔
1722
          current_kind == EQ_TERM ||
160,832✔
1723
          current_kind == BV_EQ_ATOM ||
103,771✔
1724
          current_kind == ARITH_EQ_ATOM ||
100,005✔
1725
          current_kind == ARITH_BINEQ_ATOM ||
95,817✔
1726
          current_kind == ARITH_FF_EQ_ATOM ||
342,409✔
1727
          current_kind == ARITH_FF_BINEQ_ATOM;
1728
      // don't rewrite if the equality is between Boolean terms
1729
      bool is_boolean = is_boolean_type(term_type(pre->terms, desc->arg[0]));
181,577✔
1730

1731
      term_t eq_solve_var = NULL_TERM;
181,577✔
1732
      if (is_assertion && is_equality && !is_boolean) {
181,577✔
1733
        bool is_lhs_rhs_mixed = desc->arity > 1 &&
139,635✔
1734
          term_type_kind(pre->terms, desc->arg[0]) != term_type_kind(pre->terms, desc->arg[1]);
67,857✔
1735
        // don't rewrite if equality is between mixed terms, e.g. between int and real terms
1736
        if (!is_lhs_rhs_mixed && current == t) {
71,778✔
1737
          eq_solve_var = preprocessor_get_eq_solved_var(pre, t);
47,717✔
1738
          if (eq_solve_var == NULL_TERM) {
47,717✔
1739
            term_t lhs = desc->arg[0];
27,723✔
1740
            term_kind_t lhs_kind = term_kind(terms, lhs);
27,723✔
1741
            // If lhs/rhs is a first-time seen variable, we can solve it
1742
            bool lhs_is_var = lhs_kind == UNINTERPRETED_TERM && is_pos_term(lhs);
27,723✔
1743
            if (lhs_is_var && preprocessor_get(pre, lhs) == NULL_TERM) {
27,723✔
1744
              // First time variable, let's solve
1745
              preprocessor_mark_eq(pre, t, lhs);
24,595✔
1746
              eq_solve_var = lhs;
24,595✔
1747
            } else if (desc->arity > 1) {
3,128✔
1748
              term_t rhs = desc->arg[1];
2,354✔
1749
              term_kind_t rhs_kind = term_kind(terms, rhs);
2,354✔
1750
              bool rhs_is_var = rhs_kind == UNINTERPRETED_TERM && is_pos_term(rhs);
2,354✔
1751
              if (rhs_is_var && preprocessor_get(pre, rhs) == NULL_TERM) {
2,354✔
1752
                // First time variable, let's solve
1753
                preprocessor_mark_eq(pre, t, rhs);
279✔
1754
                eq_solve_var = rhs;
279✔
1755
              }
1756
            }
1757
          } else {
1758
            // Check that we it's not there already
1759
            if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
19,994✔
1760
              eq_solve_var = NULL_TERM;
51✔
1761
            }
1762
          }
1763
        }
1764
      }
1765

1766
      ivector_t children;
1767
      init_ivector(&children, n);
181,577✔
1768

1769
      for (i = 0; i < n; ++ i) {
605,545✔
1770
        term_t child = desc->arg[i];
423,968✔
1771
        if (child != eq_solve_var) {
423,968✔
1772
          term_t child_pre = preprocessor_get(pre, child);
379,151✔
1773
          if (child_pre == NULL_TERM) {
379,151✔
1774
            children_done = false;
108,714✔
1775
            ivector_push(pre_stack, child);
108,714✔
1776
          } else if (child_pre != child) {
270,437✔
1777
            children_same = false;
106,075✔
1778
          }
1779
          if (children_done) {
379,151✔
1780
            ivector_push(&children, child_pre);
256,583✔
1781
          }
1782
        }
1783
      }
1784

1785
      if (eq_solve_var != NULL_TERM) {
181,577✔
1786
        // Check again to make sure we don't have something like x = x + 1
1787
        if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
44,817✔
1788
          // Do it again
UNCOV
1789
          children_done = false;
×
1790
        }
1791
      }
1792

1793
      if (children_done) {
181,577✔
1794
        if (eq_solve_var != NULL_TERM) {
113,539✔
1795
          term_t eq_solve_term = zero_term;
24,823✔
1796
          if (children.size > 0) {
24,823✔
1797
            eq_solve_term = children.data[0];
24,785✔
1798
          }
1799
          preprocessor_set(pre, eq_solve_var, eq_solve_term);
24,823✔
1800
          current_pre = true_term;
24,823✔
1801
        } else {
1802
          if (children_same) {
88,716✔
1803
            current_pre = current;
50,519✔
1804
          } else {
1805
            current_pre = mk_composite(pre, current_kind, n, children.data);
38,197✔
1806
          }
1807
        }
1808
      }
1809

1810
      delete_ivector(&children);
181,577✔
1811

1812
      break;
181,577✔
1813
    }
1814

1815
    case BV_ARRAY:
17,517✔
1816
    {
1817
      composite_term_t* desc = get_composite(terms, current_kind, current);
17,517✔
1818
      bool children_done = true;
17,517✔
1819
      bool children_same = true;
17,517✔
1820

1821
      n = desc->arity;
17,517✔
1822

1823
      ivector_t children;
1824
      init_ivector(&children, n);
17,517✔
1825

1826
      for (i = 0; i < n; ++ i) {
353,534✔
1827
        term_t child = desc->arg[i];
336,017✔
1828
        term_t child_pre = preprocessor_get(pre, child);
336,017✔
1829
        if (child_pre == NULL_TERM) {
336,017✔
1830
          children_done = false;
143,211✔
1831
          ivector_push(pre_stack, child);
143,211✔
1832
        } else {
1833
          if (is_arithmetic_literal(terms, child_pre) || child_pre == false_term) {
192,806✔
1834
            // purify if arithmetic literal, i.e. a = 0 where a is of integer type
1835
            child_pre = preprocessor_purify(pre, child_pre, out);
35,723✔
1836
          }
1837
          if (child_pre != child) {
192,806✔
1838
            children_same = false;
110,041✔
1839
          }
1840
        }
1841
        if (children_done) {
336,017✔
1842
          ivector_push(&children, child_pre);
179,684✔
1843
        }
1844
      }
1845

1846
      if (children_done) {
17,517✔
1847
        if (children_same) {
9,165✔
1848
          current_pre = current;
2,210✔
1849
        } else {
1850
          current_pre = mk_composite(pre, current_kind, n, children.data);
6,955✔
1851
        }
1852
      }
1853

1854
      delete_ivector(&children);
17,517✔
1855

1856
      break;
17,517✔
1857
    }
1858

1859
    case ARITH_ABS:
10✔
1860
    {
1861
      term_t arg = arith_abs_arg(terms, current);
10✔
1862
      term_t arg_pre = preprocessor_get(pre, arg);
10✔
1863
      if (arg_pre == NULL_TERM) {
10✔
1864
        ivector_push(pre_stack, arg);
4✔
1865
      } else {
1866
        type_t arg_pre_type = term_type(pre->terms, arg_pre);
6✔
1867
        term_t arg_pre_is_positive = mk_arith_term_geq0(&pre->tm, arg_pre);
6✔
1868
        term_t arg_negative = _o_yices_neg(arg_pre);
6✔
1869
        current_pre = mk_ite(&pre->tm, arg_pre_is_positive, arg_pre, arg_negative, arg_pre_type);
6✔
1870
      }
1871
      break;
10✔
1872
    }
1873

1874
    case BV_SDIV:
20✔
1875
    {
1876
      composite_term_t* desc = get_composite(terms, current_kind, current);
20✔
1877
      assert(desc->arity == 2);
1878
      term_t s = desc->arg[0];
20✔
1879
      term_t s_pre = preprocessor_get(pre, s);
20✔
1880
      if (s_pre == NULL_TERM) {
20✔
1881
        ivector_push(pre_stack, s);
7✔
1882
      }
1883
      term_t t = desc->arg[1];
20✔
1884
      term_t t_pre = preprocessor_get(pre, t);
20✔
1885
      if (t_pre == NULL_TERM) {
20✔
1886
        ivector_push(pre_stack, t);
5✔
1887
      }
1888
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
20✔
1889
        type_t tau = term_type(terms, s_pre);
11✔
1890
        uint32_t n = term_bitsize(terms, s_pre);
11✔
1891
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
11✔
1892
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
11✔
1893
        // if (msb_s) {
1894
        //   if (msb_t) {
1895
        //     t1: udiv(-s, -t)
1896
        //   } else {
1897
        //     t2: -udiv(-s, t)
1898
        //   }
1899
        // } else {
1900
        //   if (msb_t) {
1901
        //     t3: -udiv(s, -t)
1902
        //   } else {
1903
        //     t4: udiv(s, t)
1904
        //   }
1905
        // }
1906
        term_t neg_s = mk_bvneg(tm, s_pre);
11✔
1907
        term_t neg_t = mk_bvneg(tm, t_pre);
11✔
1908

1909
        term_t t1 = mk_bvdiv(tm, neg_s, neg_t);
11✔
1910
        term_t t2 = mk_bvdiv(tm, neg_s, t_pre);
11✔
1911
        t2 = mk_bvneg(&pre->tm, t2);
11✔
1912
        term_t t3 = mk_bvdiv(tm, s_pre, neg_t);
11✔
1913
        t3 = mk_bvneg(&pre->tm, t3);
11✔
1914
        term_t t4 = mk_bvdiv(tm, s_pre, t_pre);
11✔
1915

1916
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
11✔
1917
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
11✔
1918

1919
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
11✔
1920
      }
1921
      break;
20✔
1922
    }
1923
    case BV_SREM:
21✔
1924
    {
1925
      composite_term_t* desc = get_composite(terms, current_kind, current);
21✔
1926
      assert(desc->arity == 2);
1927
      term_t s = desc->arg[0];
21✔
1928
      term_t s_pre = preprocessor_get(pre, s);
21✔
1929
      if (s_pre == NULL_TERM) {
21✔
1930
        ivector_push(pre_stack, s);
8✔
1931
      }
1932
      term_t t = desc->arg[1];
21✔
1933
      term_t t_pre = preprocessor_get(pre, t);
21✔
1934
      if (t_pre == NULL_TERM) {
21✔
1935
        ivector_push(pre_stack, t);
3✔
1936
      }
1937
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
21✔
1938
        type_t tau = term_type(terms, s_pre);
12✔
1939
        uint32_t n = term_bitsize(terms, s_pre);
12✔
1940
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
12✔
1941
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
12✔
1942
        // if (msb_s) {
1943
        //   if (msb_t) {
1944
        //     t1: -urem(-s, -t)
1945
        //   } else {
1946
        //     t2: -urem(-s, t)
1947
        //   }
1948
        // } else {
1949
        //   if (msb_t) {
1950
        //     t3: -urem(s, -t)
1951
        //   } else {
1952
        //     t4: urem(s, t)
1953
        //   }
1954
        // }
1955
        term_t neg_s = mk_bvneg(tm, s_pre);
12✔
1956
        term_t neg_t = mk_bvneg(tm, t_pre);
12✔
1957

1958
        term_t t1 = mk_bvrem(tm, neg_s, neg_t);
12✔
1959
        t1 = mk_bvneg(tm, t1);
12✔
1960
        term_t t2 = mk_bvrem(tm, neg_s, t_pre);
12✔
1961
        t2 = mk_bvneg(tm, t2);
12✔
1962
        term_t t3 = mk_bvrem(tm, s_pre, neg_t);
12✔
1963
        term_t t4 = mk_bvrem(tm, s_pre, t_pre);
12✔
1964

1965
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
12✔
1966
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
12✔
1967

1968
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
12✔
1969
      }
1970
      break;
21✔
1971
    }
1972
    case BIT_TERM: // bit-select current = child[i]
112,745✔
1973
    {
1974
      uint32_t index = bit_term_index(terms, current);
112,745✔
1975
      term_t arg = bit_term_arg(terms, current);
112,745✔
1976
      term_t arg_pre = preprocessor_get(pre, arg);
112,745✔
1977
      if (arg_pre == NULL_TERM) {
112,745✔
1978
        ivector_push(pre_stack, arg);
1,584✔
1979
      } else {
1980
        if (arg_pre == arg) {
111,161✔
1981
          current_pre = current;
73,115✔
1982
        } else {
1983
          if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,046✔
UNCOV
1984
            mcsat_trace_printf(pre->tracer, "arg_pre = ");
×
UNCOV
1985
            trace_term_ln(pre->tracer, terms, arg_pre);
×
1986
          }
1987
          // For simplification purposes use API
1988
          current_pre = _o_yices_bitextract(arg_pre, index);
38,046✔
1989
          assert(current_pre != NULL_TERM);
1990
        }
1991
      }
1992
      break;
112,745✔
1993
    }
1994
    case BV_POLY:  // polynomial with generic bitvector coefficients
33✔
1995
    {
1996
      bvpoly_t* p = bvpoly_term_desc(terms, current);
33✔
1997

1998
      bool children_done = true;
33✔
1999
      bool children_same = true;
33✔
2000

2001
      n = p->nterms;
33✔
2002

2003
      ivector_t children;
2004
      init_ivector(&children, n);
33✔
2005

2006
      for (i = 0; i < n; ++ i) {
84✔
2007
        term_t x = p->mono[i].var;
51✔
2008
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
51✔
2009

2010
        if (x_pre != const_idx) {
51✔
2011
          if (x_pre == NULL_TERM) {
47✔
2012
            children_done = false;
10✔
2013
            ivector_push(pre_stack, x);
10✔
2014
          } else if (x_pre != x) {
37✔
2015
            children_same = false;
23✔
2016
          }
2017
        }
2018

2019
        if (children_done) { ivector_push(&children, x_pre); }
51✔
2020
      }
2021

2022
      if (children_done) {
33✔
2023
        if (children_same) {
26✔
2024
          current_pre = current;
11✔
2025
        } else {
2026
          current_pre = mk_bvarith_poly(tm, p, n, children.data);
15✔
2027
        }
2028
      }
2029

2030
      delete_ivector(&children);
33✔
2031

2032
      break;
33✔
2033
    }
2034
    case BV64_POLY: // polynomial with 64bit coefficients
2,573✔
2035
    {
2036
      bvpoly64_t* p = bvpoly64_term_desc(terms, current);
2,573✔
2037

2038
      bool children_done = true;
2,573✔
2039
      bool children_same = true;
2,573✔
2040

2041
      n = p->nterms;
2,573✔
2042

2043
      ivector_t children;
2044
      init_ivector(&children, n);
2,573✔
2045

2046
      for (i = 0; i < n; ++ i) {
9,827✔
2047
        term_t x = p->mono[i].var;
7,254✔
2048
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
7,254✔
2049

2050
        if (x_pre != const_idx) {
7,254✔
2051
          if (x_pre == NULL_TERM) {
5,580✔
2052
            children_done = false;
1,308✔
2053
            ivector_push(pre_stack, x);
1,308✔
2054
          } else if (x_pre != x) {
4,272✔
2055
            children_same = false;
3,568✔
2056
          }
2057
        }
2058

2059
        if (children_done) { ivector_push(&children, x_pre); }
7,254✔
2060
      }
2061

2062
      if (children_done) {
2,573✔
2063
        if (children_same) {
1,872✔
2064
          current_pre = current;
279✔
2065
        } else {
2066
          current_pre = mk_bvarith64_poly(tm, p, n, children.data);
1,593✔
2067
        }
2068
      }
2069

2070
      delete_ivector(&children);
2,573✔
2071

2072
      break;
2,573✔
2073
    }
2074

2075
    case POWER_PRODUCT:    // power products: (t1^d1 * ... * t_n^d_n)
1,679✔
2076
    {
2077
      pprod_t* pp = pprod_term_desc(terms, current);
1,679✔
2078
      bool children_done = true;
1,679✔
2079
      bool children_same = true;
1,679✔
2080

2081
      n = pp->len;
1,679✔
2082

2083
      ivector_t children;
2084
      init_ivector(&children, n);
1,679✔
2085

2086
      for (i = 0; i < n; ++ i) {
5,324✔
2087
        term_t x = pp->prod[i].var;
3,645✔
2088
        term_t x_pre = preprocessor_get(pre, x);
3,645✔
2089

2090
        if (x_pre == NULL_TERM) {
3,645✔
2091
          children_done = false;
454✔
2092
          ivector_push(pre_stack, x);
454✔
2093
        } else if (x_pre != x) {
3,191✔
2094
          children_same = false;
96✔
2095
        }
2096

2097
        if (children_done) { ivector_push(&children, x_pre); }
3,645✔
2098
      }
2099

2100
      if (children_done) {
1,679✔
2101
        if (children_same) {
1,341✔
2102
          current_pre = current;
1,283✔
2103
        } else {
2104
          // NOTE: it doens't change pp, it just uses it as a frame
2105
          current_pre = mk_pprod(tm, pp, n, children.data);
58✔
2106
        }
2107
      }
2108

2109
      delete_ivector(&children);
1,679✔
2110

2111
      break;
1,679✔
2112
    }
2113

2114
    case ARITH_POLY:       // polynomial with rational coefficients
6,972✔
2115
    {
2116
      polynomial_t* p = poly_term_desc(terms, current);
6,972✔
2117

2118
      bool children_done = true;
6,972✔
2119
      bool children_same = true;
6,972✔
2120

2121
      n = p->nterms;
6,972✔
2122

2123
      ivector_t children;
2124
      init_ivector(&children, n);
6,972✔
2125

2126
      for (i = 0; i < n; ++ i) {
26,957✔
2127
        term_t x = p->mono[i].var;
19,985✔
2128
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
19,985✔
2129

2130
        if (x_pre != const_idx) {
19,985✔
2131
          if (x_pre == NULL_TERM) {
16,939✔
2132
            children_done = false;
2,580✔
2133
            ivector_push(pre_stack, x);
2,580✔
2134
          } else if (x_pre != x) {
14,359✔
2135
            children_same = false;
952✔
2136
          }
2137
        }
2138

2139
        if (children_done) { ivector_push(&children, x_pre); }
19,985✔
2140
      }
2141

2142
      if (children_done) {
6,972✔
2143
        if (children_same) {
5,508✔
2144
          current_pre = current;
4,905✔
2145
        } else {
2146
          current_pre = mk_arith_poly(tm, p, n, children.data);
603✔
2147
        }
2148
      }
2149

2150
      delete_ivector(&children);
6,972✔
2151

2152
      break;
6,972✔
2153
    }
2154

2155
    case ARITH_FF_POLY:    // polynomial with finite field coefficients
150✔
2156
    {
2157
      polynomial_t* p = finitefield_poly_term_desc(terms, current);
150✔
2158
      const rational_t *mod = finitefield_term_order(terms, current);
150✔
2159

2160
      bool children_done = true;
150✔
2161
      bool children_same = true;
150✔
2162

2163
      n = p->nterms;
150✔
2164

2165
      ivector_t children;
2166
      init_ivector(&children, n);
150✔
2167

2168
      for (i = 0; i < n; ++ i) {
1,068✔
2169
        term_t x = p->mono[i].var;
918✔
2170
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
918✔
2171

2172
        if (x_pre != const_idx) {
918✔
2173
          if (x_pre == NULL_TERM) {
864✔
2174
            children_done = false;
380✔
2175
            ivector_push(pre_stack, x);
380✔
2176
          } else if (x_pre != x) {
484✔
UNCOV
2177
            children_same = false;
×
2178
          }
2179
        }
2180

2181
        if (children_done) { ivector_push(&children, x_pre); }
918✔
2182
      }
2183

2184
      if (children_done) {
150✔
2185
        if (children_same) {
75✔
2186
          current_pre = current;
75✔
2187
        } else {
UNCOV
2188
          current_pre = mk_arith_ff_poly(tm, p, n, children.data, mod);
×
2189
        }
2190
      }
2191

2192
      delete_ivector(&children);
150✔
2193

2194
      break;
150✔
2195
    }
2196

2197
    // FOLLOWING ARE UNINTEPRETED, SO WE PURIFY THE ARGUMENTS
2198

2199
    case APP_TERM:           // application of an uninterpreted function
8,668✔
2200
    case ARITH_RDIV:         // regular division (/ x y)
2201
    case ARITH_IDIV:         // division: (div x y) as defined in SMT-LIB 2
2202
    case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
2203
    case UPDATE_TERM:        // update array
2204
    {
2205
      composite_term_t* desc = get_composite(terms, current_kind, current);
8,668✔
2206
      bool children_done = true;
8,668✔
2207
      bool children_same = true;
8,668✔
2208

2209
      n = desc->arity;
8,668✔
2210

2211
      ivector_t children;
2212
      init_ivector(&children, n);
8,668✔
2213

2214
      for (i = 0; i < n; ++ i) {
29,851✔
2215
        term_t child = desc->arg[i];
21,183✔
2216
        term_t child_pre = preprocessor_get(pre, child);
21,183✔
2217

2218
        if (child_pre == NULL_TERM) {
21,183✔
2219
          children_done = false;
4,062✔
2220
          ivector_push(pre_stack, child);
4,062✔
2221
        } else {
2222
          // Purify if needed
2223
          child_pre = preprocessor_purify(pre, child_pre, out);
17,121✔
2224
          // If interpreted terms, we need to purify non-variables
2225
          if (child_pre != child) { children_same = false; }
17,121✔
2226
        }
2227

2228
        if (children_done) { ivector_push(&children, child_pre); }
21,183✔
2229
      }
2230

2231
      if (children_done) {
8,668✔
2232
        if (children_same) {
5,655✔
2233
          current_pre = current;
4,220✔
2234
        } else {
2235
          current_pre = mk_composite(pre, current_kind, n, children.data);
1,435✔
2236
        }
2237
      }
2238

2239
      delete_ivector(&children);
8,668✔
2240

2241
      break;
8,668✔
2242
    }
2243

2244
    case ARITH_IS_INT_ATOM:
1✔
2245
    {
2246
      // replace with t <= floor(t)
2247
      term_t child = arith_is_int_arg(terms, current);
1✔
2248
      term_t child_pre = preprocessor_get(pre, child);
1✔
2249
      if (child_pre != NULL_TERM) {
1✔
2250
        child_pre = preprocessor_purify(pre, child_pre, out);
1✔
2251
        current_pre = arith_floor(terms, child_pre);
1✔
2252
        current_pre = mk_arith_leq(tm, child_pre, current_pre);
1✔
2253
      } else {
UNCOV
2254
        ivector_push(pre_stack, child);
×
2255
      }
2256
      break;
1✔
2257
    }
2258

2259
    case ARITH_FLOOR:        // floor: purify, but its interpreted
8✔
2260
    {
2261
      term_t child = arith_floor_arg(terms, current);
8✔
2262
      term_t child_pre = preprocessor_get(pre, child);
8✔
2263

2264
      if (child_pre != NULL_TERM) {
8✔
2265
        if (term_kind(terms, child_pre) == ARITH_CONSTANT) {
5✔
2266
          rational_t floor;
2267
          q_init(&floor);
2✔
2268
          q_set(&floor, rational_term_desc(terms, child_pre));
2✔
2269
          q_floor(&floor);
2✔
2270
          current_pre = arith_constant(terms, &floor);
2✔
2271
          q_clear(&floor);
2✔
2272
        } else {
2273
          child_pre = preprocessor_purify(pre, child_pre, out);
3✔
2274
          if (child_pre != child) {
3✔
2275
            current_pre = arith_floor(terms, child_pre);
1✔
2276
          } else {
2277
            current_pre = current;
2✔
2278
          }
2279
        }
2280
      } else {
2281
        ivector_push(pre_stack, child);
3✔
2282
      }
2283

2284
      break;
8✔
2285
    }
2286

2287
    case ARITH_CEIL:        // ceil: purify, but its interpreted
9✔
2288
    {
2289
      term_t child = arith_ceil_arg(terms, current);
9✔
2290
      term_t child_pre = preprocessor_get(pre, child);
9✔
2291

2292
      if (child_pre != NULL_TERM) {
9✔
2293
        if (term_kind(terms, child_pre) == ARITH_CONSTANT) {
7✔
2294
          rational_t ceil;
2295
          q_init(&ceil);
4✔
2296
          q_set(&ceil, rational_term_desc(terms, child_pre));
4✔
2297
          q_ceil(&ceil);
4✔
2298
          current_pre = arith_constant(terms, &ceil);
4✔
2299
          q_clear(&ceil);
4✔
2300
        } else {
2301
          child_pre = preprocessor_purify(pre, child_pre, out);
3✔
2302
          if (child_pre != child) {
3✔
2303
            current_pre = arith_ceil(terms, child_pre);
2✔
2304
          } else {
2305
            current_pre = current;
1✔
2306
          }
2307
        }
2308
      } else {
2309
        ivector_push(pre_stack, child);
2✔
2310
      }
2311

2312
      break;
9✔
2313
    }
2314

2315
    case DISTINCT_TERM:
27✔
2316
    {
2317
      composite_term_t* desc = get_composite(terms, current_kind, current);
27✔
2318

2319
      bool children_done = true;
27✔
2320
      n = desc->arity;
27✔
2321

2322
      // DISTINCT_TERM is lowered below into pairwise disequalities. Apply the
2323
      // same function-sort guard before that expansion.
2324
      for (i = 0; i < n; ++ i) {
125✔
2325
        if (term_needs_function_diseq_guard(terms, desc->arg[i])) {
101✔
2326
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
3✔
2327
        }
2328
      }
2329

2330
      ivector_t children;
2331
      init_ivector(&children, n);
24✔
2332

2333
      for (i = 0; i < n; ++ i) {
122✔
2334
        term_t child = desc->arg[i];
98✔
2335
        term_t child_pre = preprocessor_get(pre, child);
98✔
2336

2337
        if (child_pre == NULL_TERM) {
98✔
2338
          children_done = false;
41✔
2339
          ivector_push(pre_stack, child);
41✔
2340
        }
2341

2342
        if (children_done) { ivector_push(&children, child_pre); }
98✔
2343
      }
2344

2345
      if (children_done) {
24✔
2346
        ivector_t distinct;
2347
        init_ivector(&distinct, 0);
14✔
2348

2349
        for (i = 0; i < n; ++ i) {
70✔
2350
          for (j = i + 1; j < n; ++ j) {
148✔
2351
            term_t neq = mk_eq(&pre->tm, children.data[i], children.data[j]);
92✔
2352
            neq = opposite_term(neq);
92✔
2353
            ivector_push(&distinct, neq);
92✔
2354
          }
2355
        }
2356
        current_pre = mk_and(&pre->tm, distinct.size, distinct.data);
14✔
2357

2358
        delete_ivector(&distinct);
14✔
2359
      }
2360

2361
      delete_ivector(&children);
24✔
2362

2363
      break;
24✔
2364
    }
2365

UNCOV
2366
    case LAMBDA_TERM:
×
UNCOV
2367
      longjmp(*pre->exception, LAMBDAS_NOT_SUPPORTED);
×
2368
      break;
2369

UNCOV
2370
    default:
×
2371
      // UNSUPPORTED TERM/THEORY
UNCOV
2372
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
2373
      break;
2374
    }
2375

2376
    if (current_pre != NULL_TERM) {
347,969✔
2377
      preprocessor_set(pre, current, current_pre);
264,360✔
2378
      ivector_pop(pre_stack);
264,360✔
2379
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
264,360✔
UNCOV
2380
        mcsat_trace_printf(pre->tracer, "current_pre = ");
×
UNCOV
2381
        trace_term_ln(pre->tracer, terms, current_pre);
×
2382
      }
2383
    }
2384

2385
  }
2386

2387
  // Return the result
2388
  t_pre = preprocessor_get(pre, t);
38,248✔
2389
  if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,248✔
UNCOV
2390
    mcsat_trace_printf(pre->tracer, "t_pre = ");
×
UNCOV
2391
    trace_term_ln(pre->tracer, terms, t_pre);
×
2392
  }
2393

2394
  ivector_reset(pre_stack);
38,248✔
2395

2396
  assert(t_pre != NULL_TERM);
2397
  return t_pre;
38,248✔
2398
}
2399

2400
void preprocessor_tuple_blast(preprocessor_t* pre, term_t t, ivector_t* out) {
12✔
2401
  ivector_reset(out);
12✔
2402
  tuple_blast_term(pre, t);
12✔
2403
  tuple_blast_get(pre, t, out);
12✔
2404
}
12✔
2405

UNCOV
2406
void preprocessor_set_exception_handler(preprocessor_t* pre, jmp_buf* handler) {
×
UNCOV
2407
  pre->exception = handler;
×
UNCOV
2408
}
×
2409

2410
void preprocessor_push(preprocessor_t* pre) {
544✔
2411
  scope_holder_push(&pre->scope,
544✔
2412
      &pre->preprocess_map_list.size,
2413
      &pre->tuple_blast_list.size,
2414
      &pre->tuple_blast_data.size,
2415
      &pre->tuple_blast_atoms.size,
2416
      &pre->purification_map_list.size,
2417
      &pre->equalities_list.size,
2418
      NULL);
2419
}
544✔
2420

2421
void preprocessor_pop(preprocessor_t* pre) {
470✔
2422

2423
  uint32_t preprocess_map_list_size = 0;
470✔
2424
  uint32_t tuple_blast_list_size = 0;
470✔
2425
  uint32_t tuple_blast_data_size = 0;
470✔
2426
  uint32_t tuple_blast_atoms_size = 0;
470✔
2427
  uint32_t purification_map_list_size = 0;
470✔
2428
  uint32_t equalities_list_size = 0;
470✔
2429

2430
  scope_holder_pop(&pre->scope,
470✔
2431
      &preprocess_map_list_size,
2432
      &tuple_blast_list_size,
2433
      &tuple_blast_data_size,
2434
      &tuple_blast_atoms_size,
2435
      &purification_map_list_size,
2436
      &equalities_list_size,
2437
      NULL);
2438

2439
  while (pre->preprocess_map_list.size > preprocess_map_list_size) {
12,053✔
2440
    term_t t = ivector_last(&pre->preprocess_map_list);
11,583✔
2441
    ivector_pop(&pre->preprocess_map_list);
11,583✔
2442
    int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
11,583✔
2443
    assert(find != NULL);
2444
    int_hmap_erase(&pre->preprocess_map, find);
11,583✔
2445
  }
2446

2447
  while (pre->tuple_blast_list.size > tuple_blast_list_size) {
1,864✔
2448
    term_t t = ivector_last(&pre->tuple_blast_list);
1,394✔
2449
    ivector_pop(&pre->tuple_blast_list);
1,394✔
2450
    int_hmap_pair_t* find = int_hmap_find(&pre->tuple_blast_map, t);
1,394✔
2451
    assert(find != NULL);
2452
    int_hmap_erase(&pre->tuple_blast_map, find);
1,394✔
2453
  }
2454
  ivector_shrink(&pre->tuple_blast_data, tuple_blast_data_size);
470✔
2455
  ivector_shrink(&pre->tuple_blast_atoms, tuple_blast_atoms_size);
470✔
2456

2457
  while (pre->purification_map_list.size > purification_map_list_size) {
607✔
2458
    term_t t = ivector_last(&pre->purification_map_list);
137✔
2459
    ivector_pop(&pre->purification_map_list);
137✔
2460
    int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
137✔
2461
    assert(find != NULL);
2462
    int_hmap_erase(&pre->purification_map, find);
137✔
2463
  }
2464

2465
  while (pre->equalities_list.size > equalities_list_size) {
523✔
2466
    term_t eq = ivector_last(&pre->equalities_list);
53✔
2467
    ivector_pop(&pre->equalities_list);
53✔
2468
    int_hmap_pair_t* find = int_hmap_find(&pre->equalities, eq);
53✔
2469
    assert(find != NULL);
2470
    int_hmap_erase(&pre->equalities, find);
53✔
2471
  }
2472
}
470✔
2473

2474
static value_t merge_blasted_function_value(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* leaves, uint32_t nleaves);
2475

2476
static
2477
value_t build_value_from_flat(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* flat, uint32_t* idx) {
120✔
2478
  type_table_t* types = pre->terms->types;
120✔
2479

2480
  if (type_kind(types, tau) == TUPLE_TYPE) {
120✔
2481
    tuple_type_t* tuple = tuple_type_desc(types, tau);
39✔
2482
    uint32_t i, n = tuple->nelem;
39✔
2483
    value_t elem[n];
39✔
2484
    for (i = 0; i < n; ++i) {
119✔
2485
      elem[i] = build_value_from_flat(pre, vtbl, tuple->elem[i], flat, idx);
80✔
2486
      if (elem[i] == null_value) {
80✔
UNCOV
2487
        return null_value;
×
2488
      }
2489
    }
2490
    return vtbl_mk_tuple(vtbl, n, elem);
39✔
2491
  } else if (type_kind(types, tau) == FUNCTION_TYPE) {
81✔
2492
    uint32_t n = type_leaf_count(pre, tau);
3✔
2493
    value_t v = merge_blasted_function_value(pre, vtbl, tau, flat + *idx, n);
3✔
2494
    *idx += n;
3✔
2495
    return v;
3✔
2496
  } else {
2497
    value_t v = flat[*idx];
78✔
2498
    (*idx)++;
78✔
2499
    return v;
78✔
2500
  }
2501
}
2502

2503
static
2504
bool map_args_match(value_table_t* vtbl, value_t map, const value_t* args, uint32_t n) {
23✔
2505
  value_map_t* m = vtbl_map(vtbl, map);
23✔
2506
  uint32_t i;
2507
  if (m->arity != n) {
23✔
UNCOV
2508
    return false;
×
2509
  }
2510
  for (i = 0; i < n; ++i) {
48✔
2511
    if (m->arg[i] != args[i]) {
34✔
2512
      return false;
9✔
2513
    }
2514
  }
2515
  return true;
14✔
2516
}
2517

2518
static
2519
value_t find_map_result(value_table_t* vtbl, const ivector_t* maps, const value_t* args, uint32_t n, value_t def) {
19✔
2520
  uint32_t i;
2521
  for (i = 0; i < maps->size; ++i) {
28✔
2522
    value_t map = maps->data[i];
23✔
2523
    if (map_args_match(vtbl, map, args, n)) {
23✔
2524
      return vtbl_map(vtbl, map)->val;
14✔
2525
    }
2526
  }
2527
  return def;
5✔
2528
}
2529

2530
static
2531
void add_unique_flat_args(ivector_t* offsets, ivector_t* data, const value_t* args, uint32_t n) {
14✔
2532
  uint32_t i, j;
2533
  for (i = 0; i < offsets->size; ++i) {
18✔
2534
    uint32_t off = offsets->data[i];
9✔
2535
    bool same = true;
9✔
2536
    for (j = 0; j < n; ++j) {
18✔
2537
      if (data->data[off + j] != args[j]) {
13✔
2538
        same = false;
4✔
2539
        break;
4✔
2540
      }
2541
    }
2542
    if (same) {
9✔
2543
      return;
5✔
2544
    }
2545
  }
2546
  ivector_push(offsets, data->size);
9✔
2547
  ivector_add(data, args, n);
9✔
2548
}
2549

2550
static
2551
value_t merge_blasted_function_value(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* leaves, uint32_t nleaves) {
5✔
2552
  type_table_t* types = pre->terms->types;
5✔
2553
  function_type_t* fun = function_type_desc(types, tau);
5✔
2554
  type_t codom = fun->range;
5✔
2555
  uint32_t i, j;
2556
  ivector_t flat_dom;
2557
  ivector_t unique_offsets;
2558
  ivector_t unique_args;
2559
  ivector_t orig_maps;
2560
  value_t result = null_value;
5✔
2561
  value_t leaf_defaults[nleaves];
5✔
2562
  ivector_t leaf_maps[nleaves];
5✔
2563
  uint32_t flat_n;
2564
  uint32_t maps_init = 0;
5✔
2565
  /* Short tag describing why we bailed, so the caller (or a user
2566
   * investigating a missing model entry) can see the cause through a
2567
   * single line of trace output. Set immediately before each `goto done`
2568
   * error exit; the successful path leaves it NULL. */
2569
  const char* fail_reason = NULL;
5✔
2570

2571
  /* All heap-backed scratch vectors are initialized up-front so that every
2572
   * exit through the `done:` label has the same cleanup responsibilities.
2573
   * In particular orig_maps is deliberately initialized here rather than
2574
   * just before the loop that populates it: if its init moves, `goto done`
2575
   * paths that run before the init would otherwise silently leak the
2576
   * vector. Keeping the init paired with the other unconditional inits
2577
   * makes that invariant self-evident. */
2578
  init_ivector(&flat_dom, 0);
5✔
2579
  init_ivector(&unique_offsets, 0);
5✔
2580
  init_ivector(&unique_args, 0);
5✔
2581
  init_ivector(&orig_maps, 0);
5✔
2582

2583
  for (i = 0; i < fun->ndom; ++i) {
10✔
2584
    type_collect_flat(types, fun->domain[i], &flat_dom);
5✔
2585
  }
2586
  flat_n = flat_dom.size;
5✔
2587

2588
  for (i = 0; i < nleaves; ++i) {
15✔
2589
    value_t def = null_value;
10✔
2590
    type_t leaf_tau = NULL_TYPE;
10✔
2591
    init_ivector(&leaf_maps[i], 0);
10✔
2592
    maps_init = i + 1;
10✔
2593
    if (!object_is_function(vtbl, leaves[i]) && !object_is_update(vtbl, leaves[i])) {
10✔
UNCOV
2594
      fail_reason = "leaf value is neither a function nor an update object";
×
UNCOV
2595
      goto done;
×
2596
    }
2597
    if (object_is_update(vtbl, leaves[i])) {
10✔
2598
      vtbl_expand_update(vtbl, leaves[i], &def, &leaf_tau);
10✔
2599
      leaf_defaults[i] = def;
10✔
2600
      if (vtbl->hset1 != NULL) {
10✔
2601
        ivector_add(&leaf_maps[i], (int32_t*) vtbl->hset1->data, vtbl->hset1->nelems);
10✔
2602
        for (j = 0; j < vtbl->hset1->nelems; ++j) {
24✔
2603
          value_map_t* map = vtbl_map(vtbl, vtbl->hset1->data[j]);
14✔
2604
          if (map->arity != flat_n) {
14✔
UNCOV
2605
            fail_reason = "update leaf map arity does not match flattened domain";
×
UNCOV
2606
            goto done;
×
2607
          }
2608
          add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
14✔
2609
        }
2610
      }
2611
      continue;
10✔
2612
    }
UNCOV
2613
    value_fun_t* fun_value = vtbl_function(vtbl, leaves[i]);
×
UNCOV
2614
    def = fun_value->def;
×
UNCOV
2615
    leaf_tau = fun_value->type;
×
UNCOV
2616
    leaf_defaults[i] = def;
×
UNCOV
2617
    ivector_add(&leaf_maps[i], (int32_t*) fun_value->map, fun_value->map_size);
×
UNCOV
2618
    for (j = 0; j < fun_value->map_size; ++j) {
×
UNCOV
2619
      value_map_t* map = vtbl_map(vtbl, fun_value->map[j]);
×
UNCOV
2620
      if (map->arity != flat_n) {
×
UNCOV
2621
        fail_reason = "function leaf map arity does not match flattened domain";
×
UNCOV
2622
        goto done;
×
2623
      }
UNCOV
2624
      add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
×
2625
    }
2626
  }
2627

2628
  for (i = 0; i < unique_offsets.size; ++i) {
14✔
2629
    uint32_t flat_idx = unique_offsets.data[i];
9✔
2630
    const value_t* flat_args = (value_t*) (unique_args.data + flat_idx);
9✔
2631
    value_t leaf_values[nleaves];
9✔
2632
    uint32_t idx;
2633
    value_t mapv;
2634

2635
    for (j = 0; j < nleaves; ++j) {
28✔
2636
      leaf_values[j] = find_map_result(vtbl, &leaf_maps[j], flat_args, flat_n, leaf_defaults[j]);
19✔
2637
    }
2638

2639
    idx = 0;
9✔
2640
    value_t out_val = build_value_from_flat(pre, vtbl, codom, leaf_values, &idx);
9✔
2641
    if (out_val == null_value) {
9✔
UNCOV
2642
      fail_reason = "could not build codomain value from flat leaf values";
×
UNCOV
2643
      goto done;
×
2644
    }
2645

2646
    value_t args_orig[fun->ndom];
9✔
2647
    idx = 0;
9✔
2648
    for (j = 0; j < fun->ndom; ++j) {
18✔
2649
      args_orig[j] = build_value_from_flat(pre, vtbl, fun->domain[j], flat_args, &idx);
9✔
2650
      if (args_orig[j] == null_value) {
9✔
UNCOV
2651
        fail_reason = "could not rebuild a domain argument from flat leaf values";
×
UNCOV
2652
        goto done;
×
2653
      }
2654
    }
2655
    mapv = vtbl_mk_map(vtbl, fun->ndom, args_orig, out_val);
9✔
2656
    ivector_push(&orig_maps, mapv);
9✔
2657
  }
2658

2659
  {
2660
    uint32_t idx = 0;
5✔
2661
    value_t def_val = build_value_from_flat(pre, vtbl, codom, leaf_defaults, &idx);
5✔
2662
    if (def_val == null_value) {
5✔
UNCOV
2663
      fail_reason = "could not rebuild the function default value";
×
UNCOV
2664
      goto done;
×
2665
    }
2666
    result = vtbl_mk_function(vtbl, tau, orig_maps.size, (value_t*) orig_maps.data, def_val);
5✔
2667
  }
2668

2669
 done:
5✔
2670
  if (fail_reason != NULL && trace_enabled(pre->tracer, "mcsat::preprocess")) {
5✔
UNCOV
2671
    mcsat_trace_printf(pre->tracer,
×
2672
                       "merge_blasted_function_value: %s\n", fail_reason);
2673
  }
2674
  /* Single cleanup path for every error exit. All ivectors above are
2675
   * unconditionally initialized before any `goto done`, so unconditional
2676
   * deletes here are correct and stay correct if new error branches are
2677
   * added. leaf_maps is the only exception: its initialization is
2678
   * interleaved with error checks in the first loop, so we still only
2679
   * delete the prefix recorded by maps_init. */
2680
  for (i = 0; i < maps_init; ++i) {
15✔
2681
    delete_ivector(&leaf_maps[i]);
10✔
2682
  }
2683
  delete_ivector(&orig_maps);
5✔
2684
  delete_ivector(&unique_offsets);
5✔
2685
  delete_ivector(&unique_args);
5✔
2686
  delete_ivector(&flat_dom);
5✔
2687
  return result;
5✔
2688
}
2689

2690
static
2691
void preprocessor_build_tuple_model(preprocessor_t* pre, model_t* model) {
51✔
2692
  value_table_t* vtbl = model_get_vtbl(model);
51✔
2693
  type_table_t* types = pre->terms->types;
51✔
2694
  uint32_t i;
2695

2696
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
70✔
2697
    term_t atom = pre->tuple_blast_atoms.data[i];
19✔
2698
    ivector_t leaves;
2699
    type_t tau = term_type(pre->terms, atom);
19✔
2700
    uint32_t n, j;
2701

2702
    if (model_find_term_value(model, atom) != null_value) {
19✔
UNCOV
2703
      continue;
×
2704
    }
2705

2706
    init_ivector(&leaves, 0);
19✔
2707
    tuple_blast_get(pre, atom, &leaves);
19✔
2708
    n = leaves.size;
19✔
2709
    if (n == 0) {
19✔
UNCOV
2710
      delete_ivector(&leaves);
×
UNCOV
2711
      continue;
×
2712
    }
2713

2714
    value_t leaf_vals[n];
19✔
2715
    bool ok = true;
19✔
2716
    for (j = 0; j < n; ++j) {
62✔
2717
      term_t leaf = leaves.data[j];
43✔
2718
      value_t v = model_find_term_value(model, leaf);
43✔
2719
      if (v == null_value &&
43✔
2720
          (model->has_alias || term_kind(pre->terms, leaf) != UNINTERPRETED_TERM)) {
16✔
2721
        v = model_get_term_value(model, leaf);
15✔
2722
      }
2723
      if (v < 0) {
43✔
2724
        /* The blasted leaf was never assigned a value by the mcsat
2725
         * search (typical for unconstrained tuple components) and
2726
         * the model cannot synthesize a default for us -- this
2727
         * happens when keep_subst=0 disables the alias-based
2728
         * default-completion path in eval_uninterpreted. Fall back
2729
         * to a freshly minted default of the leaf's declared type
2730
         * so the original tuple atom can still be reconstructed.
2731
         * vtbl_make_object handles bool / arith / bv / tuple /
2732
         * function / scalar uniformly. */
2733
        type_t leaf_tau = term_type(pre->terms, leaf);
1✔
2734
        v = vtbl_make_object(vtbl, leaf_tau);
1✔
2735
        if (v < 0) {
1✔
UNCOV
2736
          ok = false;
×
UNCOV
2737
          break;
×
2738
        }
2739
      }
2740
      leaf_vals[j] = v;
43✔
2741
    }
2742
    if (!ok) {
19✔
2743
      /* vtbl_make_object failed for some leaf: the type cannot be
2744
       * inhabited concretely (extremely unusual -- e.g. a malformed
2745
       * type table entry). Drop the atom and trace which leaf index
2746
       * was the cause so a user investigating a missing (show-model)
2747
       * entry can pin the gap. */
UNCOV
2748
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
UNCOV
2749
        mcsat_trace_printf(pre->tracer,
×
2750
                           "preprocessor_build_tuple_model: dropping atom ");
UNCOV
2751
        trace_term_ln(pre->tracer, pre->terms, atom);
×
UNCOV
2752
        mcsat_trace_printf(pre->tracer,
×
2753
                           "  (vtbl_make_object failed for blasted leaf %u)\n", j);
2754
      }
UNCOV
2755
      delete_ivector(&leaves);
×
UNCOV
2756
      continue;
×
2757
    }
2758

2759
    if (type_kind(types, tau) == FUNCTION_TYPE) {
19✔
2760
      value_t f = merge_blasted_function_value(pre, vtbl, tau, leaf_vals, n);
2✔
2761
      if (f >= 0) {
2✔
2762
        model_map_term(model, atom, f);
2✔
UNCOV
2763
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
2764
        /* merge_blasted_function_value has already traced a reason code;
2765
         * complete the message here with the concrete atom identity. */
UNCOV
2766
        mcsat_trace_printf(pre->tracer,
×
2767
                           "preprocessor_build_tuple_model: dropping function atom ");
UNCOV
2768
        trace_term_ln(pre->tracer, pre->terms, atom);
×
2769
      }
2770
    } else {
2771
      uint32_t idx = 0;
17✔
2772
      value_t v = build_value_from_flat(pre, vtbl, tau, leaf_vals, &idx);
17✔
2773
      if (v >= 0) {
17✔
2774
        model_map_term(model, atom, v);
17✔
UNCOV
2775
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
UNCOV
2776
        mcsat_trace_printf(pre->tracer,
×
2777
                           "preprocessor_build_tuple_model: dropping tuple atom ");
UNCOV
2778
        trace_term_ln(pre->tracer, pre->terms, atom);
×
UNCOV
2779
        mcsat_trace_printf(pre->tracer,
×
2780
                           "  (leaf values did not decompose into a tuple value)\n");
2781
      }
2782
    }
2783

2784
    delete_ivector(&leaves);
19✔
2785
  }
2786
}
51✔
2787

2788
static term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx);
2789
static void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out);
2790

2791
static
UNCOV
2792
term_t merge_blasted_function_term(preprocessor_t* pre, type_t tau, const term_t* leaves, uint32_t nleaves) {
×
UNCOV
2793
  term_table_t* terms = pre->terms;
×
UNCOV
2794
  type_table_t* types = terms->types;
×
UNCOV
2795
  function_type_t* fun = function_type_desc(types, tau);
×
2796
  uint32_t i, idx;
UNCOV
2797
  term_t result = NULL_TERM;
×
UNCOV
2798
  term_t vars[fun->ndom];
×
2799
  ivector_t flat_args;
2800

2801
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2802
  assert(nleaves == type_leaf_count(pre, tau));
2803

UNCOV
2804
  for (i = 0; i < fun->ndom; ++i) {
×
UNCOV
2805
    vars[i] = new_variable(terms, fun->domain[i]);
×
2806
  }
2807

UNCOV
2808
  init_ivector(&flat_args, 0);
×
UNCOV
2809
  for (i = 0; i < fun->ndom; ++i) {
×
UNCOV
2810
    collect_flat_leaf_terms(pre, vars[i], fun->domain[i], &flat_args);
×
2811
  }
2812

UNCOV
2813
  term_t leaf_apps[nleaves];
×
UNCOV
2814
  for (i = 0; i < nleaves; ++i) {
×
UNCOV
2815
    leaf_apps[i] = mk_application(&pre->tm, leaves[i], flat_args.size, (term_t*) flat_args.data);
×
UNCOV
2816
    if (leaf_apps[i] == NULL_TERM) {
×
UNCOV
2817
      goto done;
×
2818
    }
2819
  }
2820

UNCOV
2821
  idx = 0;
×
UNCOV
2822
  term_t body = build_term_from_flat(pre, fun->range, leaf_apps, &idx);
×
UNCOV
2823
  if (body == NULL_TERM || idx != nleaves) {
×
UNCOV
2824
    goto done;
×
2825
  }
2826

UNCOV
2827
  result = mk_lambda(&pre->tm, fun->ndom, vars, body);
×
2828

UNCOV
2829
 done:
×
UNCOV
2830
  delete_ivector(&flat_args);
×
UNCOV
2831
  return result;
×
2832
}
2833

2834
static
2835
term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx) {
15✔
2836
  type_table_t* types = pre->terms->types;
15✔
2837
  switch (type_kind(types, tau)) {
15✔
2838
  case TUPLE_TYPE: {
3✔
2839
    tuple_type_t* tuple = tuple_type_desc(types, tau);
3✔
2840
    uint32_t i, n = tuple->nelem;
3✔
2841
    term_t elem[n];
3✔
2842
    for (i = 0; i < n; ++i) {
9✔
2843
      elem[i] = build_term_from_flat(pre, tuple->elem[i], flat, idx);
6✔
2844
      if (elem[i] == NULL_TERM) {
6✔
UNCOV
2845
        return NULL_TERM;
×
2846
      }
2847
    }
2848
    return mk_tuple(&pre->tm, n, elem);
3✔
2849
  }
2850

UNCOV
2851
  case FUNCTION_TYPE: {
×
UNCOV
2852
    uint32_t n = type_leaf_count(pre, tau);
×
UNCOV
2853
    term_t f = merge_blasted_function_term(pre, tau, flat + *idx, n);
×
UNCOV
2854
    *idx += n;
×
UNCOV
2855
    return f;
×
2856
  }
2857

2858
  default: {
12✔
2859
    term_t t = flat[*idx];
12✔
2860
    (*idx)++;
12✔
2861
    return t;
12✔
2862
  }
2863
  }
2864
}
2865

2866
static
2867
term_t mk_unblasted_function_leaf_lambda(preprocessor_t* pre, term_t atom, uint32_t leaf_i, type_t leaf_type) {
9✔
2868
  term_table_t* terms = pre->terms;
9✔
2869
  type_table_t* types = terms->types;
9✔
2870
  function_type_t* atom_fun = function_type_desc(types, term_type(terms, atom));
9✔
2871
  function_type_t* leaf_fun = function_type_desc(types, leaf_type);
9✔
2872
  uint32_t flat_n = leaf_fun->ndom;
9✔
2873
  uint32_t i, idx;
2874
  term_t flat_vars[flat_n];
9✔
2875
  term_t orig_args[atom_fun->ndom];
9✔
2876
  term_t app;
2877
  term_t body = NULL_TERM;
9✔
2878
  term_t result = NULL_TERM;
9✔
2879
  ivector_t codom_leaves;
2880

2881
  for (i = 0; i < flat_n; ++i) {
21✔
2882
    flat_vars[i] = new_variable(terms, leaf_fun->domain[i]);
12✔
2883
  }
2884

2885
  idx = 0;
9✔
2886
  for (i = 0; i < atom_fun->ndom; ++i) {
18✔
2887
    orig_args[i] = build_term_from_flat(pre, atom_fun->domain[i], flat_vars, &idx);
9✔
2888
    if (orig_args[i] == NULL_TERM) {
9✔
UNCOV
2889
      return NULL_TERM;
×
2890
    }
2891
  }
2892
  assert(idx == flat_n);
2893

2894
  app = mk_application(&pre->tm, atom, atom_fun->ndom, orig_args);
9✔
2895
  if (app == NULL_TERM) {
9✔
UNCOV
2896
    return NULL_TERM;
×
2897
  }
2898

2899
  init_ivector(&codom_leaves, 0);
9✔
2900
  collect_flat_leaf_terms(pre, app, atom_fun->range, &codom_leaves);
9✔
2901
  if (leaf_i < codom_leaves.size) {
9✔
2902
    body = codom_leaves.data[leaf_i];
9✔
2903
  }
2904
  if (body != NULL_TERM) {
9✔
2905
    result = mk_lambda(&pre->tm, flat_n, flat_vars, body);
9✔
2906
  }
2907
  delete_ivector(&codom_leaves);
9✔
2908

2909
  return result;
9✔
2910
}
2911

2912
static
2913
void collect_function_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
5✔
2914
  type_table_t* types = pre->terms->types;
5✔
2915
  ivector_t leaf_types;
2916
  uint32_t i;
2917

2918
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2919

2920
  init_ivector(&leaf_types, 0);
5✔
2921
  function_type_collect_blasted(types, tau, &leaf_types);
5✔
2922
  for (i = 0; i < leaf_types.size; ++i) {
14✔
2923
    term_t leaf = mk_unblasted_function_leaf_lambda(pre, base, i, leaf_types.data[i]);
9✔
2924
    if (leaf != NULL_TERM) {
9✔
2925
      ivector_push(out, leaf);
9✔
2926
    }
2927
  }
2928
  delete_ivector(&leaf_types);
5✔
2929
}
5✔
2930

2931
static
2932
void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
43✔
2933
  type_table_t* types = pre->terms->types;
43✔
2934

2935
  switch (type_kind(types, tau)) {
43✔
2936
  case TUPLE_TYPE: {
14✔
2937
    tuple_type_t* tuple = tuple_type_desc(types, tau);
14✔
2938
    uint32_t i;
2939
    for (i = 0; i < tuple->nelem; ++i) {
42✔
2940
      term_t child = mk_select(&pre->tm, i, base);
28✔
2941
      collect_flat_leaf_terms(pre, child, tuple->elem[i], out);
28✔
2942
    }
2943
    break;
14✔
2944
  }
2945

2946
  case FUNCTION_TYPE:
5✔
2947
    collect_function_leaf_terms(pre, base, tau, out);
5✔
2948
    break;
5✔
2949

2950
  default:
24✔
2951
    ivector_push(out, base);
24✔
2952
    break;
24✔
2953
  }
2954
}
43✔
2955

2956
static
2957
bool substitution_has_var(const ivector_t* vars, term_t x) {
16✔
2958
  uint32_t i;
2959
  for (i = 0; i < vars->size; ++i) {
39✔
2960
    if (vars->data[i] == x) {
23✔
UNCOV
2961
      return true;
×
2962
    }
2963
  }
2964
  return false;
16✔
2965
}
2966

2967
term_t preprocessor_unblast_term(preprocessor_t* pre, term_t t) {
45✔
2968
  term_table_t* terms = pre->terms;
45✔
2969
  ivector_t vars, maps;
2970
  ivector_t leaves, accessors;
2971
  uint32_t i, j;
2972
  term_t out;
2973

2974
  if (pre->tuple_blast_atoms.size == 0) {
45✔
2975
    return t;
40✔
2976
  }
2977

2978
  init_ivector(&vars, 0);
5✔
2979
  init_ivector(&maps, 0);
5✔
2980
  init_ivector(&leaves, 0);
5✔
2981
  init_ivector(&accessors, 0);
5✔
2982

2983
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
11✔
2984
    term_t atom = pre->tuple_blast_atoms.data[i];
6✔
2985
    type_t atom_type = term_type(terms, atom);
6✔
2986
    tuple_blast_get(pre, atom, &leaves);
6✔
2987
    ivector_reset(&accessors);
6✔
2988
    collect_flat_leaf_terms(pre, atom, atom_type, &accessors);
6✔
2989
    if (leaves.size != accessors.size) {
6✔
UNCOV
2990
      continue;
×
2991
    }
2992
    for (j = 0; j < leaves.size; ++j) {
22✔
2993
      term_t x = leaves.data[j];
16✔
2994
      term_t u = accessors.data[j];
16✔
2995
      term_kind_t k = term_kind(terms, x);
16✔
2996
      bool is_var = (k == UNINTERPRETED_TERM || k == VARIABLE);
16✔
2997
      if (x != u && is_var && !substitution_has_var(&vars, x)) {
16✔
2998
        ivector_push(&vars, x);
16✔
2999
        ivector_push(&maps, u);
16✔
3000
      }
3001
    }
3002
  }
3003

3004
  if (vars.size == 0) {
5✔
UNCOV
3005
    out = t;
×
3006
  } else {
3007
    term_subst_t subst;
3008
    init_term_subst(&subst, &pre->tm, vars.size, (term_t*) vars.data, (term_t*) maps.data);
5✔
3009
    out = apply_term_subst(&subst, t);
5✔
3010
    delete_term_subst(&subst);
5✔
3011
  }
3012

3013
  delete_ivector(&accessors);
5✔
3014
  delete_ivector(&leaves);
5✔
3015
  delete_ivector(&maps);
5✔
3016
  delete_ivector(&vars);
5✔
3017

3018
  return out;
5✔
3019
}
3020

3021
void preprocessor_build_model(preprocessor_t* pre, model_t* model) {
51✔
3022
  uint32_t i = 0;
51✔
3023
  /* Lazily-initialized evaluator used only on the keep_subst=0 path
3024
   * (model->has_alias is false). When keep_subst=1, this is never
3025
   * touched and the alias-based lazy resolution handles everything. */
3026
  evaluator_t eval;
3027
  bool eval_inited = false;
51✔
3028
  for (i = 0; i < pre->equalities_list.size; ++ i) {
69✔
3029
    term_t eq = pre->equalities_list.data[i];
18✔
3030
    term_t eq_var = preprocessor_get_eq_solved_var(pre, eq);
18✔
3031
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
18✔
UNCOV
3032
      mcsat_trace_printf(pre->tracer, "eq = ");
×
UNCOV
3033
      trace_term_ln(pre->tracer, pre->terms, eq);
×
UNCOV
3034
      mcsat_trace_printf(pre->tracer, "\neq_var = ");
×
UNCOV
3035
      trace_term_ln(pre->tracer, pre->terms, eq_var);
×
UNCOV
3036
      mcsat_trace_printf(pre->tracer, "\n");
×
3037
    }
3038
    // Some equalities are solved, but then reasserted in the solver
3039
    // these already have a model
3040
    if (model_find_term_value(model, eq_var) != null_value) {
18✔
UNCOV
3041
      continue;
×
3042
    }
3043
    // Some equalities are marked, but not solved. These we skip as they
3044
    // are already set in the model
3045
    if (preprocessor_get(pre, eq_var) == eq_var) {
18✔
UNCOV
3046
      continue;
×
3047
    }
3048
    term_kind_t eq_kind = term_kind(pre->terms, eq);
18✔
3049
    composite_term_t* eq_desc = get_composite(pre->terms, eq_kind, eq);
18✔
3050
    term_t eq_subst = eq_desc->arity > 1
36✔
3051
      ? (eq_desc->arg[0] == eq_var ? eq_desc->arg[1] : eq_desc->arg[0])
16✔
3052
      : zero_term;
34✔
3053
    if (model->has_alias) {
18✔
3054
      /* Standard path: record the substitution and let the model
3055
       * evaluator resolve eq_var lazily via eval_term(eq_subst). */
3056
      model_add_substitution(model, eq_var, eq_subst);
17✔
3057
    } else {
3058
      /* keep_subst=0 path: model has no alias table, so
3059
       * model_add_substitution would assert-fail on has_alias.
3060
       * Concretely evaluate eq_subst now and bind eq_var to that
3061
       * value. This is sound: eq_var was eliminated by the
3062
       * preprocessor via eq_var = eq_subst, so any model satisfying
3063
       * eq must agree. The user asked us not to keep substitutions,
3064
       * but they still need consistent values for downstream queries
3065
       * (in particular, tuple-blasted leaves -- see
3066
       * preprocessor_build_tuple_model below, which would otherwise
3067
       * silently drop tuple atoms whose leaves remain unmapped).
3068
       * If eval fails (e.g., eq_subst transitively depends on another
3069
       * not-yet-mapped eq_var), fall back to a fresh default value. */
3070
      if (!eval_inited) {
1✔
3071
        init_evaluator(&eval, model);
1✔
3072
        eval_inited = true;
1✔
3073
      }
3074
      value_t v = eval_in_model(&eval, eq_subst);
1✔
3075
      if (v < 0) {
1✔
UNCOV
3076
        type_t eq_var_tau = term_type(pre->terms, eq_var);
×
UNCOV
3077
        v = vtbl_make_object(model_get_vtbl(model), eq_var_tau);
×
3078
      }
3079
      if (v >= 0) {
1✔
3080
        model_map_term(model, eq_var, v);
1✔
UNCOV
3081
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
UNCOV
3082
        mcsat_trace_printf(pre->tracer,
×
3083
                           "preprocessor_build_model: failed to bind eq_var ");
UNCOV
3084
        trace_term_ln(pre->tracer, pre->terms, eq_var);
×
3085
      }
3086
    }
3087
  }
3088

3089
  if (eval_inited) {
51✔
3090
    delete_evaluator(&eval);
1✔
3091
  }
3092

3093
  preprocessor_build_tuple_model(pre, model);
51✔
3094
}
51✔
3095

3096

3097
static inline
3098
void preprocessor_gc_mark_term(preprocessor_t* pre, term_t t) {
1,548✔
3099
  term_table_set_gc_mark(pre->terms, index_of(t));
1,548✔
3100
  type_table_set_gc_mark(pre->terms->types, term_type(pre->terms, t));
1,548✔
3101
}
1,548✔
3102

3103
void preprocessor_gc_mark(preprocessor_t* pre) {
11✔
3104
  uint32_t i;
3105

3106
  /* Drop the type/term memoization caches before any GC sweep that may
3107
   * follow. These caches are keyed on raw type/term IDs (`tau` and
3108
   * `index_of(t)`), and Yices recycles those IDs for new types/terms once
3109
   * the originals are swept (see `indexed_table_free` under src/terms).
3110
   * If we left stale entries in place, a freshly recycled ID could pick up
3111
   * a cached classification that belongs to the freed term/type, which
3112
   * would then drive the iterative tuple-blast dispatch down the wrong
3113
   * arm. Clearing here is cheap (the caches repopulate on first use) and
3114
   * makes the "no invalidation needed for the lifetime of the table"
3115
   * comments on these caches actually true: each "lifetime" now ends at
3116
   * GC, where we reset.
3117
   *
3118
   * `tuple_blast_map`/`preprocess_map`/`purification_map` are kept --
3119
   * their entries are explicitly marked alive below, so they survive GC
3120
   * by construction. Only the *opportunistic* memos need to be dropped. */
3121
  int_hmap_reset(&pre->type_is_tuple_free_cache);
11✔
3122
  int_hmap_reset(&pre->type_leaf_count_cache);
11✔
3123
  int_hmap_reset(&pre->term_has_tuples_cache);
11✔
3124

3125
  for (i = 0; i < pre->preprocess_map_list.size; ++ i) {
612✔
3126
    term_t t = pre->preprocess_map_list.data[i];
601✔
3127
    preprocessor_gc_mark_term(pre, t);
601✔
3128
    term_t t_pre = preprocessor_get(pre, t);
601✔
3129
    preprocessor_gc_mark_term(pre, t_pre);
601✔
3130
  }
3131

3132
  for (i = 0; i < pre->equalities_list.size; ++ i) {
11✔
UNCOV
3133
    term_t t = pre->equalities_list.data[i];
×
UNCOV
3134
    preprocessor_gc_mark_term(pre, t);
×
3135
  }
3136

3137
  for (i = 0; i < pre->tuple_blast_list.size; ++i) {
165✔
3138
    term_t t = pre->tuple_blast_list.data[i];
154✔
3139
    int_hmap_pair_t* rec = int_hmap_find(&pre->tuple_blast_map, t);
154✔
3140
    uint32_t j, n, offset;
3141
    assert(rec != NULL);
3142
    preprocessor_gc_mark_term(pre, t);
154✔
3143
    offset = rec->val;
154✔
3144
    n = pre->tuple_blast_data.data[offset];
154✔
3145
    for (j = 0; j < n; ++j) {
308✔
3146
      preprocessor_gc_mark_term(pre, pre->tuple_blast_data.data[offset + 1 + j]);
154✔
3147
    }
3148
  }
3149

3150
  for (i = 0; i < pre->purification_map_list.size; ++ i) {
30✔
3151
    term_t t = pre->purification_map_list.data[i];
19✔
3152
    preprocessor_gc_mark_term(pre, t);
19✔
3153
    term_t t_pure = int_hmap_find(&pre->purification_map, t)->val;
19✔
3154
    preprocessor_gc_mark_term(pre, t_pure);
19✔
3155
  }
3156
}
11✔
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