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

SRI-CSL / yices2 / 25366656949

05 May 2026 08:45AM UTC coverage: 66.952% (+0.3%) from 66.687%
25366656949

Pull #606

github

disteph
mcsat: extend zero-copy peek to all read-only single-leaf sites (L4)

Convert the remaining tuple_blast_get call sites whose only use of the
returned snapshot is a (size==1, data[0]) read to tuple_blast_peek:
NOT, SELECT, OR/XOR, POWER_PRODUCT, ARITH_POLY, ARITH_FF_POLY, BV64_POLY,
BV_POLY, and the generic-composite combine.

Each site already followed a uniform pattern -- tuple_blast_term, then
get into a one-shot ivector, then check size==1 and read data[0] -- so
nine independent malloc+memcpy+free triples per blasted DAG node go away.
The peek pointer is consumed within the same loop iteration before any
subsequent tuple_blast_term, preserving the lifetime invariant documented
on tuple_blast_peek.

The remaining tuple_blast_get callers (APP, UPDATE, top-level substitution
in tuple_blast_apply, model reconstruction in preprocessor_build_tuple_model
and the substitution-walk loop) all need a snapshot that survives further
tuple_blast_term calls and stay on the copying path. The peek doc-comment
is updated to spell out the split.

Verification: all 31 api tests pass in debug, release, and sanitize (the
unrelated type_macros UAF preexisting on master is unchanged); all 691
mcsat regression tests pass in all three modes.
Pull Request #606: MCSAT: add support for tuples (incl. nested with function types); blasts tuples in input constraints + reconstitutes them in models and interpolants

707 of 940 new or added lines in 3 files covered. (75.21%)

51 existing lines in 1 file now uncovered.

84411 of 126076 relevant lines covered (66.95%)

1635062.56 hits per line

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

81.74
/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_queries.h"
35
#include "model/concrete_values.h"
36

37
#include "context/context_types.h"
38

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

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

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

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

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

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

105
static
106
bool type_is_tuple_free(preprocessor_t* pre, type_t tau) {
377,202✔
107
  int_hmap_pair_t* rec = int_hmap_find(&pre->type_is_tuple_free_cache, tau);
377,202✔
108
  if (rec != NULL) {
377,202✔
109
    return rec->val != 0;
375,289✔
110
  }
111

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

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

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

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

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

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

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

185
  switch (type_kind(types, tau)) {
169✔
186
  case TUPLE_TYPE:
53✔
187
    tuple = tuple_type_desc(types, tau);
53✔
188
    for (i = 0; i < tuple->nelem; ++i) {
161✔
189
      type_collect_flat(types, tuple->elem[i], flat);
108✔
190
    }
191
    break;
53✔
192

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

197
  default:
107✔
198
    ivector_push(flat, tau);
107✔
199
    break;
107✔
200
  }
201
}
169✔
202

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

210
  assert(type_kind(types, tau) == FUNCTION_TYPE);
211
  fun = function_type_desc(types, tau);
16✔
212

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

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

225
  delete_ivector(&codom_leaf);
16✔
226
  delete_ivector(&dom_flat);
16✔
227
}
16✔
228

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

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

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

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

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

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

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

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

316
  term_table_t* terms = pre->terms;
341,616✔
317
  term_kind_t kind = term_kind(terms, t);
341,616✔
318
  uint32_t i;
319
  switch (kind) {
341,616✔
320
  case TUPLE_TERM: {
51✔
321
    composite_term_t* c = tuple_term_desc(terms, t);
51✔
322
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
153✔
323
    break;
51✔
324
  }
325
  case SELECT_TERM:
140✔
326
    ivector_push(out, select_term_desc(terms, t)->arg);
140✔
327
    break;
140✔
328
  case EQ_TERM: {
15,898✔
329
    composite_term_t* c = eq_term_desc(terms, t);
15,898✔
330
    ivector_push(out, c->arg[0]);
15,898✔
331
    ivector_push(out, c->arg[1]);
15,898✔
332
    break;
15,898✔
333
  }
334
  case DISTINCT_TERM: {
30✔
335
    composite_term_t* c = distinct_term_desc(terms, t);
30✔
336
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
150✔
337
    break;
30✔
338
  }
339
  case ITE_TERM:
20,329✔
340
  case ITE_SPECIAL: {
341
    composite_term_t* c = ite_term_desc(terms, t);
20,329✔
342
    for (i = 0; i < 3; ++i) ivector_push(out, c->arg[i]);
81,316✔
343
    break;
20,329✔
344
  }
345
  case APP_TERM: {
4,603✔
346
    composite_term_t* c = app_term_desc(terms, t);
4,603✔
347
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
15,097✔
348
    break;
4,603✔
349
  }
350
  case UPDATE_TERM: {
1,416✔
351
    composite_term_t* c = update_term_desc(terms, t);
1,416✔
352
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
5,680✔
353
    break;
1,416✔
354
  }
355
  case OR_TERM: {
48,364✔
356
    composite_term_t* c = or_term_desc(terms, t);
48,364✔
357
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
195,673✔
358
    break;
48,364✔
359
  }
360
  case XOR_TERM: {
30✔
361
    composite_term_t* c = xor_term_desc(terms, t);
30✔
362
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
156✔
363
    break;
30✔
364
  }
365
  case POWER_PRODUCT: {
1,301✔
366
    pprod_t* pp = pprod_term_desc(terms, t);
1,301✔
367
    for (i = 0; i < pp->len; ++i) ivector_push(out, pp->prod[i].var);
4,138✔
368
    break;
1,301✔
369
  }
370
  case ARITH_POLY: {
6,702✔
371
    polynomial_t* p = poly_term_desc(terms, t);
6,702✔
372
    for (i = 0; i < p->nterms; ++i) {
26,129✔
373
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
19,427✔
374
    }
375
    break;
6,702✔
376
  }
NEW
377
  case ARITH_FF_POLY: {
×
NEW
378
    polynomial_t* p = finitefield_poly_term_desc(terms, t);
×
NEW
379
    for (i = 0; i < p->nterms; ++i) {
×
NEW
380
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
×
381
    }
NEW
382
    break;
×
383
  }
384
  case BV64_POLY: {
1,738✔
385
    bvpoly64_t* p = bvpoly64_term_desc(terms, t);
1,738✔
386
    for (i = 0; i < p->nterms; ++i) {
6,840✔
387
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
5,102✔
388
    }
389
    break;
1,738✔
390
  }
391
  case BV_POLY: {
26✔
392
    bvpoly_t* p = bvpoly_term_desc(terms, t);
26✔
393
    for (i = 0; i < p->nterms; ++i) {
69✔
394
      if (p->mono[i].var != const_idx) ivector_push(out, p->mono[i].var);
43✔
395
    }
396
    break;
26✔
397
  }
398
  case ARITH_EQ_ATOM:
96,579✔
399
  case ARITH_GE_ATOM:
400
  case ARITH_BINEQ_ATOM:
401
  case ARITH_RDIV:
402
  case ARITH_IDIV:
403
  case ARITH_MOD:
404
  case BV_ARRAY:
405
  case BV_DIV:
406
  case BV_REM:
407
  case BV_SDIV:
408
  case BV_SREM:
409
  case BV_SMOD:
410
  case BV_SHL:
411
  case BV_LSHR:
412
  case BV_ASHR:
413
  case BV_EQ_ATOM:
414
  case BV_GE_ATOM:
415
  case BV_SGE_ATOM: {
416
    composite_term_t* c = get_composite(terms, kind, t);
96,579✔
417
    for (i = 0; i < c->arity; ++i) ivector_push(out, c->arg[i]);
548,009✔
418
    break;
96,579✔
419
  }
420
  default:
144,409✔
421
    /* Atomic kinds (CONSTANT_TERM, UNINTERPRETED_TERM, VARIABLE, BIT_TERM,
422
     * arithmetic/BV constants, etc.) have no children to blast first. */
423
    break;
144,409✔
424
  }
425
}
426

427
/**
428
 * Memoized: does the DAG rooted at t contain any tuple type?
429
 * Walks the DAG iteratively so deep DAGs don't blow the C stack. The
430
 * answer is polarity-insensitive (cached per index_of(t)) and covers
431
 * t's own type plus the types of every reachable sub-term.
432
 */
433
static
434
bool term_has_tuples_in_subdag(preprocessor_t* pre, term_t t) {
39,323✔
435
  int32_t t_idx = index_of(t);
39,323✔
436
  int_hmap_pair_t* rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
39,323✔
437
  if (rec != NULL) {
39,323✔
438
    return rec->val != 0;
1,789✔
439
  }
440

441
  term_table_t* terms = pre->terms;
37,534✔
442
  ivector_t stack;
443
  init_ivector(&stack, 0);
37,534✔
444
  ivector_push(&stack, t);
37,534✔
445

446
  uint64_t safety = 0;
37,534✔
447
  while (stack.size > 0) {
480,154✔
448
    /* Hard upper bound: 2 * (term-table size) is a generous loose bound on
449
     * the number of distinct (term, polarity) revisits we should ever see
450
     * here. Aborting on overflow is far better than hanging a debug build. */
451
    assert(++safety < ((uint64_t) 1 << 28));
452
    (void) safety;
453

454
    term_t current = stack.data[stack.size - 1];
442,620✔
455
    int32_t cur_idx = index_of(current);
442,620✔
456
    int_hmap_pair_t* crec = int_hmap_find(&pre->term_has_tuples_cache, cur_idx);
442,620✔
457
    if (crec != NULL) {
442,620✔
458
      ivector_pop(&stack);
65,918✔
459
      continue;
175,925✔
460
    }
461

462
    if (!type_is_tuple_free(pre, term_type(terms, current))) {
376,702✔
463
      int_hmap_add(&pre->term_has_tuples_cache, cur_idx, 1);
79✔
464
      ivector_pop(&stack);
79✔
465
      continue;
79✔
466
    }
467

468
    ivector_t children;
469
    init_ivector(&children, 0);
376,623✔
470
    tuple_blast_children(pre, current, &children);
376,623✔
471
    bool any_true = false;
376,623✔
472
    bool all_done = true;
376,623✔
473
    for (uint32_t i = 0; i < children.size; ++i) {
1,141,599✔
474
      int32_t c_idx = index_of(children.data[i]);
764,976✔
475
      int_hmap_pair_t* crec2 = int_hmap_find(&pre->term_has_tuples_cache, c_idx);
764,976✔
476
      if (crec2 == NULL) {
764,976✔
477
        ivector_push(&stack, children.data[i]);
295,158✔
478
        all_done = false;
295,158✔
479
      } else if (crec2->val != 0) {
469,818✔
480
        any_true = true;
152✔
481
      }
482
    }
483
    delete_ivector(&children);
376,623✔
484
    if (!all_done) continue;
376,623✔
485

486
    int_hmap_add(&pre->term_has_tuples_cache, cur_idx, any_true ? 1 : 0);
266,695✔
487
    ivector_pop(&stack);
266,695✔
488
  }
489

490
  delete_ivector(&stack);
37,534✔
491

492
  rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
37,534✔
493
  assert(rec != NULL);
494
  return rec->val != 0;
37,534✔
495
}
496

497
static
498
void tuple_blast_collect_arg(preprocessor_t* pre, term_t t, ivector_t* out) {
67✔
499
  const term_t* data;
500
  uint32_t n;
501
  tuple_blast_term(pre, t);
67✔
502
  /* Peek is safe here: we do not call tuple_blast_term between the peek
503
   * and the ivector_add below, so the backing tuple_blast_data cannot be
504
   * grown (and therefore cannot be reallocated) while `data` is live. */
505
  tuple_blast_peek(pre, t, &data, &n);
67✔
506
  ivector_add(out, (int32_t*) data, n);
67✔
507
}
67✔
508

509
static
510
term_t tuple_blast_eq_vector(term_manager_t* tm, const term_t* a, const term_t* b, uint32_t n) {
18✔
511
  assert(n > 0);
512
  if (n == 1) {
18✔
513
    return mk_eq(tm, a[0], b[0]);
2✔
514
  } else {
515
    ivector_t eqs;
516
    uint32_t i;
517
    init_ivector(&eqs, n);
16✔
518
    for (i = 0; i < n; ++i) {
49✔
519
      ivector_push(&eqs, mk_eq(tm, a[i], b[i]));
33✔
520
    }
521
    term_t result = mk_and(tm, eqs.size, eqs.data);
16✔
522
    delete_ivector(&eqs);
16✔
523
    return result;
16✔
524
  }
525
}
526

527
/*
528
 * Per-term combine. Computes blast(t) assuming the iterative driver
529
 * tuple_blast_term has already blasted every direct child returned by
530
 * tuple_blast_children. The recursive tuple_blast_term(pre, child) calls in
531
 * the body therefore bottom out at the early-return in the driver and do
532
 * not grow the C stack.
533
 */
534
static
535
void tuple_blast_term_body(preprocessor_t* pre, term_t t) {
213✔
536
  term_table_t* terms = pre->terms;
213✔
537
  type_table_t* types = terms->types;
213✔
538
  term_manager_t* tm = &pre->tm;
213✔
539

540
  if (tuple_blast_done(pre, t)) {
213✔
541
    return;
13✔
542
  }
543

544
  ivector_t result;
545
  init_ivector(&result, 0);
213✔
546

547
  if (is_neg_term(t)) {
213✔
548
    term_t c = unsigned_term(t);
13✔
549
    const term_t* c_data;
550
    uint32_t c_n;
551
    tuple_blast_term(pre, c);
13✔
552
    tuple_blast_peek(pre, c, &c_data, &c_n);
13✔
553
    if (c_n != 1) {
13✔
NEW
554
      delete_ivector(&result);
×
NEW
555
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
556
    }
557
    ivector_push(&result, opposite_term(c_data[0]));
13✔
558
    tuple_blast_set(pre, t, &result);
13✔
559
    delete_ivector(&result);
13✔
560
    return;
13✔
561
  }
562

563
  term_kind_t kind = term_kind(terms, t);
200✔
564
  type_t tau = term_type(terms, t);
200✔
565
  switch (kind) {
200✔
NEW
566
  case CONSTANT_TERM:
×
567
  case ARITH_CONSTANT:
568
  case ARITH_FF_CONSTANT:
569
  case BV64_CONSTANT:
570
  case BV_CONSTANT:
571
  case BIT_TERM:
NEW
572
    ivector_push(&result, t);
×
NEW
573
    break;
×
574

575
  case UNINTERPRETED_TERM:
28✔
576
  case VARIABLE: {
577
    if (type_is_tuple_free(pre, tau)) {
28✔
NEW
578
      ivector_push(&result, t);
×
579
    } else {
580
      ivector_t atom_types;
581
      uint32_t i;
582
      init_ivector(&atom_types, 0);
28✔
583
      type_collect_blasted_atom_types(types, tau, &atom_types);
28✔
584
      for (i = 0; i < atom_types.size; ++i) {
93✔
585
        term_t v = new_uninterpreted_term(terms, atom_types.data[i]);
65✔
586
        ivector_push(&result, v);
65✔
587
      }
588
      ivector_push(&pre->tuple_blast_atoms, t);
28✔
589
      delete_ivector(&atom_types);
28✔
590
    }
591
    break;
28✔
592
  }
593

594
  case TUPLE_TERM: {
27✔
595
    composite_term_t* tuple = tuple_term_desc(terms, t);
27✔
596
    uint32_t i;
597
    for (i = 0; i < tuple->arity; ++i) {
81✔
598
      tuple_blast_collect_arg(pre, tuple->arg[i], &result);
54✔
599
    }
600
    break;
27✔
601
  }
602

603
  case SELECT_TERM: {
55✔
604
    select_term_t* sel = select_term_desc(terms, t);
55✔
605
    const term_t* arg_data;
606
    uint32_t arg_n;
607
    tuple_type_t* tuple_type;
608
    uint32_t i, start, len;
609
    type_t arg_type = term_type(terms, sel->arg);
55✔
610
    if (type_kind(types, arg_type) != TUPLE_TYPE) {
55✔
NEW
611
      delete_ivector(&result);
×
NEW
612
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
613
    }
614
    tuple_blast_term(pre, sel->arg);
55✔
615
    tuple_blast_peek(pre, sel->arg, &arg_data, &arg_n);
55✔
616
    tuple_type = tuple_type_desc(types, arg_type);
55✔
617
    start = 0;
55✔
618
    for (i = 0; i < sel->idx; ++i) {
82✔
619
      start += type_leaf_count(pre, tuple_type->elem[i]);
27✔
620
    }
621
    len = type_leaf_count(pre, tuple_type->elem[sel->idx]);
55✔
622
    if (start + len > arg_n) {
55✔
NEW
623
      delete_ivector(&result);
×
NEW
624
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
625
    }
626
    ivector_add(&result, (int32_t*) (arg_data + start), len);
55✔
627
    break;
55✔
628
  }
629

630
  case EQ_TERM: {
18✔
631
    composite_term_t* eq = eq_term_desc(terms, t);
18✔
632
    const term_t *lhs, *rhs;
633
    uint32_t lhs_n, rhs_n;
634
    /* Both tuple_blast_term calls precede both peeks; tuple_blast_eq_vector
635
     * and ivector_push do not grow tuple_blast_data, so the peeked
636
     * pointers stay live for the duration of this block. */
637
    tuple_blast_term(pre, eq->arg[0]);
18✔
638
    tuple_blast_term(pre, eq->arg[1]);
18✔
639
    tuple_blast_peek(pre, eq->arg[0], &lhs, &lhs_n);
18✔
640
    tuple_blast_peek(pre, eq->arg[1], &rhs, &rhs_n);
18✔
641
    if (lhs_n != rhs_n || lhs_n == 0) {
18✔
NEW
642
      delete_ivector(&result);
×
NEW
643
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
644
    }
645
    ivector_push(&result, tuple_blast_eq_vector(tm, lhs, rhs, lhs_n));
18✔
646
    break;
18✔
647
  }
648

NEW
649
  case DISTINCT_TERM: {
×
NEW
650
    composite_term_t* d = distinct_term_desc(terms, t);
×
651
    ivector_t conjuncts;
652
    uint32_t i, j;
NEW
653
    init_ivector(&conjuncts, 0);
×
NEW
654
    for (i = 0; i < d->arity; ++i) {
×
NEW
655
      for (j = i + 1; j < d->arity; ++j) {
×
656
        const term_t *ti_data, *tj_data;
657
        uint32_t ti_n, tj_n;
658
        ivector_t disj;
659
        uint32_t k;
660
        /* Both tuple_blast_term calls complete before the peeks; after
661
         * the peeks we only call mk_eq / opposite_term / mk_or and push
662
         * into local ivectors, none of which grow tuple_blast_data. */
NEW
663
        tuple_blast_term(pre, d->arg[i]);
×
NEW
664
        tuple_blast_term(pre, d->arg[j]);
×
NEW
665
        tuple_blast_peek(pre, d->arg[i], &ti_data, &ti_n);
×
NEW
666
        tuple_blast_peek(pre, d->arg[j], &tj_data, &tj_n);
×
NEW
667
        if (ti_n != tj_n || ti_n == 0) {
×
NEW
668
          delete_ivector(&conjuncts);
×
NEW
669
          delete_ivector(&result);
×
NEW
670
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
671
        }
NEW
672
        init_ivector(&disj, ti_n);
×
NEW
673
        for (k = 0; k < ti_n; ++k) {
×
NEW
674
          ivector_push(&disj, opposite_term(mk_eq(tm, ti_data[k], tj_data[k])));
×
675
        }
NEW
676
        ivector_push(&conjuncts, mk_or(tm, disj.size, disj.data));
×
NEW
677
        delete_ivector(&disj);
×
678
      }
679
    }
NEW
680
    ivector_push(&result, mk_and(tm, conjuncts.size, conjuncts.data));
×
NEW
681
    delete_ivector(&conjuncts);
×
NEW
682
    break;
×
683
  }
684

685
  case ITE_TERM:
3✔
686
  case ITE_SPECIAL: {
687
    composite_term_t* ite = ite_term_desc(terms, t);
3✔
688
    const term_t *c_data, *t_data, *e_data;
689
    uint32_t c_n, t_n, e_n;
690
    uint32_t i;
691
    /* All three tuple_blast_term calls complete before any peek, so the
692
     * peeked pointers remain valid for the rest of this block: the only
693
     * calls after the peeks are term-manager operations (super_type,
694
     * term_type, mk_ite) plus ivector_push(&result, ...), none of which
695
     * grow tuple_blast_data. */
696
    tuple_blast_term(pre, ite->arg[0]);
3✔
697
    tuple_blast_term(pre, ite->arg[1]);
3✔
698
    tuple_blast_term(pre, ite->arg[2]);
3✔
699
    tuple_blast_peek(pre, ite->arg[0], &c_data, &c_n);
3✔
700
    tuple_blast_peek(pre, ite->arg[1], &t_data, &t_n);
3✔
701
    tuple_blast_peek(pre, ite->arg[2], &e_data, &e_n);
3✔
702
    if (c_n != 1 || t_n != e_n || t_n == 0) {
3✔
NEW
703
      delete_ivector(&result);
×
NEW
704
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
705
    }
706
    for (i = 0; i < t_n; ++i) {
10✔
707
      type_t ty = super_type(types, term_type(terms, t_data[i]), term_type(terms, e_data[i]));
7✔
708
      if (ty == NULL_TYPE) {
7✔
NEW
709
        delete_ivector(&result);
×
NEW
710
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
711
      }
712
      ivector_push(&result, mk_ite(tm, c_data[0], t_data[i], e_data[i], ty));
7✔
713
    }
714
    if (result.size == 1 &&
3✔
NEW
715
        c_data[0] == ite->arg[0] &&
×
NEW
716
        t_data[0] == ite->arg[1] &&
×
NEW
717
        e_data[0] == ite->arg[2]) {
×
NEW
718
      ivector_reset(&result);
×
NEW
719
      ivector_push(&result, t);
×
720
    }
721
    break;
3✔
722
  }
723

724
  case APP_TERM: {
13✔
725
    composite_term_t* app = app_term_desc(terms, t);
13✔
726
    ivector_t f_blast;
727
    ivector_t args_flat;
728
    uint32_t i;
729
    bool changed;
730
    tuple_blast_term(pre, app->arg[0]);
13✔
731
    init_ivector(&f_blast, 0);
13✔
732
    tuple_blast_get(pre, app->arg[0], &f_blast);
13✔
733
    init_ivector(&args_flat, 0);
13✔
734
    for (i = 1; i < app->arity; ++i) {
26✔
735
      tuple_blast_collect_arg(pre, app->arg[i], &args_flat);
13✔
736
    }
737
    changed = f_blast.size != 1 || f_blast.data[0] != app->arg[0] || args_flat.size != app->arity - 1;
13✔
738
    for (i = 1; !changed && i < app->arity; ++i) {
13✔
NEW
739
      changed = args_flat.data[i - 1] != app->arg[i];
×
740
    }
741
    if (!changed) {
13✔
NEW
742
      ivector_push(&result, t);
×
NEW
743
      delete_ivector(&args_flat);
×
NEW
744
      delete_ivector(&f_blast);
×
NEW
745
      break;
×
746
    }
747
    for (i = 0; i < f_blast.size; ++i) {
37✔
748
      term_t app_i = mk_application(tm, f_blast.data[i], args_flat.size, args_flat.data);
24✔
749
      if (app_i == NULL_TERM) {
24✔
NEW
750
        delete_ivector(&args_flat);
×
NEW
751
        delete_ivector(&f_blast);
×
NEW
752
        delete_ivector(&result);
×
NEW
753
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
754
      }
755
      ivector_push(&result, app_i);
24✔
756
    }
757
    delete_ivector(&args_flat);
13✔
758
    delete_ivector(&f_blast);
13✔
759
    break;
13✔
760
  }
761

NEW
762
  case UPDATE_TERM: {
×
NEW
763
    composite_term_t* upd = update_term_desc(terms, t);
×
764
    ivector_t f_blast;
765
    ivector_t idx_flat;
766
    ivector_t v_blast;
767
    uint32_t i;
768
    bool changed;
NEW
769
    tuple_blast_term(pre, upd->arg[0]);
×
NEW
770
    init_ivector(&f_blast, 0);
×
NEW
771
    tuple_blast_get(pre, upd->arg[0], &f_blast);
×
NEW
772
    init_ivector(&idx_flat, 0);
×
NEW
773
    for (i = 1; i + 1 < upd->arity; ++i) {
×
NEW
774
      tuple_blast_collect_arg(pre, upd->arg[i], &idx_flat);
×
775
    }
NEW
776
    tuple_blast_term(pre, upd->arg[upd->arity - 1]);
×
NEW
777
    init_ivector(&v_blast, 0);
×
NEW
778
    tuple_blast_get(pre, upd->arg[upd->arity - 1], &v_blast);
×
NEW
779
    if (v_blast.size != 1 && v_blast.size != f_blast.size) {
×
NEW
780
      delete_ivector(&f_blast);
×
NEW
781
      delete_ivector(&idx_flat);
×
NEW
782
      delete_ivector(&v_blast);
×
NEW
783
      delete_ivector(&result);
×
NEW
784
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
785
    }
NEW
786
    changed = f_blast.size != 1 || f_blast.data[0] != upd->arg[0] || idx_flat.size != upd->arity - 2 ||
×
NEW
787
              v_blast.size != 1 || v_blast.data[0] != upd->arg[upd->arity - 1];
×
NEW
788
    for (i = 1; !changed && i + 1 < upd->arity; ++i) {
×
NEW
789
      changed = idx_flat.data[i - 1] != upd->arg[i];
×
790
    }
NEW
791
    if (!changed) {
×
NEW
792
      ivector_push(&result, t);
×
NEW
793
      delete_ivector(&f_blast);
×
NEW
794
      delete_ivector(&idx_flat);
×
NEW
795
      delete_ivector(&v_blast);
×
NEW
796
      break;
×
797
    }
NEW
798
    for (i = 0; i < f_blast.size; ++i) {
×
NEW
799
      term_t vi = v_blast.size == 1 ? v_blast.data[0] : v_blast.data[i];
×
NEW
800
      term_t upd_i = mk_update(tm, f_blast.data[i], idx_flat.size, idx_flat.data, vi);
×
NEW
801
      if (upd_i == NULL_TERM) {
×
NEW
802
        delete_ivector(&f_blast);
×
NEW
803
        delete_ivector(&idx_flat);
×
NEW
804
        delete_ivector(&v_blast);
×
NEW
805
        delete_ivector(&result);
×
NEW
806
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
807
      }
NEW
808
      ivector_push(&result, upd_i);
×
809
    }
NEW
810
    delete_ivector(&f_blast);
×
NEW
811
    delete_ivector(&idx_flat);
×
NEW
812
    delete_ivector(&v_blast);
×
NEW
813
    break;
×
814
  }
815

816
  case OR_TERM:
3✔
817
  case XOR_TERM: {
818
    composite_term_t* c = (kind == OR_TERM) ? or_term_desc(terms, t) : xor_term_desc(terms, t);
3✔
819
    ivector_t args;
820
    uint32_t i;
821
    init_ivector(&args, c->arity);
3✔
822
    for (i = 0; i < c->arity; ++i) {
9✔
823
      const term_t* child_data;
824
      uint32_t child_n;
825
      tuple_blast_term(pre, c->arg[i]);
6✔
826
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
6✔
827
      if (child_n != 1) {
6✔
NEW
828
        delete_ivector(&args);
×
NEW
829
        delete_ivector(&result);
×
NEW
830
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
831
      }
832
      ivector_push(&args, child_data[0]);
6✔
833
    }
834
    ivector_push(&result, kind == OR_TERM ? mk_or(tm, args.size, args.data) : mk_xor(tm, args.size, args.data));
3✔
835
    delete_ivector(&args);
3✔
836
    break;
3✔
837
  }
838

839
  case POWER_PRODUCT: {
2✔
840
    pprod_t* pp = pprod_term_desc(terms, t);
2✔
841
    term_t args[pp->len];
2✔
842
    uint32_t i;
843
    bool changed = false;
2✔
844

845
    for (i = 0; i < pp->len; ++i) {
6✔
846
      const term_t* child_data;
847
      uint32_t child_n;
848
      tuple_blast_term(pre, pp->prod[i].var);
4✔
849
      tuple_blast_peek(pre, pp->prod[i].var, &child_data, &child_n);
4✔
850
      if (child_n != 1) {
4✔
NEW
851
        delete_ivector(&result);
×
NEW
852
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
853
      }
854
      args[i] = child_data[0];
4✔
855
      changed |= args[i] != pp->prod[i].var;
4✔
856
    }
857
    ivector_push(&result, changed ? mk_pprod(tm, pp, pp->len, args) : t);
2✔
858
    break;
2✔
859
  }
860

861
  case ARITH_POLY: {
11✔
862
    polynomial_t* p = poly_term_desc(terms, t);
11✔
863
    term_t args[p->nterms];
11✔
864
    uint32_t i;
865
    bool changed = false;
11✔
866

867
    for (i = 0; i < p->nterms; ++i) {
35✔
868
      term_t x = p->mono[i].var;
24✔
869
      if (x == const_idx) {
24✔
870
        args[i] = const_idx;
10✔
871
      } else {
872
        const term_t* child_data;
873
        uint32_t child_n;
874
        tuple_blast_term(pre, x);
14✔
875
        tuple_blast_peek(pre, x, &child_data, &child_n);
14✔
876
        if (child_n != 1) {
14✔
NEW
877
          delete_ivector(&result);
×
NEW
878
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
879
        }
880
        args[i] = child_data[0];
14✔
881
        changed |= args[i] != x;
14✔
882
      }
883
    }
884
    ivector_push(&result, changed ? mk_arith_poly(tm, p, p->nterms, args) : t);
11✔
885
    break;
11✔
886
  }
887

NEW
888
  case ARITH_FF_POLY: {
×
NEW
889
    polynomial_t* p = finitefield_poly_term_desc(terms, t);
×
NEW
890
    const rational_t* mod = finitefield_term_order(terms, t);
×
NEW
891
    term_t args[p->nterms];
×
892
    uint32_t i;
NEW
893
    bool changed = false;
×
894

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

916
  case BV64_POLY: {
2✔
917
    bvpoly64_t* p = bvpoly64_term_desc(terms, t);
2✔
918
    term_t args[p->nterms];
2✔
919
    uint32_t i;
920
    bool changed = false;
2✔
921

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

NEW
943
  case BV_POLY: {
×
NEW
944
    bvpoly_t* p = bvpoly_term_desc(terms, t);
×
NEW
945
    term_t args[p->nterms];
×
946
    uint32_t i;
NEW
947
    bool changed = false;
×
948

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

970
  case ARITH_EQ_ATOM:
38✔
971
  case ARITH_GE_ATOM:
972
  case ARITH_BINEQ_ATOM:
973
  case ARITH_RDIV:
974
  case ARITH_IDIV:
975
  case ARITH_MOD:
976
  case BV_ARRAY:
977
  case BV_DIV:
978
  case BV_REM:
979
  case BV_SDIV:
980
  case BV_SREM:
981
  case BV_SMOD:
982
  case BV_SHL:
983
  case BV_LSHR:
984
  case BV_ASHR:
985
  case BV_EQ_ATOM:
986
  case BV_GE_ATOM:
987
  case BV_SGE_ATOM: {
38✔
988
    composite_term_t* c = get_composite(terms, kind, t);
38✔
989
    term_t args[c->arity];
38✔
990
    uint32_t i;
991
    bool changed = false;
38✔
992

993
    for (i = 0; i < c->arity; ++i) {
103✔
994
      const term_t* child_data;
995
      uint32_t child_n;
996
      tuple_blast_term(pre, c->arg[i]);
65✔
997
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
65✔
998
      if (child_n != 1) {
65✔
NEW
999
        delete_ivector(&result);
×
NEW
1000
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1001
      }
1002
      args[i] = child_data[0];
65✔
1003
      changed |= args[i] != c->arg[i];
65✔
1004
    }
1005

1006
    term_t rebuilt = changed ? mk_composite(pre, kind, c->arity, args) : t;
38✔
1007
    if (rebuilt == NULL_TERM) {
38✔
NEW
1008
      delete_ivector(&result);
×
NEW
1009
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1010
    }
1011
    ivector_push(&result, rebuilt);
38✔
1012
    break;
38✔
1013
  }
1014

NEW
1015
  default:
×
NEW
1016
    ivector_push(&result, t);
×
NEW
1017
    break;
×
1018
  }
1019

1020
  tuple_blast_set(pre, t, &result);
200✔
1021
  delete_ivector(&result);
200✔
1022
}
1023

1024
/*
1025
 * Iterative bottom-up driver for tuple-blasting.
1026
 *  - C stack depth is O(1) regardless of input DAG depth (M4).
1027
 *  - Sub-DAGs that contain no tuple type anywhere are identity-blasted in
1028
 *    one step without descending into them, using the memoized
1029
 *    term_has_tuples_in_subdag (M3).
1030
 *  - For each not-yet-blasted term on the work stack we either (a) push
1031
 *    its un-blasted children, or (b) all children are blasted and we run
1032
 *    tuple_blast_term_body once. Children come from tuple_blast_children
1033
 *    which mirrors exactly the recursive descent in tuple_blast_term_body.
1034
 */
1035
static
1036
void tuple_blast_term(preprocessor_t* pre, term_t t) {
40,115✔
1037
  if (tuple_blast_done(pre, t)) {
40,115✔
1038
    return;
40,048✔
1039
  }
1040

1041
  if (!term_has_tuples_in_subdag(pre, t)) {
38,898✔
1042
    ivector_t result;
1043
    init_ivector(&result, 0);
38,831✔
1044
    ivector_push(&result, t);
38,831✔
1045
    tuple_blast_set(pre, t, &result);
38,831✔
1046
    delete_ivector(&result);
38,831✔
1047
    return;
38,831✔
1048
  }
1049

1050
  ivector_t stack;
1051
  init_ivector(&stack, 0);
67✔
1052
  ivector_push(&stack, t);
67✔
1053

1054
  uint64_t safety = 0;
67✔
1055
  while (stack.size > 0) {
493✔
1056
    /* Defensive bound. Real workloads visit each term O(1) times; 2^28
1057
     * iterations is far more than any reachable DAG should ever need. */
1058
    assert(++safety < ((uint64_t) 1 << 28));
1059
    (void) safety;
1060

1061
    term_t current = stack.data[stack.size - 1];
426✔
1062

1063
    if (tuple_blast_done(pre, current)) {
426✔
1064
      ivector_pop(&stack);
1✔
1065
      continue;
213✔
1066
    }
1067

1068
    if (!term_has_tuples_in_subdag(pre, current)) {
425✔
1069
      ivector_t result;
1070
      init_ivector(&result, 0);
69✔
1071
      ivector_push(&result, current);
69✔
1072
      tuple_blast_set(pre, current, &result);
69✔
1073
      delete_ivector(&result);
69✔
1074
      ivector_pop(&stack);
69✔
1075
      continue;
69✔
1076
    }
1077

1078
    ivector_t children;
1079
    init_ivector(&children, 0);
356✔
1080
    tuple_blast_children(pre, current, &children);
356✔
1081
    bool all_done = true;
356✔
1082
    for (uint32_t i = 0; i < children.size; ++i) {
874✔
1083
      if (!tuple_blast_done(pre, children.data[i])) {
518✔
1084
        ivector_push(&stack, children.data[i]);
216✔
1085
        all_done = false;
216✔
1086
      }
1087
    }
1088
    delete_ivector(&children);
356✔
1089
    if (!all_done) continue;
356✔
1090

1091
    tuple_blast_term_body(pre, current);
213✔
1092
    ivector_pop(&stack);
213✔
1093
  }
1094

1095
  delete_ivector(&stack);
67✔
1096
}
1097

1098
typedef struct composite_term1_s {
1099
  uint32_t arity;  // number of subterms
1100
  term_t arg[1];  // real size = arity
1101
} composite_term1_t;
1102

1103
static
1104
composite_term1_t composite_for_noncomposite;
1105

1106
static
1107
composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t) {
304,309✔
1108
  assert(term_is_composite(terms, t));
1109
  assert(term_kind(terms, t) == kind);
1110
  assert(is_pos_term(t));
1111

1112
  switch (kind) {
304,309✔
1113
  case ITE_TERM:           // if-then-else
20,874✔
1114
  case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1115
    return ite_term_desc(terms, t);
20,874✔
1116
  case EQ_TERM:            // equality
20,743✔
1117
    return eq_term_desc(terms, t);
20,743✔
1118
  case OR_TERM:            // n-ary OR
62,212✔
1119
    return or_term_desc(terms, t);
62,212✔
1120
  case XOR_TERM:           // n-ary XOR
30✔
1121
    return xor_term_desc(terms, t);
30✔
1122
  case ARITH_BINEQ_ATOM:   // equality: (t1 == t2)  (between two arithmetic terms)
7,855✔
1123
    return arith_bineq_atom_desc(terms, t);
7,855✔
1124
  case ARITH_EQ_ATOM: {
7,265✔
1125
    composite_for_noncomposite.arity = 1;
7,265✔
1126
    composite_for_noncomposite.arg[0] = arith_eq_arg(terms, t);
7,265✔
1127
    return (composite_term_t*)&composite_for_noncomposite;
7,265✔
1128
  }
1129
  case ARITH_GE_ATOM: {
16,225✔
1130
    composite_for_noncomposite.arity = 1;
16,225✔
1131
    composite_for_noncomposite.arg[0] = arith_ge_arg(terms, t);
16,225✔
1132
    return (composite_term_t*)&composite_for_noncomposite;
16,225✔
1133
  }
1134
  case ARITH_FF_BINEQ_ATOM:
12✔
1135
    return arith_ff_bineq_atom_desc(terms, t);
12✔
1136
  case ARITH_FF_EQ_ATOM: {
155✔
1137
    composite_for_noncomposite.arity = 1;
155✔
1138
    composite_for_noncomposite.arg[0] = arith_ff_eq_arg(terms, t);
155✔
1139
    return (composite_term_t*)&composite_for_noncomposite;
155✔
1140
  }
1141
  case APP_TERM:           // application of an uninterpreted function
5,841✔
1142
    return app_term_desc(terms, t);
5,841✔
1143
  case ARITH_RDIV:          // division: (/ x y)
116✔
1144
    return arith_rdiv_term_desc(terms, t);
116✔
1145
  case ARITH_IDIV:          // division: (div x y) as defined in SMT-LIB 2
176✔
1146
    return arith_idiv_term_desc(terms, t);
176✔
1147
  case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
296✔
1148
    return arith_mod_term_desc(terms, t);
296✔
1149
  case UPDATE_TERM:
2,501✔
1150
    return update_term_desc(terms, t);
2,501✔
1151
  case DISTINCT_TERM:
27✔
1152
    return distinct_term_desc(terms, t);
27✔
1153
  case BV_ARRAY:
33,080✔
1154
    return bvarray_term_desc(terms, t);
33,080✔
1155
  case BV_DIV:
180✔
1156
    return bvdiv_term_desc(terms, t);
180✔
1157
  case BV_REM:
424✔
1158
    return bvrem_term_desc(terms, t);
424✔
1159
  case BV_SDIV:
35✔
1160
    return bvsdiv_term_desc(terms, t);
35✔
1161
  case BV_SREM:
38✔
1162
    return bvsrem_term_desc(terms, t);
38✔
1163
  case BV_SMOD:
12✔
1164
    return bvsmod_term_desc(terms, t);
12✔
1165
  case BV_SHL:
284✔
1166
    return bvshl_term_desc(terms, t);
284✔
1167
  case BV_LSHR:
338✔
1168
    return bvlshr_term_desc(terms, t);
338✔
1169
  case BV_ASHR:
34✔
1170
    return bvashr_term_desc(terms, t);
34✔
1171
  case BV_EQ_ATOM:
118,708✔
1172
    return bveq_atom_desc(terms, t);
118,708✔
1173
  case BV_GE_ATOM:
5,562✔
1174
    return bvge_atom_desc(terms, t);
5,562✔
1175
  case BV_SGE_ATOM:
1,286✔
1176
    return bvsge_atom_desc(terms, t);
1,286✔
1177
  default:
×
1178
    assert(false);
1179
    return NULL;
×
1180
  }
1181
}
1182

1183
static bool type_needs_function_diseq_guard(type_table_t* types, type_t tau) {
24,772✔
1184
  uint32_t i, n;
1185

1186
  switch (type_kind(types, tau)) {
24,772✔
1187
  case FUNCTION_TYPE:
1,973✔
1188
    if (type_has_finite_domain(types, tau) ||
3,936✔
1189
        is_unit_type(types, function_type_range(types, tau))) {
1,963✔
1190
      return true;
11✔
1191
    }
1192

1193
    n = function_type_arity(types, tau);
1,962✔
1194
    for (i = 0; i < n; ++ i) {
3,928✔
1195
      if (type_needs_function_diseq_guard(types, function_type_domain(types, tau, i))) {
1,968✔
1196
        return true;
2✔
1197
      }
1198
    }
1199

1200
    return type_needs_function_diseq_guard(types, function_type_range(types, tau));
1,960✔
1201

1202
  case TUPLE_TYPE:
×
1203
    n = tuple_type_arity(types, tau);
×
1204
    for (i = 0; i < n; ++ i) {
×
1205
      if (type_needs_function_diseq_guard(types, tuple_type_component(types, tau, i))) {
×
1206
        return true;
×
1207
      }
1208
    }
1209
    return false;
×
1210

1211
  case INSTANCE_TYPE:
×
1212
    n = instance_type_arity(types, tau);
×
1213
    for (i = 0; i < n; ++ i) {
×
1214
      if (type_needs_function_diseq_guard(types, instance_type_param(types, tau, i))) {
×
1215
        return true;
×
1216
      }
1217
    }
1218
    return false;
×
1219

1220
  default:
22,799✔
1221
    return false;
22,799✔
1222
  }
1223
}
1224

1225
static bool term_needs_function_diseq_guard(term_table_t* terms, term_t t) {
20,844✔
1226
  return type_needs_function_diseq_guard(terms->types, term_type(terms, t));
20,844✔
1227
}
1228

1229
static
1230
term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children) {
46,616✔
1231
  term_manager_t* tm = &pre->tm;
46,616✔
1232
  term_table_t* terms = pre->terms;
46,616✔
1233

1234
  switch (kind) {
46,616✔
1235
  case ITE_TERM:           // if-then-else
12,893✔
1236
  case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1237
  {
1238
    assert(n == 3);
1239
    term_t type = super_type(pre->terms->types, term_type(terms, children[1]), term_type(terms, children[2]));
12,893✔
1240
    assert(type != NULL_TYPE);
1241
    return mk_ite(tm, children[0], children[1], children[2], type);
12,893✔
1242
  }
1243
  case EQ_TERM:            // equality
3,577✔
1244
    assert(n == 2);
1245
    return mk_eq(tm, children[0], children[1]);
3,577✔
1246
  case OR_TERM:            // n-ary OR
12,120✔
1247
    assert(n > 1);
1248
    return mk_or(tm, n, children);
12,120✔
1249
  case XOR_TERM:           // n-ary XOR
3✔
1250
    return mk_xor(tm, n, children);
3✔
1251
  case ARITH_EQ_ATOM:
69✔
1252
    assert(n == 1);
1253
    return mk_arith_eq(tm, children[0], zero_term);
69✔
1254
  case ARITH_GE_ATOM:
427✔
1255
    assert(n == 1);
1256
    return mk_arith_geq(tm, children[0], zero_term);
427✔
1257
  case ARITH_BINEQ_ATOM:   // equality: (t1 == t2)  (between two arithmetic terms)
247✔
1258
    assert(n == 2);
1259
    return mk_arith_eq(tm, children[0], children[1]);
247✔
1260
  case APP_TERM:           // application of an uninterpreted function
877✔
1261
    assert(n > 1);
1262
    return mk_application(tm, children[0], n-1, children + 1);
877✔
1263
  case ARITH_RDIV:
21✔
1264
    assert(n == 2);
1265
    return mk_arith_rdiv(tm, children[0], children[1]);
21✔
1266
  case ARITH_IDIV:          // division: (div x y) as defined in SMT-LIB 2
19✔
1267
    assert(n == 2);
1268
    return mk_arith_idiv(tm, children[0], children[1]);
19✔
1269
  case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
21✔
1270
    assert(n == 2);
1271
    return mk_arith_mod(tm, children[0], children[1]);
21✔
1272
  case UPDATE_TERM:
497✔
1273
    assert(n > 2);
1274
    return mk_update(tm, children[0], n-2, children + 1, children[n-1]);
497✔
1275
  case BV_ARRAY:
6,955✔
1276
    assert(n >= 1);
1277
    return mk_bvarray(tm, n, children);
6,955✔
1278
  case BV_DIV:
63✔
1279
    assert(n == 2);
1280
    return mk_bvdiv(tm, children[0], children[1]);
63✔
1281
  case BV_REM:
18✔
1282
    assert(n == 2);
1283
    return mk_bvrem(tm, children[0], children[1]);
18✔
UNCOV
1284
  case BV_SDIV:
×
1285
    assert(n == 2);
UNCOV
1286
    return mk_bvsdiv(tm, children[0], children[1]);
×
UNCOV
1287
  case BV_SREM:
×
1288
    assert(n == 2);
UNCOV
1289
    return mk_bvsrem(tm, children[0], children[1]);
×
1290
  case BV_SMOD:
2✔
1291
    assert(n == 2);
1292
    return mk_bvsmod(tm, children[0], children[1]);
2✔
1293
  case BV_SHL:
108✔
1294
    assert(n == 2);
1295
    return mk_bvshl(tm, children[0], children[1]);
108✔
1296
  case BV_LSHR:
135✔
1297
    assert(n == 2);
1298
    return mk_bvlshr(tm, children[0], children[1]);
135✔
1299
  case BV_ASHR:
3✔
1300
    assert(n == 2);
1301
    return mk_bvashr(tm, children[0], children[1]);
3✔
1302
  case BV_EQ_ATOM:
6,483✔
1303
    assert(n == 2);
1304
    return mk_bveq(tm, children[0], children[1]);
6,483✔
1305
  case BV_GE_ATOM:
1,797✔
1306
    assert(n == 2);
1307
    return mk_bvge(tm, children[0], children[1]);
1,797✔
1308
  case BV_SGE_ATOM:
281✔
1309
    assert(n == 2);
1310
    return mk_bvsge(tm, children[0], children[1]);
281✔
UNCOV
1311
  default:
×
1312
    assert(false);
UNCOV
1313
    return NULL_TERM;
×
1314
  }
1315
}
1316

1317
/**
1318
 * Returns purified version of t if we should purify t as an argument of a function.
1319
 * Any new equalities are added to output.
1320
 */
1321
static inline
1322
term_t preprocessor_purify(preprocessor_t* pre, term_t t, ivector_t* out) {
52,845✔
1323

1324
  term_table_t* terms = pre->terms;
52,845✔
1325

1326
  // Negated terms must be purified
1327
  if (is_pos_term(t)) {
52,845✔
1328
    // We don't purify variables
1329
    switch (term_kind(terms, t)) {
17,079✔
1330
    case UNINTERPRETED_TERM:
10,825✔
1331
      // Variables are already pure
1332
      return t;
10,825✔
1333
    case CONSTANT_TERM:
15✔
1334
      return t;
15✔
1335
    case ARITH_CONSTANT:
1,698✔
1336
    case ARITH_FF_CONSTANT:
1337
    case BV64_CONSTANT:
1338
    case BV_CONSTANT:
1339
      // Constants are also pure (except for false)
1340
      return t;
1,698✔
1341
    case APP_TERM:
1,685✔
1342
      // Uninterpreted functions are also already purified
1343
      return t;
1,685✔
1344
    case UPDATE_TERM:
1,680✔
1345
      return t;
1,680✔
1346
    default:
1,176✔
1347
      break;
1,176✔
1348
    }
1349
  }
1350

1351
  // Everything else gets purified. Check if in the cache
1352
  int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
36,942✔
1353
  if (find != NULL) {
36,942✔
1354
    return find->val;
36,376✔
1355
  } else {
1356
    // Make the variable
1357
    type_t t_type = term_type(terms, t);
566✔
1358
    term_t x = new_uninterpreted_term(terms, t_type);
566✔
1359
    // Remember for later
1360
    int_hmap_add(&pre->purification_map, t, x);
566✔
1361
    ivector_push(&pre->purification_map_list, t);
566✔
1362
    // Also add the variable to the pre-processor
1363
    preprocessor_set(pre, x, x);
566✔
1364
    // Add equality to output
1365
    term_t eq = mk_eq(&pre->tm, x, t);
566✔
1366
    ivector_push(out, eq);
566✔
1367

1368
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
566✔
UNCOV
1369
      mcsat_trace_printf(pre->tracer, "adding lemma = ");
×
UNCOV
1370
      trace_term_ln(pre->tracer, terms, eq);
×
1371
    }
1372

1373
    // Return the purified version
1374
    return x;
566✔
1375
  }
1376
}
1377

1378
static inline
1379
term_t mk_bvneg(term_manager_t* tm, term_t t) {
92✔
1380
  term_table_t* terms = tm->terms;
92✔
1381
  if (term_bitsize(terms,t) <= 64) {
92✔
1382
    bvarith64_buffer_t *buffer = term_manager_get_bvarith64_buffer(tm);
76✔
1383
    bvarith64_buffer_set_term(buffer, terms, t);
76✔
1384
    bvarith64_buffer_negate(buffer);
76✔
1385
    return mk_bvarith64_term(tm, buffer);
76✔
1386
  } else {
1387
    bvarith_buffer_t *buffer = term_manager_get_bvarith_buffer(tm);
16✔
1388
    bvarith_buffer_set_term(buffer, terms, t);
16✔
1389
    bvarith_buffer_negate(buffer);
16✔
1390
    return mk_bvarith_term(tm, buffer);
16✔
1391
  }
1392
}
1393

1394
// Mark equality eq: (var = t) for solving
1395
static
1396
void preprocessor_mark_eq(preprocessor_t* pre, term_t eq, term_t var) {
24,861✔
1397
  assert(is_pos_term(eq));
1398
  assert(is_pos_term(var));
1399
  assert(term_kind(pre->terms, var) == UNINTERPRETED_TERM);
1400

1401
  // Mark the equality
1402
  int_hmap_pair_t* find = int_hmap_get(&pre->equalities, eq);
24,861✔
1403
  assert(find->val == -1);
1404
  find->val = var;
24,861✔
1405
  ivector_push(&pre->equalities_list, eq);
24,861✔
1406
}
24,861✔
1407

1408
static
1409
term_t preprocessor_get_eq_solved_var(const preprocessor_t* pre, term_t eq) {
47,679✔
1410
  assert(is_pos_term(eq));
1411
  int_hmap_pair_t* find = int_hmap_find((int_hmap_t*) &pre->equalities, eq);
47,679✔
1412
  if (find != NULL) {
47,679✔
1413
    return find->val;
19,993✔
1414
  } else {
1415
    return NULL_TERM;
27,686✔
1416
  }
1417
}
1418

1419
term_t preprocessor_apply(preprocessor_t* pre, term_t t, ivector_t* out, bool is_assertion) {
39,831✔
1420

1421
  term_table_t* terms = pre->terms;
39,831✔
1422
  term_manager_t* tm = &pre->tm;
39,831✔
1423

1424
  uint32_t i, j, n;
1425
  ivector_t t_blast;
1426

1427
  tuple_blast_term(pre, t);
39,831✔
1428
  init_ivector(&t_blast, 0);
39,831✔
1429
  tuple_blast_get(pre, t, &t_blast);
39,831✔
1430
  if (t_blast.size != 1) {
39,831✔
NEW
UNCOV
1431
    delete_ivector(&t_blast);
×
NEW
UNCOV
1432
    longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1433
  }
1434
  t = t_blast.data[0];
39,831✔
1435
  delete_ivector(&t_blast);
39,831✔
1436

1437
  // Check if already preprocessed;
1438
  term_t t_pre = preprocessor_get(pre, t);
39,831✔
1439
  if (t_pre != NULL_TERM) {
39,831✔
1440
    return t_pre;
1,648✔
1441
  }
1442

1443
// Note: negative affect on general performance due to solved/substituted
1444
//       terms being to complex for explainers.
1445
//
1446
//  // First, if the assertion is a conjunction, just expand
1447
//  if (is_assertion && is_neg_term(t) && term_kind(terms, t) == OR_TERM) {
1448
//    // !(or t1 ... tn) -> !t1 && ... && !tn
1449
//    composite_term_t* t_desc = composite_term_desc(terms, t);
1450
//    for (i = 0; i < t_desc->arity; ++ i) {
1451
//      ivector_push(out, opposite_term(t_desc->arg[i]));
1452
//    }
1453
//    return true_term;
1454
//  }
1455
//
1456
  // Start
1457
  ivector_t* pre_stack = &pre->preprocessing_stack;
38,183✔
1458
  ivector_reset(pre_stack);
38,183✔
1459
  ivector_push(pre_stack, t);
38,183✔
1460

1461
  // Preprocess
1462
  while (pre_stack->size) {
506,110✔
1463
    // Current term
1464
    term_t current = ivector_last(pre_stack);
467,938✔
1465

1466
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
467,938✔
UNCOV
1467
      mcsat_trace_printf(pre->tracer, "current = ");
×
UNCOV
1468
      trace_term_ln(pre->tracer, terms, current);
×
1469
    }
1470

1471
    // If preprocessed already, done
1472
    term_t current_pre = preprocessor_get(pre, current);
467,938✔
1473
    if (current_pre != NULL_TERM) {
467,938✔
1474
      ivector_pop(pre_stack);
31,304✔
1475
      continue;
31,304✔
1476
    }
1477

1478
    // Negation
1479
    if (is_neg_term(current)) {
436,634✔
1480
      term_t child = unsigned_term(current);
88,946✔
1481
      term_t child_pre = preprocessor_get(pre, child);
88,946✔
1482
      if (child_pre == NULL_TERM) {
88,946✔
1483
        ivector_push(pre_stack, child);
42,003✔
1484
        continue;
42,003✔
1485
      } else {
1486
        ivector_pop(pre_stack);
46,943✔
1487
        current_pre = opposite_term(child_pre);
46,943✔
1488
        preprocessor_set(pre, current, current_pre);
46,943✔
1489
        continue;
46,943✔
1490
      }
1491
    }
1492

1493
    // Check for supported types
1494
    type_kind_t type = term_type_kind(terms, current);
347,688✔
1495
    switch (type) {
347,688✔
1496
    case BOOL_TYPE:
347,688✔
1497
    case INT_TYPE:
1498
    case REAL_TYPE:
1499
    case FF_TYPE:
1500
    case UNINTERPRETED_TYPE:
1501
    case FUNCTION_TYPE:
1502
    case BITVECTOR_TYPE:
1503
    case SCALAR_TYPE:
1504
      break;
347,688✔
UNCOV
1505
    default:
×
UNCOV
1506
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1507
    }
1508

1509
    // Kind of term
1510
    term_kind_t current_kind = term_kind(terms, current);
347,688✔
1511

1512
    switch(current_kind) {
347,688✔
1513
    case CONSTANT_TERM:    // constant of uninterpreted/scalar/boolean types
1,829✔
1514
    case BV64_CONSTANT:    // compact bitvector constant (64 bits at most)
1515
    case BV_CONSTANT:      // generic bitvector constant (more than 64 bits)
1516
    case ARITH_CONSTANT:   // rational constant
1517
    case ARITH_FF_CONSTANT:   // finite field constant
1518
      current_pre = current;
1,829✔
1519
      break;
1,829✔
1520

1521
    case UNINTERPRETED_TERM:  // (i.e., global variables, can't be bound).
14,054✔
1522
      current_pre = current;
14,054✔
1523
      // Unless we want special slicing
1524
      if (type == BITVECTOR_TYPE) {
14,054✔
1525
        if (pre->options->bv_var_size > 0) {
4,236✔
1526
          uint32_t size = term_bitsize(terms, current);
23✔
1527
          uint32_t var_size = pre->options->bv_var_size;
23✔
1528
          if (size > var_size) {
23✔
1529
            uint32_t n_vars = (size - 1) / var_size + 1;
2✔
1530
            term_t vars[n_vars];
2✔
1531
            for (i = n_vars - 1; size > 0; i--) {
8✔
1532
              if (size >= var_size) {
6✔
1533
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, var_size));
4✔
1534
                size -= var_size;
4✔
1535
              } else {
1536
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, size));
2✔
1537
                size = 0;
2✔
1538
              }
1539
            }
1540
            current_pre = _o_yices_bvconcat(n_vars, vars);
2✔
1541
            term_t eq = _o_yices_eq(current, current_pre);
2✔
1542
            preprocessor_mark_eq(pre, eq, current);
2✔
1543
          }
1544
        }
1545
      }
1546
      break;
14,054✔
1547

1548
    case ITE_TERM:           // if-then-else
181,427✔
1549
    case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1550
    case EQ_TERM:            // equality
1551
    case OR_TERM:            // n-ary OR
1552
    case XOR_TERM:           // n-ary XOR
1553
    case ARITH_EQ_ATOM:      // equality (t == 0)
1554
    case ARITH_BINEQ_ATOM:   // equality (t1 == t2)  (between two arithmetic terms)
1555
    case ARITH_GE_ATOM:      // inequality (t >= 0)
1556
    case ARITH_FF_EQ_ATOM:   // finite field equality (t == 0)
1557
    case ARITH_FF_BINEQ_ATOM: // finite field equality (t1 == t2)  (between two arithmetic terms)
1558
    case BV_DIV:
1559
    case BV_REM:
1560
    case BV_SMOD:
1561
    case BV_SHL:
1562
    case BV_LSHR:
1563
    case BV_ASHR:
1564
    case BV_EQ_ATOM:
1565
    case BV_GE_ATOM:
1566
    case BV_SGE_ATOM:
1567
    {
1568
      composite_term_t* desc = get_composite(terms, current_kind, current);
181,427✔
1569
      bool children_done = true;
181,427✔
1570
      bool children_same = true;
181,427✔
1571

1572
      n = desc->arity;
181,427✔
1573

1574
      // MCSAT does not yet enforce all extensionality/cardinality constraints
1575
      // for function-sort disequalities. Reject equality atoms whose type needs
1576
      // that monitoring; the Boolean abstraction may assert them either way.
1577
      if (current_kind == EQ_TERM && term_needs_function_diseq_guard(terms, desc->arg[0])) {
181,427✔
1578
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
8✔
1579
      }
1580

1581
      // Is this a top-level equality assertion
1582
      bool is_equality =
181,419✔
1583
          current_kind == EQ_TERM ||
160,684✔
1584
          current_kind == BV_EQ_ATOM ||
103,629✔
1585
          current_kind == ARITH_EQ_ATOM ||
99,871✔
1586
          current_kind == ARITH_BINEQ_ATOM ||
95,727✔
1587
          current_kind == ARITH_FF_EQ_ATOM ||
342,103✔
1588
          current_kind == ARITH_FF_BINEQ_ATOM;
1589
      // don't rewrite if the equality is between Boolean terms
1590
      bool is_boolean = is_boolean_type(term_type(pre->terms, desc->arg[0]));
181,419✔
1591

1592
      term_t eq_solve_var = NULL_TERM;
181,419✔
1593
      if (is_assertion && is_equality && !is_boolean) {
181,419✔
1594
        bool is_lhs_rhs_mixed = desc->arity > 1 &&
139,507✔
1595
          term_type_kind(pre->terms, desc->arg[0]) != term_type_kind(pre->terms, desc->arg[1]);
67,797✔
1596
        // don't rewrite if equality is between mixed terms, e.g. between int and real terms
1597
        if (!is_lhs_rhs_mixed && current == t) {
71,710✔
1598
          eq_solve_var = preprocessor_get_eq_solved_var(pre, t);
47,665✔
1599
          if (eq_solve_var == NULL_TERM) {
47,665✔
1600
            term_t lhs = desc->arg[0];
27,686✔
1601
            term_kind_t lhs_kind = term_kind(terms, lhs);
27,686✔
1602
            // If lhs/rhs is a first-time seen variable, we can solve it
1603
            bool lhs_is_var = lhs_kind == UNINTERPRETED_TERM && is_pos_term(lhs);
27,686✔
1604
            if (lhs_is_var && preprocessor_get(pre, lhs) == NULL_TERM) {
27,686✔
1605
              // First time variable, let's solve
1606
              preprocessor_mark_eq(pre, t, lhs);
24,589✔
1607
              eq_solve_var = lhs;
24,589✔
1608
            } else if (desc->arity > 1) {
3,097✔
1609
              term_t rhs = desc->arg[1];
2,331✔
1610
              term_kind_t rhs_kind = term_kind(terms, rhs);
2,331✔
1611
              bool rhs_is_var = rhs_kind == UNINTERPRETED_TERM && is_pos_term(rhs);
2,331✔
1612
              if (rhs_is_var && preprocessor_get(pre, rhs) == NULL_TERM) {
2,331✔
1613
                // First time variable, let's solve
1614
                preprocessor_mark_eq(pre, t, rhs);
270✔
1615
                eq_solve_var = rhs;
270✔
1616
              }
1617
            }
1618
          } else {
1619
            // Check that we it's not there already
1620
            if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
19,979✔
1621
              eq_solve_var = NULL_TERM;
51✔
1622
            }
1623
          }
1624
        }
1625
      }
1626

1627
      ivector_t children;
1628
      init_ivector(&children, n);
181,419✔
1629

1630
      for (i = 0; i < n; ++ i) {
605,093✔
1631
        term_t child = desc->arg[i];
423,674✔
1632
        if (child != eq_solve_var) {
423,674✔
1633
          term_t child_pre = preprocessor_get(pre, child);
378,887✔
1634
          if (child_pre == NULL_TERM) {
378,887✔
1635
            children_done = false;
108,600✔
1636
            ivector_push(pre_stack, child);
108,600✔
1637
          } else if (child_pre != child) {
270,287✔
1638
            children_same = false;
106,066✔
1639
          }
1640
          if (children_done) {
378,887✔
1641
            ivector_push(&children, child_pre);
256,443✔
1642
          }
1643
        }
1644
      }
1645

1646
      if (eq_solve_var != NULL_TERM) {
181,419✔
1647
        // Check again to make sure we don't have something like x = x + 1
1648
        if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
44,787✔
1649
          // Do it again
UNCOV
1650
          children_done = false;
×
1651
        }
1652
      }
1653

1654
      if (children_done) {
181,419✔
1655
        if (eq_solve_var != NULL_TERM) {
113,457✔
1656
          term_t eq_solve_term = zero_term;
24,808✔
1657
          if (children.size > 0) {
24,808✔
1658
            eq_solve_term = children.data[0];
24,770✔
1659
          }
1660
          preprocessor_set(pre, eq_solve_var, eq_solve_term);
24,808✔
1661
          current_pre = true_term;
24,808✔
1662
        } else {
1663
          if (children_same) {
88,649✔
1664
            current_pre = current;
50,461✔
1665
          } else {
1666
            current_pre = mk_composite(pre, current_kind, n, children.data);
38,188✔
1667
          }
1668
        }
1669
      }
1670

1671
      delete_ivector(&children);
181,419✔
1672

1673
      break;
181,419✔
1674
    }
1675

1676
    case BV_ARRAY:
17,517✔
1677
    {
1678
      composite_term_t* desc = get_composite(terms, current_kind, current);
17,517✔
1679
      bool children_done = true;
17,517✔
1680
      bool children_same = true;
17,517✔
1681

1682
      n = desc->arity;
17,517✔
1683

1684
      ivector_t children;
1685
      init_ivector(&children, n);
17,517✔
1686

1687
      for (i = 0; i < n; ++ i) {
353,534✔
1688
        term_t child = desc->arg[i];
336,017✔
1689
        term_t child_pre = preprocessor_get(pre, child);
336,017✔
1690
        if (child_pre == NULL_TERM) {
336,017✔
1691
          children_done = false;
143,211✔
1692
          ivector_push(pre_stack, child);
143,211✔
1693
        } else {
1694
          if (is_arithmetic_literal(terms, child_pre) || child_pre == false_term) {
192,806✔
1695
            // purify if arithmetic literal, i.e. a = 0 where a is of integer type
1696
            child_pre = preprocessor_purify(pre, child_pre, out);
35,723✔
1697
          }
1698
          if (child_pre != child) {
192,806✔
1699
            children_same = false;
110,041✔
1700
          }
1701
        }
1702
        if (children_done) {
336,017✔
1703
          ivector_push(&children, child_pre);
179,684✔
1704
        }
1705
      }
1706

1707
      if (children_done) {
17,517✔
1708
        if (children_same) {
9,165✔
1709
          current_pre = current;
2,210✔
1710
        } else {
1711
          current_pre = mk_composite(pre, current_kind, n, children.data);
6,955✔
1712
        }
1713
      }
1714

1715
      delete_ivector(&children);
17,517✔
1716

1717
      break;
17,517✔
1718
    }
1719

1720
    case ARITH_ABS:
8✔
1721
    {
1722
      term_t arg = arith_abs_arg(terms, current);
8✔
1723
      term_t arg_pre = preprocessor_get(pre, arg);
8✔
1724
      if (arg_pre == NULL_TERM) {
8✔
1725
        ivector_push(pre_stack, arg);
3✔
1726
      } else {
1727
        type_t arg_pre_type = term_type(pre->terms, arg_pre);
5✔
1728
        term_t arg_pre_is_positive = mk_arith_term_geq0(&pre->tm, arg_pre);
5✔
1729
        term_t arg_negative = _o_yices_neg(arg_pre);
5✔
1730
        current_pre = mk_ite(&pre->tm, arg_pre_is_positive, arg_pre, arg_negative, arg_pre_type);
5✔
1731
      }
1732
      break;
8✔
1733
    }
1734

1735
    case BV_SDIV:
20✔
1736
    {
1737
      composite_term_t* desc = get_composite(terms, current_kind, current);
20✔
1738
      assert(desc->arity == 2);
1739
      term_t s = desc->arg[0];
20✔
1740
      term_t s_pre = preprocessor_get(pre, s);
20✔
1741
      if (s_pre == NULL_TERM) {
20✔
1742
        ivector_push(pre_stack, s);
7✔
1743
      }
1744
      term_t t = desc->arg[1];
20✔
1745
      term_t t_pre = preprocessor_get(pre, t);
20✔
1746
      if (t_pre == NULL_TERM) {
20✔
1747
        ivector_push(pre_stack, t);
5✔
1748
      }
1749
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
20✔
1750
        type_t tau = term_type(terms, s_pre);
11✔
1751
        uint32_t n = term_bitsize(terms, s_pre);
11✔
1752
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
11✔
1753
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
11✔
1754
        // if (msb_s) {
1755
        //   if (msb_t) {
1756
        //     t1: udiv(-s, -t)
1757
        //   } else {
1758
        //     t2: -udiv(-s, t)
1759
        //   }
1760
        // } else {
1761
        //   if (msb_t) {
1762
        //     t3: -udiv(s, -t)
1763
        //   } else {
1764
        //     t4: udiv(s, t)
1765
        //   }
1766
        // }
1767
        term_t neg_s = mk_bvneg(tm, s_pre);
11✔
1768
        term_t neg_t = mk_bvneg(tm, t_pre);
11✔
1769

1770
        term_t t1 = mk_bvdiv(tm, neg_s, neg_t);
11✔
1771
        term_t t2 = mk_bvdiv(tm, neg_s, t_pre);
11✔
1772
        t2 = mk_bvneg(&pre->tm, t2);
11✔
1773
        term_t t3 = mk_bvdiv(tm, s_pre, neg_t);
11✔
1774
        t3 = mk_bvneg(&pre->tm, t3);
11✔
1775
        term_t t4 = mk_bvdiv(tm, s_pre, t_pre);
11✔
1776

1777
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
11✔
1778
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
11✔
1779

1780
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
11✔
1781
      }
1782
      break;
20✔
1783
    }
1784
    case BV_SREM:
21✔
1785
    {
1786
      composite_term_t* desc = get_composite(terms, current_kind, current);
21✔
1787
      assert(desc->arity == 2);
1788
      term_t s = desc->arg[0];
21✔
1789
      term_t s_pre = preprocessor_get(pre, s);
21✔
1790
      if (s_pre == NULL_TERM) {
21✔
1791
        ivector_push(pre_stack, s);
8✔
1792
      }
1793
      term_t t = desc->arg[1];
21✔
1794
      term_t t_pre = preprocessor_get(pre, t);
21✔
1795
      if (t_pre == NULL_TERM) {
21✔
1796
        ivector_push(pre_stack, t);
3✔
1797
      }
1798
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
21✔
1799
        type_t tau = term_type(terms, s_pre);
12✔
1800
        uint32_t n = term_bitsize(terms, s_pre);
12✔
1801
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
12✔
1802
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
12✔
1803
        // if (msb_s) {
1804
        //   if (msb_t) {
1805
        //     t1: -urem(-s, -t)
1806
        //   } else {
1807
        //     t2: -urem(-s, t)
1808
        //   }
1809
        // } else {
1810
        //   if (msb_t) {
1811
        //     t3: -urem(s, -t)
1812
        //   } else {
1813
        //     t4: urem(s, t)
1814
        //   }
1815
        // }
1816
        term_t neg_s = mk_bvneg(tm, s_pre);
12✔
1817
        term_t neg_t = mk_bvneg(tm, t_pre);
12✔
1818

1819
        term_t t1 = mk_bvrem(tm, neg_s, neg_t);
12✔
1820
        t1 = mk_bvneg(tm, t1);
12✔
1821
        term_t t2 = mk_bvrem(tm, neg_s, t_pre);
12✔
1822
        t2 = mk_bvneg(tm, t2);
12✔
1823
        term_t t3 = mk_bvrem(tm, s_pre, neg_t);
12✔
1824
        term_t t4 = mk_bvrem(tm, s_pre, t_pre);
12✔
1825

1826
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
12✔
1827
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
12✔
1828

1829
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
12✔
1830
      }
1831
      break;
21✔
1832
    }
1833
    case BIT_TERM: // bit-select current = child[i]
112,741✔
1834
    {
1835
      uint32_t index = bit_term_index(terms, current);
112,741✔
1836
      term_t arg = bit_term_arg(terms, current);
112,741✔
1837
      term_t arg_pre = preprocessor_get(pre, arg);
112,741✔
1838
      if (arg_pre == NULL_TERM) {
112,741✔
1839
        ivector_push(pre_stack, arg);
1,584✔
1840
      } else {
1841
        if (arg_pre == arg) {
111,157✔
1842
          current_pre = current;
73,115✔
1843
        } else {
1844
          if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,042✔
UNCOV
1845
            mcsat_trace_printf(pre->tracer, "arg_pre = ");
×
UNCOV
1846
            trace_term_ln(pre->tracer, terms, arg_pre);
×
1847
          }
1848
          // For simplification purposes use API
1849
          current_pre = _o_yices_bitextract(arg_pre, index);
38,042✔
1850
          assert(current_pre != NULL_TERM);
1851
        }
1852
      }
1853
      break;
112,741✔
1854
    }
1855
    case BV_POLY:  // polynomial with generic bitvector coefficients
33✔
1856
    {
1857
      bvpoly_t* p = bvpoly_term_desc(terms, current);
33✔
1858

1859
      bool children_done = true;
33✔
1860
      bool children_same = true;
33✔
1861

1862
      n = p->nterms;
33✔
1863

1864
      ivector_t children;
1865
      init_ivector(&children, n);
33✔
1866

1867
      for (i = 0; i < n; ++ i) {
84✔
1868
        term_t x = p->mono[i].var;
51✔
1869
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
51✔
1870

1871
        if (x_pre != const_idx) {
51✔
1872
          if (x_pre == NULL_TERM) {
47✔
1873
            children_done = false;
10✔
1874
            ivector_push(pre_stack, x);
10✔
1875
          } else if (x_pre != x) {
37✔
1876
            children_same = false;
23✔
1877
          }
1878
        }
1879

1880
        if (children_done) { ivector_push(&children, x_pre); }
51✔
1881
      }
1882

1883
      if (children_done) {
33✔
1884
        if (children_same) {
26✔
1885
          current_pre = current;
11✔
1886
        } else {
1887
          current_pre = mk_bvarith_poly(tm, p, n, children.data);
15✔
1888
        }
1889
      }
1890

1891
      delete_ivector(&children);
33✔
1892

1893
      break;
33✔
1894
    }
1895
    case BV64_POLY: // polynomial with 64bit coefficients
2,573✔
1896
    {
1897
      bvpoly64_t* p = bvpoly64_term_desc(terms, current);
2,573✔
1898

1899
      bool children_done = true;
2,573✔
1900
      bool children_same = true;
2,573✔
1901

1902
      n = p->nterms;
2,573✔
1903

1904
      ivector_t children;
1905
      init_ivector(&children, n);
2,573✔
1906

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

1911
        if (x_pre != const_idx) {
7,254✔
1912
          if (x_pre == NULL_TERM) {
5,580✔
1913
            children_done = false;
1,308✔
1914
            ivector_push(pre_stack, x);
1,308✔
1915
          } else if (x_pre != x) {
4,272✔
1916
            children_same = false;
3,568✔
1917
          }
1918
        }
1919

1920
        if (children_done) { ivector_push(&children, x_pre); }
7,254✔
1921
      }
1922

1923
      if (children_done) {
2,573✔
1924
        if (children_same) {
1,872✔
1925
          current_pre = current;
279✔
1926
        } else {
1927
          current_pre = mk_bvarith64_poly(tm, p, n, children.data);
1,593✔
1928
        }
1929
      }
1930

1931
      delete_ivector(&children);
2,573✔
1932

1933
      break;
2,573✔
1934
    }
1935

1936
    case POWER_PRODUCT:    // power products: (t1^d1 * ... * t_n^d_n)
1,675✔
1937
    {
1938
      pprod_t* pp = pprod_term_desc(terms, current);
1,675✔
1939
      bool children_done = true;
1,675✔
1940
      bool children_same = true;
1,675✔
1941

1942
      n = pp->len;
1,675✔
1943

1944
      ivector_t children;
1945
      init_ivector(&children, n);
1,675✔
1946

1947
      for (i = 0; i < n; ++ i) {
5,316✔
1948
        term_t x = pp->prod[i].var;
3,641✔
1949
        term_t x_pre = preprocessor_get(pre, x);
3,641✔
1950

1951
        if (x_pre == NULL_TERM) {
3,641✔
1952
          children_done = false;
452✔
1953
          ivector_push(pre_stack, x);
452✔
1954
        } else if (x_pre != x) {
3,189✔
1955
          children_same = false;
96✔
1956
        }
1957

1958
        if (children_done) { ivector_push(&children, x_pre); }
3,641✔
1959
      }
1960

1961
      if (children_done) {
1,675✔
1962
        if (children_same) {
1,339✔
1963
          current_pre = current;
1,281✔
1964
        } else {
1965
          // NOTE: it doens't change pp, it just uses it as a frame
1966
          current_pre = mk_pprod(tm, pp, n, children.data);
58✔
1967
        }
1968
      }
1969

1970
      delete_ivector(&children);
1,675✔
1971

1972
      break;
1,675✔
1973
    }
1974

1975
    case ARITH_POLY:       // polynomial with rational coefficients
6,940✔
1976
    {
1977
      polynomial_t* p = poly_term_desc(terms, current);
6,940✔
1978

1979
      bool children_done = true;
6,940✔
1980
      bool children_same = true;
6,940✔
1981

1982
      n = p->nterms;
6,940✔
1983

1984
      ivector_t children;
1985
      init_ivector(&children, n);
6,940✔
1986

1987
      for (i = 0; i < n; ++ i) {
26,868✔
1988
        term_t x = p->mono[i].var;
19,928✔
1989
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
19,928✔
1990

1991
        if (x_pre != const_idx) {
19,928✔
1992
          if (x_pre == NULL_TERM) {
16,899✔
1993
            children_done = false;
2,569✔
1994
            ivector_push(pre_stack, x);
2,569✔
1995
          } else if (x_pre != x) {
14,330✔
1996
            children_same = false;
946✔
1997
          }
1998
        }
1999

2000
        if (children_done) { ivector_push(&children, x_pre); }
19,928✔
2001
      }
2002

2003
      if (children_done) {
6,940✔
2004
        if (children_same) {
5,487✔
2005
          current_pre = current;
4,887✔
2006
        } else {
2007
          current_pre = mk_arith_poly(tm, p, n, children.data);
600✔
2008
        }
2009
      }
2010

2011
      delete_ivector(&children);
6,940✔
2012

2013
      break;
6,940✔
2014
    }
2015

2016
    case ARITH_FF_POLY:    // polynomial with finite field coefficients
150✔
2017
    {
2018
      polynomial_t* p = finitefield_poly_term_desc(terms, current);
150✔
2019
      const rational_t *mod = finitefield_term_order(terms, current);
150✔
2020

2021
      bool children_done = true;
150✔
2022
      bool children_same = true;
150✔
2023

2024
      n = p->nterms;
150✔
2025

2026
      ivector_t children;
2027
      init_ivector(&children, n);
150✔
2028

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

2033
        if (x_pre != const_idx) {
918✔
2034
          if (x_pre == NULL_TERM) {
864✔
2035
            children_done = false;
380✔
2036
            ivector_push(pre_stack, x);
380✔
2037
          } else if (x_pre != x) {
484✔
UNCOV
2038
            children_same = false;
×
2039
          }
2040
        }
2041

2042
        if (children_done) { ivector_push(&children, x_pre); }
918✔
2043
      }
2044

2045
      if (children_done) {
150✔
2046
        if (children_same) {
75✔
2047
          current_pre = current;
75✔
2048
        } else {
UNCOV
2049
          current_pre = mk_arith_ff_poly(tm, p, n, children.data, mod);
×
2050
        }
2051
      }
2052

2053
      delete_ivector(&children);
150✔
2054

2055
      break;
150✔
2056
    }
2057

2058
    // FOLLOWING ARE UNINTEPRETED, SO WE PURIFY THE ARGUMENTS
2059

2060
    case APP_TERM:           // application of an uninterpreted function
8,666✔
2061
    case ARITH_RDIV:         // regular division (/ x y)
2062
    case ARITH_IDIV:         // division: (div x y) as defined in SMT-LIB 2
2063
    case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
2064
    case UPDATE_TERM:        // update array
2065
    {
2066
      composite_term_t* desc = get_composite(terms, current_kind, current);
8,666✔
2067
      bool children_done = true;
8,666✔
2068
      bool children_same = true;
8,666✔
2069

2070
      n = desc->arity;
8,666✔
2071

2072
      ivector_t children;
2073
      init_ivector(&children, n);
8,666✔
2074

2075
      for (i = 0; i < n; ++ i) {
29,845✔
2076
        term_t child = desc->arg[i];
21,179✔
2077
        term_t child_pre = preprocessor_get(pre, child);
21,179✔
2078

2079
        if (child_pre == NULL_TERM) {
21,179✔
2080
          children_done = false;
4,060✔
2081
          ivector_push(pre_stack, child);
4,060✔
2082
        } else {
2083
          // Purify if needed
2084
          child_pre = preprocessor_purify(pre, child_pre, out);
17,119✔
2085
          // If interpreted terms, we need to purify non-variables
2086
          if (child_pre != child) { children_same = false; }
17,119✔
2087
        }
2088

2089
        if (children_done) { ivector_push(&children, child_pre); }
21,179✔
2090
      }
2091

2092
      if (children_done) {
8,666✔
2093
        if (children_same) {
5,654✔
2094
          current_pre = current;
4,219✔
2095
        } else {
2096
          current_pre = mk_composite(pre, current_kind, n, children.data);
1,435✔
2097
        }
2098
      }
2099

2100
      delete_ivector(&children);
8,666✔
2101

2102
      break;
8,666✔
2103
    }
2104

UNCOV
2105
    case ARITH_IS_INT_ATOM:
×
2106
    {
2107
      // replace with t <= floor(t)
UNCOV
2108
      term_t child = arith_is_int_arg(terms, current);
×
UNCOV
2109
      term_t child_pre = preprocessor_get(pre, child);
×
UNCOV
2110
      if (child_pre != NULL_TERM) {
×
UNCOV
2111
        child_pre = preprocessor_purify(pre, child_pre, out);
×
UNCOV
2112
        current_pre = arith_floor(terms, child_pre);
×
UNCOV
2113
        current_pre = mk_arith_leq(tm, child_pre, current_pre);
×
2114
      } else {
UNCOV
2115
        ivector_push(pre_stack, child);
×
2116
      }
UNCOV
2117
      break;
×
2118
    }
2119

2120
    case ARITH_FLOOR:        // floor: purify, but its interpreted
7✔
2121
    {
2122
      term_t child = arith_floor_arg(terms, current);
7✔
2123
      term_t child_pre = preprocessor_get(pre, child);
7✔
2124

2125
      if (child_pre != NULL_TERM) {
7✔
2126
        if (term_kind(terms, child_pre) == ARITH_CONSTANT) {
4✔
2127
          rational_t floor;
2128
          q_init(&floor);
1✔
2129
          q_set(&floor, rational_term_desc(terms, child_pre));
1✔
2130
          q_floor(&floor);
1✔
2131
          current_pre = arith_constant(terms, &floor);
1✔
2132
          q_clear(&floor);
1✔
2133
        } else {
2134
          child_pre = preprocessor_purify(pre, child_pre, out);
3✔
2135
          if (child_pre != child) {
3✔
2136
            current_pre = arith_floor(terms, child_pre);
1✔
2137
          } else {
2138
            current_pre = current;
2✔
2139
          }
2140
        }
2141
      } else {
2142
        ivector_push(pre_stack, child);
3✔
2143
      }
2144

2145
      break;
7✔
2146
    }
2147

UNCOV
2148
    case ARITH_CEIL:        // floor: purify, but its interpreted
×
2149
    {
UNCOV
2150
      term_t child = arith_ceil_arg(terms, current);
×
UNCOV
2151
      term_t child_pre = preprocessor_get(pre, child);
×
2152

UNCOV
2153
      if (child_pre != NULL_TERM) {
×
UNCOV
2154
        child_pre = preprocessor_purify(pre, child_pre, out);
×
UNCOV
2155
        if (child_pre != child) {
×
UNCOV
2156
          current_pre = arith_floor(terms, child_pre);
×
2157
        } else {
UNCOV
2158
          current_pre = current;
×
2159
        }
2160
      } else {
UNCOV
2161
        ivector_push(pre_stack, child);
×
2162
      }
2163

UNCOV
2164
      break;
×
2165
    }
2166

2167
    case DISTINCT_TERM:
27✔
2168
    {
2169
      composite_term_t* desc = get_composite(terms, current_kind, current);
27✔
2170

2171
      bool children_done = true;
27✔
2172
      n = desc->arity;
27✔
2173

2174
      // DISTINCT_TERM is lowered below into pairwise disequalities. Apply the
2175
      // same function-sort guard before that expansion.
2176
      for (i = 0; i < n; ++ i) {
125✔
2177
        if (term_needs_function_diseq_guard(terms, desc->arg[i])) {
101✔
2178
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
3✔
2179
        }
2180
      }
2181

2182
      ivector_t children;
2183
      init_ivector(&children, n);
24✔
2184

2185
      for (i = 0; i < n; ++ i) {
122✔
2186
        term_t child = desc->arg[i];
98✔
2187
        term_t child_pre = preprocessor_get(pre, child);
98✔
2188

2189
        if (child_pre == NULL_TERM) {
98✔
2190
          children_done = false;
41✔
2191
          ivector_push(pre_stack, child);
41✔
2192
        }
2193

2194
        if (children_done) { ivector_push(&children, child_pre); }
98✔
2195
      }
2196

2197
      if (children_done) {
24✔
2198
        ivector_t distinct;
2199
        init_ivector(&distinct, 0);
14✔
2200

2201
        for (i = 0; i < n; ++ i) {
70✔
2202
          for (j = i + 1; j < n; ++ j) {
148✔
2203
            term_t neq = mk_eq(&pre->tm, children.data[i], children.data[j]);
92✔
2204
            neq = opposite_term(neq);
92✔
2205
            ivector_push(&distinct, neq);
92✔
2206
          }
2207
        }
2208
        current_pre = mk_and(&pre->tm, distinct.size, distinct.data);
14✔
2209

2210
        delete_ivector(&distinct);
14✔
2211
      }
2212

2213
      delete_ivector(&children);
24✔
2214

2215
      break;
24✔
2216
    }
2217

UNCOV
2218
    case LAMBDA_TERM:
×
UNCOV
2219
      longjmp(*pre->exception, LAMBDAS_NOT_SUPPORTED);
×
2220
      break;
2221

UNCOV
2222
    default:
×
2223
      // UNSUPPORTED TERM/THEORY
UNCOV
2224
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
2225
      break;
2226
    }
2227

2228
    if (current_pre != NULL_TERM) {
347,677✔
2229
      preprocessor_set(pre, current, current_pre);
264,161✔
2230
      ivector_pop(pre_stack);
264,161✔
2231
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
264,161✔
UNCOV
2232
        mcsat_trace_printf(pre->tracer, "current_pre = ");
×
UNCOV
2233
        trace_term_ln(pre->tracer, terms, current_pre);
×
2234
      }
2235
    }
2236

2237
  }
2238

2239
  // Return the result
2240
  t_pre = preprocessor_get(pre, t);
38,172✔
2241
  if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,172✔
UNCOV
2242
    mcsat_trace_printf(pre->tracer, "t_pre = ");
×
UNCOV
2243
    trace_term_ln(pre->tracer, terms, t_pre);
×
2244
  }
2245

2246
  ivector_reset(pre_stack);
38,172✔
2247

2248
  assert(t_pre != NULL_TERM);
2249
  return t_pre;
38,172✔
2250
}
2251

2252
void preprocessor_set_exception_handler(preprocessor_t* pre, jmp_buf* handler) {
×
UNCOV
2253
  pre->exception = handler;
×
2254
}
×
2255

2256
void preprocessor_push(preprocessor_t* pre) {
528✔
2257
  scope_holder_push(&pre->scope,
528✔
2258
      &pre->preprocess_map_list.size,
2259
      &pre->tuple_blast_list.size,
2260
      &pre->tuple_blast_data.size,
2261
      &pre->tuple_blast_atoms.size,
2262
      &pre->purification_map_list.size,
2263
      &pre->equalities_list.size,
2264
      NULL);
2265
}
528✔
2266

2267
void preprocessor_pop(preprocessor_t* pre) {
454✔
2268

2269
  uint32_t preprocess_map_list_size = 0;
454✔
2270
  uint32_t tuple_blast_list_size = 0;
454✔
2271
  uint32_t tuple_blast_data_size = 0;
454✔
2272
  uint32_t tuple_blast_atoms_size = 0;
454✔
2273
  uint32_t purification_map_list_size = 0;
454✔
2274
  uint32_t equalities_list_size = 0;
454✔
2275

2276
  scope_holder_pop(&pre->scope,
454✔
2277
      &preprocess_map_list_size,
2278
      &tuple_blast_list_size,
2279
      &tuple_blast_data_size,
2280
      &tuple_blast_atoms_size,
2281
      &purification_map_list_size,
2282
      &equalities_list_size,
2283
      NULL);
2284

2285
  while (pre->preprocess_map_list.size > preprocess_map_list_size) {
11,955✔
2286
    term_t t = ivector_last(&pre->preprocess_map_list);
11,501✔
2287
    ivector_pop(&pre->preprocess_map_list);
11,501✔
2288
    int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
11,501✔
2289
    assert(find != NULL);
2290
    int_hmap_erase(&pre->preprocess_map, find);
11,501✔
2291
  }
2292

2293
  while (pre->tuple_blast_list.size > tuple_blast_list_size) {
1,816✔
2294
    term_t t = ivector_last(&pre->tuple_blast_list);
1,362✔
2295
    ivector_pop(&pre->tuple_blast_list);
1,362✔
2296
    int_hmap_pair_t* find = int_hmap_find(&pre->tuple_blast_map, t);
1,362✔
2297
    assert(find != NULL);
2298
    int_hmap_erase(&pre->tuple_blast_map, find);
1,362✔
2299
  }
2300
  ivector_shrink(&pre->tuple_blast_data, tuple_blast_data_size);
454✔
2301
  ivector_shrink(&pre->tuple_blast_atoms, tuple_blast_atoms_size);
454✔
2302

2303
  while (pre->purification_map_list.size > purification_map_list_size) {
589✔
2304
    term_t t = ivector_last(&pre->purification_map_list);
135✔
2305
    ivector_pop(&pre->purification_map_list);
135✔
2306
    int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
135✔
2307
    assert(find != NULL);
2308
    int_hmap_erase(&pre->purification_map, find);
135✔
2309
  }
2310

2311
  while (pre->equalities_list.size > equalities_list_size) {
504✔
2312
    term_t eq = ivector_last(&pre->equalities_list);
50✔
2313
    ivector_pop(&pre->equalities_list);
50✔
2314
    int_hmap_pair_t* find = int_hmap_find(&pre->equalities, eq);
50✔
2315
    assert(find != NULL);
2316
    int_hmap_erase(&pre->equalities, find);
50✔
2317
  }
2318
}
454✔
2319

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

2322
static
2323
value_t build_value_from_flat(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* flat, uint32_t* idx) {
104✔
2324
  type_table_t* types = pre->terms->types;
104✔
2325

2326
  if (type_kind(types, tau) == TUPLE_TYPE) {
104✔
2327
    tuple_type_t* tuple = tuple_type_desc(types, tau);
34✔
2328
    uint32_t i, n = tuple->nelem;
34✔
2329
    value_t elem[n];
34✔
2330
    for (i = 0; i < n; ++i) {
103✔
2331
      elem[i] = build_value_from_flat(pre, vtbl, tuple->elem[i], flat, idx);
69✔
2332
      if (elem[i] == null_value) {
69✔
NEW
UNCOV
2333
        return null_value;
×
2334
      }
2335
    }
2336
    return vtbl_mk_tuple(vtbl, n, elem);
34✔
2337
  } else if (type_kind(types, tau) == FUNCTION_TYPE) {
70✔
2338
    uint32_t n = type_leaf_count(pre, tau);
3✔
2339
    value_t v = merge_blasted_function_value(pre, vtbl, tau, flat + *idx, n);
3✔
2340
    *idx += n;
3✔
2341
    return v;
3✔
2342
  } else {
2343
    value_t v = flat[*idx];
67✔
2344
    (*idx)++;
67✔
2345
    return v;
67✔
2346
  }
2347
}
2348

2349
static
2350
bool map_args_match(value_table_t* vtbl, value_t map, const value_t* args, uint32_t n) {
23✔
2351
  value_map_t* m = vtbl_map(vtbl, map);
23✔
2352
  uint32_t i;
2353
  if (m->arity != n) {
23✔
NEW
UNCOV
2354
    return false;
×
2355
  }
2356
  for (i = 0; i < n; ++i) {
48✔
2357
    if (m->arg[i] != args[i]) {
34✔
2358
      return false;
9✔
2359
    }
2360
  }
2361
  return true;
14✔
2362
}
2363

2364
static
2365
value_t find_map_result(value_table_t* vtbl, const ivector_t* maps, const value_t* args, uint32_t n, value_t def) {
19✔
2366
  uint32_t i;
2367
  for (i = 0; i < maps->size; ++i) {
28✔
2368
    value_t map = maps->data[i];
23✔
2369
    if (map_args_match(vtbl, map, args, n)) {
23✔
2370
      return vtbl_map(vtbl, map)->val;
14✔
2371
    }
2372
  }
2373
  return def;
5✔
2374
}
2375

2376
static
2377
void add_unique_flat_args(ivector_t* offsets, ivector_t* data, const value_t* args, uint32_t n) {
14✔
2378
  uint32_t i, j;
2379
  for (i = 0; i < offsets->size; ++i) {
18✔
2380
    uint32_t off = offsets->data[i];
9✔
2381
    bool same = true;
9✔
2382
    for (j = 0; j < n; ++j) {
18✔
2383
      if (data->data[off + j] != args[j]) {
13✔
2384
        same = false;
4✔
2385
        break;
4✔
2386
      }
2387
    }
2388
    if (same) {
9✔
2389
      return;
5✔
2390
    }
2391
  }
2392
  ivector_push(offsets, data->size);
9✔
2393
  ivector_add(data, args, n);
9✔
2394
}
2395

2396
static
2397
value_t merge_blasted_function_value(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* leaves, uint32_t nleaves) {
5✔
2398
  type_table_t* types = pre->terms->types;
5✔
2399
  function_type_t* fun = function_type_desc(types, tau);
5✔
2400
  type_t codom = fun->range;
5✔
2401
  uint32_t i, j;
2402
  ivector_t flat_dom;
2403
  ivector_t unique_offsets;
2404
  ivector_t unique_args;
2405
  ivector_t orig_maps;
2406
  value_t result = null_value;
5✔
2407
  value_t leaf_defaults[nleaves];
5✔
2408
  ivector_t leaf_maps[nleaves];
5✔
2409
  uint32_t flat_n;
2410
  uint32_t maps_init = 0;
5✔
2411
  /* Short tag describing why we bailed, so the caller (or a user
2412
   * investigating a missing model entry) can see the cause through a
2413
   * single line of trace output. Set immediately before each `goto done`
2414
   * error exit; the successful path leaves it NULL. */
2415
  const char* fail_reason = NULL;
5✔
2416

2417
  /* All heap-backed scratch vectors are initialized up-front so that every
2418
   * exit through the `done:` label has the same cleanup responsibilities.
2419
   * In particular orig_maps is deliberately initialized here rather than
2420
   * just before the loop that populates it: if its init moves, `goto done`
2421
   * paths that run before the init would otherwise silently leak the
2422
   * vector. Keeping the init paired with the other unconditional inits
2423
   * makes that invariant self-evident. */
2424
  init_ivector(&flat_dom, 0);
5✔
2425
  init_ivector(&unique_offsets, 0);
5✔
2426
  init_ivector(&unique_args, 0);
5✔
2427
  init_ivector(&orig_maps, 0);
5✔
2428

2429
  for (i = 0; i < fun->ndom; ++i) {
10✔
2430
    type_collect_flat(types, fun->domain[i], &flat_dom);
5✔
2431
  }
2432
  flat_n = flat_dom.size;
5✔
2433

2434
  for (i = 0; i < nleaves; ++i) {
15✔
2435
    value_t def = null_value;
10✔
2436
    type_t leaf_tau = NULL_TYPE;
10✔
2437
    init_ivector(&leaf_maps[i], 0);
10✔
2438
    maps_init = i + 1;
10✔
2439
    if (!object_is_function(vtbl, leaves[i]) && !object_is_update(vtbl, leaves[i])) {
10✔
NEW
2440
      fail_reason = "leaf value is neither a function nor an update object";
×
NEW
2441
      goto done;
×
2442
    }
2443
    if (object_is_update(vtbl, leaves[i])) {
10✔
2444
      vtbl_expand_update(vtbl, leaves[i], &def, &leaf_tau);
10✔
2445
      leaf_defaults[i] = def;
10✔
2446
      if (vtbl->hset1 != NULL) {
10✔
2447
        ivector_add(&leaf_maps[i], (int32_t*) vtbl->hset1->data, vtbl->hset1->nelems);
10✔
2448
        for (j = 0; j < vtbl->hset1->nelems; ++j) {
24✔
2449
          value_map_t* map = vtbl_map(vtbl, vtbl->hset1->data[j]);
14✔
2450
          if (map->arity != flat_n) {
14✔
NEW
UNCOV
2451
            fail_reason = "update leaf map arity does not match flattened domain";
×
NEW
UNCOV
2452
            goto done;
×
2453
          }
2454
          add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
14✔
2455
        }
2456
      }
2457
      continue;
10✔
2458
    }
NEW
2459
    value_fun_t* fun_value = vtbl_function(vtbl, leaves[i]);
×
NEW
2460
    def = fun_value->def;
×
NEW
2461
    leaf_tau = fun_value->type;
×
NEW
2462
    leaf_defaults[i] = def;
×
NEW
2463
    ivector_add(&leaf_maps[i], (int32_t*) fun_value->map, fun_value->map_size);
×
NEW
2464
    for (j = 0; j < fun_value->map_size; ++j) {
×
NEW
2465
      value_map_t* map = vtbl_map(vtbl, fun_value->map[j]);
×
NEW
2466
      if (map->arity != flat_n) {
×
NEW
2467
        fail_reason = "function leaf map arity does not match flattened domain";
×
NEW
2468
        goto done;
×
2469
      }
NEW
2470
      add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
×
2471
    }
2472
  }
2473

2474
  for (i = 0; i < unique_offsets.size; ++i) {
14✔
2475
    uint32_t flat_idx = unique_offsets.data[i];
9✔
2476
    const value_t* flat_args = (value_t*) (unique_args.data + flat_idx);
9✔
2477
    value_t leaf_values[nleaves];
9✔
2478
    uint32_t idx;
2479
    value_t mapv;
2480

2481
    for (j = 0; j < nleaves; ++j) {
28✔
2482
      leaf_values[j] = find_map_result(vtbl, &leaf_maps[j], flat_args, flat_n, leaf_defaults[j]);
19✔
2483
    }
2484

2485
    idx = 0;
9✔
2486
    value_t out_val = build_value_from_flat(pre, vtbl, codom, leaf_values, &idx);
9✔
2487
    if (out_val == null_value) {
9✔
NEW
2488
      fail_reason = "could not build codomain value from flat leaf values";
×
NEW
2489
      goto done;
×
2490
    }
2491

2492
    value_t args_orig[fun->ndom];
9✔
2493
    idx = 0;
9✔
2494
    for (j = 0; j < fun->ndom; ++j) {
18✔
2495
      args_orig[j] = build_value_from_flat(pre, vtbl, fun->domain[j], flat_args, &idx);
9✔
2496
      if (args_orig[j] == null_value) {
9✔
NEW
2497
        fail_reason = "could not rebuild a domain argument from flat leaf values";
×
NEW
2498
        goto done;
×
2499
      }
2500
    }
2501
    mapv = vtbl_mk_map(vtbl, fun->ndom, args_orig, out_val);
9✔
2502
    ivector_push(&orig_maps, mapv);
9✔
2503
  }
2504

2505
  {
2506
    uint32_t idx = 0;
5✔
2507
    value_t def_val = build_value_from_flat(pre, vtbl, codom, leaf_defaults, &idx);
5✔
2508
    if (def_val == null_value) {
5✔
NEW
2509
      fail_reason = "could not rebuild the function default value";
×
NEW
2510
      goto done;
×
2511
    }
2512
    result = vtbl_mk_function(vtbl, tau, orig_maps.size, (value_t*) orig_maps.data, def_val);
5✔
2513
  }
2514

2515
 done:
5✔
2516
  if (fail_reason != NULL && trace_enabled(pre->tracer, "mcsat::preprocess")) {
5✔
NEW
2517
    mcsat_trace_printf(pre->tracer,
×
2518
                       "merge_blasted_function_value: %s\n", fail_reason);
2519
  }
2520
  /* Single cleanup path for every error exit. All ivectors above are
2521
   * unconditionally initialized before any `goto done`, so unconditional
2522
   * deletes here are correct and stay correct if new error branches are
2523
   * added. leaf_maps is the only exception: its initialization is
2524
   * interleaved with error checks in the first loop, so we still only
2525
   * delete the prefix recorded by maps_init. */
2526
  for (i = 0; i < maps_init; ++i) {
15✔
2527
    delete_ivector(&leaf_maps[i]);
10✔
2528
  }
2529
  delete_ivector(&orig_maps);
5✔
2530
  delete_ivector(&unique_offsets);
5✔
2531
  delete_ivector(&unique_args);
5✔
2532
  delete_ivector(&flat_dom);
5✔
2533
  return result;
5✔
2534
}
2535

2536
static
2537
void preprocessor_build_tuple_model(preprocessor_t* pre, model_t* model) {
44✔
2538
  value_table_t* vtbl = model_get_vtbl(model);
44✔
2539
  type_table_t* types = pre->terms->types;
44✔
2540
  uint32_t i;
2541

2542
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
58✔
2543
    term_t atom = pre->tuple_blast_atoms.data[i];
14✔
2544
    ivector_t leaves;
2545
    type_t tau = term_type(pre->terms, atom);
14✔
2546
    uint32_t n, j;
2547

2548
    if (model_find_term_value(model, atom) != null_value) {
14✔
NEW
2549
      continue;
×
2550
    }
2551

2552
    init_ivector(&leaves, 0);
14✔
2553
    tuple_blast_get(pre, atom, &leaves);
14✔
2554
    n = leaves.size;
14✔
2555
    if (n == 0) {
14✔
NEW
2556
      delete_ivector(&leaves);
×
NEW
2557
      continue;
×
2558
    }
2559

2560
    value_t leaf_vals[n];
14✔
2561
    bool ok = true;
14✔
2562
    for (j = 0; j < n; ++j) {
46✔
2563
      value_t v = model_get_term_value(model, leaves.data[j]);
32✔
2564
      if (v < 0) {
32✔
NEW
2565
        ok = false;
×
NEW
2566
        break;
×
2567
      }
2568
      leaf_vals[j] = v;
32✔
2569
    }
2570
    if (!ok) {
14✔
2571
      /* A blasted leaf was never assigned a value by the mcsat search.
2572
       * We cannot reconstruct a value for the original atom, so it will
2573
       * be absent from the returned model. Log which atom and which leaf
2574
       * index so a user investigating a missing (show-model) entry can
2575
       * pin the gap. */
NEW
2576
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2577
        mcsat_trace_printf(pre->tracer,
×
2578
                           "preprocessor_build_tuple_model: dropping atom ");
NEW
2579
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2580
        mcsat_trace_printf(pre->tracer,
×
2581
                           "  (blasted leaf %u has no value in the trail model)\n", j);
2582
      }
NEW
2583
      delete_ivector(&leaves);
×
NEW
2584
      continue;
×
2585
    }
2586

2587
    if (type_kind(types, tau) == FUNCTION_TYPE) {
14✔
2588
      value_t f = merge_blasted_function_value(pre, vtbl, tau, leaf_vals, n);
2✔
2589
      if (f >= 0) {
2✔
2590
        model_map_term(model, atom, f);
2✔
NEW
2591
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
2592
        /* merge_blasted_function_value has already traced a reason code;
2593
         * complete the message here with the concrete atom identity. */
NEW
2594
        mcsat_trace_printf(pre->tracer,
×
2595
                           "preprocessor_build_tuple_model: dropping function atom ");
NEW
2596
        trace_term_ln(pre->tracer, pre->terms, atom);
×
2597
      }
2598
    } else {
2599
      uint32_t idx = 0;
12✔
2600
      value_t v = build_value_from_flat(pre, vtbl, tau, leaf_vals, &idx);
12✔
2601
      if (v >= 0) {
12✔
2602
        model_map_term(model, atom, v);
12✔
NEW
2603
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2604
        mcsat_trace_printf(pre->tracer,
×
2605
                           "preprocessor_build_tuple_model: dropping tuple atom ");
NEW
2606
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2607
        mcsat_trace_printf(pre->tracer,
×
2608
                           "  (leaf values did not decompose into a tuple value)\n");
2609
      }
2610
    }
2611

2612
    delete_ivector(&leaves);
14✔
2613
  }
2614
}
44✔
2615

2616
static term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx);
2617
static void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out);
2618

2619
static
NEW
2620
term_t merge_blasted_function_term(preprocessor_t* pre, type_t tau, const term_t* leaves, uint32_t nleaves) {
×
NEW
2621
  term_table_t* terms = pre->terms;
×
NEW
2622
  type_table_t* types = terms->types;
×
NEW
2623
  function_type_t* fun = function_type_desc(types, tau);
×
2624
  uint32_t i, idx;
NEW
2625
  term_t result = NULL_TERM;
×
NEW
2626
  term_t vars[fun->ndom];
×
2627
  ivector_t flat_args;
2628

2629
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2630
  assert(nleaves == type_leaf_count(pre, tau));
2631

NEW
2632
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2633
    vars[i] = new_variable(terms, fun->domain[i]);
×
2634
  }
2635

NEW
2636
  init_ivector(&flat_args, 0);
×
NEW
2637
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2638
    collect_flat_leaf_terms(pre, vars[i], fun->domain[i], &flat_args);
×
2639
  }
2640

NEW
2641
  term_t leaf_apps[nleaves];
×
NEW
2642
  for (i = 0; i < nleaves; ++i) {
×
NEW
2643
    leaf_apps[i] = mk_application(&pre->tm, leaves[i], flat_args.size, (term_t*) flat_args.data);
×
NEW
2644
    if (leaf_apps[i] == NULL_TERM) {
×
NEW
2645
      goto done;
×
2646
    }
2647
  }
2648

NEW
2649
  idx = 0;
×
NEW
2650
  term_t body = build_term_from_flat(pre, fun->range, leaf_apps, &idx);
×
NEW
2651
  if (body == NULL_TERM || idx != nleaves) {
×
NEW
2652
    goto done;
×
2653
  }
2654

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

NEW
2657
 done:
×
NEW
2658
  delete_ivector(&flat_args);
×
NEW
2659
  return result;
×
2660
}
2661

2662
static
2663
term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx) {
11✔
2664
  type_table_t* types = pre->terms->types;
11✔
2665
  switch (type_kind(types, tau)) {
11✔
2666
  case TUPLE_TYPE: {
3✔
2667
    tuple_type_t* tuple = tuple_type_desc(types, tau);
3✔
2668
    uint32_t i, n = tuple->nelem;
3✔
2669
    term_t elem[n];
3✔
2670
    for (i = 0; i < n; ++i) {
9✔
2671
      elem[i] = build_term_from_flat(pre, tuple->elem[i], flat, idx);
6✔
2672
      if (elem[i] == NULL_TERM) {
6✔
NEW
2673
        return NULL_TERM;
×
2674
      }
2675
    }
2676
    return mk_tuple(&pre->tm, n, elem);
3✔
2677
  }
2678

NEW
2679
  case FUNCTION_TYPE: {
×
NEW
2680
    uint32_t n = type_leaf_count(pre, tau);
×
NEW
2681
    term_t f = merge_blasted_function_term(pre, tau, flat + *idx, n);
×
NEW
2682
    *idx += n;
×
NEW
2683
    return f;
×
2684
  }
2685

2686
  default: {
8✔
2687
    term_t t = flat[*idx];
8✔
2688
    (*idx)++;
8✔
2689
    return t;
8✔
2690
  }
2691
  }
2692
}
2693

2694
static
2695
term_t mk_unblasted_function_leaf_lambda(preprocessor_t* pre, term_t atom, uint32_t leaf_i, type_t leaf_type) {
5✔
2696
  term_table_t* terms = pre->terms;
5✔
2697
  type_table_t* types = terms->types;
5✔
2698
  function_type_t* atom_fun = function_type_desc(types, term_type(terms, atom));
5✔
2699
  function_type_t* leaf_fun = function_type_desc(types, leaf_type);
5✔
2700
  uint32_t flat_n = leaf_fun->ndom;
5✔
2701
  uint32_t i, idx;
2702
  term_t flat_vars[flat_n];
5✔
2703
  term_t orig_args[atom_fun->ndom];
5✔
2704
  term_t app;
2705
  term_t body = NULL_TERM;
5✔
2706
  term_t result = NULL_TERM;
5✔
2707
  ivector_t codom_leaves;
2708

2709
  for (i = 0; i < flat_n; ++i) {
13✔
2710
    flat_vars[i] = new_variable(terms, leaf_fun->domain[i]);
8✔
2711
  }
2712

2713
  idx = 0;
5✔
2714
  for (i = 0; i < atom_fun->ndom; ++i) {
10✔
2715
    orig_args[i] = build_term_from_flat(pre, atom_fun->domain[i], flat_vars, &idx);
5✔
2716
    if (orig_args[i] == NULL_TERM) {
5✔
NEW
2717
      return NULL_TERM;
×
2718
    }
2719
  }
2720
  assert(idx == flat_n);
2721

2722
  app = mk_application(&pre->tm, atom, atom_fun->ndom, orig_args);
5✔
2723
  if (app == NULL_TERM) {
5✔
NEW
2724
    return NULL_TERM;
×
2725
  }
2726

2727
  init_ivector(&codom_leaves, 0);
5✔
2728
  collect_flat_leaf_terms(pre, app, atom_fun->range, &codom_leaves);
5✔
2729
  if (leaf_i < codom_leaves.size) {
5✔
2730
    body = codom_leaves.data[leaf_i];
5✔
2731
  }
2732
  if (body != NULL_TERM) {
5✔
2733
    result = mk_lambda(&pre->tm, flat_n, flat_vars, body);
5✔
2734
  }
2735
  delete_ivector(&codom_leaves);
5✔
2736

2737
  return result;
5✔
2738
}
2739

2740
static
2741
void collect_function_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
3✔
2742
  type_table_t* types = pre->terms->types;
3✔
2743
  ivector_t leaf_types;
2744
  uint32_t i;
2745

2746
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2747

2748
  init_ivector(&leaf_types, 0);
3✔
2749
  function_type_collect_blasted(types, tau, &leaf_types);
3✔
2750
  for (i = 0; i < leaf_types.size; ++i) {
8✔
2751
    term_t leaf = mk_unblasted_function_leaf_lambda(pre, base, i, leaf_types.data[i]);
5✔
2752
    if (leaf != NULL_TERM) {
5✔
2753
      ivector_push(out, leaf);
5✔
2754
    }
2755
  }
2756
  delete_ivector(&leaf_types);
3✔
2757
}
3✔
2758

2759
static
2760
void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
22✔
2761
  type_table_t* types = pre->terms->types;
22✔
2762

2763
  switch (type_kind(types, tau)) {
22✔
2764
  case TUPLE_TYPE: {
7✔
2765
    tuple_type_t* tuple = tuple_type_desc(types, tau);
7✔
2766
    uint32_t i;
2767
    for (i = 0; i < tuple->nelem; ++i) {
21✔
2768
      term_t child = mk_select(&pre->tm, i, base);
14✔
2769
      collect_flat_leaf_terms(pre, child, tuple->elem[i], out);
14✔
2770
    }
2771
    break;
7✔
2772
  }
2773

2774
  case FUNCTION_TYPE:
3✔
2775
    collect_function_leaf_terms(pre, base, tau, out);
3✔
2776
    break;
3✔
2777

2778
  default:
12✔
2779
    ivector_push(out, base);
12✔
2780
    break;
12✔
2781
  }
2782
}
22✔
2783

2784
static
2785
bool substitution_has_var(const ivector_t* vars, term_t x) {
8✔
2786
  uint32_t i;
2787
  for (i = 0; i < vars->size; ++i) {
15✔
2788
    if (vars->data[i] == x) {
7✔
NEW
2789
      return true;
×
2790
    }
2791
  }
2792
  return false;
8✔
2793
}
2794

2795
term_t preprocessor_unblast_term(preprocessor_t* pre, term_t t) {
43✔
2796
  term_table_t* terms = pre->terms;
43✔
2797
  ivector_t vars, maps;
2798
  ivector_t leaves, accessors;
2799
  uint32_t i, j;
2800
  term_t out;
2801

2802
  if (pre->tuple_blast_atoms.size == 0) {
43✔
2803
    return t;
40✔
2804
  }
2805

2806
  init_ivector(&vars, 0);
3✔
2807
  init_ivector(&maps, 0);
3✔
2808
  init_ivector(&leaves, 0);
3✔
2809
  init_ivector(&accessors, 0);
3✔
2810

2811
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
6✔
2812
    term_t atom = pre->tuple_blast_atoms.data[i];
3✔
2813
    type_t atom_type = term_type(terms, atom);
3✔
2814
    tuple_blast_get(pre, atom, &leaves);
3✔
2815
    ivector_reset(&accessors);
3✔
2816
    collect_flat_leaf_terms(pre, atom, atom_type, &accessors);
3✔
2817
    if (leaves.size != accessors.size) {
3✔
NEW
2818
      continue;
×
2819
    }
2820
    for (j = 0; j < leaves.size; ++j) {
11✔
2821
      term_t x = leaves.data[j];
8✔
2822
      term_t u = accessors.data[j];
8✔
2823
      term_kind_t k = term_kind(terms, x);
8✔
2824
      bool is_var = (k == UNINTERPRETED_TERM || k == VARIABLE);
8✔
2825
      if (x != u && is_var && !substitution_has_var(&vars, x)) {
8✔
2826
        ivector_push(&vars, x);
8✔
2827
        ivector_push(&maps, u);
8✔
2828
      }
2829
    }
2830
  }
2831

2832
  if (vars.size == 0) {
3✔
NEW
2833
    out = t;
×
2834
  } else {
2835
    term_subst_t subst;
2836
    init_term_subst(&subst, &pre->tm, vars.size, (term_t*) vars.data, (term_t*) maps.data);
3✔
2837
    out = apply_term_subst(&subst, t);
3✔
2838
    delete_term_subst(&subst);
3✔
2839
  }
2840

2841
  delete_ivector(&accessors);
3✔
2842
  delete_ivector(&leaves);
3✔
2843
  delete_ivector(&maps);
3✔
2844
  delete_ivector(&vars);
3✔
2845

2846
  return out;
3✔
2847
}
2848

2849
void preprocessor_build_model(preprocessor_t* pre, model_t* model) {
44✔
2850
  uint32_t i = 0;
44✔
2851
  for (i = 0; i < pre->equalities_list.size; ++ i) {
58✔
2852
    term_t eq = pre->equalities_list.data[i];
14✔
2853
    term_t eq_var = preprocessor_get_eq_solved_var(pre, eq);
14✔
2854
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
14✔
2855
      mcsat_trace_printf(pre->tracer, "eq = ");
×
2856
      trace_term_ln(pre->tracer, pre->terms, eq);
×
2857
      mcsat_trace_printf(pre->tracer, "\neq_var = ");
×
2858
      trace_term_ln(pre->tracer, pre->terms, eq_var);
×
2859
      mcsat_trace_printf(pre->tracer, "\n");
×
2860
    }
2861
    // Some equalities are solved, but then reasserted in the solver
2862
    // these already have a model
2863
    if (model_find_term_value(model, eq_var) != null_value) {
14✔
2864
      continue;
×
2865
    }
2866
    // Some equalities are marked, but not solved. These we skip as they
2867
    // are already set in the model
2868
    if (preprocessor_get(pre, eq_var) == eq_var) {
14✔
2869
      continue;
×
2870
    }
2871
    term_kind_t eq_kind = term_kind(pre->terms, eq);
14✔
2872
    composite_term_t* eq_desc = get_composite(pre->terms, eq_kind, eq);
14✔
2873
    if (eq_desc->arity > 1) {
14✔
2874
      term_t eq_subst = eq_desc->arg[0] == eq_var ? eq_desc->arg[1] : eq_desc->arg[0];
12✔
2875
      model_add_substitution(model, eq_var, eq_subst);
12✔
2876
    } else {
2877
      model_add_substitution(model, eq_var, zero_term);
2✔
2878
    }
2879
  }
2880

2881
  preprocessor_build_tuple_model(pre, model);
44✔
2882
}
44✔
2883

2884

2885
static inline
2886
void preprocessor_gc_mark_term(preprocessor_t* pre, term_t t) {
1,272✔
2887
  term_table_set_gc_mark(pre->terms, index_of(t));
1,272✔
2888
  type_table_set_gc_mark(pre->terms->types, term_type(pre->terms, t));
1,272✔
2889
}
1,272✔
2890

2891
void preprocessor_gc_mark(preprocessor_t* pre) {
5✔
2892
  uint32_t i;
2893

2894
  for (i = 0; i < pre->preprocess_map_list.size; ++ i) {
486✔
2895
    term_t t = pre->preprocess_map_list.data[i];
481✔
2896
    preprocessor_gc_mark_term(pre, t);
481✔
2897
    term_t t_pre = preprocessor_get(pre, t);
481✔
2898
    preprocessor_gc_mark_term(pre, t_pre);
481✔
2899
  }
2900

2901
  for (i = 0; i < pre->equalities_list.size; ++ i) {
5✔
2902
    term_t t = pre->equalities_list.data[i];
×
2903
    preprocessor_gc_mark_term(pre, t);
×
2904
  }
2905

2906
  for (i = 0; i < pre->tuple_blast_list.size; ++i) {
141✔
2907
    term_t t = pre->tuple_blast_list.data[i];
136✔
2908
    int_hmap_pair_t* rec = int_hmap_find(&pre->tuple_blast_map, t);
136✔
2909
    uint32_t j, n, offset;
2910
    assert(rec != NULL);
2911
    preprocessor_gc_mark_term(pre, t);
136✔
2912
    offset = rec->val;
136✔
2913
    n = pre->tuple_blast_data.data[offset];
136✔
2914
    for (j = 0; j < n; ++j) {
272✔
2915
      preprocessor_gc_mark_term(pre, pre->tuple_blast_data.data[offset + 1 + j]);
136✔
2916
    }
2917
  }
2918

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

© 2026 Coveralls, Inc