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

SRI-CSL / yices2 / 25368527405

05 May 2026 09:28AM UTC coverage: 66.87% (+0.2%) from 66.687%
25368527405

Pull #611

github

disteph
Merge branch 'master' into mcsat-supplement-cdclt

Conflicts resolved with a hybrid of both sides:

- tests/regress/run_test.sh: keep this branch's explicit --dpllt for
  the non-mcsat side of /both/ tests (symmetric with --mcsat), because
  yices' default solver path is heuristically chosen and is not
  guaranteed to be DPLL(T) for every logic. Also adopt master's new
  per-mode .mcsat.gold / .dpllt.gold override mechanism so tests that
  intentionally differ between the two solvers can supply separate
  gold files.

- tests/regress/both/README.md: document the symmetric --mcsat /
  --dpllt pair and the per-mode gold-override convention in one place.
Pull Request #611: Wrap MCSAT as a Nelson-Oppen theory solver in CDCL(T) architecture

690 of 1006 new or added lines in 15 files covered. (68.59%)

2 existing lines in 2 files now uncovered.

84342 of 126128 relevant lines covered (66.87%)

1634859.8 hits per line

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

84.3
/src/solvers/egraph/egraph.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
/*
20
 * EGRAPH CONSTRUCTION AND MAIN OPERATIONS
21
 */
22

23
#include <stdint.h>
24
#include <stdbool.h>
25
#include <assert.h>
26
#include <inttypes.h>
27

28
#include "io/tracer.h"
29
#include "solvers/egraph/composites.h"
30
#include "solvers/egraph/egraph.h"
31
#include "solvers/egraph/egraph_explanations.h"
32
#include "solvers/egraph/egraph_utils.h"
33
#include "solvers/egraph/theory_explanations.h"
34
#include "utils/bit_tricks.h"
35
#include "utils/hash_functions.h"
36
#include "utils/index_vectors.h"
37
#include "utils/memalloc.h"
38
#include "utils/ptr_partitions.h"
39

40
#include "api/yices_globals.h"
41
#include "mt/thread_macros.h"
42

43
#define TRACE 0
44
#define TRACE_FCHECK 0
45

46
#if TRACE || TRACE_FCHECK
47

48
#include <stdio.h>
49

50
#include "solvers/cdcl/smt_core_printer.h"
51
#include "solvers/egraph/egraph_printer.h"
52
#include "solvers/cdcl/smt_core_printer.h"
53

54
#endif
55

56

57
/*
58
 * Select variant implementations
59
 */
60
#define CONSERVATIVE_DISEQ_AXIOMS 0
61

62

63
/*****************
64
 *  CLASS TABLE  *
65
 ****************/
66

67
/*
68
 * Initialization: n == initial size
69
 */
70
static void init_class_table(class_table_t *tbl, uint32_t n) {
4,792✔
71
  uint32_t i;
72
  assert(n <  MAX_CLASS_TABLE_SIZE);
73

74
  tbl->size = n;
4,792✔
75
  tbl->nclasses = 0;
4,792✔
76

77
  tbl->root = (occ_t *) safe_malloc(n * sizeof(occ_t));
4,792✔
78
  tbl->dmask = (uint32_t *) safe_malloc(n * sizeof(uint32_t));
4,792✔
79
  tbl->parents = (use_vector_t *) safe_malloc(n * sizeof(use_vector_t));
4,792✔
80
  tbl->etype = (unsigned char *) safe_malloc(n * sizeof(unsigned char));
4,792✔
81
  tbl->thvar = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
4,792✔
82

83
  // initialize all parent vectors (all empty)
84
  for (i=0; i<n; i++) {
963,192✔
85
    init_use_vector(tbl->parents + i, 0);
958,400✔
86
  }
87
}
4,792✔
88

89

90
/*
91
 * Increase size by 50%
92
 */
93
static void extend_class_table(class_table_t *tbl) {
239✔
94
  uint32_t i, n;
95

96
  n = tbl->size + 1;
239✔
97
  n += n>>1;
239✔
98

99
  if (n >= MAX_CLASS_TABLE_SIZE) {
239✔
100
    out_of_memory();
×
101
  }
102

103
  tbl->root = (occ_t *) safe_realloc(tbl->root, n * sizeof(occ_t));
239✔
104
  tbl->dmask = (uint32_t *) safe_realloc(tbl->dmask, n * sizeof(eterm_t));
239✔
105
  tbl->parents = (use_vector_t *) safe_realloc(tbl->parents, n * sizeof(use_vector_t));
239✔
106
  tbl->etype = (unsigned char *) safe_realloc(tbl->etype, n * sizeof(unsigned char));
239✔
107
  tbl->thvar = (thvar_t *) safe_realloc(tbl->thvar, n * sizeof(thvar_t));
239✔
108

109
  // initialize the new parent vectors (all empty)
110
  for (i=tbl->size; i<n; i++) {
78,807✔
111
    init_use_vector(tbl->parents + i, 0);
78,568✔
112
  }
113

114
  tbl->size = n;
239✔
115
}
239✔
116

117

118
/*
119
 * Allocate a new class
120
 * - nothing is initialized, except the parent vector
121
 * - the parent vector is empty
122
 */
123
static class_t alloc_class(class_table_t *tbl) {
93,641✔
124
  class_t i;
125

126
  i = tbl->nclasses;
93,641✔
127
  if (i >= tbl->size) {
93,641✔
128
    extend_class_table(tbl);
239✔
129
  }
130

131
  tbl->nclasses ++;
93,641✔
132
  assert(tbl->parents[i].nelems == 0);
133
  return i;
93,641✔
134
}
135

136

137

138
/*
139
 * Initialize a singleton class c with unique element pos_occ(t)
140
 * - dmask must be 0x1 if t is a constant, 0 otherwise
141
 * - tau = type of t
142
 * - x = theory variable of t
143
 */
144
static inline void init_class(class_table_t *tbl, class_t c, eterm_t t, uint32_t dmask, etype_t tau, thvar_t x) {
93,641✔
145
  tbl->root[c] = pos_occ(t);
93,641✔
146
  tbl->dmask[c] = dmask;
93,641✔
147
  tbl->etype[c] = tau;
93,641✔
148
  tbl->thvar[c] = x;
93,641✔
149
}
93,641✔
150

151

152
/*
153
 * Cleanup class c: free its parent vector if it's large
154
 * - its use vector must be empty and it must contain a single term
155
 */
156
static void free_parents(class_table_t *tbl, class_t c) {
6,235✔
157
  assert(0 < c && c < tbl->nclasses && tbl->parents[c].nelems == 0);
158

159
  // to save memory: free parent vector if it's large
160
  if (tbl->parents[c].size >= PARENT_DELETION_SIZE) {
6,235✔
161
    delete_use_vector(tbl->parents + c);
6✔
162
    init_use_vector(tbl->parents + c, 0);
6✔
163
  } else {
164
    reset_use_vector(tbl->parents + c);
6,229✔
165
  }
166
}
6,235✔
167

168

169

170

171
/*
172
 * Deletion
173
 */
174
static void delete_class_table(class_table_t *tbl) {
4,791✔
175
  uint32_t i;
176

177
  for (i=0; i<tbl->size; i++) {
1,041,559✔
178
    delete_use_vector(tbl->parents + i);
1,036,768✔
179
  }
180
  safe_free(tbl->parents);
4,791✔
181
  safe_free(tbl->root);
4,791✔
182
  safe_free(tbl->dmask);
4,791✔
183
  safe_free(tbl->etype);
4,791✔
184
  safe_free(tbl->thvar);
4,791✔
185

186
  tbl->root = NULL;
4,791✔
187
  tbl->dmask = NULL;
4,791✔
188
  tbl->parents = NULL;
4,791✔
189
  tbl->etype = NULL;
4,791✔
190
  tbl->thvar = NULL;
4,791✔
191
}
4,791✔
192

193

194
/*
195
 * Reset the class table
196
 */
197
static void reset_class_table(class_table_t *tbl) {
6✔
198
  uint32_t i;
199

200
  for (i=0; i<tbl->nclasses; i++) {
12✔
201
    if (tbl->parents[i].size >= PARENT_DELETION_SIZE) {
6✔
202
      delete_use_vector(tbl->parents + i);
×
203
      init_use_vector(tbl->parents + i, 0);
×
204
    } else {
205
      reset_use_vector(tbl->parents + i);
6✔
206
    }
207
  }
208

209
  tbl->nclasses = 0;
6✔
210
}
6✔
211

212

213

214
/****************
215
 *  TERM TABLE  *
216
 ***************/
217

218
/*
219
 * Initialization:
220
 * - n = initial size.
221
 */
222
static void init_eterm_table(eterm_table_t *tbl, uint32_t n) {
4,792✔
223
  assert(n < MAX_ETERM_TABLE_SIZE);
224

225
  tbl->size = n;
4,792✔
226
  tbl->nterms = 0;
4,792✔
227

228
  tbl->body = (composite_t **) safe_malloc(n * sizeof(composite_t *));
4,792✔
229
  tbl->label = (elabel_t *) safe_malloc(n * sizeof(elabel_t));
4,792✔
230
  tbl->next = (occ_t *) safe_malloc(n * sizeof(occ_t));
4,792✔
231
  tbl->edge = (int32_t *) safe_malloc(n * sizeof(int32_t));
4,792✔
232
  tbl->thvar = (thvar_t *) safe_malloc(n * sizeof(thvar_t));
4,792✔
233
  tbl->mark = allocate_bitvector(n);
4,792✔
234
  tbl->real_type = (type_t *) safe_malloc(n * sizeof(type_t));
4,792✔
235
}
4,792✔
236

237
/*
238
 * Increase size by 50%
239
 */
240
static void extend_eterm_table(eterm_table_t *tbl) {
239✔
241
  uint32_t n;
242

243
  n = tbl->size + 1;
239✔
244
  n += n >> 1;
239✔
245

246
  if (n >= MAX_ETERM_TABLE_SIZE) {
239✔
247
    out_of_memory();
×
248
  }
249

250
  tbl->size = n;
239✔
251

252
  tbl->body = (composite_t **) safe_realloc(tbl->body, n * sizeof(composite_t *));
239✔
253
  tbl->label = (elabel_t *) safe_realloc(tbl->label, n * sizeof(elabel_t));
239✔
254
  tbl->next = (occ_t *) safe_realloc(tbl->next, n * sizeof(occ_t));
239✔
255
  tbl->edge = (int32_t *) safe_realloc(tbl->edge, n * sizeof(int32_t));
239✔
256
  tbl->thvar = (thvar_t *) safe_realloc(tbl->thvar, n * sizeof(thvar_t));
239✔
257
  tbl->mark = extend_bitvector(tbl->mark, n);
239✔
258
  tbl->real_type = (type_t *) safe_realloc(tbl->real_type, n * sizeof(type_t));
239✔
259
}
239✔
260

261

262
/*
263
 * Allocate a new term with the following initialization:
264
 * - body = cmp
265
 * - edge = null_edge
266
 * - thvar = null_var
267
 * - label = null_label
268
 * - successor = itself
269
 * - real_type = NULL_TYPE
270
 */
271
static eterm_t new_eterm(eterm_table_t *tbl, composite_t *b) {
93,641✔
272
  eterm_t t;
273

274
  t = tbl->nterms;
93,641✔
275
  tbl->nterms ++;
93,641✔
276
  if (t >= tbl->size) {
93,641✔
277
    extend_eterm_table(tbl);
239✔
278
  }
279

280
  tbl->body[t] = b;
93,641✔
281
  tbl->label[t] = null_label;
93,641✔
282
  tbl->next[t] = pos_occ(t);
93,641✔
283
  tbl->edge[t] = null_edge;
93,641✔
284
  tbl->thvar[t] = null_thvar;
93,641✔
285
  clr_bit(tbl->mark, t);
93,641✔
286
  tbl->real_type[t] = NULL_TYPE;
93,641✔
287

288
  return t;
93,641✔
289
}
290

291

292
/*
293
 * Delete the full table
294
 */
295
static void delete_eterm_table(eterm_table_t *tbl) {
4,791✔
296
  uint32_t i, n;
297

298
  n = tbl->nterms;
4,791✔
299
  for (i=0; i<n; i++) {
92,190✔
300
    if (composite_body(tbl->body[i])) {
87,399✔
301
      safe_free(tbl->body[i]);
63,405✔
302
    }
303
  }
304

305
  safe_free(tbl->body);
4,791✔
306
  safe_free(tbl->label);
4,791✔
307
  safe_free(tbl->next);
4,791✔
308
  safe_free(tbl->edge);
4,791✔
309
  safe_free(tbl->thvar);
4,791✔
310
  delete_bitvector(tbl->mark);
4,791✔
311
  safe_free(tbl->real_type);
4,791✔
312

313
  tbl->body = NULL;
4,791✔
314
  tbl->label = NULL;
4,791✔
315
  tbl->next = NULL;
4,791✔
316
  tbl->edge = NULL;
4,791✔
317
  tbl->thvar = NULL;
4,791✔
318
  tbl->mark = NULL;
4,791✔
319
  tbl->real_type = NULL;
4,791✔
320
}
4,791✔
321

322

323

324
/*
325
 * Reset the term table: remove all terms
326
 * - atoms are deleted by emptying the egraph's atom store
327
 *   so we don't delete them here
328
 */
329
static void reset_eterm_table(eterm_table_t *tbl) {
6✔
330
  uint32_t i, n;
331

332
  n = tbl->nterms;
6✔
333
  for (i=0; i<n; i++) {
12✔
334
    if (composite_body(tbl->body[i])) {
6✔
335
      safe_free(tbl->body[i]);
×
336
    }
337
  }
338

339
  tbl->nterms = 0;
6✔
340
}
6✔
341

342

343

344

345
/********************
346
 *  DISTINCT TABLE  *
347
 *******************/
348

349
static void init_distinct_table(distinct_table_t *tbl) {
4,798✔
350
  tbl->npreds = 1;
4,798✔
351
  tbl->distinct[0] = NULL;
4,798✔
352
}
4,798✔
353

354
static inline void reset_distinct_table(distinct_table_t *tbl) {
6✔
355
  init_distinct_table(tbl);
6✔
356
}
6✔
357

358

359

360
/**********************
361
 *  LAMBDA TAG TABLE  *
362
 *********************/
363

364
/*
365
 * Allocate and initialize a descriptor:
366
 * - n = arity
367
 * - dom[0 ... n-1] = types
368
 */
369
static ltag_desc_t *new_ltag_desc(uint32_t n, type_t *dom) {
×
370
  ltag_desc_t *tmp;
371
  uint32_t i;
372

373
  if (n > MAX_LTAG_DESC_ARITY) {
×
374
    /*
375
     * This should never happen since n <= YICES_MAX_ARITY < MAX_LTAG_DESC_ARITY.
376
     * But we may change this one day.
377
     */
378
    out_of_memory();
×
379
  }
380

381
  tmp = (ltag_desc_t *) safe_malloc(sizeof(ltag_desc_t) + n * sizeof(type_t));
×
382
  tmp->arity = n;
×
383
  for (i=0; i<n; i++) {
×
384
    tmp->dom[i] = dom[i];
×
385
  }
386

387
  return tmp;
×
388
}
389

390

391
/*
392
 * Check whether d matches n and dom
393
 */
394
static bool ltag_desc_matches(ltag_desc_t *d, uint32_t n, type_t *dom) {
×
395
  uint32_t i;
396

397
  if (d->arity != n) {
×
398
    return false;
×
399
  }
400

401
  for (i=0; i<n; i++) {
×
402
    if (dom[i] != d->dom[i]) {
×
403
      return false;
×
404
    }
405
  }
406

407
  return true;
×
408
}
409

410

411
/*
412
 * Initialize/delete/reset
413
 */
414
static void init_ltag_table(ltag_table_t *tbl) {
4,792✔
415
  tbl->size = 0;
4,792✔
416
  tbl->ntags = 0;
4,792✔
417
  tbl->data = NULL;
4,792✔
418
}
4,792✔
419

420
static void delete_ltag_table(ltag_table_t *tbl) {
4,791✔
421
  uint32_t i, n;
422

423
  n = tbl->ntags;
4,791✔
424
  for (i=0; i<n; i++) {
4,791✔
425
    safe_free(tbl->data[i]);
×
426
  }
427
  safe_free(tbl->data);
4,791✔
428
  tbl->data = NULL;
4,791✔
429
}
4,791✔
430

431
static void reset_ltag_table(ltag_table_t *tbl) {
6✔
432
  uint32_t i, n;
433

434
  n = tbl->ntags;
6✔
435
  for (i=0; i<n; i++) {
6✔
436
    safe_free(tbl->data[i]);
×
437
  }
438
  tbl->ntags = 0;
6✔
439
}
6✔
440

441

442
/*
443
 * Make room in tbl
444
 */
445
static void extend_ltag_table(ltag_table_t *tbl) {
×
446
  uint32_t n;
447

448
  n = tbl->size;
×
449
  if (n == 0) {
×
450
    // start with the default size
451
    n = DEF_LTAG_TABLE_SIZE;
×
452
    assert(n <= MAX_LTAG_TABLE_SIZE);
453

454
    tbl->data = (ltag_desc_t **) safe_malloc(n * sizeof(ltag_desc_t *));
×
455
    tbl->size = n;
×
456

457
  } else {
458
    // increase size by 50%
459
    n ++;
×
460
    n += n >> 1;
×
461

462
    if (n > MAX_LTAG_TABLE_SIZE) {
×
463
      out_of_memory();
×
464
    }
465

466
    tbl->data = (ltag_desc_t **) safe_realloc(tbl->data, n * sizeof(ltag_desc_t *));
×
467
    tbl->size = n;
×
468
  }
469
}
×
470

471

472
/*
473
 * Allocate a new tag and build the corresponding descriptor
474
 * - n = arity
475
 * - dom[0 ... n-1] = types
476
 */
477
static int32_t ltag_table_add_descriptor(ltag_table_t *tbl, uint32_t n, type_t *dom) {
×
478
  uint32_t i;
479

480
  i = tbl->ntags;
×
481
  if (i == tbl->size) {
×
482
    extend_ltag_table(tbl);
×
483
  }
484
  assert(i < tbl->size);
485

486
  tbl->data[i] = new_ltag_desc(n, dom);
×
487
  tbl->ntags ++;
×
488

489
  return i;
×
490
}
491

492

493

494
/*
495
 * Get a tag for dom[0 ... n-1]
496
 */
497
static int32_t ltag_table_get_tag(ltag_table_t *tbl, uint32_t n, type_t *dom) {
×
498
  uint32_t i, ntags;
499

500
  ntags = tbl->ntags;
×
501
  for (i=0; i<ntags; i++) {
×
502
    if (ltag_desc_matches(tbl->data[i], n, dom)) {
×
503
      return i;
×
504
    }
505
  }
506

507
  return ltag_table_add_descriptor(tbl, n, dom);
×
508
}
509

510

511

512
/*
513
 * Search for a tag:
514
 * - return -1 if nothing matches dom[0 ... n-1] in the table
515
 */
516
static int32_t ltag_table_find_tag(ltag_table_t *tbl, uint32_t n, type_t *dom) {
×
517
  uint32_t i, ntags;
518

519
  ntags = tbl->ntags;
×
520
  for (i=0; i<ntags; i++) {
×
521
    if (ltag_desc_matches(tbl->data[i], n, dom)) {
×
522
      return i;
×
523
    }
524
  }
525

526
  return -1;
×
527
}
528

529

530
/*
531
 * Get tag for the function type tau:
532
 * - types = the corresponding type table
533
 */
534
static int32_t lambda_tag_for_type(ltag_table_t *tbl, type_table_t *types, type_t tau) {
×
535
  function_type_t *d;
536

537
  d = function_type_desc(types, tau);
×
538
  return ltag_table_get_tag(tbl, d->ndom, d->domain);
×
539
}
540

541

542
/*
543
 * Check whether there's an existing tag for function type tau
544
 * - return the tag if it's found or -1 otherwise
545
 */
546
static int32_t find_lambda_tag_for_type(ltag_table_t *tbl, type_table_t *types, type_t tau) {
×
547
  function_type_t *d;
548

549
  d = function_type_desc(types, tau);
×
550
  return ltag_table_find_tag(tbl, d->ndom, d->domain);
×
551
}
552

553

554

555

556
/***********************
557
 *  PROPAGATION QUEUE  *
558
 **********************/
559

560
/*
561
 * Initialize:
562
 * - n = initial size
563
 * - m = initial number of levels
564
 */
565
static void init_egraph_stack(egraph_stack_t *stack, uint32_t n, uint32_t m) {
4,792✔
566
  assert(n < MAX_EGRAPH_STACK_SIZE && 0 < m && m < MAX_EGRAPH_STACK_LEVELS);
567

568
  stack->eq = (equeue_elem_t *) safe_malloc(n * sizeof(equeue_elem_t));
4,792✔
569
  stack->etag = (unsigned char *) safe_malloc(n * sizeof(unsigned char));
4,792✔
570
  stack->edata = (expl_data_t *) safe_malloc(n * sizeof(expl_data_t));
4,792✔
571
  stack->mark = allocate_bitvector(n);
4,792✔
572
  stack->top = 0;
4,792✔
573
  stack->prop_ptr = 0;
4,792✔
574
  stack->size = n;
4,792✔
575

576
  stack->level_index = (uint32_t *) safe_malloc(m * sizeof(uint32_t));
4,792✔
577
  stack->level_index[0] = 0;
4,792✔
578
  stack->nlevels = m;
4,792✔
579
}
4,792✔
580

581

582
/*
583
 * Extend the stack: increase size by 50%
584
 */
585
static void extend_egraph_stack(egraph_stack_t *stack) {
227✔
586
  uint32_t n;
587

588
  n = stack->size + 1;
227✔
589
  n += n >> 1;
227✔
590

591
  if (n >= MAX_EGRAPH_STACK_SIZE) {
227✔
592
    out_of_memory();
×
593
  }
594

595
  stack->eq = (equeue_elem_t *) safe_realloc(stack->eq, n * sizeof(equeue_elem_t));
227✔
596
  stack->etag = (unsigned char *) safe_realloc(stack->etag, n * sizeof(unsigned char));
227✔
597
  stack->edata = (expl_data_t *) safe_realloc(stack->edata, n * sizeof(expl_data_t));
227✔
598
  stack->mark = extend_bitvector(stack->mark, n);
227✔
599
  stack->size = n;
227✔
600
}
227✔
601

602

603
/*
604
 * Increase the number of levels by 50%
605
 */
606
static void increase_egraph_stack_levels(egraph_stack_t *stack) {
272✔
607
  uint32_t n;
608

609
  n = stack->nlevels + 1;
272✔
610
  n += n>>1;
272✔
611

612
  if (n >= MAX_EGRAPH_STACK_LEVELS) {
272✔
613
    out_of_memory();
×
614
  }
615

616
  stack->level_index = (uint32_t *) safe_realloc(stack->level_index, n * sizeof(uint32_t));
272✔
617
  stack->nlevels = n;
272✔
618
}
272✔
619

620

621

622
/*
623
 * Push equality (t1 == t2) on top of the stack
624
 * - return the new edge's index
625
 * - explanation for the new edge must be set outside this function.
626
 */
627
static int32_t egraph_stack_push_eq(egraph_stack_t *stack, occ_t t1, occ_t t2) {
8,559,385✔
628
  uint32_t i;
629

630
  i = stack->top;
8,559,385✔
631
  if (i >= stack->size) {
8,559,385✔
632
    extend_egraph_stack(stack);
227✔
633
  }
634
  clr_bit(stack->mark, i);
8,559,385✔
635
  stack->top = i+1;
8,559,385✔
636
  stack->eq[i].lhs = t1;
8,559,385✔
637
  stack->eq[i].rhs = t2;
8,559,385✔
638

639
  return i;
8,559,385✔
640
}
641

642

643

644
/*
645
 * Delete the stack
646
 */
647
static void delete_egraph_stack(egraph_stack_t *stack) {
4,791✔
648
  safe_free(stack->eq);
4,791✔
649
  safe_free(stack->etag);
4,791✔
650
  safe_free(stack->edata);
4,791✔
651
  safe_free(stack->level_index);
4,791✔
652
  delete_bitvector(stack->mark);
4,791✔
653

654
  stack->eq = NULL;
4,791✔
655
  stack->etag = NULL;
4,791✔
656
  stack->edata = NULL;
4,791✔
657
  stack->level_index = NULL;
4,791✔
658
  stack->mark = NULL;
4,791✔
659
}
4,791✔
660

661

662

663
/*
664
 * Empty the stack
665
 */
666
static void reset_egraph_stack(egraph_stack_t *stack) {
6✔
667
  stack->top = 0;
6✔
668
  stack->prop_ptr = 0;
6✔
669
  stack->level_index[0] = 0;
6✔
670
}
6✔
671

672

673

674

675
/****************
676
 *  UNDO STACK  *
677
 ***************/
678

679
/*
680
 * Initialize: n = size, m = number of levels
681
 */
682
static void init_undo_stack(undo_stack_t *stack, uint32_t n, uint32_t m) {
4,792✔
683
  assert(n < MAX_EGRAPH_STACK_SIZE && 0 < m && m < MAX_EGRAPH_STACK_LEVELS);
684

685
  stack->tag = (unsigned char *) safe_malloc(n * sizeof(unsigned char));
4,792✔
686
  stack->data = (undo_t *) safe_malloc(n * sizeof(undo_t));
4,792✔
687
  stack->top = 0;
4,792✔
688
  stack->size = n;
4,792✔
689

690
  stack->level_index = (uint32_t  *) safe_malloc(m * sizeof(uint32_t));
4,792✔
691
  stack->level_index[0] = 0;
4,792✔
692
  stack->nlevels = m;
4,792✔
693
}
4,792✔
694

695
/*
696
 * Extend by 50%
697
 */
698
static void extend_undo_stack(undo_stack_t *stack) {
214✔
699
  uint32_t n;
700

701
  n = stack->size + 1;
214✔
702
  n += n >> 1;
214✔
703

704
  if (n >= MAX_EGRAPH_STACK_SIZE) {
214✔
705
    out_of_memory();
×
706
  }
707

708
  stack->tag = (unsigned char *) safe_realloc(stack->tag, n * sizeof(unsigned char));
214✔
709
  stack->data = (undo_t *) safe_realloc(stack->data, n * sizeof(undo_t));
214✔
710
  stack->size = n;
214✔
711
}
214✔
712

713
/*
714
 * Increase the number of levels
715
 */
716
static void increase_undo_stack_levels(undo_stack_t *stack) {
272✔
717
  uint32_t n;
718

719
  n = stack->nlevels + 1;
272✔
720
  n += n >> 1;
272✔
721

722
  if (n >= MAX_EGRAPH_STACK_LEVELS) {
272✔
723
    out_of_memory();
×
724
  }
725

726
  stack->level_index = (uint32_t *) safe_realloc(stack->level_index, n * sizeof(uint32_t));
272✔
727
  stack->nlevels = n;
272✔
728
}
272✔
729

730

731

732
/*
733
 * Push undo objects
734
 */
735
static inline uint32_t undo_stack_get_top(undo_stack_t *stack) {
6,104,570✔
736
  uint32_t i;
737

738
  i = stack->top;
6,104,570✔
739
  if (i >= stack->size) {
6,104,570✔
740
    extend_undo_stack(stack);
214✔
741
  }
742
  stack->top = i+1;
6,104,570✔
743

744
  return i;
6,104,570✔
745
}
746

747

748
/*
749
 * Save t and its class label l, just before the class of t is merged
750
 * with another class. This happens when an equality (t == u) is processed,
751
 */
752
static void undo_stack_push_merge(undo_stack_t *stack, occ_t t, elabel_t l) {
5,969,722✔
753
  uint32_t i;
754

755
  i = undo_stack_get_top(stack);
5,969,722✔
756
  stack->tag[i] = UNDO_MERGE;
5,969,722✔
757
  stack->data[i].merge.saved_occ = t;
5,969,722✔
758
  stack->data[i].merge.saved_label = l;
5,969,722✔
759
}
5,969,722✔
760

761

762
/*
763
 * Assertion (distinct t_0 ... t_n-1) == true
764
 * - the atom can be recovered from the distinct_table so
765
 * we just need to put a mark that DISTINCT was asserted
766
 */
767
static void undo_stack_push_distinct(undo_stack_t *stack) {
27✔
768
  uint32_t i;
769

770
  i = undo_stack_get_top(stack);
27✔
771
  stack->tag[i] = UNDO_DISTINCT;
27✔
772
}
27✔
773

774
// push pointer + tag
775
static void undo_stack_push_ptr(undo_stack_t *stack, void *p, undo_tag_t tag) {
134,821✔
776
  uint32_t i;
777

778
  i = undo_stack_get_top(stack);
134,821✔
779
  stack->tag[i] = tag;
134,821✔
780
  stack->data[i].ptr = p;
134,821✔
781
}
134,821✔
782

783
/*
784
 * UNDO_SIMPLIFY means that cmp was simplified and removed from the congruence
785
 * table and use vectors (outside of a merge-class operation). On backtracking,
786
 * we need to put cmp back into both tables.
787
 */
788
static inline void undo_stack_push_composite(undo_stack_t *stack, composite_t *cmp) {
68,169✔
789
  undo_stack_push_ptr(stack, cmp, UNDO_SIMPLIFY);
68,169✔
790
}
68,169✔
791

792

793
/*
794
 * Delete
795
 */
796
static void delete_undo_stack(undo_stack_t *stack) {
4,791✔
797
  safe_free(stack->tag);
4,791✔
798
  safe_free(stack->data);
4,791✔
799
  safe_free(stack->level_index);
4,791✔
800

801
  stack->tag = NULL;
4,791✔
802
  stack->data = NULL;
4,791✔
803
  stack->level_index = NULL;
4,791✔
804
}
4,791✔
805

806

807
/*
808
 * Empty the stack
809
 */
810
static void reset_undo_stack(undo_stack_t *stack) {
6✔
811
  stack->top = 0;
6✔
812
  stack->level_index[0] = 0;
6✔
813
}
6✔
814

815

816
/*****************
817
 *  TRAIL STACK  *
818
 ****************/
819

820
/*
821
 * Initialize a trail stack: size = 0
822
 */
823
static void init_egraph_trail(egraph_trail_stack_t *stack) {
4,792✔
824
  stack->size = 0;
4,792✔
825
  stack->top = 0;
4,792✔
826
  stack->data = NULL;
4,792✔
827
}
4,792✔
828

829

830
/*
831
 * Save level:
832
 * - nt = number of terms
833
 * - p = propagation pointer
834
 */
835
static void egraph_trail_save(egraph_trail_stack_t *stack, uint32_t nt, uint32_t p) {
4,528✔
836
  uint32_t i, n;
837

838
  i = stack->top;
4,528✔
839
  n = stack->size;
4,528✔
840
  if (i == n) {
4,528✔
841
    if (n == 0) {
4,315✔
842
      n = DEFAULT_EGRAPH_TRAIL_SIZE;
4,315✔
843
    } else {
844
      n += n;
×
845
      if (n >= MAX_EGRAPH_TRAIL_SIZE) {
×
846
        out_of_memory();
×
847
      }
848
    }
849
    stack->data = (egraph_trail_t *) safe_realloc(stack->data, n * sizeof(egraph_trail_t));
4,315✔
850
    stack->size = n;
4,315✔
851
  }
852
  stack->data[i].nterms = nt;
4,528✔
853
  stack->data[i].prop_ptr = p;
4,528✔
854

855
  stack->top = i + 1;
4,528✔
856
}
4,528✔
857

858

859
/*
860
 * Get top record
861
 */
862
static inline egraph_trail_t *egraph_trail_top(egraph_trail_stack_t *stack) {
220✔
863
  assert(stack->top > 0);
864
  return stack->data + (stack->top - 1);
220✔
865
}
866

867

868
/*
869
 * Remove top record
870
 */
871
static inline void egraph_trail_pop(egraph_trail_stack_t *stack) {
220✔
872
  assert(stack->top > 0);
873
  stack->top --;
220✔
874
}
220✔
875

876

877
/*
878
 * Empty the stack
879
 */
880
static inline void reset_egraph_trail(egraph_trail_stack_t *stack) {
6✔
881
  stack->top = 0;
6✔
882
}
6✔
883

884
/*
885
 * Delete
886
 */
887
static inline void delete_egraph_trail(egraph_trail_stack_t *stack) {
4,791✔
888
  safe_free(stack->data);
4,791✔
889
  stack->data = NULL;
4,791✔
890
}
4,791✔
891

892

893

894
/***********************
895
 *  STATISTICS RECORD  *
896
 **********************/
897

898
/*
899
 * Initialize all counters to 0
900
 */
901
static void init_egraph_stats(egraph_stats_t *s) {
4,798✔
902
  s->app_reductions = 0;
4,798✔
903

904
  s->eq_props = 0;
4,798✔
905
  s->th_props = 0;
4,798✔
906
  s->th_conflicts = 0;
4,798✔
907
  s->nd_lemmas = 0;
4,798✔
908

909
  s->aux_eqs = 0;
4,798✔
910
  s->boolack_lemmas = 0;
4,798✔
911
  s->ack_lemmas = 0;
4,798✔
912

913
  s->final_checks = 0;
4,798✔
914
  s->interface_eqs = 0;
4,798✔
915
}
4,798✔
916

917
/*
918
 * Reset: same thing
919
 */
920
static inline void reset_egraph_stats(egraph_stats_t *s) {
6✔
921
  init_egraph_stats(s);
6✔
922
}
6✔
923

924

925

926

927

928

929
/*************
930
 *   MODEL   *
931
 ************/
932

933
/*
934
 * Initialize mdl: no memory is allocated yet.
935
 */
936
static void init_egraph_model(egraph_model_t *mdl) {
4,792✔
937
  mdl->value = NULL;
4,792✔
938
  mdl->pstore = NULL;
4,792✔
939
  mdl->fval_maker = NULL;
4,792✔
940
  init_ivector(&mdl->root_classes, 0);
4,792✔
941
  init_ivector(&mdl->rank_ctr, 0);
4,792✔
942
  q_init(&mdl->arith_buffer);
4,792✔
943
  init_bvconstant(&mdl->bv_buffer);
4,792✔
944
}
4,792✔
945

946

947
/*
948
 * Delete mdl: free all the memory it uses
949
 */
950
static void delete_egraph_model(egraph_model_t *mdl) {
4,791✔
951
  safe_free(mdl->value);
4,791✔
952
  mdl->value = NULL;
4,791✔
953
  if (mdl->pstore != NULL) {
4,791✔
954
    delete_pstore(mdl->pstore);
×
955
    safe_free(mdl->pstore);
×
956
    mdl->pstore = NULL;
×
957
  }
958
  if (mdl->fval_maker != NULL) {
4,791✔
959
    delete_fresh_val_maker(mdl->fval_maker);
×
960
    safe_free(mdl->fval_maker);
×
961
    mdl->fval_maker = NULL;
×
962
  }
963
  delete_ivector(&mdl->root_classes);
4,791✔
964
  delete_ivector(&mdl->rank_ctr);
4,791✔
965
  q_clear(&mdl->arith_buffer);
4,791✔
966
  delete_bvconstant(&mdl->bv_buffer);
4,791✔
967
}
4,791✔
968

969

970
/*
971
 * Reset mdl: delete everything except the bv buffer
972
 */
973
static void reset_egraph_model(egraph_model_t *mdl) {
13,043✔
974
  safe_free(mdl->value);
13,043✔
975
  mdl->value = NULL;
13,043✔
976
  if (mdl->pstore != NULL) {
13,043✔
977
    delete_pstore(mdl->pstore);
12,646✔
978
    safe_free(mdl->pstore);
12,646✔
979
    mdl->pstore = NULL;
12,646✔
980
  }
981
  if (mdl->fval_maker != NULL) {
13,043✔
982
    delete_fresh_val_maker(mdl->fval_maker);
13,037✔
983
    safe_free(mdl->fval_maker);
13,037✔
984
    mdl->fval_maker = NULL;
13,037✔
985
  }
986
  ivector_reset(&mdl->root_classes);
13,043✔
987
  ivector_reset(&mdl->rank_ctr);
13,043✔
988
  q_clear(&mdl->arith_buffer);
13,043✔
989
}
13,043✔
990

991

992

993

994
/***********************
995
 *  ATOM CONSTRUCTION  *
996
 **********************/
997

998
/*
999
 * Create atom <v, t> and add it to the core
1000
 * - v must be a boolean variable in egraph->core, with no atom attached
1001
 * - t must be a boolean term in egraph
1002
 */
1003
static void create_egraph_atom(egraph_t *egraph, bvar_t v, eterm_t t) {
36,222✔
1004
  atom_t *atom;
1005
  smt_core_t *core;
1006

1007
  core = egraph->core;
36,222✔
1008

1009
  assert(core != NULL && bvar_atom(core, v) == NULL);
1010

1011
  atom = (atom_t *) objstore_alloc(&egraph->atom_store);
36,222✔
1012
  atom->eterm = t;
36,222✔
1013
  atom->boolvar = v;
36,222✔
1014
  atom->next = atom;
36,222✔
1015

1016
  attach_atom_to_bvar(core, v, tagged_egraph_atom(atom));
36,222✔
1017

1018
  egraph->natoms ++;
36,222✔
1019
}
36,222✔
1020

1021

1022
/*
1023
 * Swap the successors of atom1 and atom2
1024
 * - if they are in different circular list, this merge the two lists
1025
 * - if they are in the same list, this splits it into two
1026
 */
1027
static inline void swap_next_atoms(atom_t *atom1, atom_t *atom2) {
7,030,361✔
1028
  atom_t *aux;
1029

1030
  aux = atom1->next;
7,030,361✔
1031
  atom1->next = atom2->next;
7,030,361✔
1032
  atom2->next = aux;
7,030,361✔
1033
}
7,030,361✔
1034

1035

1036
/*
1037
 * For debugging only: check whether two atom lists are equal or disjoint
1038
 */
1039
#ifndef NDEBUG
1040

1041
/*
1042
 * Scan list starting from atom1, until either atom1 or atom2 is found
1043
 */
1044
static atom_t *scan_atom_list(atom_t *atom1, atom_t *atom2) {
1045
  atom_t *a;
1046
  a = atom1;
1047
  do {
1048
    a = a->next;
1049
  } while (a != atom1 && a != atom2);
1050

1051
  return a;
1052
}
1053

1054
static bool disjoint_atom_lists(atom_t *atom1, atom_t *atom2) {
1055
  return scan_atom_list(atom1, atom2) == atom1;
1056
}
1057

1058
static bool equal_atom_lists(atom_t *atom1, atom_t *atom2) {
1059
  return scan_atom_list(atom1, atom2) == atom2;
1060
}
1061

1062
#endif
1063

1064

1065
/*
1066
 * Aliases for swap_next_atoms
1067
 */
1068
static inline void merge_atom_lists(atom_t *atom1, atom_t *atom2) {
3,526,798✔
1069
  assert(disjoint_atom_lists(atom1, atom2));
1070
  swap_next_atoms(atom1, atom2);
3,526,798✔
1071
}
3,526,798✔
1072

1073
static inline void split_atom_lists(atom_t *atom1, atom_t *atom2) {
3,503,563✔
1074
  assert(equal_atom_lists(atom1, atom2));
1075
  swap_next_atoms(atom1, atom2);
3,503,563✔
1076
}
3,503,563✔
1077

1078

1079
/*
1080
 * Delete atom and remove it from the core.
1081
 */
1082
static void delete_egraph_atom(egraph_t *egraph, atom_t *atom) {
2,495✔
1083
  smt_core_t *core;
1084
  bvar_t v;
1085

1086
  core = egraph->core;
2,495✔
1087
  v = atom->boolvar;
2,495✔
1088

1089
  assert(core != NULL && bvar_atom(core, v) == tagged_egraph_atom(atom));
1090
  assert(atom->next == atom);
1091

1092
  remove_bvar_atom(core, v);
2,495✔
1093
  objstore_free(&egraph->atom_store, atom);
2,495✔
1094

1095
  assert(egraph->natoms > 0);
1096
  egraph->natoms --;
2,495✔
1097
}
2,495✔
1098

1099

1100
/*
1101
 * Get the egraph atom attached to a boolean variable v
1102
 * return NULL if v has no atom or if the atom of v is not in an egraph atom
1103
 */
1104
static atom_t *get_egraph_atom_for_bvar(egraph_t *egraph, bvar_t v) {
2,495✔
1105
  smt_core_t *core;
1106
  void *a;
1107

1108
  core = egraph->core;
2,495✔
1109
  assert(core != NULL);
1110

1111
  a = bvar_atom(core, v);
2,495✔
1112
  if (a != NULL && atom_tag(a) == EGRAPH_ATM_TAG) {
2,495✔
1113
    return (atom_t *)a;
2,495✔
1114
  }
1115
  return NULL;
×
1116
}
1117

1118

1119

1120

1121

1122

1123
/************************
1124
 *  TERM CONSTRUCTION   *
1125
 ***********************/
1126

1127
/*
1128
 * Create a composite term
1129
 */
1130
static eterm_t new_composite_eterm(egraph_t *egraph, composite_t *cmp) {
67,783✔
1131
  eterm_t t;
1132
  t = new_eterm(&egraph->terms, cmp);
67,783✔
1133
  cmp->id = t;
67,783✔
1134
  cmp->depth = UNKNOWN_DEPTH;
67,783✔
1135
  return t;
67,783✔
1136
}
1137

1138
static eterm_t new_apply(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
26,392✔
1139
  return new_composite_eterm(egraph, new_apply_composite(f, n, a));
26,392✔
1140
}
1141

1142
static eterm_t new_update(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
11,462✔
1143
  return new_composite_eterm(egraph, new_update_composite(f, n, a, v));
11,462✔
1144
}
1145

1146
static eterm_t new_tuple(egraph_t *egraph, uint32_t n, occ_t *a) {
677✔
1147
  return new_composite_eterm(egraph, new_tuple_composite(n, a));
677✔
1148
}
1149

1150
static eterm_t new_ite(egraph_t *egraph, occ_t t1, occ_t t2, occ_t t3) {
2✔
1151
  return new_composite_eterm(egraph, new_ite_composite(t1, t2, t3));
2✔
1152
}
1153

1154
static eterm_t new_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
29,234✔
1155
  return new_composite_eterm(egraph, new_eq_composite(t1, t2));
29,234✔
1156
}
1157

1158
static eterm_t new_or(egraph_t *egraph, uint32_t n, occ_t *a) {
×
1159
  return new_composite_eterm(egraph, new_or_composite(n, a));
×
1160
}
1161

1162
// fails if too many distinct terms already exist (return null_eterm)
1163
static eterm_t new_distinct(egraph_t *egraph, uint32_t n, occ_t *a) {
16✔
1164
  if (egraph->ndistincts >= MAX_DISTINCT_TERMS) {
16✔
1165
    return null_eterm;
×
1166
  }
1167
  egraph->ndistincts ++;
16✔
1168

1169
  return new_composite_eterm(egraph, new_distinct_composite(n, a));
16✔
1170
}
1171

1172
static eterm_t new_lambda(egraph_t *egraph, occ_t t, int32_t tag) {
×
1173
  return new_composite_eterm(egraph, new_lambda_composite(t, tag));
×
1174
}
1175

1176

1177
/*
1178
 * HASH CONSING FOR COMPOSITES
1179
 */
1180

1181
/*
1182
 * Hash-consing interface objects
1183
 */
1184
typedef struct {
1185
  int_hobj_t m;
1186
  egraph_t *egraph;
1187
  occ_t f;
1188
  uint32_t n;
1189
  occ_t *a;
1190
} apply_hobj_t;
1191

1192
typedef struct {
1193
  int_hobj_t m;
1194
  egraph_t *egraph;
1195
  occ_t f;
1196
  uint32_t n;
1197
  occ_t *a;
1198
  occ_t v;
1199
} update_hobj_t;
1200

1201
// hobj type used for tuple, distinct, and or
1202
typedef struct {
1203
  int_hobj_t m;
1204
  egraph_t *egraph;
1205
  uint32_t n;
1206
  occ_t *a;
1207
} composite_hobj_t;
1208

1209
typedef struct {
1210
  int_hobj_t m;
1211
  egraph_t *egraph;
1212
  occ_t t1, t2;
1213
} eq_hobj_t;
1214

1215
typedef struct {
1216
  int_hobj_t m;
1217
  egraph_t *egraph;
1218
  occ_t t1, t2, t3;
1219
} ite_hobj_t;
1220

1221
typedef struct {
1222
  int_hobj_t m;
1223
  egraph_t *egraph;
1224
  occ_t t;
1225
  int32_t tag;
1226
} lambda_hobj_t;
1227

1228

1229
/*
1230
 * Hash functions
1231
 */
1232
static uint32_t hash_apply_obj(apply_hobj_t *p) {
26,460✔
1233
  return hash_apply(p->f, p->n, p->a);
26,460✔
1234
}
1235

1236
static uint32_t hash_update_obj(update_hobj_t *p) {
11,463✔
1237
  return hash_update(p->f, p->n, p->a, p->v);
11,463✔
1238
}
1239

1240
static uint32_t hash_tuple_obj(composite_hobj_t *p) {
677✔
1241
  return hash_tuple(p->n, p->a);
677✔
1242
}
1243

1244
static uint32_t hash_eq_obj(eq_hobj_t *p) {
458,307✔
1245
  return hash_eq(p->t1, p->t2);
458,307✔
1246
}
1247

1248
static uint32_t hash_ite_obj(ite_hobj_t *p) {
2✔
1249
  return hash_ite(p->t1, p->t2, p->t3);
2✔
1250
}
1251

1252
static uint32_t hash_distinct_obj(composite_hobj_t *p) {
16✔
1253
  return hash_distinct(p->n, p->a);
16✔
1254
}
1255

1256
static uint32_t hash_or_obj(composite_hobj_t *p) {
×
1257
  return hash_or(p->n, p->a);
×
1258
}
1259

1260
static uint32_t hash_lambda_obj(lambda_hobj_t *p) {
×
1261
  return hash_lambda(p->t, p->tag);
×
1262
}
1263

1264

1265
/*
1266
 * Equality tests
1267
 */
1268
static bool equal_apply_obj(apply_hobj_t *p, eterm_t i) {
1,209✔
1269
  composite_t *c;
1270

1271
  c = p->egraph->terms.body[i];
1,209✔
1272
  assert(composite_body(c));
1273

1274
  return equal_apply(c, p->f, p->n, p->a);
1,209✔
1275
}
1276

1277
static bool equal_update_obj(update_hobj_t *p, eterm_t i) {
36✔
1278
  composite_t *c;
1279

1280
  c = p->egraph->terms.body[i];
36✔
1281
  assert(composite_body(c));
1282

1283
  return equal_update(c, p->f, p->n, p->a, p->v);
36✔
1284
}
1285

1286
static bool equal_tuple_obj(composite_hobj_t *p, eterm_t i) {
×
1287
  composite_t *c;
1288

1289
  c = p->egraph->terms.body[i];
×
1290
  assert(composite_body(c));
1291

1292
  return equal_tuple(c, p->n, p->a);
×
1293
}
1294

1295
static bool equal_eq_obj(eq_hobj_t *p, eterm_t i) {
223,376✔
1296
  composite_t *c;
1297

1298
  c = p->egraph->terms.body[i];
223,376✔
1299
  assert(composite_body(c));
1300

1301
  return equal_eq(c, p->t1, p->t2);
223,376✔
1302
}
1303

1304
static bool equal_ite_obj(ite_hobj_t *p, eterm_t i) {
×
1305
  composite_t *c;
1306

1307
  c = p->egraph->terms.body[i];
×
1308
  assert(composite_body(c));
1309

1310
  return equal_ite(c, p->t1, p->t2, p->t3);
×
1311
}
1312

1313
static bool equal_distinct_obj(composite_hobj_t *p, eterm_t i) {
×
1314
  composite_t *c;
1315

1316
  c = p->egraph->terms.body[i];
×
1317
  assert(composite_body(c));
1318

1319
  return equal_distinct(c, p->n, p->a);
×
1320
}
1321

1322
static bool equal_or_obj(composite_hobj_t *p, eterm_t i) {
×
1323
  composite_t *c;
1324

1325
  c = p->egraph->terms.body[i];
×
1326
  assert(composite_body(c));
1327

1328
  return equal_or(c, p->n, p->a);
×
1329
}
1330

1331
static bool equal_lambda_obj(lambda_hobj_t *p, eterm_t i) {
×
1332
  composite_t *c;
1333

1334
  c = p->egraph->terms.body[i];
×
1335
  assert(composite_body(c));
1336

1337
  return equal_lambda(c, p->t, p->tag);
×
1338
}
1339

1340

1341
/*
1342
 * Build functions
1343
 */
1344
static eterm_t build_apply_obj(apply_hobj_t *p) {
26,392✔
1345
  return new_apply(p->egraph, p->f, p->n, p->a);
26,392✔
1346
}
1347

1348
static eterm_t build_update_obj(update_hobj_t *p) {
11,462✔
1349
  return new_update(p->egraph, p->f, p->n, p->a, p->v);
11,462✔
1350
}
1351

1352
static eterm_t build_tuple_obj(composite_hobj_t *p) {
677✔
1353
  return new_tuple(p->egraph, p->n, p->a);
677✔
1354
}
1355

1356
static eterm_t build_eq_obj(eq_hobj_t *p) {
29,004✔
1357
  return new_eq(p->egraph, p->t1, p->t2);
29,004✔
1358
}
1359

1360
static eterm_t build_ite_obj(ite_hobj_t *p) {
2✔
1361
  return new_ite(p->egraph, p->t1, p->t2, p->t3);
2✔
1362
}
1363

1364
static eterm_t build_distinct_obj(composite_hobj_t *p) {
16✔
1365
  return new_distinct(p->egraph, p->n, p->a);
16✔
1366
}
1367

1368
static eterm_t build_or_obj(composite_hobj_t *p) {
×
1369
  return new_or(p->egraph, p->n, p->a);
×
1370
}
1371

1372
static eterm_t build_lambda_obj(lambda_hobj_t *p) {
×
1373
  return new_lambda(p->egraph, p->t, p->tag);
×
1374
}
1375

1376

1377
/*
1378
 * Hash-consing constructors
1379
 */
1380
static eterm_t egraph_apply_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
26,460✔
1381
  apply_hobj_t apply_hobj;
1382
  apply_hobj.m.hash = (hobj_hash_t) hash_apply_obj;
26,460✔
1383
  apply_hobj.m.eq = (hobj_eq_t) equal_apply_obj;
26,460✔
1384
  apply_hobj.m.build = (hobj_build_t) build_apply_obj;
26,460✔
1385
  apply_hobj.egraph = egraph;
26,460✔
1386
  apply_hobj.f = f;
26,460✔
1387
  apply_hobj.n = n;
26,460✔
1388
  apply_hobj.a = a;
26,460✔
1389

1390
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &apply_hobj);
26,460✔
1391
}
1392

1393
static eterm_t egraph_update_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
11,463✔
1394
  update_hobj_t update_hobj;
1395
  update_hobj.m.hash = (hobj_hash_t) hash_update_obj;
11,463✔
1396
  update_hobj.m.eq = (hobj_eq_t) equal_update_obj;
11,463✔
1397
  update_hobj.m.build = (hobj_build_t) build_update_obj;
11,463✔
1398
  update_hobj.egraph = egraph;
11,463✔
1399
  update_hobj.f = f;
11,463✔
1400
  update_hobj.n = n;
11,463✔
1401
  update_hobj.a = a;
11,463✔
1402
  update_hobj.v = v;
11,463✔
1403

1404
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &update_hobj);
11,463✔
1405
}
1406

1407
static eterm_t egraph_tuple_term(egraph_t *egraph, uint32_t n, occ_t *a) {
677✔
1408
  composite_hobj_t tuple_hobj;
1409
  tuple_hobj.m.hash = (hobj_hash_t) hash_tuple_obj;
677✔
1410
  tuple_hobj.m.eq = (hobj_eq_t) equal_tuple_obj;
677✔
1411
  tuple_hobj.m.build = (hobj_build_t) build_tuple_obj;
677✔
1412
  tuple_hobj.egraph = egraph;
677✔
1413
  tuple_hobj.n = n;
677✔
1414
  tuple_hobj.a = a;
677✔
1415

1416
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &tuple_hobj);
677✔
1417
}
1418

1419
static eterm_t egraph_eq_term(egraph_t *egraph, occ_t t1, occ_t t2) {
56,215✔
1420
  eq_hobj_t eq_hobj;
1421
  eq_hobj.m.hash = (hobj_hash_t) hash_eq_obj;
56,215✔
1422
  eq_hobj.m.eq = (hobj_eq_t) equal_eq_obj;
56,215✔
1423
  eq_hobj.m.build = (hobj_build_t) build_eq_obj;
56,215✔
1424
  eq_hobj.egraph = egraph;
56,215✔
1425
  eq_hobj.t1 = t1;
56,215✔
1426
  eq_hobj.t2 = t2;
56,215✔
1427

1428
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &eq_hobj);
56,215✔
1429
}
1430

1431
static eterm_t egraph_ite_term(egraph_t *egraph, occ_t t1, occ_t t2, occ_t t3) {
2✔
1432
  ite_hobj_t ite_hobj;
1433
  ite_hobj.m.hash = (hobj_hash_t) hash_ite_obj;
2✔
1434
  ite_hobj.m.eq = (hobj_eq_t) equal_ite_obj;
2✔
1435
  ite_hobj.m.build = (hobj_build_t) build_ite_obj;
2✔
1436
  ite_hobj.egraph = egraph;
2✔
1437
  ite_hobj.t1 = t1;
2✔
1438
  ite_hobj.t2 = t2;
2✔
1439
  ite_hobj.t3 = t3;
2✔
1440

1441
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &ite_hobj);
2✔
1442
}
1443

1444
static eterm_t egraph_distinct_term(egraph_t *egraph, uint32_t n, occ_t *a) {
16✔
1445
  composite_hobj_t distinct_hobj;
1446

1447
  assert(n >= 3);
1448

1449
  distinct_hobj.m.hash = (hobj_hash_t) hash_distinct_obj;
16✔
1450
  distinct_hobj.m.eq = (hobj_eq_t) equal_distinct_obj;
16✔
1451
  distinct_hobj.m.build = (hobj_build_t) build_distinct_obj;
16✔
1452
  distinct_hobj.egraph = egraph;
16✔
1453
  distinct_hobj.n = n;
16✔
1454
  distinct_hobj.a = a;
16✔
1455

1456
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &distinct_hobj);
16✔
1457
}
1458

1459
static eterm_t egraph_or_term(egraph_t *egraph, uint32_t n, occ_t *a) {
×
1460
  composite_hobj_t or_hobj;
1461
  or_hobj.m.hash = (hobj_hash_t) hash_or_obj;
×
1462
  or_hobj.m.eq = (hobj_eq_t) equal_or_obj;
×
1463
  or_hobj.m.build = (hobj_build_t) build_or_obj;
×
1464
  or_hobj.egraph = egraph;
×
1465
  or_hobj.n = n;
×
1466
  or_hobj.a = a;
×
1467

1468
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &or_hobj);
×
1469
}
1470

1471
static eterm_t egraph_lambda_term(egraph_t *egraph, occ_t t, int32_t tag) {
×
1472
  lambda_hobj_t lambda_hobj;
1473
  lambda_hobj.m.hash = (hobj_hash_t) hash_lambda_obj;
×
1474
  lambda_hobj.m.eq = (hobj_eq_t) equal_lambda_obj;
×
1475
  lambda_hobj.m.build = (hobj_build_t) build_lambda_obj;
×
1476
  lambda_hobj.egraph = egraph;
×
1477
  lambda_hobj.t = t;
×
1478
  lambda_hobj.tag = tag;
×
1479

1480
  return int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &lambda_hobj);
×
1481
}
1482

1483

1484
/*
1485
 * Search whether a composite term already exists
1486
 * - all functions return -1 (= null_eterm) if the term requested isn't present
1487
 * - they return the eterm index otherwise
1488
 */
1489
static eterm_t egraph_find_apply_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
×
1490
  apply_hobj_t apply_hobj;
1491
  apply_hobj.m.hash = (hobj_hash_t) hash_apply_obj;
×
1492
  apply_hobj.m.eq = (hobj_eq_t) equal_apply_obj;
×
1493
  apply_hobj.m.build = (hobj_build_t) build_apply_obj;
×
1494
  apply_hobj.egraph = egraph;
×
1495
  apply_hobj.f = f;
×
1496
  apply_hobj.n = n;
×
1497
  apply_hobj.a = a;
×
1498

1499
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &apply_hobj);
×
1500
}
1501

1502
static eterm_t egraph_find_update_term(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
×
1503
  update_hobj_t update_hobj;
1504
  update_hobj.m.hash = (hobj_hash_t) hash_update_obj;
×
1505
  update_hobj.m.eq = (hobj_eq_t) equal_update_obj;
×
1506
  update_hobj.m.build = (hobj_build_t) build_update_obj;
×
1507
  update_hobj.egraph = egraph;
×
1508
  update_hobj.f = f;
×
1509
  update_hobj.n = n;
×
1510
  update_hobj.a = a;
×
1511
  update_hobj.v = v;
×
1512

1513
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &update_hobj);
×
1514
}
1515

1516
static eterm_t egraph_find_tuple_term(egraph_t *egraph, uint32_t n, occ_t *a) {
×
1517
  composite_hobj_t tuple_hobj;
1518
  tuple_hobj.m.hash = (hobj_hash_t) hash_tuple_obj;
×
1519
  tuple_hobj.m.eq = (hobj_eq_t) equal_tuple_obj;
×
1520
  tuple_hobj.m.build = (hobj_build_t) build_tuple_obj;
×
1521
  tuple_hobj.egraph = egraph;
×
1522
  tuple_hobj.n = n;
×
1523
  tuple_hobj.a = a;
×
1524

1525
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &tuple_hobj);
×
1526
}
1527

1528
static eterm_t egraph_find_eq_term(egraph_t *egraph, occ_t t1, occ_t t2) {
401,379✔
1529
  eq_hobj_t eq_hobj;
1530
  eq_hobj.m.hash = (hobj_hash_t) hash_eq_obj;
401,379✔
1531
  eq_hobj.m.eq = (hobj_eq_t) equal_eq_obj;
401,379✔
1532
  eq_hobj.m.build = (hobj_build_t) build_eq_obj;
401,379✔
1533
  eq_hobj.egraph = egraph;
401,379✔
1534
  eq_hobj.t1 = t1;
401,379✔
1535
  eq_hobj.t2 = t2;
401,379✔
1536

1537
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &eq_hobj);
401,379✔
1538
}
1539

1540
static eterm_t egraph_find_ite_term(egraph_t *egraph, occ_t t1, occ_t t2, occ_t t3) {
×
1541
  ite_hobj_t ite_hobj;
1542
  ite_hobj.m.hash = (hobj_hash_t) hash_ite_obj;
×
1543
  ite_hobj.m.eq = (hobj_eq_t) equal_ite_obj;
×
1544
  ite_hobj.m.build = (hobj_build_t) build_ite_obj;
×
1545
  ite_hobj.egraph = egraph;
×
1546
  ite_hobj.t1 = t1;
×
1547
  ite_hobj.t2 = t2;
×
1548
  ite_hobj.t3 = t3;
×
1549

1550
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &ite_hobj);
×
1551
}
1552

1553
static eterm_t egraph_find_distinct_term(egraph_t *egraph, uint32_t n, occ_t *a) {
×
1554
  composite_hobj_t distinct_hobj;
1555

1556
  assert(n >= 3);
1557

1558
  distinct_hobj.m.hash = (hobj_hash_t) hash_distinct_obj;
×
1559
  distinct_hobj.m.eq = (hobj_eq_t) equal_distinct_obj;
×
1560
  distinct_hobj.m.build = (hobj_build_t) build_distinct_obj;
×
1561
  distinct_hobj.egraph = egraph;
×
1562
  distinct_hobj.n = n;
×
1563
  distinct_hobj.a = a;
×
1564

1565
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &distinct_hobj);
×
1566
}
1567

1568
static eterm_t egraph_find_or_term(egraph_t *egraph, uint32_t n, occ_t *a) {
×
1569
  composite_hobj_t or_hobj;
1570
  or_hobj.m.hash = (hobj_hash_t) hash_or_obj;
×
1571
  or_hobj.m.eq = (hobj_eq_t) equal_or_obj;
×
1572
  or_hobj.m.build = (hobj_build_t) build_or_obj;
×
1573
  or_hobj.egraph = egraph;
×
1574
  or_hobj.n = n;
×
1575
  or_hobj.a = a;
×
1576

1577
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &or_hobj);
×
1578
}
1579

1580
static eterm_t egraph_find_lambda_term(egraph_t *egraph, occ_t t, int32_t tag) {
×
1581
  lambda_hobj_t lambda_hobj;
1582
  lambda_hobj.m.hash = (hobj_hash_t) hash_lambda_obj;
×
1583
  lambda_hobj.m.eq = (hobj_eq_t) equal_lambda_obj;
×
1584
  lambda_hobj.m.build = (hobj_build_t) build_lambda_obj;
×
1585
  lambda_hobj.egraph = egraph;
×
1586
  lambda_hobj.t = t;
×
1587
  lambda_hobj.tag = tag;
×
1588

1589
  return int_htbl_find_obj(&egraph->htbl, (int_hobj_t *) &lambda_hobj);
×
1590
}
1591

1592

1593

1594

1595

1596
/*************************************
1597
 *  HASH CONSING FOR CONSTANT TERMS  *
1598
 ************************************/
1599

1600
/*
1601
 * Get the hash-table for constants: allocate it if needed.
1602
 */
1603
static int_htbl_t *egraph_get_const_htbl(egraph_t *egraph) {
2,008✔
1604
  int_htbl_t *tmp;
1605

1606
  tmp = egraph->const_htbl;
2,008✔
1607
  if (tmp == NULL) {
2,008✔
1608
    tmp = (int_htbl_t *) safe_malloc(sizeof(int_htbl_t));
125✔
1609
    init_int_htbl(tmp, 0);
125✔
1610
    egraph->const_htbl = tmp;
125✔
1611
  }
1612

1613
  return tmp;
2,008✔
1614
}
1615

1616

1617
/*
1618
 * Delete the hash-table for constants if it exists
1619
 */
1620
static void egraph_free_const_htbl(egraph_t *egraph) {
4,797✔
1621
  int_htbl_t *tmp;
1622

1623
  tmp = egraph->const_htbl;
4,797✔
1624
  if (tmp != NULL) {
4,797✔
1625
    delete_int_htbl(tmp);
125✔
1626
    safe_free(tmp);
125✔
1627
    egraph->const_htbl = NULL;
125✔
1628
  }
1629
}
4,797✔
1630

1631

1632
/*
1633
 * Hash consing object: a constant is defined by its type tau and its index id
1634
 */
1635
typedef struct {
1636
  int_hobj_t m;
1637
  egraph_t *egraph;
1638
  type_t tau;
1639
  int32_t id;
1640
} const_hobj_t;
1641

1642

1643
static inline uint32_t hash_constant(type_t tau, int32_t id) {
2,046✔
1644
  return jenkins_hash_pair(tau, id, 0x1889aed2);
2,046✔
1645
}
1646

1647
// interface to the htbl
1648
static uint32_t hash_const_hobj(const_hobj_t *p) {
2,008✔
1649
  return hash_constant(p->tau, p->id);
2,008✔
1650
}
1651

1652
static bool equal_const_hobj(const_hobj_t *p, eterm_t i) {
824✔
1653
  eterm_table_t *terms;
1654

1655
  terms = &p->egraph->terms;
824✔
1656
  return terms->real_type[i] == p->tau && constant_body_id(terms->body[i]) == p->id;
824✔
1657
}
1658

1659
// build function: just create a new term with descriptor = constant(id)
1660
// the type must be set later, after a class is created
1661
static eterm_t build_const_hobj(const_hobj_t *p) {
1,184✔
1662
  return new_eterm(&p->egraph->terms, mk_constant_body(p->id));
1,184✔
1663
}
1664

1665
/*
1666
 * Get the constant term defined by (tau, id):
1667
 * - if that's a new term, the initialization is not complete yet
1668
 */
1669
static eterm_t egraph_constant_term(egraph_t *egraph, type_t tau, int32_t id) {
2,008✔
1670
  int_htbl_t *const_htbl;
1671
  const_hobj_t const_hobj;
1672

1673
  const_hobj.m.hash = (hobj_hash_t) hash_const_hobj;
2,008✔
1674
  const_hobj.m.eq = (hobj_eq_t) equal_const_hobj;
2,008✔
1675
  const_hobj.m.build = (hobj_build_t) build_const_hobj;
2,008✔
1676
  const_hobj.egraph = egraph;
2,008✔
1677
  const_hobj.tau = tau;
2,008✔
1678
  const_hobj.id = id;
2,008✔
1679

1680
  const_htbl = egraph_get_const_htbl(egraph);
2,008✔
1681

1682
  return int_htbl_get_obj(const_htbl, (int_hobj_t *) &const_hobj);
2,008✔
1683
}
1684

1685

1686
/*
1687
 * Remove the htbl record for constant term t
1688
 */
1689
static void egraph_delete_constant(egraph_t *egraph, eterm_t t) {
38✔
1690
  type_t tau;
1691
  int32_t id;
1692
  uint32_t h;
1693

1694
  assert(egraph_term_is_constant(egraph, t) && egraph->const_htbl != NULL);
1695

1696
  tau = egraph_term_real_type(egraph, t);
38✔
1697
  id = constant_body_id(egraph_term_body(egraph, t));
38✔
1698
  h = hash_constant(tau, id);
38✔
1699
  int_htbl_erase_record(egraph->const_htbl, h, t);
38✔
1700
}
38✔
1701

1702

1703

1704

1705

1706
/**************************************************************
1707
 *  SIMPLIFICATION OF COMPOSITES/SEARCH FOR CONGRUENCE ROOTS  *
1708
 *************************************************************/
1709

1710
/*
1711
 * All analyze_xxx functions check whether a composite p simplifies or
1712
 * is congruent to another composite q.
1713
 * - if so, they add an equality to the propagation queue and return true
1714
 * - otherwise they store p in the congruence table and use vectors,
1715
 *   and return false
1716
 */
1717

1718
/*
1719
 * Propagation of the form (t1 == t2) implies (p->id == x)
1720
 */
1721
static inline void add_eq_implies_eq(egraph_t *egraph, composite_t *p, occ_t x, occ_t t1, occ_t t2) {
870,595✔
1722
  int32_t k;
1723

1724
  // don't add anything if (p->id == x) already holds
1725
  if (egraph_equal_occ(egraph, pos_occ(p->id), x)) return;
870,595✔
1726

1727
  k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), x);
129,085✔
1728
  egraph->stack.etag[k] = EXPL_EQ;
129,085✔
1729
  egraph->stack.edata[k].t[0] = t1;
129,085✔
1730
  egraph->stack.edata[k].t[1] = t2;
129,085✔
1731

1732
#if TRACE
1733
  printf("---> EGRAPH: equality ");
1734
  print_occurrence(stdout, pos_occ(p->id));
1735
  printf(" == ");
1736
  print_occurrence(stdout, x);
1737
  printf(" implied by ");
1738
  print_occurrence(stdout, t1);
1739
  printf(" == ");
1740
  print_occurrence(stdout, t2);
1741
  printf("\n");
1742
#endif
1743
}
1744

1745

1746
/*
1747
 * Propagation of the form (t1 != t2) implies (p->id == x), where t1 != t2 was derived from dmasks
1748
 * dmsk must be dmask[class(t1)] & dmask[class(t2)]
1749
 * The implied equality is always (p->id == false), where p is an equality term.
1750
 */
1751
static inline void add_diseq_implies_eq(egraph_t *egraph, composite_t *p, occ_t x,
461,795✔
1752
                                        occ_t t1, occ_t t2, uint32_t dmsk) {
1753
  int32_t k;
1754
  uint32_t i;
1755

1756
  // don't add anything if (p->id == x) already holds
1757
  if (egraph_equal_occ(egraph, pos_occ(p->id), x)) return;
461,795✔
1758

1759
  k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), x);
227,593✔
1760

1761
  // the tag depends on bit i of dmsk
1762
  i = ctz(dmsk);
227,593✔
1763
  assert(0 <= i && i < egraph->dtable.npreds);
1764
  egraph->stack.etag[k] = (expl_tag_t) (i + EXPL_DISTINCT0);
227,593✔
1765
  egraph->stack.edata[k].t[0] = t1;
227,593✔
1766
  egraph->stack.edata[k].t[1] = t2;
227,593✔
1767

1768
#if TRACE
1769
  printf("---> EGRAPH: equality ");
1770
  print_occurrence(stdout, pos_occ(p->id));
1771
  printf(" == ");
1772
  print_occurrence(stdout, x);
1773
  printf(" implied by dmasks\n");
1774
#endif
1775

1776
}
1777

1778

1779

1780
/*
1781
 * Basic terms: update/apply/tuple.
1782
 * - no simplification rule is applied
1783
 * - compute signature and look for a congruent term
1784
 */
1785
static bool analyze_basic(egraph_t *egraph, composite_t *p) {
5,531,867✔
1786
  composite_t *q;
1787
  signature_t *sgn;
1788
  elabel_t *label;
1789
  int32_t k;
1790

1791
  label = egraph->terms.label;
5,531,867✔
1792
  sgn = &egraph->sgn;
5,531,867✔
1793

1794
  signature_basic(p, label, sgn);
5,531,867✔
1795
  q = congruence_table_get(&egraph->ctable, p, sgn, label);
5,531,867✔
1796
  if (q != p) {
5,531,867✔
1797
    // basic_congruence between p and q
1798
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
2,153,617✔
1799
    egraph->stack.etag[k] = EXPL_BASIC_CONGRUENCE;
2,153,617✔
1800
#if TRACE
1801
    printf("---> EGRAPH: equality ");
1802
    print_occurrence(stdout, pos_occ(p->id));
1803
    printf(" == ");
1804
    print_occurrence(stdout, pos_occ(q->id));
1805
    printf(" implied by congruence\n");
1806
    printf("---> i.e., ");
1807
    print_composite(stdout, p);
1808
    printf(" == ");
1809
    print_composite(stdout, q);
1810
    printf("\n");
1811
#endif
1812
    return true;
2,153,617✔
1813
  }
1814

1815
  return false;
3,378,250✔
1816
}
1817

1818

1819
/*
1820
 * p is (eq t1 t2)
1821
 *
1822
 * TODO?
1823
 * add more simplifications for boolean equality:
1824
 *   t1 == true  implies (eq t1 t2) == t2
1825
 *   t1 == false implies (eq t1 t2) == (not t2)
1826
 */
1827
static bool analyze_eq(egraph_t *egraph, composite_t *p) {
3,725,953✔
1828
  occ_t t1, t2;
1829
  elabel_t l1, l2;
1830
  uint32_t dmsk;
1831
  composite_t *q;
1832
  signature_t *sgn;
1833
  elabel_t *label;
1834
  int32_t k;
1835

1836
  t1 = p->child[0];
3,725,953✔
1837
  t2 = p->child[1];
3,725,953✔
1838
  l1 = egraph_label(egraph, t1);
3,725,953✔
1839
  l2 = egraph_label(egraph, t2);
3,725,953✔
1840

1841
  // t1 == t2 implies (eq t1 t2) == true
1842
  if (l1 == l2) {
3,725,953✔
1843
    add_eq_implies_eq(egraph, p, true_occ, t1, t2);
870,540✔
1844
    return true;
870,540✔
1845
  }
1846

1847
  // t1 == (not t2) implies (eq t1 t2) == false
1848
  if (l1 == opposite_label(l2)) {
2,855,413✔
1849
    add_eq_implies_eq(egraph, p, false_occ, t1, opposite_occ(t2));
53✔
1850
    return true;
53✔
1851
  }
1852

1853
  // t1 != t2 implies (eq t1 t2) == false
1854
  dmsk = egraph->classes.dmask[class_of(l1)] & egraph->classes.dmask[class_of(l2)];
2,855,360✔
1855
  if (dmsk != 0) {
2,855,360✔
1856
    // note: the test (dmask[class_of(l1)] & dmask[class_of(l2)] != 0)
1857
    // always fails if l1 and l2 are boolean
1858
    add_diseq_implies_eq(egraph, p, false_occ, t1, t2, dmsk);
393,626✔
1859
    return true;
393,626✔
1860
  }
1861

1862
  // check for congruence
1863
  label = egraph->terms.label;
2,461,734✔
1864
  sgn = &egraph->sgn;
2,461,734✔
1865

1866
  signature_eq(p, label, sgn);
2,461,734✔
1867
  q = congruence_table_get(&egraph->ctable, p, sgn, label);
2,461,734✔
1868
  if (q != p) {
2,461,734✔
1869
    // congruence
1870
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
1,710,114✔
1871
    /*
1872
     * EXPL_EQ_CONGRUENCE1 is the tag in two cases:
1873
     * 1) t == u AND v == w IMPLIES (eq t v) == (eq u w)
1874
     * 2) t == not u AND v == not w IMPLIES (eq t v) == (eq u w)
1875
     *    where t, u, v, w are boolean terms
1876
     */
1877
    if (egraph_class(egraph, q->child[0]) == class_of(l1)) {
1,710,114✔
1878
      egraph->stack.etag[k] = EXPL_EQ_CONGRUENCE1;
1,155,151✔
1879
    } else {
1880
      egraph->stack.etag[k] = EXPL_EQ_CONGRUENCE2;
554,963✔
1881
    }
1882
#if TRACE
1883
    printf("---> EGRAPH: equality ");
1884
    print_occurrence(stdout, pos_occ(p->id));
1885
    printf(" == ");
1886
    print_occurrence(stdout, pos_occ(q->id));
1887
    printf(" implied by eq congruence\n");
1888
    printf("---> i.e., ");
1889
    print_composite(stdout, p);
1890
    printf(" == ");
1891
    print_composite(stdout, q);
1892
    printf("\n");
1893
#endif
1894
    return true;
1,710,114✔
1895
  }
1896

1897
  return false;
751,620✔
1898
}
1899

1900

1901
/*
1902
 * p is (ite t1 t2 t3)
1903
 */
1904
static bool analyze_ite(egraph_t *egraph, composite_t *p) {
3✔
1905
  occ_t t1, t2, t3;
1906
  elabel_t l1, l2, l3;
1907
  composite_t *q;
1908
  signature_t *sgn;
1909
  elabel_t *label;
1910
  int32_t k;
1911

1912
  t1 = p->child[0];
3✔
1913
  t2 = p->child[1];
3✔
1914
  t3 = p->child[2];
3✔
1915

1916
  l1 = egraph_label(egraph, t1);
3✔
1917

1918
  // t1 == true implies (ite t1 t2 t3) == t2
1919
  if (l1 == true_label) {
3✔
1920
    add_eq_implies_eq(egraph, p, t2, t1, true_occ);
1✔
1921
    return true;
1✔
1922
  }
1923

1924
  // t1 == false implies (ite t1 t2 t3) == t3
1925
  if (l1 == false_label) {
2✔
1926
    add_eq_implies_eq(egraph, p, t3, t1, false_occ);
×
1927
    return true;
×
1928
  }
1929

1930
  // t2 == t3 implies (ite t1 t2 t3) == t2
1931
  l2 = egraph_label(egraph, t2);
2✔
1932
  l3 = egraph_label(egraph, t3);
2✔
1933
  if (l2 == l3) {
2✔
1934
    add_eq_implies_eq(egraph, p, t2, t2, t3);
1✔
1935
    return true;
1✔
1936
  }
1937

1938
  // congruence check
1939
  label = egraph->terms.label;
1✔
1940
  sgn = &egraph->sgn;
1✔
1941

1942
  signature_ite(p, label, sgn);
1✔
1943
  q = congruence_table_get(&egraph->ctable, p, sgn, label);
1✔
1944
  if (q != p) {
1✔
1945
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
×
1946
    if (egraph_label(egraph, q->child[0]) == l1) {
×
1947
      egraph->stack.etag[k] = EXPL_ITE_CONGRUENCE1;
×
1948
    } else {
1949
      assert(egraph_label(egraph, q->child[0]) == opposite_label(l1));
1950
      egraph->stack.etag[k] = EXPL_ITE_CONGRUENCE2;
×
1951
    }
1952
#if TRACE
1953
    printf("---> EGRAPH: equality ");
1954
    print_occurrence(stdout, pos_occ(p->id));
1955
    printf(" == ");
1956
    print_occurrence(stdout, pos_occ(q->id));
1957
    printf(" implied by ite congruence\n");
1958
#endif
1959
    return true;
×
1960
  }
1961

1962
  return false;
1✔
1963
}
1964

1965
/*
1966
 * p is (distinct t1 ... t_n)
1967
 */
1968
static bool analyze_distinct(egraph_t *egraph, composite_t *p) {
×
1969
  composite_t *q;
1970
  signature_t *sgn;
1971
  elabel_t *label;
1972
  uint32_t i, n;
1973
  int32_t k;
1974

1975
  label = egraph->terms.label;
×
1976
  sgn = &egraph->sgn;
×
1977
  signature_distinct(p, label, sgn);
×
1978
  // sgn = labels of t1 ... t_n in increasing order
1979

1980
  n = composite_arity(p);
×
1981
  assert(tag_arity(sgn->tag) == n);
1982
  for (i=0; i<n-1; i++) {
×
1983
    // t_i == t_j implies (distinct t1 ... t_n) == false
1984
    if (sgn->sigma[i] == sgn->sigma[i+1]) {
×
1985
      k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), false_occ);
×
1986
      gen_distinct_simpl_antecedent(egraph, p, sgn->sigma[i], k);
×
1987
#if TRACE
1988
      printf("---> EGRAPH: distinct term ");
1989
      print_occurrence(stdout, pos_occ(p->id));
1990
      printf(" reduced to false because ");
1991
      print_occurrence(stdout, egraph->stack.edata[k].t[0]);
1992
      printf(" == ");
1993
      print_occurrence(stdout, egraph->stack.edata[k].t[1]);
1994
      printf("\n");
1995
#endif
1996
      return true;
×
1997
    }
1998
  }
1999

2000
  // check for congruence
2001
  q = congruence_table_get(&egraph->ctable, p, sgn, label);
×
2002
  if (q != p) {
×
2003
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
×
2004
    gen_distinct_congruence_antecedent(egraph, p, q, k);
×
2005
#if TRACE
2006
    printf("---> EGRAPH: equality ");
2007
    print_occurrence(stdout, pos_occ(p->id));
2008
    printf(" == ");
2009
    print_occurrence(stdout, pos_occ(q->id));
2010
    printf(" implied by distinct congruence\n");
2011
    printf("---> i.e., ");
2012
    print_composite(stdout, p);
2013
    printf(" == ");
2014
    print_composite(stdout, q);
2015
    printf("\n");
2016
#endif
2017
    return true;
×
2018
  }
2019

2020
  return false;
×
2021
}
2022

2023

2024
/*
2025
 * p is (or t_1 ... t_n)
2026
 */
2027
static occ_t find_child_label(egraph_t *egraph, composite_t *p, elabel_t x) {
×
2028
  uint32_t i, n;
2029
  occ_t t;
2030

2031
  n = composite_arity(p);
×
2032
  for (i=0; i<n; i++) {
×
2033
    t = p->child[i];
×
2034
    if (egraph_label(egraph, t) == x) return t;
×
2035
  }
2036
  return null_occurrence;
×
2037
}
2038

2039

2040
static bool analyze_or(egraph_t *egraph, composite_t *p) {
×
2041
  composite_t *q;
2042
  signature_t *sgn;
2043
  elabel_t *label;
2044
  uint32_t i, n;
2045
  int32_t k;
2046
  occ_t t, u;
2047

2048
  label = egraph->terms.label;
×
2049
  sgn = &egraph->sgn;
×
2050
  signature_or(p, label, sgn);
×
2051

2052
  // sgn = labels of t_1 ... t_n in increasing order
2053
  // with duplicates and false_labels removed
2054
  n = tag_arity(sgn->tag);
×
2055

2056
  if (n == 0) {
×
2057
    // (or t_1 ... t_n) == false
2058
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), false_occ);
×
2059
    egraph->stack.etag[k] = EXPL_SIMP_OR;
×
2060
#if TRACE
2061
      printf("---> EGRAPH: or term ");
2062
      print_occurrence(stdout, pos_occ(p->id));
2063
      printf(" = ");
2064
      print_composite(stdout, p);
2065
      printf(" reduced to false\n");
2066
#endif
2067
    return true;
×
2068
  }
2069

2070
  // if one t_i == true then true_label is in sgn->sigma[0]
2071
  // (or ... true ...) == true
2072
  if (sgn->sigma[0] == true_label) {
×
2073
    t = find_child_label(egraph, p, true_label);
×
2074
    assert(t >= 0);
2075
    add_eq_implies_eq(egraph, p, true_occ, t, true_occ);
×
2076
    return true;
×
2077
  }
2078

2079
  if (n == 1) {
×
2080
    // (or t_1 ... t_n) == t
2081
    t = find_child_label(egraph, p, sgn->sigma[0]);
×
2082
    assert(t >= 0);
2083
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), t);
×
2084
    egraph->stack.etag[k] = EXPL_SIMP_OR;
×
2085
#if TRACE
2086
      printf("---> EGRAPH: or term ");
2087
      print_occurrence(stdout, pos_occ(p->id));
2088
      printf(" = ");
2089
      print_composite(stdout, p);
2090
      printf(" reduced to ");
2091
      print_occurrence(stdout, t);
2092
      printf("\n");
2093
#endif
2094
    return true;
×
2095
  }
2096

2097
  // check for complementary labels
2098
  for (i=1; i<n; i++) {
×
2099
    if (sgn->sigma[i] == opposite_label(sgn->sigma[i-1])) {
×
2100
      t = find_child_label(egraph, p, sgn->sigma[i]);
×
2101
      u = find_child_label(egraph, p, sgn->sigma[i-1]);
×
2102
      assert(t >= 0 && u >= 0);
2103
      assert(egraph_label(egraph, u) == opposite_label(egraph_label(egraph, t)));
2104

2105
      // t == (not u) implies (or ... t ... u ...) == true
2106
      add_eq_implies_eq(egraph, p, true_occ, t, opposite_occ(u));
×
2107

2108
      return true;
×
2109
    }
2110
  }
2111

2112
  // check for congruence
2113
  q = congruence_table_get(&egraph->ctable, p, sgn, label);
×
2114
  if (q != p) {
×
2115
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
×
2116
    gen_or_congruence_antecedent(egraph, p, q, k);
×
2117
#if TRACE
2118
    printf("---> EGRAPH: equality ");
2119
    print_occurrence(stdout, pos_occ(p->id));
2120
    printf(" == ");
2121
    print_occurrence(stdout, pos_occ(q->id));
2122
    printf(" implied by or congruence\n");
2123
    printf("---> i.e., ");
2124
    print_composite(stdout, p);
2125
    printf(" == ");
2126
    print_composite(stdout, q);
2127
    printf("\n");
2128
#endif
2129
    return true;
×
2130
  }
2131

2132
  return false;
×
2133
}
2134

2135

2136

2137
/*
2138
 * p is (lambda c tag)
2139
 */
2140
static bool analyze_lambda(egraph_t *egraph, composite_t *p) {
×
2141
  composite_t *q;
2142
  signature_t *sgn;
2143
  elabel_t *label;
2144
  int32_t k;
2145

2146
  label = egraph->terms.label;
×
2147
  sgn = &egraph->sgn;
×
2148

2149
  signature_lambda(p, label, sgn);
×
2150
  q = congruence_table_get(&egraph->ctable, p, sgn, label);
×
2151
  if (q != p) {
×
2152
    // basic congruence
2153
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(p->id), pos_occ(q->id));
×
2154
    egraph->stack.etag[k] = EXPL_BASIC_CONGRUENCE;
×
2155
#if TRACE
2156
    printf("---> EGRAPH: equality ");
2157
    print_occurrence(stdout, pos_occ(p->id));
2158
    printf(" == ");
2159
    print_occurrence(stdout, pos_occ(q->id));
2160
    printf(" implied by lambda congruence\n");
2161
    printf("---> i.e., ");
2162
    print_composite(stdout, p);
2163
    printf(" == ");
2164
    print_composite(stdout, q);
2165
    printf("\n");
2166
#endif
2167
    return true;
×
2168
  }
2169

2170
  return false;
×
2171
}
2172

2173
static bool composite_simplifies(egraph_t *egraph, composite_t *p) {
9,257,823✔
2174
  switch (composite_kind(p)) {
9,257,823✔
2175
  case COMPOSITE_APPLY:
5,531,867✔
2176
  case COMPOSITE_UPDATE:
2177
  case COMPOSITE_TUPLE:
2178
    return analyze_basic(egraph, p);
5,531,867✔
2179

2180
  case COMPOSITE_EQ:
3,725,953✔
2181
    return analyze_eq(egraph, p);
3,725,953✔
2182

2183
  case COMPOSITE_ITE:
3✔
2184
    return analyze_ite(egraph, p);
3✔
2185

2186
  case COMPOSITE_DISTINCT:
×
2187
    return analyze_distinct(egraph, p);
×
2188

2189
  case COMPOSITE_OR:
×
2190
    return analyze_or(egraph, p);
×
2191

2192
  case COMPOSITE_LAMBDA:
×
2193
    return analyze_lambda(egraph, p);
×
2194
  }
2195

2196
  assert(false);
2197
  return false;
×
2198
}
2199

2200

2201

2202

2203
/*********************
2204
 *  TERM ACTIVATION  *
2205
 ********************/
2206

2207
/*
2208
 * Check whether t is a newly created term (not active yet)
2209
 */
2210
static inline bool egraph_term_is_fresh(egraph_t *egraph, eterm_t t) {
97,463✔
2211
  assert(0 <= t && t < egraph->terms.nterms);
2212
  return egraph->terms.label[t] == null_label;
97,463✔
2213
}
2214

2215

2216
/*
2217
 * Add composite d to the congruence table and use vectors
2218
 * - if d is created at decision_level > 0 push d
2219
 *   on the undo stack to be reanalyzed after backtracking.
2220
 * - check whether t is equal to another term u and if so
2221
 *   push the equality (t == u)
2222
 */
2223
static void egraph_activate_composite(egraph_t *egraph, composite_t *d) {
124,045✔
2224
  undo_tag_t tag;
2225

2226
  assert(composite_body(d) && egraph->decision_level >= egraph->base_level);
2227

2228
  tag = REANALYZE_COMPOSITE;
124,045✔
2229

2230
  if (! composite_simplifies(egraph, d)) {
124,045✔
2231
    /*
2232
     * d is a congruence root
2233
     * - composite_simplifies has added d to the congruence table
2234
     * - we need to add it to the parent vectors
2235
     */
2236
    attach_composite(d, egraph->terms.label, egraph->classes.parents);
100,993✔
2237
    tag = REANALYZE_CONGRUENCE_ROOT;
100,993✔
2238

2239
  }
2240

2241
  /*
2242
   * If decision_level > base_level, we'll have to reanalyze d
2243
   * after backtracking.
2244
   *
2245
   * If decision_level == base_level and base_level > 0, we'll also
2246
   * have to reanalyze d on the next call to egraph_pop.  This will
2247
   * force d to be removed from the parent vector and congruence table.
2248
   *
2249
   * We also have to do this if we're in reconcile_mode (since we may have to
2250
   * backtrack and undo the provisional equalities added by model reconciliation).
2251
   */
2252
  if (egraph->decision_level > 0 || egraph->reconcile_mode) {
124,045✔
2253
    undo_stack_push_ptr(&egraph->undo, d, tag);
66,652✔
2254
  }
2255
}
124,045✔
2256

2257

2258
/*
2259
 * Check whether theory variable x is a constant
2260
 * - tau = egraph type for x
2261
 */
2262
static bool constant_theory_var(egraph_t *egraph, etype_t tau, thvar_t x) {
87,659✔
2263
  if (x != null_thvar) {
87,659✔
2264
    switch (tau) {
61,789✔
2265
    case ETYPE_INT:
15,942✔
2266
    case ETYPE_REAL:
2267
    case ETYPE_BV:
2268
      return egraph->eg[tau]->is_constant(egraph->th[tau], x);
15,942✔
2269

2270
    default:
45,847✔
2271
      break;
45,847✔
2272
    }
2273
  }
2274

2275
  return false;
71,717✔
2276
}
2277

2278

2279
/*
2280
 * Attach variable x and type tau then activate term t:
2281
 * - add t to a fresh singleton class c
2282
 *
2283
 * HACK: don't do a full activation for (distinct ...) terms
2284
 * - it's enough to just add them to a singleton class.
2285
 * - maintaining them into the congruence table and parent vectors
2286
 *   is usually a waste of time.
2287
 */
2288
static void egraph_activate_term(egraph_t *egraph, eterm_t t, etype_t tau, thvar_t x) {
93,641✔
2289
  class_t c;
2290
  composite_t *d;
2291
  uint32_t dmask;
2292

2293
  assert(egraph_term_is_fresh(egraph, t));
2294

2295
  c = alloc_class(&egraph->classes);
93,641✔
2296
  d = egraph->terms.body[t];
93,641✔
2297
  egraph->terms.label[t] = pos_label(c);
93,641✔
2298
  egraph->terms.thvar[t] = x;
93,641✔
2299

2300
  dmask = 0x0;
93,641✔
2301
  if (constant_body(d) || constant_theory_var(egraph, tau, x)) {
93,641✔
2302
    dmask = 0x1;
7,250✔
2303
  }
2304
  init_class(&egraph->classes, c, t, dmask, tau, x);
93,641✔
2305

2306
  if (composite_body(d) && composite_kind(d) != COMPOSITE_DISTINCT) {
93,641✔
2307
    egraph_activate_composite(egraph, d);
67,767✔
2308
  }
2309
}
93,641✔
2310

2311

2312
/*
2313
 * Reactivate the terms in reanalyze_vector
2314
 * - this must be called after backtracking and before processing any equality
2315
 */
2316
static void egraph_reactivate_dynamic_terms(egraph_t *egraph) {
7,318✔
2317
  pvector_t *v;
2318
  composite_t *p;
2319
  uint32_t i, n;
2320

2321
  v = &egraph->reanalyze_vector;
7,318✔
2322
  n = v->size;
7,318✔
2323
  for (i=0; i<n; i++) {
63,596✔
2324
    p = v->data[i];
56,278✔
2325
    assert(composite_body(p));
2326
    egraph_activate_composite(egraph, p);
56,278✔
2327
  }
2328
  pvector_reset(v);
7,318✔
2329
}
7,318✔
2330

2331

2332

2333

2334

2335
/******************************************
2336
 *  EQUALITY/DISTINCT/DISEQUALITY CHECKS  *
2337
 *****************************************/
2338

2339
/*
2340
 * Check whether t1 and t2 are known to be disequal
2341
 * Returns true in the following cases:
2342
 * 1) t1 and (not t2) are equal
2343
 * 2) there are distinct constants a1 and a2 with t1 == a1 and t2 == a2
2344
 * 3) there's a term v = (eq u1 u2), such that v == false, and
2345
 *     t1 == u1, t2 == u2 or t1 == u2, t2 == u1
2346
 * 4) there's a term v = (distinct u_1 ... u_n) such that v == true,
2347
 *    and t1 == u_i and t2 == u_j with i /= j
2348
 * 5) t1 and t2 are attached to two theory variables x1 and x2,
2349
 *    and the theory solver knows that x1 != x2
2350
 */
2351
bool egraph_check_diseq(egraph_t *egraph, occ_t t1, occ_t t2) {
29,540✔
2352
  uint32_t *dmask;
2353
  composite_t *eq;
2354
  elabel_t l1, l2;
2355

2356
  l1 = egraph_label(egraph, t1);
29,540✔
2357
  l2 = egraph_label(egraph, t2);
29,540✔
2358

2359
  if (l1 == l2) return false;
29,540✔
2360
  if (l1 == opposite_label(l2))  return true;  // t1 == (not t2)
18,068✔
2361

2362
  if (is_pos_label(l1) && is_pos_label(l2)) {
18,068✔
2363
    dmask = egraph->classes.dmask;
18,067✔
2364
    if ((dmask[class_of(l1)] & dmask[class_of(l2)]) != 0) {
18,067✔
2365
      return true;
123✔
2366
    }
2367
  }
2368

2369
  eq = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
17,945✔
2370
  return eq != NULL_COMPOSITE && egraph_occ_is_false(egraph, pos_occ(eq->id));
17,945✔
2371
}
2372

2373

2374
/*
2375
 * Check whether t1 and t2 are disequal via the theory solver
2376
 * Return true if t1 and t2 are attached to two theory variables x1 and x2
2377
 * and the corresponding theory solver knows that x1 and x2 are distinct.
2378
 * - this looks at the base variables for t1 and t2
2379
 */
2380
bool egraph_check_theory_diseq(egraph_t *egraph, occ_t t1, occ_t t2) {
108,797✔
2381
  etype_t i;
2382
  thvar_t x1, x2;
2383

2384
  i = egraph_type(egraph, t1);
108,797✔
2385
  switch (i) {
108,797✔
2386
  case ETYPE_INT:
91,611✔
2387
  case ETYPE_REAL:
2388
  case ETYPE_BV:
2389
  case ETYPE_FUNCTION:
2390
    x1 = egraph_term_base_thvar(egraph, term_of_occ(t1));
91,611✔
2391
    x2 = egraph_term_base_thvar(egraph, term_of_occ(t2));
91,611✔
2392
    return x1 != null_thvar && x2 != null_thvar &&
91,611✔
2393
      egraph->eg[i] != NULL &&
274,833✔
2394
      egraph->eg[i]->check_diseq(egraph->th[i], x1, x2);
91,611✔
2395

2396
  default:
17,186✔
2397
    return false;
17,186✔
2398
  }
2399
}
2400

2401

2402
/*
2403
 * Check whether d = (distinct u_1 ... u_n) is false.
2404
 * Returns true if u_i == u_j for i/=j
2405
 */
2406
bool egraph_check_distinct_false(egraph_t *egraph, composite_t *d) {
9✔
2407
  occ_t t;
2408
  elabel_t x;
2409
  uint32_t i, n;
2410
  int_hmap_t *imap;
2411
  int_hmap_pair_t *p;
2412
  bool result;
2413

2414
  assert(composite_kind(d) == COMPOSITE_DISTINCT);
2415

2416
  n = composite_arity(d);
9✔
2417
  result = false;
9✔
2418
  imap = egraph_get_imap(egraph);
9✔
2419

2420
  for (i=0; i<n; i++) {
36✔
2421
    t = d->child[i];
27✔
2422
    x = egraph_label(egraph, t);
27✔
2423
    p = int_hmap_get(imap, x);
27✔
2424
    if (p->val >= 0) {
27✔
2425
      result = true;
×
2426
      break;
×
2427
    }
2428
    p->val = t;
27✔
2429
  }
2430

2431
  int_hmap_reset(imap);
9✔
2432

2433
  return result;
9✔
2434
}
2435

2436

2437
/*
2438
 * Check whether d = (distinct u_1 ... u_n) is true.
2439
 * (Expensive).
2440
 */
2441
bool egraph_check_distinct_true(egraph_t *egraph, composite_t *d) {
×
2442
  uint32_t i, j, n;
2443
  occ_t x, y;
2444

2445
  assert(composite_kind(d) == COMPOSITE_DISTINCT);
2446
  n = composite_arity(d);
×
2447

2448
  for (i=0; i<n; i++) {
×
2449
    x = d->child[i];
×
2450
    for (j=i+1; j<n; j++) {
×
2451
      y = d->child[j];
×
2452
      if (! egraph_check_diseq(egraph, x, y) && ! egraph_check_theory_diseq(egraph, x, y)) {
×
2453
        return false;
×
2454
      }
2455
    }
2456
  }
2457

2458
  return true;
×
2459
}
2460

2461

2462
/*
2463
 * Incomplete but faster version
2464
 */
2465
bool egraph_fast_check_distinct_true(egraph_t *egraph, composite_t *d) {
×
2466
  uint32_t *dmask;
2467
  uint32_t i, n, dmsk;
2468
  occ_t x;
2469

2470
  assert(composite_kind(d) == COMPOSITE_DISTINCT);
2471

2472
  n = composite_arity(d);
×
2473
  assert(n > 0);
2474

2475
  dmask = egraph->classes.dmask;
×
2476
  dmsk = ~((uint32_t) 0);
×
2477
  i = 0;
×
2478
  do {
2479
    x = d->child[i];
×
2480
    dmsk &= dmask[egraph_class(egraph, x)];
×
2481
    i ++;
×
2482
  } while (dmsk != 0 && i < n);
×
2483

2484
  // dmsk trick does not rule out u_i == u_j
2485
  return dmsk != 0 && ! egraph_check_distinct_false(egraph, d);
×
2486
}
2487

2488

2489

2490

2491
/*******************************************
2492
 *   PREDICATE/BOOLEAN TERM CONSTRUCTORS   *
2493
 ******************************************/
2494

2495
#ifndef NDEBUG
2496

2497
/*
2498
 * For debugging: check whether (t == false) is in the assertion queue
2499
 * - i.e., t was asserted to be false, but egraph_term_is_false(egraph, t)
2500
 *   does not hold yet.
2501
 */
2502
static bool egraph_term_asserted_false(egraph_t *egraph, eterm_t t) {
2503
  equeue_elem_t *e;
2504
  uint32_t i, n;
2505
  occ_t u;
2506

2507
  u = pos_occ(t);
2508

2509
  n = egraph->stack.top;
2510
  for (i=egraph->stack.prop_ptr; i<n; i++) {
2511
    e = egraph->stack.eq + i;
2512
    if ((e->lhs == u && e->rhs == false_occ) ||
2513
        (e->lhs == false_occ && e->rhs == u)) {
2514
      return true;
2515
    }
2516
  }
2517

2518
  return false;
2519
}
2520

2521
#endif
2522

2523

2524
/*
2525
 * Atoms (type = BOOL, theory variable = a fresh boolean variable)
2526
 * - all return pos_occ(theory_variable)
2527
 * - make_pred build an uninterpreted predicate (f a[0] ... a[n])
2528
 * - make_distinct rewrites (distinct a[0] ... a[n-1]) to a conjunction of
2529
 *   disequalities if the distinct limit is reached.
2530
 */
2531
static literal_t egraph_term2literal(egraph_t *egraph, eterm_t t) {
58,742✔
2532
  bvar_t v;
2533

2534
  if (egraph_term_is_fresh(egraph, t)) {
58,742✔
2535
    v = create_boolean_variable(egraph->core);
31,151✔
2536
    create_egraph_atom(egraph, v, t);
31,151✔
2537
    egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
31,151✔
2538
    egraph_activate_term(egraph, t, ETYPE_BOOL, v);
31,151✔
2539
  } else {
2540
#if CONSERVATIVE_DISEQ_AXIOMS
2541
    v = egraph->terms.thvar[t];
2542
    assert(v != null_thvar && egraph_term_type(egraph, t) == ETYPE_BOOL);
2543
#else
2544
    /*
2545
     * Hackish: this assumes that all existing boolean terms with no
2546
     * theory variables attached are equalities asserted false (via
2547
     * egraph_assert_diseq_axiom) at the base level.
2548
     */
2549
    assert(egraph_term_type(egraph, t) == ETYPE_BOOL);
2550
    v = egraph->terms.thvar[t];
27,591✔
2551
    if (v == null_thvar) {
27,591✔
2552
      /*
2553
       * This assertion is wrong: the equality t == false may not
2554
       * be processed yet (i.e., still in the queue). If that's the
2555
       * case, egraph_term_is_false(egraph, t) will return false and
2556
       * the assertion will fail.
2557
       */
2558
      // assert(egraph_term_is_eq(egraph, t) && egraph_term_is_false(egraph, t));
2559
      assert(egraph_term_is_eq(egraph, t));
2560
      assert(egraph_term_is_false(egraph, t) || egraph_term_asserted_false(egraph, t));
2561

2562
      return false_literal;
32✔
2563
    }
2564
#endif
2565
  }
2566

2567
  return pos_lit(v);
58,710✔
2568
}
2569

2570

2571
literal_t egraph_make_pred(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
4,406✔
2572
  eterm_t t;
2573
  t = egraph_apply_term(egraph, f, n, a);
4,406✔
2574
  return egraph_term2literal(egraph, t);
4,406✔
2575
}
2576

2577

2578
literal_t egraph_make_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
94,221✔
2579
  occ_t aux;
2580
  eterm_t t;
2581

2582
  // simplify
2583
  if (t1 == t2) return true_literal;
94,221✔
2584

2585
  /*
2586
   * Careful: if we're in the reconcile_mode at the base level
2587
   * we can't check for equality/disequality here using egraph_equal_occ or
2588
   * egraph_check_diseq. That's because there may be tentative equalities
2589
   * in the egraph at this point (so egraph_equal_occ and egraph_check_diseq
2590
   * may give incorrect results).
2591
   *
2592
   * The test for reconcile_mode was missing. Bug reported by Martin Gabris.
2593
   */
2594
  //  if (egraph->base_level == egraph->decision_level) {
2595
  if (egraph->base_level == egraph->decision_level
94,178✔
2596
      && (! egraph->reconcile_mode || egraph->stack.top == egraph->reconcile_neqs)) {
14,642✔
2597
    if (egraph_equal_occ(egraph, t1, t2)) {
14,636✔
2598
      return true_literal;
37✔
2599
    } else if (egraph_check_diseq(egraph, t1, t2)) {
14,599✔
2600
      return false_literal;
195✔
2601
    }
2602
  }
2603

2604
  if (egraph_check_theory_diseq(egraph, t1, t2)) {
93,946✔
2605
    // should work at any decision level
2606
    return false_literal;
47,704✔
2607
  }
2608

2609
  // normalize
2610
  if (t1 > t2) {
46,242✔
2611
    aux = t1; t1 = t2; t2 = aux;
29,650✔
2612
  }
2613

2614
  t = egraph_eq_term(egraph, t1, t2);
46,242✔
2615
  return egraph_term2literal(egraph, t);
46,242✔
2616
}
2617

2618

2619
#if ! CONSERVATIVE_DISEQ_AXIOMS
2620

2621
/*
2622
 * Variant of make_eq used by assert_diseq_axiom:
2623
 * create a term but not the attached atom or literal
2624
 */
2625
static occ_t egraph_make_eq_term(egraph_t *egraph, occ_t t1, occ_t t2) {
2,573✔
2626
  occ_t aux;
2627
  eterm_t t;
2628

2629
  // simplify
2630
  if (t1 == t2) return true_occ;
2,573✔
2631

2632
  if (egraph->base_level == egraph->decision_level) {
2,571✔
2633
    if (egraph_equal_occ(egraph, t1, t2)) {
2,571✔
2634
      return true_occ;
4✔
2635
    } else if (egraph_check_diseq(egraph, t1, t2) || egraph_check_theory_diseq(egraph, t1, t2)) {
2,567✔
2636
      return false_occ;
60✔
2637
    }
2638
  }
2639

2640
  // normalize
2641
  if (t1 > t2) {
2,507✔
2642
    aux = t1; t1 = t2; t2 = aux;
1,220✔
2643
  }
2644

2645
  t = egraph_eq_term(egraph, t1, t2);
2,507✔
2646
  if (egraph_term_is_fresh(egraph, t)) {
2,507✔
2647
    egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
2,493✔
2648
    egraph_activate_term(egraph, t, ETYPE_BOOL, null_thvar);
2,493✔
2649
  }
2650
  return pos_occ(t);
2,507✔
2651
}
2652

2653
#endif
2654

2655
/*
2656
 * Generate all equalities (a[i] == a[j]) for 0 <= i < j <n
2657
 * - the result is stored as literals in vector *v
2658
 */
2659
static void expand_distinct(egraph_t *egraph, uint32_t n, occ_t *a, ivector_t *v) {
8✔
2660
  uint32_t i, j;
2661
  occ_t a_i;
2662
  literal_t l;
2663

2664
  ivector_reset(v);
8✔
2665
  for (i=0; i<n-1; i++) {
25✔
2666
    a_i = a[i];
17✔
2667
    for (j=i+1; j<n; j++) {
44✔
2668
      l = egraph_make_eq(egraph, a_i, a[j]);
27✔
2669
      ivector_push(v, l);
27✔
2670
    }
2671
  }
2672
}
8✔
2673

2674
/*
2675
 * Create a fresh boolean variable x and assert clauses equivalent to
2676
 * - not(x) == (distinct a[0] ... a[n-1])
2677
 */
2678
static literal_t assert_distinct_def_clauses(egraph_t *egraph, uint32_t n, occ_t *a) {
×
2679
  ivector_t *v;
2680
  literal_t l;
2681
  uint32_t i, p;
2682
  smt_core_t *core;
2683

2684
  v = &egraph->aux_buffer;
×
2685
  expand_distinct(egraph, n, a, v);
×
2686
  core = egraph->core;
×
2687
  assert(core != NULL);
2688
  l = pos_lit(create_boolean_variable(core));
×
2689

2690
  // clauses for pos_lit(x) == (or (eq a[0] a[1]) .... (eq a[n-1] a[n]))
2691
  p = v->size;
×
2692
  for (i=0; i<p; i++) {
×
2693
    add_binary_clause(core, l, not(v->data[i]));
×
2694
  }
2695
  ivector_push(v, not(l));
×
2696
  add_clause(core, p+1, v->data);
×
2697

2698
  return not(l);
×
2699
}
2700

2701

2702
literal_t egraph_make_distinct(egraph_t *egraph, uint32_t n, occ_t *a) {
6✔
2703
  eterm_t t;
2704

2705
  /*
2706
   * TODO: check this:
2707
   * 1) normalize the term t?
2708
   * 2) always expand small distinct terms?
2709
   */
2710
  t = egraph_distinct_term(egraph, n, a);
6✔
2711
  if (t == null_eterm) {
6✔
2712
    return assert_distinct_def_clauses(egraph, n, a);
×
2713
  } else {
2714
    return egraph_term2literal(egraph, t);
6✔
2715
  }
2716
}
2717

2718

2719

2720

2721
/*
2722
 * Boolean if-then-else
2723
 */
2724
literal_t egraph_make_boolean_ite(egraph_t *egraph, occ_t c, occ_t t1, occ_t t2) {
×
2725
  eterm_t t;
2726

2727
  if (is_pos_occ(c)) {
×
2728
    t = egraph_ite_term(egraph, c, t1, t2);
×
2729
  } else {
2730
    t = egraph_ite_term(egraph, opposite_occ(c), t2, t1);
×
2731
  }
2732
  return egraph_term2literal(egraph, t);
×
2733
}
2734

2735

2736
/*
2737
 * OR term
2738
 */
2739
literal_t egraph_make_or(egraph_t *egraph, uint32_t n, occ_t *a) {
×
2740
  eterm_t t;
2741

2742
  t = egraph_or_term(egraph, n, a);
×
2743
  return egraph_term2literal(egraph, t);
×
2744
}
2745

2746

2747

2748

2749

2750
/****************************************
2751
 *  TEST WHETHER COMPOSITE TERMS EXIST  *
2752
 ***************************************/
2753

2754
bool egraph_apply_exists(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
×
2755
  return egraph_find_apply_term(egraph, f, n, a) >= 0;
×
2756
}
2757

2758
bool egraph_ite_exists(egraph_t *egraph, occ_t c, occ_t t1, occ_t t2) {
×
2759
  if (is_pos_occ(c)) {
×
2760
    return egraph_find_ite_term(egraph, c, t1, t2) >= 0;
×
2761
  } else {
2762
    return egraph_find_ite_term(egraph, opposite_occ(c), t2, t1) >= 0;
×
2763
  }
2764
}
2765

2766
bool egraph_update_exists(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v) {
×
2767
  return egraph_find_update_term(egraph, f, n, a, v) >= 0;
×
2768
}
2769

2770
bool egraph_tuple_exists(egraph_t *egraph, uint32_t n, occ_t *a) {
×
2771
  return egraph_find_tuple_term(egraph, n, a) >= 0;
×
2772
}
2773

2774
bool egraph_eq_exists(egraph_t *egraph, occ_t t1, occ_t t2) {
×
2775
  if (t1 < t2) {
×
2776
    return egraph_find_eq_term(egraph, t1, t2) >= 0;
×
2777
  } else {
2778
    return egraph_find_eq_term(egraph, t2, t1) >= 0;
×
2779
  }
2780
}
2781

2782
bool egraph_distinct_exists(egraph_t *egraph, uint32_t n, occ_t *a) {
×
2783
  return egraph_find_distinct_term(egraph, n, a) >= 0;
×
2784
}
2785

2786
bool egraph_or_exists(egraph_t *egraph, uint32_t n, occ_t *a) {
×
2787
  return egraph_find_or_term(egraph, n, a) >= 0;
×
2788
}
2789

2790

2791
bool egraph_lambda_exists(egraph_t *egraph, occ_t t, type_t tau) {
×
2792
  int32_t tag;
2793

2794
  tag = find_lambda_tag_for_type(&egraph->tag_table, egraph->types, tau);
×
2795
  return tag >= 0 && egraph_find_lambda_term(egraph, t, tag);
×
2796
}
2797

2798

2799

2800
/**********************************
2801
 *  APPLY/UPDATE SIMPLIFICATIONS  *
2802
 *********************************/
2803

2804
/*
2805
 * Check whether (a[0], ..., a[n-1]) != (b[0],...,b[n-1]) holds at the base level
2806
 */
2807
static bool egraph_check_diseq_arrays(egraph_t *egraph, uint32_t n, occ_t *a, occ_t *b) {
12,374✔
2808
  uint32_t i;
2809

2810
  for (i=0; i<n; i++) {
24,290✔
2811
    if (egraph_check_diseq(egraph, a[i], b[i]) || egraph_check_theory_diseq(egraph, a[i], b[i])) {
12,374✔
2812
      return true;
458✔
2813
    }
2814
  }
2815
  return false;
11,916✔
2816
}
2817

2818

2819
/*
2820
 * Check whether (a[0] ... a[n-1]) == (b[0] ... b[n-1]) at the current level
2821
 */
2822
static bool egraph_check_eq_arrays(egraph_t *egraph, uint32_t n, occ_t *a, occ_t *b) {
22,835✔
2823
  uint32_t i;
2824

2825
  for (i=0; i<n; i++) {
34,316✔
2826
    if (! egraph_check_eq(egraph, a[i], b[i])) {
22,835✔
2827
      return false;
11,354✔
2828
    }
2829
  }
2830
  return true;
11,481✔
2831
}
2832

2833

2834
static void auto_activate(egraph_t *egraph, eterm_t u, type_t type);
2835

2836
/*
2837
 * Check whether (apply f a[0] ... a[n-1]) is reducible
2838
 * to an existing term occurrence u.
2839
 * - return null_occurrence if nothing is found
2840
 */
2841
static occ_t egraph_reduce_apply(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
20,886✔
2842
  composite_t *cmp;
2843
  eterm_t t;
2844
  occ_t g;
2845

2846
  g = f;
20,886✔
2847
  assert(is_pos_occ(g));
2848
  cmp = egraph_term_body(egraph, term_of_occ(g));
20,886✔
2849
  while (composite_body(cmp) && composite_kind(cmp) == COMPOSITE_UPDATE) {
21,344✔
2850
    assert(composite_arity(cmp) == n + 2);
2851
    // g is (update h b[0] .. b[n-1] v)
2852
    if (egraph_check_diseq_arrays(egraph, n, cmp->child + 1, a)) {
12,374✔
2853
      // (apply g a[0] ... a[n-1]) --> (apply h a[0] ... a[n-1])
2854
      g = composite_child(cmp, 0); // g := h
458✔
2855
      assert(is_pos_occ(g));
2856
      cmp = egraph_term_body(egraph, term_of_occ(g));
458✔
2857
    } else if (egraph_check_eq_arrays(egraph, n, cmp->child + 1, a)) {
11,916✔
2858
      // (apply g a[0] ... a[n-1]) --> v
2859
      return composite_child(cmp, n+1);
11,472✔
2860
    } else {
2861
      if (g != f) {
444✔
2862
        // (apply f a[0] ... a[n-1]) == (apply g a[0] ... a[n-1])
2863
        // so we return (apply g a[0] ... a[n-1]).
2864
        t = egraph_apply_term(egraph, g, n, a);
49✔
2865
        if (egraph_term_is_fresh(egraph, t)) {
49✔
2866
          type_t tau;
2867

2868
          tau = egraph_term_real_type(egraph, term_of_occ(g));
49✔
2869
          tau = function_type_range(egraph->types, tau);
49✔
2870
          auto_activate(egraph, t, tau);
49✔
2871
        }
2872
        return pos_occ(t);
49✔
2873
      }
2874
      break;
395✔
2875
    }
2876
  }
2877

2878
  return null_occurrence;
9,365✔
2879
}
2880

2881

2882

2883

2884

2885
/******************************************
2886
 *   CONSTRUCTORS FOR NON-BOOLEAN TERMS   *
2887
 *****************************************/
2888

2889
/*
2890
 * Conversion from a type tau in the type table to an egraph type
2891
 */
2892
static const uint8_t type_kind2etype[NUM_TYPE_KINDS] = {
2893
  ETYPE_NONE,     // UNUSED_TYPE (should not occur)
2894
  ETYPE_BOOL,     // BOOL_TYPE
2895
  ETYPE_INT,      // INT_TYPE
2896
  ETYPE_REAL,     // REAL_TYPE
2897
  ETYPE_NONE,     // FF_TYPE // TODO not implemented
2898
  ETYPE_BV,       // BITVECTOR_TYPE
2899
  ETYPE_NONE,     // SCALAR_TYPE
2900
  ETYPE_NONE,     // UNINTERPRETED_TYPE
2901
  ETYPE_NONE,     // VARIABLE_TYPE (should not occur)
2902
  ETYPE_TUPLE,    // TUPLE_TYPE
2903
  ETYPE_FUNCTION, // FUNCTION_TYPE
2904
  ETYPE_NONE,     // INSTANCE_TYPE
2905
};
2906

2907
static inline etype_t type_to_etype(type_table_t *types, type_t tau) {
53,759✔
2908
  return (etype_t) type_kind2etype[type_kind(types, tau)];
53,759✔
2909
}
2910

2911

2912
/*
2913
 * Activate egraph term u and attach an adequate theory variable to u
2914
 * - type = type for u
2915
 */
2916
static void auto_activate(egraph_t *egraph, eterm_t u, type_t type) {
48,525✔
2917
  etype_t tau;
2918
  thvar_t x;
2919
  uint32_t n;
2920

2921
  assert(egraph_term_is_fresh(egraph, u));
2922

2923
  /*
2924
   * To ensure that attach_eterm is called last:
2925
   * 1) create a theory variable x
2926
   * 2) activate the term u
2927
   * 3) attach u to x in the satellite solver
2928
   */
2929
  tau = type_to_etype(egraph->types, type);
48,525✔
2930
  x = null_thvar;
48,525✔
2931
  switch (tau) {
48,525✔
2932
  case ETYPE_INT:
3,257✔
2933
    if (egraph->arith_smt != NULL) {
3,257✔
2934
      x = egraph->arith_eg->create_arith_var(egraph->th[ETYPE_INT], true);
3,257✔
2935
    }
2936
    break;
3,257✔
2937

2938
  case ETYPE_REAL:
958✔
2939
    if (egraph->arith_smt != NULL) {
958✔
2940
      x = egraph->arith_eg->create_arith_var(egraph->th[ETYPE_REAL], false);
958✔
2941
    }
2942
    break;
958✔
2943

2944
  case ETYPE_BV:
6,493✔
2945
    if (egraph->bv_smt != NULL) {
6,493✔
2946
      n = bv_type_size(egraph->types, type);
6,493✔
2947
      x = egraph->bv_eg->create_bv_var(egraph->th[ETYPE_BV], n);
6,493✔
2948
    }
2949
    break;
6,493✔
2950

2951
  case ETYPE_FUNCTION:
14,476✔
2952
    if (egraph->ctrl[ETYPE_FUNCTION] != NULL) {
14,476✔
2953
      x = egraph->fun_eg->create_fun_var(egraph->th[ETYPE_FUNCTION], type);
13,736✔
2954
    }
2955
    break;
14,476✔
2956

2957
  case ETYPE_NONE:
22,312✔
2958
    // no theory variable
2959
    break;
22,312✔
2960

2961
  case ETYPE_TUPLE:
789✔
2962
    // if u is a tuple term, theory variable = the term itself
2963
    if (egraph_term_is_composite_tuple(egraph, u)) {
789✔
2964
      x = u;
677✔
2965
    }
2966
    break;
789✔
2967

2968
  case ETYPE_BOOL:
240✔
2969
    x = create_boolean_variable(egraph->core);
240✔
2970
    create_egraph_atom(egraph, x, u);
240✔
2971
    break;
240✔
2972

2973
  default:
×
2974
    assert(false);
2975
    abort();
×
2976
  }
2977

2978
  // set the term type and activate it
2979
  egraph_set_term_real_type(egraph, u, type);
48,525✔
2980
  egraph_activate_term(egraph, u, tau, x);
48,525✔
2981

2982
  // attach u to x in the satellite solver
2983
  if (tau <= ETYPE_FUNCTION && egraph->eg[tau] != NULL) {
48,525✔
2984
    egraph->eg[tau]->attach_eterm(egraph->th[tau], x, u);
24,444✔
2985
  }
2986

2987
}
48,525✔
2988

2989

2990
/*
2991
 * Create the constant of type tau and index id
2992
 * - id = same index as the matching constant in the term table
2993
 */
2994
eterm_t egraph_make_constant(egraph_t *egraph, type_t tau, int32_t id) {
2,008✔
2995
  eterm_t t;
2996

2997
  t = egraph_constant_term(egraph, tau, id);
2,008✔
2998
  if (egraph_term_is_fresh(egraph, t)) {
2,008✔
2999
    egraph_set_term_real_type(egraph, t, tau);
1,184✔
3000
    egraph_activate_term(egraph, t, ETYPE_NONE, null_thvar);
1,184✔
3001
  }
3002

3003
  return t;
2,008✔
3004
}
3005

3006

3007
/*
3008
 * If-then-else of type tau
3009
 */
3010
eterm_t egraph_make_ite(egraph_t *egraph, occ_t c, occ_t t1, occ_t t2, type_t tau) {
2✔
3011
  eterm_t t;
3012

3013
  if (is_pos_occ(c)) {
2✔
3014
    t = egraph_ite_term(egraph, c, t1, t2);
2✔
3015
  } else {
3016
    t = egraph_ite_term(egraph, opposite_occ(c), t2, t1);
×
3017
  }
3018

3019
  if (egraph_term_is_fresh(egraph, t)) {
2✔
3020
    auto_activate(egraph, t, tau);
2✔
3021
  }
3022
  return t;
2✔
3023
}
3024

3025

3026
/*
3027
 * Update of type tau
3028
 */
3029
eterm_t egraph_make_update(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, occ_t v, type_t tau) {
11,470✔
3030
  composite_t *cmp;
3031
  eterm_t t;
3032

3033
  assert(is_pos_occ(f));
3034

3035
  /*
3036
   * simplification: remove double updates at the same indices:
3037
   * rewrite (update (update f x a) x b) to (update f x b)
3038
   */
3039
  cmp = egraph_term_body(egraph, term_of_occ(f));
11,470✔
3040
  if (composite_body(cmp) && composite_kind(cmp) == COMPOSITE_UPDATE &&
22,363✔
3041
      egraph_check_eq_arrays(egraph, n, cmp->child + 1, a)) {
10,893✔
3042
    f = cmp->child[0];
2✔
3043
    assert(is_pos_occ(f));
3044
  }
3045

3046
  /*
3047
   * Simplification 2: (update f x (f x)) is f
3048
   */
3049
  cmp = egraph_term_body(egraph, term_of_occ(v));
11,470✔
3050
  if (is_pos_occ(v) && composite_body(cmp) &&
12,000✔
3051
      composite_kind(cmp) == COMPOSITE_APPLY &&
530✔
3052
      cmp->child[0] == f &&  egraph_check_eq_arrays(egraph, n, cmp->child + 1, a)) {
526✔
3053
    return term_of_occ(f);
7✔
3054
  }
3055

3056
  t = egraph_update_term(egraph, f, n, a, v);
11,463✔
3057
  if (egraph_term_is_fresh(egraph, t)) {
11,463✔
3058
    auto_activate(egraph, t, tau);
11,462✔
3059
  }
3060
  return t;
11,463✔
3061
}
3062

3063

3064
/*
3065
 * Tuples: (type = tau, etype = TUPLE, theory variable = itself)
3066
 * - the term's body is (tuple a[0], .., a[n-1])
3067
 */
3068
eterm_t egraph_make_tuple(egraph_t *egraph, uint32_t n, occ_t *a, type_t tau) {
677✔
3069
  eterm_t t;
3070

3071
  t = egraph_tuple_term(egraph, n, a);
677✔
3072
  if (egraph_term_is_fresh(egraph, t)) {
677✔
3073
    auto_activate(egraph, t, tau);
677✔
3074
  }
3075
  return t;
677✔
3076
}
3077

3078

3079
/*
3080
 * Constant lambda term (lambda ... c)
3081
 * - tau must be a function type
3082
 * - attach a theory variable in the array solver (if present)
3083
 */
3084
eterm_t egraph_make_lambda(egraph_t *egraph, occ_t c, type_t tau) {
×
3085
  eterm_t t;
3086
  int32_t tag;
3087

3088
  tag = lambda_tag_for_type(&egraph->tag_table, egraph->types, tau);
×
3089
  t = egraph_lambda_term(egraph, c, tag);
×
3090
  if (egraph_term_is_fresh(egraph, t)) {
×
3091
    auto_activate(egraph, t, tau);
×
3092
  }
3093

3094
  return t;
×
3095
}
3096

3097

3098
/*
3099
 * TYPE CONSTRAINTS
3100
 */
3101

3102
/*
3103
 * Axiom for term occurrence t of scalar type tau
3104
 */
3105
static void egraph_add_scalar_axiom(egraph_t *egraph, occ_t t, type_t tau) {
447✔
3106
  uint32_t i, n;
3107
  occ_t k;
3108
  ivector_t *v;
3109

3110
  n = scalar_type_cardinal(egraph->types, tau);
447✔
3111
  v = &egraph->aux_buffer;
447✔
3112
  ivector_reset(v);
447✔
3113

3114
  for (i=0; i<n; i++) {
1,291✔
3115
    k = pos_occ(egraph_make_constant(egraph, tau, i));
844✔
3116
    ivector_push(v, egraph_make_eq(egraph, t, k));
844✔
3117
  }
3118
  assert(v->size == n);
3119

3120
  add_clause(egraph->core, n, v->data);
447✔
3121
}
447✔
3122

3123

3124
/*
3125
 * Skolem term for type tau:
3126
 * - if tau is atomic, return a fresh variable of type tau
3127
 * - if tau is a tuple type, return (tuple x_1 ... x_n)
3128
 *   where x_1 ... x_n are recursive skolem terms for tau's component
3129
 */
3130
eterm_t egraph_skolem_term(egraph_t *egraph, type_t tau) {
14,774✔
3131
  tuple_type_t *d;
3132
  occ_t *a;
3133
  eterm_t t;
3134
  uint32_t i, n;
3135

3136
  switch (type_kind(egraph->types, tau)) {
14,774✔
3137
  case TUPLE_TYPE:
487✔
3138
    d = tuple_type_desc(egraph->types, tau);
487✔
3139
    n = d->nelem;
487✔
3140
    a = alloc_istack_array(&egraph->istack, n);
487✔
3141
    for (i=0; i<n; i++) {
1,064✔
3142
      a[i] = pos_occ(egraph_skolem_term(egraph, d->elem[i]));
577✔
3143
    }
3144
    t = egraph_make_tuple(egraph, n, a, tau);
487✔
3145
    free_istack_array(&egraph->istack, a);
487✔
3146
    break;
487✔
3147

3148
  default:
14,287✔
3149
    t = egraph_make_variable(egraph, tau);
14,287✔
3150
    break;
14,287✔
3151
  }
3152

3153
  return t;
14,774✔
3154
}
3155

3156

3157
/*
3158
 * Type constraints for a fresh term t of type tau
3159
 */
3160
static void egraph_add_type_constraints(egraph_t *egraph, eterm_t t, type_t tau) {
36,335✔
3161
  occ_t sk;
3162
  literal_t l;
3163
  int32_t k;
3164

3165
  switch (type_kind(egraph->types, tau)) {
36,335✔
3166
  case SCALAR_TYPE:
447✔
3167
    egraph_add_scalar_axiom(egraph, pos_occ(t), tau);
447✔
3168
    break;
447✔
3169

3170
  case TUPLE_TYPE:
112✔
3171
    sk = pos_occ(egraph_skolem_term(egraph, tau));
112✔
3172
    if (egraph->presearch) {
112✔
3173
      // before start search: assert the axiom directly
3174
      assert(egraph->decision_level == egraph->base_level);
3175
      k = egraph_stack_push_eq(&egraph->stack, pos_occ(t), sk);
112✔
3176
      egraph->stack.etag[k] = EXPL_AXIOM;
112✔
3177
    } else {
3178
      /*
3179
       * Add a unit clause in the core.
3180
       *
3181
       * IMPORTANT: we can't add an equality axiom directly
3182
       * (even if decision_level == base_level), because
3183
       * any equality pushed into egraph->stack may be removed
3184
       * (in final_check).
3185
       */
3186
      l = egraph_make_eq(egraph, pos_occ(t), sk);
×
3187
      add_unit_clause(egraph->core, l);
×
3188
    }
3189
    break;
112✔
3190

3191
  default:
35,776✔
3192
    break;
35,776✔
3193
  }
3194
}
36,335✔
3195

3196
/*
3197
 * Create a fresh variable of type tau
3198
 */
3199
eterm_t egraph_make_variable(egraph_t *egraph, type_t tau) {
14,609✔
3200
  eterm_t t;
3201

3202
  t = new_eterm(&egraph->terms, VARIABLE_BODY);
14,609✔
3203
  auto_activate(egraph, t, tau);
14,609✔
3204
  egraph_add_type_constraints(egraph, t, tau);
14,609✔
3205
  return t;
14,609✔
3206
}
3207

3208

3209
/*
3210
 * Create a function application of type tau
3211
 */
3212
eterm_t egraph_make_apply(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a, type_t tau) {
21,791✔
3213
  eterm_t t;
3214
  occ_t u;
3215
  int32_t k;
3216

3217
  t = egraph_apply_term(egraph, f, n, a);
21,791✔
3218
  if (egraph_term_is_fresh(egraph, t)) {
21,791✔
3219
    auto_activate(egraph, t, tau);
21,726✔
3220
    egraph_add_type_constraints(egraph, t, tau);
21,726✔
3221
    if (egraph->presearch) {
21,726✔
3222
      assert(egraph->decision_level == egraph->base_level);
3223
      // check for apply/update reduction
3224
      u = egraph_reduce_apply(egraph, f, n, a);
20,886✔
3225
      if (u != null_occurrence) {
20,886✔
3226
        // add (t == u) as an axiom
3227
        k = egraph_stack_push_eq(&egraph->stack, pos_occ(t), u);
11,521✔
3228
        egraph->stack.etag[k] = EXPL_AXIOM;
11,521✔
3229
        egraph->stats.app_reductions ++;
11,521✔
3230
      }
3231
    }
3232
  }
3233
  return t;
21,791✔
3234
}
3235

3236

3237

3238

3239
/***************
3240
 *  UTILITIES  *
3241
 **************/
3242

3243
/*
3244
 * Search for a tuple-term u such that u == t
3245
 * - return null_eterm if there is none
3246
 */
3247
eterm_t egraph_get_tuple_in_class(egraph_t *egraph, eterm_t t) {
245✔
3248
  eterm_t tv;
3249
  class_t c;
3250

3251
  c = egraph_term_class(egraph, t);
245✔
3252
  assert(egraph_class_is_tuple(egraph, c));
3253
  tv = egraph_class_thvar(egraph, c);
245✔
3254

3255
#ifndef NDEBUG
3256
  if (tv != null_eterm) {
3257
    composite_t *cmp;
3258
    cmp = egraph_term_body(egraph, tv);
3259
    assert(composite_body(cmp) && cmp != NULL && composite_kind(cmp) == COMPOSITE_TUPLE);
3260
  }
3261
#endif
3262

3263
  return tv;
245✔
3264
}
3265

3266

3267
/*
3268
 * Return a term t equal to boolean variable v
3269
 * - search for an egraph atom of the form <t, v>
3270
 * - if there is one return t
3271
 * - otherwise, create a fresh term t (variable + BOOL type)
3272
 *   and construct the atom <t, v>
3273
 * - if v already has a non-egraph atom attached,
3274
 *   then we create a fresh v', assert v' == v in the core then
3275
 *   attach t to v'
3276
 *
3277
 * BUG FIX: 2017/05/16: We also create a fresh v' and assert v' == v
3278
 * if the variable v is already assigned. This makes sure that the
3279
 * egraph will be notified that v' is true or false on the next call
3280
 * to propagate, and turn that into t==true or t==false.
3281
 *
3282
 *
3283
 * If a new term is created, it is activated.
3284
 */
3285
eterm_t egraph_bvar2term(egraph_t *egraph, bvar_t v) {
40✔
3286
  void *atom;
3287
  bvar_t aux;
3288
  eterm_t t;
3289
  smt_core_t *core;
3290

3291
  core = egraph->core;
40✔
3292
  assert(core != NULL);
3293

3294
  atom = bvar_atom(core, v);
40✔
3295
  if (atom != NULL && atom_tag(atom) == EGRAPH_ATM_TAG) {
40✔
3296
    return ((atom_t *) atom)->eterm;
7✔
3297
  }
3298

3299
  if (atom != NULL || bvar_is_assigned(core, v)) {
33✔
3300
    /*
3301
     * Either v is attached for an atom outisde the egraph
3302
     * or v is already assigned. In this case, we replace v by a fresh
3303
     * variable and assert aux == v in the core.
3304
     */
3305
    aux = v;
1✔
3306
    v = create_boolean_variable(core);
1✔
3307
    // assert aux <=> v
3308
    add_binary_clause(core, pos_lit(v), neg_lit(aux));
1✔
3309
    add_binary_clause(core, neg_lit(v), pos_lit(aux));
1✔
3310
  }
3311

3312
  // create fresh t + new atom  <t, v>
3313
  t = new_eterm(&egraph->terms, VARIABLE_BODY);
33✔
3314
  create_egraph_atom(egraph, v, t);
33✔
3315
  egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
33✔
3316
  egraph_activate_term(egraph, t, ETYPE_BOOL, v);
33✔
3317

3318
  return t;
33✔
3319
}
3320

3321

3322

3323

3324
/*
3325
 * Return a term t of type tau equal to theory variable v
3326
 * - t is a fresh egraph variable
3327
 * - v must not be attached to another term t'
3328
 * - there must be a theory solver for the type tau
3329
 */
3330
eterm_t egraph_thvar2term(egraph_t *egraph, thvar_t v, type_t tau) {
5,234✔
3331
  etype_t eta;
3332
  eterm_t t;
3333

3334
  eta = type_to_etype(egraph->types, tau);
5,234✔
3335
  assert(eta <= ETYPE_FUNCTION && egraph->eg[eta] != NULL);
3336

3337
  // fresh variable
3338
  t = new_eterm(&egraph->terms, VARIABLE_BODY);
5,234✔
3339

3340
  // set the term type and activate t
3341
  egraph_set_term_real_type(egraph, t, tau);
5,234✔
3342
  egraph_activate_term(egraph, t, eta, v);
5,234✔
3343

3344
  // attach t to v in the satellite solver
3345
  egraph->eg[eta]->attach_eterm(egraph->th[eta], v, t);
5,234✔
3346

3347
  return t;
5,234✔
3348
}
3349

3350

3351
/*
3352
 * Create the built-in boolean constant
3353
 */
3354
static void egraph_init_constant(egraph_t *egraph) {
4,798✔
3355
  eterm_t t0;
3356

3357
  t0 = new_eterm(&egraph->terms, mk_constant_body(0));
4,798✔
3358
  assert(t0 == true_eterm);
3359
  create_egraph_atom(egraph, const_bvar, t0);
4,798✔
3360
  egraph_set_term_real_type(egraph, t0, bool_type(egraph->types));
4,798✔
3361
  egraph_activate_term(egraph, t0, ETYPE_BOOL, const_bvar);
4,798✔
3362
}
4,798✔
3363

3364

3365

3366

3367
/**************************
3368
 *  AUXILIARY EQUALITIES  *
3369
 *************************/
3370

3371
/*
3372
 * Auxiliary equalities are created when adding ackermann lemmas.
3373
 * To prevent blow up, we put a limit on the number of auxiliary
3374
 * equalities created. When the limit is reached, creation of
3375
 * new auxiliary fails. Only lemmas that are built from existing
3376
 * equalities can be added at that point.
3377
 * - the quota is stored in egraph->aux_eq_quota
3378
 * - the number of auxiliary equalities created is in egraph->stats.aux_eqs
3379
 */
3380

3381
/*
3382
 * Variant build function for auxiliary equalities
3383
 */
3384
static eterm_t build_aux_eq_obj(eq_hobj_t *p) {
321✔
3385
  egraph_t *g;
3386

3387
  g = p->egraph;
321✔
3388
  if (g->stats.aux_eqs >= g->aux_eq_quota) {
321✔
3389
    return null_eterm;
91✔
3390
  }
3391
  g->stats.aux_eqs ++;
230✔
3392
  return new_eq(g, p->t1, p->t2);
230✔
3393
}
3394

3395
/*
3396
 * Constructor for auxiliary equality:
3397
 * - returns null_literal if the construction fails (i.e., when the quota is reached)
3398
 */
3399
static literal_t egraph_make_aux_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
1,433✔
3400
  occ_t aux;
3401
  eterm_t t;
3402
  eq_hobj_t aux_eq_hobj;
3403

3404
  if (t1 == t2) return true_literal;
1,433✔
3405

3406
  if (t1 > t2) {
713✔
3407
    // normalize
3408
    aux = t1; t1 = t2; t2 = aux;
606✔
3409
  }
3410

3411
  // call hash-consing constructor
3412
  aux_eq_hobj.m.hash = (hobj_hash_t) hash_eq_obj;
713✔
3413
  aux_eq_hobj.m.eq = (hobj_eq_t) equal_eq_obj;
713✔
3414
  aux_eq_hobj.m.build =(hobj_build_t) build_aux_eq_obj ;
713✔
3415
  aux_eq_hobj.egraph = egraph;
713✔
3416
  aux_eq_hobj.t1 = t1;
713✔
3417
  aux_eq_hobj.t2 = t2;
713✔
3418
  t = int_htbl_get_obj(&egraph->htbl, (int_hobj_t *) &aux_eq_hobj);
713✔
3419

3420
  if (t == null_eterm) {
713✔
3421
    return null_literal;  // quota exceeded
91✔
3422
  } else {
3423
    return egraph_term2literal(egraph, t);
622✔
3424
  }
3425
}
3426

3427

3428

3429

3430
/************************
3431
 *  LEMMA CONSTRUCTION  *
3432
 ***********************/
3433

3434
/*
3435
 * Distinct expansion: add the lemma
3436
 *  ((distinct t_1 ... t_n) or (eq t_1 t_2) .... or (eq t_n-1 t_n))
3437
 * where d = (distinct t_1 ... t_n)
3438
 */
3439
static void create_distinct_lemma(egraph_t *egraph, composite_t *d) {
9✔
3440
  bvar_t x;
3441
  eterm_t t;
3442
  ivector_t *v;
3443
  cache_elem_t *e;
3444

3445
  assert(composite_kind(d) == COMPOSITE_DISTINCT);
3446

3447
  // check the cache first
3448
  t = d->id;
9✔
3449
  e = cache_get(&egraph->cache, DISTINCT_LEMMA, t, null_eterm);
9✔
3450
  if (e->flag == NEW_CACHE_ELEM) {
9✔
3451
    // lemma not previously expanded
3452
    e->flag ++;
4✔
3453

3454
    // create the clause
3455
    v = &egraph->aux_buffer;
4✔
3456
    expand_distinct(egraph, composite_arity(d), d->child, v);
4✔
3457

3458
    x = egraph->terms.thvar[t];
4✔
3459
    ivector_push(v, pos_lit(x));
4✔
3460
    add_clause(egraph->core, v->size, v->data);
4✔
3461

3462
    // update statistics
3463
    egraph->stats.nd_lemmas ++;
4✔
3464
  }
3465
}
9✔
3466

3467

3468
/*
3469
 * Get cache element for ackermann lemma (t1, t2)
3470
 */
3471
static cache_elem_t *cache_get_ackermann_lemma(cache_t *cache, eterm_t t1, eterm_t t2) {
15,031✔
3472
  eterm_t aux;
3473

3474
  if (t1 > t2) {
15,031✔
3475
    aux = t1; t1 = t2; t2 = aux;
9,393✔
3476
  }
3477
  return cache_get(cache, ACKERMANN_LEMMA, t1, t2);
15,031✔
3478
}
3479

3480

3481
/*
3482
 * Ackermann lemma: add the lemma
3483
 *   (eq t_1 u_1) ... (eq t_n u_n) IMPLIES (eq (f t_1 ... t_n) (f u_1 ... u_n))
3484
 * - c1 = (f t_1 ... t_n)
3485
 * - c2 = (f u_1 ... u_n)
3486
 */
3487
static void create_ackermann_lemma(egraph_t *egraph, composite_t *c1, composite_t *c2) {
15,031✔
3488
  uint32_t i, n;
3489
  ivector_t *v;
3490
  cache_elem_t *e;
3491
  literal_t l;
3492
  eterm_t b1, b2;
3493
  thvar_t x1, x2;
3494

3495
  assert(composite_kind(c1) == composite_kind(c2) && composite_arity(c1) == composite_arity(c2));
3496

3497
  b1 = c1->id;
15,031✔
3498
  b2 = c2->id;
15,031✔
3499

3500
  if (egraph_term_type(egraph, b1) == ETYPE_BOOL) {
15,031✔
3501
    assert(egraph_term_type(egraph, b2) == ETYPE_BOOL);
3502

3503
    if (egraph_option_enabled(egraph, EGRAPH_DYNAMIC_BOOLACKERMANN) &&
227✔
3504
        egraph->stats.boolack_lemmas < egraph->max_boolackermann) {
227✔
3505

3506
      /*
3507
       * (f t_1 ... t_n) and (f u_1 ... u_n) are boolean.
3508
       * Find boolean variables
3509
       *   x1 <==> (f t_1 ... t_n) and x2 <==> (f u_1 ... u_n)
3510
       * Add two clause:
3511
       *  (eq t_1 u_1) AND ... AND (eq t_n u_n) AND x1 ==> x2
3512
       *  (eq t_1 u_1) AND ... AND (eq t_n u_n) AND x2 ==> x1
3513
       *
3514
       * Before generating the clauses, check the number of hits for
3515
       * the pair (b1, b2). Add the clauses if this reaches
3516
       * boolack_threshold.
3517
       */
3518
      e = cache_get_ackermann_lemma(&egraph->cache, b1, b2);
227✔
3519
      if (e->flag < egraph->boolack_threshold) {
227✔
3520
        e->flag ++;
227✔
3521
        if (e->flag == egraph->boolack_threshold) {
227✔
3522
          x1 = egraph_term_base_thvar(egraph, b1);
1✔
3523
          x2 = egraph_term_base_thvar(egraph, b2);
1✔
3524
          if (x1 != null_thvar && x2 != null_thvar) {
1✔
3525
            // generate the clause
3526
            v = &egraph->aux_buffer;
1✔
3527
            ivector_reset(v);
1✔
3528
            n = composite_arity(c1);
1✔
3529
            for (i=0; i<n; i++) {
3✔
3530
              l = egraph_make_aux_eq(egraph, c1->child[i], c2->child[i]);
2✔
3531
              if (l == null_literal) return; // quota exceeded: fail
2✔
3532
              if (l != true_literal) {
2✔
3533
                ivector_push(v, not(l));
1✔
3534
              }
3535
            }
3536
            i = v->size;
1✔
3537
            // add x1 ==> x2
3538
            ivector_push(v, neg_lit(x1));
1✔
3539
            ivector_push(v, pos_lit(x2));
1✔
3540
            add_clause(egraph->core, v->size, v->data);
1✔
3541
            // add x2 ==> x1
3542
            v->data[i] = neg_lit(x2);
1✔
3543
            v->data[i+1] = pos_lit(x1);
1✔
3544
            add_clause(egraph->core, v->size, v->data);
1✔
3545

3546
            egraph->stats.boolack_lemmas ++;
1✔
3547
          }
3548
        }
3549
      }
3550
    }
3551

3552
  } else {
3553

3554
    if (egraph_option_enabled(egraph, EGRAPH_DYNAMIC_ACKERMANN) &&
14,804✔
3555
        egraph->stats.ack_lemmas < egraph->max_ackermann) {
14,804✔
3556

3557
      /*
3558
       * Non-boolean case: add the clause
3559
       * (t_1 == u_1 and ... and t_n == u_n) ==>
3560
       *                (f t_1 .. t_n) == (f u_1 ... u_n)
3561
       *
3562
       * Generate the lemma if the number of hits for (b1, b2)
3563
       * reaches ackermann_threshold.
3564
       */
3565
      e = cache_get_ackermann_lemma(&egraph->cache, b1, b2);
14,804✔
3566
      if (e->flag < egraph->ackermann_threshold) {
14,804✔
3567
        e->flag ++;
14,443✔
3568
        if (e->flag == egraph->ackermann_threshold) {
14,443✔
3569
          v = &egraph->aux_buffer;
502✔
3570
          ivector_reset(v);
502✔
3571
          n = composite_arity(c1);
502✔
3572
          for (i=0; i<n; i++) {
1,842✔
3573
            l = egraph_make_aux_eq(egraph, c1->child[i], c2->child[i]);
1,431✔
3574
            if (l == null_literal) return; // aux_eq_quota exceeded
1,431✔
3575
            if (l != true_literal) {
1,340✔
3576
              ivector_push(v, not(l));
621✔
3577
            }
3578
          }
3579
          l = egraph_make_eq(egraph, pos_occ(b1), pos_occ(b2));
411✔
3580
          ivector_push(v, l);
411✔
3581

3582
#if 0
3583
          printf("---> ackermann lemma[%"PRIu32"]:\n", egraph->stats.ack_lemmas + 1);
3584
          n = v->size;
3585
          assert(n > 0);
3586
          if (n > 1) {
3587
            printf("(or ");
3588
          }
3589
          for (i=0; i<n; i++) {
3590
            printf(" ");
3591
            print_egraph_atom_of_literal(stdout, egraph, v->data[i]);
3592
          }
3593
          if (n > 1) {
3594
            printf(")");
3595
          }
3596
          printf("\n");
3597
          printf("      ");
3598
          print_eterm_def(stdout, egraph,  c1->id);
3599
          printf("      ");
3600
          print_eterm_def(stdout, egraph,  c2->id);
3601
          fflush(stdout);
3602
#endif
3603

3604
          add_clause(egraph->core, v->size, v->data);
411✔
3605

3606
          // update statistics
3607
          egraph->stats.ack_lemmas ++;
411✔
3608
        }
3609
      }
3610
    }
3611
  }
3612
}
3613

3614

3615

3616

3617
/*********************************************************
3618
 *  EQUALITY AND DISEQUALITIES BETWEEN THEORY VARIABLES  *
3619
 ********************************************************/
3620

3621
/*
3622
 * Propagate equality between two theory variables v1 and v2 in theory i
3623
 * - v1 = theory var of c1
3624
 * - v2 = theory var of c2
3625
 * - id = edge index that caused v1 and v2 to be merged (must be stored by the
3626
 *   theory solver to pass it to egraph_explain_equality).
3627
 * This is called when c1 and c2 are merged
3628
 * - c1 remains root (and v1 remains visible in the egraph)
3629
 * - c2 is no longer root after the merge (so v2 is no longer
3630
 *   visible in the egraph).
3631
 */
3632
static void propagate_satellite_equality(egraph_t *egraph, etype_t i, thvar_t v1, thvar_t v2, int32_t id) {
816,151✔
3633
  assert(i < NUM_SATELLITES && egraph->eg[i] != NULL);
3634

3635
  // call the merge function for theory i
3636
  egraph->eg[i]->assert_equality(egraph->th[i], v1, v2, id);
816,151✔
3637
}
816,151✔
3638

3639

3640
/*
3641
 * Propagate disequality between v1 and v2 in theory i
3642
 */
3643
static void propagate_satellite_disequality(egraph_t *egraph, etype_t i, thvar_t v1, thvar_t v2, composite_t *hint) {
1,460,151✔
3644
  assert(i < NUM_SATELLITES && egraph->eg[i] != NULL);
3645
  egraph->eg[i]->assert_disequality(egraph->th[i], v1, v2, hint);
1,460,151✔
3646
}
1,460,151✔
3647

3648

3649
/*
3650
 * Propagate (distinct a[0] ... a[n-1]) to satellite solver i
3651
 * - each a[k] is a theory variable in that solver
3652
 * - hint is a composite term that implies (distinct a[0] ... a[n-1]):
3653
 *   hint is (distinct t_0 ... t_p-1) asserted true,
3654
 *   and each a[i] is a theory variable attached to the class of some term t_j
3655
 */
3656
static void propagate_satellite_distinct(egraph_t *egraph, etype_t i, uint32_t n, thvar_t *a, composite_t *hint) {
8✔
3657
  assert(i < NUM_SATELLITES && egraph->eg[i] != NULL);
3658
  egraph->eg[i]->assert_distinct(egraph->th[i], n, a, hint);
8✔
3659
}
8✔
3660

3661

3662
/*
3663
 * EQUALITIES BETWEEN TUPLES AND BETWEEN BOOLEAN VARIABLES
3664
 */
3665

3666
/*
3667
 * Tuple-equality propagation: implement the rule
3668
 * (tuple t_1 ... t_n) == (tuple u_1 ... u_n) implies t_i == u_i
3669
 * - v1: term with body[v1] = (tuple t_1 ... t_n)
3670
 * - v2: term with body[v2] = (tuple u_1 ... u_n)
3671
 */
3672
static void propagate_tuple_equality(egraph_t *egraph, eterm_t v1, eterm_t v2) {
1,298✔
3673
  composite_t *p1, *p2;
3674
  uint32_t i, n;
3675
  occ_t x1, x2;
3676
  int32_t k;
3677

3678
  p1 = egraph_term_body(egraph, v1);
1,298✔
3679
  p2 = egraph_term_body(egraph, v2);
1,298✔
3680

3681
  // if input is type correct, then p1 and p2 must have same arity
3682
  // so p1->tag == p2->tag
3683
  assert(composite_body(p1) && composite_body(p2) && p1->tag == p2->tag
3684
         && composite_kind(p1) == COMPOSITE_TUPLE);
3685

3686
  assert(egraph_equal_occ(egraph, pos_occ(v1), pos_occ(v2)));
3687

3688
  n = composite_arity(p1);
1,298✔
3689
  x1 = pos_occ(v1);
1,298✔
3690
  x2 = pos_occ(v2);
1,298✔
3691
  for (i=0; i<n; i++) {
2,957✔
3692
    if (! egraph_equal_occ(egraph, p1->child[i], p2->child[i])) {
1,659✔
3693
      // (x1 == x2) implies p1->child[i] == p2->child[i]
3694
      k = egraph_stack_push_eq(&egraph->stack, p1->child[i], p2->child[i]);
691✔
3695
      egraph->stack.etag[k] = EXPL_EQ;
691✔
3696
      egraph->stack.edata[k].t[0] = x1;
691✔
3697
      egraph->stack.edata[k].t[1] = x2;
691✔
3698
    }
3699
  }
3700
}
1,298✔
3701

3702

3703
/*
3704
 * When boolean variable v1 and v2 are merged into the same boolean class
3705
 * - this means that either v1 == v2 or v1 == (not v2)
3706
 * - if v1 == const_bvar, then v2 is now true or false.
3707
 * - id = edge index that caused v1 and v2 to be merged
3708
 *
3709
 * Special case: if v1 is const_bvar then v2 may also be const_bvar
3710
 * - that's because we use const_bvar as theory variable for (distinct .. ) axioms
3711
 *   so different classes may be mapped to const_bvar.
3712
 */
3713
static void propagate_boolean_equality(egraph_t *egraph, bvar_t v1, bvar_t v2, int32_t id) {
3,526,797✔
3714
  atom_t *atm1, *atm2, *atm;
3715
  smt_core_t *core;
3716
  literal_t l;
3717

3718
  core = egraph->core;
3,526,797✔
3719
  assert(core != NULL && bvar_has_atom(core, v1) && bvar_has_atom(core, v2));
3720

3721
  atm1 = get_bvar_atom(core, v1);
3,526,797✔
3722
  atm2 = get_bvar_atom(core, v2);
3,526,797✔
3723

3724
  if (v1 == const_bvar) {
3,526,797✔
3725
    atm = atm2;
2,634,568✔
3726
    do {
3727
      /*
3728
       * atm->eterm is either true or false
3729
       * assign the same value to atm->boolvar
3730
       * we keep track of the edge id in the antecedent of atm->boolvar
3731
       * in the core.
3732
       */
3733
      assert(egraph_term_is_true(egraph, atm->eterm) ||
3734
             egraph_term_is_false(egraph, atm->eterm));
3735

3736
      if (bvar_is_unassigned(core, atm->boolvar)) {
3,998,211✔
3737
        l = mk_lit(atm->boolvar, egraph_term_is_false(egraph, atm->eterm));
1,598,528✔
3738
        propagate_literal(core, l, mk_i32_expl(id));
1,598,528✔
3739
        egraph->stats.th_props ++;
1,598,528✔
3740
      }
3741

3742
      atm = atm->next;
3,998,211✔
3743

3744
    } while (atm != atm2);
3,998,211✔
3745
  }
3746

3747
  merge_atom_lists(atm1, atm2);
3,526,797✔
3748
}
3,526,797✔
3749

3750

3751

3752
/*
3753
 * Propagate equality between two theory variables v1 and v2
3754
 * - v1 = theory var of c1
3755
 * - v2 = theory var of c2
3756
 * - id = edge index that caused c1 and c2 to be merged
3757
 *
3758
 * This is called when c1 and c2 are merged:
3759
 * - c1 remains root (and v1 remains visible in the egraph)
3760
 * - c2 is no longer root after the merge (so v2 is no longer
3761
 *   visible in the egraph).
3762
 */
3763
static void propagate_thvar_equality(egraph_t *egraph, class_t c1, thvar_t v1, class_t c2, thvar_t v2, int32_t id) {
4,344,246✔
3764
  etype_t i;
3765

3766
  assert(v1 != null_thvar && v2 != null_thvar &&
3767
         v1 == egraph_class_thvar(egraph, c1) &&
3768
         v2 == egraph_class_thvar(egraph, c2));
3769

3770
  i = egraph->classes.etype[c1];
4,344,246✔
3771
  switch (i) {
4,344,246✔
3772
  case ETYPE_INT:
816,151✔
3773
  case ETYPE_REAL:
3774
  case ETYPE_BV:
3775
  case ETYPE_FUNCTION:
3776
    propagate_satellite_equality(egraph, i, v1, v2, id);
816,151✔
3777
    break;
816,151✔
3778

3779
  case ETYPE_BOOL:
3,526,797✔
3780
    propagate_boolean_equality(egraph, v1, v2, id);
3,526,797✔
3781
    break;
3,526,797✔
3782

3783
  case ETYPE_TUPLE:
1,298✔
3784
    propagate_tuple_equality(egraph, v1, v2);
1,298✔
3785
    break;
1,298✔
3786

3787
  default:
4,344,246✔
3788
    assert(false);
3789
  }
3790
}
4,344,246✔
3791

3792

3793
/*
3794
 * Remove equality between two theory variables v1 and v2
3795
 * - this is used only for boolean variables
3796
 * - satellite solvers remove equalities or disequalities by backtracking
3797
 * - for tuple equalities, there's nothing to undo
3798
 */
3799
static void undo_thvar_equality(egraph_t *egraph, class_t c1, thvar_t v1, class_t c2, thvar_t v2) {
5,320,925✔
3800
  smt_core_t *core;
3801

3802
  assert(v1 != null_thvar && v2 != null_thvar &&
3803
         v1 == egraph_class_thvar(egraph, c1) &&
3804
         v2 == egraph_class_thvar(egraph, c2));
3805

3806
  if (egraph->classes.etype[c1] == ETYPE_BOOL) {
5,320,925✔
3807
    core = egraph->core;
3,503,563✔
3808
    assert(core != NULL && bvar_has_atom(core, v1) && bvar_has_atom(core, v2));
3809
    split_atom_lists(get_bvar_atom(core, v1), get_bvar_atom(core, v2));
3,503,563✔
3810
  }
3811
}
5,320,925✔
3812

3813

3814
/*
3815
 * Hack: to ensure that undo_thvar_equality works when a conflict is detected
3816
 * by check_atom_propagation, we merge the lists of atoms for Boolean variables v1 and v2.
3817
 */
3818
static void fixup_atom_lists(egraph_t *egraph, bvar_t v1, bvar_t v2) {
1✔
3819
  atom_t *atm1, *atm2;
3820
  smt_core_t *core;
3821

3822
  core = egraph->core;
1✔
3823

3824
  assert(core != NULL && bvar_has_atom(core, v1) && bvar_has_atom(core, v2));
3825

3826
  atm1 = get_bvar_atom(core, v1);
1✔
3827
  atm2 = get_bvar_atom(core, v2);
1✔
3828

3829
  merge_atom_lists(atm1, atm2);
1✔
3830
}
1✔
3831

3832

3833

3834
/*********************
3835
 *  ATOM ASSIGNMENT  *
3836
 ********************/
3837

3838
/*
3839
 * Check for propagations when atom t --> (eq t1 t2) becomes true or false
3840
 */
3841
static void check_eq_atom(egraph_t *egraph, occ_t t, composite_t *atom) {
3,849,009✔
3842
  occ_t t1, t2;
3843
  class_t c1, c2;
3844
  thvar_t v1, v2;
3845
  int32_t k;
3846
  etype_t i;
3847

3848
  t &= ~0x1; // make sure t = pos_occ(atom->id);
3,849,009✔
3849
  assert(t == pos_occ(atom->id) && atom->tag == mk_eq_tag());
3850

3851
  if (egraph_occ_is_true(egraph, t)) {
3,849,009✔
3852
    t1 = atom->child[0];
1,496,758✔
3853
    t2 = atom->child[1];
1,496,758✔
3854
    if (! egraph_equal_occ(egraph, t1, t2)) {
1,496,758✔
3855
      // (eq t1 t2) == true implies (t1 == t2)
3856
      k = egraph_stack_push_eq(&egraph->stack, t1, t2);
1,295,696✔
3857
      egraph->stack.etag[k] = EXPL_EQ;
1,295,696✔
3858
      egraph->stack.edata[k].t[0] = t;
1,295,696✔
3859
      egraph->stack.edata[k].t[1] = true_occ;
1,295,696✔
3860
#if TRACE
3861
      printf("---> EGRAPH: equality ");
3862
      print_occurrence(stdout, t1);
3863
      printf(" == ");
3864
      print_occurrence(stdout, t2);
3865
      printf(" implied by ");
3866
      print_composite(stdout, atom);
3867
      printf(" == true\n");
3868
#endif
3869
    }
3870

3871
  } else {
3872

3873
    assert(egraph_occ_is_false(egraph, t));
3874

3875
    t1 = atom->child[0];
2,352,251✔
3876
    t2 = atom->child[1];
2,352,251✔
3877
    i = egraph_type(egraph, t1);
2,352,251✔
3878

3879
    if (i < NUM_SATELLITES ) {
2,352,251✔
3880
      /*
3881
       * Propagate the disequality to a satellite solver, if needed.
3882
       */
3883
      c1 = egraph_class(egraph, t1);
1,460,151✔
3884
      v1 = egraph->classes.thvar[c1];
1,460,151✔
3885
      c2 = egraph_class(egraph, t2);
1,460,151✔
3886
      v2 = egraph->classes.thvar[c2];
1,460,151✔
3887
      if (v1 != null_thvar && v2 != null_thvar) {
1,460,151✔
3888
        propagate_satellite_disequality(egraph, i, v1, v2, atom);
1,460,151✔
3889
      }
3890

3891
    } else if (i == ETYPE_BOOL) {
892,100✔
3892
      assert(egraph_type(egraph, t2) == ETYPE_BOOL);
3893
      /*
3894
       * Propagation rule: (eq t1 t2) == false implies (t1 == not t2)
3895
       */
3896
      if (! egraph_opposite_occ(egraph, t1, t2)) {
48✔
3897
        k = egraph_stack_push_eq(&egraph->stack, t1, opposite_occ(t2));
27✔
3898
        egraph->stack.etag[k] = EXPL_EQ;
27✔
3899
        egraph->stack.edata[k].t[0] = t;
27✔
3900
        egraph->stack.edata[k].t[1] = false_occ;
27✔
3901
#if TRACE
3902
        printf("---> EGRAPH: equality ");
3903
        print_occurrence(stdout, t1);
3904
        printf(" == ");
3905
        print_occurrence(stdout, opposite_occ(t2));
3906
        printf(" implied by ");
3907
        print_composite(stdout, atom);
3908
        printf(" == false\n");
3909
#endif
3910
      }
3911
    }
3912
  }
3913
}
3,849,009✔
3914

3915

3916
/*
3917
 * Check whether the assertion (distinct t_1 ... t_n) can
3918
 * be propagated to a satellite theory.
3919
 * - atom = (distinct t_1 ... t_n)
3920
 * - tau = the type of t_1
3921
 */
3922
static void check_satellite_distinct(egraph_t *egraph, etype_t tau, composite_t *atom) {
8✔
3923
  ivector_t *v;
3924
  uint32_t i, n;
3925
  class_t c;
3926
  thvar_t x;
3927

3928
  assert(tau < NUM_SATELLITES && composite_kind(atom) == COMPOSITE_DISTINCT);
3929

3930
  v = &egraph->aux_buffer;
8✔
3931
  ivector_reset(v);
8✔
3932

3933
  // collect the theory variables in classes of t_1 ... t_n
3934
  n = composite_arity(atom);
8✔
3935
  for (i=0; i<n; i++) {
37✔
3936
    c = egraph_class(egraph, atom->child[i]);
29✔
3937
    x = egraph->classes.thvar[c];
29✔
3938
    if (x != null_thvar) {
29✔
3939
      ivector_push(v, x);
29✔
3940
    }
3941
  }
3942

3943
  if (v->size > 2) {
8✔
3944
    propagate_satellite_distinct(egraph, tau, v->size, v->data, atom);
8✔
3945
  } else if (v->size == 2) {
×
3946
    propagate_satellite_disequality(egraph, tau, v->data[0], v->data[1], atom);
×
3947
  }
3948

3949
}
8✔
3950

3951

3952
/*
3953
 * Assert (distinct t_1 ... t_n):
3954
 * - assumes that this does not cause a conflict in the egraph. All children
3955
 *   t_1 ... t_n must be in different classes.
3956
 */
3957
static void assert_distinct(egraph_t *egraph, composite_t *atom) {
27✔
3958
  uint32_t k, i, n, j, m;
3959
  uint32_t msk;
3960
  class_t c, c1, c2;
3961
  use_vector_t *v;
3962
  composite_t *p;
3963
  occ_t t1, t2;
3964
  uint32_t *dmask;
3965
  etype_t tau;
3966

3967
  assert(egraph->dtable.npreds < NDISTINCTS);
3968

3969
  // save data for backtracking
3970
  undo_stack_push_distinct(&egraph->undo);
27✔
3971

3972
  // assign an index to atom in dtable
3973
  k = egraph->dtable.npreds;
27✔
3974
  egraph->dtable.distinct[k] = atom;
27✔
3975
  egraph->dtable.npreds ++;
27✔
3976

3977
  dmask = egraph->classes.dmask;
27✔
3978

3979
  // update dmasks
3980
  msk = ((uint32_t) 1) << k;
27✔
3981
  n = composite_arity(atom);
27✔
3982
  for (i=0; i<n; i++) {
122✔
3983
    c = egraph_class(egraph, atom->child[i]);
95✔
3984
    assert((dmask[c] & msk) == 0);
3985
    dmask[c] |= msk;
95✔
3986
  }
3987

3988
#if TRACE
3989
  printf("---> EGRAPH: asserting ");
3990
  print_composite(stdout, atom);
3991
  printf("\n");
3992
#endif
3993

3994
  // scan equality terms to check whether this makes them false
3995
  for (i=0; i<n; i++) {
122✔
3996
    c = egraph_class(egraph, atom->child[i]);
95✔
3997
    v = egraph->classes.parents + c;
95✔
3998
    m = v->last;
95✔
3999
    for (j=0; j<m; j++) {
2,690✔
4000
      p = v->data[j];
2,595✔
4001
      if (valid_entry(p) && p->tag == mk_eq_tag()) {
2,595✔
4002
        // p in v implies that p is in the congruence table,
4003
        // so it was not false (or true) on entry to this function
4004
        t1 = p->child[0];
141✔
4005
        t2 = p->child[1];
141✔
4006
        c1 = egraph_class(egraph, t1);
141✔
4007
        c2 = egraph_class(egraph, t2);
141✔
4008
        assert(c1 == c || c2 == c);
4009

4010
        if ((dmask[c1] & dmask[c2]) != 0) {
141✔
4011
          assert((dmask[c1] & dmask[c2]) == msk);
4012
          // p = (eq t1 t2) is false
4013
          add_diseq_implies_eq(egraph, p, false_occ, t1, t2, msk);
51✔
4014
          congruence_table_remove(&egraph->ctable, p);
51✔
4015
          detach_composite(p, egraph->terms.label, egraph->classes.parents);
51✔
4016
          assert(empty_entry(v->data[j]));
4017
          // save p  to restore it on backtracking
4018
          undo_stack_push_composite(&egraph->undo, p);
51✔
4019
        }
4020

4021
      }
4022
    }
4023
  }
4024

4025
  /*
4026
   * Propagate to a satellite solver if needed
4027
   */
4028
  tau = egraph_type(egraph, atom->child[0]);
27✔
4029
  if (tau < NUM_SATELLITES) {
27✔
4030
    check_satellite_distinct(egraph, tau, atom);
8✔
4031
  }
4032

4033
}
27✔
4034

4035

4036
/*
4037
 * Process atom (distinct t_1 ... t_n) after it's asserted true or false.
4038
 * - return false if there's a conflict
4039
 */
4040
static bool check_distinct_atom(egraph_t *egraph, occ_t t, composite_t *atom) {
37✔
4041
  t &= ~0x1;
37✔
4042
  assert(t == pos_occ(atom->id) && composite_kind(atom) == COMPOSITE_DISTINCT);
4043

4044
  if (egraph_occ_is_true(egraph, t)) {
37✔
4045
    // It's redundant to check for a conflict if atom is
4046
    // in the congruence table, but we don't know for sure.
4047
    if (egraph_inconsistent_distinct(egraph, atom, &egraph->expl_vector)) {
28✔
4048
      return false;
1✔
4049
    } else {
4050
      assert_distinct(egraph, atom);
27✔
4051
    }
4052

4053
  } else {
4054

4055
    assert(egraph_occ_is_false(egraph, t));
4056

4057
    // important: egraph_inconsistent_not_distinct must be called
4058
    // after egraph_check_distinct_false.
4059
    if (egraph_check_distinct_false(egraph, atom)) {
9✔
4060
      return true;
×
4061
    }
4062

4063
    if (egraph_inconsistent_not_distinct(egraph, atom, &egraph->expl_vector)) {
9✔
4064
      return false;
×
4065
    }
4066

4067
    // expand (not (distinct ...))
4068
    create_distinct_lemma(egraph, atom);
9✔
4069
  }
4070

4071
  return true;
36✔
4072
}
4073

4074

4075
/*
4076
 * Function called when t is assigned to true or false
4077
 * Check whether t is an atom and if so assert the atom.
4078
 * - return false if a conflict is detected
4079
 */
4080
static bool check_atom_propagation(egraph_t *egraph, occ_t t) {
4,000,915✔
4081
  composite_t *atom;
4082

4083
  assert(egraph_class(egraph, t) == bool_constant_class);
4084

4085
  atom = egraph_term_body(egraph, term_of_occ(t));
4,000,915✔
4086
  if (composite_body(atom)) {
4,000,915✔
4087
    assert(atom != NULL);
4088
    switch (composite_kind(atom)) {
3,999,425✔
4089
    case COMPOSITE_EQ:
3,849,009✔
4090
      check_eq_atom(egraph, t, atom);
3,849,009✔
4091
      break;
3,849,009✔
4092

4093
    case COMPOSITE_DISTINCT:
37✔
4094
      return check_distinct_atom(egraph, t, atom);
37✔
4095

4096
    default:
150,379✔
4097
      // not an atom
4098
      break;
150,379✔
4099
    }
4100
  }
4101

4102
  return true;
4,000,878✔
4103
}
4104

4105

4106

4107

4108
/***********************
4109
 *  MERGE TWO CLASSES  *
4110
 **********************/
4111

4112
/*
4113
 * Invert the edges on the branch from x to its root
4114
 */
4115
static void invert_branch(egraph_t *egraph, occ_t x) {
11,890,301✔
4116
  eterm_t t;
4117
  int32_t i, j;
4118
  equeue_elem_t *eq;
4119
  int32_t *edge;
4120

4121
  eq = egraph->stack.eq;
11,890,301✔
4122
  edge = egraph->terms.edge;
11,890,301✔
4123

4124
  t = term_of_occ(x);
11,890,301✔
4125
  i = null_edge;
11,890,301✔
4126
  for (;;) {
4127
    j = edge[t];
14,723,567✔
4128
    edge[t] = i;
14,723,567✔
4129
    if (j < 0) break; // j == null_edge
14,723,567✔
4130
    t = edge_next(eq + j, t);
2,833,266✔
4131
    i = j;
2,833,266✔
4132
  }
4133
}
11,890,301✔
4134

4135
/*
4136
 * Scan use vector u. Store all equality terms into v
4137
 */
4138
static void collect_eqterms(use_vector_t *u, pvector_t *v) {
4,843✔
4139
  uint32_t i, n;
4140
  composite_t *p;
4141

4142
  pvector_reset(v);
4,843✔
4143
  n = u->last;
4,843✔
4144
  for (i=0; i<n; i++) {
102,658✔
4145
    p = u->data[i];
97,815✔
4146
    if (valid_entry(p) && p->tag == mk_eq_tag()) {
97,815✔
4147
      pvector_push(v, p);
73,312✔
4148
    }
4149
  }
4150
}
4,843✔
4151

4152
/*
4153
 * Check all composites in v: they are all equalities
4154
 * check whether they have become false (after change in dmask).
4155
 */
4156
static void check_false_eq(egraph_t *egraph, pvector_t *v) {
4,843✔
4157
  uint32_t i;
4158
  composite_t *p;
4159
  occ_t t1, t2;
4160
  class_t c1, c2;
4161
  uint32_t *dmask, msk;
4162

4163
  dmask = egraph->classes.dmask;
4,843✔
4164

4165
  for (i=0; i<v->size; i++) {
78,155✔
4166
    p = v->data[i];
73,312✔
4167
    assert(p->tag == mk_eq_tag());
4168
    t1 = p->child[0];
73,312✔
4169
    t2 = p->child[1];
73,312✔
4170
    c1 = egraph_class(egraph, t1);
73,312✔
4171
    c2 = egraph_class(egraph, t2);
73,312✔
4172
    msk = dmask[c1] & dmask[c2];
73,312✔
4173
    if (msk != 0) {
73,312✔
4174
      // t1 != t2 implies (eq t1 t2) == false
4175
      add_diseq_implies_eq(egraph, p, false_occ, t1, t2, msk);
68,118✔
4176
      congruence_table_remove(&egraph->ctable, p);
68,118✔
4177
      detach_composite(p, egraph->terms.label, egraph->classes.parents);
68,118✔
4178
      // save p so it can be restored on backtracking
4179
      undo_stack_push_composite(&egraph->undo, p);
68,118✔
4180
    }
4181
  }
4182
}
4,843✔
4183

4184
/*
4185
 * Check whether equality with index i is from a theory solver
4186
 */
4187
static bool eq_is_from_satellite(egraph_t *egraph, int32_t i) {
4,974,616✔
4188
  expl_tag_t tag;
4189

4190
  assert(0 <= i && i < egraph->stack.top);
4191
  tag = egraph->stack.etag[i];
4,974,616✔
4192
  return tag == EXPL_ARITH_PROPAGATION || tag == EXPL_BV_PROPAGATION;
4,974,616✔
4193
}
4194

4195
/*
4196
 * Process equality (t1 == t2): i = corresponding edge id
4197
 * - egraph->stack.eq[i] is (t1 == t2)
4198
 * - egraph->stack.etag[i] + egraph->stack.edata[i] == antecedent/explanation
4199
 *
4200
 * - returned value: true means no inconsistency detected
4201
 * - false means that a conflict was detected. The conflict literals are stored
4202
 *   in egraph->expl_vector.
4203
 */
4204
static bool process_equality(egraph_t *egraph, occ_t t1, occ_t t2, int32_t i) {
6,712,530✔
4205
  class_t c1, c2;
4206
  int32_t aux;
4207
  use_vector_t *v;
4208
  uint32_t j, n, dmask;
4209
  composite_t *p;
4210
  elabel_t l;
4211
  occ_t t;
4212
  thvar_t v1, v2;
4213

4214
#if TRACE
4215
  printf("\n---> EGRAPH: processing equality ");
4216
  print_occurrence(stdout, t1);
4217
  printf(" == ");
4218
  print_occurrence(stdout, t2);
4219
  printf("\n");
4220
  if (egraph_term_is_composite(egraph, term_of_occ(t1))) {
4221
    printf("---> ");
4222
    print_eterm_def(stdout, egraph, term_of_occ(t1));
4223
  }
4224
  if (egraph_term_is_composite(egraph, term_of_occ(t2))) {
4225
    printf("---> ");
4226
    print_eterm_def(stdout, egraph, term_of_occ(t2));
4227
  }
4228
#endif
4229

4230
  // check whether (t1 == t2) is redundant
4231
  if (egraph_equal_occ(egraph, t1, t2)) {
6,712,530✔
4232
#if TRACE
4233
    printf("---> redundant\n");
4234
    fflush(stdout);
4235
#endif
4236
    return true;
1,718,694✔
4237
  }
4238

4239
  // check whether it's inconsistent and if so construct the explanation
4240
  if (egraph_inconsistent_edge(egraph, t1, t2, i, &egraph->expl_vector)) {
4,993,836✔
4241
#if TRACE
4242
    printf("---> conflict\n");
4243
    fflush(stdout);
4244
#endif
4245

4246
    if (egraph->stack.etag[i] == EXPL_BASIC_CONGRUENCE) {
19,219✔
4247
      // store t1 t2 for local Ackermann generation
4248
      egraph->ack_left = t1;
15,501✔
4249
      egraph->ack_right = t2;
15,501✔
4250
    }
4251

4252
    return false;
19,219✔
4253
  }
4254

4255
#if TRACE
4256
  printf("---> merging ");
4257
  print_label(stdout, egraph_label(egraph, t1));
4258
  printf(" and ");
4259
  print_label(stdout, egraph_label(egraph, t2));
4260
  printf("\n");
4261
  fflush(stdout);
4262
#endif
4263

4264
  /*
4265
   * Merge class of t2 into class of t1
4266
   */
4267
  c1 = egraph_class(egraph, t1);
4,974,617✔
4268
  c2 = egraph_class(egraph, t2);
4,974,617✔
4269

4270
  assert(c1 != c2 && (egraph->classes.dmask[c1] & egraph->classes.dmask[c2]) == 0);
4271

4272
  // swap if necessary: we want c1 := union(c1, c2)
4273
  // and we want to keep bool_constant_class as the root class
4274
  if (c2 == bool_constant_class ||
4,974,617✔
4275
      (c1 != bool_constant_class && egraph_class_nparents(egraph, c2) > egraph_class_nparents(egraph, c1))) {
2,337,346✔
4276
    aux = t1; t1 = t2; t2 = aux;
3,129,563✔
4277
    aux = c1; c1 = c2; c2 = aux;
3,129,563✔
4278
  }
4279

4280
  // save t2 and its current label for backtracking
4281
  undo_stack_push_merge(&egraph->undo, t2, egraph_label(egraph, t2));
4,974,617✔
4282

4283
  // update explanation tree: make t2 root of its tree
4284
  invert_branch(egraph, t2);
4,974,617✔
4285
  assert(egraph->terms.edge[term_of_occ(t2)] == null_edge);
4286
  egraph->terms.edge[term_of_occ(t2)] = i; // new edge: t2 ---> t1
4,974,617✔
4287

4288
  /*
4289
   * remove c2's parents from the congruence table
4290
   * since their signature will change.
4291
   */
4292
  v = egraph->classes.parents + c2;
4,974,617✔
4293
  n = v->last;
4,974,617✔
4294
  for (j=0; j<n; j++) {
16,893,057✔
4295
    p = v->data[j];
11,918,440✔
4296
    if (valid_entry(p)) {
11,918,440✔
4297
      // p is valid, i.e., it's in the congruence table
4298
      congruence_table_remove(&egraph->ctable, p);
6,626,250✔
4299
      // remove p from the parent vectors, except v
4300
      separate_composite(p, egraph->terms.label, egraph->classes.parents, c2);
6,626,250✔
4301
      assert(v->data[j] == p);
4302
    }
4303
  }
4304

4305
  /*
4306
   * Assign new label to all terms in t2's class:
4307
   * new label == current label of t1
4308
   */
4309
  l = egraph_label(egraph, t1);
4,974,617✔
4310
  t = t2;
4,974,617✔
4311
  do {
4312
    egraph_set_label(egraph, t, l);
9,753,886✔
4313
    t = egraph_next(egraph, t);
9,753,886✔
4314
    assert(term_of_occ(t) != term_of_occ(t2) || t == t2);
4315
  } while (t != t2);
9,753,886✔
4316

4317
  // update dmask of c1
4318
  dmask = egraph->classes.dmask[c1];
4,974,617✔
4319
  egraph->classes.dmask[c1] |= egraph->classes.dmask[c2];
4,974,617✔
4320

4321
  //  merge lists of terms: swap next[t1] and next[t2]
4322
  t = egraph_next(egraph, t2);
4,974,617✔
4323
  egraph_set_next(egraph, t2, egraph_next(egraph, t1));
4,974,617✔
4324
  egraph_set_next(egraph, t1, t);
4,974,617✔
4325

4326
  /*
4327
   * For propagation: if dmask[c1] has changed, some equality
4328
   * terms in parents[c1] may have become false. Collect them
4329
   * into egraph->cmp_vector.
4330
   */
4331
  if (egraph->classes.dmask[c1] != dmask) {
4,974,617✔
4332
    collect_eqterms(egraph->classes.parents + c1, &egraph->cmp_vector);
4,843✔
4333
  }
4334

4335
  /*
4336
   * Reprocess all composites in v == all parents of c2
4337
   *
4338
   * For backtracking, we keep all these composites in v
4339
   * - if p remains a congruence root, it's kept as is in v
4340
   * - if p is no longer a congruence root, it's kept as a marked
4341
   *   pointer in v.
4342
   */
4343
  for (j=0; j<n; j++) {
16,893,057✔
4344
    p = v->data[j];
11,918,440✔
4345
    if (valid_entry(p)) {
11,918,440✔
4346
      if (composite_simplifies(egraph, p)) {
6,626,250✔
4347
        // p is no longer in the congruence table
4348
        // put a mark for backtracking
4349
        mark_use_vector_entry(v, j);
4,274,205✔
4350
      } else {
4351
        // put p back into the use vectors
4352
        // this adds p into c1's parent vector
4353
        attach_composite(p, egraph->terms.label, egraph->classes.parents);
2,352,045✔
4354
      }
4355
    }
4356
  }
4357

4358

4359
  /*
4360
   * Propagation 1: visit all equality terms in cmp_vector:
4361
   * check whether they have become false.
4362
   */
4363
  if (egraph->classes.dmask[c1] != dmask) {
4,974,617✔
4364
    check_false_eq(egraph, &egraph->cmp_vector);
4,843✔
4365
  }
4366

4367
  /*
4368
   * Propagation 2: if c1 == bool_constant_class, some atoms may
4369
   * have become true or false.
4370
   */
4371
  if (c1 == bool_constant_class) {
4,974,617✔
4372
    // atoms to visit = terms that were in t2's class.
4373
    // now they are in the list t1->next ... --> t2
4374
    t = t1;
2,637,271✔
4375
    do {
4376
      t = egraph_next(egraph, t);
4,000,915✔
4377
      if (! check_atom_propagation(egraph, t)) {
4,000,915✔
4378
        // conflict
4379

4380
        /*
4381
         * HACK/BUG FIX: this fixes a bug reported by Dorus Peelen.
4382
         *
4383
         * Before returning false, we must merge the atoms of v1 and v2
4384
         * otherwise the backtracking will fail; it will call undo_thvar_equality,
4385
         * and that function requires the lists of atoms of v1 and v2 to be merged.
4386
         */
4387
        v1 = egraph->classes.thvar[c1];
1✔
4388
        v2 = egraph->classes.thvar[c2];
1✔
4389
        assert(v1 != null_thvar && v2 != null_thvar);
4390
        fixup_atom_lists(egraph, v1, v2);
1✔
4391
        return false;
1✔
4392
      }
4393
    } while (t != t2);
4,000,914✔
4394
  }
4395

4396
  /*
4397
   * Deal with theory variables of c1 and c2:
4398
   * - if c2 has a theory var v2 but not c1, set v2 as theory var of c1
4399
   * - if both have a theory variable, propagate equality (v1 == v2) to theory solvers
4400
   * - check the explanation for i before propagating to the theory solver
4401
   *   if the equality i was propagated from Simplex or BV solver, there's no point
4402
   *   sending v1 == v2 to this solver (and doing so pauses a circularity problem).
4403
   *
4404
   * NOTE: this is also how we propagate tuple/boolean equalities
4405
   *
4406
   * TODO:
4407
   * - extend this to deal with equalities between lambda terms
4408
   *     (lambda t x) == (lambda t y) ==> (x == y) since t does not occur in x or y
4409
   *   this requires removing the satellite solver for array/function theory
4410
   *   and move support for these theories here (cf. update_graph)
4411
   */
4412
  if (!eq_is_from_satellite(egraph, i)) {
4,974,616✔
4413
    v2 = egraph->classes.thvar[c2];
4,958,261✔
4414
    if (v2 != null_thvar) {
4,958,261✔
4415
      v1 = egraph->classes.thvar[c1];
4,344,359✔
4416
      if (v1 != null_thvar) {
4,344,359✔
4417
        propagate_thvar_equality(egraph, c1, v1, c2, v2, i);
4,344,246✔
4418
      } else {
4419
        egraph->classes.thvar[c1] = v2;
113✔
4420
      }
4421
    }
4422
  }
4423

4424
#if TRACE_FCHECK
4425
  printf("\nDONE PROCESSING EQUALITY\n\n");
4426
  print_egraph_terms(stdout, egraph);
4427
  printf("\n");
4428
  print_egraph_root_classes_details(stdout, egraph);
4429
  fflush(stdout);
4430
#endif
4431

4432
  return true;
4,974,616✔
4433
}
4434

4435

4436

4437

4438
/***************************
4439
 *  INTERNALIZATION START  *
4440
 **************************/
4441

4442
/*
4443
 * Set the presearch flag. Propagate the call to the satellite solvers
4444
 */
4445
void egraph_start_internalization(egraph_t *egraph) {
31,595✔
4446
  uint32_t i;
4447

4448
  egraph->presearch = true;
31,595✔
4449

4450
  for (i=0; i<NUM_SATELLITES; i++) {
221,165✔
4451
    if (egraph->ctrl[i] != NULL) {
189,570✔
4452
      egraph->ctrl[i]->start_internalization(egraph->th[i]);
87,334✔
4453
    }
4454
  }
4455
}
31,595✔
4456

4457

4458

4459
/******************
4460
 *  START SEARCH  *
4461
 *****************/
4462

4463
void egraph_start_search(egraph_t *egraph) {
13,462✔
4464
  uint32_t i;
4465

4466
#if TRACE
4467
  fprintf(stdout, "---> EGRAPH START_SEARCH [dlevel = %"PRIu32", decisions = %"PRIu64"]\n",
4468
          egraph->decision_level, egraph->core->stats.decisions);
4469
  fprintf(stdout, "\n=== EGRAPH TERMS ===\n");
4470
  print_egraph_terms(stdout, egraph);
4471
  fprintf(stdout, "\n");
4472
#endif
4473

4474
  assert(egraph->core != NULL && egraph->decision_level == egraph->base_level);
4475

4476
  egraph->stats.eq_props = 0;
13,462✔
4477
  egraph->stats.th_props = 0;
13,462✔
4478
  egraph->stats.th_conflicts = 0;
13,462✔
4479

4480
  egraph->stats.final_checks = 0;
13,462✔
4481
  egraph->stats.interface_eqs = 0;
13,462✔
4482

4483
  for (i=0; i<NUM_SATELLITES; i++) {
94,234✔
4484
    if (egraph->ctrl[i] != NULL) {
80,772✔
4485
      egraph->ctrl[i]->start_search(egraph->th[i]);
38,716✔
4486
    }
4487
  }
4488

4489
#if TRACE
4490
  printf("\n=== EGRAPH TERMS ===\n");
4491
  print_egraph_terms(stdout, egraph);
4492
  printf("\n");
4493
#endif
4494

4495
  egraph->presearch = false;
13,462✔
4496
}
13,462✔
4497

4498

4499

4500
/*****************************
4501
 *  INCREASE DECISION LEVEL  *
4502
 ****************************/
4503

4504
static void egraph_open_decision_level(egraph_t *egraph) {
6,467,796✔
4505
  uint32_t k;
4506

4507
  k = egraph->decision_level + 1;
6,467,796✔
4508
  egraph->decision_level = k;
6,467,796✔
4509
  if (egraph->stack.nlevels <= k) {
6,467,796✔
4510
    increase_egraph_stack_levels(&egraph->stack);
272✔
4511
  }
4512
  egraph->stack.level_index[k] = egraph->stack.top;
6,467,796✔
4513

4514
  if (egraph->undo.nlevels <= k) {
6,467,796✔
4515
    increase_undo_stack_levels(&egraph->undo);
272✔
4516
  }
4517
  egraph->undo.level_index[k] = egraph->undo.top;
6,467,796✔
4518

4519
  // open new scope in arena
4520
  arena_push(&egraph->arena);
6,467,796✔
4521

4522
#if TRACE
4523
  printf("\n---> Egraph: increase decision level to %"PRIu32"\n", egraph->decision_level);
4524
#endif
4525
}
6,467,796✔
4526

4527

4528
/*
4529
 * Increase the decision level
4530
 * - the propagation queue should be empty
4531
 */
4532
void egraph_increase_decision_level(egraph_t *egraph) {
6,463,268✔
4533
  uint32_t i;
4534

4535
  assert(egraph->stack.prop_ptr == egraph->stack.top);
4536

4537
  egraph_open_decision_level(egraph);
6,463,268✔
4538

4539
  // forward to satellite solvers
4540
  for (i=0; i<NUM_SATELLITES; i++) {
45,242,876✔
4541
    if (egraph->ctrl[i] != NULL) {
38,779,608✔
4542
      egraph->ctrl[i]->increase_decision_level(egraph->th[i]);
12,848,517✔
4543
    }
4544
  }
4545
}
6,463,268✔
4546

4547

4548
/**********
4549
 *  PUSH  *
4550
 *********/
4551

4552
void egraph_push(egraph_t *egraph) {
4,528✔
4553
  uint32_t i;
4554

4555
  assert(egraph->decision_level == egraph->base_level);
4556
  assert(egraph->terms.nterms == egraph->classes.nclasses);
4557
  assert(egraph->reanalyze_vector.size == 0);
4558

4559
  // save number of terms == number of classes, and propagation pointer
4560
  egraph_trail_save(&egraph->trail_stack, egraph->terms.nterms, egraph->stack.prop_ptr);
4,528✔
4561

4562
  // mark cache content
4563
  cache_push(&egraph->cache);
4,528✔
4564

4565
  // forward to the satellite solvers
4566
  for (i=0; i<NUM_SATELLITES; i++) {
31,696✔
4567
    if (egraph->ctrl[i] != NULL) {
27,168✔
4568
      egraph->ctrl[i]->push(egraph->th[i]);
12,844✔
4569
    }
4570
  }
4571

4572
  // increase base level and decision level
4573
  egraph->base_level ++;
4,528✔
4574
  egraph_open_decision_level(egraph);
4,528✔
4575

4576
#if 0
4577
  printf("\n*** EGRAPH PUSH EXIT ****\n");
4578
  print_egraph_root_classes_details(stdout, egraph);
4579
  print_egraph_congruence_roots(stdout, egraph);
4580
#endif
4581

4582
}
4,528✔
4583

4584

4585

4586
/***********
4587
 *  RESET  *
4588
 **********/
4589

4590
/*
4591
 * - remove all terms, classes, and atoms
4592
 * - reset all stacks and tables
4593
 * - set base_level and decision_level to 0
4594
 */
4595
void egraph_reset(egraph_t *egraph) {
6✔
4596
  uint32_t i;
4597

4598
  egraph->base_level = 0;
6✔
4599
  egraph->decision_level = 0;
6✔
4600
  egraph->presearch = false;
6✔
4601
  egraph->ndistincts = 0;
6✔
4602
  egraph->natoms = 0;
6✔
4603
  egraph->is_high_order = false;
6✔
4604

4605
  reset_egraph_stats(&egraph->stats);
6✔
4606
  egraph->ack_left = null_occurrence;
6✔
4607
  egraph->ack_right = null_occurrence;
6✔
4608

4609
  reset_class_table(&egraph->classes);
6✔
4610
  reset_eterm_table(&egraph->terms);
6✔
4611
  reset_egraph_stack(&egraph->stack);
6✔
4612
  reset_undo_stack(&egraph->undo);
6✔
4613
  reset_distinct_table(&egraph->dtable);
6✔
4614
  reset_congruence_table(&egraph->ctable);
6✔
4615
  reset_ltag_table(&egraph->tag_table);
6✔
4616
  reset_egraph_trail(&egraph->trail_stack);
6✔
4617

4618
  egraph_free_const_htbl(egraph);
6✔
4619
  reset_int_htbl(&egraph->htbl);
6✔
4620
  reset_objstore(&egraph->atom_store);  // delete all atoms
6✔
4621
  reset_cache(&egraph->cache);
6✔
4622
  arena_reset(&egraph->arena);
6✔
4623
  reset_istack(&egraph->istack);
6✔
4624

4625
  ivector_reset(&egraph->interface_eqs);
6✔
4626
  egraph->reconcile_top = 0;
6✔
4627
  egraph->reconcile_neqs = 0;
6✔
4628
  egraph->reconcile_mode = false;
6✔
4629

4630
  if (egraph->app_partition != NULL) {
6✔
4631
    delete_ptr_partition(egraph->app_partition);
×
4632
    safe_free(egraph->app_partition);
×
4633
    egraph->app_partition = NULL;
×
4634
  }
4635

4636
  egraph_init_constant(egraph);
6✔
4637

4638
  // model-building objects
4639
  reset_egraph_model(&egraph->mdl);
6✔
4640

4641
  // forward reset to the satellite solvers
4642
  for (i=0; i<NUM_SATELLITES; i++) {
42✔
4643
    if (egraph->ctrl[i] != NULL) {
36✔
4644
      egraph->ctrl[i]->reset(egraph->th[i]);
17✔
4645
    }
4646
  }
4647
}
6✔
4648

4649

4650

4651

4652

4653
/*******************
4654
 *  BACKTRACKING   *
4655
 ******************/
4656

4657
/*
4658
 * Undo operation: remove the last (distinct ...)
4659
 */
4660
static void undo_distinct(egraph_t *egraph) {
15✔
4661
  uint32_t k, msk, i, n;
4662
  uint32_t *dmask;
4663
  composite_t *d;
4664
  class_t c;
4665

4666
  assert(egraph->dtable.npreds > 1);
4667

4668
  k = egraph->dtable.npreds - 1;
15✔
4669
  d = egraph->dtable.distinct[k];
15✔
4670
  egraph->dtable.npreds = k;
15✔
4671

4672
  // clear bit k in dmasks
4673
  dmask = egraph->classes.dmask;
15✔
4674
  msk = ~(((uint32_t) 1) << k);
15✔
4675

4676
  assert(d != NULL && composite_kind(d) == COMPOSITE_DISTINCT);
4677
  n = composite_arity(d);
15✔
4678
  for (i=0; i<n; i++) {
61✔
4679
    c = egraph_class(egraph, d->child[i]);
46✔
4680
    assert((dmask[c] & ~msk) == ~msk);
4681
    dmask[c] &= msk;
46✔
4682
  }
4683
}
15✔
4684

4685

4686
/*
4687
 * Put composite cmp back into its parents vector
4688
 * and into the congruence table.
4689
 */
4690
static void restore_composite(egraph_t *egraph, composite_t *cmp) {
66,346✔
4691
#ifndef NDEBUG
4692
  // cmp->hash should be valid
4693
  signature_composite(cmp, egraph->terms.label, &egraph->sgn);
4694
  assert(cmp->hash == hash_signature(&egraph->sgn));
4695
#endif
4696
  congruence_table_add(&egraph->ctable, cmp);
66,346✔
4697
  attach_composite(cmp, egraph->terms.label, egraph->classes.parents);
66,346✔
4698
}
66,346✔
4699

4700

4701
/*
4702
 * Undo merge: t2 = saved occurrence, l2 = saved label
4703
 * - let i = edge[t2] then egraph->stack.eq[i] is either <t1, t2> or <t2, t1>
4704
 * - undo merge is the converse of process_equality(t1, t2, i):
4705
 */
4706
static void undo_merge(egraph_t *egraph, occ_t t2, elabel_t l2) {
5,920,579✔
4707
  class_t c1, c2;
4708
  occ_t t1, t;
4709
  int32_t i, n;
4710
  use_vector_t *v;
4711
  composite_t *p;
4712
  elabel_t *label;
4713

4714
  c1 = egraph_class(egraph, t2);
5,920,579✔
4715
  c2 = class_of(l2);
5,920,579✔
4716

4717
  i = egraph->terms.edge[term_of_occ(t2)];
5,920,579✔
4718
  assert(0 <= i && i < egraph->stack.top);
4719

4720
  t1 = edge_next_occ(egraph->stack.eq + i, t2);
5,920,579✔
4721
  assert(egraph_class(egraph, t1) == c1);
4722

4723
  /*
4724
   * parents[c2] stores composites that need to be reinserted
4725
   * in ctable after relabeling.
4726
   * - marked elements in parents[c2] --> not currently in ctable
4727
   * - valid elements in parents[c2] --> still in ctable
4728
   * First loop: remove all composites in parents[c2] from ctable,
4729
   * remove mark from the marked elements.
4730
   */
4731
  label = egraph->terms.label;
5,920,579✔
4732
  v = egraph->classes.parents + c2;
5,920,579✔
4733
  n = v->last;
5,920,579✔
4734
  for (i=0; i<n; i++) {
20,408,208✔
4735
    p = v->data[i];
14,487,629✔
4736
    if (valid_entry(p)) {
14,487,629✔
4737
      congruence_table_remove(&egraph->ctable, p);
4,016,347✔
4738
      detach_composite(p, label, egraph->classes.parents);
4,016,347✔
4739
    } else if (marked_entry(p)) {
10,471,282✔
4740
      unmark_use_vector_entry(v, i);
5,084,248✔
4741
    }
4742
  }
4743

4744
  /*
4745
   * class c1 is a circular list of the form
4746
   * t1 --> x .... --> t2 --> y ... --> t1
4747
   * we split it in into two circular sublists:
4748
   * t2 --> x ... --> t2  and t1 --> y ... -> t1
4749
   */
4750
  t = egraph_next(egraph, t2);
5,920,579✔
4751
  egraph_set_next(egraph, t2, egraph_next(egraph, t1));
5,920,579✔
4752
  egraph_set_next(egraph, t1, t);
5,920,579✔
4753

4754
  // restore label l2 to t2 and all terms in its list
4755
  t = t2;
5,920,579✔
4756
  do {
4757
    egraph_set_label(egraph, t, l2);
11,240,864✔
4758
    t = egraph_next(egraph, t);
11,240,864✔
4759
    assert(term_of_occ(t) != term_of_occ(t2) || t == t2);
4760
  } while (t != t2);
11,240,864✔
4761

4762
  // restore dmask of c1
4763
  egraph->classes.dmask[c1] &= ~egraph->classes.dmask[c2];
5,920,579✔
4764

4765
  // remove edge from t2 --> t1 then restore branch t2 ---> c2.root
4766
  egraph->terms.edge[term_of_occ(t2)] = null_edge;
5,920,579✔
4767
  invert_branch(egraph, egraph->classes.root[c2]);
5,920,579✔
4768

4769
  /*
4770
   * Put parents[c2] back into ctable
4771
   */
4772
  for (i=0; i<n; i++) {
20,408,208✔
4773
    p = v->data[i];
14,487,629✔
4774
    assert(valid_entry(p) || empty_entry(p));
4775
    if (valid_entry(p)) {
14,487,629✔
4776
      signature_composite(p, label, &egraph->sgn);
9,100,595✔
4777
      p->hash = hash_signature(&egraph->sgn);
9,100,595✔
4778
      // p should be a congruence root
4779
      assert(congruence_table_find(&egraph->ctable, &egraph->sgn, label) == NULL_COMPOSITE);
4780

4781
      congruence_table_add(&egraph->ctable, p);
9,100,595✔
4782
      clear_use_vector_entry(v, i); // required for attach_composite
9,100,595✔
4783
      attach_composite(p, label, egraph->classes.parents);
9,100,595✔
4784
    }
4785
  }
4786

4787
  /*
4788
   * Restore theory variables:
4789
   * if thvar[c1] == thvar[c2] != null, then we restore thvar[c1] to null
4790
   * if thvar[c1] != thvar[c2] and thvar[c2] != null, undo_thvar_equality
4791
   * does any extra processing needed.
4792
   *
4793
   * Exception: if c1 == bool_constant_class, it may happen that
4794
   * thvar[c1] == thvar[2] == const_bvar: but we don't want to
4795
   * set thvar[c1] to null_thvar.
4796
   */
4797
  if (egraph->classes.thvar[c2] != null_thvar) {
5,920,579✔
4798
    assert(egraph->classes.thvar[c1] != null_thvar);
4799
    if (egraph->classes.thvar[c1] == egraph->classes.thvar[c2])  {
5,321,037✔
4800
      if (c1 != bool_constant_class) {
112✔
4801
        egraph->classes.thvar[c1] = null_thvar;
112✔
4802
      }
4803
    } else {
4804
      undo_thvar_equality(egraph, c1, egraph->classes.thvar[c1], c2, egraph->classes.thvar[c2]);
5,320,925✔
4805
    }
4806
  }
4807

4808
}
5,920,579✔
4809

4810

4811
/*
4812
 * Remove a congruence root from the congruence table and use vectors.
4813
 * - at the time this function is called, p should be in a singleton
4814
 *   class c (the class created when p was activated).
4815
 */
4816
static void deactivate_congruence_root(egraph_t *egraph, composite_t *p) {
40,315✔
4817
#ifndef NDEBUG
4818
  class_t c;
4819
  eterm_t t;
4820
#endif
4821
  elabel_t *label;
4822

4823
  label = egraph->terms.label;
40,315✔
4824

4825
#ifndef NDEBUG
4826
  t = p->id;
4827
  c = egraph_term_class(egraph, t);
4828

4829
  // check that p->hash is valid
4830
  signature_composite(p, label, &egraph->sgn);
4831
  assert(p->hash == hash_signature(&egraph->sgn));
4832

4833
  // check that p is in ctable
4834
  assert(congruence_table_find(&egraph->ctable, &egraph->sgn, label) == p);
4835

4836
  // t should be root of c and c should contain t only
4837
  assert(egraph->classes.root[c] == pos_occ(t));
4838
  assert(egraph->terms.next[t] == pos_occ(t));
4839
#endif
4840

4841
  congruence_table_remove(&egraph->ctable, p);
40,315✔
4842
  detach_composite(p, label, egraph->classes.parents);
40,315✔
4843
}
40,315✔
4844

4845

4846
/*
4847
 * Generate the ackermann lemma for term occurrences t1 and t2
4848
 */
4849
static void egraph_gen_ackermann_lemma(egraph_t *egraph, occ_t t1, occ_t t2) {
15,031✔
4850
  composite_t *c1, *c2;
4851

4852
  c1 = egraph_term_body(egraph, term_of_occ(t1));
15,031✔
4853
  c2 = egraph_term_body(egraph, term_of_occ(t2));
15,031✔
4854
  create_ackermann_lemma(egraph, c1, c2);
15,031✔
4855
}
15,031✔
4856

4857

4858
/*
4859
 * Backtrack to back_level
4860
 * (we need to isolate this because it's used in pop);
4861
 */
4862
static void egraph_local_backtrack(egraph_t *egraph, uint32_t back_level) {
94,069✔
4863
  uint32_t i, k;
4864
  unsigned char *utag;
4865
  undo_t *udata;
4866
  uint32_t n;
4867

4868
  assert(egraph->base_level <= back_level && back_level < egraph->decision_level);
4869

4870
#if TRACE
4871
  printf("---> EGRAPH:   Backtracking to level %"PRIu32"\n\n", back_level);
4872
#endif
4873

4874

4875
  /*
4876
   * Generate ackermann lemmas if enabled: this must be done first
4877
   */
4878
  if (egraph->ack_left != null_occurrence &&
120,880✔
4879
      egraph_option_enabled(egraph, EGRAPH_DYNAMIC_ACKERMANN | EGRAPH_DYNAMIC_BOOLACKERMANN)) {
26,811✔
4880
    assert(egraph->ack_right != null_occurrence);
4881
    egraph_gen_ackermann_lemma(egraph, egraph->ack_left, egraph->ack_right);
15,031✔
4882
    egraph->ack_left = null_occurrence;
15,031✔
4883
    egraph->ack_right = null_occurrence;
15,031✔
4884
  }
4885

4886

4887
  // undo everything in undo_stack[k ... top-1]
4888
  k = egraph->undo.level_index[back_level + 1];
94,069✔
4889
  i = egraph->undo.top;
94,069✔
4890
  utag = egraph->undo.tag;
94,069✔
4891
  udata = egraph->undo.data;
94,069✔
4892
  while (i > k) {
5,141,214✔
4893
    i --;
5,047,145✔
4894
    switch (utag[i]) {
5,047,145✔
4895
    case UNDO_MERGE:
4,926,582✔
4896
      undo_merge(egraph, udata[i].merge.saved_occ, udata[i].merge.saved_label);
4,926,582✔
4897
      break;
4,926,582✔
4898

4899
    case UNDO_DISTINCT:
15✔
4900
      undo_distinct(egraph);
15✔
4901
      break;
15✔
4902

4903
    case UNDO_SIMPLIFY:
66,346✔
4904
      restore_composite(egraph, udata[i].ptr);
66,346✔
4905
      break;
66,346✔
4906

4907
    // store terms to reanalyze into reanalyze_vector
4908
    case REANALYZE_CONGRUENCE_ROOT:
37,508✔
4909
      deactivate_congruence_root(egraph, udata[i].ptr);
37,508✔
4910
      pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
37,508✔
4911
      break;
37,508✔
4912

4913
    case REANALYZE_COMPOSITE:
16,694✔
4914
      pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
16,694✔
4915
      break;
16,694✔
4916

4917
    default:
5,047,145✔
4918
      assert(false);
4919
    }
4920
  }
4921
  assert(i == k);
4922
  egraph->undo.top = k;
94,069✔
4923

4924
  // Cleanup the propagation stack
4925
  k = egraph->stack.level_index[back_level + 1];
94,069✔
4926
  egraph->stack.top = k;
94,069✔
4927
  egraph->stack.prop_ptr = k;
94,069✔
4928

4929
  // delete all temporary data in the arena
4930
  n = egraph->decision_level;
94,069✔
4931
  do {
4932
    arena_pop(&egraph->arena);
6,434,526✔
4933
    n --;
6,434,526✔
4934
  } while (n > back_level);
6,434,526✔
4935

4936
  egraph->decision_level = back_level;
94,069✔
4937
}
94,069✔
4938

4939

4940
/*
4941
 * Full backtrack: egraph + all satellite solvers
4942
 */
4943
void egraph_backtrack(egraph_t *egraph, uint32_t back_level) {
93,849✔
4944
  uint32_t i;
4945

4946
  egraph_local_backtrack(egraph, back_level);
93,849✔
4947
  if (back_level == egraph->base_level && egraph->reanalyze_vector.size > 0) {
93,849✔
4948
    egraph_reactivate_dynamic_terms(egraph);
324✔
4949
  }
4950

4951
  // forward to the satellite solvers
4952
  for (i=0; i<NUM_SATELLITES; i++) {
656,943✔
4953
    if (egraph->ctrl[i] != NULL) {
563,094✔
4954
      egraph->ctrl[i]->backtrack(egraph->th[i], back_level);
161,487✔
4955
    }
4956
  }
4957
}
93,849✔
4958

4959

4960

4961
/*********
4962
 *  POP  *
4963
 ********/
4964

4965
/*
4966
 * Delete composite p
4967
 * - remove it from the congruence table and parent vectors
4968
 *   if it's a congruence root
4969
 * - also remove the corresponding record from the htbl
4970
 */
4971
static void delete_composite(egraph_t *egraph, composite_t *p) {
4,378✔
4972
  elabel_t *label;
4973
  uint32_t h;
4974

4975
  label = egraph->terms.label;
4,378✔
4976

4977
  // compute p->hash
4978
  signature_composite(p, label, &egraph->sgn);
4,378✔
4979
  p->hash = hash_signature(&egraph->sgn);
4,378✔
4980

4981
  if (congruence_table_remove_if_present(&egraph->ctable, p)) {
4,378✔
4982
    detach_composite(p, label, egraph->classes.parents);
×
4983
  }
4984

4985
  // hash code used in hash-consing
4986
  h = hash_composite(p);
4,378✔
4987
  int_htbl_erase_record(&egraph->htbl, h, p->id);
4,378✔
4988

4989
  safe_free(p);
4,378✔
4990
}
4,378✔
4991

4992

4993
/*
4994
 * Cleanup the term table
4995
 * - remove terms of id n to nterms - 1
4996
 */
4997
static void restore_eterms(egraph_t *egraph, uint32_t n) {
220✔
4998
  composite_t *cmp;
4999
  eterm_t t;
5000
  thvar_t x;
5001
  atom_t *atom;
5002

5003
  t = egraph->terms.nterms;
220✔
5004
  assert(t >= n);
5005

5006
  while (t > n) {
6,455✔
5007
    t --;
6,235✔
5008
    cmp = egraph_term_body(egraph, t);
6,235✔
5009
    if (composite_body(cmp)) {
6,235✔
5010
      delete_composite(egraph, cmp);
4,378✔
5011
    } else if (constant_body(cmp)) {
1,857✔
5012
      egraph_delete_constant(egraph, t);
38✔
5013
    }
5014

5015
    x = egraph_term_thvar(egraph, t);
6,235✔
5016
    assert(x == egraph_term_base_thvar(egraph, t) ||
5017
           (x == null_thvar && egraph_term_base_thvar(egraph, t) == const_bvar)); // special case: cf. assert_pred_axiom
5018

5019
    /*
5020
     * another special case: in assert_distinct_axiom, we attach t
5021
     * to the theory variable const_var (i.e., 0) and we don't want
5022
     * to delete the corresponding atom here.
5023
     */
5024
    if (x != null_thvar && x != const_bvar && egraph_term_type(egraph, t) == ETYPE_BOOL) {
6,235✔
5025
      // remove atom if there's one
5026
      atom = get_egraph_atom_for_bvar(egraph, x);
2,495✔
5027
      if (atom != NULL) {
2,495✔
5028
        delete_egraph_atom(egraph, atom);
2,495✔
5029
      }
5030
    }
5031
  }
5032

5033
  egraph->terms.nterms = n;
220✔
5034
}
220✔
5035

5036

5037
/*
5038
 * Cleanup the class table: remove class of ids n to nclasses - 1
5039
 */
5040
static void restore_classes(egraph_t *egraph, uint32_t n) {
220✔
5041
  class_t c;
5042

5043
  c = egraph->classes.nclasses;
220✔
5044
  assert(c >= n);
5045

5046
  while (c > n) {
6,455✔
5047
    c --;
6,235✔
5048
    free_parents(&egraph->classes, c);
6,235✔
5049
  }
5050
  egraph->classes.nclasses = n;
220✔
5051
}
220✔
5052

5053

5054
#ifndef NDEBUG
5055
/*
5056
 * For debugging: check that all composites in the reanalyze_vector
5057
 * are terms to be deleted.
5058
 */
5059
static bool reanalyze_to_delete(egraph_t *egraph) {
5060
  pvector_t *v;
5061
  composite_t *p;
5062
  uint32_t i, n, k;
5063

5064
  // k = index of the first term to delete. All terms with id < k must
5065
  // be preserved.
5066
  k = egraph_trail_top(&egraph->trail_stack)->nterms;
5067

5068
  v = &egraph->reanalyze_vector;
5069
  n = v->size;
5070
  for (i=0; i<n; i++) {
5071
    p = v->data[i];
5072
    if (p->id < k) {
5073
      return false;
5074
    }
5075
  }
5076

5077
  return true;
5078
}
5079
#endif
5080

5081

5082
/*
5083
 * Return to the previous base_level
5084
 */
5085
void egraph_pop(egraph_t *egraph) {
220✔
5086
  egraph_trail_t *trail;
5087
  uint32_t i;
5088

5089
#if 0
5090
  printf("*** EGRAPH POP ENTRY ****\n");
5091
  print_egraph_root_classes_details(stdout, egraph);
5092
  print_egraph_congruence_roots(stdout, egraph);
5093
#endif
5094

5095
  assert(egraph->base_level > 0 && egraph->base_level == egraph->decision_level);
5096
  assert(egraph->reanalyze_vector.size == 0);
5097

5098
  // decrease base_level then backtrack
5099
  egraph->ack_left = null_occurrence;
220✔
5100
  egraph->ack_right = null_occurrence;
220✔
5101
  egraph->base_level --;
220✔
5102
  egraph_local_backtrack(egraph, egraph->base_level);
220✔
5103

5104
  // local_backtrack may have moved terms to the reanalyze_vector
5105
  // these should all be dead term so we can empty the reanalyze_vector.
5106
  assert(reanalyze_to_delete(egraph));
5107
  pvector_reset(&egraph->reanalyze_vector);
220✔
5108

5109
  // clear the high-order flag
5110
  egraph->is_high_order = false;
220✔
5111

5112
  // remove all terms and classes of id >= trail->nterms
5113
  trail = egraph_trail_top(&egraph->trail_stack);
220✔
5114
  restore_eterms(egraph, trail->nterms);
220✔
5115
  restore_classes(egraph, trail->nterms);
220✔
5116

5117
  // restore the propagation pointer
5118
  egraph->stack.prop_ptr = trail->prop_ptr;
220✔
5119

5120
  // cleanup the cache
5121
  cache_pop(&egraph->cache);
220✔
5122

5123
  // remove top trail element
5124
  egraph_trail_pop(&egraph->trail_stack);
220✔
5125

5126
  // forward pop to the satellite solvers
5127
  for (i=0; i<NUM_SATELLITES; i++) {
1,540✔
5128
    if (egraph->ctrl[i] != NULL) {
1,320✔
5129
      egraph->ctrl[i]->pop(egraph->th[i]);
337✔
5130
    }
5131
  }
5132

5133
#if 0
5134
  printf("\n*** EGRAPH POP: EXIT ****\n");
5135
  print_egraph_root_classes_details(stdout, egraph);
5136
  print_egraph_congruence_roots(stdout, egraph);
5137
#endif
5138

5139
}
220✔
5140

5141

5142

5143
/*****************
5144
 *  PROPAGATION  *
5145
 ****************/
5146

5147
/*
5148
 * Propagation via equality propagation queue.
5149
 * Return false if a conflict is detected, true otherwise.
5150
 * If there's a conflict, it is stored (as a conjunction of literals) in egraph->expl_vector.
5151
 */
5152
static bool egraph_internal_propagation(egraph_t *egraph) {
6,825,908✔
5153
  equeue_elem_t *e;
5154
  uint32_t i;
5155

5156
  // reactivate any composite in the reanalyze_vector
5157
  if (egraph->reanalyze_vector.size > 0) {
6,825,908✔
5158
    egraph_reactivate_dynamic_terms(egraph);
6,994✔
5159
  }
5160

5161
  // process the equality queue
5162
  i = egraph->stack.prop_ptr;
6,825,908✔
5163
  while (i < egraph->stack.top) {
13,519,218✔
5164
    e = egraph->stack.eq + i;
6,712,530✔
5165
    if (! process_equality(egraph, e->lhs, e->rhs, i)) {
6,712,530✔
5166
#if 0
5167
      printf("---> EGRAPH CONFLICT on ");
5168
      print_occurrence(stdout, e->lhs);
5169
      printf(" == ");
5170
      print_occurrence(stdout, e->rhs);
5171
      printf("\n     explanation: ");
5172
      print_egraph_conflict(stdout, egraph, &egraph->expl_vector);
5173
      printf("\n");
5174
      fflush(stdout);
5175
#endif
5176
      egraph->stack.prop_ptr = i;
19,220✔
5177
      return false;
19,220✔
5178
    }
5179
    i ++;
6,693,310✔
5180
  }
5181
  egraph->stack.prop_ptr = i;
6,806,688✔
5182

5183
  return true;
6,806,688✔
5184
}
5185

5186

5187
/*
5188
 * Full propagation: in egraph and satellite solvers
5189
 * Return false if there's a conflict, true otherwise.
5190
 * If the conflict is in the egraph, report it to the core.
5191
 */
5192
bool egraph_propagate(egraph_t *egraph) {
6,813,087✔
5193
  uint32_t i, k;
5194
  ivector_t *conflict;
5195

5196
#if TRACE
5197
  printf("---> EGRAPH PROPAGATE [dlevel = %"PRIu32", decisions = %"PRIu64"]\n",
5198
         egraph->decision_level, egraph->core->stats.decisions);
5199
#endif
5200

5201
  do {
5202
    if (! egraph_internal_propagation(egraph)) {
6,825,908✔
5203
      /*
5204
       * Egraph conflict:
5205
       * the conflict is in egraph->expl_vector, in the form "not (l1 and .... and l_n)"
5206
       * we need to turn this into the clause "(not l_1) or ... or (not l_n)"
5207
       * and add the end marker.
5208
       */
5209
      conflict = &egraph->expl_vector;
19,220✔
5210
      for (i=0; i<conflict->size; i++) {
149,316✔
5211
        conflict->data[i] = not(conflict->data[i]);
130,096✔
5212
      }
5213
      ivector_push(conflict, null_literal); // end marker
19,220✔
5214
      record_theory_conflict(egraph->core, conflict->data);
19,220✔
5215

5216
      egraph->stats.th_conflicts ++;
19,220✔
5217

5218
      return false;
19,220✔
5219
    }
5220

5221

5222
    // To detect equalities propagated from the theory solvers (i.e., the simplex
5223
    // solver for now).
5224
    k = egraph->stack.top;
6,806,688✔
5225

5226
    // go through all the satellite solvers
5227
    for (i=0; i<NUM_SATELLITES; i++) {
47,614,176✔
5228
      if (egraph->ctrl[i] != NULL) {
40,814,575✔
5229
        if (! egraph->ctrl[i]->propagate(egraph->th[i])) {
13,448,077✔
5230
          return false;
7,087✔
5231
        }
5232
      }
5233
    }
5234

5235

5236
  } while (egraph->stack.top > k);
6,799,601✔
5237

5238

5239
  return true;
6,786,780✔
5240
}
5241

5242

5243

5244
/***************************
5245
 *  INTERFACE EQUALITIES   *
5246
 **************************/
5247

5248
/*
5249
 * Simpler version of make_eq: does not check whether
5250
 * t1 and t2 are known to be equal or distinct.
5251
 *
5252
 * In particular, this function does not call the theory's check_diseq
5253
 * function to avoid circularity.
5254
 */
5255
literal_t egraph_make_simple_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
7,466✔
5256
  occ_t aux;
5257
  eterm_t t;
5258

5259
  assert(t1 != t2);
5260

5261
  // normalize
5262
  if (t1 > t2) {
7,466✔
5263
    aux = t1; t1 = t2; t2 = aux;
103✔
5264
  }
5265

5266
  t = egraph_eq_term(egraph, t1, t2);
7,466✔
5267
  return egraph_term2literal(egraph, t);
7,466✔
5268
}
5269

5270

5271

5272
/*
5273
 * Check whether (eq t1 t2) exists and if it does return the
5274
 * corresponding literal.
5275
 * - return null_literal if (eq t1 t2) does not exist
5276
 * - return false_literal if (eq t1 t2) does exist but is not attached to an atom
5277
 */
5278
literal_t egraph_find_eq(egraph_t *egraph, occ_t t1, occ_t t2) {
401,379✔
5279
  occ_t aux;
5280
  eterm_t eq;
5281
  bvar_t v;
5282
  literal_t l;
5283

5284
  if (t1 > t2) {
401,379✔
5285
    aux = t1; t1 = t2; t2 = aux;
296,978✔
5286
  }
5287

5288
  l = null_literal;
401,379✔
5289
  eq = egraph_find_eq_term(egraph, t1, t2);
401,379✔
5290
  if (eq >= 0) {
401,379✔
5291
    assert(egraph_term_type(egraph, eq) == ETYPE_BOOL);
5292
    v = egraph->terms.thvar[eq];
195,773✔
5293
#if CONSERVATIVE_DISEQ_AXIOMS
5294
    assert(v != null_thvar);
5295
    l = pos_lit(v);
5296
#else
5297
    // null_thvar is possible if (eq t1 t2) is false at the top level
5298
    if (v == null_thvar) {
195,773✔
5299
      assert(egraph_term_is_false(egraph, eq) || egraph_term_asserted_false(egraph, eq));
5300
      l = false_literal; // eq is asserted as an axiom, so its literal is false
3✔
5301
    } else {
5302
      l = pos_lit(v);
195,770✔
5303
    }
5304
#endif
5305
  }
5306

5307
  return l;
401,379✔
5308
}
5309

5310

5311

5312

5313
/**********************
5314
 *  HIGH-ORDER TERMS  *
5315
 *********************/
5316

5317
/*
5318
 * Check whether child i of p is a function
5319
 */
5320
static inline bool composite_child_is_function(egraph_t *egraph, composite_t *cmp, uint32_t i) {
65,868✔
5321
  return egraph_term_is_function(egraph, term_of_occ(composite_child(cmp, i)));
65,868✔
5322
}
5323

5324
/*
5325
 * Check whether one child of p is a function:
5326
 * - scan children from i to p's arity (i=0 or i=1 to skip the first child)
5327
 */
5328
static bool composite_has_function_child(egraph_t *egraph, composite_t *cmp, uint32_t i) {
32,920✔
5329
  uint32_t n;
5330

5331
  n = composite_arity(cmp);
32,920✔
5332
  while (i < n) {
83,812✔
5333
    if (composite_child_is_function(egraph, cmp, i)) {
50,907✔
5334
      return true;
15✔
5335
    }
5336
    i ++;
50,892✔
5337
  }
5338
  return false;
32,905✔
5339
}
5340

5341
/*
5342
 * Check whether composite cmp is high order:
5343
 * - return true if some of cmp's children are function terms
5344
 */
5345
static bool composite_is_high_order(egraph_t *egraph, composite_t *cmp) {
47,881✔
5346
  switch (composite_kind(cmp)) {
47,881✔
5347
  case COMPOSITE_APPLY:
32,788✔
5348
  case COMPOSITE_UPDATE:
5349
    return composite_has_function_child(egraph, cmp, 1);
32,788✔
5350
  case COMPOSITE_TUPLE:
132✔
5351
    return composite_has_function_child(egraph, cmp, 0);
132✔
5352
  case COMPOSITE_EQ:
14,940✔
5353
    // (eq u v): both u and v are functions or neither is
5354
    return composite_child_is_function(egraph, cmp, 0);
14,940✔
5355
  case COMPOSITE_ITE:
2✔
5356
    // (ite c u v): both u and v are functions or neither is
5357
    return composite_child_is_function(egraph, cmp, 1);
2✔
5358
  case COMPOSITE_DISTINCT:
19✔
5359
    // (distinct u_1 ... u_n) all children are functions or none
5360
    return composite_child_is_function(egraph, cmp, 0);
19✔
5361
  case COMPOSITE_OR:
×
5362
  default:
5363
    return false;
×
5364
  }
5365
}
5366

5367

5368
/*
5369
 * Check whether there's a high order term in the egraph
5370
 */
5371
static bool egraph_has_high_order_terms(egraph_t *egraph) {
25,795✔
5372
  composite_t *cmp;
5373
  uint32_t i, n;
5374

5375
  n = egraph_num_terms(egraph);
25,795✔
5376
  for (i=0; i<n; i++) {
120,824✔
5377
    cmp = egraph_term_body(egraph, i);
95,084✔
5378
    if (composite_body(cmp) && composite_is_high_order(egraph, cmp)) {
95,084✔
5379
      return true;
55✔
5380
    }
5381
  }
5382
  return false;
25,740✔
5383
}
5384

5385

5386
/*
5387
 * Check for high-order terms then cache the result in egraph->is_high_order
5388
 */
5389
static bool egraph_is_high_order(egraph_t *egraph) {
26,136✔
5390
  bool h;
5391

5392
  h = egraph->is_high_order;
26,136✔
5393
  if (!h) {
26,136✔
5394
    h = egraph_has_high_order_terms(egraph);
25,795✔
5395
    egraph->is_high_order = h;
25,795✔
5396
  }
5397
  return h;
26,136✔
5398
}
5399

5400

5401
/*
5402
 * Find the maximum function depth of the children of composite cmp
5403
 * - scan children from i to cmp's arity (i=0 or i=1 to skip the first child)
5404
 */
5405
static int32_t composite_max_child_depth(egraph_t *egraph, composite_t *cmp, uint32_t i) {
1,948✔
5406
  uint32_t n;
5407
  int32_t maxdepth, cdepth;
5408
  eterm_t x;
5409
  composite_t *c;
5410

5411
  n = composite_arity(cmp);
1,948✔
5412
  maxdepth = DEF_DEPTH;
1,948✔
5413
  while (i < n) {
5,837✔
5414
    x = term_of_occ(composite_child(cmp, i));
3,889✔
5415
    c = egraph_term_body(egraph, x);
3,889✔
5416
    if (composite_body(c)) {
3,889✔
5417
      cdepth = composite_depth(egraph, c);
2,296✔
5418
      maxdepth = (cdepth > maxdepth) ? cdepth : maxdepth;
2,296✔
5419
    }
5420
    i ++;
3,889✔
5421
  }
5422
  return maxdepth;
1,948✔
5423
}
5424

5425

5426
/*
5427
 * Find (and store) the function depth of composite cmp
5428
 */
5429
int32_t composite_depth(egraph_t *egraph, composite_t *cmp) {
942,774✔
5430
  if (cmp->depth != UNKNOWN_DEPTH) {
942,774✔
5431
#if 0
5432
    printf("cmp_depth (cached) is %d for ", cmp->depth);
5433
    print_composite(stdout, cmp);
5434
    printf("\n");
5435
#endif
5436
    return cmp->depth;
940,826✔
5437
  }
5438

5439
  int32_t depth;
5440
  depth = UNKNOWN_DEPTH;
1,948✔
5441

5442
  switch (composite_kind(cmp)) {
1,948✔
5443
  case COMPOSITE_APPLY:
1,948✔
5444
  case COMPOSITE_UPDATE:
5445
    depth = 1 + composite_max_child_depth(egraph, cmp, 1);
1,948✔
5446
    break;
1,948✔
5447
  case COMPOSITE_TUPLE:
×
5448
  case COMPOSITE_EQ:
5449
  case COMPOSITE_ITE:
5450
  case COMPOSITE_DISTINCT:
5451
  case COMPOSITE_OR:
5452
  case COMPOSITE_LAMBDA:
5453
    depth = composite_max_child_depth(egraph, cmp, 0);
×
5454
    break;
×
5455
  default:
1,948✔
5456
    assert(false);
5457
  }
5458

5459
  cmp->depth = depth;
1,948✔
5460
#if 0
5461
  printf("cmp_depth is %d for ", depth);
5462
  print_composite(stdout, cmp);
5463
  printf("\n");
5464
#endif
5465

5466
  return depth;
1,948✔
5467
}
5468

5469

5470
/*
5471
 * Find (and store) the function depth of eterm t
5472
 */
5473
int32_t eterm_depth(egraph_t *egraph, eterm_t t) {
64,699✔
5474
  composite_t *c;
5475

5476
  c = egraph_term_body(egraph, t);
64,699✔
5477
  if (composite_body(c))
64,699✔
5478
    return composite_depth(egraph, c);
20,599✔
5479
  else
5480
    return DEF_DEPTH;
44,100✔
5481
}
5482

5483

5484
/******************************************************************
5485
 *  MODIFY THE EGRAPH TO MINIMIZE THE NUMBER OF INTERFACE LEMMAS  *
5486
 *****************************************************************/
5487

5488
/*
5489
 * Prepare the satellite models for the arithmetic and bitvector theories
5490
 */
5491
static void egraph_prepare_models(egraph_t *egraph) {
17,241✔
5492
  if (egraph->ctrl[ETYPE_REAL] != NULL) {
17,241✔
5493
    assert(egraph->eg[ETYPE_REAL] != NULL);
5494
    egraph->eg[ETYPE_REAL]->prepare_model(egraph->th[ETYPE_REAL]);
13,424✔
5495
  }
5496
  if (egraph->ctrl[ETYPE_BV] != NULL) {
17,241✔
5497
    assert(egraph->eg[ETYPE_BV] != NULL);
5498
    egraph->eg[ETYPE_BV]->prepare_model(egraph->th[ETYPE_BV]);
15,612✔
5499
  }
5500
}
17,241✔
5501

5502

5503
/*
5504
 * Release the satellite models
5505
 */
5506
static void egraph_release_models(egraph_t *egraph) {
17,241✔
5507
  if (egraph->ctrl[ETYPE_REAL] != NULL) {
17,241✔
5508
    assert(egraph->eg[ETYPE_REAL] != NULL);
5509
    egraph->eg[ETYPE_REAL]->release_model(egraph->th[ETYPE_REAL]);
13,424✔
5510
  }
5511
  if (egraph->ctrl[ETYPE_BV] != NULL) {
17,241✔
5512
    assert(egraph->eg[ETYPE_BV] != NULL);
5513
    egraph->eg[ETYPE_BV]->release_model(egraph->th[ETYPE_BV]);
15,612✔
5514
  }
5515
}
17,241✔
5516

5517

5518

5519
#if TRACE_FCHECK
5520
/*
5521
 * Test: check whether there are duplicates in vector v
5522
 */
5523
static void check_interface_duplicates(ivector_t *v) {
5524
  uint32_t i, j, n;
5525
  occ_t t1, t2;
5526

5527
  n = v->size;
5528
  for (i=0; i<n; i += 2) {
5529
    t1 = v->data[i];
5530
    t2 = v->data[i+1];
5531
    for (j=i+2; j<n; j += 2) {
5532
      if ((v->data[j] == t1 && v->data[j+1] == t2)
5533
          || (v->data[j] == t2 && v->data[j+1] == t1)) {
5534
        printf("---> EGRAPH: interface lemma duplicate: "
5535
               "v[%"PRIu32", %"PRIu32"] = (%"PRId32", %"PRId32"); "
5536
               "v[%"PRIu32", %"PRIu32"] = (%"PRId32", %"PRId32")\n", i, i+1, t1, t2, j, j+1, v->data[j], v->data[j+1]);
5537
        fflush(stdout);
5538
      }
5539
    }
5540
  }
5541
}
5542

5543
#endif
5544

5545

5546
/*
5547
 * Generate interface lemmas for pairs of term occurrences stored in v
5548
 * - stop as soon as max_eqs interface lemmas are produced
5549
 * - return the number of lemmas generated
5550
 */
5551
static uint32_t egraph_gen_interface_lemmas(egraph_t *egraph, uint32_t max_eqs, ivector_t *v) {
2,167✔
5552
  void *satellite;
5553
  th_egraph_interface_t *interface;
5554
  uint32_t i, n;
5555
  occ_t t1, t2;
5556
  thvar_t x1, x2;
5557
  literal_t eq;
5558

5559
#if TRACE_FCHECK
5560
  check_interface_duplicates(v);
5561
#endif
5562

5563
  n = v->size;
2,167✔
5564
  assert(n > 0);
5565
  if (n > 2 * max_eqs) {
2,167✔
5566
    n = 2 * max_eqs;
1✔
5567
  }
5568

5569
  for (i=0; i<n; i += 2) {
4,849✔
5570
    t1 = v->data[i];
2,682✔
5571
    t2 = v->data[i+1];
2,682✔
5572
    assert(egraph_class(egraph, t1) != egraph_class(egraph, t2));
5573
    x1 = egraph_base_thvar(egraph, t1);
2,682✔
5574
    x2 = egraph_base_thvar(egraph, t2);
2,682✔
5575
    assert(x1 != null_thvar && x2 != null_thvar);
5576

5577
    switch (egraph_type(egraph, t1)) {
2,682✔
5578
    case ETYPE_INT:
463✔
5579
    case ETYPE_REAL:
5580
      satellite = egraph->th[ETYPE_REAL];
463✔
5581
      interface = egraph->eg[ETYPE_REAL];
463✔
5582
      break;
463✔
5583

5584
    case ETYPE_BV:
2,219✔
5585
      satellite = egraph->th[ETYPE_BV];
2,219✔
5586
      interface = egraph->eg[ETYPE_BV];
2,219✔
5587
      break;
2,219✔
5588

5589
    default:
×
5590
      assert(false);
5591
      abort();
×
5592
      break;
5593
    }
5594

5595
    assert(interface->equal_in_model(satellite, x1, x2));
5596
    eq = egraph_make_simple_eq(egraph, t1, t2);
2,682✔
5597
    interface->gen_interface_lemma(satellite, not(eq), x1, x2, true);
2,682✔
5598
  }
5599

5600
  assert(n/2 <= max_eqs);
5601

5602
  return n/2;
2,167✔
5603
}
5604

5605
/*
5606
 * Check whether Boolean variables x1 and x2 have different values in the core
5607
 */
5608
static bool bool_var_equal_in_model(egraph_t *egraph, thvar_t x1, thvar_t x2) {
×
5609
  bval_t b1, b2;
5610

5611
  b1 = bvar_value(egraph->core, x1);
×
5612
  b2 = bvar_value(egraph->core, x2);
×
5613
  assert(bval_is_def(b1) && bval_is_def(b2));
5614
  return b1 == b2;
×
5615
}
5616

5617
/*
5618
 * Check whether x1 and x2 have different values in the relevant theory solver
5619
 * - i = type of x1
5620
 * - we ignore the function solver here
5621
 */
5622
static bool diseq_in_model(egraph_t *egraph, etype_t i, thvar_t x1, thvar_t x2) {
995,351✔
5623
  switch (i) {
995,351✔
5624
  case ETYPE_INT:
591,081✔
5625
  case ETYPE_REAL:
5626
  case ETYPE_BV:
5627
    return !egraph->eg[i]->equal_in_model(egraph->th[i], x1, x2);
591,081✔
5628

5629
  case ETYPE_BOOL:
×
5630
    return  !bool_var_equal_in_model(egraph, x1, x2);;
×
5631

5632
  default:
404,270✔
5633
    return false;
404,270✔
5634
  }
5635
}
5636

5637

5638
/*
5639
 * Check whether the classes of t1 and t2 can be merged
5640
 * - c1 must be the class of t1 and c2 must be the class of t2
5641
 * - if c1 and c2 have theory variables, then they can be merged if the
5642
 *   variables have equal values in the theory model
5643
 */
5644
static bool mergeable_classes(egraph_t *egraph, occ_t t1, occ_t t2, class_t c1, class_t c2) {
997,788✔
5645
  uint32_t msk;
5646
  composite_t *cmp;
5647
  thvar_t x1, x2;
5648

5649
  if (egraph_opposite_occ(egraph, t1, t2)) {
997,788✔
5650
    return false;
53✔
5651
  }
5652

5653
  assert(c1 != c2);
5654

5655
  msk = egraph->classes.dmask[c1] & egraph->classes.dmask[c2];
997,735✔
5656
  if (msk != 0) {
997,735✔
5657
    return false;
14✔
5658
  }
5659

5660
  cmp = congruence_table_find_eq(&egraph->ctable, t1, t2, egraph->terms.label);
997,721✔
5661
  if (cmp != NULL && egraph_occ_is_false(egraph, pos_occ(cmp->id))) {
997,721✔
5662
    return false;
2,370✔
5663
  }
5664

5665
  x1 = egraph_class_thvar(egraph, c1);
995,351✔
5666
  x2 = egraph_class_thvar(egraph, c2);
995,351✔
5667

5668
  if (x1 != null_thvar && x2 != null_thvar &&
1,990,702✔
5669
      diseq_in_model(egraph, egraph_class_type(egraph, c1), x1, x2)) {
995,351✔
5670
    return false;
246✔
5671
  }
5672

5673
  return true;
995,105✔
5674
}
5675

5676

5677
/*
5678
 * Propagate equality v1 == v2 during reconciliation
5679
 * - id = edge that caused merging of c1 and c2
5680
 */
5681
static void reconcile_thvar(egraph_t *egraph, class_t c1, thvar_t v1, class_t c2, thvar_t v2, int32_t id) {
995,105✔
5682
  etype_t i;
5683

5684
  assert(v1 != null_thvar && v2 != null_thvar &&
5685
         v1 == egraph_class_thvar(egraph, c1) &&
5686
         v2 == egraph_class_thvar(egraph, c2));
5687

5688
  i = egraph->classes.etype[c1];
995,105✔
5689

5690
  switch (i) {
995,105✔
5691
  case ETYPE_INT:
590,835✔
5692
  case ETYPE_REAL:
5693
  case ETYPE_BV:
5694
    assert(egraph->eg[i]->equal_in_model(egraph->th[i], v1, v2));
5695
    break;
590,835✔
5696

5697
  case ETYPE_FUNCTION:
404,270✔
5698
    egraph->eg[i]->assert_equality(egraph->th[i], v1, v2, id);
404,270✔
5699
    break;
404,270✔
5700

5701
  case ETYPE_BOOL:
×
5702
    // all Boolean variables are already assigned in the core.
5703
    assert(bool_var_equal_in_model(egraph, v1, v2));
5704
    break;
×
5705

5706
  case ETYPE_TUPLE:
×
5707
    propagate_tuple_equality(egraph, v1, v2);
×
5708
    break;
×
5709

5710
  default:
995,105✔
5711
    assert(false);
5712
  }
5713
}
995,105✔
5714

5715

5716
/*
5717
 * Attempt to merge the classes of t1 and t2 without affecting the theory models
5718
 * - t1 and t2 must not be Boolean
5719
 * - i = corresponding edge id
5720
 * - return true if t1 and t2 can be merged
5721
 * - return false otherwise
5722
 */
5723
static bool test_merge(egraph_t *egraph, occ_t t1, occ_t t2, int32_t i) {
1,418,994✔
5724
  use_vector_t *v;
5725
  composite_t *p;
5726
  class_t c1, c2;
5727
  int32_t aux;
5728
  uint32_t j, n;
5729
  elabel_t l;
5730
  occ_t t;
5731
  thvar_t v1, v2;
5732

5733
  if (egraph_equal_occ(egraph, t1, t2)) {
1,418,994✔
5734
    return true;
421,206✔
5735
  }
5736

5737
  c1 = egraph_class(egraph, t1);
997,788✔
5738
  c2 = egraph_class(egraph, t2);
997,788✔
5739

5740
  if (! mergeable_classes(egraph, t1, t2, c1, c2)) {
997,788✔
5741
    return false;
2,683✔
5742
  }
5743

5744
  assert(c1 != c2 && (egraph->classes.dmask[c1] & egraph->classes.dmask[c2]) == 0);
5745

5746
  // make sure c2 is the class with smallest parent vector
5747
  if (egraph_class_nparents(egraph, c2) > egraph_class_nparents(egraph, c1)) {
995,105✔
5748
    aux = t1; t1 = t2; t2 = aux;
5,522✔
5749
    aux = c1; c1 = c2; c2 = aux;
5,522✔
5750
  }
5751

5752
  // save t2 and its label for backtracking
5753
  undo_stack_push_merge(&egraph->undo, t2, egraph_label(egraph, t2));
995,105✔
5754

5755
  // update the explanation tree
5756
  invert_branch(egraph, t2);
995,105✔
5757
  assert(egraph->terms.edge[term_of_occ(t2)] == null_edge);
5758
  egraph->terms.edge[term_of_occ(t2)] = i;
995,105✔
5759

5760
  // remove c2's parents from the congruence table
5761
  v = egraph->classes.parents + c2;
995,105✔
5762
  n = v->last;
995,105✔
5763
  for (j=0; j<n; j++) {
3,615,867✔
5764
    p  = v->data[j];
2,620,762✔
5765
    if (valid_entry(p)) {
2,620,762✔
5766
      // p is in the congruence table
5767
      congruence_table_remove(&egraph->ctable, p);
2,507,528✔
5768
      // remove p from the parent vectors (except v)
5769
      separate_composite(p, egraph->terms.label, egraph->classes.parents, c2);
2,507,528✔
5770
      assert(v->data[j] == p);
5771
    }
5772
  }
5773

5774
  // assign a new label to all terms in t2's class
5775
  l = egraph_label(egraph, t1);
995,105✔
5776
  t = t2;
995,105✔
5777
  do {
5778
    egraph_set_label(egraph, t, l);
1,607,663✔
5779
    t = egraph_next(egraph, t);
1,607,663✔
5780
    assert(term_of_occ(t) != term_of_occ(t2) || t == t2);
5781
  } while (t != t2);
1,607,663✔
5782

5783
  // update dmask of c1
5784
  egraph->classes.dmask[c1] |= egraph->classes.dmask[c2];
995,105✔
5785

5786
  //  merge lists of terms: swap next[t1] and next[t2]
5787
  t = egraph_next(egraph, t2);
995,105✔
5788
  egraph_set_next(egraph, t2, egraph_next(egraph, t1));
995,105✔
5789
  egraph_set_next(egraph, t1, t);
995,105✔
5790

5791
  // reprocess all the composites in v
5792
  for (j=0; j<n; j++) {
3,615,867✔
5793
    p = v->data[j];
2,620,762✔
5794
    if (valid_entry(p)) {
2,620,762✔
5795
      if (composite_simplifies(egraph, p)) {
2,507,528✔
5796
        // p no longer a congruence root: put a mark for backtracking
5797
        mark_use_vector_entry(v, j);
830,695✔
5798
      } else {
5799
        // put p back into the use vectors: this add p to c's parent
5800
        attach_composite(p, egraph->terms.label, egraph->classes.parents);
1,676,833✔
5801
      }
5802
    }
5803
  }
5804

5805
  /*
5806
   * deal with the theory variables of c1 and c2:
5807
   */
5808
  v2 = egraph->classes.thvar[c2];
995,105✔
5809
  v1 = egraph->classes.thvar[c1];
995,105✔
5810
  if (v1 != null_thvar) {
995,105✔
5811
    assert(v2 != null_thvar);
5812
    reconcile_thvar(egraph, c1, v1, c2, v2, i);
995,105✔
5813
  }
5814

5815
  return true;
995,105✔
5816
}
5817

5818

5819

5820
/*
5821
 * Backtrack if a reconciliation attempt fails:
5822
 * - k = top of the undo queue when the EXPL_RECONCILE edge was added
5823
 *   (so this revert all merges in undo[k ... top-1]
5824
 */
5825
static void egraph_undo_reconcile_attempt(egraph_t *egraph, uint32_t k) {
18,934✔
5826
  uint32_t i;
5827
  unsigned char *utag;
5828
  undo_t *udata;
5829

5830
  assert(k <= egraph->undo.top);
5831

5832
  i = egraph->undo.top;
18,934✔
5833
  utag = egraph->undo.tag;
18,934✔
5834
  udata = egraph->undo.data;
18,934✔
5835

5836
  while (i > k) {
1,019,385✔
5837
    i --;
1,000,451✔
5838
    switch (utag[i]) {
1,000,451✔
5839
    case UNDO_MERGE:
993,997✔
5840
      undo_merge(egraph, udata[i].merge.saved_occ, udata[i].merge.saved_label);
993,997✔
5841
      break;
993,997✔
5842

5843
    case UNDO_SIMPLIFY:
×
5844
      restore_composite(egraph, udata[i].ptr);
×
5845
      break;
×
5846

5847
    case UNDO_DISTINCT:
×
5848
      assert(false); // should not happen
5849
      undo_distinct(egraph);
×
5850
      break;
×
5851

5852
    // store terms to reanalyze into reanalyze_vector
5853
    case REANALYZE_CONGRUENCE_ROOT:
2,807✔
5854
      deactivate_congruence_root(egraph, udata[i].ptr);
2,807✔
5855
      pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
2,807✔
5856
      break;
2,807✔
5857

5858
    case REANALYZE_COMPOSITE:
3,647✔
5859
      pvector_push(&egraph->reanalyze_vector, udata[i].ptr);
3,647✔
5860
      break;
3,647✔
5861

5862
    default:
×
5863
      assert(false);
5864
      break;
×
5865
    }
5866
  }
5867

5868
  assert(i == k);
5869
  egraph->undo.top = k;
18,934✔
5870
}
18,934✔
5871

5872

5873

5874
/*
5875
 * Collect an interface equality (t1 == t2) when reconciliation fails
5876
 * - source = edge that started the reconciliation
5877
 * - i = conflict edge
5878
 */
5879
static void collect_interface_pair(egraph_t *egraph, int32_t source, int32_t i) {
2,683✔
5880
  equeue_elem_t *e;
5881
  ivector_t *v;
5882
  int32_t k;
5883

5884
  k = egraph_get_reconcile_edge(egraph, source, i);
2,683✔
5885
  e = egraph->stack.eq + k;
2,683✔
5886

5887
  v = &egraph->interface_eqs;
2,683✔
5888
  ivector_push(v, e->lhs);
2,683✔
5889
  ivector_push(v, e->rhs);
2,683✔
5890
}
2,683✔
5891

5892

5893
/*
5894
 * Propagate equalities during reconciliation
5895
 */
5896
static bool egraph_prop_reconcile(egraph_t *egraph) {
591,334✔
5897
  equeue_elem_t *e;
5898
  uint32_t i, s;
5899

5900
  i = egraph->stack.prop_ptr;
591,334✔
5901
  s = i;
591,334✔
5902
  while (i < egraph->stack.top) {
2,007,645✔
5903
    e = egraph->stack.eq + i;
1,418,994✔
5904
    if (!test_merge(egraph, e->lhs, e->rhs, i)) {
1,418,994✔
5905
      collect_interface_pair(egraph, s, i);
2,683✔
5906
      return false;
2,683✔
5907
    }
5908
    i ++;
1,416,311✔
5909
  }
5910
  egraph->stack.prop_ptr = i;
588,651✔
5911

5912
  return true;
588,651✔
5913
}
5914

5915

5916
/*
5917
 * Attempt to make t1 and t2 equal in the egraph then propagate
5918
 * - return false if that leads to a conflict
5919
 * - return true otherwise
5920
 */
5921
static bool egraph_reconcile_pair(egraph_t *egraph, occ_t t1, occ_t t2) {
591,821✔
5922
  int32_t k;
5923
  uint32_t top;
5924

5925
  assert(egraph->stack.prop_ptr == egraph->stack.top);
5926

5927
  if (egraph_equal_occ(egraph, t1, t2)) {
591,821✔
5928
    return true;  // already equal: nothing to do
487✔
5929
  }
5930

5931
  top = egraph->undo.top;
591,334✔
5932
  k = egraph_stack_push_eq(&egraph->stack, t1, t2);
591,334✔
5933
  assert(k == egraph->stack.prop_ptr);
5934

5935
  egraph->stack.etag[k] = EXPL_RECONCILE;
591,334✔
5936
  if (egraph_prop_reconcile(egraph)) {
591,334✔
5937
    return true;
588,651✔
5938
  }
5939

5940
  // clean up
5941
  egraph_undo_reconcile_attempt(egraph, top);
2,683✔
5942
  egraph->stack.top = k;
2,683✔
5943
  egraph->stack.prop_ptr = k;
2,683✔
5944
  return false;
2,683✔
5945
}
5946

5947

5948
/*
5949
 * Process a class of terms
5950
 * - every element of v is a variable in a theory solver
5951
 * - solver = the theory solver for v
5952
 * - eg = the egraph interface for that solver
5953
 */
5954
static bool egraph_reconcile_class(egraph_t *egraph, int32_t *v, void *solver, th_egraph_interface_t *eg) {
16,824✔
5955
  uint32_t i, n;
5956
  eterm_t t1, t2;
5957

5958
  n = iv_size(v);
16,824✔
5959
  assert(n >= 2);
5960

5961
  t1 = eg->eterm_of_var(solver, v[0]);
16,824✔
5962
  for (i=1; i<n; i++) {
605,962✔
5963
    t2 = eg->eterm_of_var(solver, v[i]);
591,821✔
5964
    if (!egraph_reconcile_pair(egraph, pos_occ(t1), pos_occ(t2))) {
591,821✔
5965
#if 0
5966
      printf("Reconciliation failed for class with %"PRIu32" elements, at element %"PRIu32"\n", n, i);
5967
#endif
5968
      return false;
2,683✔
5969
    }
5970
  }
5971

5972
  return true;
14,141✔
5973
}
5974

5975

5976
/*
5977
 * Process a term partition
5978
 * - return true if all terms of every class in the partition can be reconciled
5979
 * - return false otherwise
5980
 */
5981
static bool egraph_reconcile_partition(egraph_t *egraph, ipart_t *partition, void *solver, th_egraph_interface_t *eg) {
29,036✔
5982
  int32_t *v;
5983
  uint32_t i, n;
5984
  bool reconciled;
5985

5986
  reconciled = true;
29,036✔
5987
  n = int_partition_nclasses(partition);
29,036✔
5988
  for (i=0; i<n; i++) {
45,860✔
5989
    v = partition->classes[i];
16,824✔
5990
    reconciled &= egraph_reconcile_class(egraph, v, solver, eg);
16,824✔
5991
  }
5992

5993
  return reconciled;
29,036✔
5994
}
5995

5996

5997

5998
/*
5999
 * Try model reconciliation: return true if that worked, false otherwise
6000
 * - if the result is false then candidates for interface lemmas are
6001
 *   stored in egraph->interface_eqs.
6002
 */
6003
static bool egraph_reconcile(egraph_t *egraph) {
17,241✔
6004
  ipart_t *partition;
6005
  bool reconciled;
6006

6007
  reconciled = true;
17,241✔
6008

6009
  if (egraph->ctrl[ETYPE_REAL] != NULL) {
17,241✔
6010
    partition = egraph->eg[ETYPE_REAL]->build_model_partition(egraph->th[ETYPE_REAL]);
13,424✔
6011
    reconciled = egraph_reconcile_partition(egraph, partition, egraph->th[ETYPE_REAL], egraph->eg[ETYPE_REAL]);
13,424✔
6012
    egraph->eg[ETYPE_REAL]->release_model_partition(egraph->th[ETYPE_REAL], partition);
13,424✔
6013
  }
6014

6015
  if (egraph->ctrl[ETYPE_BV] != NULL) {
17,241✔
6016
    partition = egraph->eg[ETYPE_BV]->build_model_partition(egraph->th[ETYPE_BV]);
15,612✔
6017
    reconciled &= egraph_reconcile_partition(egraph, partition, egraph->th[ETYPE_BV], egraph->eg[ETYPE_BV]);
15,612✔
6018
    egraph->eg[ETYPE_BV]->release_model_partition(egraph->th[ETYPE_BV], partition);
15,612✔
6019
  }
6020

6021
  return reconciled;
17,241✔
6022
}
6023

6024

6025

6026
/*
6027
 * Prepare for reconciliation:
6028
 * - store the current number of equalities + the top of the undo stack
6029
 * - set the reconcile_mode flag
6030
 */
6031
static void egraph_start_reconciliation(egraph_t *egraph) {
17,241✔
6032
  assert(egraph->stack.prop_ptr == egraph->stack.top);
6033
  egraph->reconcile_top = egraph->undo.top;
17,241✔
6034
  egraph->reconcile_neqs = egraph->stack.top;
17,241✔
6035
  egraph->reconcile_mode = true;
17,241✔
6036
}
17,241✔
6037

6038

6039
/*
6040
 * Restore the egraph state to what it was before reconciliation:
6041
 */
6042
static void egraph_reconciliation_restore(egraph_t *egraph) {
16,251✔
6043
  egraph_undo_reconcile_attempt(egraph, egraph->reconcile_top);
16,251✔
6044
  egraph->stack.top = egraph->reconcile_neqs;
16,251✔
6045
  egraph->stack.prop_ptr = egraph->reconcile_neqs;
16,251✔
6046
  egraph->reconcile_mode = false;
16,251✔
6047
}
16,251✔
6048

6049

6050

6051

6052

6053
/*****************
6054
 *  FINAL CHECK  *
6055
 ****************/
6056

6057
/*
6058
 * BASELINE VERSION OF FINAL CHECK
6059
 * - call final_check on all satellites then use the reconcile_model
6060
 *   function in each solver
6061
 */
6062
static fcheck_code_t baseline_final_check(egraph_t *egraph) {
19✔
6063
  fcheck_code_t c;
6064
  uint32_t i, max_eq;
6065

6066
#if TRACE_FCHECK
6067
  printf("---> EGRAPH: final check (baseline)\n\n");
6068
  print_egraph_terms(stdout, egraph);
6069
  printf("\n");
6070
  print_egraph_root_classes_details(stdout, egraph);
6071
  fflush(stdout);
6072
#endif
6073

6074
  if (egraph->ctrl[ETYPE_REAL] != NULL) {
19✔
6075
    // arithmetic solver
6076
    c = egraph->ctrl[ETYPE_REAL]->final_check(egraph->th[ETYPE_REAL]);
19✔
6077
    if (c != FCHECK_SAT) {
19✔
6078
#if TRACE_FCHECK
6079
      printf("---> exit at arith final check\n");
6080
      fflush(stdout);
6081
#endif
6082
      return c;
1✔
6083
    }
6084
  }
6085

6086
  if (egraph->ctrl[ETYPE_BV] != NULL) {
18✔
6087
    // bitvector solver
6088
    c = egraph->ctrl[ETYPE_BV]->final_check(egraph->th[ETYPE_BV]);
×
6089
    if (c != FCHECK_SAT) {
×
6090
#if TRACE_FCHECK
6091
       printf("---> exit at bv final check\n");
6092
       fflush(stdout);
6093
#endif
6094
      return c;
×
6095
    }
6096
  }
6097

6098
  if (egraph->ctrl[ETYPE_FUNCTION] != NULL) {
18✔
6099
    // array solver
6100
    c = egraph->ctrl[ETYPE_FUNCTION]->final_check(egraph->th[ETYPE_FUNCTION]);
×
6101
    if (c != FCHECK_SAT) {
×
6102
#if TRACE_FCHECK
6103
      printf("---> exit at array final check\n");
6104
      fflush(stdout);
6105
#endif
6106
      return c;
×
6107
    }
6108
  }
6109

6110
  if (egraph->ctrl[ETYPE_MCSAT] != NULL) {
18✔
6111
    // supplementary mcsat solver
NEW
6112
    c = egraph->ctrl[ETYPE_MCSAT]->final_check(egraph->th[ETYPE_MCSAT]);
×
NEW
6113
    if (c != FCHECK_SAT) {
×
6114
#if TRACE_FCHECK
6115
      printf("---> exit at supplementary mcsat final check\n");
6116
      fflush(stdout);
6117
#endif
NEW
6118
      return c;
×
6119
    }
6120
  }
6121

6122

6123
  // i = number of interface equalities generated
6124
  // max_eq = bound on number of interface equalities
6125
  max_eq = egraph->max_interface_eqs;
18✔
6126
  i = 0;
18✔
6127
  assert(i < max_eq);
6128

6129
  if (egraph->ctrl[ETYPE_REAL] != NULL) {
18✔
6130
    // reconcile for arithmetic solver
6131
    assert(egraph->eg[ETYPE_REAL] != NULL);
6132
    i = egraph->eg[ETYPE_REAL]->reconcile_model(egraph->th[ETYPE_REAL], max_eq);
18✔
6133
  }
6134

6135
  if (i < max_eq && egraph->ctrl[ETYPE_BV] != NULL) {
18✔
6136
    // reconcile in bitvector solver
6137
    assert(egraph->eg[ETYPE_BV] != NULL);
6138
    i += egraph->eg[ETYPE_BV]->reconcile_model(egraph->th[ETYPE_BV], max_eq - i);
×
6139
  }
6140

6141
#if TRACE_FCHECK
6142
  if (i > 0) {
6143
    printf("---> %"PRIu32" interface lemmas from bv/arith solvers\n", i);
6144
    fflush(stdout);
6145
  }
6146
#endif
6147

6148
  if (i == 0 && egraph->ctrl[ETYPE_FUNCTION] != NULL && egraph_is_high_order(egraph)) {
18✔
6149
    /*
6150
     * reconcile for array solver: do it only if bv and arith models
6151
     * are consistent with the egraph. Also there's nothing to do
6152
     * if there are no high-order terms.
6153
     */
6154
    assert(egraph->eg[ETYPE_FUNCTION] != NULL);
6155
    i = egraph->eg[ETYPE_FUNCTION]->reconcile_model(egraph->th[ETYPE_FUNCTION], 1);
×
6156
#if TRACE_CHECK
6157
    if (i > 0) {
6158
      printf("---> %"PRIu32" interface lemmas from array solver\n", i);
6159
      fflush(stdout);
6160
    }
6161
#endif
6162
  }
6163

6164
  egraph->stats.interface_eqs += i;
18✔
6165

6166
  if (i == 1) {
18✔
6167
    trace_printf(egraph->core->trace, 3, "(final check: 1 interface lemma)\n");
12✔
6168
  } else {
6169
    trace_printf(egraph->core->trace, 3, "(final check: %"PRIu32" interface lemmas)\n", i);
6✔
6170
  }
6171

6172
  c = FCHECK_SAT; // default value
18✔
6173
  if (i > 0) {
18✔
6174
    c = FCHECK_CONTINUE;
15✔
6175
  }
6176

6177
  if (c == FCHECK_SAT) {
18✔
6178
    if (egraph->ctrl[ETYPE_QUANT] != NULL) {
3✔
6179
      // quant solver
6180
      c = egraph->ctrl[ETYPE_QUANT]->final_check(egraph->th[ETYPE_QUANT]);
×
6181
      if (c != FCHECK_SAT) {
×
6182
#if TRACE_FCHECK
6183
        printf("---> exit at quant final check\n");
6184
        fflush(stdout);
6185
#endif
6186
        return c;
×
6187
      }
6188
    }
6189
  }
6190

6191
  return c;
18✔
6192
}
6193

6194

6195
/*
6196
 * New: experimental version
6197
 */
6198
static fcheck_code_t experimental_final_check(egraph_t *egraph) {
17,616✔
6199
  fcheck_code_t c;
6200
  uint32_t i, max_eqs;
6201

6202
#if TRACE_FCHECK
6203
  printf("---> EGRAPH: final check (experimental)\n\n");
6204
  print_egraph_terms(stdout, egraph);
6205
  printf("\n\n");
6206
  print_egraph_root_classes_details(stdout, egraph);
6207
  fflush(stdout);
6208
#endif
6209

6210
  if (egraph->ctrl[ETYPE_REAL] != NULL) {
17,616✔
6211
    c = egraph->ctrl[ETYPE_REAL]->final_check(egraph->th[ETYPE_REAL]);
13,799✔
6212
    if (c != FCHECK_SAT) {
13,799✔
6213
#if TRACE_FCHECK
6214
      printf("---> exit at arith final check\n");
6215
      fflush(stdout);
6216
#endif
6217
      return c;
375✔
6218
    }
6219
  }
6220

6221
  if (egraph->ctrl[ETYPE_BV] != NULL) {
17,241✔
6222
    // bitvector solver
6223
    c = egraph->ctrl[ETYPE_BV]->final_check(egraph->th[ETYPE_BV]);
15,612✔
6224
    if (c != FCHECK_SAT) {
15,612✔
6225
#if TRACE_FCHECK
6226
      printf("---> exit at bv final check\n");
6227
      fflush(stdout);
6228
#endif
6229
      return c;
×
6230
    }
6231
  }
6232

6233
  if (egraph->ctrl[ETYPE_MCSAT] != NULL) {
17,241✔
6234
    c = egraph->ctrl[ETYPE_MCSAT]->final_check(egraph->th[ETYPE_MCSAT]);
4✔
6235
    if (c != FCHECK_SAT) {
4✔
6236
#if TRACE_FCHECK
6237
      printf("---> exit at supplementary mcsat final check\n");
6238
      fflush(stdout);
6239
#endif
NEW
6240
      return c;
×
6241
    }
6242
  }
6243

6244

6245
  /*
6246
   * Try egraph reconciliation
6247
   */
6248
  c = FCHECK_SAT;
17,241✔
6249
  egraph_prepare_models(egraph);
17,241✔
6250
  egraph_start_reconciliation(egraph);
17,241✔
6251

6252
  if (! egraph_reconcile(egraph)) {
17,241✔
6253
    egraph_reconciliation_restore(egraph);
2,167✔
6254

6255
    max_eqs = egraph->max_interface_eqs;
2,167✔
6256

6257
    // Generate interface equalities
6258
    i = egraph_gen_interface_lemmas(egraph, max_eqs, &egraph->interface_eqs);
2,167✔
6259

6260
    egraph->stats.interface_eqs += i;
2,167✔
6261
    ivector_reset(&egraph->interface_eqs);
2,167✔
6262
    c = FCHECK_CONTINUE;
2,167✔
6263

6264
    if (i == 1) {
2,167✔
6265
      trace_printf(egraph->core->trace, 3, "(final check: 1 interface lemma)\n");
1,832✔
6266
    } else {
6267
      trace_printf(egraph->core->trace, 3, "(final check: %"PRIu32" interface lemmas)\n", i);
335✔
6268
    }
6269

6270
#if TRACE_FCHECK
6271
    printf("---> egraph reconcile failed: %"PRIu32" interface lemmas\n", i);
6272
    fflush(stdout);
6273
#endif
6274

6275

6276
  } else if (egraph->ctrl[ETYPE_FUNCTION] != NULL) {
15,074✔
6277
#if TRACE_FCHECK
6278
    printf("---> EGRAPH: final check: after reconcile\n\n");
6279
    print_egraph_terms(stdout, egraph);
6280
    printf("\n\n");
6281
    print_egraph_root_classes_details(stdout, egraph);
6282
    fflush(stdout);
6283
#endif
6284
    /*
6285
     * bv/arith models are consistent with the egraph:
6286
     * deal with the array solver
6287
     */
6288
    c = egraph->ctrl[ETYPE_FUNCTION]->final_check(egraph->th[ETYPE_FUNCTION]);
13,935✔
6289
    if (c == FCHECK_SAT) {
13,935✔
6290
      if (egraph_is_high_order(egraph)) {
13,099✔
6291
        i = egraph->eg[ETYPE_FUNCTION]->reconcile_model(egraph->th[ETYPE_FUNCTION], 1);
372✔
6292
        if (i > 0) {
372✔
6293
#if TRACE_FCHECK
6294
          printf("---> exit after array reconcile: %"PRIu32" lemmas\n", i);
6295
          fflush(stdout);
6296
#endif
6297
          trace_printf(egraph->core->trace, 3, "(final check: %"PRIu32" array lemmas)\n", i);
322✔
6298
          c = FCHECK_CONTINUE;
322✔
6299
        }
6300
      }
6301
    } else {
6302
#if TRACE_FCHECK
6303
      printf("---> exit at array final check\n");
6304
      fflush(stdout);
6305
#endif
6306
    }
6307

6308
    if (c != FCHECK_SAT) {
13,935✔
6309
      egraph_reconciliation_restore(egraph);
1,158✔
6310
    }
6311
  }
6312

6313
  egraph_release_models(egraph);
17,241✔
6314

6315

6316
  if (c == FCHECK_SAT) {
17,241✔
6317
    if (egraph->ctrl[ETYPE_QUANT] != NULL) {
13,916✔
6318
      // quant solver
6319
      c = egraph->ctrl[ETYPE_QUANT]->final_check(egraph->th[ETYPE_QUANT]);
794✔
6320
      if (c != FCHECK_SAT) {
794✔
6321
#if TRACE_FCHECK
6322
        printf("---> exit at quant final check\n");
6323
        fflush(stdout);
6324
#endif
6325
        return c;
672✔
6326
      }
6327
    }
6328
  }
6329

6330
  return c;
16,569✔
6331
}
6332

6333

6334
/*
6335
 * Call final check for all the satellite solvers
6336
 * If all return SAT, try to build consistent models
6337
 * If models are not consistent, generate interface equalities
6338
 */
6339
fcheck_code_t _o_egraph_final_check(egraph_t *egraph) {
17,635✔
6340
  egraph->stats.final_checks ++;
17,635✔
6341

6342
  if (egraph_option_disabled(egraph, EGRAPH_OPTIMISTIC_FCHECK)) {
17,635✔
6343
    return baseline_final_check(egraph);
19✔
6344
  } else {
6345
    return experimental_final_check(egraph);
17,616✔
6346
  }
6347
}
6348

6349
fcheck_code_t egraph_final_check(egraph_t *egraph) {
17,635✔
6350
  MT_PROTECT(fcheck_code_t, __yices_globals.lock, _o_egraph_final_check(egraph));
17,635✔
6351
}
6352

6353

6354
/*
6355
 * Clear the edges added during reconciliation:
6356
 * - if egraph_final_check succeeds, then we may have added new equalities
6357
 *   in the egraph (during model reconciliation).
6358
 * - before any other operation on the egraph (e.g., assert, push, pop), we
6359
 *   must restore it to what it was at the start of final check
6360
 */
6361
void egraph_clear(egraph_t *egraph) {
12,926✔
6362
  uint32_t i;
6363

6364
  if (egraph->reconcile_mode) {
12,926✔
6365
    egraph_reconciliation_restore(egraph);
12,926✔
6366
  }
6367
  // forward to the satellite solvers
6368
  for (i=0; i<NUM_SATELLITES; i++) {
90,482✔
6369
    if (egraph->ctrl[i] != NULL) {
77,556✔
6370
      egraph->ctrl[i]->clear(egraph->th[i]);
37,869✔
6371
    }
6372
  }
6373
}
12,926✔
6374

6375

6376

6377
/****************
6378
 *  ASSERTIONS  *
6379
 ***************/
6380

6381
/*
6382
 * Assert (t == true) with explanation l
6383
 * - term_of_occ(t) must be a boolean term
6384
 */
6385
void egraph_assert_term(egraph_t *egraph, occ_t t, literal_t l) {
3,746,843✔
6386
  int32_t k;
6387

6388
#if TRACE
6389
  printf("---> EGRAPH: Asserting term ");
6390
  print_occurrence(stdout, t);
6391
  printf(", expl = ");
6392
  print_literal(stdout, l);
6393
  printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6394
  if (egraph_term_is_composite(egraph, term_of_occ(t))) {
6395
    printf("---> ");
6396
    print_eterm_def(stdout, egraph, term_of_occ(t));
6397
  }
6398
  if (egraph_occ_is_true(egraph, t)) {
6399
    printf("---> EGRAPH: Term ");
6400
    print_occurrence(stdout, t);
6401
    printf(" is already true\n");
6402
  }
6403
#endif
6404

6405
  // don't do anything if t is already true
6406
  if (! egraph_occ_is_true(egraph, t)) {
3,746,843✔
6407
    k = egraph_stack_push_eq(&egraph->stack, t, true_occ);
2,407,038✔
6408
    egraph->stack.etag[k] = EXPL_ASSERT;
2,407,038✔
6409
    egraph->stack.edata[k].lit = l;
2,407,038✔
6410
  }
6411
}
3,746,843✔
6412

6413
/*
6414
 * Assert (t1 == t2) with explanation l
6415
 */
6416
void egraph_assert_eq(egraph_t *egraph, occ_t t1, occ_t t2, literal_t l) {
×
6417
  int32_t k;
6418

6419
#if TRACE
6420
  printf("---> EGRAPH: Asserting ");
6421
  print_occurrence(stdout, t1);
6422
  printf(" == ");
6423
  print_occurrence(stdout, t2);
6424
  printf(" , expl = ");
6425
  print_literal(stdout, l);
6426
  printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6427
  if (egraph_equal_occ(egraph, t1, t2)) {
6428
    printf("---> EGRAPH: ");
6429
    print_occurrence(stdout, t1);
6430
    printf(" and ");
6431
    print_occurrence(stdout, t2);
6432
    printf(" are already equal\n");
6433
  }
6434
#endif
6435

6436
  // don't do anything if t1 and t2 are already equal
6437
  if (! egraph_equal_occ(egraph, t1, t2)) {
×
6438
    k = egraph_stack_push_eq(&egraph->stack, t1, t2);
×
6439
    egraph->stack.etag[k] = EXPL_ASSERT;
×
6440
    egraph->stack.edata[k].lit = l;
×
6441
  }
6442
}
×
6443

6444

6445

6446
/*
6447
 * Assert atom atm with explanation l (propagation from the core)
6448
 * - if l has positive polarity then atom is asserted true
6449
 *   if l has negative polarity then atom is asserted false
6450
 * - forward to arithmetic or bitvector solver if required
6451
 * - return false if there's a conflict, true otherwise
6452
 */
6453
bool egraph_assert_atom(egraph_t *egraph, void *atom, literal_t l) {
5,303,299✔
6454
  atom_t *a;
6455
  occ_t t;
6456
  bool resu;
6457

6458
  resu = true;
5,303,299✔
6459

6460
  switch (atom_tag(atom)) {
5,303,299✔
6461
  case EGRAPH_ATM_TAG:
3,746,843✔
6462
    a = (atom_t *) untag_atom(atom);
3,746,843✔
6463
    assert(a->boolvar == var_of(l));
6464
    t = mk_occ(a->eterm, sign_of(l));
3,746,843✔
6465
    egraph_assert_term(egraph, t, l);
3,746,843✔
6466
    break;
3,746,843✔
6467

6468
  case ARITH_ATM_TAG:
305,962✔
6469
    resu = egraph->arith_smt->assert_atom(egraph->th[ETYPE_INT], untag_atom(atom), l);
305,962✔
6470
    break;
305,962✔
6471

6472
  case BV_ATM_TAG:
1,250,477✔
6473
    resu = egraph->bv_smt->assert_atom(egraph->th[ETYPE_BV], untag_atom(atom), l);
1,250,477✔
6474
    break;
1,250,477✔
6475

6476
  case MCSAT_ATM_TAG:
17✔
6477
    assert(egraph->mcsat_smt != NULL);
6478
    resu = egraph->mcsat_smt->assert_atom(egraph->th[ETYPE_MCSAT], untag_atom(atom), l);
17✔
6479
    break;
17✔
6480
  }
6481

6482
  return resu;
5,303,299✔
6483
}
6484

6485

6486
/*
6487
 * Assert (t == true) as an axiom
6488
 * - axiom assertion is allowed at the base level only
6489
 */
6490
void egraph_assert_axiom(egraph_t *egraph, occ_t t) {
×
6491
  int32_t k;
6492

6493
#if TRACE
6494
  printf("---> EGRAPH: Asserting axiom ");
6495
  print_occurrence(stdout, t);
6496
  printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6497
  if (egraph_term_is_composite(egraph, term_of_occ(t))) {
6498
    printf("---> ");
6499
    print_eterm_def(stdout, egraph, term_of_occ(t));
6500
  }
6501
#endif
6502

6503
  assert(egraph->decision_level == egraph->base_level);
6504
  k = egraph_stack_push_eq(&egraph->stack, true_occ, t);
×
6505
  egraph->stack.etag[k] = EXPL_AXIOM;
×
6506
}
×
6507

6508

6509
/*
6510
 * Assert (t1 == t2) as an axiom
6511
 */
6512
void egraph_assert_eq_axiom(egraph_t *egraph, occ_t t1, occ_t t2) {
12,947✔
6513
  int32_t k;
6514

6515
#if TRACE
6516
  printf("---> EGRAPH: Asserting axiom ");
6517
  print_occurrence(stdout, t1);
6518
  printf(" == ");
6519
  print_occurrence(stdout, t2);
6520
  printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6521
#endif
6522

6523
  assert(egraph->decision_level == egraph->base_level);
6524
  k = egraph_stack_push_eq(&egraph->stack, t1, t2);
12,947✔
6525
  egraph->stack.etag[k] = EXPL_AXIOM;
12,947✔
6526
}
12,947✔
6527

6528

6529
/*
6530
 * Assert (t1 != t2) as an axiom
6531
 * - create equality atom l --> (eq t1 t2) then assert not(l)
6532
 *   in the core
6533
 */
6534
void egraph_assert_diseq_axiom(egraph_t *egraph, occ_t t1, occ_t t2) {
2,573✔
6535
#if CONSERVATIVE_DISEQ_AXIOMS
6536
  literal_t l;
6537
#else
6538
  occ_t eq;
6539
  int32_t k;
6540
#endif
6541

6542

6543
#if TRACE
6544
  printf("---> EGRAPH: Asserting axiom ");
6545
  print_occurrence(stdout, t1);
6546
  printf(" != ");
6547
  print_occurrence(stdout, t2);
6548
  printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6549
#endif
6550

6551
  assert(egraph->decision_level == egraph->base_level);
6552
#if CONSERVATIVE_DISEQ_AXIOMS
6553
  // conservative approach
6554
  l = egraph_make_eq(egraph, t1, t2);
6555
  add_unit_clause(egraph->core, not(l));
6556
#else
6557
  // avoid creation of an atom: eq has no theory variable attached
6558
  eq = egraph_make_eq_term(egraph, t1, t2);
2,573✔
6559
  k = egraph_stack_push_eq(&egraph->stack, eq, false_occ);
2,573✔
6560
  egraph->stack.etag[k] = EXPL_AXIOM;
2,573✔
6561
#endif
6562
}
2,573✔
6563

6564

6565
/*
6566
 * Assert (distinct t1 ... tn) as an axiom
6567
 */
6568
void egraph_assert_distinct_axiom(egraph_t *egraph, uint32_t n, occ_t *t) {
10✔
6569
  eterm_t d;
6570
  int32_t k;
6571
  uint32_t i, j;
6572

6573
  assert(egraph->decision_level == egraph->base_level);
6574
  d = egraph_distinct_term(egraph, n, t);
10✔
6575
  if (d != null_eterm) {
10✔
6576
    if (egraph_term_is_fresh(egraph, d)) {
10✔
6577
      egraph_set_term_real_type(egraph, d, bool_type(egraph->types));
10✔
6578
      egraph_activate_term(egraph, d, ETYPE_BOOL, const_bvar);
10✔
6579
    }
6580
#if TRACE
6581
    printf("---> EGRAPH: Asserting axiom ");
6582
    print_composite(stdout, egraph->terms.body[d]);
6583
    printf(", decision level = %"PRIu32"\n", egraph->decision_level);
6584
#endif
6585
    k = egraph_stack_push_eq(&egraph->stack, pos_occ(d), true_occ);
10✔
6586
    egraph->stack.etag[k] = EXPL_AXIOM;
10✔
6587

6588
  } else {
6589
    /*
6590
     * Too many distinct terms. Expand into n*(n-1)/2 disequalities
6591
     */
6592
    for (i=0; i<n-1; i++) {
×
6593
      for (j=i+1; j<n; j++) {
×
6594
        egraph_assert_diseq_axiom(egraph, t[i], t[j]);
×
6595
      }
6596
    }
6597
  }
6598
}
10✔
6599

6600

6601
/*
6602
 * Assert not (distinct t_1 ... t_n) as an axiom:
6603
 * this adds the clause "(eq t_1 t_2) or .... or (eq t_n-1 t_n)" to the core
6604
 */
6605
void egraph_assert_notdistinct_axiom(egraph_t *egraph, uint32_t n, occ_t *t) {
4✔
6606
  ivector_t *v;
6607

6608
  assert(egraph->decision_level == egraph->base_level);
6609
  v = &egraph->aux_buffer;
4✔
6610
  expand_distinct(egraph, n, t, v);
4✔
6611
  add_clause(egraph->core, v->size, v->data);
4✔
6612
}
4✔
6613

6614

6615
/*
6616
 * Assert (f a_1 ... a_n) as an axiom
6617
 * - build term t := (f a_1 ... a_n) and add const_bvar as its theory variable
6618
 * - push equality (t == true)
6619
 */
6620
void egraph_assert_pred_axiom(egraph_t *egraph, occ_t f, uint32_t n, occ_t *a) {
214✔
6621
  eterm_t t;
6622
  int32_t k;
6623

6624
  t = egraph_apply_term(egraph, f, n, a);
214✔
6625
  if (egraph_term_is_fresh(egraph, t)) {
214✔
6626
    /*
6627
     * HACK: we attach bool_const as theory variable of t
6628
     * but we attach no theory variable to the class of t
6629
     * (thvar[t] is used by the ackermann lemma function)
6630
     */
6631
    egraph_set_term_real_type(egraph, t, bool_type(egraph->types));
213✔
6632
    egraph_activate_term(egraph, t, ETYPE_BOOL, null_thvar);
213✔
6633
    egraph->terms.thvar[t] = const_bvar;
213✔
6634

6635
  } else if (egraph->terms.thvar[t] == null_thvar) {
1✔
6636
    egraph->terms.thvar[t] = const_bvar;
×
6637
  }
6638

6639
  k = egraph_stack_push_eq(&egraph->stack, true_occ, pos_occ(t));
214✔
6640
  egraph->stack.etag[k] = EXPL_AXIOM;
214✔
6641
}
214✔
6642

6643

6644
/*
6645
 * Assert not (f t_1 ... t_n) as an axiom:
6646
 * build literal l = (f t_1 ... t_n) then assert not l in the core
6647
 */
6648
void egraph_assert_notpred_axiom(egraph_t *egraph, occ_t f, uint32_t n, occ_t *t) {
28✔
6649
  literal_t l;
6650

6651
  l = egraph_make_pred(egraph, f, n, t);
28✔
6652
  add_unit_clause(egraph->core, not(l));
28✔
6653
}
28✔
6654

6655

6656

6657

6658
/******************************************
6659
 *  EQUALITY PROPAGATION FROM SATELLITES  *
6660
 *****************************************/
6661

6662
/*
6663
 * Propagation from a satellite solver
6664
 * - add the equality (t1 == t2) to the propagation queue with explanation expl
6665
 * - id = code to identify the satellite solver
6666
 *   valid codes are EXPL_ARITH_PROPAGATION, EXPL_BV_PROPAGATION, EXPL_FUN_PROPAGATION
6667
 * - expl = whatever the solver needs to explain the equality
6668
 */
6669
void egraph_propagate_equality(egraph_t *egraph, eterm_t t1, eterm_t t2, expl_tag_t id, void *expl) {
128,703✔
6670
  int32_t k;
6671

6672
  assert((id == EXPL_ARITH_PROPAGATION && egraph_term_is_arith(egraph, t1) &&
6673
          egraph_term_is_arith(egraph, t2)) ||
6674
         (id == EXPL_BV_PROPAGATION && egraph_term_is_bv(egraph, t1) && egraph_term_is_bv(egraph, t2)) ||
6675
         (id == EXPL_FUN_PROPAGATION && egraph_term_is_function(egraph, t1) &&
6676
          egraph_term_is_function(egraph, t2)));
6677

6678
  if (egraph_equal_occ(egraph, pos_occ(t1), pos_occ(t2))) {
128,703✔
6679
#if 0
6680
    printf("---> EGRAPH: redundant eq prop: g!%"PRId32" == g!%"PRId32"\n", t1, t2);
6681
#endif
6682
    // redundant
6683
    return;
111,890✔
6684
  }
6685

6686
#if 0
6687
  printf("---> EGRAPH: good eq prop: g!%"PRId32" == g!%"PRId32"\n", t1, t2);
6688
#endif
6689
  egraph->stats.eq_props ++;
16,813✔
6690

6691
  k = egraph_stack_push_eq(&egraph->stack, pos_occ(t1), pos_occ(t2));
16,813✔
6692
  egraph->stack.etag[k] = id;
16,813✔
6693
  egraph->stack.edata[k].ptr = expl;
16,813✔
6694
}
6695

6696

6697

6698
/************************
6699
 *  THEORY EXPLANATION  *
6700
 ***********************/
6701

6702
/*
6703
 * Expand a theory implication:
6704
 * - a theory solver called propagate_literal(core, l, expl)
6705
 * - the core needs to convert expl to a conjunction of literals
6706
 */
6707
void egraph_expand_explanation(egraph_t *egraph, literal_t l, void *expl, ivector_t *v) {
43,290✔
6708
  void *atom;
6709
  atom_t *a;
6710
  occ_t u;
6711
  int32_t id;
6712

6713
  assert(v->size == 0);
6714

6715
  atom = get_bvar_atom(egraph->core, var_of(l));
43,290✔
6716
  switch (atom_tag(atom)) {
43,290✔
6717
  case EGRAPH_ATM_TAG:
41,074✔
6718
    a = (atom_t *) atom;
41,074✔
6719
    assert(a->boolvar == var_of(l));
6720
    assert(literal_is_assigned(egraph->core, l) &&
6721
           bvar_value(egraph->core, var_of(l)) == egraph_term_truth_value(egraph, a->eterm));
6722
    id = i32_of_expl(expl);    // id := edge that triggered the propagation
41,074✔
6723
    u = mk_occ(a->eterm, sign_of(l));
41,074✔
6724
#if 0
6725
    printf("---> EGRAPH: expand explanation for ");
6726
    print_literal(stdout, l);
6727
    printf(" (trigger edge = %"PRId32")\n", id);
6728
#endif
6729
    /*
6730
     * Build the explanation for u == true
6731
     */
6732
    egraph_explain_equality(egraph, u, true_occ, id, v);
41,074✔
6733
    break;
41,074✔
6734

6735
  case ARITH_ATM_TAG:
2,216✔
6736
    egraph->arith_smt->expand_explanation(egraph->th[ETYPE_INT], l, expl, v);
2,216✔
6737
    break;
2,216✔
6738

6739
  case BV_ATM_TAG:
×
6740
    egraph->bv_smt->expand_explanation(egraph->th[ETYPE_BV], l, expl, v);
×
6741
    break;
×
6742

NEW
6743
  case MCSAT_ATM_TAG:
×
6744
    assert(egraph->mcsat_smt != NULL);
NEW
6745
    egraph->mcsat_smt->expand_explanation(egraph->th[ETYPE_MCSAT], l, expl, v);
×
NEW
6746
    break;
×
6747
  }
6748
}
43,290✔
6749

6750

6751

6752

6753
/*************************
6754
 *  SPLITTING HEURISTIC  *
6755
 ************************/
6756

6757
/*
6758
 * For an equality atom c = (eq t1 t2) and l attached to that atom
6759
 * select whether to branch on l or (not l)
6760
 * - if t1 and t2 are attached to theory variables, the decision is
6761
 *   made by the satellite solver
6762
 * - otherwise, return l
6763
 */
6764
static literal_t egraph_select_eq_polarity(egraph_t *egraph, composite_t *c, literal_t l) {
333✔
6765
  occ_t t1, t2;
6766
  class_t c1, c2;
6767
  thvar_t v1, v2;
6768
  etype_t i;
6769

6770
  assert(composite_kind(c) == COMPOSITE_EQ);
6771

6772
  t1 = c->child[0];
333✔
6773
  t2 = c->child[1];
333✔
6774
  i = egraph_type(egraph, t1);
333✔
6775
  if (i < NUM_SATELLITES) {
333✔
6776
    c1 = egraph_class(egraph, t1);
333✔
6777
    v1 = egraph->classes.thvar[c1];
333✔
6778
    c2 = egraph_class(egraph, t2);
333✔
6779
    v2 = egraph->classes.thvar[c2];
333✔
6780
    if (v1 != null_thvar && v2 != null_thvar) {
333✔
6781
      assert(egraph->eg[i] != NULL);
6782
      return egraph->eg[i]->select_eq_polarity(egraph->th[i], v1, v2, pos_lit(var_of(l)));
333✔
6783
    }
6784
  }
6785

6786
  return l;
×
6787
}
6788

6789

6790
/*
6791
 * Select whether to branch on l or (not l)
6792
 * - atom = the atom attached to var_of(l)
6793
 * - forward to the appropriate subsolver
6794
 */
6795
static literal_t egraph_select_polarity(egraph_t *egraph, void *atom, literal_t l) {
742✔
6796
  atom_t *a;
6797
  composite_t *c;
6798

6799
  switch (atom_tag(atom)) {
742✔
6800
  case ARITH_ATM_TAG:
409✔
6801
    return egraph->arith_smt->select_polarity(egraph->th[ETYPE_INT], untag_atom(atom), l);
409✔
6802

6803
  case BV_ATM_TAG:
×
6804
    return egraph->bv_smt->select_polarity(egraph->th[ETYPE_BV], untag_atom(atom), l);
×
6805

NEW
6806
  case MCSAT_ATM_TAG:
×
6807
    assert(egraph->mcsat_smt != NULL);
NEW
6808
    return egraph->mcsat_smt->select_polarity(egraph->th[ETYPE_MCSAT], untag_atom(atom), l);
×
6809

6810
  case EGRAPH_ATM_TAG:
333✔
6811
  default:
6812
    // FOR EQUALITY ATOMS: defer to the satellite solver if any
6813
    a = (atom_t *) untag_atom(atom);
333✔
6814
    assert(a->boolvar == var_of(l));
6815
    c = egraph_term_body(egraph, a->eterm);
333✔
6816
    if (composite_body(c) && composite_kind(c) == COMPOSITE_EQ) {
333✔
6817
      l = egraph_select_eq_polarity(egraph, c, l);
333✔
6818
    }
6819
    return l;
333✔
6820
  }
6821
}
6822

6823

6824

6825

6826

6827

6828

6829
/***********************
6830
 *  CONTROL INTERFACE  *
6831
 **********************/
6832

6833
static th_ctrl_interface_t egraph_control = {
6834
  (start_intern_fun_t) egraph_start_internalization,
6835
  (start_fun_t) egraph_start_search,
6836
  (propagate_fun_t) egraph_propagate,
6837
  (final_check_fun_t) egraph_final_check,
6838
  (increase_level_fun_t) egraph_increase_decision_level,
6839
  (backtrack_fun_t) egraph_backtrack,
6840
  (push_fun_t) egraph_push,
6841
  (pop_fun_t) egraph_pop,
6842
  (reset_fun_t) egraph_reset,
6843
  (clear_fun_t) egraph_clear,
6844
};
6845

6846

6847

6848
/*******************
6849
 *  SMT INTERFACE  *
6850
 ******************/
6851

6852
static th_smt_interface_t egraph_smt = {
6853
  (assert_fun_t) egraph_assert_atom,
6854
  (expand_expl_fun_t) egraph_expand_explanation,
6855
  (select_pol_fun_t) egraph_select_polarity,
6856
  NULL,
6857
  NULL,
6858
};
6859

6860

6861

6862

6863
/*************************
6864
 *  EGRAPH CONSTRUCTION  *
6865
 ************************/
6866

6867
/*
6868
 * Initialize all internal structures
6869
 * - ttbl = attached type table
6870
 * - use default initial sizes
6871
 * - subsolver descriptors are all NULL and core is also NULL
6872
 * - set all options and parameters to their default values
6873
 */
6874
void init_egraph(egraph_t *egraph, type_table_t *ttbl) {
4,792✔
6875
  uint32_t i;
6876

6877
  egraph->core = NULL;
4,792✔
6878
  egraph->types = ttbl;
4,792✔
6879

6880
  egraph->base_level = 0;
4,792✔
6881
  egraph->decision_level = 0;
4,792✔
6882
  egraph->presearch = false;
4,792✔
6883
  egraph->ndistincts = 0;
4,792✔
6884
  egraph->natoms = 0;
4,792✔
6885
  egraph->is_high_order = false;
4,792✔
6886

6887
  init_egraph_stats(&egraph->stats);
4,792✔
6888

6889
  egraph->options = EGRAPH_DEFAULT_OPTIONS;
4,792✔
6890
  egraph->max_ackermann = DEFAULT_MAX_ACKERMANN;
4,792✔
6891
  egraph->max_boolackermann = DEFAULT_MAX_BOOLACKERMANN;
4,792✔
6892
  egraph->aux_eq_quota = DEFAULT_AUX_EQ_QUOTA;
4,792✔
6893
  egraph->ackermann_threshold = DEFAULT_ACKERMANN_THRESHOLD;
4,792✔
6894
  egraph->boolack_threshold = DEFAULT_BOOLACK_THRESHOLD;
4,792✔
6895
  egraph->max_interface_eqs = DEFAULT_MAX_INTERFACE_EQS;
4,792✔
6896
  egraph->ack_left = null_occurrence;
4,792✔
6897
  egraph->ack_right = null_occurrence;
4,792✔
6898

6899
  init_class_table(&egraph->classes, DEFAULT_CLASS_TABLE_SIZE);
4,792✔
6900
  init_eterm_table(&egraph->terms, DEFAULT_ETERM_TABLE_SIZE);
4,792✔
6901
  init_egraph_stack(&egraph->stack, DEFAULT_EGRAPH_STACK_SIZE, DEFAULT_EGRAPH_NLEVELS);
4,792✔
6902
  init_undo_stack(&egraph->undo, DEFAULT_EGRAPH_STACK_SIZE, DEFAULT_EGRAPH_NLEVELS);
4,792✔
6903
  init_distinct_table(&egraph->dtable);
4,792✔
6904
  init_congruence_table(&egraph->ctable, 0);
4,792✔
6905
  init_ltag_table(&egraph->tag_table);
4,792✔
6906

6907
  egraph->update_graph = NULL;
4,792✔
6908

6909
  init_egraph_trail(&egraph->trail_stack);
4,792✔
6910

6911

6912
  // auxiliary buffers and data structures
6913
  egraph->const_htbl = NULL;
4,792✔
6914
  init_int_htbl(&egraph->htbl, 0);
4,792✔
6915
  init_objstore(&egraph->atom_store, sizeof(atom_t), ATOM_BANK_SIZE);
4,792✔
6916
  init_cache(&egraph->cache);
4,792✔
6917

6918
  egraph->imap = NULL;
4,792✔
6919
  init_sign_buffer(&egraph->sgn);
4,792✔
6920
  init_arena(&egraph->arena);
4,792✔
6921
  init_ivector(&egraph->expl_queue, DEFAULT_EXPL_VECTOR_SIZE);
4,792✔
6922
  init_ivector(&egraph->expl_vector, DEFAULT_EXPL_VECTOR_SIZE);
4,792✔
6923
  init_pvector(&egraph->cmp_vector, DEFAULT_CMP_VECTOR_SIZE);
4,792✔
6924
  init_ivector(&egraph->aux_buffer, 0);
4,792✔
6925
  init_istack(&egraph->istack);
4,792✔
6926

6927
  egraph->short_cuts = true;
4,792✔
6928
  egraph->top_id = 0;
4,792✔
6929

6930
  init_ivector(&egraph->interface_eqs, 40);
4,792✔
6931
  egraph->reconcile_top = 0;
4,792✔
6932
  egraph->reconcile_neqs = 0;
4,792✔
6933
  egraph->reconcile_mode = false;
4,792✔
6934

6935
  init_pvector(&egraph->reanalyze_vector, 0);
4,792✔
6936
  init_th_explanation(&egraph->th_expl);
4,792✔
6937
  egraph->app_partition = NULL;
4,792✔
6938

6939
  // satellite solvers and descriptors
6940
  for (i=0; i<NUM_SATELLITES; i++) {
33,544✔
6941
    egraph->th[i] = NULL;
28,752✔
6942
    egraph->ctrl[i] = NULL;
28,752✔
6943
    egraph->eg[i] = NULL;
28,752✔
6944
  }
6945
  egraph->arith_smt = NULL;
4,792✔
6946
  egraph->bv_smt = NULL;
4,792✔
6947
  egraph->mcsat_smt = NULL;
4,792✔
6948
  egraph->arith_eg = NULL;
4,792✔
6949
  egraph->bv_eg = NULL;
4,792✔
6950
  egraph->fun_eg = NULL;
4,792✔
6951
  egraph->quant_eg = NULL;
4,792✔
6952

6953
  // model-construction object
6954
  init_egraph_model(&egraph->mdl);
4,792✔
6955
}
4,792✔
6956

6957

6958

6959

6960
/*
6961
 * Attach an arithmetic solver: it's used for both INT and REAL
6962
 * - the control interface is attached only to type REAL
6963
 *   so that push/pop/reset/start_search are not called twice
6964
 */
6965
void egraph_attach_arithsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
4,335✔
6966
                               th_smt_interface_t *smt, th_egraph_interface_t *eg,
6967
                               arith_egraph_interface_t *arith_eg) {
6968

6969
  assert(egraph->core == NULL && egraph->arith_smt == NULL);
6970

6971
  egraph->th[ETYPE_INT] = solver;
4,335✔
6972
  egraph->th[ETYPE_REAL] = solver;
4,335✔
6973
  egraph->ctrl[ETYPE_INT] = NULL;
4,335✔
6974
  egraph->ctrl[ETYPE_REAL] = ctrl;
4,335✔
6975
  egraph->eg[ETYPE_INT] = eg;
4,335✔
6976
  egraph->eg[ETYPE_REAL] = eg;
4,335✔
6977
  egraph->arith_smt = smt;
4,335✔
6978
  egraph->arith_eg = arith_eg;
4,335✔
6979
}
4,335✔
6980

6981

6982
/*
6983
 * Attach a bitvector solver
6984
 */
6985
void egraph_attach_bvsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
4,418✔
6986
                            th_smt_interface_t *smt, th_egraph_interface_t *eg,
6987
                            bv_egraph_interface_t *bv_eg) {
6988

6989
  assert(egraph->core == NULL && egraph->bv_smt == NULL);
6990

6991
  egraph->th[ETYPE_BV] = solver;
4,418✔
6992
  egraph->ctrl[ETYPE_BV] = ctrl;
4,418✔
6993
  egraph->eg[ETYPE_BV] = eg;
4,418✔
6994
  egraph->bv_smt = smt;
4,418✔
6995
  egraph->bv_eg = bv_eg;
4,418✔
6996
}
4,418✔
6997

6998

6999
/*
7000
 * Attach supplementary mcsat solver
7001
 */
7002
void egraph_attach_mcsat_solver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
10✔
7003
                                th_smt_interface_t *smt, th_egraph_interface_t *eg) {
7004
  etype_t id;
7005

7006
  assert(egraph->ctrl[ETYPE_MCSAT] == NULL && egraph->mcsat_smt == NULL);
7007

7008
  id = ETYPE_MCSAT;
10✔
7009
  egraph->th[id] = solver;
10✔
7010
  egraph->ctrl[id] = ctrl;
10✔
7011
  egraph->eg[id] = eg;
10✔
7012
  egraph->mcsat_smt = smt;
10✔
7013
}
10✔
7014

7015
/*
7016
 * Detach supplementary mcsat solver
7017
 */
7018
void egraph_detach_mcsat_solver(egraph_t *egraph) {
10✔
7019
  etype_t id;
7020

7021
  id = ETYPE_MCSAT;
10✔
7022
  egraph->th[id] = NULL;
10✔
7023
  egraph->ctrl[id] = NULL;
10✔
7024
  egraph->eg[id] = NULL;
10✔
7025
  egraph->mcsat_smt = NULL;
10✔
7026
}
10✔
7027

7028

7029
/*
7030
 * Attach a function subsolver
7031
 * - solver = pointer to the subsolver object
7032
 * - ctrl, eg, fun_eg  = interface descriptors
7033
 */
7034
void egraph_attach_funsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
4,425✔
7035
                             th_egraph_interface_t *eg, fun_egraph_interface_t *fun_eg) {
7036
  etype_t id;
7037

7038
  assert(egraph->core == NULL && egraph->ctrl[ETYPE_FUNCTION] == NULL);
7039

7040
  id = ETYPE_FUNCTION;
4,425✔
7041
  egraph->th[id] = solver;
4,425✔
7042
  egraph->ctrl[id] = ctrl;
4,425✔
7043
  egraph->eg[id] = eg;
4,425✔
7044
  egraph->fun_eg = fun_eg;
4,425✔
7045
}
4,425✔
7046

7047

7048
/*
7049
 * Attach a quant subsolver
7050
 * - solver = pointer to the subsolver object
7051
 * - ctrl, eg, quant_eg  = interface descriptors
7052
 */
7053
void egraph_attach_quantsolver(egraph_t *egraph, void *solver, th_ctrl_interface_t *ctrl,
52✔
7054
                             th_egraph_interface_t *eg, quant_egraph_interface_t *quant_eg) {
7055
  etype_t id;
7056

7057
//  assert(egraph->core == NULL && egraph->ctrl[ETYPE_QUANT] == NULL);
7058
  assert(egraph->ctrl[ETYPE_QUANT] == NULL);
7059

7060
  id = ETYPE_QUANT;
52✔
7061
  egraph->th[id] = solver;
52✔
7062
  egraph->ctrl[id] = ctrl;
52✔
7063
  egraph->eg[id] = eg;
52✔
7064
  egraph->quant_eg = quant_eg;
52✔
7065
}
52✔
7066

7067
/*
7068
 * Get the egraph control and smt interfaces:
7069
 */
7070
th_ctrl_interface_t *egraph_ctrl_interface(egraph_t *egraph) {
4,792✔
7071
  return &egraph_control;
4,792✔
7072
}
7073

7074
th_smt_interface_t *egraph_smt_interface(egraph_t *egraph) {
4,792✔
7075
  return &egraph_smt;
4,792✔
7076
}
7077

7078

7079
/*
7080
 * Attach the core to the egraph
7081
 * - the core must be initialized with the egraph_control and egraph_smt_interface
7082
 */
7083
void egraph_attach_core(egraph_t *egraph, smt_core_t *core) {
4,792✔
7084
  assert(core != NULL && core->th_solver == egraph);
7085

7086
  egraph->core = core;
4,792✔
7087
  egraph_init_constant(egraph);
4,792✔
7088
}
4,792✔
7089

7090

7091
/*
7092
 * Delete everything
7093
 */
7094
void delete_egraph(egraph_t *egraph) {
4,791✔
7095
  delete_egraph_model(&egraph->mdl);
4,791✔
7096
  if (egraph->app_partition != NULL) {
4,791✔
7097
    delete_ptr_partition(egraph->app_partition);
94✔
7098
    safe_free(egraph->app_partition);
94✔
7099
    egraph->app_partition = NULL;
94✔
7100
  }
7101
  delete_th_explanation(&egraph->th_expl);
4,791✔
7102
  delete_pvector(&egraph->reanalyze_vector);
4,791✔
7103
  delete_ivector(&egraph->interface_eqs);
4,791✔
7104
  delete_istack(&egraph->istack);
4,791✔
7105
  delete_ivector(&egraph->aux_buffer);
4,791✔
7106
  delete_pvector(&egraph->cmp_vector);
4,791✔
7107
  delete_ivector(&egraph->expl_vector);
4,791✔
7108
  delete_ivector(&egraph->expl_queue);
4,791✔
7109
  delete_arena(&egraph->arena);
4,791✔
7110
  delete_sign_buffer(&egraph->sgn);
4,791✔
7111
  if (egraph->imap != NULL) {
4,791✔
7112
    delete_int_hmap(egraph->imap);
14✔
7113
    safe_free(egraph->imap);
14✔
7114
    egraph->imap = NULL;
14✔
7115
  }
7116
  delete_cache(&egraph->cache);
4,791✔
7117
  delete_objstore(&egraph->atom_store);
4,791✔
7118
  delete_int_htbl(&egraph->htbl);
4,791✔
7119
  egraph_free_const_htbl(egraph);
4,791✔
7120
  delete_egraph_trail(&egraph->trail_stack);
4,791✔
7121
  delete_ltag_table(&egraph->tag_table);
4,791✔
7122
  delete_congruence_table(&egraph->ctable);
4,791✔
7123
  delete_undo_stack(&egraph->undo);
4,791✔
7124
  delete_egraph_stack(&egraph->stack);
4,791✔
7125
  delete_eterm_table(&egraph->terms);
4,791✔
7126
  delete_class_table(&egraph->classes);
4,791✔
7127
}
4,791✔
7128

7129

7130

7131

7132
/*************************************
7133
 *  SUPPORT FOR ARRAY-THEORY SOLVER  *
7134
 ************************************/
7135

7136
// TODO: MIGRATE ALL THIS TO THE UPDATE-GRAPH MODULE
7137

7138
/*
7139
 * Get the lambda tag for function type tau
7140
 * - tau must be a function type
7141
 */
7142
int32_t egraph_get_lambda_tag(egraph_t *egraph, type_t tau) {
×
7143
  return lambda_tag_for_type(&egraph->tag_table, egraph->types, tau);
×
7144
}
7145

7146

7147
/*
7148
 * Collect all composite terms of the form (apply g ....)
7149
 * where g is in the same class as f
7150
 * - only the congruence roots are collected
7151
 * - they are added to the pointer vector *v
7152
 */
7153
void egraph_collect_applications(egraph_t *egraph, eterm_t f, pvector_t *v) {
38,779✔
7154
  use_vector_t *u;
7155
  composite_t *p;
7156
  class_t c;
7157
  occ_t g;
7158
  uint32_t i, n;
7159

7160
  c = egraph_term_class(egraph, f);
38,779✔
7161
  u = egraph_class_parents(egraph, c);
38,779✔
7162
  n = u->last;
38,779✔
7163
  for (i=0; i<n; i++) {
198,394✔
7164
    p = u->data[i];
159,615✔
7165
    if (valid_entry(p) && composite_kind(p) == COMPOSITE_APPLY) {
159,615✔
7166
      g = composite_child(p, 0); // function term of p
68,867✔
7167
      if (egraph_class(egraph, g) == c) {
68,867✔
7168
        pvector_push(v, p);
66,022✔
7169
      }
7170
    }
7171
  }
7172
}
38,779✔
7173

7174

7175
/*
7176
 * Return a term congruent to (apply g i_1 ... i_n) or NULL_COMPOSITE if there isn't one
7177
 * - c = composite of the form (apply f i_1 ... i_n)
7178
 */
7179
composite_t *egraph_find_modified_application(egraph_t *egraph, eterm_t g, composite_t *c) {
8,664,873✔
7180
  signature_t *sgn;
7181
  elabel_t *label;
7182

7183
  assert(composite_kind(c) == COMPOSITE_APPLY);
7184

7185
  label = egraph->terms.label;
8,664,873✔
7186
  sgn = &egraph->sgn;
8,664,873✔
7187
  signature_modified_apply(c, g, label, sgn);
8,664,873✔
7188
  return congruence_table_find(&egraph->ctable, sgn, label);
8,664,873✔
7189
}
7190

7191

7192
#if 0
7193

7194
// NOT USED
7195
/*
7196
 * Return a randomly chosen class label of type tau
7197
 * - if there's no term of type tau, return null_label
7198
 */
7199
elabel_t egraph_get_label_for_type(egraph_t *egraph, type_t tau) {
7200
  uint32_t n, k;
7201
  eterm_t t, u;
7202

7203

7204
  if (is_boolean_type(tau)) {
7205
    // select true or false randomly
7206
    k = random_uint32();
7207
    if (k & 0x400) {
7208
      return true_label;
7209
    } else {
7210
      return false_label;
7211
    }
7212

7213
  } else {
7214

7215
    n = egraph_num_terms(egraph);
7216
    u = null_eterm;
7217
    k = 0;
7218
    for (t=0; t<n; t++) {
7219
      if (egraph_term_real_type(egraph, t) == tau) {
7220
        k ++;
7221
        if (random_uint(k) == 0) {
7222
          u = t;
7223
        }
7224
      }
7225
    }
7226
    if (u == null_eterm) {
7227
      return null_label;
7228
    } else {
7229
      return egraph_term_label(egraph, u);
7230
    }
7231
  }
7232
}
7233

7234
#endif
7235

7236

7237
/*
7238
 * Fill in array a with at most n distinct class labels of type tau.
7239
 * If there are fewer than n classes of type tau, then the array is
7240
 * partially filled (in a[0 ... k-1])
7241
 * - return the number of labels k actually stored in a (k <= n)
7242
 */
7243
uint32_t egraph_get_labels_for_type(egraph_t *egraph, type_t tau, elabel_t *a, uint32_t n) {
581✔
7244
  uint32_t k, p;
7245
  class_t c;
7246
  eterm_t t;
7247

7248
  assert(n > 0);
7249

7250
  if (is_boolean_type(tau)) {
581✔
7251
    if (n == 1) {
157✔
7252
      a[0] = true_label;
54✔
7253
      return 1;
54✔
7254
    } else {
7255
      a[0] = true_label;
103✔
7256
      a[1] = false_label;
103✔
7257
      return 2;
103✔
7258
    }
7259

7260
  } else {
7261

7262
    p = egraph_num_classes(egraph);
424✔
7263
    k = 0;
424✔
7264
    for (c=0; c<p; c++) {
104,418✔
7265
      if (egraph_class_is_root_class(egraph, c)) {
104,386✔
7266
        t = term_of_occ(egraph_class_root(egraph, c));
24,849✔
7267
        if (egraph_term_real_type(egraph, t) == tau) {
24,849✔
7268
          assert(k < n);
7269
          a[k] = pos_label(c);
850✔
7270
          assert(a[k] == egraph_term_label(egraph, t));
7271
          k ++;
850✔
7272
          if (k == n) break;
850✔
7273
        }
7274
      }
7275
    }
7276

7277
    return k;
424✔
7278
  }
7279
}
7280

7281

7282
#if 0
7283

7284
// NOT USED
7285
/*
7286
 * Number of classes of type tau in the egraph
7287
 */
7288
uint32_t egraph_num_classes_of_type(egraph_t *egraph, type_t tau) {
7289
  int32_t c, n;
7290
  eterm_t t;
7291
  uint32_t k;
7292

7293
  k = 0;
7294
  n = egraph_num_classes(egraph);
7295
  for (c=0; c<n; c++) {
7296
    if (egraph_class_is_root_class(egraph, c)) {
7297
      t = term_of_occ(egraph_class_root(egraph, c));
7298
      if (egraph_term_real_type(egraph, t) == tau) {
7299
        k ++;
7300
      }
7301
    }
7302
  }
7303

7304
  // for booleans, we double k because of polarity
7305
  if (is_boolean_type(tau)) {
7306
    k *= 2;
7307
  }
7308

7309
  return k;
7310
}
7311

7312
#endif
7313

7314

7315
/*
7316
 * Hash and match functions for partition table
7317
 */
7318
static uint32_t hash_arg(egraph_t *egraph, composite_t *c) {
242,285✔
7319
  return hash_arg_signature(c, egraph->terms.label);
242,285✔
7320
}
7321

7322
static bool match_arg(egraph_t *egraph, composite_t *c, composite_t *d) {
179,373✔
7323
  return same_arg_signature(c, d, egraph->terms.label);
179,373✔
7324
}
7325

7326

7327

7328
/*
7329
 * Return the partition structure.
7330
 * Allocate and initialize it if needed.
7331
 */
7332
static ppart_t *egraph_get_app_partition(egraph_t *egraph) {
1,216✔
7333
  ppart_t *pp;
7334

7335
  pp = egraph->app_partition;
1,216✔
7336
  if (pp == NULL) {
1,216✔
7337
    pp = (ppart_t *) safe_malloc(sizeof(ppart_t));
94✔
7338
    init_ptr_partition(pp, 0, egraph, (ppart_hash_fun_t) hash_arg, (ppart_match_fun_t) match_arg);
94✔
7339
    egraph->app_partition = pp;
94✔
7340
  }
7341
  // the pp structure should be empty here
7342
  assert(pp->nelems == 0 && pp->nclasses == 0);
7343

7344
  return pp;
1,216✔
7345
}
7346

7347

7348

7349
/*
7350
 * Build a partition of the (apply ...) terms in the egraph
7351
 * based on argument matches.
7352
 * - scan all composite terms that are (apply ...) and congruence roots
7353
 * - add them one by one to the pp structure
7354
 * - two terms (apply f t_1 ... t_n) and (apply g u_1 ... u_m)
7355
 *   are in the same partition if their arguments are equal in the egraph:
7356
 *   (i.e., n = m and t_1 == u_1 and ... and t_n == u_m)
7357
 * Result:
7358
 * - all non-singleton classes are stored in pp->classes
7359
 *   (cf. ptr_partitions.h and ptr_partitions.c)
7360
 */
7361
void egraph_build_arg_partition(egraph_t *egraph) {
1,216✔
7362
  //  uint32_t i, n;
7363
  uint32_t n;
7364
  composite_t *cmp;
7365
  ppart_t *pp;
7366

7367
  pp = egraph_get_app_partition(egraph);
1,216✔
7368
  n = egraph_num_terms(egraph);
1,216✔
7369
  //  for (i=0; i<n; i++) {
7370
  //    cmp = egraph_term_body(egraph, i);
7371
  // test: do this in reverse order
7372
  while (n > 0) {
2,880,408✔
7373
    n --;
2,879,192✔
7374
    cmp = egraph_term_body(egraph, n);
2,879,192✔
7375
    if (composite_body(cmp) &&
5,560,600✔
7376
        composite_kind(cmp) == COMPOSITE_APPLY &&
3,157,180✔
7377
        congruence_table_is_root(&egraph->ctable, cmp, egraph->terms.label)) {
475,772✔
7378
      ptr_partition_add(pp, cmp);
242,285✔
7379
    }
7380
  }
7381
}
1,216✔
7382

7383

7384
/************************
7385
 *  MODEL CONSTRUCTION  *
7386
 ***********************/
7387

7388
/*
7389
 * Return the value of term occurrence t in the egraph model
7390
 * - the value of all root classes should be available in array value
7391
 */
7392
value_t egraph_get_value(egraph_t *egraph, value_table_t *vtbl, occ_t t) {
23,348✔
7393
  elabel_t l;
7394
  value_t v;
7395

7396
  assert(egraph->mdl.value != NULL && egraph_occ_is_valid(egraph, t));
7397

7398
  l = egraph_label(egraph, t);
23,348✔
7399
  if (is_pos_label(l)) {
23,348✔
7400
    v = egraph->mdl.value[class_of(l)];
19,750✔
7401
  } else if (l == false_label) {
3,598✔
7402
    v = vtbl_mk_false(vtbl);
3,598✔
7403
  } else {
7404
    // this should not happen, but just to be safe we return unknown
7405
    v = vtbl_mk_unknown(vtbl);
×
7406
  }
7407

7408
  return v;
23,348✔
7409
}
7410

7411

7412
/*
7413
 * Get the type of class c: check the root term's type
7414
 * - if that type is TUPLE/FUNCTION/REAL, the root type may not be
7415
 *   precise enough, so we check the other elements in the class
7416
 * - otherwise, return the root type
7417
 */
7418
static type_t egraph_real_type_of_class(egraph_t *egraph, class_t c) {
2,020✔
7419
  type_table_t *types;
7420
  type_t tau, sigma;
7421
  occ_t t, u;
7422

7423
  t = egraph_class_root(egraph, c);
2,020✔
7424
  tau = egraph_term_real_type(egraph, term_of_occ(t));
2,020✔
7425
  assert(tau != NULL_TYPE);
7426

7427
  types = egraph->types;
2,020✔
7428
  switch (type_kind(types, tau)) {
2,020✔
7429
  case REAL_TYPE:
×
7430
    u = t;
×
7431
    do {
7432
      // check whether there's an integer object in the class
7433
      u = egraph_next(egraph, u);
×
7434
      assert(term_of_occ(t) != term_of_occ(u) || t == u);
7435
      tau = egraph_term_real_type(egraph, term_of_occ(u));
×
7436
      assert(is_arithmetic_type(tau));
7437
    } while (t != u && is_real_type(tau));
×
7438
    break;
×
7439

7440
  case TUPLE_TYPE:
2,020✔
7441
  case FUNCTION_TYPE:
7442
    u = egraph_next(egraph, t);
2,020✔
7443
    while (u != t) {
4,197✔
7444
      // refine the type tau
7445
      // TODO: we could optimize this to avoid creating the
7446
      // intermediate subtypes??
7447
      assert(term_of_occ(t) != term_of_occ(u));
7448
      sigma = egraph_term_real_type(egraph, term_of_occ(u));
2,177✔
7449
      tau = inf_type(types, tau, sigma);
2,177✔
7450
      assert(tau != NULL_TYPE);
7451
      u = egraph_next(egraph, u);
2,177✔
7452
    }
7453
    break;
2,020✔
7454

7455
  default:
×
7456
    break;
×
7457
  }
7458

7459
  return tau;
2,020✔
7460
}
7461

7462

7463
/*
7464
 * Convert an abstract value (particle x) to a concrete value
7465
 * - the particle is from egraph->mdl.pstore
7466
 * - x must be either a labeled particle of a fresh particle (not a tuple)
7467
 */
7468
static value_t egraph_concretize_value(egraph_t *egraph, value_table_t *vtbl, particle_t x) {
92,160✔
7469
  pstore_t *pstore;
7470
  value_t v;
7471
  elabel_t l;
7472

7473
  pstore = egraph->mdl.pstore;
92,160✔
7474
  v = particle_concrete_value(pstore, x);
92,160✔
7475
  if (v == null_value) {
92,160✔
7476
    switch (particle_kind(pstore, x)) {
2,069✔
7477
    case LABEL_PARTICLE:
1,732✔
7478
      l = particle_label(pstore, x);
1,732✔
7479
      if (is_pos_label(l)) {
1,732✔
7480
        v = egraph->mdl.value[class_of(l)];
1,723✔
7481
        assert(! object_is_unknown(vtbl, v));
7482
      } else if (l == false_label) {
9✔
7483
        v  = vtbl_mk_false(vtbl);
9✔
7484
      } else {
7485
        // should not happen
7486
        assert(false);
7487
        v = vtbl_mk_unknown(vtbl);
×
7488
      }
7489
      break;
1,732✔
7490

7491
    case FRESH_PARTICLE:
337✔
7492
      v = make_fresh_value(egraph->mdl.fval_maker, fresh_particle_type(pstore, x));
337✔
7493
      break;
337✔
7494

7495
    default:
×
7496
      assert(false);
7497
      abort();
×
7498
    }
7499
    pstore_make_concrete(pstore, x, v);
2,069✔
7500
  }
7501

7502
  return v;
92,160✔
7503
}
7504

7505

7506
/*
7507
 * Concretize a tuple particle x
7508
 * - the result is stored as n concrete values in v[0 ... n-1]
7509
 * - the tuple must have n components
7510
 */
7511
static void egraph_concretize_tuple(egraph_t *egraph, value_table_t *vtbl, particle_t x, uint32_t n, value_t *v) {
650✔
7512
  particle_tuple_t *tuple;
7513
  uint32_t i;
7514

7515
  tuple = tuple_particle_desc(egraph->mdl.pstore, x);
650✔
7516
  assert(tuple->nelems == n);
7517
  for (i=0; i<n; i++) {
2,361✔
7518
    v[i] = egraph_concretize_value(egraph, vtbl, tuple->elem[i]);
1,711✔
7519
  }
7520
}
650✔
7521

7522

7523
/*
7524
 * Conversion of a map of abstract values to a function object
7525
 * - map = the function map (abstract)
7526
 * - tau = function type
7527
 *
7528
 * For every element [idx -> val] of map, we add the mapping (f i) = v to f.
7529
 * where i = concretization of idx and v = concretization of val
7530
 */
7531
static value_t egraph_concretize_map(egraph_t *egraph, value_table_t *vtbl, map_t *map, type_t tau) {
1,469✔
7532
  value_t *aux;
7533
  value_t *all_maps;
7534
  value_t buffer[1];
7535
  value_t v;
7536
  uint32_t i, n, m;
7537

7538
  n = function_type_arity(egraph->types, tau);
1,469✔
7539
  m = map->nelems;
1,469✔
7540

7541
  all_maps = alloc_istack_array(&egraph->istack, m);
1,469✔
7542

7543
  if (n == 1) {
1,469✔
7544
    for (i=0; i<m; i++) {
45,611✔
7545
      buffer[0] = egraph_concretize_value(egraph, vtbl, map->data[i].index);
44,165✔
7546
      v = egraph_concretize_value(egraph, vtbl, map->data[i].value);
44,165✔
7547
      all_maps[i] = vtbl_mk_map(vtbl, 1, buffer, v);
44,165✔
7548
    }
7549
  } else {
7550
    aux = alloc_istack_array(&egraph->istack, n);
23✔
7551

7552
    for (i=0; i<m; i++) {
673✔
7553
      egraph_concretize_tuple(egraph, vtbl, map->data[i].index, n, aux);
650✔
7554
      v = egraph_concretize_value(egraph, vtbl, map->data[i].value);
650✔
7555
      all_maps[i] = vtbl_mk_map(vtbl, n, aux, v);
650✔
7556
    }
7557

7558
    free_istack_array(&egraph->istack, aux);
23✔
7559
  }
7560

7561
  // get the default value
7562
  if (map->def != null_particle) {
1,469✔
7563
    v = egraph_concretize_value(egraph, vtbl, map->def);
1,469✔
7564
  } else {
7565
    v = vtbl_mk_unknown(vtbl);
×
7566
  }
7567

7568
  // build the function
7569
  v = vtbl_mk_function(vtbl, tau, m, all_maps, v);
1,469✔
7570

7571
  free_istack_array(&egraph->istack, all_maps);
1,469✔
7572

7573
  return v;
1,469✔
7574
}
7575

7576

7577
/*
7578
 * Value for an arithmetic class c.
7579
 * c must have etype INT or REAL
7580
 */
7581
static value_t egraph_value_of_arith_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
834✔
7582
  rational_t *aux;
7583
  thvar_t x;
7584
  value_t v;
7585

7586
  assert(egraph_class_type(egraph, c) == ETYPE_INT || egraph_class_type(egraph, c) == ETYPE_REAL);
7587

7588
  x = egraph_class_thvar(egraph, c);
834✔
7589
  if (x == null_thvar) {
834✔
7590
    // there's no arithmetic solver
7591
    assert(egraph->arith_smt == NULL);
7592
    v = make_fresh_integer(egraph->mdl.fval_maker);
×
7593
  } else {
7594
    // there must be an arithmetic solver and it must have assigned a value to x
7595
    aux = &egraph->mdl.arith_buffer;
834✔
7596
    if (egraph->arith_eg->value_in_model(egraph->th[ETYPE_INT], x, aux)) {
834✔
7597
      v = vtbl_mk_rational(vtbl, aux);
834✔
7598
    } else {
7599
      v = vtbl_mk_unknown(vtbl);
×
7600
    }
7601
  }
7602
  return v;
834✔
7603
}
7604

7605

7606
/*
7607
 * Value for a bitvector class c.
7608
 * c must have etype BV
7609
 */
7610
static value_t egraph_value_of_bv_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
1,075✔
7611
  bvconstant_t *bv;
7612
  thvar_t x;
7613
  value_t v;
7614
  uint32_t n;
7615
  type_t tau;
7616

7617
  assert(egraph_class_type(egraph, c) == ETYPE_BV);
7618
  x = egraph_class_thvar(egraph, c);
1,075✔
7619
  if (x == null_thvar) {
1,075✔
7620
    // no bitvector solver
7621
    assert(egraph->bv_smt == NULL);
7622
    tau = egraph_real_type_of_class(egraph, c);
×
7623
    n = bv_type_size(egraph->types, tau);
×
7624
    v = make_fresh_bv(egraph->mdl.fval_maker, n);
×
7625
  } else {
7626
    // there must be a bitvector solver and it must have assigned a value to x
7627
    bv = &egraph->mdl.bv_buffer;
1,075✔
7628
    if (egraph->bv_eg->value_in_model(egraph->th[ETYPE_BV], x, bv)) {
1,075✔
7629
      v = vtbl_mk_bv_from_constant(vtbl, bv);
1,075✔
7630
    } else {
7631
      v = vtbl_mk_unknown(vtbl);
×
7632
    }
7633
  }
7634

7635
  return v;
1,075✔
7636
}
7637

7638
/*
7639
 * Value for a tuple class c
7640
 * c must have etype TUPLE
7641
 */
7642
static value_t egraph_value_of_tuple_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
×
7643
  composite_t *cmp;
7644
  value_t *aux;
7645
  value_t v;
7646
  eterm_t x;
7647
  uint32_t i, n;
7648

7649
  assert(egraph_class_type(egraph, c) == ETYPE_TUPLE);
7650
  x = egraph_class_thvar(egraph, c);
×
7651
  if (x != null_eterm) {
×
7652
    /*
7653
     * x is a (tuple ...) composite in the class
7654
     */
7655
    cmp = egraph_term_body(egraph, x);
×
7656
    assert(cmp != NULL && composite_body(cmp) && composite_kind(cmp) == COMPOSITE_TUPLE);
7657

7658
    n = composite_arity(cmp);
×
7659
    aux = alloc_istack_array(&egraph->istack, n);
×
7660

7661
    // get a value for all the children classes
7662
    // they should all have a non-null value
7663
    for (i=0; i<n; i++) {
×
7664
      aux[i] = egraph_get_value(egraph, vtbl, composite_child(cmp, i));
×
7665
    }
7666

7667
    v = vtbl_mk_tuple(vtbl, n, aux);
×
7668

7669
    free_istack_array(&egraph->istack, aux);
×
7670

7671
  } else {
7672
    // This should never happen
7673
    assert(false);
7674
    v = vtbl_mk_unknown(vtbl);
×
7675
  }
7676

7677
  return v;
×
7678
}
7679

7680

7681
/*
7682
 * Convert composite p to a mapping object
7683
 * - p must be (apply f a[0] .. a[n-1])
7684
 * - we construct the mapping object (v[0] ... v[n-1] |-> r)
7685
 *   where v[i] = value of a[i]
7686
 *            r = value of class of p
7687
 */
7688
static value_t egraph_composite_value(egraph_t *egraph, value_table_t *vtbl, composite_t *p) {
6,856✔
7689
  value_t *aux;
7690
  value_t v;
7691
  uint32_t i, n;
7692

7693
  assert(composite_kind(p) == COMPOSITE_APPLY);
7694
  n = composite_arity(p);
6,856✔
7695
  assert(n >= 2);
7696
  n --;
6,856✔
7697

7698
  aux = alloc_istack_array(&egraph->istack, n);
6,856✔
7699

7700
  // values of a[0] ... a[n-1]
7701
  // they should all be defined
7702
  for (i=0; i<n; i++) {
20,471✔
7703
    aux[i] = egraph_get_value(egraph, vtbl, composite_child(p, i+1));
13,615✔
7704
  }
7705

7706
  // value of f
7707
  v = egraph_get_value(egraph, vtbl, pos_occ(p->id));
6,856✔
7708

7709
  // build the mapping object [aux[0] ... aux[n-1] -> v]
7710
  v = vtbl_mk_map(vtbl, n, aux, v);
6,856✔
7711

7712
  free_istack_array(&egraph->istack, aux);
6,856✔
7713

7714
  return v;
6,856✔
7715
}
7716

7717

7718
/*
7719
 * Get a default constant for functions of type tau
7720
 * - when we generate a model for a function f of type tau,
7721
 *   then we have values for a finite number of terms of the form
7722
 *    f(a_11 ... a_1k) .... f(a_n1 ... a_nk)
7723
 * - to print the model in SMT format, we need to extend f to a full
7724
 *   function by giving a default value f(x_1, ..., x_k) for
7725
 *   points other than a_1, ..., a_n.
7726
 * - we can extend f with an arbitrary default value when we're in QF_UF because
7727
 *   only the f(a_11, ... a_1k) matter for satisfying the assertions.
7728
 *
7729
 * We check whether we have high-order terms here and return unknown as the default in
7730
 * such a case (as this means we're outside of QF_UF).
7731
 */
7732
static value_t egraph_make_default_fun_value(egraph_t *egraph, value_table_t *vtbl, type_t tau) {
551✔
7733
  return egraph->is_high_order ? vtbl_mk_unknown(vtbl) : vtbl_make_object(vtbl, function_type_range(egraph->types, tau));
551✔
7734
}
7735

7736
/*
7737
 * Build a mapping from the composite terms in c's parent vector
7738
 * - tau = type of class c
7739
 */
7740
static value_t egraph_make_fun_value(egraph_t *egraph, value_table_t *vtbl, class_t c, type_t tau) {
551✔
7741
  use_vector_t *u;
7742
  composite_t *p;
7743
  occ_t g;
7744
  uint32_t i, n, j;
7745
  value_t *all_maps;
7746
  value_t v;
7747

7748
  u = egraph_class_parents(egraph, c);
551✔
7749
  n = u->last;
551✔
7750

7751
  assert(n < VTBL_MAX_MAP_SIZE);
7752
  all_maps = alloc_istack_array(&egraph->istack, n);
551✔
7753

7754
  j = 0;
551✔
7755
  for (i=0; i<n; i++) {
7,836✔
7756
    p = u->data[i];
7,285✔
7757
    if (valid_entry(p) && composite_kind(p) == COMPOSITE_APPLY) {
7,285✔
7758
      g = composite_child(p, 0); // function term of p
6,856✔
7759
      if (egraph_class(egraph, g) == c) {
6,856✔
7760
        all_maps[j] = egraph_composite_value(egraph, vtbl, p);
6,856✔
7761
        j ++;
6,856✔
7762
      }
7763
    }
7764
  }
7765

7766

7767
  // function without a default value
7768
  //  v = vtbl_mk_function(vtbl, tau, j, all_maps, vtbl_mk_unknown(vtbl));
7769
  v = egraph_make_default_fun_value(egraph, vtbl, tau);
551✔
7770
  v = vtbl_mk_function(vtbl, tau, j, all_maps, v);
551✔
7771

7772
  free_istack_array(&egraph->istack, all_maps);
551✔
7773

7774
  return v;
551✔
7775
}
7776

7777

7778
/*
7779
 * Value for a array/function class c.
7780
 * c must have etype FUNCTION
7781
 */
7782
static value_t egraph_value_of_fun_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
2,020✔
7783
  map_t *map;
7784
  thvar_t x;
7785
  value_t v;
7786
  type_t tau;
7787

7788
  assert(egraph_class_type(egraph, c) == ETYPE_FUNCTION);
7789
  x = egraph_class_thvar(egraph, c);
2,020✔
7790
  tau = egraph_real_type_of_class(egraph, c);
2,020✔
7791
  if (x == null_thvar) {
2,020✔
7792
    /*
7793
     * no array/function solver: create a new function
7794
     * using the composites terms in c's parent vector
7795
     */
7796
    v = egraph_make_fun_value(egraph, vtbl, c, tau);
551✔
7797
  } else {
7798
    /*
7799
     * there is a function solver and it must have assigned a value to x
7800
     */
7801
    assert(egraph->fun_eg != NULL);
7802
    map = egraph->fun_eg->value_in_model(egraph->th[ETYPE_FUNCTION], x);
1,469✔
7803
    if (map != NULL) {
1,469✔
7804
      v = egraph_concretize_map(egraph, vtbl, map, tau);
1,469✔
7805
    } else {
7806
      v = vtbl_mk_unknown(vtbl);
×
7807
    }
7808
  }
7809

7810
  return v;
2,020✔
7811
}
7812

7813

7814
/*
7815
 * Value of an uninterpreted class c
7816
 * c must have etype NONE
7817
 */
7818
static value_t egraph_value_of_uninterpreted_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
4,995✔
7819
  occ_t root;
7820
  eterm_t t;
7821
  type_t tau;
7822
  value_t v;
7823

7824
  /*
7825
   * Search for a constant t in the class. If there's none
7826
   * create an anonymous uninterpreted constant/
7827
   */
7828
  root = egraph_class_root(egraph, c);
4,995✔
7829
  assert(is_pos_occ(root));
7830
  tau = egraph_term_real_type(egraph, term_of_occ(root));
4,995✔
7831
  assert(tau != NULL_TYPE);
7832

7833
  if ((egraph->classes.dmask[c] & 0x1) != 0) {
4,995✔
7834
    // the class contains a constant
7835
    t = term_of_occ(root);
3,491✔
7836
    while (! constant_body(egraph_term_body(egraph, t))) {
4,118✔
7837
      t = term_of_occ(egraph->terms.next[t]);
627✔
7838
      assert(t != term_of_occ(root)); // make sure we don't loop forever
7839
    }
7840

7841
    // v = constant of type tau and same id as t, no name
7842
    v = vtbl_mk_const(vtbl, tau, constant_body_id(egraph_term_body(egraph, t)), NULL);
3,491✔
7843

7844
  } else {
7845
    // fresh anonymous constant
7846
    v = make_fresh_const(egraph->mdl.fval_maker, tau);
1,504✔
7847
  }
7848

7849
  return v;
4,995✔
7850
}
7851

7852

7853
/*
7854
 * Get the value of class c
7855
 */
7856
static value_t egraph_value_of_class(egraph_t *egraph, value_table_t *vtbl, class_t c) {
21,961✔
7857
  value_t v;
7858

7859
  switch (egraph_class_type(egraph, c)) {
21,961✔
7860
  case ETYPE_INT:
834✔
7861
  case ETYPE_REAL:
7862
    v = egraph_value_of_arith_class(egraph, vtbl, c);
834✔
7863
    break;
834✔
7864

7865
  case ETYPE_FUNCTION:
2,020✔
7866
    v = egraph_value_of_fun_class(egraph, vtbl, c);
2,020✔
7867
    break;
2,020✔
7868

7869
  case ETYPE_BV:
1,075✔
7870
    v = egraph_value_of_bv_class(egraph, vtbl, c);
1,075✔
7871
    break;
1,075✔
7872

7873
  case ETYPE_BOOL:
13,037✔
7874
    /*
7875
     * If all literals are assigned in the core, then all the boolean terms are in
7876
     * the bool_constant_class. So the value[c] must be true.
7877
     */
7878
    assert(c == bool_constant_class &&
7879
           bvar_value(egraph->core, egraph_class_thvar(egraph, c)) == VAL_TRUE);
7880
    v = vtbl_mk_true(vtbl);
13,037✔
7881
    break;
13,037✔
7882

7883
  case ETYPE_TUPLE:
×
7884
    v = egraph_value_of_tuple_class(egraph, vtbl, c);
×
7885
    break;
×
7886

7887
  case ETYPE_NONE:
4,995✔
7888
    v = egraph_value_of_uninterpreted_class(egraph, vtbl, c);
4,995✔
7889
    break;
4,995✔
7890

7891
  default:
×
7892
    /*
7893
     * Should not happen
7894
     */
7895
    assert(false);
7896
    v = vtbl_mk_unknown(vtbl);
×
7897
    break;
×
7898
  }
7899

7900
  return v;
21,961✔
7901
}
7902

7903

7904
/*
7905
 * Assign a value to all the root classes
7906
 * - the root classes must be stored in egraph->mdl.root_classes
7907
 */
7908
static void egraph_model_for_root_classes(egraph_t *egraph, value_table_t *vtbl) {
13,037✔
7909
  ivector_t *v;
7910
  uint32_t i, n;
7911
  class_t c;
7912

7913
  v = &egraph->mdl.root_classes;
13,037✔
7914
  n = v->size;
13,037✔
7915
  for (i=0; i<n; i++) {
34,998✔
7916
    c = v->data[i];
21,961✔
7917
    assert(egraph_class_is_root_class(egraph, c));
7918
    // first build values for classes with constants
7919
    /* we do this because we choose the body-id as its value id if it
7920
     * is of scalar type
7921
     *
7922
     * however, if we let classes without constant run first, it may
7923
     * happen that they take the value id which we need for classes
7924
     * with constants
7925
     */
7926
    if ((egraph->classes.dmask[c] & 0x1) != 0) {
21,961✔
7927
      // class contains a constant
7928
      assert(egraph->mdl.value[c] == null_value);
7929
      egraph->mdl.value[c] = egraph_value_of_class(egraph, vtbl, c);
17,114✔
7930
    }
7931
  }
7932
  for (i=0; i<n; i++) {
34,998✔
7933
    c = v->data[i];
21,961✔
7934
    assert(egraph_class_is_root_class(egraph, c));
7935
    // now build values for classes without constants
7936
    if ((egraph->classes.dmask[c] & 0x1) == 0) {
21,961✔
7937
      // class doesn't contain a constant
7938
      assert(egraph->mdl.value[c] == null_value);
7939
      egraph->mdl.value[c] = egraph_value_of_class(egraph, vtbl, c);
4,847✔
7940
    }
7941
  }
7942
}
13,037✔
7943

7944

7945

7946
/*
7947
 * Rank of a class c
7948
 */
7949
static uint32_t egraph_class_rank(egraph_t *egraph, class_t c) {
43,922✔
7950
  occ_t t;
7951
  type_t tau;
7952

7953
  t = egraph_class_root(egraph, c);
43,922✔
7954
  tau = egraph_term_real_type(egraph, term_of_occ(t));
43,922✔
7955
  return type_depth(egraph->types, tau);
43,922✔
7956
}
7957

7958

7959
/*
7960
 * Increment rank counter k
7961
 * - ctr = vector of counters
7962
 * - also initialize all counters of rank < k if needed
7963
 */
7964
static void egraph_increment_rank_counter(ivector_t *ctr, uint32_t k) {
21,961✔
7965
  uint32_t i;
7966

7967
  if (ctr->size <= k) {
21,961✔
7968
    resize_ivector(ctr, k+1);
13,249✔
7969
    assert(ctr->capacity > k);
7970
    for (i=ctr->size; i<=k; i++) {
26,502✔
7971
      ctr->data[i] = 0;
13,253✔
7972
    }
7973
    ctr->size = k+1;
13,249✔
7974
  }
7975
  ctr->data[k] ++;
21,961✔
7976
}
21,961✔
7977

7978

7979
/*
7980
 * Collect all root classes
7981
 * - store them in mdl->root_classes, sorted by increasing rank
7982
 */
7983
static void egraph_collect_root_classes(egraph_t *egraph) {
13,037✔
7984
  ivector_t *v;
7985
  ivector_t *ctr;
7986
  uint32_t i, j, n, k, s;
7987

7988
  ctr = &egraph->mdl.rank_ctr;
13,037✔
7989
  ivector_reset(ctr);
13,037✔
7990

7991
  // first pass: count the number of root classes per rank
7992
  n = egraph_num_classes(egraph);
13,037✔
7993
  for (i=0; i<n; i++) {
74,141✔
7994
    if (egraph_class_is_root_class(egraph, i)) {
61,104✔
7995
      k = egraph_class_rank(egraph, i);
21,961✔
7996
      egraph_increment_rank_counter(ctr, k);
21,961✔
7997
    }
7998
  }
7999

8000
  s = 0;
13,037✔
8001
  n = ctr->size;
13,037✔
8002
  for (i=0; i<n; i++) {
26,290✔
8003
    k = ctr->data[i]; // number of classes of rank i
13,253✔
8004
    ctr->data[i] = s; // number of classes of rank < I
13,253✔
8005
    s += k;
13,253✔
8006
  }
8007

8008
  /*
8009
   * s = total number of root classes
8010
   * store the classes in increasing
8011
   * rank order in egraph->mdl.root_classes;
8012
   */
8013
  v = &egraph->mdl.root_classes;
13,037✔
8014
  resize_ivector(v, s);
13,037✔
8015
  v->size = s;
13,037✔
8016
  n = egraph_num_classes(egraph);
13,037✔
8017
  for (i=0; i<n; i++) {
74,141✔
8018
    if (egraph_class_is_root_class(egraph, i)) {
61,104✔
8019
      k = egraph_class_rank(egraph, i);
21,961✔
8020
      assert(k < ctr->size);
8021
      j = ctr->data[k];
21,961✔
8022
      v->data[j] = i;
21,961✔
8023
      ctr->data[k] = j+1;
21,961✔
8024
    }
8025
  }
8026
}
13,037✔
8027

8028

8029
/*
8030
 * Build a model: the model maps egraph classes to objects built in vtbl
8031
 */
8032
void egraph_build_model(egraph_t *egraph, value_table_t *vtbl) {
13,037✔
8033
  uint32_t i, n;
8034
  pstore_t *pstore;
8035
  fresh_val_maker_t *fval;
8036

8037
  /*
8038
   * Allocate and initialize the value array
8039
   */
8040
  n = egraph->classes.nclasses;
13,037✔
8041
  egraph->mdl.value = (value_t *) safe_malloc(n * sizeof(value_t));
13,037✔
8042
  for (i=0; i<n; i++) {
74,141✔
8043
    egraph->mdl.value[i] = null_value;
61,104✔
8044
  }
8045

8046
  /*
8047
   * Allocate and initialize the pstore then build the array model
8048
   */
8049
  if (egraph->fun_eg != NULL) {
13,037✔
8050
    pstore = (pstore_t *) safe_malloc(sizeof(pstore_t));
12,646✔
8051
    egraph->mdl.pstore = pstore;
12,646✔
8052
    init_pstore(pstore, egraph->types);
12,646✔
8053
    egraph->fun_eg->build_model(egraph->th[ETYPE_FUNCTION], pstore);
12,646✔
8054
  }
8055

8056
  /*
8057
   * Allocate the free_val_maker:
8058
   * - it may be needed even if we don't have a function solver
8059
   */
8060
  fval = (fresh_val_maker_t *) safe_malloc(sizeof(fresh_val_maker_t));
13,037✔
8061
  init_fresh_val_maker(fval, vtbl);
13,037✔
8062
  egraph->mdl.fval_maker = fval;
13,037✔
8063

8064
  egraph_collect_root_classes(egraph);
13,037✔
8065

8066
  /*
8067
   * Check whether we have high order terms
8068
   * - this sets egraph->is_high_order to true in this case
8069
   */
8070
  (void) egraph_is_high_order(egraph);
13,037✔
8071

8072
  // assign a value to all root classes
8073
  egraph_model_for_root_classes(egraph, vtbl);
13,037✔
8074
}
13,037✔
8075

8076

8077

8078
/*
8079
 * Free/reset internal structures
8080
 */
8081
void egraph_free_model(egraph_t *egraph) {
13,037✔
8082
  if (egraph->fun_eg != NULL) {
13,037✔
8083
    egraph->fun_eg->free_model(egraph->th[ETYPE_FUNCTION]);
12,646✔
8084
  }
8085
  reset_egraph_model(&egraph->mdl);
13,037✔
8086
}
13,037✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc