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

SRI-CSL / yices2 / 25365016246

05 May 2026 08:06AM UTC coverage: 66.883% (+0.2%) from 66.687%
25365016246

Pull #606

github

disteph
mcsat: trace dropped atoms in preprocessor_build_tuple_model

preprocessor_build_tuple_model has three paths along which a
tuple-blasted atom can quietly fail to appear in the reconstructed
model:

  1. one of the blasted leaf variables has no value in the trail,
  2. the function-type merge in merge_blasted_function_value returns
     null_value for one of several structural reasons (leaf value is
     neither a function nor an update object, a map's arity does not
     match the flattened domain, or a sub-call to build_value_from_flat
     could not rebuild a codomain / domain / default value),
  3. the non-function tuple merge in build_value_from_flat itself
     returns null_value.

Under the previous code each of these branches just `continue`'d or
returned null_value and the caller conditionally invoked
model_map_term only on success. A user inspecting (show-model) would
see the atom missing with no signal anywhere as to why.

Emit a short line under the existing "mcsat::preprocess" trace tag at
each drop site:

  - the leaf-missing case in preprocessor_build_tuple_model names the
    atom and the leaf index that is unassigned;
  - merge_blasted_function_value records a short reason string at each
    of its five `goto done` exits (via a local fail_reason variable
    set immediately before the jump), and emits it from the single
    cleanup label; the caller then adds the concrete atom term;
  - the tuple (non-function) branch in preprocessor_build_tuple_model
    names the atom and notes that the leaves did not decompose.

trace_enabled is a no-op in NDEBUG, so release builds pay nothing at
runtime. mcsat_trace_printf and trace_term_ln are already used from
this file under the same tag, so no new headers or dependencies.

No semantic change to the rebuilt model; the 31 api tests and the 8
tuple .ys regressions still pass in debug, sanitize, and release.
Pull Request #606: MCSAT: add support for tuples (incl. nested with function types); blasts tuples in input constraints + reconstitutes them in models and interpolants

721 of 967 new or added lines in 3 files covered. (74.56%)

65 existing lines in 1 file now uncovered.

84342 of 126103 relevant lines covered (66.88%)

1633298.86 hits per line

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

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

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

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

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

112
  type_table_t* types = pre->terms->types;
1,910✔
113
  type_kind_t kind = type_kind(types, tau);
1,910✔
114
  uint32_t i;
115
  bool result;
116
  switch (kind) {
1,910✔
117
  case BOOL_TYPE:
1,675✔
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,675✔
125
    break;
1,675✔
126
  case TUPLE_TYPE:
33✔
127
    result = false;
33✔
128
    break;
33✔
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,910✔
145
  return result;
1,910✔
146
}
147

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

155
  type_table_t* types = pre->terms->types;
55✔
156
  tuple_type_t* tuple;
157
  uint32_t i, count;
158
  switch (type_kind(types, tau)) {
55✔
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:
38✔
170
    count = 1;
38✔
171
    break;
38✔
172
  }
173

174
  int_hmap_add(&pre->type_leaf_count_cache, tau, (int32_t) count);
55✔
175
  return count;
55✔
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) {
163✔
182
  tuple_type_t* tuple;
183
  uint32_t i;
184

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

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

197
  default:
103✔
198
    ivector_push(flat, tau);
103✔
199
    break;
103✔
200
  }
201
}
163✔
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) {
26✔
231
  switch (type_kind(types, tau)) {
26✔
232
  case TUPLE_TYPE:
22✔
233
    type_collect_flat(types, tau, out);
22✔
234
    break;
22✔
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
}
26✔
243

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

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

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

264
static
265
void tuple_blast_get(preprocessor_t* pre, term_t t, ivector_t* out) {
40,003✔
266
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
40,003✔
267
  assert(rec != NULL);
268
  uint32_t offset = rec->val;
40,003✔
269
  uint32_t n = pre->tuple_blast_data.data[offset];
40,003✔
270
  ivector_reset(out);
40,003✔
271
  ivector_add(out, pre->tuple_blast_data.data + offset + 1, n);
40,003✔
272
}
40,003✔
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
 * (ITE / DISTINCT / EQ / tuple_blast_collect_arg) where the current
280
 * ivector-based tuple_blast_get pays a malloc + memcpy per sub-term.
281
 */
282
static
283
void tuple_blast_peek(preprocessor_t* pre, term_t t, const term_t** data_out, uint32_t* n_out) {
110✔
284
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
110✔
285
  assert(rec != NULL);
286
  uint32_t offset = rec->val;
110✔
287
  *n_out = pre->tuple_blast_data.data[offset];
110✔
288
  *data_out = (const term_t*) (pre->tuple_blast_data.data + offset + 1);
110✔
289
}
110✔
290

291
static
292
void tuple_blast_term(preprocessor_t* pre, term_t t);
293
static
294
void tuple_blast_term_body(preprocessor_t* pre, term_t t);
295
static composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t);
296
static term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children);
297

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

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

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

437
  term_table_t* terms = pre->terms;
37,530✔
438
  ivector_t stack;
439
  init_ivector(&stack, 0);
37,530✔
440
  ivector_push(&stack, t);
37,530✔
441

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

450
    term_t current = stack.data[stack.size - 1];
442,599✔
451
    int32_t cur_idx = index_of(current);
442,599✔
452
    int_hmap_pair_t* crec = int_hmap_find(&pre->term_has_tuples_cache, cur_idx);
442,599✔
453
    if (crec != NULL) {
442,599✔
454
      ivector_pop(&stack);
65,916✔
455
      continue;
175,913✔
456
    }
457

458
    if (!type_is_tuple_free(pre, term_type(terms, current))) {
376,683✔
459
      int_hmap_add(&pre->term_has_tuples_cache, cur_idx, 1);
77✔
460
      ivector_pop(&stack);
77✔
461
      continue;
77✔
462
    }
463

464
    ivector_t children;
465
    init_ivector(&children, 0);
376,606✔
466
    tuple_blast_children(pre, current, &children);
376,606✔
467
    bool any_true = false;
376,606✔
468
    bool all_done = true;
376,606✔
469
    for (uint32_t i = 0; i < children.size; ++i) {
1,141,560✔
470
      int32_t c_idx = index_of(children.data[i]);
764,954✔
471
      int_hmap_pair_t* crec2 = int_hmap_find(&pre->term_has_tuples_cache, c_idx);
764,954✔
472
      if (crec2 == NULL) {
764,954✔
473
        ivector_push(&stack, children.data[i]);
295,149✔
474
        all_done = false;
295,149✔
475
      } else if (crec2->val != 0) {
469,805✔
476
        any_true = true;
140✔
477
      }
478
    }
479
    delete_ivector(&children);
376,606✔
480
    if (!all_done) continue;
376,606✔
481

482
    int_hmap_add(&pre->term_has_tuples_cache, cur_idx, any_true ? 1 : 0);
266,686✔
483
    ivector_pop(&stack);
266,686✔
484
  }
485

486
  delete_ivector(&stack);
37,530✔
487

488
  rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
37,530✔
489
  assert(rec != NULL);
490
  return rec->val != 0;
37,530✔
491
}
492

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

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

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

536
  if (tuple_blast_done(pre, t)) {
201✔
537
    return;
11✔
538
  }
539

540
  ivector_t result;
541
  init_ivector(&result, 0);
201✔
542

543
  if (is_neg_term(t)) {
201✔
544
    term_t c = unsigned_term(t);
11✔
545
    ivector_t c_blast;
546
    tuple_blast_term(pre, c);
11✔
547
    init_ivector(&c_blast, 0);
11✔
548
    tuple_blast_get(pre, c, &c_blast);
11✔
549
    if (c_blast.size != 1) {
11✔
NEW
550
      delete_ivector(&c_blast);
×
NEW
551
      delete_ivector(&result);
×
NEW
552
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
553
    }
554
    ivector_push(&result, opposite_term(c_blast.data[0]));
11✔
555
    delete_ivector(&c_blast);
11✔
556
    tuple_blast_set(pre, t, &result);
11✔
557
    delete_ivector(&result);
11✔
558
    return;
11✔
559
  }
560

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

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

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

601
  case SELECT_TERM: {
51✔
602
    select_term_t* sel = select_term_desc(terms, t);
51✔
603
    ivector_t arg_blast;
604
    tuple_type_t* tuple_type;
605
    uint32_t i, start, len;
606
    type_t arg_type = term_type(terms, sel->arg);
51✔
607
    if (type_kind(types, arg_type) != TUPLE_TYPE) {
51✔
NEW
608
      delete_ivector(&result);
×
NEW
609
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
610
    }
611
    tuple_blast_term(pre, sel->arg);
51✔
612
    init_ivector(&arg_blast, 0);
51✔
613
    tuple_blast_get(pre, sel->arg, &arg_blast);
51✔
614
    tuple_type = tuple_type_desc(types, arg_type);
51✔
615
    start = 0;
51✔
616
    for (i = 0; i < sel->idx; ++i) {
76✔
617
      start += type_leaf_count(pre, tuple_type->elem[i]);
25✔
618
    }
619
    len = type_leaf_count(pre, tuple_type->elem[sel->idx]);
51✔
620
    if (start + len > arg_blast.size) {
51✔
NEW
621
      delete_ivector(&arg_blast);
×
NEW
622
      delete_ivector(&result);
×
NEW
623
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
624
    }
625
    ivector_add(&result, arg_blast.data + start, len);
51✔
626
    delete_ivector(&arg_blast);
51✔
627
    break;
51✔
628
  }
629

630
  case EQ_TERM: {
17✔
631
    composite_term_t* eq = eq_term_desc(terms, t);
17✔
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]);
17✔
638
    tuple_blast_term(pre, eq->arg[1]);
17✔
639
    tuple_blast_peek(pre, eq->arg[0], &lhs, &lhs_n);
17✔
640
    tuple_blast_peek(pre, eq->arg[1], &rhs, &rhs_n);
17✔
641
    if (lhs_n != rhs_n || lhs_n == 0) {
17✔
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));
17✔
646
    break;
17✔
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
      ivector_t child;
824
      tuple_blast_term(pre, c->arg[i]);
6✔
825
      init_ivector(&child, 0);
6✔
826
      tuple_blast_get(pre, c->arg[i], &child);
6✔
827
      if (child.size != 1) {
6✔
NEW
828
        delete_ivector(&child);
×
NEW
829
        delete_ivector(&args);
×
NEW
830
        delete_ivector(&result);
×
NEW
831
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
832
      }
833
      ivector_push(&args, child.data[0]);
6✔
834
      delete_ivector(&child);
6✔
835
    }
836
    ivector_push(&result, kind == OR_TERM ? mk_or(tm, args.size, args.data) : mk_xor(tm, args.size, args.data));
3✔
837
    delete_ivector(&args);
3✔
838
    break;
3✔
839
  }
840

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

847
    for (i = 0; i < pp->len; ++i) {
6✔
848
      ivector_t child;
849
      tuple_blast_term(pre, pp->prod[i].var);
4✔
850
      init_ivector(&child, 0);
4✔
851
      tuple_blast_get(pre, pp->prod[i].var, &child);
4✔
852
      if (child.size != 1) {
4✔
NEW
853
        delete_ivector(&child);
×
NEW
854
        delete_ivector(&result);
×
NEW
855
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
856
      }
857
      args[i] = child.data[0];
4✔
858
      changed |= args[i] != pp->prod[i].var;
4✔
859
      delete_ivector(&child);
4✔
860
    }
861
    ivector_push(&result, changed ? mk_pprod(tm, pp, pp->len, args) : t);
2✔
862
    break;
2✔
863
  }
864

865
  case ARITH_POLY: {
10✔
866
    polynomial_t* p = poly_term_desc(terms, t);
10✔
867
    term_t args[p->nterms];
10✔
868
    uint32_t i;
869
    bool changed = false;
10✔
870

871
    for (i = 0; i < p->nterms; ++i) {
31✔
872
      term_t x = p->mono[i].var;
21✔
873
      if (x == const_idx) {
21✔
874
        args[i] = const_idx;
9✔
875
      } else {
876
        ivector_t child;
877
        tuple_blast_term(pre, x);
12✔
878
        init_ivector(&child, 0);
12✔
879
        tuple_blast_get(pre, x, &child);
12✔
880
        if (child.size != 1) {
12✔
NEW
881
          delete_ivector(&child);
×
NEW
882
          delete_ivector(&result);
×
NEW
883
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
884
        }
885
        args[i] = child.data[0];
12✔
886
        changed |= args[i] != x;
12✔
887
        delete_ivector(&child);
12✔
888
      }
889
    }
890
    ivector_push(&result, changed ? mk_arith_poly(tm, p, p->nterms, args) : t);
10✔
891
    break;
10✔
892
  }
893

NEW
894
  case ARITH_FF_POLY: {
×
NEW
895
    polynomial_t* p = finitefield_poly_term_desc(terms, t);
×
NEW
896
    const rational_t* mod = finitefield_term_order(terms, t);
×
NEW
897
    term_t args[p->nterms];
×
898
    uint32_t i;
NEW
899
    bool changed = false;
×
900

NEW
901
    for (i = 0; i < p->nterms; ++i) {
×
NEW
902
      term_t x = p->mono[i].var;
×
NEW
903
      if (x == const_idx) {
×
NEW
904
        args[i] = const_idx;
×
905
      } else {
906
        ivector_t child;
NEW
907
        tuple_blast_term(pre, x);
×
NEW
908
        init_ivector(&child, 0);
×
NEW
909
        tuple_blast_get(pre, x, &child);
×
NEW
910
        if (child.size != 1) {
×
NEW
911
          delete_ivector(&child);
×
NEW
912
          delete_ivector(&result);
×
NEW
913
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
914
        }
NEW
915
        args[i] = child.data[0];
×
NEW
916
        changed |= args[i] != x;
×
NEW
917
        delete_ivector(&child);
×
918
      }
919
    }
NEW
920
    ivector_push(&result, changed ? mk_arith_ff_poly(tm, p, p->nterms, args, mod) : t);
×
NEW
921
    break;
×
922
  }
923

924
  case BV64_POLY: {
2✔
925
    bvpoly64_t* p = bvpoly64_term_desc(terms, t);
2✔
926
    term_t args[p->nterms];
2✔
927
    uint32_t i;
928
    bool changed = false;
2✔
929

930
    for (i = 0; i < p->nterms; ++i) {
6✔
931
      term_t x = p->mono[i].var;
4✔
932
      if (x == const_idx) {
4✔
933
        args[i] = const_idx;
2✔
934
      } else {
935
        ivector_t child;
936
        tuple_blast_term(pre, x);
2✔
937
        init_ivector(&child, 0);
2✔
938
        tuple_blast_get(pre, x, &child);
2✔
939
        if (child.size != 1) {
2✔
NEW
940
          delete_ivector(&child);
×
NEW
941
          delete_ivector(&result);
×
NEW
942
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
943
        }
944
        args[i] = child.data[0];
2✔
945
        changed |= args[i] != x;
2✔
946
        delete_ivector(&child);
2✔
947
      }
948
    }
949
    ivector_push(&result, changed ? mk_bvarith64_poly(tm, p, p->nterms, args) : t);
2✔
950
    break;
2✔
951
  }
952

NEW
953
  case BV_POLY: {
×
NEW
954
    bvpoly_t* p = bvpoly_term_desc(terms, t);
×
NEW
955
    term_t args[p->nterms];
×
956
    uint32_t i;
NEW
957
    bool changed = false;
×
958

NEW
959
    for (i = 0; i < p->nterms; ++i) {
×
NEW
960
      term_t x = p->mono[i].var;
×
NEW
961
      if (x == const_idx) {
×
NEW
962
        args[i] = const_idx;
×
963
      } else {
964
        ivector_t child;
NEW
965
        tuple_blast_term(pre, x);
×
NEW
966
        init_ivector(&child, 0);
×
NEW
967
        tuple_blast_get(pre, x, &child);
×
NEW
968
        if (child.size != 1) {
×
NEW
969
          delete_ivector(&child);
×
NEW
970
          delete_ivector(&result);
×
NEW
971
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
972
        }
NEW
973
        args[i] = child.data[0];
×
NEW
974
        changed |= args[i] != x;
×
NEW
975
        delete_ivector(&child);
×
976
      }
977
    }
NEW
978
    ivector_push(&result, changed ? mk_bvarith_poly(tm, p, p->nterms, args) : t);
×
NEW
979
    break;
×
980
  }
981

982
  case ARITH_EQ_ATOM:
36✔
983
  case ARITH_GE_ATOM:
984
  case ARITH_BINEQ_ATOM:
985
  case ARITH_RDIV:
986
  case ARITH_IDIV:
987
  case ARITH_MOD:
988
  case BV_ARRAY:
989
  case BV_DIV:
990
  case BV_REM:
991
  case BV_SDIV:
992
  case BV_SREM:
993
  case BV_SMOD:
994
  case BV_SHL:
995
  case BV_LSHR:
996
  case BV_ASHR:
997
  case BV_EQ_ATOM:
998
  case BV_GE_ATOM:
999
  case BV_SGE_ATOM: {
36✔
1000
    composite_term_t* c = get_composite(terms, kind, t);
36✔
1001
    term_t args[c->arity];
36✔
1002
    uint32_t i;
1003
    bool changed = false;
36✔
1004

1005
    for (i = 0; i < c->arity; ++i) {
98✔
1006
      ivector_t child;
1007
      tuple_blast_term(pre, c->arg[i]);
62✔
1008
      init_ivector(&child, 0);
62✔
1009
      tuple_blast_get(pre, c->arg[i], &child);
62✔
1010
      if (child.size != 1) {
62✔
NEW
1011
        delete_ivector(&child);
×
NEW
1012
        delete_ivector(&result);
×
NEW
1013
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1014
      }
1015
      args[i] = child.data[0];
62✔
1016
      changed |= args[i] != c->arg[i];
62✔
1017
      delete_ivector(&child);
62✔
1018
    }
1019

1020
    term_t rebuilt = changed ? mk_composite(pre, kind, c->arity, args) : t;
36✔
1021
    if (rebuilt == NULL_TERM) {
36✔
NEW
1022
      delete_ivector(&result);
×
NEW
1023
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1024
    }
1025
    ivector_push(&result, rebuilt);
36✔
1026
    break;
36✔
1027
  }
1028

NEW
1029
  default:
×
NEW
1030
    ivector_push(&result, t);
×
NEW
1031
    break;
×
1032
  }
1033

1034
  tuple_blast_set(pre, t, &result);
190✔
1035
  delete_ivector(&result);
190✔
1036
}
1037

1038
/*
1039
 * Iterative bottom-up driver for tuple-blasting.
1040
 *  - C stack depth is O(1) regardless of input DAG depth (M4).
1041
 *  - Sub-DAGs that contain no tuple type anywhere are identity-blasted in
1042
 *    one step without descending into them, using the memoized
1043
 *    term_has_tuples_in_subdag (M3).
1044
 *  - For each not-yet-blasted term on the work stack we either (a) push
1045
 *    its un-blasted children, or (b) all children are blasted and we run
1046
 *    tuple_blast_term_body once. Children come from tuple_blast_children
1047
 *    which mirrors exactly the recursive descent in tuple_blast_term_body.
1048
 */
1049
static
1050
void tuple_blast_term(preprocessor_t* pre, term_t t) {
40,098✔
1051
  if (tuple_blast_done(pre, t)) {
40,098✔
1052
    return;
40,035✔
1053
  }
1054

1055
  if (!term_has_tuples_in_subdag(pre, t)) {
38,894✔
1056
    ivector_t result;
1057
    init_ivector(&result, 0);
38,831✔
1058
    ivector_push(&result, t);
38,831✔
1059
    tuple_blast_set(pre, t, &result);
38,831✔
1060
    delete_ivector(&result);
38,831✔
1061
    return;
38,831✔
1062
  }
1063

1064
  ivector_t stack;
1065
  init_ivector(&stack, 0);
63✔
1066
  ivector_push(&stack, t);
63✔
1067

1068
  uint64_t safety = 0;
63✔
1069
  while (stack.size > 0) {
468✔
1070
    /* Defensive bound. Real workloads visit each term O(1) times; 2^28
1071
     * iterations is far more than any reachable DAG should ever need. */
1072
    assert(++safety < ((uint64_t) 1 << 28));
1073
    (void) safety;
1074

1075
    term_t current = stack.data[stack.size - 1];
405✔
1076

1077
    if (tuple_blast_done(pre, current)) {
405✔
1078
      ivector_pop(&stack);
1✔
1079
      continue;
204✔
1080
    }
1081

1082
    if (!term_has_tuples_in_subdag(pre, current)) {
404✔
1083
      ivector_t result;
1084
      init_ivector(&result, 0);
68✔
1085
      ivector_push(&result, current);
68✔
1086
      tuple_blast_set(pre, current, &result);
68✔
1087
      delete_ivector(&result);
68✔
1088
      ivector_pop(&stack);
68✔
1089
      continue;
68✔
1090
    }
1091

1092
    ivector_t children;
1093
    init_ivector(&children, 0);
336✔
1094
    tuple_blast_children(pre, current, &children);
336✔
1095
    bool all_done = true;
336✔
1096
    for (uint32_t i = 0; i < children.size; ++i) {
830✔
1097
      if (!tuple_blast_done(pre, children.data[i])) {
494✔
1098
        ivector_push(&stack, children.data[i]);
207✔
1099
        all_done = false;
207✔
1100
      }
1101
    }
1102
    delete_ivector(&children);
336✔
1103
    if (!all_done) continue;
336✔
1104

1105
    tuple_blast_term_body(pre, current);
201✔
1106
    ivector_pop(&stack);
201✔
1107
  }
1108

1109
  delete_ivector(&stack);
63✔
1110
}
1111

1112
typedef struct composite_term1_s {
1113
  uint32_t arity;  // number of subterms
1114
  term_t arg[1];  // real size = arity
1115
} composite_term1_t;
1116

1117
static
1118
composite_term1_t composite_for_noncomposite;
1119

1120
static
1121
composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t) {
304,292✔
1122
  assert(term_is_composite(terms, t));
1123
  assert(term_kind(terms, t) == kind);
1124
  assert(is_pos_term(t));
1125

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

1197
static bool type_needs_function_diseq_guard(type_table_t* types, type_t tau) {
24,770✔
1198
  uint32_t i, n;
1199

1200
  switch (type_kind(types, tau)) {
24,770✔
1201
  case FUNCTION_TYPE:
1,973✔
1202
    if (type_has_finite_domain(types, tau) ||
3,936✔
1203
        is_unit_type(types, function_type_range(types, tau))) {
1,963✔
1204
      return true;
11✔
1205
    }
1206

1207
    n = function_type_arity(types, tau);
1,962✔
1208
    for (i = 0; i < n; ++ i) {
3,928✔
1209
      if (type_needs_function_diseq_guard(types, function_type_domain(types, tau, i))) {
1,968✔
1210
        return true;
2✔
1211
      }
1212
    }
1213

1214
    return type_needs_function_diseq_guard(types, function_type_range(types, tau));
1,960✔
1215

UNCOV
1216
  case TUPLE_TYPE:
×
UNCOV
1217
    n = tuple_type_arity(types, tau);
×
1218
    for (i = 0; i < n; ++ i) {
×
UNCOV
1219
      if (type_needs_function_diseq_guard(types, tuple_type_component(types, tau, i))) {
×
UNCOV
1220
        return true;
×
1221
      }
1222
    }
UNCOV
1223
    return false;
×
1224

UNCOV
1225
  case INSTANCE_TYPE:
×
UNCOV
1226
    n = instance_type_arity(types, tau);
×
UNCOV
1227
    for (i = 0; i < n; ++ i) {
×
UNCOV
1228
      if (type_needs_function_diseq_guard(types, instance_type_param(types, tau, i))) {
×
UNCOV
1229
        return true;
×
1230
      }
1231
    }
UNCOV
1232
    return false;
×
1233

1234
  default:
22,797✔
1235
    return false;
22,797✔
1236
  }
1237
}
1238

1239
static bool term_needs_function_diseq_guard(term_table_t* terms, term_t t) {
20,842✔
1240
  return type_needs_function_diseq_guard(terms->types, term_type(terms, t));
20,842✔
1241
}
1242

1243
static
1244
term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children) {
46,613✔
1245
  term_manager_t* tm = &pre->tm;
46,613✔
1246
  term_table_t* terms = pre->terms;
46,613✔
1247

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

1331
/**
1332
 * Returns purified version of t if we should purify t as an argument of a function.
1333
 * Any new equalities are added to output.
1334
 */
1335
static inline
1336
term_t preprocessor_purify(preprocessor_t* pre, term_t t, ivector_t* out) {
52,845✔
1337

1338
  term_table_t* terms = pre->terms;
52,845✔
1339

1340
  // Negated terms must be purified
1341
  if (is_pos_term(t)) {
52,845✔
1342
    // We don't purify variables
1343
    switch (term_kind(terms, t)) {
17,079✔
1344
    case UNINTERPRETED_TERM:
10,825✔
1345
      // Variables are already pure
1346
      return t;
10,825✔
1347
    case CONSTANT_TERM:
15✔
1348
      return t;
15✔
1349
    case ARITH_CONSTANT:
1,698✔
1350
    case ARITH_FF_CONSTANT:
1351
    case BV64_CONSTANT:
1352
    case BV_CONSTANT:
1353
      // Constants are also pure (except for false)
1354
      return t;
1,698✔
1355
    case APP_TERM:
1,685✔
1356
      // Uninterpreted functions are also already purified
1357
      return t;
1,685✔
1358
    case UPDATE_TERM:
1,680✔
1359
      return t;
1,680✔
1360
    default:
1,176✔
1361
      break;
1,176✔
1362
    }
1363
  }
1364

1365
  // Everything else gets purified. Check if in the cache
1366
  int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
36,942✔
1367
  if (find != NULL) {
36,942✔
1368
    return find->val;
36,376✔
1369
  } else {
1370
    // Make the variable
1371
    type_t t_type = term_type(terms, t);
566✔
1372
    term_t x = new_uninterpreted_term(terms, t_type);
566✔
1373
    // Remember for later
1374
    int_hmap_add(&pre->purification_map, t, x);
566✔
1375
    ivector_push(&pre->purification_map_list, t);
566✔
1376
    // Also add the variable to the pre-processor
1377
    preprocessor_set(pre, x, x);
566✔
1378
    // Add equality to output
1379
    term_t eq = mk_eq(&pre->tm, x, t);
566✔
1380
    ivector_push(out, eq);
566✔
1381

1382
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
566✔
UNCOV
1383
      mcsat_trace_printf(pre->tracer, "adding lemma = ");
×
UNCOV
1384
      trace_term_ln(pre->tracer, terms, eq);
×
1385
    }
1386

1387
    // Return the purified version
1388
    return x;
566✔
1389
  }
1390
}
1391

1392
static inline
1393
term_t mk_bvneg(term_manager_t* tm, term_t t) {
92✔
1394
  term_table_t* terms = tm->terms;
92✔
1395
  if (term_bitsize(terms,t) <= 64) {
92✔
1396
    bvarith64_buffer_t *buffer = term_manager_get_bvarith64_buffer(tm);
76✔
1397
    bvarith64_buffer_set_term(buffer, terms, t);
76✔
1398
    bvarith64_buffer_negate(buffer);
76✔
1399
    return mk_bvarith64_term(tm, buffer);
76✔
1400
  } else {
1401
    bvarith_buffer_t *buffer = term_manager_get_bvarith_buffer(tm);
16✔
1402
    bvarith_buffer_set_term(buffer, terms, t);
16✔
1403
    bvarith_buffer_negate(buffer);
16✔
1404
    return mk_bvarith_term(tm, buffer);
16✔
1405
  }
1406
}
1407

1408
// Mark equality eq: (var = t) for solving
1409
static
1410
void preprocessor_mark_eq(preprocessor_t* pre, term_t eq, term_t var) {
24,860✔
1411
  assert(is_pos_term(eq));
1412
  assert(is_pos_term(var));
1413
  assert(term_kind(pre->terms, var) == UNINTERPRETED_TERM);
1414

1415
  // Mark the equality
1416
  int_hmap_pair_t* find = int_hmap_get(&pre->equalities, eq);
24,860✔
1417
  assert(find->val == -1);
1418
  find->val = var;
24,860✔
1419
  ivector_push(&pre->equalities_list, eq);
24,860✔
1420
}
24,860✔
1421

1422
static
1423
term_t preprocessor_get_eq_solved_var(const preprocessor_t* pre, term_t eq) {
47,674✔
1424
  assert(is_pos_term(eq));
1425
  int_hmap_pair_t* find = int_hmap_find((int_hmap_t*) &pre->equalities, eq);
47,674✔
1426
  if (find != NULL) {
47,674✔
1427
    return find->val;
19,991✔
1428
  } else {
1429
    return NULL_TERM;
27,683✔
1430
  }
1431
}
1432

1433
term_t preprocessor_apply(preprocessor_t* pre, term_t t, ivector_t* out, bool is_assertion) {
39,827✔
1434

1435
  term_table_t* terms = pre->terms;
39,827✔
1436
  term_manager_t* tm = &pre->tm;
39,827✔
1437

1438
  uint32_t i, j, n;
1439
  ivector_t t_blast;
1440

1441
  tuple_blast_term(pre, t);
39,827✔
1442
  init_ivector(&t_blast, 0);
39,827✔
1443
  tuple_blast_get(pre, t, &t_blast);
39,827✔
1444
  if (t_blast.size != 1) {
39,827✔
NEW
UNCOV
1445
    delete_ivector(&t_blast);
×
NEW
UNCOV
1446
    longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1447
  }
1448
  t = t_blast.data[0];
39,827✔
1449
  delete_ivector(&t_blast);
39,827✔
1450

1451
  // Check if already preprocessed;
1452
  term_t t_pre = preprocessor_get(pre, t);
39,827✔
1453
  if (t_pre != NULL_TERM) {
39,827✔
1454
    return t_pre;
1,648✔
1455
  }
1456

1457
// Note: negative affect on general performance due to solved/substituted
1458
//       terms being to complex for explainers.
1459
//
1460
//  // First, if the assertion is a conjunction, just expand
1461
//  if (is_assertion && is_neg_term(t) && term_kind(terms, t) == OR_TERM) {
1462
//    // !(or t1 ... tn) -> !t1 && ... && !tn
1463
//    composite_term_t* t_desc = composite_term_desc(terms, t);
1464
//    for (i = 0; i < t_desc->arity; ++ i) {
1465
//      ivector_push(out, opposite_term(t_desc->arg[i]));
1466
//    }
1467
//    return true_term;
1468
//  }
1469
//
1470
  // Start
1471
  ivector_t* pre_stack = &pre->preprocessing_stack;
38,179✔
1472
  ivector_reset(pre_stack);
38,179✔
1473
  ivector_push(pre_stack, t);
38,179✔
1474

1475
  // Preprocess
1476
  while (pre_stack->size) {
506,090✔
1477
    // Current term
1478
    term_t current = ivector_last(pre_stack);
467,922✔
1479

1480
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
467,922✔
UNCOV
1481
      mcsat_trace_printf(pre->tracer, "current = ");
×
UNCOV
1482
      trace_term_ln(pre->tracer, terms, current);
×
1483
    }
1484

1485
    // If preprocessed already, done
1486
    term_t current_pre = preprocessor_get(pre, current);
467,922✔
1487
    if (current_pre != NULL_TERM) {
467,922✔
1488
      ivector_pop(pre_stack);
31,304✔
1489
      continue;
31,304✔
1490
    }
1491

1492
    // Negation
1493
    if (is_neg_term(current)) {
436,618✔
1494
      term_t child = unsigned_term(current);
88,942✔
1495
      term_t child_pre = preprocessor_get(pre, child);
88,942✔
1496
      if (child_pre == NULL_TERM) {
88,942✔
1497
        ivector_push(pre_stack, child);
42,001✔
1498
        continue;
42,001✔
1499
      } else {
1500
        ivector_pop(pre_stack);
46,941✔
1501
        current_pre = opposite_term(child_pre);
46,941✔
1502
        preprocessor_set(pre, current, current_pre);
46,941✔
1503
        continue;
46,941✔
1504
      }
1505
    }
1506

1507
    // Check for supported types
1508
    type_kind_t type = term_type_kind(terms, current);
347,676✔
1509
    switch (type) {
347,676✔
1510
    case BOOL_TYPE:
347,676✔
1511
    case INT_TYPE:
1512
    case REAL_TYPE:
1513
    case FF_TYPE:
1514
    case UNINTERPRETED_TYPE:
1515
    case FUNCTION_TYPE:
1516
    case BITVECTOR_TYPE:
1517
    case SCALAR_TYPE:
1518
      break;
347,676✔
UNCOV
1519
    default:
×
UNCOV
1520
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1521
    }
1522

1523
    // Kind of term
1524
    term_kind_t current_kind = term_kind(terms, current);
347,676✔
1525

1526
    switch(current_kind) {
347,676✔
1527
    case CONSTANT_TERM:    // constant of uninterpreted/scalar/boolean types
1,828✔
1528
    case BV64_CONSTANT:    // compact bitvector constant (64 bits at most)
1529
    case BV_CONSTANT:      // generic bitvector constant (more than 64 bits)
1530
    case ARITH_CONSTANT:   // rational constant
1531
    case ARITH_FF_CONSTANT:   // finite field constant
1532
      current_pre = current;
1,828✔
1533
      break;
1,828✔
1534

1535
    case UNINTERPRETED_TERM:  // (i.e., global variables, can't be bound).
14,051✔
1536
      current_pre = current;
14,051✔
1537
      // Unless we want special slicing
1538
      if (type == BITVECTOR_TYPE) {
14,051✔
1539
        if (pre->options->bv_var_size > 0) {
4,236✔
1540
          uint32_t size = term_bitsize(terms, current);
23✔
1541
          uint32_t var_size = pre->options->bv_var_size;
23✔
1542
          if (size > var_size) {
23✔
1543
            uint32_t n_vars = (size - 1) / var_size + 1;
2✔
1544
            term_t vars[n_vars];
2✔
1545
            for (i = n_vars - 1; size > 0; i--) {
8✔
1546
              if (size >= var_size) {
6✔
1547
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, var_size));
4✔
1548
                size -= var_size;
4✔
1549
              } else {
1550
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, size));
2✔
1551
                size = 0;
2✔
1552
              }
1553
            }
1554
            current_pre = _o_yices_bvconcat(n_vars, vars);
2✔
1555
            term_t eq = _o_yices_eq(current, current_pre);
2✔
1556
            preprocessor_mark_eq(pre, eq, current);
2✔
1557
          }
1558
        }
1559
      }
1560
      break;
14,051✔
1561

1562
    case ITE_TERM:           // if-then-else
181,421✔
1563
    case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1564
    case EQ_TERM:            // equality
1565
    case OR_TERM:            // n-ary OR
1566
    case XOR_TERM:           // n-ary XOR
1567
    case ARITH_EQ_ATOM:      // equality (t == 0)
1568
    case ARITH_BINEQ_ATOM:   // equality (t1 == t2)  (between two arithmetic terms)
1569
    case ARITH_GE_ATOM:      // inequality (t >= 0)
1570
    case ARITH_FF_EQ_ATOM:   // finite field equality (t == 0)
1571
    case ARITH_FF_BINEQ_ATOM: // finite field equality (t1 == t2)  (between two arithmetic terms)
1572
    case BV_DIV:
1573
    case BV_REM:
1574
    case BV_SMOD:
1575
    case BV_SHL:
1576
    case BV_LSHR:
1577
    case BV_ASHR:
1578
    case BV_EQ_ATOM:
1579
    case BV_GE_ATOM:
1580
    case BV_SGE_ATOM:
1581
    {
1582
      composite_term_t* desc = get_composite(terms, current_kind, current);
181,421✔
1583
      bool children_done = true;
181,421✔
1584
      bool children_same = true;
181,421✔
1585

1586
      n = desc->arity;
181,421✔
1587

1588
      // MCSAT does not yet enforce all extensionality/cardinality constraints
1589
      // for function-sort disequalities. Reject equality atoms whose type needs
1590
      // that monitoring; the Boolean abstraction may assert them either way.
1591
      if (current_kind == EQ_TERM && term_needs_function_diseq_guard(terms, desc->arg[0])) {
181,421✔
1592
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
8✔
1593
      }
1594

1595
      // Is this a top-level equality assertion
1596
      bool is_equality =
181,413✔
1597
          current_kind == EQ_TERM ||
160,680✔
1598
          current_kind == BV_EQ_ATOM ||
103,625✔
1599
          current_kind == ARITH_EQ_ATOM ||
99,869✔
1600
          current_kind == ARITH_BINEQ_ATOM ||
95,727✔
1601
          current_kind == ARITH_FF_EQ_ATOM ||
342,093✔
1602
          current_kind == ARITH_FF_BINEQ_ATOM;
1603
      // don't rewrite if the equality is between Boolean terms
1604
      bool is_boolean = is_boolean_type(term_type(pre->terms, desc->arg[0]));
181,413✔
1605

1606
      term_t eq_solve_var = NULL_TERM;
181,413✔
1607
      if (is_assertion && is_equality && !is_boolean) {
181,413✔
1608
        bool is_lhs_rhs_mixed = desc->arity > 1 &&
139,501✔
1609
          term_type_kind(pre->terms, desc->arg[0]) != term_type_kind(pre->terms, desc->arg[1]);
67,795✔
1610
        // don't rewrite if equality is between mixed terms, e.g. between int and real terms
1611
        if (!is_lhs_rhs_mixed && current == t) {
71,706✔
1612
          eq_solve_var = preprocessor_get_eq_solved_var(pre, t);
47,661✔
1613
          if (eq_solve_var == NULL_TERM) {
47,661✔
1614
            term_t lhs = desc->arg[0];
27,683✔
1615
            term_kind_t lhs_kind = term_kind(terms, lhs);
27,683✔
1616
            // If lhs/rhs is a first-time seen variable, we can solve it
1617
            bool lhs_is_var = lhs_kind == UNINTERPRETED_TERM && is_pos_term(lhs);
27,683✔
1618
            if (lhs_is_var && preprocessor_get(pre, lhs) == NULL_TERM) {
27,683✔
1619
              // First time variable, let's solve
1620
              preprocessor_mark_eq(pre, t, lhs);
24,589✔
1621
              eq_solve_var = lhs;
24,589✔
1622
            } else if (desc->arity > 1) {
3,094✔
1623
              term_t rhs = desc->arg[1];
2,330✔
1624
              term_kind_t rhs_kind = term_kind(terms, rhs);
2,330✔
1625
              bool rhs_is_var = rhs_kind == UNINTERPRETED_TERM && is_pos_term(rhs);
2,330✔
1626
              if (rhs_is_var && preprocessor_get(pre, rhs) == NULL_TERM) {
2,330✔
1627
                // First time variable, let's solve
1628
                preprocessor_mark_eq(pre, t, rhs);
269✔
1629
                eq_solve_var = rhs;
269✔
1630
              }
1631
            }
1632
          } else {
1633
            // Check that we it's not there already
1634
            if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
19,978✔
1635
              eq_solve_var = NULL_TERM;
51✔
1636
            }
1637
          }
1638
        }
1639
      }
1640

1641
      ivector_t children;
1642
      init_ivector(&children, n);
181,413✔
1643

1644
      for (i = 0; i < n; ++ i) {
605,077✔
1645
        term_t child = desc->arg[i];
423,664✔
1646
        if (child != eq_solve_var) {
423,664✔
1647
          term_t child_pre = preprocessor_get(pre, child);
378,879✔
1648
          if (child_pre == NULL_TERM) {
378,879✔
1649
            children_done = false;
108,597✔
1650
            ivector_push(pre_stack, child);
108,597✔
1651
          } else if (child_pre != child) {
270,282✔
1652
            children_same = false;
106,065✔
1653
          }
1654
          if (children_done) {
378,879✔
1655
            ivector_push(&children, child_pre);
256,438✔
1656
          }
1657
        }
1658
      }
1659

1660
      if (eq_solve_var != NULL_TERM) {
181,413✔
1661
        // Check again to make sure we don't have something like x = x + 1
1662
        if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
44,785✔
1663
          // Do it again
UNCOV
1664
          children_done = false;
×
1665
        }
1666
      }
1667

1668
      if (children_done) {
181,413✔
1669
        if (eq_solve_var != NULL_TERM) {
113,454✔
1670
          term_t eq_solve_term = zero_term;
24,807✔
1671
          if (children.size > 0) {
24,807✔
1672
            eq_solve_term = children.data[0];
24,769✔
1673
          }
1674
          preprocessor_set(pre, eq_solve_var, eq_solve_term);
24,807✔
1675
          current_pre = true_term;
24,807✔
1676
        } else {
1677
          if (children_same) {
88,647✔
1678
            current_pre = current;
50,460✔
1679
          } else {
1680
            current_pre = mk_composite(pre, current_kind, n, children.data);
38,187✔
1681
          }
1682
        }
1683
      }
1684

1685
      delete_ivector(&children);
181,413✔
1686

1687
      break;
181,413✔
1688
    }
1689

1690
    case BV_ARRAY:
17,517✔
1691
    {
1692
      composite_term_t* desc = get_composite(terms, current_kind, current);
17,517✔
1693
      bool children_done = true;
17,517✔
1694
      bool children_same = true;
17,517✔
1695

1696
      n = desc->arity;
17,517✔
1697

1698
      ivector_t children;
1699
      init_ivector(&children, n);
17,517✔
1700

1701
      for (i = 0; i < n; ++ i) {
353,534✔
1702
        term_t child = desc->arg[i];
336,017✔
1703
        term_t child_pre = preprocessor_get(pre, child);
336,017✔
1704
        if (child_pre == NULL_TERM) {
336,017✔
1705
          children_done = false;
143,211✔
1706
          ivector_push(pre_stack, child);
143,211✔
1707
        } else {
1708
          if (is_arithmetic_literal(terms, child_pre) || child_pre == false_term) {
192,806✔
1709
            // purify if arithmetic literal, i.e. a = 0 where a is of integer type
1710
            child_pre = preprocessor_purify(pre, child_pre, out);
35,723✔
1711
          }
1712
          if (child_pre != child) {
192,806✔
1713
            children_same = false;
110,041✔
1714
          }
1715
        }
1716
        if (children_done) {
336,017✔
1717
          ivector_push(&children, child_pre);
179,684✔
1718
        }
1719
      }
1720

1721
      if (children_done) {
17,517✔
1722
        if (children_same) {
9,165✔
1723
          current_pre = current;
2,210✔
1724
        } else {
1725
          current_pre = mk_composite(pre, current_kind, n, children.data);
6,955✔
1726
        }
1727
      }
1728

1729
      delete_ivector(&children);
17,517✔
1730

1731
      break;
17,517✔
1732
    }
1733

1734
    case ARITH_ABS:
8✔
1735
    {
1736
      term_t arg = arith_abs_arg(terms, current);
8✔
1737
      term_t arg_pre = preprocessor_get(pre, arg);
8✔
1738
      if (arg_pre == NULL_TERM) {
8✔
1739
        ivector_push(pre_stack, arg);
3✔
1740
      } else {
1741
        type_t arg_pre_type = term_type(pre->terms, arg_pre);
5✔
1742
        term_t arg_pre_is_positive = mk_arith_term_geq0(&pre->tm, arg_pre);
5✔
1743
        term_t arg_negative = _o_yices_neg(arg_pre);
5✔
1744
        current_pre = mk_ite(&pre->tm, arg_pre_is_positive, arg_pre, arg_negative, arg_pre_type);
5✔
1745
      }
1746
      break;
8✔
1747
    }
1748

1749
    case BV_SDIV:
20✔
1750
    {
1751
      composite_term_t* desc = get_composite(terms, current_kind, current);
20✔
1752
      assert(desc->arity == 2);
1753
      term_t s = desc->arg[0];
20✔
1754
      term_t s_pre = preprocessor_get(pre, s);
20✔
1755
      if (s_pre == NULL_TERM) {
20✔
1756
        ivector_push(pre_stack, s);
7✔
1757
      }
1758
      term_t t = desc->arg[1];
20✔
1759
      term_t t_pre = preprocessor_get(pre, t);
20✔
1760
      if (t_pre == NULL_TERM) {
20✔
1761
        ivector_push(pre_stack, t);
5✔
1762
      }
1763
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
20✔
1764
        type_t tau = term_type(terms, s_pre);
11✔
1765
        uint32_t n = term_bitsize(terms, s_pre);
11✔
1766
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
11✔
1767
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
11✔
1768
        // if (msb_s) {
1769
        //   if (msb_t) {
1770
        //     t1: udiv(-s, -t)
1771
        //   } else {
1772
        //     t2: -udiv(-s, t)
1773
        //   }
1774
        // } else {
1775
        //   if (msb_t) {
1776
        //     t3: -udiv(s, -t)
1777
        //   } else {
1778
        //     t4: udiv(s, t)
1779
        //   }
1780
        // }
1781
        term_t neg_s = mk_bvneg(tm, s_pre);
11✔
1782
        term_t neg_t = mk_bvneg(tm, t_pre);
11✔
1783

1784
        term_t t1 = mk_bvdiv(tm, neg_s, neg_t);
11✔
1785
        term_t t2 = mk_bvdiv(tm, neg_s, t_pre);
11✔
1786
        t2 = mk_bvneg(&pre->tm, t2);
11✔
1787
        term_t t3 = mk_bvdiv(tm, s_pre, neg_t);
11✔
1788
        t3 = mk_bvneg(&pre->tm, t3);
11✔
1789
        term_t t4 = mk_bvdiv(tm, s_pre, t_pre);
11✔
1790

1791
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
11✔
1792
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
11✔
1793

1794
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
11✔
1795
      }
1796
      break;
20✔
1797
    }
1798
    case BV_SREM:
21✔
1799
    {
1800
      composite_term_t* desc = get_composite(terms, current_kind, current);
21✔
1801
      assert(desc->arity == 2);
1802
      term_t s = desc->arg[0];
21✔
1803
      term_t s_pre = preprocessor_get(pre, s);
21✔
1804
      if (s_pre == NULL_TERM) {
21✔
1805
        ivector_push(pre_stack, s);
8✔
1806
      }
1807
      term_t t = desc->arg[1];
21✔
1808
      term_t t_pre = preprocessor_get(pre, t);
21✔
1809
      if (t_pre == NULL_TERM) {
21✔
1810
        ivector_push(pre_stack, t);
3✔
1811
      }
1812
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
21✔
1813
        type_t tau = term_type(terms, s_pre);
12✔
1814
        uint32_t n = term_bitsize(terms, s_pre);
12✔
1815
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
12✔
1816
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
12✔
1817
        // if (msb_s) {
1818
        //   if (msb_t) {
1819
        //     t1: -urem(-s, -t)
1820
        //   } else {
1821
        //     t2: -urem(-s, t)
1822
        //   }
1823
        // } else {
1824
        //   if (msb_t) {
1825
        //     t3: -urem(s, -t)
1826
        //   } else {
1827
        //     t4: urem(s, t)
1828
        //   }
1829
        // }
1830
        term_t neg_s = mk_bvneg(tm, s_pre);
12✔
1831
        term_t neg_t = mk_bvneg(tm, t_pre);
12✔
1832

1833
        term_t t1 = mk_bvrem(tm, neg_s, neg_t);
12✔
1834
        t1 = mk_bvneg(tm, t1);
12✔
1835
        term_t t2 = mk_bvrem(tm, neg_s, t_pre);
12✔
1836
        t2 = mk_bvneg(tm, t2);
12✔
1837
        term_t t3 = mk_bvrem(tm, s_pre, neg_t);
12✔
1838
        term_t t4 = mk_bvrem(tm, s_pre, t_pre);
12✔
1839

1840
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
12✔
1841
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
12✔
1842

1843
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
12✔
1844
      }
1845
      break;
21✔
1846
    }
1847
    case BIT_TERM: // bit-select current = child[i]
112,741✔
1848
    {
1849
      uint32_t index = bit_term_index(terms, current);
112,741✔
1850
      term_t arg = bit_term_arg(terms, current);
112,741✔
1851
      term_t arg_pre = preprocessor_get(pre, arg);
112,741✔
1852
      if (arg_pre == NULL_TERM) {
112,741✔
1853
        ivector_push(pre_stack, arg);
1,584✔
1854
      } else {
1855
        if (arg_pre == arg) {
111,157✔
1856
          current_pre = current;
73,115✔
1857
        } else {
1858
          if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,042✔
UNCOV
1859
            mcsat_trace_printf(pre->tracer, "arg_pre = ");
×
UNCOV
1860
            trace_term_ln(pre->tracer, terms, arg_pre);
×
1861
          }
1862
          // For simplification purposes use API
1863
          current_pre = _o_yices_bitextract(arg_pre, index);
38,042✔
1864
          assert(current_pre != NULL_TERM);
1865
        }
1866
      }
1867
      break;
112,741✔
1868
    }
1869
    case BV_POLY:  // polynomial with generic bitvector coefficients
33✔
1870
    {
1871
      bvpoly_t* p = bvpoly_term_desc(terms, current);
33✔
1872

1873
      bool children_done = true;
33✔
1874
      bool children_same = true;
33✔
1875

1876
      n = p->nterms;
33✔
1877

1878
      ivector_t children;
1879
      init_ivector(&children, n);
33✔
1880

1881
      for (i = 0; i < n; ++ i) {
84✔
1882
        term_t x = p->mono[i].var;
51✔
1883
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
51✔
1884

1885
        if (x_pre != const_idx) {
51✔
1886
          if (x_pre == NULL_TERM) {
47✔
1887
            children_done = false;
10✔
1888
            ivector_push(pre_stack, x);
10✔
1889
          } else if (x_pre != x) {
37✔
1890
            children_same = false;
23✔
1891
          }
1892
        }
1893

1894
        if (children_done) { ivector_push(&children, x_pre); }
51✔
1895
      }
1896

1897
      if (children_done) {
33✔
1898
        if (children_same) {
26✔
1899
          current_pre = current;
11✔
1900
        } else {
1901
          current_pre = mk_bvarith_poly(tm, p, n, children.data);
15✔
1902
        }
1903
      }
1904

1905
      delete_ivector(&children);
33✔
1906

1907
      break;
33✔
1908
    }
1909
    case BV64_POLY: // polynomial with 64bit coefficients
2,573✔
1910
    {
1911
      bvpoly64_t* p = bvpoly64_term_desc(terms, current);
2,573✔
1912

1913
      bool children_done = true;
2,573✔
1914
      bool children_same = true;
2,573✔
1915

1916
      n = p->nterms;
2,573✔
1917

1918
      ivector_t children;
1919
      init_ivector(&children, n);
2,573✔
1920

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

1925
        if (x_pre != const_idx) {
7,254✔
1926
          if (x_pre == NULL_TERM) {
5,580✔
1927
            children_done = false;
1,308✔
1928
            ivector_push(pre_stack, x);
1,308✔
1929
          } else if (x_pre != x) {
4,272✔
1930
            children_same = false;
3,568✔
1931
          }
1932
        }
1933

1934
        if (children_done) { ivector_push(&children, x_pre); }
7,254✔
1935
      }
1936

1937
      if (children_done) {
2,573✔
1938
        if (children_same) {
1,872✔
1939
          current_pre = current;
279✔
1940
        } else {
1941
          current_pre = mk_bvarith64_poly(tm, p, n, children.data);
1,593✔
1942
        }
1943
      }
1944

1945
      delete_ivector(&children);
2,573✔
1946

1947
      break;
2,573✔
1948
    }
1949

1950
    case POWER_PRODUCT:    // power products: (t1^d1 * ... * t_n^d_n)
1,675✔
1951
    {
1952
      pprod_t* pp = pprod_term_desc(terms, current);
1,675✔
1953
      bool children_done = true;
1,675✔
1954
      bool children_same = true;
1,675✔
1955

1956
      n = pp->len;
1,675✔
1957

1958
      ivector_t children;
1959
      init_ivector(&children, n);
1,675✔
1960

1961
      for (i = 0; i < n; ++ i) {
5,316✔
1962
        term_t x = pp->prod[i].var;
3,641✔
1963
        term_t x_pre = preprocessor_get(pre, x);
3,641✔
1964

1965
        if (x_pre == NULL_TERM) {
3,641✔
1966
          children_done = false;
452✔
1967
          ivector_push(pre_stack, x);
452✔
1968
        } else if (x_pre != x) {
3,189✔
1969
          children_same = false;
96✔
1970
        }
1971

1972
        if (children_done) { ivector_push(&children, x_pre); }
3,641✔
1973
      }
1974

1975
      if (children_done) {
1,675✔
1976
        if (children_same) {
1,339✔
1977
          current_pre = current;
1,281✔
1978
        } else {
1979
          // NOTE: it doens't change pp, it just uses it as a frame
1980
          current_pre = mk_pprod(tm, pp, n, children.data);
58✔
1981
        }
1982
      }
1983

1984
      delete_ivector(&children);
1,675✔
1985

1986
      break;
1,675✔
1987
    }
1988

1989
    case ARITH_POLY:       // polynomial with rational coefficients
6,938✔
1990
    {
1991
      polynomial_t* p = poly_term_desc(terms, current);
6,938✔
1992

1993
      bool children_done = true;
6,938✔
1994
      bool children_same = true;
6,938✔
1995

1996
      n = p->nterms;
6,938✔
1997

1998
      ivector_t children;
1999
      init_ivector(&children, n);
6,938✔
2000

2001
      for (i = 0; i < n; ++ i) {
26,860✔
2002
        term_t x = p->mono[i].var;
19,922✔
2003
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
19,922✔
2004

2005
        if (x_pre != const_idx) {
19,922✔
2006
          if (x_pre == NULL_TERM) {
16,895✔
2007
            children_done = false;
2,568✔
2008
            ivector_push(pre_stack, x);
2,568✔
2009
          } else if (x_pre != x) {
14,327✔
2010
            children_same = false;
944✔
2011
          }
2012
        }
2013

2014
        if (children_done) { ivector_push(&children, x_pre); }
19,922✔
2015
      }
2016

2017
      if (children_done) {
6,938✔
2018
        if (children_same) {
5,486✔
2019
          current_pre = current;
4,887✔
2020
        } else {
2021
          current_pre = mk_arith_poly(tm, p, n, children.data);
599✔
2022
        }
2023
      }
2024

2025
      delete_ivector(&children);
6,938✔
2026

2027
      break;
6,938✔
2028
    }
2029

2030
    case ARITH_FF_POLY:    // polynomial with finite field coefficients
150✔
2031
    {
2032
      polynomial_t* p = finitefield_poly_term_desc(terms, current);
150✔
2033
      const rational_t *mod = finitefield_term_order(terms, current);
150✔
2034

2035
      bool children_done = true;
150✔
2036
      bool children_same = true;
150✔
2037

2038
      n = p->nterms;
150✔
2039

2040
      ivector_t children;
2041
      init_ivector(&children, n);
150✔
2042

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

2047
        if (x_pre != const_idx) {
918✔
2048
          if (x_pre == NULL_TERM) {
864✔
2049
            children_done = false;
380✔
2050
            ivector_push(pre_stack, x);
380✔
2051
          } else if (x_pre != x) {
484✔
UNCOV
2052
            children_same = false;
×
2053
          }
2054
        }
2055

2056
        if (children_done) { ivector_push(&children, x_pre); }
918✔
2057
      }
2058

2059
      if (children_done) {
150✔
2060
        if (children_same) {
75✔
2061
          current_pre = current;
75✔
2062
        } else {
UNCOV
2063
          current_pre = mk_arith_ff_poly(tm, p, n, children.data, mod);
×
2064
        }
2065
      }
2066

2067
      delete_ivector(&children);
150✔
2068

2069
      break;
150✔
2070
    }
2071

2072
    // FOLLOWING ARE UNINTEPRETED, SO WE PURIFY THE ARGUMENTS
2073

2074
    case APP_TERM:           // application of an uninterpreted function
8,666✔
2075
    case ARITH_RDIV:         // regular division (/ x y)
2076
    case ARITH_IDIV:         // division: (div x y) as defined in SMT-LIB 2
2077
    case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
2078
    case UPDATE_TERM:        // update array
2079
    {
2080
      composite_term_t* desc = get_composite(terms, current_kind, current);
8,666✔
2081
      bool children_done = true;
8,666✔
2082
      bool children_same = true;
8,666✔
2083

2084
      n = desc->arity;
8,666✔
2085

2086
      ivector_t children;
2087
      init_ivector(&children, n);
8,666✔
2088

2089
      for (i = 0; i < n; ++ i) {
29,845✔
2090
        term_t child = desc->arg[i];
21,179✔
2091
        term_t child_pre = preprocessor_get(pre, child);
21,179✔
2092

2093
        if (child_pre == NULL_TERM) {
21,179✔
2094
          children_done = false;
4,060✔
2095
          ivector_push(pre_stack, child);
4,060✔
2096
        } else {
2097
          // Purify if needed
2098
          child_pre = preprocessor_purify(pre, child_pre, out);
17,119✔
2099
          // If interpreted terms, we need to purify non-variables
2100
          if (child_pre != child) { children_same = false; }
17,119✔
2101
        }
2102

2103
        if (children_done) { ivector_push(&children, child_pre); }
21,179✔
2104
      }
2105

2106
      if (children_done) {
8,666✔
2107
        if (children_same) {
5,654✔
2108
          current_pre = current;
4,219✔
2109
        } else {
2110
          current_pre = mk_composite(pre, current_kind, n, children.data);
1,435✔
2111
        }
2112
      }
2113

2114
      delete_ivector(&children);
8,666✔
2115

2116
      break;
8,666✔
2117
    }
2118

UNCOV
2119
    case ARITH_IS_INT_ATOM:
×
2120
    {
2121
      // replace with t <= floor(t)
UNCOV
2122
      term_t child = arith_is_int_arg(terms, current);
×
UNCOV
2123
      term_t child_pre = preprocessor_get(pre, child);
×
UNCOV
2124
      if (child_pre != NULL_TERM) {
×
UNCOV
2125
        child_pre = preprocessor_purify(pre, child_pre, out);
×
UNCOV
2126
        current_pre = arith_floor(terms, child_pre);
×
UNCOV
2127
        current_pre = mk_arith_leq(tm, child_pre, current_pre);
×
2128
      } else {
UNCOV
2129
        ivector_push(pre_stack, child);
×
2130
      }
UNCOV
2131
      break;
×
2132
    }
2133

2134
    case ARITH_FLOOR:        // floor: purify, but its interpreted
7✔
2135
    {
2136
      term_t child = arith_floor_arg(terms, current);
7✔
2137
      term_t child_pre = preprocessor_get(pre, child);
7✔
2138

2139
      if (child_pre != NULL_TERM) {
7✔
2140
        if (term_kind(terms, child_pre) == ARITH_CONSTANT) {
4✔
2141
          rational_t floor;
2142
          q_init(&floor);
1✔
2143
          q_set(&floor, rational_term_desc(terms, child_pre));
1✔
2144
          q_floor(&floor);
1✔
2145
          current_pre = arith_constant(terms, &floor);
1✔
2146
          q_clear(&floor);
1✔
2147
        } else {
2148
          child_pre = preprocessor_purify(pre, child_pre, out);
3✔
2149
          if (child_pre != child) {
3✔
2150
            current_pre = arith_floor(terms, child_pre);
1✔
2151
          } else {
2152
            current_pre = current;
2✔
2153
          }
2154
        }
2155
      } else {
2156
        ivector_push(pre_stack, child);
3✔
2157
      }
2158

2159
      break;
7✔
2160
    }
2161

UNCOV
2162
    case ARITH_CEIL:        // floor: purify, but its interpreted
×
2163
    {
2164
      term_t child = arith_ceil_arg(terms, current);
×
UNCOV
2165
      term_t child_pre = preprocessor_get(pre, child);
×
2166

UNCOV
2167
      if (child_pre != NULL_TERM) {
×
UNCOV
2168
        child_pre = preprocessor_purify(pre, child_pre, out);
×
UNCOV
2169
        if (child_pre != child) {
×
UNCOV
2170
          current_pre = arith_floor(terms, child_pre);
×
2171
        } else {
UNCOV
2172
          current_pre = current;
×
2173
        }
2174
      } else {
UNCOV
2175
        ivector_push(pre_stack, child);
×
2176
      }
2177

UNCOV
2178
      break;
×
2179
    }
2180

2181
    case DISTINCT_TERM:
27✔
2182
    {
2183
      composite_term_t* desc = get_composite(terms, current_kind, current);
27✔
2184

2185
      bool children_done = true;
27✔
2186
      n = desc->arity;
27✔
2187

2188
      // DISTINCT_TERM is lowered below into pairwise disequalities. Apply the
2189
      // same function-sort guard before that expansion.
2190
      for (i = 0; i < n; ++ i) {
125✔
2191
        if (term_needs_function_diseq_guard(terms, desc->arg[i])) {
101✔
2192
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
3✔
2193
        }
2194
      }
2195

2196
      ivector_t children;
2197
      init_ivector(&children, n);
24✔
2198

2199
      for (i = 0; i < n; ++ i) {
122✔
2200
        term_t child = desc->arg[i];
98✔
2201
        term_t child_pre = preprocessor_get(pre, child);
98✔
2202

2203
        if (child_pre == NULL_TERM) {
98✔
2204
          children_done = false;
41✔
2205
          ivector_push(pre_stack, child);
41✔
2206
        }
2207

2208
        if (children_done) { ivector_push(&children, child_pre); }
98✔
2209
      }
2210

2211
      if (children_done) {
24✔
2212
        ivector_t distinct;
2213
        init_ivector(&distinct, 0);
14✔
2214

2215
        for (i = 0; i < n; ++ i) {
70✔
2216
          for (j = i + 1; j < n; ++ j) {
148✔
2217
            term_t neq = mk_eq(&pre->tm, children.data[i], children.data[j]);
92✔
2218
            neq = opposite_term(neq);
92✔
2219
            ivector_push(&distinct, neq);
92✔
2220
          }
2221
        }
2222
        current_pre = mk_and(&pre->tm, distinct.size, distinct.data);
14✔
2223

2224
        delete_ivector(&distinct);
14✔
2225
      }
2226

2227
      delete_ivector(&children);
24✔
2228

2229
      break;
24✔
2230
    }
2231

2232
    case LAMBDA_TERM:
×
2233
      longjmp(*pre->exception, LAMBDAS_NOT_SUPPORTED);
×
2234
      break;
2235

UNCOV
2236
    default:
×
2237
      // UNSUPPORTED TERM/THEORY
UNCOV
2238
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
2239
      break;
2240
    }
2241

2242
    if (current_pre != NULL_TERM) {
347,665✔
2243
      preprocessor_set(pre, current, current_pre);
264,153✔
2244
      ivector_pop(pre_stack);
264,153✔
2245
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
264,153✔
UNCOV
2246
        mcsat_trace_printf(pre->tracer, "current_pre = ");
×
UNCOV
2247
        trace_term_ln(pre->tracer, terms, current_pre);
×
2248
      }
2249
    }
2250

2251
  }
2252

2253
  // Return the result
2254
  t_pre = preprocessor_get(pre, t);
38,168✔
2255
  if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,168✔
UNCOV
2256
    mcsat_trace_printf(pre->tracer, "t_pre = ");
×
UNCOV
2257
    trace_term_ln(pre->tracer, terms, t_pre);
×
2258
  }
2259

2260
  ivector_reset(pre_stack);
38,168✔
2261

2262
  assert(t_pre != NULL_TERM);
2263
  return t_pre;
38,168✔
2264
}
2265

UNCOV
2266
void preprocessor_set_exception_handler(preprocessor_t* pre, jmp_buf* handler) {
×
UNCOV
2267
  pre->exception = handler;
×
UNCOV
2268
}
×
2269

2270
void preprocessor_push(preprocessor_t* pre) {
528✔
2271
  scope_holder_push(&pre->scope,
528✔
2272
      &pre->preprocess_map_list.size,
2273
      &pre->tuple_blast_list.size,
2274
      &pre->tuple_blast_data.size,
2275
      &pre->tuple_blast_atoms.size,
2276
      &pre->purification_map_list.size,
2277
      &pre->equalities_list.size,
2278
      NULL);
2279
}
528✔
2280

2281
void preprocessor_pop(preprocessor_t* pre) {
454✔
2282

2283
  uint32_t preprocess_map_list_size = 0;
454✔
2284
  uint32_t tuple_blast_list_size = 0;
454✔
2285
  uint32_t tuple_blast_data_size = 0;
454✔
2286
  uint32_t tuple_blast_atoms_size = 0;
454✔
2287
  uint32_t purification_map_list_size = 0;
454✔
2288
  uint32_t equalities_list_size = 0;
454✔
2289

2290
  scope_holder_pop(&pre->scope,
454✔
2291
      &preprocess_map_list_size,
2292
      &tuple_blast_list_size,
2293
      &tuple_blast_data_size,
2294
      &tuple_blast_atoms_size,
2295
      &purification_map_list_size,
2296
      &equalities_list_size,
2297
      NULL);
2298

2299
  while (pre->preprocess_map_list.size > preprocess_map_list_size) {
11,955✔
2300
    term_t t = ivector_last(&pre->preprocess_map_list);
11,501✔
2301
    ivector_pop(&pre->preprocess_map_list);
11,501✔
2302
    int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
11,501✔
2303
    assert(find != NULL);
2304
    int_hmap_erase(&pre->preprocess_map, find);
11,501✔
2305
  }
2306

2307
  while (pre->tuple_blast_list.size > tuple_blast_list_size) {
1,816✔
2308
    term_t t = ivector_last(&pre->tuple_blast_list);
1,362✔
2309
    ivector_pop(&pre->tuple_blast_list);
1,362✔
2310
    int_hmap_pair_t* find = int_hmap_find(&pre->tuple_blast_map, t);
1,362✔
2311
    assert(find != NULL);
2312
    int_hmap_erase(&pre->tuple_blast_map, find);
1,362✔
2313
  }
2314
  ivector_shrink(&pre->tuple_blast_data, tuple_blast_data_size);
454✔
2315
  ivector_shrink(&pre->tuple_blast_atoms, tuple_blast_atoms_size);
454✔
2316

2317
  while (pre->purification_map_list.size > purification_map_list_size) {
589✔
2318
    term_t t = ivector_last(&pre->purification_map_list);
135✔
2319
    ivector_pop(&pre->purification_map_list);
135✔
2320
    int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
135✔
2321
    assert(find != NULL);
2322
    int_hmap_erase(&pre->purification_map, find);
135✔
2323
  }
2324

2325
  while (pre->equalities_list.size > equalities_list_size) {
504✔
2326
    term_t eq = ivector_last(&pre->equalities_list);
50✔
2327
    ivector_pop(&pre->equalities_list);
50✔
2328
    int_hmap_pair_t* find = int_hmap_find(&pre->equalities, eq);
50✔
2329
    assert(find != NULL);
2330
    int_hmap_erase(&pre->equalities, find);
50✔
2331
  }
2332
}
454✔
2333

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

2336
static
2337
value_t build_value_from_flat(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* flat, uint32_t* idx) {
98✔
2338
  type_table_t* types = pre->terms->types;
98✔
2339

2340
  if (type_kind(types, tau) == TUPLE_TYPE) {
98✔
2341
    tuple_type_t* tuple = tuple_type_desc(types, tau);
32✔
2342
    uint32_t i, n = tuple->nelem;
32✔
2343
    value_t elem[n];
32✔
2344
    for (i = 0; i < n; ++i) {
97✔
2345
      elem[i] = build_value_from_flat(pre, vtbl, tuple->elem[i], flat, idx);
65✔
2346
      if (elem[i] == null_value) {
65✔
NEW
2347
        return null_value;
×
2348
      }
2349
    }
2350
    return vtbl_mk_tuple(vtbl, n, elem);
32✔
2351
  } else if (type_kind(types, tau) == FUNCTION_TYPE) {
66✔
2352
    uint32_t n = type_leaf_count(pre, tau);
3✔
2353
    value_t v = merge_blasted_function_value(pre, vtbl, tau, flat + *idx, n);
3✔
2354
    *idx += n;
3✔
2355
    return v;
3✔
2356
  } else {
2357
    value_t v = flat[*idx];
63✔
2358
    (*idx)++;
63✔
2359
    return v;
63✔
2360
  }
2361
}
2362

2363
static
2364
bool map_args_match(value_table_t* vtbl, value_t map, const value_t* args, uint32_t n) {
23✔
2365
  value_map_t* m = vtbl_map(vtbl, map);
23✔
2366
  uint32_t i;
2367
  if (m->arity != n) {
23✔
NEW
2368
    return false;
×
2369
  }
2370
  for (i = 0; i < n; ++i) {
48✔
2371
    if (m->arg[i] != args[i]) {
34✔
2372
      return false;
9✔
2373
    }
2374
  }
2375
  return true;
14✔
2376
}
2377

2378
static
2379
value_t find_map_result(value_table_t* vtbl, const ivector_t* maps, const value_t* args, uint32_t n, value_t def) {
19✔
2380
  uint32_t i;
2381
  for (i = 0; i < maps->size; ++i) {
28✔
2382
    value_t map = maps->data[i];
23✔
2383
    if (map_args_match(vtbl, map, args, n)) {
23✔
2384
      return vtbl_map(vtbl, map)->val;
14✔
2385
    }
2386
  }
2387
  return def;
5✔
2388
}
2389

2390
static
2391
void add_unique_flat_args(ivector_t* offsets, ivector_t* data, const value_t* args, uint32_t n) {
14✔
2392
  uint32_t i, j;
2393
  for (i = 0; i < offsets->size; ++i) {
18✔
2394
    uint32_t off = offsets->data[i];
9✔
2395
    bool same = true;
9✔
2396
    for (j = 0; j < n; ++j) {
18✔
2397
      if (data->data[off + j] != args[j]) {
13✔
2398
        same = false;
4✔
2399
        break;
4✔
2400
      }
2401
    }
2402
    if (same) {
9✔
2403
      return;
5✔
2404
    }
2405
  }
2406
  ivector_push(offsets, data->size);
9✔
2407
  ivector_add(data, args, n);
9✔
2408
}
2409

2410
static
2411
value_t merge_blasted_function_value(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* leaves, uint32_t nleaves) {
5✔
2412
  type_table_t* types = pre->terms->types;
5✔
2413
  function_type_t* fun = function_type_desc(types, tau);
5✔
2414
  type_t codom = fun->range;
5✔
2415
  uint32_t i, j;
2416
  ivector_t flat_dom;
2417
  ivector_t unique_offsets;
2418
  ivector_t unique_args;
2419
  ivector_t orig_maps;
2420
  value_t result = null_value;
5✔
2421
  value_t leaf_defaults[nleaves];
5✔
2422
  ivector_t leaf_maps[nleaves];
5✔
2423
  uint32_t flat_n;
2424
  uint32_t maps_init = 0;
5✔
2425
  /* Short tag describing why we bailed, so the caller (or a user
2426
   * investigating a missing model entry) can see the cause through a
2427
   * single line of trace output. Set immediately before each `goto done`
2428
   * error exit; the successful path leaves it NULL. */
2429
  const char* fail_reason = NULL;
5✔
2430

2431
  /* All heap-backed scratch vectors are initialized up-front so that every
2432
   * exit through the `done:` label has the same cleanup responsibilities.
2433
   * In particular orig_maps is deliberately initialized here rather than
2434
   * just before the loop that populates it: if its init moves, `goto done`
2435
   * paths that run before the init would otherwise silently leak the
2436
   * vector. Keeping the init paired with the other unconditional inits
2437
   * makes that invariant self-evident. */
2438
  init_ivector(&flat_dom, 0);
5✔
2439
  init_ivector(&unique_offsets, 0);
5✔
2440
  init_ivector(&unique_args, 0);
5✔
2441
  init_ivector(&orig_maps, 0);
5✔
2442

2443
  for (i = 0; i < fun->ndom; ++i) {
10✔
2444
    type_collect_flat(types, fun->domain[i], &flat_dom);
5✔
2445
  }
2446
  flat_n = flat_dom.size;
5✔
2447

2448
  for (i = 0; i < nleaves; ++i) {
15✔
2449
    value_t def = null_value;
10✔
2450
    type_t leaf_tau = NULL_TYPE;
10✔
2451
    init_ivector(&leaf_maps[i], 0);
10✔
2452
    maps_init = i + 1;
10✔
2453
    if (!object_is_function(vtbl, leaves[i]) && !object_is_update(vtbl, leaves[i])) {
10✔
NEW
2454
      fail_reason = "leaf value is neither a function nor an update object";
×
NEW
2455
      goto done;
×
2456
    }
2457
    if (object_is_update(vtbl, leaves[i])) {
10✔
2458
      vtbl_expand_update(vtbl, leaves[i], &def, &leaf_tau);
10✔
2459
      leaf_defaults[i] = def;
10✔
2460
      if (vtbl->hset1 != NULL) {
10✔
2461
        ivector_add(&leaf_maps[i], (int32_t*) vtbl->hset1->data, vtbl->hset1->nelems);
10✔
2462
        for (j = 0; j < vtbl->hset1->nelems; ++j) {
24✔
2463
          value_map_t* map = vtbl_map(vtbl, vtbl->hset1->data[j]);
14✔
2464
          if (map->arity != flat_n) {
14✔
NEW
2465
            fail_reason = "update leaf map arity does not match flattened domain";
×
NEW
2466
            goto done;
×
2467
          }
2468
          add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
14✔
2469
        }
2470
      }
2471
      continue;
10✔
2472
    }
NEW
2473
    value_fun_t* fun_value = vtbl_function(vtbl, leaves[i]);
×
NEW
2474
    def = fun_value->def;
×
NEW
2475
    leaf_tau = fun_value->type;
×
NEW
2476
    leaf_defaults[i] = def;
×
NEW
2477
    ivector_add(&leaf_maps[i], (int32_t*) fun_value->map, fun_value->map_size);
×
NEW
2478
    for (j = 0; j < fun_value->map_size; ++j) {
×
NEW
2479
      value_map_t* map = vtbl_map(vtbl, fun_value->map[j]);
×
NEW
2480
      if (map->arity != flat_n) {
×
NEW
2481
        fail_reason = "function leaf map arity does not match flattened domain";
×
NEW
2482
        goto done;
×
2483
      }
NEW
2484
      add_unique_flat_args(&unique_offsets, &unique_args, map->arg, flat_n);
×
2485
    }
2486
  }
2487

2488
  for (i = 0; i < unique_offsets.size; ++i) {
14✔
2489
    uint32_t flat_idx = unique_offsets.data[i];
9✔
2490
    const value_t* flat_args = (value_t*) (unique_args.data + flat_idx);
9✔
2491
    value_t leaf_values[nleaves];
9✔
2492
    uint32_t idx;
2493
    value_t mapv;
2494

2495
    for (j = 0; j < nleaves; ++j) {
28✔
2496
      leaf_values[j] = find_map_result(vtbl, &leaf_maps[j], flat_args, flat_n, leaf_defaults[j]);
19✔
2497
    }
2498

2499
    idx = 0;
9✔
2500
    value_t out_val = build_value_from_flat(pre, vtbl, codom, leaf_values, &idx);
9✔
2501
    if (out_val == null_value) {
9✔
NEW
2502
      fail_reason = "could not build codomain value from flat leaf values";
×
NEW
2503
      goto done;
×
2504
    }
2505

2506
    value_t args_orig[fun->ndom];
9✔
2507
    idx = 0;
9✔
2508
    for (j = 0; j < fun->ndom; ++j) {
18✔
2509
      args_orig[j] = build_value_from_flat(pre, vtbl, fun->domain[j], flat_args, &idx);
9✔
2510
      if (args_orig[j] == null_value) {
9✔
NEW
2511
        fail_reason = "could not rebuild a domain argument from flat leaf values";
×
NEW
2512
        goto done;
×
2513
      }
2514
    }
2515
    mapv = vtbl_mk_map(vtbl, fun->ndom, args_orig, out_val);
9✔
2516
    ivector_push(&orig_maps, mapv);
9✔
2517
  }
2518

2519
  {
2520
    uint32_t idx = 0;
5✔
2521
    value_t def_val = build_value_from_flat(pre, vtbl, codom, leaf_defaults, &idx);
5✔
2522
    if (def_val == null_value) {
5✔
NEW
2523
      fail_reason = "could not rebuild the function default value";
×
NEW
2524
      goto done;
×
2525
    }
2526
    result = vtbl_mk_function(vtbl, tau, orig_maps.size, (value_t*) orig_maps.data, def_val);
5✔
2527
  }
2528

2529
 done:
5✔
2530
  if (fail_reason != NULL && trace_enabled(pre->tracer, "mcsat::preprocess")) {
5✔
NEW
2531
    mcsat_trace_printf(pre->tracer,
×
2532
                       "merge_blasted_function_value: %s\n", fail_reason);
2533
  }
2534
  /* Single cleanup path for every error exit. All ivectors above are
2535
   * unconditionally initialized before any `goto done`, so unconditional
2536
   * deletes here are correct and stay correct if new error branches are
2537
   * added. leaf_maps is the only exception: its initialization is
2538
   * interleaved with error checks in the first loop, so we still only
2539
   * delete the prefix recorded by maps_init. */
2540
  for (i = 0; i < maps_init; ++i) {
15✔
2541
    delete_ivector(&leaf_maps[i]);
10✔
2542
  }
2543
  delete_ivector(&orig_maps);
5✔
2544
  delete_ivector(&unique_offsets);
5✔
2545
  delete_ivector(&unique_args);
5✔
2546
  delete_ivector(&flat_dom);
5✔
2547
  return result;
5✔
2548
}
2549

2550
static
2551
void preprocessor_build_tuple_model(preprocessor_t* pre, model_t* model) {
43✔
2552
  value_table_t* vtbl = model_get_vtbl(model);
43✔
2553
  type_table_t* types = pre->terms->types;
43✔
2554
  uint32_t i;
2555

2556
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
55✔
2557
    term_t atom = pre->tuple_blast_atoms.data[i];
12✔
2558
    ivector_t leaves;
2559
    type_t tau = term_type(pre->terms, atom);
12✔
2560
    uint32_t n, j;
2561

2562
    if (model_find_term_value(model, atom) != null_value) {
12✔
NEW
2563
      continue;
×
2564
    }
2565

2566
    init_ivector(&leaves, 0);
12✔
2567
    tuple_blast_get(pre, atom, &leaves);
12✔
2568
    n = leaves.size;
12✔
2569
    if (n == 0) {
12✔
NEW
2570
      delete_ivector(&leaves);
×
NEW
2571
      continue;
×
2572
    }
2573

2574
    value_t leaf_vals[n];
12✔
2575
    bool ok = true;
12✔
2576
    for (j = 0; j < n; ++j) {
40✔
2577
      value_t v = model_get_term_value(model, leaves.data[j]);
28✔
2578
      if (v < 0) {
28✔
NEW
2579
        ok = false;
×
NEW
2580
        break;
×
2581
      }
2582
      leaf_vals[j] = v;
28✔
2583
    }
2584
    if (!ok) {
12✔
2585
      /* A blasted leaf was never assigned a value by the mcsat search.
2586
       * We cannot reconstruct a value for the original atom, so it will
2587
       * be absent from the returned model. Log which atom and which leaf
2588
       * index so a user investigating a missing (show-model) entry can
2589
       * pin the gap. */
NEW
2590
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2591
        mcsat_trace_printf(pre->tracer,
×
2592
                           "preprocessor_build_tuple_model: dropping atom ");
NEW
2593
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2594
        mcsat_trace_printf(pre->tracer,
×
2595
                           "  (blasted leaf %u has no value in the trail model)\n", j);
2596
      }
NEW
2597
      delete_ivector(&leaves);
×
NEW
2598
      continue;
×
2599
    }
2600

2601
    if (type_kind(types, tau) == FUNCTION_TYPE) {
12✔
2602
      value_t f = merge_blasted_function_value(pre, vtbl, tau, leaf_vals, n);
2✔
2603
      if (f >= 0) {
2✔
2604
        model_map_term(model, atom, f);
2✔
NEW
2605
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
2606
        /* merge_blasted_function_value has already traced a reason code;
2607
         * complete the message here with the concrete atom identity. */
NEW
2608
        mcsat_trace_printf(pre->tracer,
×
2609
                           "preprocessor_build_tuple_model: dropping function atom ");
NEW
2610
        trace_term_ln(pre->tracer, pre->terms, atom);
×
2611
      }
2612
    } else {
2613
      uint32_t idx = 0;
10✔
2614
      value_t v = build_value_from_flat(pre, vtbl, tau, leaf_vals, &idx);
10✔
2615
      if (v >= 0) {
10✔
2616
        model_map_term(model, atom, v);
10✔
NEW
2617
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2618
        mcsat_trace_printf(pre->tracer,
×
2619
                           "preprocessor_build_tuple_model: dropping tuple atom ");
NEW
2620
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2621
        mcsat_trace_printf(pre->tracer,
×
2622
                           "  (leaf values did not decompose into a tuple value)\n");
2623
      }
2624
    }
2625

2626
    delete_ivector(&leaves);
12✔
2627
  }
2628
}
43✔
2629

2630
static term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx);
2631
static void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out);
2632

2633
static
NEW
2634
term_t merge_blasted_function_term(preprocessor_t* pre, type_t tau, const term_t* leaves, uint32_t nleaves) {
×
NEW
2635
  term_table_t* terms = pre->terms;
×
NEW
2636
  type_table_t* types = terms->types;
×
NEW
2637
  function_type_t* fun = function_type_desc(types, tau);
×
2638
  uint32_t i, idx;
NEW
2639
  term_t result = NULL_TERM;
×
NEW
2640
  term_t vars[fun->ndom];
×
2641
  ivector_t flat_args;
2642

2643
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2644
  assert(nleaves == type_leaf_count(pre, tau));
2645

NEW
2646
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2647
    vars[i] = new_variable(terms, fun->domain[i]);
×
2648
  }
2649

NEW
2650
  init_ivector(&flat_args, 0);
×
NEW
2651
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2652
    collect_flat_leaf_terms(pre, vars[i], fun->domain[i], &flat_args);
×
2653
  }
2654

NEW
2655
  term_t leaf_apps[nleaves];
×
NEW
2656
  for (i = 0; i < nleaves; ++i) {
×
NEW
2657
    leaf_apps[i] = mk_application(&pre->tm, leaves[i], flat_args.size, (term_t*) flat_args.data);
×
NEW
2658
    if (leaf_apps[i] == NULL_TERM) {
×
NEW
2659
      goto done;
×
2660
    }
2661
  }
2662

NEW
2663
  idx = 0;
×
NEW
2664
  term_t body = build_term_from_flat(pre, fun->range, leaf_apps, &idx);
×
NEW
2665
  if (body == NULL_TERM || idx != nleaves) {
×
NEW
2666
    goto done;
×
2667
  }
2668

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

NEW
2671
 done:
×
NEW
2672
  delete_ivector(&flat_args);
×
NEW
2673
  return result;
×
2674
}
2675

2676
static
2677
term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx) {
11✔
2678
  type_table_t* types = pre->terms->types;
11✔
2679
  switch (type_kind(types, tau)) {
11✔
2680
  case TUPLE_TYPE: {
3✔
2681
    tuple_type_t* tuple = tuple_type_desc(types, tau);
3✔
2682
    uint32_t i, n = tuple->nelem;
3✔
2683
    term_t elem[n];
3✔
2684
    for (i = 0; i < n; ++i) {
9✔
2685
      elem[i] = build_term_from_flat(pre, tuple->elem[i], flat, idx);
6✔
2686
      if (elem[i] == NULL_TERM) {
6✔
NEW
2687
        return NULL_TERM;
×
2688
      }
2689
    }
2690
    return mk_tuple(&pre->tm, n, elem);
3✔
2691
  }
2692

NEW
2693
  case FUNCTION_TYPE: {
×
NEW
2694
    uint32_t n = type_leaf_count(pre, tau);
×
NEW
2695
    term_t f = merge_blasted_function_term(pre, tau, flat + *idx, n);
×
NEW
2696
    *idx += n;
×
NEW
2697
    return f;
×
2698
  }
2699

2700
  default: {
8✔
2701
    term_t t = flat[*idx];
8✔
2702
    (*idx)++;
8✔
2703
    return t;
8✔
2704
  }
2705
  }
2706
}
2707

2708
static
2709
term_t mk_unblasted_function_leaf_lambda(preprocessor_t* pre, term_t atom, uint32_t leaf_i, type_t leaf_type) {
5✔
2710
  term_table_t* terms = pre->terms;
5✔
2711
  type_table_t* types = terms->types;
5✔
2712
  function_type_t* atom_fun = function_type_desc(types, term_type(terms, atom));
5✔
2713
  function_type_t* leaf_fun = function_type_desc(types, leaf_type);
5✔
2714
  uint32_t flat_n = leaf_fun->ndom;
5✔
2715
  uint32_t i, idx;
2716
  term_t flat_vars[flat_n];
5✔
2717
  term_t orig_args[atom_fun->ndom];
5✔
2718
  term_t app;
2719
  term_t body = NULL_TERM;
5✔
2720
  term_t result = NULL_TERM;
5✔
2721
  ivector_t codom_leaves;
2722

2723
  for (i = 0; i < flat_n; ++i) {
13✔
2724
    flat_vars[i] = new_variable(terms, leaf_fun->domain[i]);
8✔
2725
  }
2726

2727
  idx = 0;
5✔
2728
  for (i = 0; i < atom_fun->ndom; ++i) {
10✔
2729
    orig_args[i] = build_term_from_flat(pre, atom_fun->domain[i], flat_vars, &idx);
5✔
2730
    if (orig_args[i] == NULL_TERM) {
5✔
NEW
2731
      return NULL_TERM;
×
2732
    }
2733
  }
2734
  assert(idx == flat_n);
2735

2736
  app = mk_application(&pre->tm, atom, atom_fun->ndom, orig_args);
5✔
2737
  if (app == NULL_TERM) {
5✔
NEW
2738
    return NULL_TERM;
×
2739
  }
2740

2741
  init_ivector(&codom_leaves, 0);
5✔
2742
  collect_flat_leaf_terms(pre, app, atom_fun->range, &codom_leaves);
5✔
2743
  if (leaf_i < codom_leaves.size) {
5✔
2744
    body = codom_leaves.data[leaf_i];
5✔
2745
  }
2746
  if (body != NULL_TERM) {
5✔
2747
    result = mk_lambda(&pre->tm, flat_n, flat_vars, body);
5✔
2748
  }
2749
  delete_ivector(&codom_leaves);
5✔
2750

2751
  return result;
5✔
2752
}
2753

2754
static
2755
void collect_function_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
3✔
2756
  type_table_t* types = pre->terms->types;
3✔
2757
  ivector_t leaf_types;
2758
  uint32_t i;
2759

2760
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2761

2762
  init_ivector(&leaf_types, 0);
3✔
2763
  function_type_collect_blasted(types, tau, &leaf_types);
3✔
2764
  for (i = 0; i < leaf_types.size; ++i) {
8✔
2765
    term_t leaf = mk_unblasted_function_leaf_lambda(pre, base, i, leaf_types.data[i]);
5✔
2766
    if (leaf != NULL_TERM) {
5✔
2767
      ivector_push(out, leaf);
5✔
2768
    }
2769
  }
2770
  delete_ivector(&leaf_types);
3✔
2771
}
3✔
2772

2773
static
2774
void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
22✔
2775
  type_table_t* types = pre->terms->types;
22✔
2776

2777
  switch (type_kind(types, tau)) {
22✔
2778
  case TUPLE_TYPE: {
7✔
2779
    tuple_type_t* tuple = tuple_type_desc(types, tau);
7✔
2780
    uint32_t i;
2781
    for (i = 0; i < tuple->nelem; ++i) {
21✔
2782
      term_t child = mk_select(&pre->tm, i, base);
14✔
2783
      collect_flat_leaf_terms(pre, child, tuple->elem[i], out);
14✔
2784
    }
2785
    break;
7✔
2786
  }
2787

2788
  case FUNCTION_TYPE:
3✔
2789
    collect_function_leaf_terms(pre, base, tau, out);
3✔
2790
    break;
3✔
2791

2792
  default:
12✔
2793
    ivector_push(out, base);
12✔
2794
    break;
12✔
2795
  }
2796
}
22✔
2797

2798
static
2799
bool substitution_has_var(const ivector_t* vars, term_t x) {
8✔
2800
  uint32_t i;
2801
  for (i = 0; i < vars->size; ++i) {
15✔
2802
    if (vars->data[i] == x) {
7✔
NEW
2803
      return true;
×
2804
    }
2805
  }
2806
  return false;
8✔
2807
}
2808

2809
term_t preprocessor_unblast_term(preprocessor_t* pre, term_t t) {
43✔
2810
  term_table_t* terms = pre->terms;
43✔
2811
  ivector_t vars, maps;
2812
  ivector_t leaves, accessors;
2813
  uint32_t i, j;
2814
  term_t out;
2815

2816
  if (pre->tuple_blast_atoms.size == 0) {
43✔
2817
    return t;
40✔
2818
  }
2819

2820
  init_ivector(&vars, 0);
3✔
2821
  init_ivector(&maps, 0);
3✔
2822
  init_ivector(&leaves, 0);
3✔
2823
  init_ivector(&accessors, 0);
3✔
2824

2825
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
6✔
2826
    term_t atom = pre->tuple_blast_atoms.data[i];
3✔
2827
    type_t atom_type = term_type(terms, atom);
3✔
2828
    tuple_blast_get(pre, atom, &leaves);
3✔
2829
    ivector_reset(&accessors);
3✔
2830
    collect_flat_leaf_terms(pre, atom, atom_type, &accessors);
3✔
2831
    if (leaves.size != accessors.size) {
3✔
NEW
2832
      continue;
×
2833
    }
2834
    for (j = 0; j < leaves.size; ++j) {
11✔
2835
      term_t x = leaves.data[j];
8✔
2836
      term_t u = accessors.data[j];
8✔
2837
      term_kind_t k = term_kind(terms, x);
8✔
2838
      bool is_var = (k == UNINTERPRETED_TERM || k == VARIABLE);
8✔
2839
      if (x != u && is_var && !substitution_has_var(&vars, x)) {
8✔
2840
        ivector_push(&vars, x);
8✔
2841
        ivector_push(&maps, u);
8✔
2842
      }
2843
    }
2844
  }
2845

2846
  if (vars.size == 0) {
3✔
NEW
2847
    out = t;
×
2848
  } else {
2849
    term_subst_t subst;
2850
    init_term_subst(&subst, &pre->tm, vars.size, (term_t*) vars.data, (term_t*) maps.data);
3✔
2851
    out = apply_term_subst(&subst, t);
3✔
2852
    delete_term_subst(&subst);
3✔
2853
  }
2854

2855
  delete_ivector(&accessors);
3✔
2856
  delete_ivector(&leaves);
3✔
2857
  delete_ivector(&maps);
3✔
2858
  delete_ivector(&vars);
3✔
2859

2860
  return out;
3✔
2861
}
2862

2863
void preprocessor_build_model(preprocessor_t* pre, model_t* model) {
43✔
2864
  uint32_t i = 0;
43✔
2865
  for (i = 0; i < pre->equalities_list.size; ++ i) {
56✔
2866
    term_t eq = pre->equalities_list.data[i];
13✔
2867
    term_t eq_var = preprocessor_get_eq_solved_var(pre, eq);
13✔
2868
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
13✔
2869
      mcsat_trace_printf(pre->tracer, "eq = ");
×
UNCOV
2870
      trace_term_ln(pre->tracer, pre->terms, eq);
×
UNCOV
2871
      mcsat_trace_printf(pre->tracer, "\neq_var = ");
×
UNCOV
2872
      trace_term_ln(pre->tracer, pre->terms, eq_var);
×
UNCOV
2873
      mcsat_trace_printf(pre->tracer, "\n");
×
2874
    }
2875
    // Some equalities are solved, but then reasserted in the solver
2876
    // these already have a model
2877
    if (model_find_term_value(model, eq_var) != null_value) {
13✔
UNCOV
2878
      continue;
×
2879
    }
2880
    // Some equalities are marked, but not solved. These we skip as they
2881
    // are already set in the model
2882
    if (preprocessor_get(pre, eq_var) == eq_var) {
13✔
UNCOV
2883
      continue;
×
2884
    }
2885
    term_kind_t eq_kind = term_kind(pre->terms, eq);
13✔
2886
    composite_term_t* eq_desc = get_composite(pre->terms, eq_kind, eq);
13✔
2887
    if (eq_desc->arity > 1) {
13✔
2888
      term_t eq_subst = eq_desc->arg[0] == eq_var ? eq_desc->arg[1] : eq_desc->arg[0];
11✔
2889
      model_add_substitution(model, eq_var, eq_subst);
11✔
2890
    } else {
2891
      model_add_substitution(model, eq_var, zero_term);
2✔
2892
    }
2893
  }
2894

2895
  preprocessor_build_tuple_model(pre, model);
43✔
2896
}
43✔
2897

2898

2899
static inline
2900
void preprocessor_gc_mark_term(preprocessor_t* pre, term_t t) {
1,272✔
2901
  term_table_set_gc_mark(pre->terms, index_of(t));
1,272✔
2902
  type_table_set_gc_mark(pre->terms->types, term_type(pre->terms, t));
1,272✔
2903
}
1,272✔
2904

2905
void preprocessor_gc_mark(preprocessor_t* pre) {
5✔
2906
  uint32_t i;
2907

2908
  for (i = 0; i < pre->preprocess_map_list.size; ++ i) {
486✔
2909
    term_t t = pre->preprocess_map_list.data[i];
481✔
2910
    preprocessor_gc_mark_term(pre, t);
481✔
2911
    term_t t_pre = preprocessor_get(pre, t);
481✔
2912
    preprocessor_gc_mark_term(pre, t_pre);
481✔
2913
  }
2914

2915
  for (i = 0; i < pre->equalities_list.size; ++ i) {
5✔
2916
    term_t t = pre->equalities_list.data[i];
×
2917
    preprocessor_gc_mark_term(pre, t);
×
2918
  }
2919

2920
  for (i = 0; i < pre->tuple_blast_list.size; ++i) {
141✔
2921
    term_t t = pre->tuple_blast_list.data[i];
136✔
2922
    int_hmap_pair_t* rec = int_hmap_find(&pre->tuple_blast_map, t);
136✔
2923
    uint32_t j, n, offset;
2924
    assert(rec != NULL);
2925
    preprocessor_gc_mark_term(pre, t);
136✔
2926
    offset = rec->val;
136✔
2927
    n = pre->tuple_blast_data.data[offset];
136✔
2928
    for (j = 0; j < n; ++j) {
272✔
2929
      preprocessor_gc_mark_term(pre, pre->tuple_blast_data.data[offset + 1 + j]);
136✔
2930
    }
2931
  }
2932

2933
  for (i = 0; i < pre->purification_map_list.size; ++ i) {
24✔
2934
    term_t t = pre->purification_map_list.data[i];
19✔
2935
    preprocessor_gc_mark_term(pre, t);
19✔
2936
    term_t t_pure = int_hmap_find(&pre->purification_map, t)->val;
19✔
2937
    preprocessor_gc_mark_term(pre, t_pure);
19✔
2938
  }
2939
}
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