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

SRI-CSL / yices2 / 25524988749

07 May 2026 10:13PM UTC coverage: 67.079% (+0.4%) from 66.687%
25524988749

Pull #606

github

disteph
tests: actually exercise ARITH_CEIL dispatch in tuple_unary_arith.ys

The previous header claimed the .ys file covered ARITH_CEIL alongside
ARITH_FLOOR / ARITH_IS_INT_ATOM / ARITH_ABS, but no ceil assertion was
present. The original assumption was that mcsat's nra plugin could not
solve any (= (ceil x) k) constraint and so ceil could only be reviewed
for dispatch by inspection.

That assumption is wrong: mcsat *does* route and answer ceil queries.
Separately, mcsat's nra plugin has a real semantic bug where (ceil x)
is treated like (floor x) for a range of rationals (e.g. it answers
sat for `(ceil 7/2) = 3` and unsat for `(ceil 7/2) = 4`). That bug is
unrelated to the tuple-blast dispatch fix in 9fefa45b and out of scope
for this PR.

So we add a deliberately *lax* ceil constraint over a tuple component
-- (<= (ceil (select x 2)) 100) -- which holds under both the correct
and the buggy interpretation. This exercises the ARITH_CEIL dispatch
arm end-to-end without depending on ceil's exact value, restoring the
header's accuracy. Update the matching note in mcsat_tuples.c to point
at the .ys file's header for the ceil-semantics caveat.
Pull Request #606: MCSAT: add support for tuples (incl. nested with function types); blasts tuples in input constraints + reconstitutes them in models and interpolants

784 of 1059 new or added lines in 3 files covered. (74.03%)

6 existing lines in 1 file now uncovered.

84648 of 126192 relevant lines covered (67.08%)

1641839.53 hits per line

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

81.46
/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) {
717✔
44
  pre->terms = terms;
717✔
45
  init_term_manager(&pre->tm, terms);
717✔
46
  init_int_hmap(&pre->preprocess_map, 0);
717✔
47
  init_ivector(&pre->preprocess_map_list, 0);
717✔
48
  init_int_hmap(&pre->tuple_blast_map, 0);
717✔
49
  init_ivector(&pre->tuple_blast_data, 0);
717✔
50
  init_ivector(&pre->tuple_blast_list, 0);
717✔
51
  init_ivector(&pre->tuple_blast_atoms, 0);
717✔
52
  init_int_hmap(&pre->type_is_tuple_free_cache, 0);
717✔
53
  init_int_hmap(&pre->type_leaf_count_cache, 0);
717✔
54
  init_int_hmap(&pre->term_has_tuples_cache, 0);
717✔
55
  init_int_hmap(&pre->purification_map, 0);
717✔
56
  init_ivector(&pre->purification_map_list, 0);
717✔
57
  init_ivector(&pre->preprocessing_stack, 0);
717✔
58
  init_int_hmap(&pre->equalities, 0);
717✔
59
  init_ivector(&pre->equalities_list, 0);
717✔
60
  pre->tracer = NULL;
717✔
61
  pre->exception = handler;
717✔
62
  pre->options = options;
717✔
63
  scope_holder_construct(&pre->scope);
717✔
64
}
717✔
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) {
717✔
71
  delete_int_hmap(&pre->purification_map);
717✔
72
  delete_ivector(&pre->purification_map_list);
717✔
73
  delete_int_hmap(&pre->tuple_blast_map);
717✔
74
  delete_ivector(&pre->tuple_blast_data);
717✔
75
  delete_ivector(&pre->tuple_blast_list);
717✔
76
  delete_ivector(&pre->tuple_blast_atoms);
717✔
77
  delete_int_hmap(&pre->type_is_tuple_free_cache);
717✔
78
  delete_int_hmap(&pre->type_leaf_count_cache);
717✔
79
  delete_int_hmap(&pre->term_has_tuples_cache);
717✔
80
  delete_int_hmap(&pre->preprocess_map);
717✔
81
  delete_ivector(&pre->preprocess_map_list);
717✔
82
  delete_ivector(&pre->preprocessing_stack);
717✔
83
  delete_int_hmap(&pre->equalities);
717✔
84
  delete_ivector(&pre->equalities_list);
717✔
85
  delete_term_manager(&pre->tm);
717✔
86
  scope_holder_destruct(&pre->scope);
717✔
87
}
717✔
88

89
static
90
term_t preprocessor_get(preprocessor_t* pre, term_t t) {
1,602,489✔
91
  int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
1,602,489✔
92
  if (find == NULL) {
1,602,489✔
93
    return NULL_TERM;
868,791✔
94
  } else {
95
    return find->val;
733,698✔
96
  }
97
}
98

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

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

113
  type_table_t* types = pre->terms->types;
2,064✔
114
  type_kind_t kind = type_kind(types, tau);
2,064✔
115
  uint32_t i;
116
  bool result;
117
  switch (kind) {
2,064✔
118
  case BOOL_TYPE:
1,819✔
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,819✔
126
    break;
1,819✔
127
  case TUPLE_TYPE:
42✔
128
    result = false;
42✔
129
    break;
42✔
130
  case FUNCTION_TYPE: {
203✔
131
    function_type_t* fun = function_type_desc(types, tau);
203✔
132
    result = type_is_tuple_free(pre, fun->range);
203✔
133
    for (i = 0; result && i < fun->ndom; ++i) {
473✔
134
      if (!type_is_tuple_free(pre, fun->domain[i])) {
270✔
135
        result = false;
3✔
136
      }
137
    }
138
    break;
203✔
139
  }
NEW
140
  default:
×
NEW
141
    result = false;
×
NEW
142
    break;
×
143
  }
144

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

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

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

175
  int_hmap_add(&pre->type_leaf_count_cache, tau, (int32_t) count);
72✔
176
  return count;
72✔
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) {
210✔
183
  tuple_type_t* tuple;
184
  uint32_t i;
185

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

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

198
  default:
134✔
199
    ivector_push(flat, tau);
134✔
200
    break;
134✔
201
  }
202
}
210✔
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) {
36✔
232
  switch (type_kind(types, tau)) {
36✔
233
  case TUPLE_TYPE:
32✔
234
    type_collect_flat(types, tau, out);
32✔
235
    break;
32✔
236
  case FUNCTION_TYPE:
4✔
237
    function_type_collect_blasted(types, tau, out);
4✔
238
    break;
4✔
NEW
239
  default:
×
NEW
240
    ivector_push(out, tau);
×
NEW
241
    break;
×
242
  }
243
}
36✔
244

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

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

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

265
static
266
void tuple_blast_get(preprocessor_t* pre, term_t t, ivector_t* out) {
39,888✔
267
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
39,888✔
268
  assert(rec != NULL);
269
  uint32_t offset = rec->val;
39,888✔
270
  uint32_t n = pre->tuple_blast_data.data[offset];
39,888✔
271
  ivector_reset(out);
39,888✔
272
  ivector_add(out, pre->tuple_blast_data.data + offset + 1, n);
39,888✔
273
}
39,888✔
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) {
324✔
289
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
324✔
290
  assert(rec != NULL);
291
  uint32_t offset = rec->val;
324✔
292
  *n_out = pre->tuple_blast_data.data[offset];
324✔
293
  *data_out = (const term_t*) (pre->tuple_blast_data.data + offset + 1);
324✔
294
}
324✔
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) {
410,703✔
312
  if (is_neg_term(t)) {
410,703✔
313
    ivector_push(out, unsigned_term(t));
41,542✔
314
    return;
41,542✔
315
  }
316

317
  term_table_t* terms = pre->terms;
369,161✔
318
  term_kind_t kind = term_kind(terms, t);
369,161✔
319
  uint32_t i;
320
  switch (kind) {
369,161✔
321
  case TUPLE_TERM: {
51✔
322
    composite_term_t* c = tuple_term_desc(terms, t);
51✔
323
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
153✔
324
    break;
51✔
325
  }
326
  case SELECT_TERM:
176✔
327
    ivector_push(out, select_term_desc(terms, t)->arg);
176✔
328
    break;
176✔
329
  case EQ_TERM: {
20,243✔
330
    composite_term_t* c = eq_term_desc(terms, t);
20,243✔
331
    ivector_push(out, c->arg[0]);
20,243✔
332
    ivector_push(out, c->arg[1]);
20,243✔
333
    break;
20,243✔
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,604✔
347
    composite_term_t* c = app_term_desc(terms, t);
4,604✔
348
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
15,100✔
349
    break;
4,604✔
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,666✔
357
    composite_term_t* c = or_term_desc(terms, t);
58,666✔
358
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
226,579✔
359
    break;
58,666✔
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,672✔
367
    pprod_t* pp = pprod_term_desc(terms, t);
1,672✔
368
    for (i = 0; i < pp->len; ++i) ivector_push(out, pp->prod[i].var);
5,311✔
369
    break;
1,672✔
370
  }
371
  case ARITH_POLY: {
6,719✔
372
    polynomial_t* p = poly_term_desc(terms, t);
6,719✔
373
    for (i = 0; i < p->nterms; ++i) {
26,184✔
374
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
19,465✔
375
    }
376
    break;
6,719✔
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,709✔
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,709✔
418
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
584,449✔
419
    break;
98,709✔
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:
2✔
433
    ivector_push(out, arith_ceil_arg(terms, t));
2✔
434
    break;
2✔
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,495✔
448
    /* Truly atomic kinds (CONSTANT_TERM, UNINTERPRETED_TERM, VARIABLE,
449
     * arithmetic/BV constants, etc.) have no children to blast first. */
450
    break;
40,495✔
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,431✔
462
  int32_t t_idx = index_of(t);
39,431✔
463
  int_hmap_pair_t* rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
39,431✔
464
  if (rec != NULL) {
39,431✔
465
    return rec->val != 0;
1,876✔
466
  }
467

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

473
  uint64_t safety = 0;
37,555✔
474
  while (stack.size > 0) {
520,280✔
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];
482,725✔
482
    int32_t cur_idx = index_of(current);
482,725✔
483
    int_hmap_pair_t* crec = int_hmap_find(&pre->term_has_tuples_cache, cur_idx);
482,725✔
484
    if (crec != NULL) {
482,725✔
485
      ivector_pop(&stack);
72,368✔
486
      continue;
197,429✔
487
    }
488

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

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

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

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

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

524
static
525
void tuple_blast_collect_arg(preprocessor_t* pre, term_t t, ivector_t* out) {
67✔
526
  const term_t* data;
527
  uint32_t n;
528
  tuple_blast_term(pre, t);
67✔
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);
67✔
533
  ivector_add(out, (int32_t*) data, n);
67✔
534
}
67✔
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) {
19✔
538
  assert(n > 0);
539
  if (n == 1) {
19✔
540
    return mk_eq(tm, a[0], b[0]);
2✔
541
  } else {
542
    ivector_t eqs;
543
    uint32_t i;
544
    init_ivector(&eqs, n);
17✔
545
    for (i = 0; i < n; ++i) {
52✔
546
      ivector_push(&eqs, mk_eq(tm, a[i], b[i]));
35✔
547
    }
548
    term_t result = mk_and(tm, eqs.size, eqs.data);
17✔
549
    delete_ivector(&eqs);
17✔
550
    return result;
17✔
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) {
263✔
563
  term_table_t* terms = pre->terms;
263✔
564
  type_table_t* types = terms->types;
263✔
565
  term_manager_t* tm = &pre->tm;
263✔
566

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

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

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

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

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

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

629
  case SELECT_TERM: {
67✔
630
    select_term_t* sel = select_term_desc(terms, t);
67✔
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);
67✔
636
    if (type_kind(types, arg_type) != TUPLE_TYPE) {
67✔
NEW
637
      delete_ivector(&result);
×
NEW
638
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
639
    }
640
    tuple_blast_term(pre, sel->arg);
67✔
641
    tuple_blast_peek(pre, sel->arg, &arg_data, &arg_n);
67✔
642
    tuple_type = tuple_type_desc(types, arg_type);
67✔
643
    start = 0;
67✔
644
    for (i = 0; i < sel->idx; ++i) {
101✔
645
      start += type_leaf_count(pre, tuple_type->elem[i]);
34✔
646
    }
647
    len = type_leaf_count(pre, tuple_type->elem[sel->idx]);
67✔
648
    if (start + len > arg_n) {
67✔
NEW
649
      delete_ivector(&result);
×
NEW
650
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
651
    }
652
    ivector_add(&result, (int32_t*) (arg_data + start), len);
67✔
653
    break;
67✔
654
  }
655

656
  case EQ_TERM: {
19✔
657
    composite_term_t* eq = eq_term_desc(terms, t);
19✔
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]);
19✔
664
    tuple_blast_term(pre, eq->arg[1]);
19✔
665
    tuple_blast_peek(pre, eq->arg[0], &lhs, &lhs_n);
19✔
666
    tuple_blast_peek(pre, eq->arg[1], &rhs, &rhs_n);
19✔
667
    if (lhs_n != rhs_n || lhs_n == 0) {
19✔
NEW
668
      delete_ivector(&result);
×
NEW
669
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
670
    }
671
    ivector_push(&result, tuple_blast_eq_vector(tm, lhs, rhs, lhs_n));
19✔
672
    break;
19✔
673
  }
674

NEW
675
  case DISTINCT_TERM: {
×
NEW
676
    composite_term_t* d = distinct_term_desc(terms, t);
×
677
    ivector_t conjuncts;
678
    uint32_t i, j;
NEW
679
    init_ivector(&conjuncts, 0);
×
NEW
680
    for (i = 0; i < d->arity; ++i) {
×
NEW
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. */
NEW
689
        tuple_blast_term(pre, d->arg[i]);
×
NEW
690
        tuple_blast_term(pre, d->arg[j]);
×
NEW
691
        tuple_blast_peek(pre, d->arg[i], &ti_data, &ti_n);
×
NEW
692
        tuple_blast_peek(pre, d->arg[j], &tj_data, &tj_n);
×
NEW
693
        if (ti_n != tj_n || ti_n == 0) {
×
NEW
694
          delete_ivector(&conjuncts);
×
NEW
695
          delete_ivector(&result);
×
NEW
696
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
697
        }
NEW
698
        init_ivector(&disj, ti_n);
×
NEW
699
        for (k = 0; k < ti_n; ++k) {
×
NEW
700
          ivector_push(&disj, opposite_term(mk_eq(tm, ti_data[k], tj_data[k])));
×
701
        }
NEW
702
        ivector_push(&conjuncts, mk_or(tm, disj.size, disj.data));
×
NEW
703
        delete_ivector(&disj);
×
704
      }
705
    }
NEW
706
    ivector_push(&result, mk_and(tm, conjuncts.size, conjuncts.data));
×
NEW
707
    delete_ivector(&conjuncts);
×
NEW
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✔
NEW
729
      delete_ivector(&result);
×
NEW
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✔
NEW
735
        delete_ivector(&result);
×
NEW
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✔
NEW
741
        c_data[0] == ite->arg[0] &&
×
NEW
742
        t_data[0] == ite->arg[1] &&
×
NEW
743
        e_data[0] == ite->arg[2]) {
×
NEW
744
      ivector_reset(&result);
×
NEW
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✔
NEW
765
      changed = args_flat.data[i - 1] != app->arg[i];
×
766
    }
767
    if (!changed) {
13✔
NEW
768
      ivector_push(&result, t);
×
NEW
769
      delete_ivector(&args_flat);
×
NEW
770
      delete_ivector(&f_blast);
×
NEW
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✔
NEW
776
        delete_ivector(&args_flat);
×
NEW
777
        delete_ivector(&f_blast);
×
NEW
778
        delete_ivector(&result);
×
NEW
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

NEW
788
  case UPDATE_TERM: {
×
NEW
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;
NEW
795
    tuple_blast_term(pre, upd->arg[0]);
×
NEW
796
    init_ivector(&f_blast, 0);
×
NEW
797
    tuple_blast_get(pre, upd->arg[0], &f_blast);
×
NEW
798
    init_ivector(&idx_flat, 0);
×
NEW
799
    for (i = 1; i + 1 < upd->arity; ++i) {
×
NEW
800
      tuple_blast_collect_arg(pre, upd->arg[i], &idx_flat);
×
801
    }
NEW
802
    tuple_blast_term(pre, upd->arg[upd->arity - 1]);
×
NEW
803
    init_ivector(&v_blast, 0);
×
NEW
804
    tuple_blast_get(pre, upd->arg[upd->arity - 1], &v_blast);
×
NEW
805
    if (v_blast.size != 1 && v_blast.size != f_blast.size) {
×
NEW
806
      delete_ivector(&f_blast);
×
NEW
807
      delete_ivector(&idx_flat);
×
NEW
808
      delete_ivector(&v_blast);
×
NEW
809
      delete_ivector(&result);
×
NEW
810
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
811
    }
NEW
812
    changed = f_blast.size != 1 || f_blast.data[0] != upd->arg[0] || idx_flat.size != upd->arity - 2 ||
×
NEW
813
              v_blast.size != 1 || v_blast.data[0] != upd->arg[upd->arity - 1];
×
NEW
814
    for (i = 1; !changed && i + 1 < upd->arity; ++i) {
×
NEW
815
      changed = idx_flat.data[i - 1] != upd->arg[i];
×
816
    }
NEW
817
    if (!changed) {
×
NEW
818
      ivector_push(&result, t);
×
NEW
819
      delete_ivector(&f_blast);
×
NEW
820
      delete_ivector(&idx_flat);
×
NEW
821
      delete_ivector(&v_blast);
×
NEW
822
      break;
×
823
    }
NEW
824
    for (i = 0; i < f_blast.size; ++i) {
×
NEW
825
      term_t vi = v_blast.size == 1 ? v_blast.data[0] : v_blast.data[i];
×
NEW
826
      term_t upd_i = mk_update(tm, f_blast.data[i], idx_flat.size, idx_flat.data, vi);
×
NEW
827
      if (upd_i == NULL_TERM) {
×
NEW
828
        delete_ivector(&f_blast);
×
NEW
829
        delete_ivector(&idx_flat);
×
NEW
830
        delete_ivector(&v_blast);
×
NEW
831
        delete_ivector(&result);
×
NEW
832
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
833
      }
NEW
834
      ivector_push(&result, upd_i);
×
835
    }
NEW
836
    delete_ivector(&f_blast);
×
NEW
837
    delete_ivector(&idx_flat);
×
NEW
838
    delete_ivector(&v_blast);
×
NEW
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✔
NEW
854
        delete_ivector(&args);
×
NEW
855
        delete_ivector(&result);
×
NEW
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✔
NEW
877
        delete_ivector(&result);
×
NEW
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: {
15✔
888
    polynomial_t* p = poly_term_desc(terms, t);
15✔
889
    term_t args[p->nterms];
15✔
890
    uint32_t i;
891
    bool changed = false;
15✔
892

893
    for (i = 0; i < p->nterms; ++i) {
47✔
894
      term_t x = p->mono[i].var;
32✔
895
      if (x == const_idx) {
32✔
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);
19✔
901
        tuple_blast_peek(pre, x, &child_data, &child_n);
19✔
902
        if (child_n != 1) {
19✔
NEW
903
          delete_ivector(&result);
×
NEW
904
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
905
        }
906
        args[i] = child_data[0];
19✔
907
        changed |= args[i] != x;
19✔
908
      }
909
    }
910
    ivector_push(&result, changed ? mk_arith_poly(tm, p, p->nterms, args) : t);
15✔
911
    break;
15✔
912
  }
913

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

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

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

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

996
  case ARITH_EQ_ATOM:
49✔
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: {
49✔
1014
    composite_term_t* c = get_composite(terms, kind, t);
49✔
1015
    term_t args[c->arity];
49✔
1016
    uint32_t i;
1017
    bool changed = false;
49✔
1018

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

1032
    term_t rebuilt = changed ? mk_composite(pre, kind, c->arity, args) : t;
49✔
1033
    if (rebuilt == NULL_TERM) {
49✔
NEW
1034
      delete_ivector(&result);
×
NEW
1035
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1036
    }
1037
    ivector_push(&result, rebuilt);
49✔
1038
    break;
49✔
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✔
NEW
1058
      delete_ivector(&result);
×
NEW
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✔
NEW
1064
      delete_ivector(&result);
×
NEW
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✔
NEW
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✔
NEW
1087
      delete_ivector(&result);
×
NEW
1088
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1089
    }
1090
    term_t rebuilt;
1091
    if (child_data[0] == arg) {
4✔
NEW
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✔
NEW
1099
      default: assert(false); rebuilt = NULL_TERM;
×
1100
      }
1101
    }
1102
    if (rebuilt == NULL_TERM) {
4✔
NEW
1103
      delete_ivector(&result);
×
NEW
1104
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1105
    }
1106
    ivector_push(&result, rebuilt);
4✔
1107
    break;
4✔
1108
  }
NEW
1109
  case ARITH_FF_EQ_ATOM: {
×
NEW
1110
    term_t arg = arith_ff_eq_arg(terms, t);
×
1111
    const term_t* child_data;
1112
    uint32_t child_n;
NEW
1113
    tuple_blast_term(pre, arg);
×
NEW
1114
    tuple_blast_peek(pre, arg, &child_data, &child_n);
×
NEW
1115
    if (child_n != 1) {
×
NEW
1116
      delete_ivector(&result);
×
NEW
1117
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1118
    }
NEW
1119
    term_t rebuilt = (child_data[0] == arg) ? t :
×
NEW
1120
                     mk_arith_ff_term_eq0(&pre->tm, child_data[0]);
×
NEW
1121
    if (rebuilt == NULL_TERM) {
×
NEW
1122
      delete_ivector(&result);
×
NEW
1123
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1124
    }
NEW
1125
    ivector_push(&result, rebuilt);
×
NEW
1126
    break;
×
1127
  }
NEW
1128
  case ARITH_FF_BINEQ_ATOM: {
×
NEW
1129
    composite_term_t* c = arith_ff_bineq_atom_desc(terms, t);
×
1130
    term_t args[2];
NEW
1131
    bool changed = false;
×
1132
    uint32_t i;
NEW
1133
    for (i = 0; i < 2; ++i) {
×
1134
      const term_t* child_data;
1135
      uint32_t child_n;
NEW
1136
      tuple_blast_term(pre, c->arg[i]);
×
NEW
1137
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
×
NEW
1138
      if (child_n != 1) {
×
NEW
1139
        delete_ivector(&result);
×
NEW
1140
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1141
      }
NEW
1142
      args[i] = child_data[0];
×
NEW
1143
      changed |= args[i] != c->arg[i];
×
1144
    }
NEW
1145
    term_t rebuilt = changed ? mk_arith_ff_eq(&pre->tm, args[0], args[1]) : t;
×
NEW
1146
    if (rebuilt == NULL_TERM) {
×
NEW
1147
      delete_ivector(&result);
×
NEW
1148
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1149
    }
NEW
1150
    ivector_push(&result, rebuilt);
×
NEW
1151
    break;
×
1152
  }
1153

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

1159
  tuple_blast_set(pre, t, &result);
245✔
1160
  delete_ivector(&result);
245✔
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,189✔
1176
  if (tuple_blast_done(pre, t)) {
40,189✔
1177
    return;
40,102✔
1178
  }
1179

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

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

1193
  uint64_t safety = 0;
87✔
1194
  while (stack.size > 0) {
600✔
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];
513✔
1201

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

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

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

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

1234
  delete_ivector(&stack);
87✔
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,484✔
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,484✔
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,747✔
1256
    return eq_term_desc(terms, t);
20,747✔
1257
  case OR_TERM:            // n-ary OR
62,216✔
1258
    return or_term_desc(terms, t);
62,216✔
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,902✔
1262
    return arith_bineq_atom_desc(terms, t);
7,902✔
1263
  case ARITH_EQ_ATOM: {
7,272✔
1264
    composite_for_noncomposite.arity = 1;
7,272✔
1265
    composite_for_noncomposite.arg[0] = arith_eq_arg(terms, t);
7,272✔
1266
    return (composite_term_t*)&composite_for_noncomposite;
7,272✔
1267
  }
1268
  case ARITH_GE_ATOM: {
16,242✔
1269
    composite_for_noncomposite.arity = 1;
16,242✔
1270
    composite_for_noncomposite.arg[0] = arith_ge_arg(terms, t);
16,242✔
1271
    return (composite_term_t*)&composite_for_noncomposite;
16,242✔
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,841✔
1281
    return app_term_desc(terms, t);
5,841✔
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,830✔
1311
    return bveq_atom_desc(terms, t);
118,830✔
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✔
1316
  default:
×
1317
    assert(false);
1318
    return NULL;
×
1319
  }
1320
}
1321

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

1325
  switch (type_kind(types, tau)) {
24,784✔
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

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

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

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

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

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

1373
  switch (kind) {
46,631✔
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:
430✔
1394
    assert(n == 1);
1395
    return mk_arith_geq(tm, children[0], zero_term);
430✔
1396
  case ARITH_BINEQ_ATOM:   // equality: (t1 == t2)  (between two arithmetic terms)
255✔
1397
    assert(n == 2);
1398
    return mk_arith_eq(tm, children[0], children[1]);
255✔
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✔
1423
  case BV_SDIV:
×
1424
    assert(n == 2);
1425
    return mk_bvsdiv(tm, children[0], children[1]);
×
1426
  case BV_SREM:
×
1427
    assert(n == 2);
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,485✔
1442
    assert(n == 2);
1443
    return mk_bveq(tm, children[0], children[1]);
6,485✔
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✔
1450
  default:
×
1451
    assert(false);
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,847✔
1462

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

1465
  // Negated terms must be purified
1466
  if (is_pos_term(t)) {
52,847✔
1467
    // We don't purify variables
1468
    switch (term_kind(terms, t)) {
17,081✔
1469
    case UNINTERPRETED_TERM:
10,825✔
1470
      // Variables are already pure
1471
      return t;
10,825✔
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,176✔
1486
      break;
1,176✔
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,942✔
1492
  if (find != NULL) {
36,942✔
1493
    return find->val;
36,376✔
1494
  } else {
1495
    // Make the variable
1496
    type_t t_type = term_type(terms, t);
566✔
1497
    term_t x = new_uninterpreted_term(terms, t_type);
566✔
1498
    // Remember for later
1499
    int_hmap_add(&pre->purification_map, t, x);
566✔
1500
    ivector_push(&pre->purification_map_list, t);
566✔
1501
    // Also add the variable to the pre-processor
1502
    preprocessor_set(pre, x, x);
566✔
1503
    // Add equality to output
1504
    term_t eq = mk_eq(&pre->tm, x, t);
566✔
1505
    ivector_push(out, eq);
566✔
1506

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

1512
    // Return the purified version
1513
    return x;
566✔
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,867✔
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,867✔
1542
  assert(find->val == -1);
1543
  find->val = var;
24,867✔
1544
  ivector_push(&pre->equalities_list, eq);
24,867✔
1545
}
24,867✔
1546

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

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

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

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

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

1576
  // Check if already preprocessed;
1577
  term_t t_pre = preprocessor_get(pre, t);
39,852✔
1578
  if (t_pre != NULL_TERM) {
39,852✔
1579
    return t_pre;
1,649✔
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,203✔
1597
  ivector_reset(pre_stack);
38,203✔
1598
  ivector_push(pre_stack, t);
38,203✔
1599

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

1605
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
468,016✔
1606
      mcsat_trace_printf(pre->tracer, "current = ");
×
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,016✔
1612
    if (current_pre != NULL_TERM) {
468,016✔
1613
      ivector_pop(pre_stack);
31,304✔
1614
      continue;
31,304✔
1615
    }
1616

1617
    // Negation
1618
    if (is_neg_term(current)) {
436,712✔
1619
      term_t child = unsigned_term(current);
88,962✔
1620
      term_t child_pre = preprocessor_get(pre, child);
88,962✔
1621
      if (child_pre == NULL_TERM) {
88,962✔
1622
        ivector_push(pre_stack, child);
42,011✔
1623
        continue;
42,011✔
1624
      } else {
1625
        ivector_pop(pre_stack);
46,951✔
1626
        current_pre = opposite_term(child_pre);
46,951✔
1627
        preprocessor_set(pre, current, current_pre);
46,951✔
1628
        continue;
46,951✔
1629
      }
1630
    }
1631

1632
    // Check for supported types
1633
    type_kind_t type = term_type_kind(terms, current);
347,750✔
1634
    switch (type) {
347,750✔
1635
    case BOOL_TYPE:
347,750✔
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,750✔
1644
    default:
×
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,750✔
1650

1651
    switch(current_kind) {
347,750✔
1652
    case CONSTANT_TERM:    // constant of uninterpreted/scalar/boolean types
1,836✔
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,836✔
1658
      break;
1,836✔
1659

1660
    case UNINTERPRETED_TERM:  // (i.e., global variables, can't be bound).
14,063✔
1661
      current_pre = current;
14,063✔
1662
      // Unless we want special slicing
1663
      if (type == BITVECTOR_TYPE) {
14,063✔
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,063✔
1686

1687
    case ITE_TERM:           // if-then-else
181,457✔
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,457✔
1708
      bool children_done = true;
181,457✔
1709
      bool children_same = true;
181,457✔
1710

1711
      n = desc->arity;
181,457✔
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,457✔
1717
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
8✔
1718
      }
1719

1720
      // Is this a top-level equality assertion
1721
      bool is_equality =
181,449✔
1722
          current_kind == EQ_TERM ||
160,710✔
1723
          current_kind == BV_EQ_ATOM ||
103,651✔
1724
          current_kind == ARITH_EQ_ATOM ||
99,891✔
1725
          current_kind == ARITH_BINEQ_ATOM ||
95,735✔
1726
          current_kind == ARITH_FF_EQ_ATOM ||
342,159✔
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,449✔
1730

1731
      term_t eq_solve_var = NULL_TERM;
181,449✔
1732
      if (is_assertion && is_equality && !is_boolean) {
181,449✔
1733
        bool is_lhs_rhs_mixed = desc->arity > 1 &&
139,549✔
1734
          term_type_kind(pre->terms, desc->arg[0]) != term_type_kind(pre->terms, desc->arg[1]);
67,817✔
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,732✔
1737
          eq_solve_var = preprocessor_get_eq_solved_var(pre, t);
47,683✔
1738
          if (eq_solve_var == NULL_TERM) {
47,683✔
1739
            term_t lhs = desc->arg[0];
27,698✔
1740
            term_kind_t lhs_kind = term_kind(terms, lhs);
27,698✔
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,698✔
1743
            if (lhs_is_var && preprocessor_get(pre, lhs) == NULL_TERM) {
27,698✔
1744
              // First time variable, let's solve
1745
              preprocessor_mark_eq(pre, t, lhs);
24,589✔
1746
              eq_solve_var = lhs;
24,589✔
1747
            } else if (desc->arity > 1) {
3,109✔
1748
              term_t rhs = desc->arg[1];
2,341✔
1749
              term_kind_t rhs_kind = term_kind(terms, rhs);
2,341✔
1750
              bool rhs_is_var = rhs_kind == UNINTERPRETED_TERM && is_pos_term(rhs);
2,341✔
1751
              if (rhs_is_var && preprocessor_get(pre, rhs) == NULL_TERM) {
2,341✔
1752
                // First time variable, let's solve
1753
                preprocessor_mark_eq(pre, t, rhs);
276✔
1754
                eq_solve_var = rhs;
276✔
1755
              }
1756
            }
1757
          } else {
1758
            // Check that we it's not there already
1759
            if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
19,985✔
1760
              eq_solve_var = NULL_TERM;
51✔
1761
            }
1762
          }
1763
        }
1764
      }
1765

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

1769
      for (i = 0; i < n; ++ i) {
605,177✔
1770
        term_t child = desc->arg[i];
423,728✔
1771
        if (child != eq_solve_var) {
423,728✔
1772
          term_t child_pre = preprocessor_get(pre, child);
378,929✔
1773
          if (child_pre == NULL_TERM) {
378,929✔
1774
            children_done = false;
108,619✔
1775
            ivector_push(pre_stack, child);
108,619✔
1776
          } else if (child_pre != child) {
270,310✔
1777
            children_same = false;
106,070✔
1778
          }
1779
          if (children_done) {
378,929✔
1780
            ivector_push(&children, child_pre);
256,466✔
1781
          }
1782
        }
1783
      }
1784

1785
      if (eq_solve_var != NULL_TERM) {
181,449✔
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,799✔
1788
          // Do it again
1789
          children_done = false;
×
1790
        }
1791
      }
1792

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

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

1812
      break;
181,449✔
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✔
1984
            mcsat_trace_printf(pre->tracer, "arg_pre = ");
×
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,675✔
2076
    {
2077
      pprod_t* pp = pprod_term_desc(terms, current);
1,675✔
2078
      bool children_done = true;
1,675✔
2079
      bool children_same = true;
1,675✔
2080

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

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

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

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

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

2100
      if (children_done) {
1,675✔
2101
        if (children_same) {
1,339✔
2102
          current_pre = current;
1,281✔
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,675✔
2110

2111
      break;
1,675✔
2112
    }
2113

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

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

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

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

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

2130
        if (x_pre != const_idx) {
19,943✔
2131
          if (x_pre == NULL_TERM) {
16,908✔
2132
            children_done = false;
2,572✔
2133
            ivector_push(pre_stack, x);
2,572✔
2134
          } else if (x_pre != x) {
14,336✔
2135
            children_same = false;
949✔
2136
          }
2137
        }
2138

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

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

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

2152
      break;
6,947✔
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✔
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 {
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,666✔
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,666✔
2206
      bool children_done = true;
8,666✔
2207
      bool children_same = true;
8,666✔
2208

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

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

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

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

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

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

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

2241
      break;
8,666✔
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 {
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:        // floor: purify, but its interpreted
1✔
2288
    {
2289
      term_t child = arith_ceil_arg(terms, current);
1✔
2290
      term_t child_pre = preprocessor_get(pre, child);
1✔
2291

2292
      if (child_pre != NULL_TERM) {
1✔
2293
        child_pre = preprocessor_purify(pre, child_pre, out);
1✔
2294
        if (child_pre != child) {
1✔
2295
          current_pre = arith_floor(terms, child_pre);
1✔
2296
        } else {
2297
          current_pre = current;
×
2298
        }
2299
      } else {
2300
        ivector_push(pre_stack, child);
×
2301
      }
2302

2303
      break;
1✔
2304
    }
2305

2306
    case DISTINCT_TERM:
27✔
2307
    {
2308
      composite_term_t* desc = get_composite(terms, current_kind, current);
27✔
2309

2310
      bool children_done = true;
27✔
2311
      n = desc->arity;
27✔
2312

2313
      // DISTINCT_TERM is lowered below into pairwise disequalities. Apply the
2314
      // same function-sort guard before that expansion.
2315
      for (i = 0; i < n; ++ i) {
125✔
2316
        if (term_needs_function_diseq_guard(terms, desc->arg[i])) {
101✔
2317
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
3✔
2318
        }
2319
      }
2320

2321
      ivector_t children;
2322
      init_ivector(&children, n);
24✔
2323

2324
      for (i = 0; i < n; ++ i) {
122✔
2325
        term_t child = desc->arg[i];
98✔
2326
        term_t child_pre = preprocessor_get(pre, child);
98✔
2327

2328
        if (child_pre == NULL_TERM) {
98✔
2329
          children_done = false;
41✔
2330
          ivector_push(pre_stack, child);
41✔
2331
        }
2332

2333
        if (children_done) { ivector_push(&children, child_pre); }
98✔
2334
      }
2335

2336
      if (children_done) {
24✔
2337
        ivector_t distinct;
2338
        init_ivector(&distinct, 0);
14✔
2339

2340
        for (i = 0; i < n; ++ i) {
70✔
2341
          for (j = i + 1; j < n; ++ j) {
148✔
2342
            term_t neq = mk_eq(&pre->tm, children.data[i], children.data[j]);
92✔
2343
            neq = opposite_term(neq);
92✔
2344
            ivector_push(&distinct, neq);
92✔
2345
          }
2346
        }
2347
        current_pre = mk_and(&pre->tm, distinct.size, distinct.data);
14✔
2348

2349
        delete_ivector(&distinct);
14✔
2350
      }
2351

2352
      delete_ivector(&children);
24✔
2353

2354
      break;
24✔
2355
    }
2356

2357
    case LAMBDA_TERM:
×
2358
      longjmp(*pre->exception, LAMBDAS_NOT_SUPPORTED);
×
2359
      break;
2360

2361
    default:
×
2362
      // UNSUPPORTED TERM/THEORY
2363
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
2364
      break;
2365
    }
2366

2367
    if (current_pre != NULL_TERM) {
347,739✔
2368
      preprocessor_set(pre, current, current_pre);
264,204✔
2369
      ivector_pop(pre_stack);
264,204✔
2370
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
264,204✔
2371
        mcsat_trace_printf(pre->tracer, "current_pre = ");
×
2372
        trace_term_ln(pre->tracer, terms, current_pre);
×
2373
      }
2374
    }
2375

2376
  }
2377

2378
  // Return the result
2379
  t_pre = preprocessor_get(pre, t);
38,192✔
2380
  if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,192✔
2381
    mcsat_trace_printf(pre->tracer, "t_pre = ");
×
2382
    trace_term_ln(pre->tracer, terms, t_pre);
×
2383
  }
2384

2385
  ivector_reset(pre_stack);
38,192✔
2386

2387
  assert(t_pre != NULL_TERM);
2388
  return t_pre;
38,192✔
2389
}
2390

2391
void preprocessor_set_exception_handler(preprocessor_t* pre, jmp_buf* handler) {
×
2392
  pre->exception = handler;
×
2393
}
×
2394

2395
void preprocessor_push(preprocessor_t* pre) {
529✔
2396
  scope_holder_push(&pre->scope,
529✔
2397
      &pre->preprocess_map_list.size,
2398
      &pre->tuple_blast_list.size,
2399
      &pre->tuple_blast_data.size,
2400
      &pre->tuple_blast_atoms.size,
2401
      &pre->purification_map_list.size,
2402
      &pre->equalities_list.size,
2403
      NULL);
2404
}
529✔
2405

2406
void preprocessor_pop(preprocessor_t* pre) {
455✔
2407

2408
  uint32_t preprocess_map_list_size = 0;
455✔
2409
  uint32_t tuple_blast_list_size = 0;
455✔
2410
  uint32_t tuple_blast_data_size = 0;
455✔
2411
  uint32_t tuple_blast_atoms_size = 0;
455✔
2412
  uint32_t purification_map_list_size = 0;
455✔
2413
  uint32_t equalities_list_size = 0;
455✔
2414

2415
  scope_holder_pop(&pre->scope,
455✔
2416
      &preprocess_map_list_size,
2417
      &tuple_blast_list_size,
2418
      &tuple_blast_data_size,
2419
      &tuple_blast_atoms_size,
2420
      &purification_map_list_size,
2421
      &equalities_list_size,
2422
      NULL);
2423

2424
  while (pre->preprocess_map_list.size > preprocess_map_list_size) {
11,959✔
2425
    term_t t = ivector_last(&pre->preprocess_map_list);
11,504✔
2426
    ivector_pop(&pre->preprocess_map_list);
11,504✔
2427
    int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
11,504✔
2428
    assert(find != NULL);
2429
    int_hmap_erase(&pre->preprocess_map, find);
11,504✔
2430
  }
2431

2432
  while (pre->tuple_blast_list.size > tuple_blast_list_size) {
1,821✔
2433
    term_t t = ivector_last(&pre->tuple_blast_list);
1,366✔
2434
    ivector_pop(&pre->tuple_blast_list);
1,366✔
2435
    int_hmap_pair_t* find = int_hmap_find(&pre->tuple_blast_map, t);
1,366✔
2436
    assert(find != NULL);
2437
    int_hmap_erase(&pre->tuple_blast_map, find);
1,366✔
2438
  }
2439
  ivector_shrink(&pre->tuple_blast_data, tuple_blast_data_size);
455✔
2440
  ivector_shrink(&pre->tuple_blast_atoms, tuple_blast_atoms_size);
455✔
2441

2442
  while (pre->purification_map_list.size > purification_map_list_size) {
590✔
2443
    term_t t = ivector_last(&pre->purification_map_list);
135✔
2444
    ivector_pop(&pre->purification_map_list);
135✔
2445
    int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
135✔
2446
    assert(find != NULL);
2447
    int_hmap_erase(&pre->purification_map, find);
135✔
2448
  }
2449

2450
  while (pre->equalities_list.size > equalities_list_size) {
505✔
2451
    term_t eq = ivector_last(&pre->equalities_list);
50✔
2452
    ivector_pop(&pre->equalities_list);
50✔
2453
    int_hmap_pair_t* find = int_hmap_find(&pre->equalities, eq);
50✔
2454
    assert(find != NULL);
2455
    int_hmap_erase(&pre->equalities, find);
50✔
2456
  }
2457
}
455✔
2458

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

2461
static
2462
value_t build_value_from_flat(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* flat, uint32_t* idx) {
117✔
2463
  type_table_t* types = pre->terms->types;
117✔
2464

2465
  if (type_kind(types, tau) == TUPLE_TYPE) {
117✔
2466
    tuple_type_t* tuple = tuple_type_desc(types, tau);
38✔
2467
    uint32_t i, n = tuple->nelem;
38✔
2468
    value_t elem[n];
38✔
2469
    for (i = 0; i < n; ++i) {
116✔
2470
      elem[i] = build_value_from_flat(pre, vtbl, tuple->elem[i], flat, idx);
78✔
2471
      if (elem[i] == null_value) {
78✔
NEW
2472
        return null_value;
×
2473
      }
2474
    }
2475
    return vtbl_mk_tuple(vtbl, n, elem);
38✔
2476
  } else if (type_kind(types, tau) == FUNCTION_TYPE) {
79✔
2477
    uint32_t n = type_leaf_count(pre, tau);
3✔
2478
    value_t v = merge_blasted_function_value(pre, vtbl, tau, flat + *idx, n);
3✔
2479
    *idx += n;
3✔
2480
    return v;
3✔
2481
  } else {
2482
    value_t v = flat[*idx];
76✔
2483
    (*idx)++;
76✔
2484
    return v;
76✔
2485
  }
2486
}
2487

2488
static
2489
bool map_args_match(value_table_t* vtbl, value_t map, const value_t* args, uint32_t n) {
23✔
2490
  value_map_t* m = vtbl_map(vtbl, map);
23✔
2491
  uint32_t i;
2492
  if (m->arity != n) {
23✔
NEW
2493
    return false;
×
2494
  }
2495
  for (i = 0; i < n; ++i) {
48✔
2496
    if (m->arg[i] != args[i]) {
34✔
2497
      return false;
9✔
2498
    }
2499
  }
2500
  return true;
14✔
2501
}
2502

2503
static
2504
value_t find_map_result(value_table_t* vtbl, const ivector_t* maps, const value_t* args, uint32_t n, value_t def) {
19✔
2505
  uint32_t i;
2506
  for (i = 0; i < maps->size; ++i) {
28✔
2507
    value_t map = maps->data[i];
23✔
2508
    if (map_args_match(vtbl, map, args, n)) {
23✔
2509
      return vtbl_map(vtbl, map)->val;
14✔
2510
    }
2511
  }
2512
  return def;
5✔
2513
}
2514

2515
static
2516
void add_unique_flat_args(ivector_t* offsets, ivector_t* data, const value_t* args, uint32_t n) {
14✔
2517
  uint32_t i, j;
2518
  for (i = 0; i < offsets->size; ++i) {
18✔
2519
    uint32_t off = offsets->data[i];
9✔
2520
    bool same = true;
9✔
2521
    for (j = 0; j < n; ++j) {
18✔
2522
      if (data->data[off + j] != args[j]) {
13✔
2523
        same = false;
4✔
2524
        break;
4✔
2525
      }
2526
    }
2527
    if (same) {
9✔
2528
      return;
5✔
2529
    }
2530
  }
2531
  ivector_push(offsets, data->size);
9✔
2532
  ivector_add(data, args, n);
9✔
2533
}
2534

2535
static
2536
value_t merge_blasted_function_value(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* leaves, uint32_t nleaves) {
5✔
2537
  type_table_t* types = pre->terms->types;
5✔
2538
  function_type_t* fun = function_type_desc(types, tau);
5✔
2539
  type_t codom = fun->range;
5✔
2540
  uint32_t i, j;
2541
  ivector_t flat_dom;
2542
  ivector_t unique_offsets;
2543
  ivector_t unique_args;
2544
  ivector_t orig_maps;
2545
  value_t result = null_value;
5✔
2546
  value_t leaf_defaults[nleaves];
5✔
2547
  ivector_t leaf_maps[nleaves];
5✔
2548
  uint32_t flat_n;
2549
  uint32_t maps_init = 0;
5✔
2550
  /* Short tag describing why we bailed, so the caller (or a user
2551
   * investigating a missing model entry) can see the cause through a
2552
   * single line of trace output. Set immediately before each `goto done`
2553
   * error exit; the successful path leaves it NULL. */
2554
  const char* fail_reason = NULL;
5✔
2555

2556
  /* All heap-backed scratch vectors are initialized up-front so that every
2557
   * exit through the `done:` label has the same cleanup responsibilities.
2558
   * In particular orig_maps is deliberately initialized here rather than
2559
   * just before the loop that populates it: if its init moves, `goto done`
2560
   * paths that run before the init would otherwise silently leak the
2561
   * vector. Keeping the init paired with the other unconditional inits
2562
   * makes that invariant self-evident. */
2563
  init_ivector(&flat_dom, 0);
5✔
2564
  init_ivector(&unique_offsets, 0);
5✔
2565
  init_ivector(&unique_args, 0);
5✔
2566
  init_ivector(&orig_maps, 0);
5✔
2567

2568
  for (i = 0; i < fun->ndom; ++i) {
10✔
2569
    type_collect_flat(types, fun->domain[i], &flat_dom);
5✔
2570
  }
2571
  flat_n = flat_dom.size;
5✔
2572

2573
  for (i = 0; i < nleaves; ++i) {
15✔
2574
    value_t def = null_value;
10✔
2575
    type_t leaf_tau = NULL_TYPE;
10✔
2576
    init_ivector(&leaf_maps[i], 0);
10✔
2577
    maps_init = i + 1;
10✔
2578
    if (!object_is_function(vtbl, leaves[i]) && !object_is_update(vtbl, leaves[i])) {
10✔
NEW
2579
      fail_reason = "leaf value is neither a function nor an update object";
×
NEW
2580
      goto done;
×
2581
    }
2582
    if (object_is_update(vtbl, leaves[i])) {
10✔
2583
      vtbl_expand_update(vtbl, leaves[i], &def, &leaf_tau);
10✔
2584
      leaf_defaults[i] = def;
10✔
2585
      if (vtbl->hset1 != NULL) {
10✔
2586
        ivector_add(&leaf_maps[i], (int32_t*) vtbl->hset1->data, vtbl->hset1->nelems);
10✔
2587
        for (j = 0; j < vtbl->hset1->nelems; ++j) {
24✔
2588
          value_map_t* map = vtbl_map(vtbl, vtbl->hset1->data[j]);
14✔
2589
          if (map->arity != flat_n) {
14✔
NEW
2590
            fail_reason = "update leaf map arity does not match flattened domain";
×
NEW
2591
            goto done;
×
2592
          }
2593
          add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
14✔
2594
        }
2595
      }
2596
      continue;
10✔
2597
    }
NEW
2598
    value_fun_t* fun_value = vtbl_function(vtbl, leaves[i]);
×
NEW
2599
    def = fun_value->def;
×
NEW
2600
    leaf_tau = fun_value->type;
×
NEW
2601
    leaf_defaults[i] = def;
×
NEW
2602
    ivector_add(&leaf_maps[i], (int32_t*) fun_value->map, fun_value->map_size);
×
NEW
2603
    for (j = 0; j < fun_value->map_size; ++j) {
×
NEW
2604
      value_map_t* map = vtbl_map(vtbl, fun_value->map[j]);
×
NEW
2605
      if (map->arity != flat_n) {
×
NEW
2606
        fail_reason = "function leaf map arity does not match flattened domain";
×
NEW
2607
        goto done;
×
2608
      }
NEW
2609
      add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
×
2610
    }
2611
  }
2612

2613
  for (i = 0; i < unique_offsets.size; ++i) {
14✔
2614
    uint32_t flat_idx = unique_offsets.data[i];
9✔
2615
    const value_t* flat_args = (value_t*) (unique_args.data + flat_idx);
9✔
2616
    value_t leaf_values[nleaves];
9✔
2617
    uint32_t idx;
2618
    value_t mapv;
2619

2620
    for (j = 0; j < nleaves; ++j) {
28✔
2621
      leaf_values[j] = find_map_result(vtbl, &leaf_maps[j], flat_args, flat_n, leaf_defaults[j]);
19✔
2622
    }
2623

2624
    idx = 0;
9✔
2625
    value_t out_val = build_value_from_flat(pre, vtbl, codom, leaf_values, &idx);
9✔
2626
    if (out_val == null_value) {
9✔
NEW
2627
      fail_reason = "could not build codomain value from flat leaf values";
×
NEW
2628
      goto done;
×
2629
    }
2630

2631
    value_t args_orig[fun->ndom];
9✔
2632
    idx = 0;
9✔
2633
    for (j = 0; j < fun->ndom; ++j) {
18✔
2634
      args_orig[j] = build_value_from_flat(pre, vtbl, fun->domain[j], flat_args, &idx);
9✔
2635
      if (args_orig[j] == null_value) {
9✔
NEW
2636
        fail_reason = "could not rebuild a domain argument from flat leaf values";
×
NEW
2637
        goto done;
×
2638
      }
2639
    }
2640
    mapv = vtbl_mk_map(vtbl, fun->ndom, args_orig, out_val);
9✔
2641
    ivector_push(&orig_maps, mapv);
9✔
2642
  }
2643

2644
  {
2645
    uint32_t idx = 0;
5✔
2646
    value_t def_val = build_value_from_flat(pre, vtbl, codom, leaf_defaults, &idx);
5✔
2647
    if (def_val == null_value) {
5✔
NEW
2648
      fail_reason = "could not rebuild the function default value";
×
NEW
2649
      goto done;
×
2650
    }
2651
    result = vtbl_mk_function(vtbl, tau, orig_maps.size, (value_t*) orig_maps.data, def_val);
5✔
2652
  }
2653

2654
 done:
5✔
2655
  if (fail_reason != NULL && trace_enabled(pre->tracer, "mcsat::preprocess")) {
5✔
NEW
2656
    mcsat_trace_printf(pre->tracer,
×
2657
                       "merge_blasted_function_value: %s\n", fail_reason);
2658
  }
2659
  /* Single cleanup path for every error exit. All ivectors above are
2660
   * unconditionally initialized before any `goto done`, so unconditional
2661
   * deletes here are correct and stay correct if new error branches are
2662
   * added. leaf_maps is the only exception: its initialization is
2663
   * interleaved with error checks in the first loop, so we still only
2664
   * delete the prefix recorded by maps_init. */
2665
  for (i = 0; i < maps_init; ++i) {
15✔
2666
    delete_ivector(&leaf_maps[i]);
10✔
2667
  }
2668
  delete_ivector(&orig_maps);
5✔
2669
  delete_ivector(&unique_offsets);
5✔
2670
  delete_ivector(&unique_args);
5✔
2671
  delete_ivector(&flat_dom);
5✔
2672
  return result;
5✔
2673
}
2674

2675
static
2676
void preprocessor_build_tuple_model(preprocessor_t* pre, model_t* model) {
48✔
2677
  value_table_t* vtbl = model_get_vtbl(model);
48✔
2678
  type_table_t* types = pre->terms->types;
48✔
2679
  uint32_t i;
2680

2681
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
66✔
2682
    term_t atom = pre->tuple_blast_atoms.data[i];
18✔
2683
    ivector_t leaves;
2684
    type_t tau = term_type(pre->terms, atom);
18✔
2685
    uint32_t n, j;
2686

2687
    if (model_find_term_value(model, atom) != null_value) {
18✔
NEW
2688
      continue;
×
2689
    }
2690

2691
    init_ivector(&leaves, 0);
18✔
2692
    tuple_blast_get(pre, atom, &leaves);
18✔
2693
    n = leaves.size;
18✔
2694
    if (n == 0) {
18✔
NEW
2695
      delete_ivector(&leaves);
×
NEW
2696
      continue;
×
2697
    }
2698

2699
    value_t leaf_vals[n];
18✔
2700
    bool ok = true;
18✔
2701
    for (j = 0; j < n; ++j) {
59✔
2702
      value_t v = model_get_term_value(model, leaves.data[j]);
41✔
2703
      if (v < 0) {
41✔
2704
        /* The blasted leaf was never assigned a value by the mcsat
2705
         * search (typical for unconstrained tuple components) and
2706
         * the model cannot synthesize a default for us -- this
2707
         * happens when keep_subst=0 disables the alias-based
2708
         * default-completion path in eval_uninterpreted. Fall back
2709
         * to a freshly minted default of the leaf's declared type
2710
         * so the original tuple atom can still be reconstructed.
2711
         * vtbl_make_object handles bool / arith / bv / tuple /
2712
         * function / scalar uniformly. */
2713
        type_t leaf_tau = term_type(pre->terms, leaves.data[j]);
1✔
2714
        v = vtbl_make_object(vtbl, leaf_tau);
1✔
2715
        if (v < 0) {
1✔
NEW
2716
          ok = false;
×
NEW
2717
          break;
×
2718
        }
2719
      }
2720
      leaf_vals[j] = v;
41✔
2721
    }
2722
    if (!ok) {
18✔
2723
      /* vtbl_make_object failed for some leaf: the type cannot be
2724
       * inhabited concretely (extremely unusual -- e.g. a malformed
2725
       * type table entry). Drop the atom and trace which leaf index
2726
       * was the cause so a user investigating a missing (show-model)
2727
       * entry can pin the gap. */
NEW
2728
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2729
        mcsat_trace_printf(pre->tracer,
×
2730
                           "preprocessor_build_tuple_model: dropping atom ");
NEW
2731
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2732
        mcsat_trace_printf(pre->tracer,
×
2733
                           "  (vtbl_make_object failed for blasted leaf %u)\n", j);
2734
      }
NEW
2735
      delete_ivector(&leaves);
×
NEW
2736
      continue;
×
2737
    }
2738

2739
    if (type_kind(types, tau) == FUNCTION_TYPE) {
18✔
2740
      value_t f = merge_blasted_function_value(pre, vtbl, tau, leaf_vals, n);
2✔
2741
      if (f >= 0) {
2✔
2742
        model_map_term(model, atom, f);
2✔
NEW
2743
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
2744
        /* merge_blasted_function_value has already traced a reason code;
2745
         * complete the message here with the concrete atom identity. */
NEW
2746
        mcsat_trace_printf(pre->tracer,
×
2747
                           "preprocessor_build_tuple_model: dropping function atom ");
NEW
2748
        trace_term_ln(pre->tracer, pre->terms, atom);
×
2749
      }
2750
    } else {
2751
      uint32_t idx = 0;
16✔
2752
      value_t v = build_value_from_flat(pre, vtbl, tau, leaf_vals, &idx);
16✔
2753
      if (v >= 0) {
16✔
2754
        model_map_term(model, atom, v);
16✔
NEW
2755
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2756
        mcsat_trace_printf(pre->tracer,
×
2757
                           "preprocessor_build_tuple_model: dropping tuple atom ");
NEW
2758
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2759
        mcsat_trace_printf(pre->tracer,
×
2760
                           "  (leaf values did not decompose into a tuple value)\n");
2761
      }
2762
    }
2763

2764
    delete_ivector(&leaves);
18✔
2765
  }
2766
}
48✔
2767

2768
static term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx);
2769
static void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out);
2770

2771
static
NEW
2772
term_t merge_blasted_function_term(preprocessor_t* pre, type_t tau, const term_t* leaves, uint32_t nleaves) {
×
NEW
2773
  term_table_t* terms = pre->terms;
×
NEW
2774
  type_table_t* types = terms->types;
×
NEW
2775
  function_type_t* fun = function_type_desc(types, tau);
×
2776
  uint32_t i, idx;
NEW
2777
  term_t result = NULL_TERM;
×
NEW
2778
  term_t vars[fun->ndom];
×
2779
  ivector_t flat_args;
2780

2781
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2782
  assert(nleaves == type_leaf_count(pre, tau));
2783

NEW
2784
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2785
    vars[i] = new_variable(terms, fun->domain[i]);
×
2786
  }
2787

NEW
2788
  init_ivector(&flat_args, 0);
×
NEW
2789
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2790
    collect_flat_leaf_terms(pre, vars[i], fun->domain[i], &flat_args);
×
2791
  }
2792

NEW
2793
  term_t leaf_apps[nleaves];
×
NEW
2794
  for (i = 0; i < nleaves; ++i) {
×
NEW
2795
    leaf_apps[i] = mk_application(&pre->tm, leaves[i], flat_args.size, (term_t*) flat_args.data);
×
NEW
2796
    if (leaf_apps[i] == NULL_TERM) {
×
NEW
2797
      goto done;
×
2798
    }
2799
  }
2800

NEW
2801
  idx = 0;
×
NEW
2802
  term_t body = build_term_from_flat(pre, fun->range, leaf_apps, &idx);
×
NEW
2803
  if (body == NULL_TERM || idx != nleaves) {
×
NEW
2804
    goto done;
×
2805
  }
2806

NEW
2807
  result = mk_lambda(&pre->tm, fun->ndom, vars, body);
×
2808

NEW
2809
 done:
×
NEW
2810
  delete_ivector(&flat_args);
×
NEW
2811
  return result;
×
2812
}
2813

2814
static
2815
term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx) {
15✔
2816
  type_table_t* types = pre->terms->types;
15✔
2817
  switch (type_kind(types, tau)) {
15✔
2818
  case TUPLE_TYPE: {
3✔
2819
    tuple_type_t* tuple = tuple_type_desc(types, tau);
3✔
2820
    uint32_t i, n = tuple->nelem;
3✔
2821
    term_t elem[n];
3✔
2822
    for (i = 0; i < n; ++i) {
9✔
2823
      elem[i] = build_term_from_flat(pre, tuple->elem[i], flat, idx);
6✔
2824
      if (elem[i] == NULL_TERM) {
6✔
NEW
2825
        return NULL_TERM;
×
2826
      }
2827
    }
2828
    return mk_tuple(&pre->tm, n, elem);
3✔
2829
  }
2830

NEW
2831
  case FUNCTION_TYPE: {
×
NEW
2832
    uint32_t n = type_leaf_count(pre, tau);
×
NEW
2833
    term_t f = merge_blasted_function_term(pre, tau, flat + *idx, n);
×
NEW
2834
    *idx += n;
×
NEW
2835
    return f;
×
2836
  }
2837

2838
  default: {
12✔
2839
    term_t t = flat[*idx];
12✔
2840
    (*idx)++;
12✔
2841
    return t;
12✔
2842
  }
2843
  }
2844
}
2845

2846
static
2847
term_t mk_unblasted_function_leaf_lambda(preprocessor_t* pre, term_t atom, uint32_t leaf_i, type_t leaf_type) {
9✔
2848
  term_table_t* terms = pre->terms;
9✔
2849
  type_table_t* types = terms->types;
9✔
2850
  function_type_t* atom_fun = function_type_desc(types, term_type(terms, atom));
9✔
2851
  function_type_t* leaf_fun = function_type_desc(types, leaf_type);
9✔
2852
  uint32_t flat_n = leaf_fun->ndom;
9✔
2853
  uint32_t i, idx;
2854
  term_t flat_vars[flat_n];
9✔
2855
  term_t orig_args[atom_fun->ndom];
9✔
2856
  term_t app;
2857
  term_t body = NULL_TERM;
9✔
2858
  term_t result = NULL_TERM;
9✔
2859
  ivector_t codom_leaves;
2860

2861
  for (i = 0; i < flat_n; ++i) {
21✔
2862
    flat_vars[i] = new_variable(terms, leaf_fun->domain[i]);
12✔
2863
  }
2864

2865
  idx = 0;
9✔
2866
  for (i = 0; i < atom_fun->ndom; ++i) {
18✔
2867
    orig_args[i] = build_term_from_flat(pre, atom_fun->domain[i], flat_vars, &idx);
9✔
2868
    if (orig_args[i] == NULL_TERM) {
9✔
NEW
2869
      return NULL_TERM;
×
2870
    }
2871
  }
2872
  assert(idx == flat_n);
2873

2874
  app = mk_application(&pre->tm, atom, atom_fun->ndom, orig_args);
9✔
2875
  if (app == NULL_TERM) {
9✔
NEW
2876
    return NULL_TERM;
×
2877
  }
2878

2879
  init_ivector(&codom_leaves, 0);
9✔
2880
  collect_flat_leaf_terms(pre, app, atom_fun->range, &codom_leaves);
9✔
2881
  if (leaf_i < codom_leaves.size) {
9✔
2882
    body = codom_leaves.data[leaf_i];
9✔
2883
  }
2884
  if (body != NULL_TERM) {
9✔
2885
    result = mk_lambda(&pre->tm, flat_n, flat_vars, body);
9✔
2886
  }
2887
  delete_ivector(&codom_leaves);
9✔
2888

2889
  return result;
9✔
2890
}
2891

2892
static
2893
void collect_function_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
5✔
2894
  type_table_t* types = pre->terms->types;
5✔
2895
  ivector_t leaf_types;
2896
  uint32_t i;
2897

2898
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2899

2900
  init_ivector(&leaf_types, 0);
5✔
2901
  function_type_collect_blasted(types, tau, &leaf_types);
5✔
2902
  for (i = 0; i < leaf_types.size; ++i) {
14✔
2903
    term_t leaf = mk_unblasted_function_leaf_lambda(pre, base, i, leaf_types.data[i]);
9✔
2904
    if (leaf != NULL_TERM) {
9✔
2905
      ivector_push(out, leaf);
9✔
2906
    }
2907
  }
2908
  delete_ivector(&leaf_types);
5✔
2909
}
5✔
2910

2911
static
2912
void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
40✔
2913
  type_table_t* types = pre->terms->types;
40✔
2914

2915
  switch (type_kind(types, tau)) {
40✔
2916
  case TUPLE_TYPE: {
13✔
2917
    tuple_type_t* tuple = tuple_type_desc(types, tau);
13✔
2918
    uint32_t i;
2919
    for (i = 0; i < tuple->nelem; ++i) {
39✔
2920
      term_t child = mk_select(&pre->tm, i, base);
26✔
2921
      collect_flat_leaf_terms(pre, child, tuple->elem[i], out);
26✔
2922
    }
2923
    break;
13✔
2924
  }
2925

2926
  case FUNCTION_TYPE:
5✔
2927
    collect_function_leaf_terms(pre, base, tau, out);
5✔
2928
    break;
5✔
2929

2930
  default:
22✔
2931
    ivector_push(out, base);
22✔
2932
    break;
22✔
2933
  }
2934
}
40✔
2935

2936
static
2937
bool substitution_has_var(const ivector_t* vars, term_t x) {
14✔
2938
  uint32_t i;
2939
  for (i = 0; i < vars->size; ++i) {
36✔
2940
    if (vars->data[i] == x) {
22✔
NEW
2941
      return true;
×
2942
    }
2943
  }
2944
  return false;
14✔
2945
}
2946

2947
term_t preprocessor_unblast_term(preprocessor_t* pre, term_t t) {
44✔
2948
  term_table_t* terms = pre->terms;
44✔
2949
  ivector_t vars, maps;
2950
  ivector_t leaves, accessors;
2951
  uint32_t i, j;
2952
  term_t out;
2953

2954
  if (pre->tuple_blast_atoms.size == 0) {
44✔
2955
    return t;
40✔
2956
  }
2957

2958
  init_ivector(&vars, 0);
4✔
2959
  init_ivector(&maps, 0);
4✔
2960
  init_ivector(&leaves, 0);
4✔
2961
  init_ivector(&accessors, 0);
4✔
2962

2963
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
9✔
2964
    term_t atom = pre->tuple_blast_atoms.data[i];
5✔
2965
    type_t atom_type = term_type(terms, atom);
5✔
2966
    tuple_blast_get(pre, atom, &leaves);
5✔
2967
    ivector_reset(&accessors);
5✔
2968
    collect_flat_leaf_terms(pre, atom, atom_type, &accessors);
5✔
2969
    if (leaves.size != accessors.size) {
5✔
NEW
2970
      continue;
×
2971
    }
2972
    for (j = 0; j < leaves.size; ++j) {
19✔
2973
      term_t x = leaves.data[j];
14✔
2974
      term_t u = accessors.data[j];
14✔
2975
      term_kind_t k = term_kind(terms, x);
14✔
2976
      bool is_var = (k == UNINTERPRETED_TERM || k == VARIABLE);
14✔
2977
      if (x != u && is_var && !substitution_has_var(&vars, x)) {
14✔
2978
        ivector_push(&vars, x);
14✔
2979
        ivector_push(&maps, u);
14✔
2980
      }
2981
    }
2982
  }
2983

2984
  if (vars.size == 0) {
4✔
NEW
2985
    out = t;
×
2986
  } else {
2987
    term_subst_t subst;
2988
    init_term_subst(&subst, &pre->tm, vars.size, (term_t*) vars.data, (term_t*) maps.data);
4✔
2989
    out = apply_term_subst(&subst, t);
4✔
2990
    delete_term_subst(&subst);
4✔
2991
  }
2992

2993
  delete_ivector(&accessors);
4✔
2994
  delete_ivector(&leaves);
4✔
2995
  delete_ivector(&maps);
4✔
2996
  delete_ivector(&vars);
4✔
2997

2998
  return out;
4✔
2999
}
3000

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

3069
  if (eval_inited) {
48✔
3070
    delete_evaluator(&eval);
1✔
3071
  }
3072

3073
  preprocessor_build_tuple_model(pre, model);
48✔
3074
}
48✔
3075

3076

3077
static inline
3078
void preprocessor_gc_mark_term(preprocessor_t* pre, term_t t) {
1,272✔
3079
  term_table_set_gc_mark(pre->terms, index_of(t));
1,272✔
3080
  type_table_set_gc_mark(pre->terms->types, term_type(pre->terms, t));
1,272✔
3081
}
1,272✔
3082

3083
void preprocessor_gc_mark(preprocessor_t* pre) {
5✔
3084
  uint32_t i;
3085

3086
  /* Drop the type/term memoization caches before any GC sweep that may
3087
   * follow. These caches are keyed on raw type/term IDs (`tau` and
3088
   * `index_of(t)`), and Yices recycles those IDs for new types/terms once
3089
   * the originals are swept (see `indexed_table_free` under src/terms).
3090
   * If we left stale entries in place, a freshly recycled ID could pick up
3091
   * a cached classification that belongs to the freed term/type, which
3092
   * would then drive the iterative tuple-blast dispatch down the wrong
3093
   * arm. Clearing here is cheap (the caches repopulate on first use) and
3094
   * makes the "no invalidation needed for the lifetime of the table"
3095
   * comments on these caches actually true: each "lifetime" now ends at
3096
   * GC, where we reset.
3097
   *
3098
   * `tuple_blast_map`/`preprocess_map`/`purification_map` are kept --
3099
   * their entries are explicitly marked alive below, so they survive GC
3100
   * by construction. Only the *opportunistic* memos need to be dropped. */
3101
  int_hmap_reset(&pre->type_is_tuple_free_cache);
5✔
3102
  int_hmap_reset(&pre->type_leaf_count_cache);
5✔
3103
  int_hmap_reset(&pre->term_has_tuples_cache);
5✔
3104

3105
  for (i = 0; i < pre->preprocess_map_list.size; ++ i) {
486✔
3106
    term_t t = pre->preprocess_map_list.data[i];
481✔
3107
    preprocessor_gc_mark_term(pre, t);
481✔
3108
    term_t t_pre = preprocessor_get(pre, t);
481✔
3109
    preprocessor_gc_mark_term(pre, t_pre);
481✔
3110
  }
3111

3112
  for (i = 0; i < pre->equalities_list.size; ++ i) {
5✔
UNCOV
3113
    term_t t = pre->equalities_list.data[i];
×
UNCOV
3114
    preprocessor_gc_mark_term(pre, t);
×
3115
  }
3116

3117
  for (i = 0; i < pre->tuple_blast_list.size; ++i) {
141✔
3118
    term_t t = pre->tuple_blast_list.data[i];
136✔
3119
    int_hmap_pair_t* rec = int_hmap_find(&pre->tuple_blast_map, t);
136✔
3120
    uint32_t j, n, offset;
3121
    assert(rec != NULL);
3122
    preprocessor_gc_mark_term(pre, t);
136✔
3123
    offset = rec->val;
136✔
3124
    n = pre->tuple_blast_data.data[offset];
136✔
3125
    for (j = 0; j < n; ++j) {
272✔
3126
      preprocessor_gc_mark_term(pre, pre->tuple_blast_data.data[offset + 1 + j]);
136✔
3127
    }
3128
  }
3129

3130
  for (i = 0; i < pre->purification_map_list.size; ++ i) {
24✔
3131
    term_t t = pre->purification_map_list.data[i];
19✔
3132
    preprocessor_gc_mark_term(pre, t);
19✔
3133
    term_t t_pure = int_hmap_find(&pre->purification_map, t)->val;
19✔
3134
    preprocessor_gc_mark_term(pre, t_pure);
19✔
3135
  }
3136
}
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc