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

SRI-CSL / yices2 / 25536264253

08 May 2026 04:12AM UTC coverage: 67.087% (+0.4%) from 66.687%
25536264253

Pull #606

github

web-flow
Merge f7f89fbdb into 7878664a0
Pull Request #606: MCSAT: add support for tuples (incl. nested with function types); blasts tuples in input constraints + reconstitutes them in models and interpolants

851 of 1132 new or added lines in 3 files covered. (75.18%)

2 existing lines in 1 file now uncovered.

84692 of 126242 relevant lines covered (67.09%)

1632532.76 hits per line

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

81.64
/src/mcsat/preprocessor.c
1
/*
2
 * This file is part of the Yices SMT Solver.
3
 * Copyright (C) 2017 SRI International.
4
 *
5
 * Yices is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * Yices is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
#if defined(CYGWIN) || defined(MINGW)
20
#ifndef __YICES_DLLSPEC__
21
#define __YICES_DLLSPEC__ __declspec(dllexport)
22
#endif
23
#endif
24

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

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

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

38
#include "context/context_types.h"
39

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

43
#include <stdlib.h>
44

45
/* TEMP DIAG: stderr trace macro, gated on env var YICES_PP_TRACE so the
46
 * diagnostic prints don't pollute regression-test stderr (regression
47
 * tests diff stderr against expected output). Set YICES_PP_TRACE=1 in CI
48
 * runs that need to debug the Windows MinGW release+thread-safety
49
 * failure. To be removed along with every PP_DIAG call site once the
50
 * failure is pinpointed. */
51
static int pp_diag_enabled(void) {
857✔
52
  static int cached = -1;
53
  if (cached < 0) {
857✔
54
    const char* s = getenv("YICES_PP_TRACE");
28✔
55
    cached = (s != NULL && s[0] != '\0' && s[0] != '0') ? 1 : 0;
28✔
56
  }
57
  return cached;
857✔
58
}
59
#define PP_DIAG(...) do { if (pp_diag_enabled()) { fprintf(stderr, __VA_ARGS__); fflush(stderr); } } while (0)
60

61
void preprocessor_construct(preprocessor_t* pre, term_table_t* terms, jmp_buf* handler, const mcsat_options_t* options) {
717✔
62
  pre->terms = terms;
717✔
63
  init_term_manager(&pre->tm, terms);
717✔
64
  init_int_hmap(&pre->preprocess_map, 0);
717✔
65
  init_ivector(&pre->preprocess_map_list, 0);
717✔
66
  init_int_hmap(&pre->tuple_blast_map, 0);
717✔
67
  init_ivector(&pre->tuple_blast_data, 0);
717✔
68
  init_ivector(&pre->tuple_blast_list, 0);
717✔
69
  init_ivector(&pre->tuple_blast_atoms, 0);
717✔
70
  init_int_hmap(&pre->type_is_tuple_free_cache, 0);
717✔
71
  init_int_hmap(&pre->type_leaf_count_cache, 0);
717✔
72
  init_int_hmap(&pre->term_has_tuples_cache, 0);
717✔
73
  init_int_hmap(&pre->purification_map, 0);
717✔
74
  init_ivector(&pre->purification_map_list, 0);
717✔
75
  init_ivector(&pre->preprocessing_stack, 0);
717✔
76
  init_int_hmap(&pre->equalities, 0);
717✔
77
  init_ivector(&pre->equalities_list, 0);
717✔
78
  pre->tracer = NULL;
717✔
79
  pre->exception = handler;
717✔
80
  pre->options = options;
717✔
81
  scope_holder_construct(&pre->scope);
717✔
82
}
717✔
83

84
void preprocessor_set_tracer(preprocessor_t* pre, tracer_t* tracer) {
284✔
85
  pre->tracer = tracer;
284✔
86
}
284✔
87

88
void preprocessor_destruct(preprocessor_t* pre) {
717✔
89
  delete_int_hmap(&pre->purification_map);
717✔
90
  delete_ivector(&pre->purification_map_list);
717✔
91
  delete_int_hmap(&pre->tuple_blast_map);
717✔
92
  delete_ivector(&pre->tuple_blast_data);
717✔
93
  delete_ivector(&pre->tuple_blast_list);
717✔
94
  delete_ivector(&pre->tuple_blast_atoms);
717✔
95
  delete_int_hmap(&pre->type_is_tuple_free_cache);
717✔
96
  delete_int_hmap(&pre->type_leaf_count_cache);
717✔
97
  delete_int_hmap(&pre->term_has_tuples_cache);
717✔
98
  delete_int_hmap(&pre->preprocess_map);
717✔
99
  delete_ivector(&pre->preprocess_map_list);
717✔
100
  delete_ivector(&pre->preprocessing_stack);
717✔
101
  delete_int_hmap(&pre->equalities);
717✔
102
  delete_ivector(&pre->equalities_list);
717✔
103
  delete_term_manager(&pre->tm);
717✔
104
  scope_holder_destruct(&pre->scope);
717✔
105
}
717✔
106

107
static
108
term_t preprocessor_get(preprocessor_t* pre, term_t t) {
1,602,489✔
109
  int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
1,602,489✔
110
  if (find == NULL) {
1,602,489✔
111
    return NULL_TERM;
868,791✔
112
  } else {
113
    return find->val;
733,698✔
114
  }
115
}
116

117
static
118
void preprocessor_set(preprocessor_t* pre, term_t t, term_t t_pre) {
336,535✔
119
  assert(preprocessor_get(pre, t) == NULL_TERM);
120
  int_hmap_add(&pre->preprocess_map, t, t_pre);
336,535✔
121
  ivector_push(&pre->preprocess_map_list, t);
336,535✔
122
}
336,535✔
123

124
static
125
bool type_is_tuple_free(preprocessor_t* pre, type_t tau) {
410,866✔
126
  int_hmap_pair_t* rec = int_hmap_find(&pre->type_is_tuple_free_cache, tau);
410,866✔
127
  if (rec != NULL) {
410,866✔
128
    return rec->val != 0;
408,802✔
129
  }
130

131
  type_table_t* types = pre->terms->types;
2,064✔
132
  type_kind_t kind = type_kind(types, tau);
2,064✔
133
  uint32_t i;
134
  bool result;
135
  switch (kind) {
2,064✔
136
  case BOOL_TYPE:
1,819✔
137
  case INT_TYPE:
138
  case REAL_TYPE:
139
  case BITVECTOR_TYPE:
140
  case SCALAR_TYPE:
141
  case UNINTERPRETED_TYPE:
142
  case FF_TYPE:
143
    result = true;
1,819✔
144
    break;
1,819✔
145
  case TUPLE_TYPE:
42✔
146
    result = false;
42✔
147
    break;
42✔
148
  case FUNCTION_TYPE: {
203✔
149
    function_type_t* fun = function_type_desc(types, tau);
203✔
150
    result = type_is_tuple_free(pre, fun->range);
203✔
151
    for (i = 0; result && i < fun->ndom; ++i) {
473✔
152
      if (!type_is_tuple_free(pre, fun->domain[i])) {
270✔
153
        result = false;
3✔
154
      }
155
    }
156
    break;
203✔
157
  }
NEW
158
  default:
×
NEW
159
    result = false;
×
NEW
160
    break;
×
161
  }
162

163
  int_hmap_add(&pre->type_is_tuple_free_cache, tau, result ? 1 : 0);
2,064✔
164
  return result;
2,064✔
165
}
166

167
static
168
uint32_t type_leaf_count(preprocessor_t* pre, type_t tau) {
132✔
169
  int_hmap_pair_t* rec = int_hmap_find(&pre->type_leaf_count_cache, tau);
132✔
170
  if (rec != NULL) {
132✔
171
    return (uint32_t) rec->val;
60✔
172
  }
173

174
  type_table_t* types = pre->terms->types;
72✔
175
  tuple_type_t* tuple;
176
  uint32_t i, count;
177
  switch (type_kind(types, tau)) {
72✔
178
  case TUPLE_TYPE:
9✔
179
    tuple = tuple_type_desc(types, tau);
9✔
180
    count = 0;
9✔
181
    for (i = 0; i < tuple->nelem; ++i) {
27✔
182
      count += type_leaf_count(pre, tuple->elem[i]);
18✔
183
    }
184
    break;
9✔
185
  case FUNCTION_TYPE:
10✔
186
    count = type_leaf_count(pre, function_type_desc(types, tau)->range);
10✔
187
    break;
10✔
188
  default:
53✔
189
    count = 1;
53✔
190
    break;
53✔
191
  }
192

193
  int_hmap_add(&pre->type_leaf_count_cache, tau, (int32_t) count);
72✔
194
  return count;
72✔
195
}
196

197
static void function_type_collect_blasted(type_table_t* types, type_t tau, ivector_t* out);
198

199
static
200
void type_collect_flat(type_table_t* types, type_t tau, ivector_t* flat) {
210✔
201
  tuple_type_t* tuple;
202
  uint32_t i;
203

204
  switch (type_kind(types, tau)) {
210✔
205
  case TUPLE_TYPE:
65✔
206
    tuple = tuple_type_desc(types, tau);
65✔
207
    for (i = 0; i < tuple->nelem; ++i) {
198✔
208
      type_collect_flat(types, tuple->elem[i], flat);
133✔
209
    }
210
    break;
65✔
211

212
  case FUNCTION_TYPE:
11✔
213
    function_type_collect_blasted(types, tau, flat);
11✔
214
    break;
11✔
215

216
  default:
134✔
217
    ivector_push(flat, tau);
134✔
218
    break;
134✔
219
  }
220
}
210✔
221

222
static
223
void function_type_collect_blasted(type_table_t* types, type_t tau, ivector_t* out) {
20✔
224
  function_type_t* fun;
225
  ivector_t dom_flat;
226
  ivector_t codom_leaf;
227
  uint32_t i;
228

229
  assert(type_kind(types, tau) == FUNCTION_TYPE);
230
  fun = function_type_desc(types, tau);
20✔
231

232
  init_ivector(&dom_flat, 0);
20✔
233
  for (i = 0; i < fun->ndom; ++i) {
40✔
234
    type_collect_flat(types, fun->domain[i], &dom_flat);
20✔
235
  }
236

237
  init_ivector(&codom_leaf, 0);
20✔
238
  type_collect_flat(types, fun->range, &codom_leaf);
20✔
239
  for (i = 0; i < codom_leaf.size; ++i) {
57✔
240
    type_t ft = function_type(types, codom_leaf.data[i], dom_flat.size, (type_t*) dom_flat.data);
37✔
241
    ivector_push(out, ft);
37✔
242
  }
243

244
  delete_ivector(&codom_leaf);
20✔
245
  delete_ivector(&dom_flat);
20✔
246
}
20✔
247

248
static
249
void type_collect_blasted_atom_types(type_table_t* types, type_t tau, ivector_t* out) {
36✔
250
  switch (type_kind(types, tau)) {
36✔
251
  case TUPLE_TYPE:
32✔
252
    type_collect_flat(types, tau, out);
32✔
253
    break;
32✔
254
  case FUNCTION_TYPE:
4✔
255
    function_type_collect_blasted(types, tau, out);
4✔
256
    break;
4✔
NEW
257
  default:
×
NEW
258
    ivector_push(out, tau);
×
NEW
259
    break;
×
260
  }
261
}
36✔
262

263
static
264
int_hmap_pair_t* tuple_blast_find(preprocessor_t* pre, term_t t) {
81,788✔
265
  return int_hmap_find(&pre->tuple_blast_map, t);
81,788✔
266
}
267

268
static
269
bool tuple_blast_done(preprocessor_t* pre, term_t t) {
41,576✔
270
  return tuple_blast_find(pre, t) != NULL;
41,576✔
271
}
272

273
static
274
void tuple_blast_set(preprocessor_t* pre, term_t t, const ivector_t* terms) {
39,172✔
275
  int_hmap_pair_t* rec = int_hmap_get(&pre->tuple_blast_map, t);
39,172✔
276
  assert(rec->val < 0);
277
  rec->val = pre->tuple_blast_data.size;
39,172✔
278
  ivector_push(&pre->tuple_blast_data, terms->size);
39,172✔
279
  ivector_add(&pre->tuple_blast_data, terms->data, terms->size);
39,172✔
280
  ivector_push(&pre->tuple_blast_list, t);
39,172✔
281
}
39,172✔
282

283
static
284
void tuple_blast_get(preprocessor_t* pre, term_t t, ivector_t* out) {
39,888✔
285
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
39,888✔
286
  assert(rec != NULL);
287
  uint32_t offset = rec->val;
39,888✔
288
  uint32_t n = pre->tuple_blast_data.data[offset];
39,888✔
289
  ivector_reset(out);
39,888✔
290
  ivector_add(out, pre->tuple_blast_data.data + offset + 1, n);
39,888✔
291
}
39,888✔
292

293
/*
294
 * Zero-copy read of the blasted leaves for t. Returns pointers directly
295
 * into tuple_blast_data, so the caller MUST NOT hold the returned pointer
296
 * across any operation that can grow tuple_blast_data -- most notably a
297
 * subsequent tuple_blast_term call. Intended for read-only hot paths
298
 * (NOT, SELECT, EQ, ITE, DISTINCT, OR/XOR, POWER_PRODUCT, *_POLY,
299
 * generic-composite combine, tuple_blast_collect_arg) where the
300
 * ivector-based tuple_blast_get would pay a malloc + memcpy per sub-term.
301
 * Use tuple_blast_get when the snapshot must outlive a subsequent
302
 * tuple_blast_term call (APP, UPDATE, top-level substitution, model
303
 * reconstruction).
304
 */
305
static
306
void tuple_blast_peek(preprocessor_t* pre, term_t t, const term_t** data_out, uint32_t* n_out) {
324✔
307
  int_hmap_pair_t* rec = tuple_blast_find(pre, t);
324✔
308
  assert(rec != NULL);
309
  uint32_t offset = rec->val;
324✔
310
  *n_out = pre->tuple_blast_data.data[offset];
324✔
311
  *data_out = (const term_t*) (pre->tuple_blast_data.data + offset + 1);
324✔
312
}
324✔
313

314
static
315
void tuple_blast_term(preprocessor_t* pre, term_t t);
316
static
317
void tuple_blast_term_body(preprocessor_t* pre, term_t t);
318
static composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t);
319
static term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children);
320

321
/**
322
 * Collect the direct sub-terms of t that must be blasted before t can be
323
 * combined. The set returned here MUST cover every sub-term that
324
 * tuple_blast_term_body recursively blasts for kind(t); otherwise the
325
 * iterative driver tuple_blast_term will deadlock (children never blasted)
326
 * or compute a wrong combine.
327
 */
328
static
329
void tuple_blast_children(preprocessor_t* pre, term_t t, ivector_t* out) {
410,703✔
330
  if (is_neg_term(t)) {
410,703✔
331
    ivector_push(out, unsigned_term(t));
41,542✔
332
    return;
41,542✔
333
  }
334

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

472
/**
473
 * Memoized: does the DAG rooted at t contain any tuple type?
474
 * Walks the DAG iteratively so deep DAGs don't blow the C stack. The
475
 * answer is polarity-insensitive (cached per index_of(t)) and covers
476
 * t's own type plus the types of every reachable sub-term.
477
 */
478
static
479
bool term_has_tuples_in_subdag(preprocessor_t* pre, term_t t) {
39,431✔
480
  int32_t t_idx = index_of(t);
39,431✔
481
  int_hmap_pair_t* rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
39,431✔
482
  if (rec != NULL) {
39,431✔
483
    return rec->val != 0;
1,876✔
484
  }
485

486
  term_table_t* terms = pre->terms;
37,555✔
487
  ivector_t stack;
488
  init_ivector(&stack, 0);
37,555✔
489
  ivector_push(&stack, t);
37,555✔
490

491
  uint64_t safety = 0;
37,555✔
492
  while (stack.size > 0) {
520,280✔
493
    /* Hard upper bound: 2 * (term-table size) is a generous loose bound on
494
     * the number of distinct (term, polarity) revisits we should ever see
495
     * here. Aborting on overflow is far better than hanging a debug build. */
496
    assert(++safety < ((uint64_t) 1 << 28));
497
    (void) safety;
498

499
    term_t current = stack.data[stack.size - 1];
482,725✔
500
    int32_t cur_idx = index_of(current);
482,725✔
501
    int_hmap_pair_t* crec = int_hmap_find(&pre->term_has_tuples_cache, cur_idx);
482,725✔
502
    if (crec != NULL) {
482,725✔
503
      ivector_pop(&stack);
72,368✔
504
      continue;
197,429✔
505
    }
506

507
    if (!type_is_tuple_free(pre, term_type(terms, current))) {
410,357✔
508
      int_hmap_add(&pre->term_has_tuples_cache, cur_idx, 1);
89✔
509
      ivector_pop(&stack);
89✔
510
      continue;
89✔
511
    }
512

513
    ivector_t children;
514
    init_ivector(&children, 0);
410,268✔
515
    tuple_blast_children(pre, current, &children);
410,268✔
516
    bool any_true = false;
410,268✔
517
    bool all_done = true;
410,268✔
518
    for (uint32_t i = 0; i < children.size; ++i) {
1,362,301✔
519
      int32_t c_idx = index_of(children.data[i]);
952,033✔
520
      int_hmap_pair_t* crec2 = int_hmap_find(&pre->term_has_tuples_cache, c_idx);
952,033✔
521
      if (crec2 == NULL) {
952,033✔
522
        ivector_push(&stack, children.data[i]);
320,198✔
523
        all_done = false;
320,198✔
524
      } else if (crec2->val != 0) {
631,835✔
525
        any_true = true;
193✔
526
      }
527
    }
528
    delete_ivector(&children);
410,268✔
529
    if (!all_done) continue;
410,268✔
530

531
    int_hmap_add(&pre->term_has_tuples_cache, cur_idx, any_true ? 1 : 0);
285,296✔
532
    ivector_pop(&stack);
285,296✔
533
  }
534

535
  delete_ivector(&stack);
37,555✔
536

537
  rec = int_hmap_find(&pre->term_has_tuples_cache, t_idx);
37,555✔
538
  assert(rec != NULL);
539
  return rec->val != 0;
37,555✔
540
}
541

542
static
543
void tuple_blast_collect_arg(preprocessor_t* pre, term_t t, ivector_t* out) {
67✔
544
  const term_t* data;
545
  uint32_t n;
546
  tuple_blast_term(pre, t);
67✔
547
  /* Peek is safe here: we do not call tuple_blast_term between the peek
548
   * and the ivector_add below, so the backing tuple_blast_data cannot be
549
   * grown (and therefore cannot be reallocated) while `data` is live. */
550
  tuple_blast_peek(pre, t, &data, &n);
67✔
551
  ivector_add(out, (int32_t*) data, n);
67✔
552
}
67✔
553

554
static
555
term_t tuple_blast_eq_vector(term_manager_t* tm, const term_t* a, const term_t* b, uint32_t n) {
19✔
556
  assert(n > 0);
557
  if (n == 1) {
19✔
558
    return mk_eq(tm, a[0], b[0]);
2✔
559
  } else {
560
    ivector_t eqs;
561
    uint32_t i;
562
    init_ivector(&eqs, n);
17✔
563
    for (i = 0; i < n; ++i) {
52✔
564
      ivector_push(&eqs, mk_eq(tm, a[i], b[i]));
35✔
565
    }
566
    term_t result = mk_and(tm, eqs.size, eqs.data);
17✔
567
    delete_ivector(&eqs);
17✔
568
    return result;
17✔
569
  }
570
}
571

572
/*
573
 * Per-term combine. Computes blast(t) assuming the iterative driver
574
 * tuple_blast_term has already blasted every direct child returned by
575
 * tuple_blast_children. The recursive tuple_blast_term(pre, child) calls in
576
 * the body therefore bottom out at the early-return in the driver and do
577
 * not grow the C stack.
578
 */
579
static
580
void tuple_blast_term_body(preprocessor_t* pre, term_t t) {
263✔
581
  term_table_t* terms = pre->terms;
263✔
582
  type_table_t* types = terms->types;
263✔
583
  term_manager_t* tm = &pre->tm;
263✔
584

585
  if (tuple_blast_done(pre, t)) {
263✔
586
    return;
18✔
587
  }
588

589
  ivector_t result;
590
  init_ivector(&result, 0);
263✔
591

592
  if (is_neg_term(t)) {
263✔
593
    term_t c = unsigned_term(t);
18✔
594
    const term_t* c_data;
595
    uint32_t c_n;
596
    tuple_blast_term(pre, c);
18✔
597
    tuple_blast_peek(pre, c, &c_data, &c_n);
18✔
598
    if (c_n != 1) {
18✔
NEW
599
      delete_ivector(&result);
×
NEW
600
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
601
    }
602
    ivector_push(&result, opposite_term(c_data[0]));
18✔
603
    tuple_blast_set(pre, t, &result);
18✔
604
    delete_ivector(&result);
18✔
605
    return;
18✔
606
  }
607

608
  term_kind_t kind = term_kind(terms, t);
245✔
609
  type_t tau = term_type(terms, t);
245✔
610
  switch (kind) {
245✔
NEW
611
  case CONSTANT_TERM:
×
612
  case ARITH_CONSTANT:
613
  case ARITH_FF_CONSTANT:
614
  case BV64_CONSTANT:
615
  case BV_CONSTANT:
NEW
616
    ivector_push(&result, t);
×
NEW
617
    break;
×
618

619
  case UNINTERPRETED_TERM:
36✔
620
  case VARIABLE: {
621
    if (type_is_tuple_free(pre, tau)) {
36✔
NEW
622
      ivector_push(&result, t);
×
623
    } else {
624
      ivector_t atom_types;
625
      uint32_t i;
626
      init_ivector(&atom_types, 0);
36✔
627
      type_collect_blasted_atom_types(types, tau, &atom_types);
36✔
628
      for (i = 0; i < atom_types.size; ++i) {
120✔
629
        term_t v = new_uninterpreted_term(terms, atom_types.data[i]);
84✔
630
        ivector_push(&result, v);
84✔
631
      }
632
      ivector_push(&pre->tuple_blast_atoms, t);
36✔
633
      delete_ivector(&atom_types);
36✔
634
    }
635
    break;
36✔
636
  }
637

638
  case TUPLE_TERM: {
27✔
639
    composite_term_t* tuple = tuple_term_desc(terms, t);
27✔
640
    uint32_t i;
641
    for (i = 0; i < tuple->arity; ++i) {
81✔
642
      tuple_blast_collect_arg(pre, tuple->arg[i], &result);
54✔
643
    }
644
    break;
27✔
645
  }
646

647
  case SELECT_TERM: {
67✔
648
    select_term_t* sel = select_term_desc(terms, t);
67✔
649
    const term_t* arg_data;
650
    uint32_t arg_n;
651
    tuple_type_t* tuple_type;
652
    uint32_t i, start, len;
653
    type_t arg_type = term_type(terms, sel->arg);
67✔
654
    if (type_kind(types, arg_type) != TUPLE_TYPE) {
67✔
NEW
655
      delete_ivector(&result);
×
NEW
656
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
657
    }
658
    tuple_blast_term(pre, sel->arg);
67✔
659
    tuple_blast_peek(pre, sel->arg, &arg_data, &arg_n);
67✔
660
    tuple_type = tuple_type_desc(types, arg_type);
67✔
661
    start = 0;
67✔
662
    for (i = 0; i < sel->idx; ++i) {
101✔
663
      start += type_leaf_count(pre, tuple_type->elem[i]);
34✔
664
    }
665
    len = type_leaf_count(pre, tuple_type->elem[sel->idx]);
67✔
666
    if (start + len > arg_n) {
67✔
NEW
667
      delete_ivector(&result);
×
NEW
668
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
669
    }
670
    ivector_add(&result, (int32_t*) (arg_data + start), len);
67✔
671
    break;
67✔
672
  }
673

674
  case EQ_TERM: {
19✔
675
    composite_term_t* eq = eq_term_desc(terms, t);
19✔
676
    const term_t *lhs, *rhs;
677
    uint32_t lhs_n, rhs_n;
678
    /* Both tuple_blast_term calls precede both peeks; tuple_blast_eq_vector
679
     * and ivector_push do not grow tuple_blast_data, so the peeked
680
     * pointers stay live for the duration of this block. */
681
    tuple_blast_term(pre, eq->arg[0]);
19✔
682
    tuple_blast_term(pre, eq->arg[1]);
19✔
683
    tuple_blast_peek(pre, eq->arg[0], &lhs, &lhs_n);
19✔
684
    tuple_blast_peek(pre, eq->arg[1], &rhs, &rhs_n);
19✔
685
    if (lhs_n != rhs_n || lhs_n == 0) {
19✔
NEW
686
      delete_ivector(&result);
×
NEW
687
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
688
    }
689
    ivector_push(&result, tuple_blast_eq_vector(tm, lhs, rhs, lhs_n));
19✔
690
    break;
19✔
691
  }
692

NEW
693
  case DISTINCT_TERM: {
×
NEW
694
    composite_term_t* d = distinct_term_desc(terms, t);
×
695
    ivector_t conjuncts;
696
    uint32_t i, j;
NEW
697
    init_ivector(&conjuncts, 0);
×
NEW
698
    for (i = 0; i < d->arity; ++i) {
×
NEW
699
      for (j = i + 1; j < d->arity; ++j) {
×
700
        const term_t *ti_data, *tj_data;
701
        uint32_t ti_n, tj_n;
702
        ivector_t disj;
703
        uint32_t k;
704
        /* Both tuple_blast_term calls complete before the peeks; after
705
         * the peeks we only call mk_eq / opposite_term / mk_or and push
706
         * into local ivectors, none of which grow tuple_blast_data. */
NEW
707
        tuple_blast_term(pre, d->arg[i]);
×
NEW
708
        tuple_blast_term(pre, d->arg[j]);
×
NEW
709
        tuple_blast_peek(pre, d->arg[i], &ti_data, &ti_n);
×
NEW
710
        tuple_blast_peek(pre, d->arg[j], &tj_data, &tj_n);
×
NEW
711
        if (ti_n != tj_n || ti_n == 0) {
×
NEW
712
          delete_ivector(&conjuncts);
×
NEW
713
          delete_ivector(&result);
×
NEW
714
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
715
        }
NEW
716
        init_ivector(&disj, ti_n);
×
NEW
717
        for (k = 0; k < ti_n; ++k) {
×
NEW
718
          ivector_push(&disj, opposite_term(mk_eq(tm, ti_data[k], tj_data[k])));
×
719
        }
NEW
720
        ivector_push(&conjuncts, mk_or(tm, disj.size, disj.data));
×
NEW
721
        delete_ivector(&disj);
×
722
      }
723
    }
NEW
724
    ivector_push(&result, mk_and(tm, conjuncts.size, conjuncts.data));
×
NEW
725
    delete_ivector(&conjuncts);
×
NEW
726
    break;
×
727
  }
728

729
  case ITE_TERM:
3✔
730
  case ITE_SPECIAL: {
731
    composite_term_t* ite = ite_term_desc(terms, t);
3✔
732
    const term_t *c_data, *t_data, *e_data;
733
    uint32_t c_n, t_n, e_n;
734
    uint32_t i;
735
    /* All three tuple_blast_term calls complete before any peek, so the
736
     * peeked pointers remain valid for the rest of this block: the only
737
     * calls after the peeks are term-manager operations (super_type,
738
     * term_type, mk_ite) plus ivector_push(&result, ...), none of which
739
     * grow tuple_blast_data. */
740
    tuple_blast_term(pre, ite->arg[0]);
3✔
741
    tuple_blast_term(pre, ite->arg[1]);
3✔
742
    tuple_blast_term(pre, ite->arg[2]);
3✔
743
    tuple_blast_peek(pre, ite->arg[0], &c_data, &c_n);
3✔
744
    tuple_blast_peek(pre, ite->arg[1], &t_data, &t_n);
3✔
745
    tuple_blast_peek(pre, ite->arg[2], &e_data, &e_n);
3✔
746
    if (c_n != 1 || t_n != e_n || t_n == 0) {
3✔
NEW
747
      delete_ivector(&result);
×
NEW
748
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
749
    }
750
    for (i = 0; i < t_n; ++i) {
10✔
751
      type_t ty = super_type(types, term_type(terms, t_data[i]), term_type(terms, e_data[i]));
7✔
752
      if (ty == NULL_TYPE) {
7✔
NEW
753
        delete_ivector(&result);
×
NEW
754
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
755
      }
756
      ivector_push(&result, mk_ite(tm, c_data[0], t_data[i], e_data[i], ty));
7✔
757
    }
758
    if (result.size == 1 &&
3✔
NEW
759
        c_data[0] == ite->arg[0] &&
×
NEW
760
        t_data[0] == ite->arg[1] &&
×
NEW
761
        e_data[0] == ite->arg[2]) {
×
NEW
762
      ivector_reset(&result);
×
NEW
763
      ivector_push(&result, t);
×
764
    }
765
    break;
3✔
766
  }
767

768
  case APP_TERM: {
13✔
769
    composite_term_t* app = app_term_desc(terms, t);
13✔
770
    ivector_t f_blast;
771
    ivector_t args_flat;
772
    uint32_t i;
773
    bool changed;
774
    tuple_blast_term(pre, app->arg[0]);
13✔
775
    init_ivector(&f_blast, 0);
13✔
776
    tuple_blast_get(pre, app->arg[0], &f_blast);
13✔
777
    init_ivector(&args_flat, 0);
13✔
778
    for (i = 1; i < app->arity; ++i) {
26✔
779
      tuple_blast_collect_arg(pre, app->arg[i], &args_flat);
13✔
780
    }
781
    changed = f_blast.size != 1 || f_blast.data[0] != app->arg[0] || args_flat.size != app->arity - 1;
13✔
782
    for (i = 1; !changed && i < app->arity; ++i) {
13✔
NEW
783
      changed = args_flat.data[i - 1] != app->arg[i];
×
784
    }
785
    if (!changed) {
13✔
NEW
786
      ivector_push(&result, t);
×
NEW
787
      delete_ivector(&args_flat);
×
NEW
788
      delete_ivector(&f_blast);
×
NEW
789
      break;
×
790
    }
791
    for (i = 0; i < f_blast.size; ++i) {
37✔
792
      term_t app_i = mk_application(tm, f_blast.data[i], args_flat.size, args_flat.data);
24✔
793
      if (app_i == NULL_TERM) {
24✔
NEW
794
        delete_ivector(&args_flat);
×
NEW
795
        delete_ivector(&f_blast);
×
NEW
796
        delete_ivector(&result);
×
NEW
797
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
798
      }
799
      ivector_push(&result, app_i);
24✔
800
    }
801
    delete_ivector(&args_flat);
13✔
802
    delete_ivector(&f_blast);
13✔
803
    break;
13✔
804
  }
805

NEW
806
  case UPDATE_TERM: {
×
NEW
807
    composite_term_t* upd = update_term_desc(terms, t);
×
808
    ivector_t f_blast;
809
    ivector_t idx_flat;
810
    ivector_t v_blast;
811
    uint32_t i;
812
    bool changed;
NEW
813
    tuple_blast_term(pre, upd->arg[0]);
×
NEW
814
    init_ivector(&f_blast, 0);
×
NEW
815
    tuple_blast_get(pre, upd->arg[0], &f_blast);
×
NEW
816
    init_ivector(&idx_flat, 0);
×
NEW
817
    for (i = 1; i + 1 < upd->arity; ++i) {
×
NEW
818
      tuple_blast_collect_arg(pre, upd->arg[i], &idx_flat);
×
819
    }
NEW
820
    tuple_blast_term(pre, upd->arg[upd->arity - 1]);
×
NEW
821
    init_ivector(&v_blast, 0);
×
NEW
822
    tuple_blast_get(pre, upd->arg[upd->arity - 1], &v_blast);
×
NEW
823
    if (v_blast.size != 1 && v_blast.size != f_blast.size) {
×
NEW
824
      delete_ivector(&f_blast);
×
NEW
825
      delete_ivector(&idx_flat);
×
NEW
826
      delete_ivector(&v_blast);
×
NEW
827
      delete_ivector(&result);
×
NEW
828
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
829
    }
NEW
830
    changed = f_blast.size != 1 || f_blast.data[0] != upd->arg[0] || idx_flat.size != upd->arity - 2 ||
×
NEW
831
              v_blast.size != 1 || v_blast.data[0] != upd->arg[upd->arity - 1];
×
NEW
832
    for (i = 1; !changed && i + 1 < upd->arity; ++i) {
×
NEW
833
      changed = idx_flat.data[i - 1] != upd->arg[i];
×
834
    }
NEW
835
    if (!changed) {
×
NEW
836
      ivector_push(&result, t);
×
NEW
837
      delete_ivector(&f_blast);
×
NEW
838
      delete_ivector(&idx_flat);
×
NEW
839
      delete_ivector(&v_blast);
×
NEW
840
      break;
×
841
    }
NEW
842
    for (i = 0; i < f_blast.size; ++i) {
×
NEW
843
      term_t vi = v_blast.size == 1 ? v_blast.data[0] : v_blast.data[i];
×
NEW
844
      term_t upd_i = mk_update(tm, f_blast.data[i], idx_flat.size, idx_flat.data, vi);
×
NEW
845
      if (upd_i == NULL_TERM) {
×
NEW
846
        delete_ivector(&f_blast);
×
NEW
847
        delete_ivector(&idx_flat);
×
NEW
848
        delete_ivector(&v_blast);
×
NEW
849
        delete_ivector(&result);
×
NEW
850
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
851
      }
NEW
852
      ivector_push(&result, upd_i);
×
853
    }
NEW
854
    delete_ivector(&f_blast);
×
NEW
855
    delete_ivector(&idx_flat);
×
NEW
856
    delete_ivector(&v_blast);
×
NEW
857
    break;
×
858
  }
859

860
  case OR_TERM:
4✔
861
  case XOR_TERM: {
862
    composite_term_t* c = (kind == OR_TERM) ? or_term_desc(terms, t) : xor_term_desc(terms, t);
4✔
863
    ivector_t args;
864
    uint32_t i;
865
    init_ivector(&args, c->arity);
4✔
866
    for (i = 0; i < c->arity; ++i) {
12✔
867
      const term_t* child_data;
868
      uint32_t child_n;
869
      tuple_blast_term(pre, c->arg[i]);
8✔
870
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
8✔
871
      if (child_n != 1) {
8✔
NEW
872
        delete_ivector(&args);
×
NEW
873
        delete_ivector(&result);
×
NEW
874
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
875
      }
876
      ivector_push(&args, child_data[0]);
8✔
877
    }
878
    ivector_push(&result, kind == OR_TERM ? mk_or(tm, args.size, args.data) : mk_xor(tm, args.size, args.data));
4✔
879
    delete_ivector(&args);
4✔
880
    break;
4✔
881
  }
882

883
  case POWER_PRODUCT: {
2✔
884
    pprod_t* pp = pprod_term_desc(terms, t);
2✔
885
    term_t args[pp->len];
2✔
886
    uint32_t i;
887
    bool changed = false;
2✔
888

889
    for (i = 0; i < pp->len; ++i) {
6✔
890
      const term_t* child_data;
891
      uint32_t child_n;
892
      tuple_blast_term(pre, pp->prod[i].var);
4✔
893
      tuple_blast_peek(pre, pp->prod[i].var, &child_data, &child_n);
4✔
894
      if (child_n != 1) {
4✔
NEW
895
        delete_ivector(&result);
×
NEW
896
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
897
      }
898
      args[i] = child_data[0];
4✔
899
      changed |= args[i] != pp->prod[i].var;
4✔
900
    }
901
    ivector_push(&result, changed ? mk_pprod(tm, pp, pp->len, args) : t);
2✔
902
    break;
2✔
903
  }
904

905
  case ARITH_POLY: {
15✔
906
    polynomial_t* p = poly_term_desc(terms, t);
15✔
907
    term_t args[p->nterms];
15✔
908
    uint32_t i;
909
    bool changed = false;
15✔
910

911
    for (i = 0; i < p->nterms; ++i) {
47✔
912
      term_t x = p->mono[i].var;
32✔
913
      if (x == const_idx) {
32✔
914
        args[i] = const_idx;
13✔
915
      } else {
916
        const term_t* child_data;
917
        uint32_t child_n;
918
        tuple_blast_term(pre, x);
19✔
919
        tuple_blast_peek(pre, x, &child_data, &child_n);
19✔
920
        if (child_n != 1) {
19✔
NEW
921
          delete_ivector(&result);
×
NEW
922
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
923
        }
924
        args[i] = child_data[0];
19✔
925
        changed |= args[i] != x;
19✔
926
      }
927
    }
928
    ivector_push(&result, changed ? mk_arith_poly(tm, p, p->nterms, args) : t);
15✔
929
    break;
15✔
930
  }
931

NEW
932
  case ARITH_FF_POLY: {
×
NEW
933
    polynomial_t* p = finitefield_poly_term_desc(terms, t);
×
NEW
934
    const rational_t* mod = finitefield_term_order(terms, t);
×
NEW
935
    term_t args[p->nterms];
×
936
    uint32_t i;
NEW
937
    bool changed = false;
×
938

NEW
939
    for (i = 0; i < p->nterms; ++i) {
×
NEW
940
      term_t x = p->mono[i].var;
×
NEW
941
      if (x == const_idx) {
×
NEW
942
        args[i] = const_idx;
×
943
      } else {
944
        const term_t* child_data;
945
        uint32_t child_n;
NEW
946
        tuple_blast_term(pre, x);
×
NEW
947
        tuple_blast_peek(pre, x, &child_data, &child_n);
×
NEW
948
        if (child_n != 1) {
×
NEW
949
          delete_ivector(&result);
×
NEW
950
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
951
        }
NEW
952
        args[i] = child_data[0];
×
NEW
953
        changed |= args[i] != x;
×
954
      }
955
    }
NEW
956
    ivector_push(&result, changed ? mk_arith_ff_poly(tm, p, p->nterms, args, mod) : t);
×
NEW
957
    break;
×
958
  }
959

960
  case BV64_POLY: {
2✔
961
    bvpoly64_t* p = bvpoly64_term_desc(terms, t);
2✔
962
    term_t args[p->nterms];
2✔
963
    uint32_t i;
964
    bool changed = false;
2✔
965

966
    for (i = 0; i < p->nterms; ++i) {
6✔
967
      term_t x = p->mono[i].var;
4✔
968
      if (x == const_idx) {
4✔
969
        args[i] = const_idx;
2✔
970
      } else {
971
        const term_t* child_data;
972
        uint32_t child_n;
973
        tuple_blast_term(pre, x);
2✔
974
        tuple_blast_peek(pre, x, &child_data, &child_n);
2✔
975
        if (child_n != 1) {
2✔
NEW
976
          delete_ivector(&result);
×
NEW
977
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
978
        }
979
        args[i] = child_data[0];
2✔
980
        changed |= args[i] != x;
2✔
981
      }
982
    }
983
    ivector_push(&result, changed ? mk_bvarith64_poly(tm, p, p->nterms, args) : t);
2✔
984
    break;
2✔
985
  }
986

NEW
987
  case BV_POLY: {
×
NEW
988
    bvpoly_t* p = bvpoly_term_desc(terms, t);
×
NEW
989
    term_t args[p->nterms];
×
990
    uint32_t i;
NEW
991
    bool changed = false;
×
992

NEW
993
    for (i = 0; i < p->nterms; ++i) {
×
NEW
994
      term_t x = p->mono[i].var;
×
NEW
995
      if (x == const_idx) {
×
NEW
996
        args[i] = const_idx;
×
997
      } else {
998
        const term_t* child_data;
999
        uint32_t child_n;
NEW
1000
        tuple_blast_term(pre, x);
×
NEW
1001
        tuple_blast_peek(pre, x, &child_data, &child_n);
×
NEW
1002
        if (child_n != 1) {
×
NEW
1003
          delete_ivector(&result);
×
NEW
1004
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1005
        }
NEW
1006
        args[i] = child_data[0];
×
NEW
1007
        changed |= args[i] != x;
×
1008
      }
1009
    }
NEW
1010
    ivector_push(&result, changed ? mk_bvarith_poly(tm, p, p->nterms, args) : t);
×
NEW
1011
    break;
×
1012
  }
1013

1014
  case ARITH_EQ_ATOM:
49✔
1015
  case ARITH_GE_ATOM:
1016
  case ARITH_BINEQ_ATOM:
1017
  case ARITH_RDIV:
1018
  case ARITH_IDIV:
1019
  case ARITH_MOD:
1020
  case BV_ARRAY:
1021
  case BV_DIV:
1022
  case BV_REM:
1023
  case BV_SDIV:
1024
  case BV_SREM:
1025
  case BV_SMOD:
1026
  case BV_SHL:
1027
  case BV_LSHR:
1028
  case BV_ASHR:
1029
  case BV_EQ_ATOM:
1030
  case BV_GE_ATOM:
1031
  case BV_SGE_ATOM: {
49✔
1032
    composite_term_t* c = get_composite(terms, kind, t);
49✔
1033
    term_t args[c->arity];
49✔
1034
    uint32_t i;
1035
    bool changed = false;
49✔
1036

1037
    for (i = 0; i < c->arity; ++i) {
133✔
1038
      const term_t* child_data;
1039
      uint32_t child_n;
1040
      tuple_blast_term(pre, c->arg[i]);
84✔
1041
      tuple_blast_peek(pre, c->arg[i], &child_data, &child_n);
84✔
1042
      if (child_n != 1) {
84✔
NEW
1043
        delete_ivector(&result);
×
NEW
1044
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1045
      }
1046
      args[i] = child_data[0];
84✔
1047
      changed |= args[i] != c->arg[i];
84✔
1048
    }
1049

1050
    term_t rebuilt = changed ? mk_composite(pre, kind, c->arity, args) : t;
49✔
1051
    if (rebuilt == NULL_TERM) {
49✔
NEW
1052
      delete_ivector(&result);
×
NEW
1053
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1054
    }
1055
    ivector_push(&result, rebuilt);
49✔
1056
    break;
49✔
1057
  }
1058

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

NEW
1172
  default:
×
NEW
1173
    ivector_push(&result, t);
×
NEW
1174
    break;
×
1175
  }
1176

1177
  tuple_blast_set(pre, t, &result);
245✔
1178
  delete_ivector(&result);
245✔
1179
}
1180

1181
/*
1182
 * Iterative bottom-up driver for tuple-blasting.
1183
 *  - C stack depth is O(1) regardless of input DAG depth (M4).
1184
 *  - Sub-DAGs that contain no tuple type anywhere are identity-blasted in
1185
 *    one step without descending into them, using the memoized
1186
 *    term_has_tuples_in_subdag (M3).
1187
 *  - For each not-yet-blasted term on the work stack we either (a) push
1188
 *    its un-blasted children, or (b) all children are blasted and we run
1189
 *    tuple_blast_term_body once. Children come from tuple_blast_children
1190
 *    which mirrors exactly the recursive descent in tuple_blast_term_body.
1191
 */
1192
static
1193
void tuple_blast_term(preprocessor_t* pre, term_t t) {
40,189✔
1194
  if (tuple_blast_done(pre, t)) {
40,189✔
1195
    return;
40,102✔
1196
  }
1197

1198
  if (!term_has_tuples_in_subdag(pre, t)) {
38,919✔
1199
    ivector_t result;
1200
    init_ivector(&result, 0);
38,832✔
1201
    ivector_push(&result, t);
38,832✔
1202
    tuple_blast_set(pre, t, &result);
38,832✔
1203
    delete_ivector(&result);
38,832✔
1204
    return;
38,832✔
1205
  }
1206

1207
  ivector_t stack;
1208
  init_ivector(&stack, 0);
87✔
1209
  ivector_push(&stack, t);
87✔
1210

1211
  uint64_t safety = 0;
87✔
1212
  while (stack.size > 0) {
600✔
1213
    /* Defensive bound. Real workloads visit each term O(1) times; 2^28
1214
     * iterations is far more than any reachable DAG should ever need. */
1215
    assert(++safety < ((uint64_t) 1 << 28));
1216
    (void) safety;
1217

1218
    term_t current = stack.data[stack.size - 1];
513✔
1219

1220
    if (tuple_blast_done(pre, current)) {
513✔
1221
      ivector_pop(&stack);
1✔
1222
      continue;
250✔
1223
    }
1224

1225
    if (!term_has_tuples_in_subdag(pre, current)) {
512✔
1226
      ivector_t result;
1227
      init_ivector(&result, 0);
77✔
1228
      ivector_push(&result, current);
77✔
1229
      tuple_blast_set(pre, current, &result);
77✔
1230
      delete_ivector(&result);
77✔
1231
      ivector_pop(&stack);
77✔
1232
      continue;
77✔
1233
    }
1234

1235
    ivector_t children;
1236
    init_ivector(&children, 0);
435✔
1237
    tuple_blast_children(pre, current, &children);
435✔
1238
    bool all_done = true;
435✔
1239
    for (uint32_t i = 0; i < children.size; ++i) {
1,046✔
1240
      if (!tuple_blast_done(pre, children.data[i])) {
611✔
1241
        ivector_push(&stack, children.data[i]);
254✔
1242
        all_done = false;
254✔
1243
      }
1244
    }
1245
    delete_ivector(&children);
435✔
1246
    if (!all_done) continue;
435✔
1247

1248
    tuple_blast_term_body(pre, current);
263✔
1249
    ivector_pop(&stack);
263✔
1250
  }
1251

1252
  delete_ivector(&stack);
87✔
1253
}
1254

1255
typedef struct composite_term1_s {
1256
  uint32_t arity;  // number of subterms
1257
  term_t arg[1];  // real size = arity
1258
} composite_term1_t;
1259

1260
static
1261
composite_term1_t composite_for_noncomposite;
1262

1263
static
1264
composite_term_t* get_composite(term_table_t* terms, term_kind_t kind, term_t t) {
306,484✔
1265
  assert(term_is_composite(terms, t));
1266
  assert(term_kind(terms, t) == kind);
1267
  assert(is_pos_term(t));
1268

1269
  switch (kind) {
306,484✔
1270
  case ITE_TERM:           // if-then-else
20,874✔
1271
  case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1272
    return ite_term_desc(terms, t);
20,874✔
1273
  case EQ_TERM:            // equality
20,747✔
1274
    return eq_term_desc(terms, t);
20,747✔
1275
  case OR_TERM:            // n-ary OR
62,216✔
1276
    return or_term_desc(terms, t);
62,216✔
1277
  case XOR_TERM:           // n-ary XOR
30✔
1278
    return xor_term_desc(terms, t);
30✔
1279
  case ARITH_BINEQ_ATOM:   // equality: (t1 == t2)  (between two arithmetic terms)
7,902✔
1280
    return arith_bineq_atom_desc(terms, t);
7,902✔
1281
  case ARITH_EQ_ATOM: {
7,272✔
1282
    composite_for_noncomposite.arity = 1;
7,272✔
1283
    composite_for_noncomposite.arg[0] = arith_eq_arg(terms, t);
7,272✔
1284
    return (composite_term_t*)&composite_for_noncomposite;
7,272✔
1285
  }
1286
  case ARITH_GE_ATOM: {
16,242✔
1287
    composite_for_noncomposite.arity = 1;
16,242✔
1288
    composite_for_noncomposite.arg[0] = arith_ge_arg(terms, t);
16,242✔
1289
    return (composite_term_t*)&composite_for_noncomposite;
16,242✔
1290
  }
1291
  case ARITH_FF_BINEQ_ATOM:
12✔
1292
    return arith_ff_bineq_atom_desc(terms, t);
12✔
1293
  case ARITH_FF_EQ_ATOM: {
155✔
1294
    composite_for_noncomposite.arity = 1;
155✔
1295
    composite_for_noncomposite.arg[0] = arith_ff_eq_arg(terms, t);
155✔
1296
    return (composite_term_t*)&composite_for_noncomposite;
155✔
1297
  }
1298
  case APP_TERM:           // application of an uninterpreted function
5,841✔
1299
    return app_term_desc(terms, t);
5,841✔
1300
  case ARITH_RDIV:          // division: (/ x y)
116✔
1301
    return arith_rdiv_term_desc(terms, t);
116✔
1302
  case ARITH_IDIV:          // division: (div x y) as defined in SMT-LIB 2
178✔
1303
    return arith_idiv_term_desc(terms, t);
178✔
1304
  case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
296✔
1305
    return arith_mod_term_desc(terms, t);
296✔
1306
  case UPDATE_TERM:
2,501✔
1307
    return update_term_desc(terms, t);
2,501✔
1308
  case DISTINCT_TERM:
27✔
1309
    return distinct_term_desc(terms, t);
27✔
1310
  case BV_ARRAY:
34,821✔
1311
    return bvarray_term_desc(terms, t);
34,821✔
1312
  case BV_DIV:
186✔
1313
    return bvdiv_term_desc(terms, t);
186✔
1314
  case BV_REM:
424✔
1315
    return bvrem_term_desc(terms, t);
424✔
1316
  case BV_SDIV:
40✔
1317
    return bvsdiv_term_desc(terms, t);
40✔
1318
  case BV_SREM:
42✔
1319
    return bvsrem_term_desc(terms, t);
42✔
1320
  case BV_SMOD:
12✔
1321
    return bvsmod_term_desc(terms, t);
12✔
1322
  case BV_SHL:
286✔
1323
    return bvshl_term_desc(terms, t);
286✔
1324
  case BV_LSHR:
558✔
1325
    return bvlshr_term_desc(terms, t);
558✔
1326
  case BV_ASHR:
42✔
1327
    return bvashr_term_desc(terms, t);
42✔
1328
  case BV_EQ_ATOM:
118,830✔
1329
    return bveq_atom_desc(terms, t);
118,830✔
1330
  case BV_GE_ATOM:
5,550✔
1331
    return bvge_atom_desc(terms, t);
5,550✔
1332
  case BV_SGE_ATOM:
1,284✔
1333
    return bvsge_atom_desc(terms, t);
1,284✔
1334
  default:
×
1335
    assert(false);
1336
    return NULL;
×
1337
  }
1338
}
1339

1340
static bool type_needs_function_diseq_guard(type_table_t* types, type_t tau) {
24,784✔
1341
  uint32_t i, n;
1342

1343
  switch (type_kind(types, tau)) {
24,784✔
1344
  case FUNCTION_TYPE:
1,977✔
1345
    if (type_has_finite_domain(types, tau) ||
3,944✔
1346
        is_unit_type(types, function_type_range(types, tau))) {
1,967✔
1347
      return true;
11✔
1348
    }
1349

1350
    n = function_type_arity(types, tau);
1,966✔
1351
    for (i = 0; i < n; ++ i) {
3,936✔
1352
      if (type_needs_function_diseq_guard(types, function_type_domain(types, tau, i))) {
1,972✔
1353
        return true;
2✔
1354
      }
1355
    }
1356

1357
    return type_needs_function_diseq_guard(types, function_type_range(types, tau));
1,964✔
1358

1359
  case TUPLE_TYPE:
×
1360
    n = tuple_type_arity(types, tau);
×
1361
    for (i = 0; i < n; ++ i) {
×
1362
      if (type_needs_function_diseq_guard(types, tuple_type_component(types, tau, i))) {
×
1363
        return true;
×
1364
      }
1365
    }
1366
    return false;
×
1367

1368
  case INSTANCE_TYPE:
×
1369
    n = instance_type_arity(types, tau);
×
1370
    for (i = 0; i < n; ++ i) {
×
1371
      if (type_needs_function_diseq_guard(types, instance_type_param(types, tau, i))) {
×
1372
        return true;
×
1373
      }
1374
    }
1375
    return false;
×
1376

1377
  default:
22,807✔
1378
    return false;
22,807✔
1379
  }
1380
}
1381

1382
static bool term_needs_function_diseq_guard(term_table_t* terms, term_t t) {
20,848✔
1383
  return type_needs_function_diseq_guard(terms->types, term_type(terms, t));
20,848✔
1384
}
1385

1386
static
1387
term_t mk_composite(preprocessor_t* pre, term_kind_t kind, uint32_t n, term_t* children) {
46,631✔
1388
  term_manager_t* tm = &pre->tm;
46,631✔
1389
  term_table_t* terms = pre->terms;
46,631✔
1390

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

1474
/**
1475
 * Returns purified version of t if we should purify t as an argument of a function.
1476
 * Any new equalities are added to output.
1477
 */
1478
static inline
1479
term_t preprocessor_purify(preprocessor_t* pre, term_t t, ivector_t* out) {
52,847✔
1480

1481
  term_table_t* terms = pre->terms;
52,847✔
1482

1483
  // Negated terms must be purified
1484
  if (is_pos_term(t)) {
52,847✔
1485
    // We don't purify variables
1486
    switch (term_kind(terms, t)) {
17,081✔
1487
    case UNINTERPRETED_TERM:
10,825✔
1488
      // Variables are already pure
1489
      return t;
10,825✔
1490
    case CONSTANT_TERM:
15✔
1491
      return t;
15✔
1492
    case ARITH_CONSTANT:
1,700✔
1493
    case ARITH_FF_CONSTANT:
1494
    case BV64_CONSTANT:
1495
    case BV_CONSTANT:
1496
      // Constants are also pure (except for false)
1497
      return t;
1,700✔
1498
    case APP_TERM:
1,685✔
1499
      // Uninterpreted functions are also already purified
1500
      return t;
1,685✔
1501
    case UPDATE_TERM:
1,680✔
1502
      return t;
1,680✔
1503
    default:
1,176✔
1504
      break;
1,176✔
1505
    }
1506
  }
1507

1508
  // Everything else gets purified. Check if in the cache
1509
  int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
36,942✔
1510
  if (find != NULL) {
36,942✔
1511
    return find->val;
36,376✔
1512
  } else {
1513
    // Make the variable
1514
    type_t t_type = term_type(terms, t);
566✔
1515
    term_t x = new_uninterpreted_term(terms, t_type);
566✔
1516
    // Remember for later
1517
    int_hmap_add(&pre->purification_map, t, x);
566✔
1518
    ivector_push(&pre->purification_map_list, t);
566✔
1519
    // Also add the variable to the pre-processor
1520
    preprocessor_set(pre, x, x);
566✔
1521
    // Add equality to output
1522
    term_t eq = mk_eq(&pre->tm, x, t);
566✔
1523
    ivector_push(out, eq);
566✔
1524

1525
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
566✔
1526
      mcsat_trace_printf(pre->tracer, "adding lemma = ");
×
1527
      trace_term_ln(pre->tracer, terms, eq);
×
1528
    }
1529

1530
    // Return the purified version
1531
    return x;
566✔
1532
  }
1533
}
1534

1535
static inline
1536
term_t mk_bvneg(term_manager_t* tm, term_t t) {
92✔
1537
  term_table_t* terms = tm->terms;
92✔
1538
  if (term_bitsize(terms,t) <= 64) {
92✔
1539
    bvarith64_buffer_t *buffer = term_manager_get_bvarith64_buffer(tm);
76✔
1540
    bvarith64_buffer_set_term(buffer, terms, t);
76✔
1541
    bvarith64_buffer_negate(buffer);
76✔
1542
    return mk_bvarith64_term(tm, buffer);
76✔
1543
  } else {
1544
    bvarith_buffer_t *buffer = term_manager_get_bvarith_buffer(tm);
16✔
1545
    bvarith_buffer_set_term(buffer, terms, t);
16✔
1546
    bvarith_buffer_negate(buffer);
16✔
1547
    return mk_bvarith_term(tm, buffer);
16✔
1548
  }
1549
}
1550

1551
// Mark equality eq: (var = t) for solving
1552
static
1553
void preprocessor_mark_eq(preprocessor_t* pre, term_t eq, term_t var) {
24,867✔
1554
  assert(is_pos_term(eq));
1555
  assert(is_pos_term(var));
1556
  assert(term_kind(pre->terms, var) == UNINTERPRETED_TERM);
1557

1558
  // Mark the equality
1559
  int_hmap_pair_t* find = int_hmap_get(&pre->equalities, eq);
24,867✔
1560
  assert(find->val == -1);
1561
  find->val = var;
24,867✔
1562
  ivector_push(&pre->equalities_list, eq);
24,867✔
1563
}
24,867✔
1564

1565
static
1566
term_t preprocessor_get_eq_solved_var(const preprocessor_t* pre, term_t eq) {
47,701✔
1567
  assert(is_pos_term(eq));
1568
  int_hmap_pair_t* find = int_hmap_find((int_hmap_t*) &pre->equalities, eq);
47,701✔
1569
  if (find != NULL) {
47,701✔
1570
    return find->val;
20,003✔
1571
  } else {
1572
    return NULL_TERM;
27,698✔
1573
  }
1574
}
1575

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

1578
  term_table_t* terms = pre->terms;
39,852✔
1579
  term_manager_t* tm = &pre->tm;
39,852✔
1580

1581
  uint32_t i, j, n;
1582
  ivector_t t_blast;
1583

1584
  tuple_blast_term(pre, t);
39,852✔
1585
  init_ivector(&t_blast, 0);
39,852✔
1586
  tuple_blast_get(pre, t, &t_blast);
39,852✔
1587
  if (t_blast.size != 1) {
39,852✔
NEW
1588
    delete_ivector(&t_blast);
×
NEW
1589
    longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1590
  }
1591
  t = t_blast.data[0];
39,852✔
1592
  delete_ivector(&t_blast);
39,852✔
1593

1594
  // Check if already preprocessed;
1595
  term_t t_pre = preprocessor_get(pre, t);
39,852✔
1596
  if (t_pre != NULL_TERM) {
39,852✔
1597
    return t_pre;
1,649✔
1598
  }
1599

1600
// Note: negative affect on general performance due to solved/substituted
1601
//       terms being to complex for explainers.
1602
//
1603
//  // First, if the assertion is a conjunction, just expand
1604
//  if (is_assertion && is_neg_term(t) && term_kind(terms, t) == OR_TERM) {
1605
//    // !(or t1 ... tn) -> !t1 && ... && !tn
1606
//    composite_term_t* t_desc = composite_term_desc(terms, t);
1607
//    for (i = 0; i < t_desc->arity; ++ i) {
1608
//      ivector_push(out, opposite_term(t_desc->arg[i]));
1609
//    }
1610
//    return true_term;
1611
//  }
1612
//
1613
  // Start
1614
  ivector_t* pre_stack = &pre->preprocessing_stack;
38,203✔
1615
  ivector_reset(pre_stack);
38,203✔
1616
  ivector_push(pre_stack, t);
38,203✔
1617

1618
  // Preprocess
1619
  while (pre_stack->size) {
506,208✔
1620
    // Current term
1621
    term_t current = ivector_last(pre_stack);
468,016✔
1622

1623
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
468,016✔
1624
      mcsat_trace_printf(pre->tracer, "current = ");
×
1625
      trace_term_ln(pre->tracer, terms, current);
×
1626
    }
1627

1628
    // If preprocessed already, done
1629
    term_t current_pre = preprocessor_get(pre, current);
468,016✔
1630
    if (current_pre != NULL_TERM) {
468,016✔
1631
      ivector_pop(pre_stack);
31,304✔
1632
      continue;
31,304✔
1633
    }
1634

1635
    // Negation
1636
    if (is_neg_term(current)) {
436,712✔
1637
      term_t child = unsigned_term(current);
88,962✔
1638
      term_t child_pre = preprocessor_get(pre, child);
88,962✔
1639
      if (child_pre == NULL_TERM) {
88,962✔
1640
        ivector_push(pre_stack, child);
42,011✔
1641
        continue;
42,011✔
1642
      } else {
1643
        ivector_pop(pre_stack);
46,951✔
1644
        current_pre = opposite_term(child_pre);
46,951✔
1645
        preprocessor_set(pre, current, current_pre);
46,951✔
1646
        continue;
46,951✔
1647
      }
1648
    }
1649

1650
    // Check for supported types
1651
    type_kind_t type = term_type_kind(terms, current);
347,750✔
1652
    switch (type) {
347,750✔
1653
    case BOOL_TYPE:
347,750✔
1654
    case INT_TYPE:
1655
    case REAL_TYPE:
1656
    case FF_TYPE:
1657
    case UNINTERPRETED_TYPE:
1658
    case FUNCTION_TYPE:
1659
    case BITVECTOR_TYPE:
1660
    case SCALAR_TYPE:
1661
      break;
347,750✔
1662
    default:
×
1663
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
1664
    }
1665

1666
    // Kind of term
1667
    term_kind_t current_kind = term_kind(terms, current);
347,750✔
1668

1669
    switch(current_kind) {
347,750✔
1670
    case CONSTANT_TERM:    // constant of uninterpreted/scalar/boolean types
1,836✔
1671
    case BV64_CONSTANT:    // compact bitvector constant (64 bits at most)
1672
    case BV_CONSTANT:      // generic bitvector constant (more than 64 bits)
1673
    case ARITH_CONSTANT:   // rational constant
1674
    case ARITH_FF_CONSTANT:   // finite field constant
1675
      current_pre = current;
1,836✔
1676
      break;
1,836✔
1677

1678
    case UNINTERPRETED_TERM:  // (i.e., global variables, can't be bound).
14,063✔
1679
      current_pre = current;
14,063✔
1680
      // Unless we want special slicing
1681
      if (type == BITVECTOR_TYPE) {
14,063✔
1682
        if (pre->options->bv_var_size > 0) {
4,236✔
1683
          uint32_t size = term_bitsize(terms, current);
23✔
1684
          uint32_t var_size = pre->options->bv_var_size;
23✔
1685
          if (size > var_size) {
23✔
1686
            uint32_t n_vars = (size - 1) / var_size + 1;
2✔
1687
            term_t vars[n_vars];
2✔
1688
            for (i = n_vars - 1; size > 0; i--) {
8✔
1689
              if (size >= var_size) {
6✔
1690
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, var_size));
4✔
1691
                size -= var_size;
4✔
1692
              } else {
1693
                vars[i] = new_uninterpreted_term(terms, bv_type(terms->types, size));
2✔
1694
                size = 0;
2✔
1695
              }
1696
            }
1697
            current_pre = _o_yices_bvconcat(n_vars, vars);
2✔
1698
            term_t eq = _o_yices_eq(current, current_pre);
2✔
1699
            preprocessor_mark_eq(pre, eq, current);
2✔
1700
          }
1701
        }
1702
      }
1703
      break;
14,063✔
1704

1705
    case ITE_TERM:           // if-then-else
181,457✔
1706
    case ITE_SPECIAL:        // special if-then-else term (NEW: EXPERIMENTAL)
1707
    case EQ_TERM:            // equality
1708
    case OR_TERM:            // n-ary OR
1709
    case XOR_TERM:           // n-ary XOR
1710
    case ARITH_EQ_ATOM:      // equality (t == 0)
1711
    case ARITH_BINEQ_ATOM:   // equality (t1 == t2)  (between two arithmetic terms)
1712
    case ARITH_GE_ATOM:      // inequality (t >= 0)
1713
    case ARITH_FF_EQ_ATOM:   // finite field equality (t == 0)
1714
    case ARITH_FF_BINEQ_ATOM: // finite field equality (t1 == t2)  (between two arithmetic terms)
1715
    case BV_DIV:
1716
    case BV_REM:
1717
    case BV_SMOD:
1718
    case BV_SHL:
1719
    case BV_LSHR:
1720
    case BV_ASHR:
1721
    case BV_EQ_ATOM:
1722
    case BV_GE_ATOM:
1723
    case BV_SGE_ATOM:
1724
    {
1725
      composite_term_t* desc = get_composite(terms, current_kind, current);
181,457✔
1726
      bool children_done = true;
181,457✔
1727
      bool children_same = true;
181,457✔
1728

1729
      n = desc->arity;
181,457✔
1730

1731
      // MCSAT does not yet enforce all extensionality/cardinality constraints
1732
      // for function-sort disequalities. Reject equality atoms whose type needs
1733
      // that monitoring; the Boolean abstraction may assert them either way.
1734
      if (current_kind == EQ_TERM && term_needs_function_diseq_guard(terms, desc->arg[0])) {
181,457✔
1735
        longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
8✔
1736
      }
1737

1738
      // Is this a top-level equality assertion
1739
      bool is_equality =
181,449✔
1740
          current_kind == EQ_TERM ||
160,710✔
1741
          current_kind == BV_EQ_ATOM ||
103,651✔
1742
          current_kind == ARITH_EQ_ATOM ||
99,891✔
1743
          current_kind == ARITH_BINEQ_ATOM ||
95,735✔
1744
          current_kind == ARITH_FF_EQ_ATOM ||
342,159✔
1745
          current_kind == ARITH_FF_BINEQ_ATOM;
1746
      // don't rewrite if the equality is between Boolean terms
1747
      bool is_boolean = is_boolean_type(term_type(pre->terms, desc->arg[0]));
181,449✔
1748

1749
      term_t eq_solve_var = NULL_TERM;
181,449✔
1750
      if (is_assertion && is_equality && !is_boolean) {
181,449✔
1751
        bool is_lhs_rhs_mixed = desc->arity > 1 &&
139,549✔
1752
          term_type_kind(pre->terms, desc->arg[0]) != term_type_kind(pre->terms, desc->arg[1]);
67,817✔
1753
        // don't rewrite if equality is between mixed terms, e.g. between int and real terms
1754
        if (!is_lhs_rhs_mixed && current == t) {
71,732✔
1755
          eq_solve_var = preprocessor_get_eq_solved_var(pre, t);
47,683✔
1756
          if (eq_solve_var == NULL_TERM) {
47,683✔
1757
            term_t lhs = desc->arg[0];
27,698✔
1758
            term_kind_t lhs_kind = term_kind(terms, lhs);
27,698✔
1759
            // If lhs/rhs is a first-time seen variable, we can solve it
1760
            bool lhs_is_var = lhs_kind == UNINTERPRETED_TERM && is_pos_term(lhs);
27,698✔
1761
            if (lhs_is_var && preprocessor_get(pre, lhs) == NULL_TERM) {
27,698✔
1762
              // First time variable, let's solve
1763
              preprocessor_mark_eq(pre, t, lhs);
24,589✔
1764
              eq_solve_var = lhs;
24,589✔
1765
            } else if (desc->arity > 1) {
3,109✔
1766
              term_t rhs = desc->arg[1];
2,341✔
1767
              term_kind_t rhs_kind = term_kind(terms, rhs);
2,341✔
1768
              bool rhs_is_var = rhs_kind == UNINTERPRETED_TERM && is_pos_term(rhs);
2,341✔
1769
              if (rhs_is_var && preprocessor_get(pre, rhs) == NULL_TERM) {
2,341✔
1770
                // First time variable, let's solve
1771
                preprocessor_mark_eq(pre, t, rhs);
276✔
1772
                eq_solve_var = rhs;
276✔
1773
              }
1774
            }
1775
          } else {
1776
            // Check that we it's not there already
1777
            if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
19,985✔
1778
              eq_solve_var = NULL_TERM;
51✔
1779
            }
1780
          }
1781
        }
1782
      }
1783

1784
      ivector_t children;
1785
      init_ivector(&children, n);
181,449✔
1786

1787
      for (i = 0; i < n; ++ i) {
605,177✔
1788
        term_t child = desc->arg[i];
423,728✔
1789
        if (child != eq_solve_var) {
423,728✔
1790
          term_t child_pre = preprocessor_get(pre, child);
378,929✔
1791
          if (child_pre == NULL_TERM) {
378,929✔
1792
            children_done = false;
108,619✔
1793
            ivector_push(pre_stack, child);
108,619✔
1794
          } else if (child_pre != child) {
270,310✔
1795
            children_same = false;
106,070✔
1796
          }
1797
          if (children_done) {
378,929✔
1798
            ivector_push(&children, child_pre);
256,466✔
1799
          }
1800
        }
1801
      }
1802

1803
      if (eq_solve_var != NULL_TERM) {
181,449✔
1804
        // Check again to make sure we don't have something like x = x + 1
1805
        if (preprocessor_get(pre, eq_solve_var) != NULL_TERM) {
44,799✔
1806
          // Do it again
1807
          children_done = false;
×
1808
        }
1809
      }
1810

1811
      if (children_done) {
181,449✔
1812
        if (eq_solve_var != NULL_TERM) {
113,472✔
1813
          term_t eq_solve_term = zero_term;
24,814✔
1814
          if (children.size > 0) {
24,814✔
1815
            eq_solve_term = children.data[0];
24,776✔
1816
          }
1817
          preprocessor_set(pre, eq_solve_var, eq_solve_term);
24,814✔
1818
          current_pre = true_term;
24,814✔
1819
        } else {
1820
          if (children_same) {
88,658✔
1821
            current_pre = current;
50,466✔
1822
          } else {
1823
            current_pre = mk_composite(pre, current_kind, n, children.data);
38,192✔
1824
          }
1825
        }
1826
      }
1827

1828
      delete_ivector(&children);
181,449✔
1829

1830
      break;
181,449✔
1831
    }
1832

1833
    case BV_ARRAY:
17,517✔
1834
    {
1835
      composite_term_t* desc = get_composite(terms, current_kind, current);
17,517✔
1836
      bool children_done = true;
17,517✔
1837
      bool children_same = true;
17,517✔
1838

1839
      n = desc->arity;
17,517✔
1840

1841
      ivector_t children;
1842
      init_ivector(&children, n);
17,517✔
1843

1844
      for (i = 0; i < n; ++ i) {
353,534✔
1845
        term_t child = desc->arg[i];
336,017✔
1846
        term_t child_pre = preprocessor_get(pre, child);
336,017✔
1847
        if (child_pre == NULL_TERM) {
336,017✔
1848
          children_done = false;
143,211✔
1849
          ivector_push(pre_stack, child);
143,211✔
1850
        } else {
1851
          if (is_arithmetic_literal(terms, child_pre) || child_pre == false_term) {
192,806✔
1852
            // purify if arithmetic literal, i.e. a = 0 where a is of integer type
1853
            child_pre = preprocessor_purify(pre, child_pre, out);
35,723✔
1854
          }
1855
          if (child_pre != child) {
192,806✔
1856
            children_same = false;
110,041✔
1857
          }
1858
        }
1859
        if (children_done) {
336,017✔
1860
          ivector_push(&children, child_pre);
179,684✔
1861
        }
1862
      }
1863

1864
      if (children_done) {
17,517✔
1865
        if (children_same) {
9,165✔
1866
          current_pre = current;
2,210✔
1867
        } else {
1868
          current_pre = mk_composite(pre, current_kind, n, children.data);
6,955✔
1869
        }
1870
      }
1871

1872
      delete_ivector(&children);
17,517✔
1873

1874
      break;
17,517✔
1875
    }
1876

1877
    case ARITH_ABS:
10✔
1878
    {
1879
      term_t arg = arith_abs_arg(terms, current);
10✔
1880
      term_t arg_pre = preprocessor_get(pre, arg);
10✔
1881
      if (arg_pre == NULL_TERM) {
10✔
1882
        ivector_push(pre_stack, arg);
4✔
1883
      } else {
1884
        type_t arg_pre_type = term_type(pre->terms, arg_pre);
6✔
1885
        term_t arg_pre_is_positive = mk_arith_term_geq0(&pre->tm, arg_pre);
6✔
1886
        term_t arg_negative = _o_yices_neg(arg_pre);
6✔
1887
        current_pre = mk_ite(&pre->tm, arg_pre_is_positive, arg_pre, arg_negative, arg_pre_type);
6✔
1888
      }
1889
      break;
10✔
1890
    }
1891

1892
    case BV_SDIV:
20✔
1893
    {
1894
      composite_term_t* desc = get_composite(terms, current_kind, current);
20✔
1895
      assert(desc->arity == 2);
1896
      term_t s = desc->arg[0];
20✔
1897
      term_t s_pre = preprocessor_get(pre, s);
20✔
1898
      if (s_pre == NULL_TERM) {
20✔
1899
        ivector_push(pre_stack, s);
7✔
1900
      }
1901
      term_t t = desc->arg[1];
20✔
1902
      term_t t_pre = preprocessor_get(pre, t);
20✔
1903
      if (t_pre == NULL_TERM) {
20✔
1904
        ivector_push(pre_stack, t);
5✔
1905
      }
1906
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
20✔
1907
        type_t tau = term_type(terms, s_pre);
11✔
1908
        uint32_t n = term_bitsize(terms, s_pre);
11✔
1909
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
11✔
1910
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
11✔
1911
        // if (msb_s) {
1912
        //   if (msb_t) {
1913
        //     t1: udiv(-s, -t)
1914
        //   } else {
1915
        //     t2: -udiv(-s, t)
1916
        //   }
1917
        // } else {
1918
        //   if (msb_t) {
1919
        //     t3: -udiv(s, -t)
1920
        //   } else {
1921
        //     t4: udiv(s, t)
1922
        //   }
1923
        // }
1924
        term_t neg_s = mk_bvneg(tm, s_pre);
11✔
1925
        term_t neg_t = mk_bvneg(tm, t_pre);
11✔
1926

1927
        term_t t1 = mk_bvdiv(tm, neg_s, neg_t);
11✔
1928
        term_t t2 = mk_bvdiv(tm, neg_s, t_pre);
11✔
1929
        t2 = mk_bvneg(&pre->tm, t2);
11✔
1930
        term_t t3 = mk_bvdiv(tm, s_pre, neg_t);
11✔
1931
        t3 = mk_bvneg(&pre->tm, t3);
11✔
1932
        term_t t4 = mk_bvdiv(tm, s_pre, t_pre);
11✔
1933

1934
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
11✔
1935
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
11✔
1936

1937
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
11✔
1938
      }
1939
      break;
20✔
1940
    }
1941
    case BV_SREM:
21✔
1942
    {
1943
      composite_term_t* desc = get_composite(terms, current_kind, current);
21✔
1944
      assert(desc->arity == 2);
1945
      term_t s = desc->arg[0];
21✔
1946
      term_t s_pre = preprocessor_get(pre, s);
21✔
1947
      if (s_pre == NULL_TERM) {
21✔
1948
        ivector_push(pre_stack, s);
8✔
1949
      }
1950
      term_t t = desc->arg[1];
21✔
1951
      term_t t_pre = preprocessor_get(pre, t);
21✔
1952
      if (t_pre == NULL_TERM) {
21✔
1953
        ivector_push(pre_stack, t);
3✔
1954
      }
1955
      if (s_pre != NULL_TERM && t_pre != NULL_TERM) {
21✔
1956
        type_t tau = term_type(terms, s_pre);
12✔
1957
        uint32_t n = term_bitsize(terms, s_pre);
12✔
1958
        term_t msb_s = mk_bitextract(tm, s_pre, n-1);
12✔
1959
        term_t msb_t = mk_bitextract(tm, t_pre, n-1);
12✔
1960
        // if (msb_s) {
1961
        //   if (msb_t) {
1962
        //     t1: -urem(-s, -t)
1963
        //   } else {
1964
        //     t2: -urem(-s, t)
1965
        //   }
1966
        // } else {
1967
        //   if (msb_t) {
1968
        //     t3: -urem(s, -t)
1969
        //   } else {
1970
        //     t4: urem(s, t)
1971
        //   }
1972
        // }
1973
        term_t neg_s = mk_bvneg(tm, s_pre);
12✔
1974
        term_t neg_t = mk_bvneg(tm, t_pre);
12✔
1975

1976
        term_t t1 = mk_bvrem(tm, neg_s, neg_t);
12✔
1977
        t1 = mk_bvneg(tm, t1);
12✔
1978
        term_t t2 = mk_bvrem(tm, neg_s, t_pre);
12✔
1979
        t2 = mk_bvneg(tm, t2);
12✔
1980
        term_t t3 = mk_bvrem(tm, s_pre, neg_t);
12✔
1981
        term_t t4 = mk_bvrem(tm, s_pre, t_pre);
12✔
1982

1983
        term_t b1 = mk_ite(tm, msb_t, t1, t2, tau);
12✔
1984
        term_t b2 = mk_ite(tm, msb_t, t3, t4, tau);
12✔
1985

1986
        current_pre = mk_ite(tm, msb_s, b1, b2, tau);
12✔
1987
      }
1988
      break;
21✔
1989
    }
1990
    case BIT_TERM: // bit-select current = child[i]
112,745✔
1991
    {
1992
      uint32_t index = bit_term_index(terms, current);
112,745✔
1993
      term_t arg = bit_term_arg(terms, current);
112,745✔
1994
      term_t arg_pre = preprocessor_get(pre, arg);
112,745✔
1995
      if (arg_pre == NULL_TERM) {
112,745✔
1996
        ivector_push(pre_stack, arg);
1,584✔
1997
      } else {
1998
        if (arg_pre == arg) {
111,161✔
1999
          current_pre = current;
73,115✔
2000
        } else {
2001
          if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,046✔
2002
            mcsat_trace_printf(pre->tracer, "arg_pre = ");
×
2003
            trace_term_ln(pre->tracer, terms, arg_pre);
×
2004
          }
2005
          // For simplification purposes use API
2006
          current_pre = _o_yices_bitextract(arg_pre, index);
38,046✔
2007
          assert(current_pre != NULL_TERM);
2008
        }
2009
      }
2010
      break;
112,745✔
2011
    }
2012
    case BV_POLY:  // polynomial with generic bitvector coefficients
33✔
2013
    {
2014
      bvpoly_t* p = bvpoly_term_desc(terms, current);
33✔
2015

2016
      bool children_done = true;
33✔
2017
      bool children_same = true;
33✔
2018

2019
      n = p->nterms;
33✔
2020

2021
      ivector_t children;
2022
      init_ivector(&children, n);
33✔
2023

2024
      for (i = 0; i < n; ++ i) {
84✔
2025
        term_t x = p->mono[i].var;
51✔
2026
        term_t x_pre = (x == const_idx ? const_idx : preprocessor_get(pre, x));
51✔
2027

2028
        if (x_pre != const_idx) {
51✔
2029
          if (x_pre == NULL_TERM) {
47✔
2030
            children_done = false;
10✔
2031
            ivector_push(pre_stack, x);
10✔
2032
          } else if (x_pre != x) {
37✔
2033
            children_same = false;
23✔
2034
          }
2035
        }
2036

2037
        if (children_done) { ivector_push(&children, x_pre); }
51✔
2038
      }
2039

2040
      if (children_done) {
33✔
2041
        if (children_same) {
26✔
2042
          current_pre = current;
11✔
2043
        } else {
2044
          current_pre = mk_bvarith_poly(tm, p, n, children.data);
15✔
2045
        }
2046
      }
2047

2048
      delete_ivector(&children);
33✔
2049

2050
      break;
33✔
2051
    }
2052
    case BV64_POLY: // polynomial with 64bit coefficients
2,573✔
2053
    {
2054
      bvpoly64_t* p = bvpoly64_term_desc(terms, current);
2,573✔
2055

2056
      bool children_done = true;
2,573✔
2057
      bool children_same = true;
2,573✔
2058

2059
      n = p->nterms;
2,573✔
2060

2061
      ivector_t children;
2062
      init_ivector(&children, n);
2,573✔
2063

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

2068
        if (x_pre != const_idx) {
7,254✔
2069
          if (x_pre == NULL_TERM) {
5,580✔
2070
            children_done = false;
1,308✔
2071
            ivector_push(pre_stack, x);
1,308✔
2072
          } else if (x_pre != x) {
4,272✔
2073
            children_same = false;
3,568✔
2074
          }
2075
        }
2076

2077
        if (children_done) { ivector_push(&children, x_pre); }
7,254✔
2078
      }
2079

2080
      if (children_done) {
2,573✔
2081
        if (children_same) {
1,872✔
2082
          current_pre = current;
279✔
2083
        } else {
2084
          current_pre = mk_bvarith64_poly(tm, p, n, children.data);
1,593✔
2085
        }
2086
      }
2087

2088
      delete_ivector(&children);
2,573✔
2089

2090
      break;
2,573✔
2091
    }
2092

2093
    case POWER_PRODUCT:    // power products: (t1^d1 * ... * t_n^d_n)
1,675✔
2094
    {
2095
      pprod_t* pp = pprod_term_desc(terms, current);
1,675✔
2096
      bool children_done = true;
1,675✔
2097
      bool children_same = true;
1,675✔
2098

2099
      n = pp->len;
1,675✔
2100

2101
      ivector_t children;
2102
      init_ivector(&children, n);
1,675✔
2103

2104
      for (i = 0; i < n; ++ i) {
5,316✔
2105
        term_t x = pp->prod[i].var;
3,641✔
2106
        term_t x_pre = preprocessor_get(pre, x);
3,641✔
2107

2108
        if (x_pre == NULL_TERM) {
3,641✔
2109
          children_done = false;
452✔
2110
          ivector_push(pre_stack, x);
452✔
2111
        } else if (x_pre != x) {
3,189✔
2112
          children_same = false;
96✔
2113
        }
2114

2115
        if (children_done) { ivector_push(&children, x_pre); }
3,641✔
2116
      }
2117

2118
      if (children_done) {
1,675✔
2119
        if (children_same) {
1,339✔
2120
          current_pre = current;
1,281✔
2121
        } else {
2122
          // NOTE: it doens't change pp, it just uses it as a frame
2123
          current_pre = mk_pprod(tm, pp, n, children.data);
58✔
2124
        }
2125
      }
2126

2127
      delete_ivector(&children);
1,675✔
2128

2129
      break;
1,675✔
2130
    }
2131

2132
    case ARITH_POLY:       // polynomial with rational coefficients
6,947✔
2133
    {
2134
      polynomial_t* p = poly_term_desc(terms, current);
6,947✔
2135

2136
      bool children_done = true;
6,947✔
2137
      bool children_same = true;
6,947✔
2138

2139
      n = p->nterms;
6,947✔
2140

2141
      ivector_t children;
2142
      init_ivector(&children, n);
6,947✔
2143

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

2148
        if (x_pre != const_idx) {
19,943✔
2149
          if (x_pre == NULL_TERM) {
16,908✔
2150
            children_done = false;
2,572✔
2151
            ivector_push(pre_stack, x);
2,572✔
2152
          } else if (x_pre != x) {
14,336✔
2153
            children_same = false;
949✔
2154
          }
2155
        }
2156

2157
        if (children_done) { ivector_push(&children, x_pre); }
19,943✔
2158
      }
2159

2160
      if (children_done) {
6,947✔
2161
        if (children_same) {
5,491✔
2162
          current_pre = current;
4,889✔
2163
        } else {
2164
          current_pre = mk_arith_poly(tm, p, n, children.data);
602✔
2165
        }
2166
      }
2167

2168
      delete_ivector(&children);
6,947✔
2169

2170
      break;
6,947✔
2171
    }
2172

2173
    case ARITH_FF_POLY:    // polynomial with finite field coefficients
150✔
2174
    {
2175
      polynomial_t* p = finitefield_poly_term_desc(terms, current);
150✔
2176
      const rational_t *mod = finitefield_term_order(terms, current);
150✔
2177

2178
      bool children_done = true;
150✔
2179
      bool children_same = true;
150✔
2180

2181
      n = p->nterms;
150✔
2182

2183
      ivector_t children;
2184
      init_ivector(&children, n);
150✔
2185

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

2190
        if (x_pre != const_idx) {
918✔
2191
          if (x_pre == NULL_TERM) {
864✔
2192
            children_done = false;
380✔
2193
            ivector_push(pre_stack, x);
380✔
2194
          } else if (x_pre != x) {
484✔
2195
            children_same = false;
×
2196
          }
2197
        }
2198

2199
        if (children_done) { ivector_push(&children, x_pre); }
918✔
2200
      }
2201

2202
      if (children_done) {
150✔
2203
        if (children_same) {
75✔
2204
          current_pre = current;
75✔
2205
        } else {
2206
          current_pre = mk_arith_ff_poly(tm, p, n, children.data, mod);
×
2207
        }
2208
      }
2209

2210
      delete_ivector(&children);
150✔
2211

2212
      break;
150✔
2213
    }
2214

2215
    // FOLLOWING ARE UNINTEPRETED, SO WE PURIFY THE ARGUMENTS
2216

2217
    case APP_TERM:           // application of an uninterpreted function
8,666✔
2218
    case ARITH_RDIV:         // regular division (/ x y)
2219
    case ARITH_IDIV:         // division: (div x y) as defined in SMT-LIB 2
2220
    case ARITH_MOD:          // remainder: (mod x y) is y - x * (div x y)
2221
    case UPDATE_TERM:        // update array
2222
    {
2223
      composite_term_t* desc = get_composite(terms, current_kind, current);
8,666✔
2224
      bool children_done = true;
8,666✔
2225
      bool children_same = true;
8,666✔
2226

2227
      n = desc->arity;
8,666✔
2228

2229
      ivector_t children;
2230
      init_ivector(&children, n);
8,666✔
2231

2232
      for (i = 0; i < n; ++ i) {
29,845✔
2233
        term_t child = desc->arg[i];
21,179✔
2234
        term_t child_pre = preprocessor_get(pre, child);
21,179✔
2235

2236
        if (child_pre == NULL_TERM) {
21,179✔
2237
          children_done = false;
4,060✔
2238
          ivector_push(pre_stack, child);
4,060✔
2239
        } else {
2240
          // Purify if needed
2241
          child_pre = preprocessor_purify(pre, child_pre, out);
17,119✔
2242
          // If interpreted terms, we need to purify non-variables
2243
          if (child_pre != child) { children_same = false; }
17,119✔
2244
        }
2245

2246
        if (children_done) { ivector_push(&children, child_pre); }
21,179✔
2247
      }
2248

2249
      if (children_done) {
8,666✔
2250
        if (children_same) {
5,654✔
2251
          current_pre = current;
4,219✔
2252
        } else {
2253
          current_pre = mk_composite(pre, current_kind, n, children.data);
1,435✔
2254
        }
2255
      }
2256

2257
      delete_ivector(&children);
8,666✔
2258

2259
      break;
8,666✔
2260
    }
2261

2262
    case ARITH_IS_INT_ATOM:
1✔
2263
    {
2264
      // replace with t <= floor(t)
2265
      term_t child = arith_is_int_arg(terms, current);
1✔
2266
      term_t child_pre = preprocessor_get(pre, child);
1✔
2267
      if (child_pre != NULL_TERM) {
1✔
2268
        child_pre = preprocessor_purify(pre, child_pre, out);
1✔
2269
        current_pre = arith_floor(terms, child_pre);
1✔
2270
        current_pre = mk_arith_leq(tm, child_pre, current_pre);
1✔
2271
      } else {
2272
        ivector_push(pre_stack, child);
×
2273
      }
2274
      break;
1✔
2275
    }
2276

2277
    case ARITH_FLOOR:        // floor: purify, but its interpreted
8✔
2278
    {
2279
      term_t child = arith_floor_arg(terms, current);
8✔
2280
      term_t child_pre = preprocessor_get(pre, child);
8✔
2281

2282
      if (child_pre != NULL_TERM) {
8✔
2283
        if (term_kind(terms, child_pre) == ARITH_CONSTANT) {
5✔
2284
          rational_t floor;
2285
          q_init(&floor);
2✔
2286
          q_set(&floor, rational_term_desc(terms, child_pre));
2✔
2287
          q_floor(&floor);
2✔
2288
          current_pre = arith_constant(terms, &floor);
2✔
2289
          q_clear(&floor);
2✔
2290
        } else {
2291
          child_pre = preprocessor_purify(pre, child_pre, out);
3✔
2292
          if (child_pre != child) {
3✔
2293
            current_pre = arith_floor(terms, child_pre);
1✔
2294
          } else {
2295
            current_pre = current;
2✔
2296
          }
2297
        }
2298
      } else {
2299
        ivector_push(pre_stack, child);
3✔
2300
      }
2301

2302
      break;
8✔
2303
    }
2304

2305
    case ARITH_CEIL:        // floor: purify, but its interpreted
1✔
2306
    {
2307
      term_t child = arith_ceil_arg(terms, current);
1✔
2308
      term_t child_pre = preprocessor_get(pre, child);
1✔
2309

2310
      if (child_pre != NULL_TERM) {
1✔
2311
        child_pre = preprocessor_purify(pre, child_pre, out);
1✔
2312
        if (child_pre != child) {
1✔
2313
          current_pre = arith_floor(terms, child_pre);
1✔
2314
        } else {
2315
          current_pre = current;
×
2316
        }
2317
      } else {
2318
        ivector_push(pre_stack, child);
×
2319
      }
2320

2321
      break;
1✔
2322
    }
2323

2324
    case DISTINCT_TERM:
27✔
2325
    {
2326
      composite_term_t* desc = get_composite(terms, current_kind, current);
27✔
2327

2328
      bool children_done = true;
27✔
2329
      n = desc->arity;
27✔
2330

2331
      // DISTINCT_TERM is lowered below into pairwise disequalities. Apply the
2332
      // same function-sort guard before that expansion.
2333
      for (i = 0; i < n; ++ i) {
125✔
2334
        if (term_needs_function_diseq_guard(terms, desc->arg[i])) {
101✔
2335
          longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
3✔
2336
        }
2337
      }
2338

2339
      ivector_t children;
2340
      init_ivector(&children, n);
24✔
2341

2342
      for (i = 0; i < n; ++ i) {
122✔
2343
        term_t child = desc->arg[i];
98✔
2344
        term_t child_pre = preprocessor_get(pre, child);
98✔
2345

2346
        if (child_pre == NULL_TERM) {
98✔
2347
          children_done = false;
41✔
2348
          ivector_push(pre_stack, child);
41✔
2349
        }
2350

2351
        if (children_done) { ivector_push(&children, child_pre); }
98✔
2352
      }
2353

2354
      if (children_done) {
24✔
2355
        ivector_t distinct;
2356
        init_ivector(&distinct, 0);
14✔
2357

2358
        for (i = 0; i < n; ++ i) {
70✔
2359
          for (j = i + 1; j < n; ++ j) {
148✔
2360
            term_t neq = mk_eq(&pre->tm, children.data[i], children.data[j]);
92✔
2361
            neq = opposite_term(neq);
92✔
2362
            ivector_push(&distinct, neq);
92✔
2363
          }
2364
        }
2365
        current_pre = mk_and(&pre->tm, distinct.size, distinct.data);
14✔
2366

2367
        delete_ivector(&distinct);
14✔
2368
      }
2369

2370
      delete_ivector(&children);
24✔
2371

2372
      break;
24✔
2373
    }
2374

2375
    case LAMBDA_TERM:
×
2376
      longjmp(*pre->exception, LAMBDAS_NOT_SUPPORTED);
×
2377
      break;
2378

2379
    default:
×
2380
      // UNSUPPORTED TERM/THEORY
2381
      longjmp(*pre->exception, MCSAT_EXCEPTION_UNSUPPORTED_THEORY);
×
2382
      break;
2383
    }
2384

2385
    if (current_pre != NULL_TERM) {
347,739✔
2386
      preprocessor_set(pre, current, current_pre);
264,204✔
2387
      ivector_pop(pre_stack);
264,204✔
2388
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
264,204✔
2389
        mcsat_trace_printf(pre->tracer, "current_pre = ");
×
2390
        trace_term_ln(pre->tracer, terms, current_pre);
×
2391
      }
2392
    }
2393

2394
  }
2395

2396
  // Return the result
2397
  t_pre = preprocessor_get(pre, t);
38,192✔
2398
  if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
38,192✔
2399
    mcsat_trace_printf(pre->tracer, "t_pre = ");
×
2400
    trace_term_ln(pre->tracer, terms, t_pre);
×
2401
  }
2402

2403
  ivector_reset(pre_stack);
38,192✔
2404

2405
  assert(t_pre != NULL_TERM);
2406
  return t_pre;
38,192✔
2407
}
2408

2409
void preprocessor_set_exception_handler(preprocessor_t* pre, jmp_buf* handler) {
×
2410
  pre->exception = handler;
×
2411
}
×
2412

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

2424
void preprocessor_pop(preprocessor_t* pre) {
455✔
2425

2426
  uint32_t preprocess_map_list_size = 0;
455✔
2427
  uint32_t tuple_blast_list_size = 0;
455✔
2428
  uint32_t tuple_blast_data_size = 0;
455✔
2429
  uint32_t tuple_blast_atoms_size = 0;
455✔
2430
  uint32_t purification_map_list_size = 0;
455✔
2431
  uint32_t equalities_list_size = 0;
455✔
2432

2433
  scope_holder_pop(&pre->scope,
455✔
2434
      &preprocess_map_list_size,
2435
      &tuple_blast_list_size,
2436
      &tuple_blast_data_size,
2437
      &tuple_blast_atoms_size,
2438
      &purification_map_list_size,
2439
      &equalities_list_size,
2440
      NULL);
2441

2442
  while (pre->preprocess_map_list.size > preprocess_map_list_size) {
11,959✔
2443
    term_t t = ivector_last(&pre->preprocess_map_list);
11,504✔
2444
    ivector_pop(&pre->preprocess_map_list);
11,504✔
2445
    int_hmap_pair_t* find = int_hmap_find(&pre->preprocess_map, t);
11,504✔
2446
    assert(find != NULL);
2447
    int_hmap_erase(&pre->preprocess_map, find);
11,504✔
2448
  }
2449

2450
  while (pre->tuple_blast_list.size > tuple_blast_list_size) {
1,821✔
2451
    term_t t = ivector_last(&pre->tuple_blast_list);
1,366✔
2452
    ivector_pop(&pre->tuple_blast_list);
1,366✔
2453
    int_hmap_pair_t* find = int_hmap_find(&pre->tuple_blast_map, t);
1,366✔
2454
    assert(find != NULL);
2455
    int_hmap_erase(&pre->tuple_blast_map, find);
1,366✔
2456
  }
2457
  ivector_shrink(&pre->tuple_blast_data, tuple_blast_data_size);
455✔
2458
  ivector_shrink(&pre->tuple_blast_atoms, tuple_blast_atoms_size);
455✔
2459

2460
  while (pre->purification_map_list.size > purification_map_list_size) {
590✔
2461
    term_t t = ivector_last(&pre->purification_map_list);
135✔
2462
    ivector_pop(&pre->purification_map_list);
135✔
2463
    int_hmap_pair_t* find = int_hmap_find(&pre->purification_map, t);
135✔
2464
    assert(find != NULL);
2465
    int_hmap_erase(&pre->purification_map, find);
135✔
2466
  }
2467

2468
  while (pre->equalities_list.size > equalities_list_size) {
505✔
2469
    term_t eq = ivector_last(&pre->equalities_list);
50✔
2470
    ivector_pop(&pre->equalities_list);
50✔
2471
    int_hmap_pair_t* find = int_hmap_find(&pre->equalities, eq);
50✔
2472
    assert(find != NULL);
2473
    int_hmap_erase(&pre->equalities, find);
50✔
2474
  }
2475
}
455✔
2476

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

2479
static
2480
value_t build_value_from_flat(preprocessor_t* pre, value_table_t* vtbl, type_t tau, const value_t* flat, uint32_t* idx) {
117✔
2481
  type_table_t* types = pre->terms->types;
117✔
2482
  PP_DIAG("[build_value_from_flat] enter tau=%d idx=%u\n", (int) tau, (unsigned) *idx);
117✔
2483

2484
  if (type_kind(types, tau) == TUPLE_TYPE) {
117✔
2485
    tuple_type_t* tuple = tuple_type_desc(types, tau);
38✔
2486
    uint32_t i, n = tuple->nelem;
38✔
2487
    PP_DIAG("[build_value_from_flat] TUPLE n=%u\n", (unsigned) n);
38✔
2488
    value_t elem[n];
38✔
2489
    for (i = 0; i < n; ++i) {
116✔
2490
      elem[i] = build_value_from_flat(pre, vtbl, tuple->elem[i], flat, idx);
78✔
2491
      if (elem[i] == null_value) {
78✔
NEW
2492
        PP_DIAG("[build_value_from_flat] TUPLE elem %u null\n", (unsigned) i);
×
NEW
2493
        return null_value;
×
2494
      }
2495
    }
2496
    PP_DIAG("[build_value_from_flat] TUPLE calling vtbl_mk_tuple\n");
38✔
2497
    value_t r = vtbl_mk_tuple(vtbl, n, elem);
38✔
2498
    PP_DIAG("[build_value_from_flat] TUPLE vtbl_mk_tuple -> %d\n", (int) r);
38✔
2499
    return r;
38✔
2500
  } else if (type_kind(types, tau) == FUNCTION_TYPE) {
79✔
2501
    uint32_t n = type_leaf_count(pre, tau);
3✔
2502
    PP_DIAG("[build_value_from_flat] FUNCTION n_leaves=%u\n", (unsigned) n);
3✔
2503
    value_t v = merge_blasted_function_value(pre, vtbl, tau, flat + *idx, n);
3✔
2504
    *idx += n;
3✔
2505
    PP_DIAG("[build_value_from_flat] FUNCTION merge -> %d new_idx=%u\n", (int) v, (unsigned) *idx);
3✔
2506
    return v;
3✔
2507
  } else {
2508
    value_t v = flat[*idx];
76✔
2509
    (*idx)++;
76✔
2510
    PP_DIAG("[build_value_from_flat] LEAF v=%d new_idx=%u\n", (int) v, (unsigned) *idx);
76✔
2511
    return v;
76✔
2512
  }
2513
}
2514

2515
static
2516
bool map_args_match(value_table_t* vtbl, value_t map, const value_t* args, uint32_t n) {
23✔
2517
  value_map_t* m = vtbl_map(vtbl, map);
23✔
2518
  uint32_t i;
2519
  if (m->arity != n) {
23✔
NEW
2520
    return false;
×
2521
  }
2522
  for (i = 0; i < n; ++i) {
48✔
2523
    if (m->arg[i] != args[i]) {
34✔
2524
      return false;
9✔
2525
    }
2526
  }
2527
  return true;
14✔
2528
}
2529

2530
static
2531
value_t find_map_result(value_table_t* vtbl, const ivector_t* maps, const value_t* args, uint32_t n, value_t def) {
19✔
2532
  uint32_t i;
2533
  for (i = 0; i < maps->size; ++i) {
28✔
2534
    value_t map = maps->data[i];
23✔
2535
    if (map_args_match(vtbl, map, args, n)) {
23✔
2536
      return vtbl_map(vtbl, map)->val;
14✔
2537
    }
2538
  }
2539
  return def;
5✔
2540
}
2541

2542
static
2543
void add_unique_flat_args(ivector_t* offsets, ivector_t* data, const value_t* args, uint32_t n) {
14✔
2544
  uint32_t i, j;
2545
  for (i = 0; i < offsets->size; ++i) {
18✔
2546
    uint32_t off = offsets->data[i];
9✔
2547
    bool same = true;
9✔
2548
    for (j = 0; j < n; ++j) {
18✔
2549
      if (data->data[off + j] != args[j]) {
13✔
2550
        same = false;
4✔
2551
        break;
4✔
2552
      }
2553
    }
2554
    if (same) {
9✔
2555
      return;
5✔
2556
    }
2557
  }
2558
  ivector_push(offsets, data->size);
9✔
2559
  ivector_add(data, args, n);
9✔
2560
}
2561

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

2583
  /* All heap-backed scratch vectors are initialized up-front so that every
2584
   * exit through the `done:` label has the same cleanup responsibilities.
2585
   * In particular orig_maps is deliberately initialized here rather than
2586
   * just before the loop that populates it: if its init moves, `goto done`
2587
   * paths that run before the init would otherwise silently leak the
2588
   * vector. Keeping the init paired with the other unconditional inits
2589
   * makes that invariant self-evident. */
2590
  init_ivector(&flat_dom, 0);
5✔
2591
  init_ivector(&unique_offsets, 0);
5✔
2592
  init_ivector(&unique_args, 0);
5✔
2593
  init_ivector(&orig_maps, 0);
5✔
2594

2595
  for (i = 0; i < fun->ndom; ++i) {
10✔
2596
    type_collect_flat(types, fun->domain[i], &flat_dom);
5✔
2597
  }
2598
  flat_n = flat_dom.size;
5✔
2599

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

2640
  for (i = 0; i < unique_offsets.size; ++i) {
14✔
2641
    uint32_t flat_idx = unique_offsets.data[i];
9✔
2642
    const value_t* flat_args = (value_t*) (unique_args.data + flat_idx);
9✔
2643
    value_t leaf_values[nleaves];
9✔
2644
    uint32_t idx;
2645
    value_t mapv;
2646

2647
    for (j = 0; j < nleaves; ++j) {
28✔
2648
      leaf_values[j] = find_map_result(vtbl, &leaf_maps[j], flat_args, flat_n, leaf_defaults[j]);
19✔
2649
    }
2650

2651
    idx = 0;
9✔
2652
    value_t out_val = build_value_from_flat(pre, vtbl, codom, leaf_values, &idx);
9✔
2653
    if (out_val == null_value) {
9✔
NEW
2654
      fail_reason = "could not build codomain value from flat leaf values";
×
NEW
2655
      goto done;
×
2656
    }
2657

2658
    value_t args_orig[fun->ndom];
9✔
2659
    idx = 0;
9✔
2660
    for (j = 0; j < fun->ndom; ++j) {
18✔
2661
      args_orig[j] = build_value_from_flat(pre, vtbl, fun->domain[j], flat_args, &idx);
9✔
2662
      if (args_orig[j] == null_value) {
9✔
NEW
2663
        fail_reason = "could not rebuild a domain argument from flat leaf values";
×
NEW
2664
        goto done;
×
2665
      }
2666
    }
2667
    mapv = vtbl_mk_map(vtbl, fun->ndom, args_orig, out_val);
9✔
2668
    ivector_push(&orig_maps, mapv);
9✔
2669
  }
2670

2671
  {
2672
    uint32_t idx = 0;
5✔
2673
    value_t def_val = build_value_from_flat(pre, vtbl, codom, leaf_defaults, &idx);
5✔
2674
    if (def_val == null_value) {
5✔
NEW
2675
      fail_reason = "could not rebuild the function default value";
×
NEW
2676
      goto done;
×
2677
    }
2678
    result = vtbl_mk_function(vtbl, tau, orig_maps.size, (value_t*) orig_maps.data, def_val);
5✔
2679
  }
2680

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

2702
static
2703
void preprocessor_build_tuple_model(preprocessor_t* pre, model_t* model) {
48✔
2704
  value_table_t* vtbl = model_get_vtbl(model);
48✔
2705
  type_table_t* types = pre->terms->types;
48✔
2706
  uint32_t i;
2707

2708
  /* TEMP DIAG (windows release+thread-safety mcsat_tuples failure) */
2709
  PP_DIAG("[pp_build_tuple] enter, atoms=%u\n",
48✔
2710
          (unsigned) pre->tuple_blast_atoms.size);
2711
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
66✔
2712
    term_t atom = pre->tuple_blast_atoms.data[i];
18✔
2713
    ivector_t leaves;
2714
    type_t tau = term_type(pre->terms, atom);
18✔
2715
    uint32_t n, j;
2716

2717
    PP_DIAG("[pp_build_tuple] i=%u atom=%d tau=%d\n",
18✔
2718
            (unsigned) i, (int) atom, (int) tau);
2719

2720
    if (model_find_term_value(model, atom) != null_value) {
18✔
NEW
2721
      PP_DIAG("[pp_build_tuple]   atom already mapped, continue\n");
×
NEW
2722
      continue;
×
2723
    }
2724

2725
    init_ivector(&leaves, 0);
18✔
2726
    tuple_blast_get(pre, atom, &leaves);
18✔
2727
    n = leaves.size;
18✔
2728
    PP_DIAG("[pp_build_tuple]   n_leaves=%u\n", (unsigned) n);
18✔
2729
    if (n == 0) {
18✔
NEW
2730
      delete_ivector(&leaves);
×
NEW
2731
      continue;
×
2732
    }
2733

2734
    value_t leaf_vals[n];
18✔
2735
    bool ok = true;
18✔
2736
    for (j = 0; j < n; ++j) {
59✔
2737
      PP_DIAG("[pp_build_tuple]   j=%u leaf=%d\n",
41✔
2738
              (unsigned) j, (int) leaves.data[j]);
2739
      value_t v = model_get_term_value(model, leaves.data[j]);
41✔
2740
      PP_DIAG("[pp_build_tuple]     model_get_term_value -> %d\n", (int) v);
41✔
2741
      if (v < 0) {
41✔
2742
        /* The blasted leaf was never assigned a value by the mcsat
2743
         * search (typical for unconstrained tuple components) and
2744
         * the model cannot synthesize a default for us -- this
2745
         * happens when keep_subst=0 disables the alias-based
2746
         * default-completion path in eval_uninterpreted. Fall back
2747
         * to a freshly minted default of the leaf's declared type
2748
         * so the original tuple atom can still be reconstructed.
2749
         * vtbl_make_object handles bool / arith / bv / tuple /
2750
         * function / scalar uniformly. */
2751
        type_t leaf_tau = term_type(pre->terms, leaves.data[j]);
1✔
2752
        PP_DIAG("[pp_build_tuple]     leaf_tau=%d, calling vtbl_make_object\n",
1✔
2753
                (int) leaf_tau);
2754
        v = vtbl_make_object(vtbl, leaf_tau);
1✔
2755
        PP_DIAG("[pp_build_tuple]     vtbl_make_object -> %d\n", (int) v);
1✔
2756
        if (v < 0) {
1✔
NEW
2757
          ok = false;
×
NEW
2758
          break;
×
2759
        }
2760
      }
2761
      leaf_vals[j] = v;
41✔
2762
    }
2763
    PP_DIAG("[pp_build_tuple]   leaf loop done, ok=%d\n", (int) ok);
18✔
2764
    if (!ok) {
18✔
2765
      /* vtbl_make_object failed for some leaf: the type cannot be
2766
       * inhabited concretely (extremely unusual -- e.g. a malformed
2767
       * type table entry). Drop the atom and trace which leaf index
2768
       * was the cause so a user investigating a missing (show-model)
2769
       * entry can pin the gap. */
NEW
2770
      if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2771
        mcsat_trace_printf(pre->tracer,
×
2772
                           "preprocessor_build_tuple_model: dropping atom ");
NEW
2773
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2774
        mcsat_trace_printf(pre->tracer,
×
2775
                           "  (vtbl_make_object failed for blasted leaf %u)\n", j);
2776
      }
NEW
2777
      delete_ivector(&leaves);
×
NEW
2778
      continue;
×
2779
    }
2780

2781
    if (type_kind(types, tau) == FUNCTION_TYPE) {
18✔
2782
      PP_DIAG("[pp_build_tuple]   FUNCTION_TYPE branch\n");
2✔
2783
      value_t f = merge_blasted_function_value(pre, vtbl, tau, leaf_vals, n);
2✔
2784
      PP_DIAG("[pp_build_tuple]   merge_blasted_function_value -> %d\n", (int) f);
2✔
2785
      if (f >= 0) {
2✔
2786
        model_map_term(model, atom, f);
2✔
NEW
2787
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
2788
        /* merge_blasted_function_value has already traced a reason code;
2789
         * complete the message here with the concrete atom identity. */
NEW
2790
        mcsat_trace_printf(pre->tracer,
×
2791
                           "preprocessor_build_tuple_model: dropping function atom ");
NEW
2792
        trace_term_ln(pre->tracer, pre->terms, atom);
×
2793
      }
2794
    } else {
2795
      PP_DIAG("[pp_build_tuple]   non-FUNCTION branch, calling build_value_from_flat\n");
16✔
2796
      uint32_t idx = 0;
16✔
2797
      value_t v = build_value_from_flat(pre, vtbl, tau, leaf_vals, &idx);
16✔
2798
      PP_DIAG("[pp_build_tuple]   build_value_from_flat -> %d (idx=%u)\n",
16✔
2799
              (int) v, (unsigned) idx);
2800
      if (v >= 0) {
16✔
2801
        PP_DIAG("[pp_build_tuple]   model_map_term(atom=%d, v=%d)\n",
16✔
2802
                (int) atom, (int) v);
2803
        model_map_term(model, atom, v);
16✔
2804
        PP_DIAG("[pp_build_tuple]   model_map_term OK\n");
16✔
NEW
2805
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
2806
        mcsat_trace_printf(pre->tracer,
×
2807
                           "preprocessor_build_tuple_model: dropping tuple atom ");
NEW
2808
        trace_term_ln(pre->tracer, pre->terms, atom);
×
NEW
2809
        mcsat_trace_printf(pre->tracer,
×
2810
                           "  (leaf values did not decompose into a tuple value)\n");
2811
      }
2812
    }
2813

2814
    delete_ivector(&leaves);
18✔
2815
    PP_DIAG("[pp_build_tuple]   end of iteration i=%u\n", (unsigned) i);
18✔
2816
  }
2817
  PP_DIAG("[pp_build_tuple] exit\n");
48✔
2818
}
48✔
2819

2820
static term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx);
2821
static void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out);
2822

2823
static
NEW
2824
term_t merge_blasted_function_term(preprocessor_t* pre, type_t tau, const term_t* leaves, uint32_t nleaves) {
×
NEW
2825
  term_table_t* terms = pre->terms;
×
NEW
2826
  type_table_t* types = terms->types;
×
NEW
2827
  function_type_t* fun = function_type_desc(types, tau);
×
2828
  uint32_t i, idx;
NEW
2829
  term_t result = NULL_TERM;
×
NEW
2830
  term_t vars[fun->ndom];
×
2831
  ivector_t flat_args;
2832

2833
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2834
  assert(nleaves == type_leaf_count(pre, tau));
2835

NEW
2836
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2837
    vars[i] = new_variable(terms, fun->domain[i]);
×
2838
  }
2839

NEW
2840
  init_ivector(&flat_args, 0);
×
NEW
2841
  for (i = 0; i < fun->ndom; ++i) {
×
NEW
2842
    collect_flat_leaf_terms(pre, vars[i], fun->domain[i], &flat_args);
×
2843
  }
2844

NEW
2845
  term_t leaf_apps[nleaves];
×
NEW
2846
  for (i = 0; i < nleaves; ++i) {
×
NEW
2847
    leaf_apps[i] = mk_application(&pre->tm, leaves[i], flat_args.size, (term_t*) flat_args.data);
×
NEW
2848
    if (leaf_apps[i] == NULL_TERM) {
×
NEW
2849
      goto done;
×
2850
    }
2851
  }
2852

NEW
2853
  idx = 0;
×
NEW
2854
  term_t body = build_term_from_flat(pre, fun->range, leaf_apps, &idx);
×
NEW
2855
  if (body == NULL_TERM || idx != nleaves) {
×
NEW
2856
    goto done;
×
2857
  }
2858

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

NEW
2861
 done:
×
NEW
2862
  delete_ivector(&flat_args);
×
NEW
2863
  return result;
×
2864
}
2865

2866
static
2867
term_t build_term_from_flat(preprocessor_t* pre, type_t tau, const term_t* flat, uint32_t* idx) {
15✔
2868
  type_table_t* types = pre->terms->types;
15✔
2869
  switch (type_kind(types, tau)) {
15✔
2870
  case TUPLE_TYPE: {
3✔
2871
    tuple_type_t* tuple = tuple_type_desc(types, tau);
3✔
2872
    uint32_t i, n = tuple->nelem;
3✔
2873
    term_t elem[n];
3✔
2874
    for (i = 0; i < n; ++i) {
9✔
2875
      elem[i] = build_term_from_flat(pre, tuple->elem[i], flat, idx);
6✔
2876
      if (elem[i] == NULL_TERM) {
6✔
NEW
2877
        return NULL_TERM;
×
2878
      }
2879
    }
2880
    return mk_tuple(&pre->tm, n, elem);
3✔
2881
  }
2882

NEW
2883
  case FUNCTION_TYPE: {
×
NEW
2884
    uint32_t n = type_leaf_count(pre, tau);
×
NEW
2885
    term_t f = merge_blasted_function_term(pre, tau, flat + *idx, n);
×
NEW
2886
    *idx += n;
×
NEW
2887
    return f;
×
2888
  }
2889

2890
  default: {
12✔
2891
    term_t t = flat[*idx];
12✔
2892
    (*idx)++;
12✔
2893
    return t;
12✔
2894
  }
2895
  }
2896
}
2897

2898
static
2899
term_t mk_unblasted_function_leaf_lambda(preprocessor_t* pre, term_t atom, uint32_t leaf_i, type_t leaf_type) {
9✔
2900
  term_table_t* terms = pre->terms;
9✔
2901
  type_table_t* types = terms->types;
9✔
2902
  function_type_t* atom_fun = function_type_desc(types, term_type(terms, atom));
9✔
2903
  function_type_t* leaf_fun = function_type_desc(types, leaf_type);
9✔
2904
  uint32_t flat_n = leaf_fun->ndom;
9✔
2905
  uint32_t i, idx;
2906
  term_t flat_vars[flat_n];
9✔
2907
  term_t orig_args[atom_fun->ndom];
9✔
2908
  term_t app;
2909
  term_t body = NULL_TERM;
9✔
2910
  term_t result = NULL_TERM;
9✔
2911
  ivector_t codom_leaves;
2912

2913
  for (i = 0; i < flat_n; ++i) {
21✔
2914
    flat_vars[i] = new_variable(terms, leaf_fun->domain[i]);
12✔
2915
  }
2916

2917
  idx = 0;
9✔
2918
  for (i = 0; i < atom_fun->ndom; ++i) {
18✔
2919
    orig_args[i] = build_term_from_flat(pre, atom_fun->domain[i], flat_vars, &idx);
9✔
2920
    if (orig_args[i] == NULL_TERM) {
9✔
NEW
2921
      return NULL_TERM;
×
2922
    }
2923
  }
2924
  assert(idx == flat_n);
2925

2926
  app = mk_application(&pre->tm, atom, atom_fun->ndom, orig_args);
9✔
2927
  if (app == NULL_TERM) {
9✔
NEW
2928
    return NULL_TERM;
×
2929
  }
2930

2931
  init_ivector(&codom_leaves, 0);
9✔
2932
  collect_flat_leaf_terms(pre, app, atom_fun->range, &codom_leaves);
9✔
2933
  if (leaf_i < codom_leaves.size) {
9✔
2934
    body = codom_leaves.data[leaf_i];
9✔
2935
  }
2936
  if (body != NULL_TERM) {
9✔
2937
    result = mk_lambda(&pre->tm, flat_n, flat_vars, body);
9✔
2938
  }
2939
  delete_ivector(&codom_leaves);
9✔
2940

2941
  return result;
9✔
2942
}
2943

2944
static
2945
void collect_function_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
5✔
2946
  type_table_t* types = pre->terms->types;
5✔
2947
  ivector_t leaf_types;
2948
  uint32_t i;
2949

2950
  assert(type_kind(types, tau) == FUNCTION_TYPE);
2951

2952
  init_ivector(&leaf_types, 0);
5✔
2953
  function_type_collect_blasted(types, tau, &leaf_types);
5✔
2954
  for (i = 0; i < leaf_types.size; ++i) {
14✔
2955
    term_t leaf = mk_unblasted_function_leaf_lambda(pre, base, i, leaf_types.data[i]);
9✔
2956
    if (leaf != NULL_TERM) {
9✔
2957
      ivector_push(out, leaf);
9✔
2958
    }
2959
  }
2960
  delete_ivector(&leaf_types);
5✔
2961
}
5✔
2962

2963
static
2964
void collect_flat_leaf_terms(preprocessor_t* pre, term_t base, type_t tau, ivector_t* out) {
40✔
2965
  type_table_t* types = pre->terms->types;
40✔
2966

2967
  switch (type_kind(types, tau)) {
40✔
2968
  case TUPLE_TYPE: {
13✔
2969
    tuple_type_t* tuple = tuple_type_desc(types, tau);
13✔
2970
    uint32_t i;
2971
    for (i = 0; i < tuple->nelem; ++i) {
39✔
2972
      term_t child = mk_select(&pre->tm, i, base);
26✔
2973
      collect_flat_leaf_terms(pre, child, tuple->elem[i], out);
26✔
2974
    }
2975
    break;
13✔
2976
  }
2977

2978
  case FUNCTION_TYPE:
5✔
2979
    collect_function_leaf_terms(pre, base, tau, out);
5✔
2980
    break;
5✔
2981

2982
  default:
22✔
2983
    ivector_push(out, base);
22✔
2984
    break;
22✔
2985
  }
2986
}
40✔
2987

2988
static
2989
bool substitution_has_var(const ivector_t* vars, term_t x) {
14✔
2990
  uint32_t i;
2991
  for (i = 0; i < vars->size; ++i) {
36✔
2992
    if (vars->data[i] == x) {
22✔
NEW
2993
      return true;
×
2994
    }
2995
  }
2996
  return false;
14✔
2997
}
2998

2999
term_t preprocessor_unblast_term(preprocessor_t* pre, term_t t) {
44✔
3000
  term_table_t* terms = pre->terms;
44✔
3001
  ivector_t vars, maps;
3002
  ivector_t leaves, accessors;
3003
  uint32_t i, j;
3004
  term_t out;
3005

3006
  if (pre->tuple_blast_atoms.size == 0) {
44✔
3007
    return t;
40✔
3008
  }
3009

3010
  init_ivector(&vars, 0);
4✔
3011
  init_ivector(&maps, 0);
4✔
3012
  init_ivector(&leaves, 0);
4✔
3013
  init_ivector(&accessors, 0);
4✔
3014

3015
  for (i = 0; i < pre->tuple_blast_atoms.size; ++i) {
9✔
3016
    term_t atom = pre->tuple_blast_atoms.data[i];
5✔
3017
    type_t atom_type = term_type(terms, atom);
5✔
3018
    tuple_blast_get(pre, atom, &leaves);
5✔
3019
    ivector_reset(&accessors);
5✔
3020
    collect_flat_leaf_terms(pre, atom, atom_type, &accessors);
5✔
3021
    if (leaves.size != accessors.size) {
5✔
NEW
3022
      continue;
×
3023
    }
3024
    for (j = 0; j < leaves.size; ++j) {
19✔
3025
      term_t x = leaves.data[j];
14✔
3026
      term_t u = accessors.data[j];
14✔
3027
      term_kind_t k = term_kind(terms, x);
14✔
3028
      bool is_var = (k == UNINTERPRETED_TERM || k == VARIABLE);
14✔
3029
      if (x != u && is_var && !substitution_has_var(&vars, x)) {
14✔
3030
        ivector_push(&vars, x);
14✔
3031
        ivector_push(&maps, u);
14✔
3032
      }
3033
    }
3034
  }
3035

3036
  if (vars.size == 0) {
4✔
NEW
3037
    out = t;
×
3038
  } else {
3039
    term_subst_t subst;
3040
    init_term_subst(&subst, &pre->tm, vars.size, (term_t*) vars.data, (term_t*) maps.data);
4✔
3041
    out = apply_term_subst(&subst, t);
4✔
3042
    delete_term_subst(&subst);
4✔
3043
  }
3044

3045
  delete_ivector(&accessors);
4✔
3046
  delete_ivector(&leaves);
4✔
3047
  delete_ivector(&maps);
4✔
3048
  delete_ivector(&vars);
4✔
3049

3050
  return out;
4✔
3051
}
3052

3053
void preprocessor_build_model(preprocessor_t* pre, model_t* model) {
48✔
3054
  uint32_t i = 0;
48✔
3055
  /* Lazily-initialized evaluator used only on the keep_subst=0 path
3056
   * (model->has_alias is false). When keep_subst=1, this is never
3057
   * touched and the alias-based lazy resolution handles everything. */
3058
  evaluator_t eval;
3059
  bool eval_inited = false;
48✔
3060
  /* TEMP DIAG (windows release+thread-safety mcsat_tuples failure) */
3061
  PP_DIAG("[pp_build_model] enter, has_alias=%d, eqs=%u\n",
48✔
3062
          (int) model->has_alias, (unsigned) pre->equalities_list.size);
3063
  for (i = 0; i < pre->equalities_list.size; ++ i) {
66✔
3064
    term_t eq = pre->equalities_list.data[i];
18✔
3065
    term_t eq_var = preprocessor_get_eq_solved_var(pre, eq);
18✔
3066
    PP_DIAG("[pp_build_model] i=%u eq=%d eq_var=%d\n",
18✔
3067
            (unsigned) i, (int) eq, (int) eq_var);
3068
    if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
18✔
3069
      mcsat_trace_printf(pre->tracer, "eq = ");
×
3070
      trace_term_ln(pre->tracer, pre->terms, eq);
×
3071
      mcsat_trace_printf(pre->tracer, "\neq_var = ");
×
3072
      trace_term_ln(pre->tracer, pre->terms, eq_var);
×
3073
      mcsat_trace_printf(pre->tracer, "\n");
×
3074
    }
3075
    // Some equalities are solved, but then reasserted in the solver
3076
    // these already have a model
3077
    if (model_find_term_value(model, eq_var) != null_value) {
18✔
NEW
3078
      PP_DIAG("[pp_build_model]   already mapped, continue\n");
×
UNCOV
3079
      continue;
×
3080
    }
3081
    // Some equalities are marked, but not solved. These we skip as they
3082
    // are already set in the model
3083
    if (preprocessor_get(pre, eq_var) == eq_var) {
18✔
NEW
3084
      PP_DIAG("[pp_build_model]   not solved, continue\n");
×
UNCOV
3085
      continue;
×
3086
    }
3087
    term_kind_t eq_kind = term_kind(pre->terms, eq);
18✔
3088
    PP_DIAG("[pp_build_model]   eq_kind=%d\n", (int) eq_kind);
18✔
3089
    composite_term_t* eq_desc = get_composite(pre->terms, eq_kind, eq);
18✔
3090
    PP_DIAG("[pp_build_model]   eq_desc=%p arity=%u\n",
18✔
3091
            (void*) eq_desc, eq_desc ? (unsigned) eq_desc->arity : 0u);
3092
    term_t eq_subst = eq_desc->arity > 1
36✔
3093
      ? (eq_desc->arg[0] == eq_var ? eq_desc->arg[1] : eq_desc->arg[0])
16✔
3094
      : zero_term;
34✔
3095
    PP_DIAG("[pp_build_model]   eq_subst=%d\n", (int) eq_subst);
18✔
3096
    if (model->has_alias) {
18✔
3097
      /* Standard path: record the substitution and let the model
3098
       * evaluator resolve eq_var lazily via eval_term(eq_subst). */
3099
      model_add_substitution(model, eq_var, eq_subst);
17✔
3100
    } else {
3101
      /* keep_subst=0 path: model has no alias table, so
3102
       * model_add_substitution would assert-fail on has_alias.
3103
       * Concretely evaluate eq_subst now and bind eq_var to that
3104
       * value. This is sound: eq_var was eliminated by the
3105
       * preprocessor via eq_var = eq_subst, so any model satisfying
3106
       * eq must agree. The user asked us not to keep substitutions,
3107
       * but they still need consistent values for downstream queries
3108
       * (in particular, tuple-blasted leaves -- see
3109
       * preprocessor_build_tuple_model below, which would otherwise
3110
       * silently drop tuple atoms whose leaves remain unmapped).
3111
       * If eval fails (e.g., eq_subst transitively depends on another
3112
       * not-yet-mapped eq_var), fall back to a fresh default value. */
3113
      if (!eval_inited) {
1✔
3114
        PP_DIAG("[pp_build_model]   init_evaluator\n");
1✔
3115
        init_evaluator(&eval, model);
1✔
3116
        eval_inited = true;
1✔
3117
        PP_DIAG("[pp_build_model]   init_evaluator OK\n");
1✔
3118
      }
3119
      PP_DIAG("[pp_build_model]   eval_in_model(%d)\n", (int) eq_subst);
1✔
3120
      value_t v = eval_in_model(&eval, eq_subst);
1✔
3121
      PP_DIAG("[pp_build_model]   eval_in_model -> v=%d\n", (int) v);
1✔
3122
      if (v < 0) {
1✔
NEW
3123
        type_t eq_var_tau = term_type(pre->terms, eq_var);
×
NEW
3124
        PP_DIAG("[pp_build_model]   vtbl_make_object(tau=%d)\n", (int) eq_var_tau);
×
NEW
3125
        v = vtbl_make_object(model_get_vtbl(model), eq_var_tau);
×
NEW
3126
        PP_DIAG("[pp_build_model]   vtbl_make_object -> v=%d\n", (int) v);
×
3127
      }
3128
      if (v >= 0) {
1✔
3129
        PP_DIAG("[pp_build_model]   model_map_term(eq_var=%d, v=%d)\n",
1✔
3130
                (int) eq_var, (int) v);
3131
        model_map_term(model, eq_var, v);
1✔
3132
        PP_DIAG("[pp_build_model]   model_map_term OK\n");
1✔
NEW
3133
      } else if (trace_enabled(pre->tracer, "mcsat::preprocess")) {
×
NEW
3134
        mcsat_trace_printf(pre->tracer,
×
3135
                           "preprocessor_build_model: failed to bind eq_var ");
NEW
3136
        trace_term_ln(pre->tracer, pre->terms, eq_var);
×
3137
      }
3138
    }
3139
  }
3140

3141
  if (eval_inited) {
48✔
3142
    PP_DIAG("[pp_build_model] delete_evaluator\n");
1✔
3143
    delete_evaluator(&eval);
1✔
3144
    PP_DIAG("[pp_build_model] delete_evaluator OK\n");
1✔
3145
  }
3146

3147
  PP_DIAG("[pp_build_model] calling preprocessor_build_tuple_model\n");
48✔
3148
  preprocessor_build_tuple_model(pre, model);
48✔
3149
  PP_DIAG("[pp_build_model] exit\n");
48✔
3150
}
48✔
3151

3152

3153
static inline
3154
void preprocessor_gc_mark_term(preprocessor_t* pre, term_t t) {
1,272✔
3155
  term_table_set_gc_mark(pre->terms, index_of(t));
1,272✔
3156
  type_table_set_gc_mark(pre->terms->types, term_type(pre->terms, t));
1,272✔
3157
}
1,272✔
3158

3159
void preprocessor_gc_mark(preprocessor_t* pre) {
5✔
3160
  uint32_t i;
3161

3162
  /* Drop the type/term memoization caches before any GC sweep that may
3163
   * follow. These caches are keyed on raw type/term IDs (`tau` and
3164
   * `index_of(t)`), and Yices recycles those IDs for new types/terms once
3165
   * the originals are swept (see `indexed_table_free` under src/terms).
3166
   * If we left stale entries in place, a freshly recycled ID could pick up
3167
   * a cached classification that belongs to the freed term/type, which
3168
   * would then drive the iterative tuple-blast dispatch down the wrong
3169
   * arm. Clearing here is cheap (the caches repopulate on first use) and
3170
   * makes the "no invalidation needed for the lifetime of the table"
3171
   * comments on these caches actually true: each "lifetime" now ends at
3172
   * GC, where we reset.
3173
   *
3174
   * `tuple_blast_map`/`preprocess_map`/`purification_map` are kept --
3175
   * their entries are explicitly marked alive below, so they survive GC
3176
   * by construction. Only the *opportunistic* memos need to be dropped. */
3177
  int_hmap_reset(&pre->type_is_tuple_free_cache);
5✔
3178
  int_hmap_reset(&pre->type_leaf_count_cache);
5✔
3179
  int_hmap_reset(&pre->term_has_tuples_cache);
5✔
3180

3181
  for (i = 0; i < pre->preprocess_map_list.size; ++ i) {
486✔
3182
    term_t t = pre->preprocess_map_list.data[i];
481✔
3183
    preprocessor_gc_mark_term(pre, t);
481✔
3184
    term_t t_pre = preprocessor_get(pre, t);
481✔
3185
    preprocessor_gc_mark_term(pre, t_pre);
481✔
3186
  }
3187

3188
  for (i = 0; i < pre->equalities_list.size; ++ i) {
5✔
3189
    term_t t = pre->equalities_list.data[i];
×
3190
    preprocessor_gc_mark_term(pre, t);
×
3191
  }
3192

3193
  for (i = 0; i < pre->tuple_blast_list.size; ++i) {
141✔
3194
    term_t t = pre->tuple_blast_list.data[i];
136✔
3195
    int_hmap_pair_t* rec = int_hmap_find(&pre->tuple_blast_map, t);
136✔
3196
    uint32_t j, n, offset;
3197
    assert(rec != NULL);
3198
    preprocessor_gc_mark_term(pre, t);
136✔
3199
    offset = rec->val;
136✔
3200
    n = pre->tuple_blast_data.data[offset];
136✔
3201
    for (j = 0; j < n; ++j) {
272✔
3202
      preprocessor_gc_mark_term(pre, pre->tuple_blast_data.data[offset + 1 + j]);
136✔
3203
    }
3204
  }
3205

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

© 2026 Coveralls, Inc