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

SRI-CSL / yices2 / 25530974729

08 May 2026 01:12AM UTC coverage: 67.079% (+0.4%) from 66.687%
25530974729

Pull #606

github

disteph
tests: TEMP per-step trace inside test_partial_tuple_model_no_keep_subst

The previous instrumentation pinpointed test_partial_tuple_model_no_keep_subst
as the test that aborts on windows-latest|release|--enable-thread-safety
--enable-mcsat. The captured stderr showed only "START" with no further
output before the abort, so we don't yet know which yices API call inside
the test is the culprit.

This commit adds a TRACE_STEP macro that prints a stderr line (with
explicit fflush) after each yices API call inside the test. The next CI
run should show exactly which call is the last to print before the abort.

To be reverted along with the previous diagnostic commit once the root
cause is fixed.
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%)

1632715.97 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