mirror of
https://github.com/Z3Prover/z3
synced 2025-06-19 12:23:38 +00:00
Debug dlist insertion
Found because of assertion failure in test_polysat::test_fixed_point_arith_div_mul_inverse()
This commit is contained in:
parent
e58815884f
commit
f184545aca
5 changed files with 96 additions and 32 deletions
|
@ -75,18 +75,18 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void viable::pop_viable() {
|
void viable::pop_viable() {
|
||||||
auto& [v, k, e] = m_trail.back();
|
auto const& [v, k, e] = m_trail.back();
|
||||||
SASSERT(well_formed(m_units[v]));
|
SASSERT(well_formed(m_units[v]));
|
||||||
switch (k) {
|
switch (k) {
|
||||||
case entry_kind::unit_e:
|
case entry_kind::unit_e:
|
||||||
e->remove_from(m_units[v], e);
|
entry::remove_from(m_units[v], e);
|
||||||
SASSERT(well_formed(m_units[v]));
|
SASSERT(well_formed(m_units[v]));
|
||||||
break;
|
break;
|
||||||
case entry_kind::equal_e:
|
case entry_kind::equal_e:
|
||||||
e->remove_from(m_equal_lin[v], e);
|
entry::remove_from(m_equal_lin[v], e);
|
||||||
break;
|
break;
|
||||||
case entry_kind::diseq_e:
|
case entry_kind::diseq_e:
|
||||||
e->remove_from(m_diseq_lin[v], e);
|
entry::remove_from(m_diseq_lin[v], e);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -104,7 +104,9 @@ namespace polysat {
|
||||||
(void)k;
|
(void)k;
|
||||||
SASSERT(well_formed(m_units[v]));
|
SASSERT(well_formed(m_units[v]));
|
||||||
if (e->prev() != e) {
|
if (e->prev() != e) {
|
||||||
e->prev()->insert_after(e);
|
entry* pos = e->prev();
|
||||||
|
e->init(e);
|
||||||
|
pos->insert_after(e);
|
||||||
if (e->interval.lo_val() < m_units[v]->interval.lo_val())
|
if (e->interval.lo_val() < m_units[v]->interval.lo_val())
|
||||||
m_units[v] = e;
|
m_units[v] = e;
|
||||||
}
|
}
|
||||||
|
@ -180,6 +182,7 @@ namespace polysat {
|
||||||
entries[v] = e;
|
entries[v] = e;
|
||||||
else
|
else
|
||||||
e->insert_after(entries[v]);
|
e->insert_after(entries[v]);
|
||||||
|
SASSERT(entries[v]->invariant());
|
||||||
SASSERT(well_formed(m_units[v]));
|
SASSERT(well_formed(m_units[v]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,10 +275,10 @@ namespace polysat {
|
||||||
*/
|
*/
|
||||||
bool viable::refine_equal_lin(pvar v, rational const& val) {
|
bool viable::refine_equal_lin(pvar v, rational const& val) {
|
||||||
// LOG_H2("refine-equal-lin with v" << v << ", val = " << val);
|
// LOG_H2("refine-equal-lin with v" << v << ", val = " << val);
|
||||||
auto* e = m_equal_lin[v];
|
entry const* e = m_equal_lin[v];
|
||||||
if (!e)
|
if (!e)
|
||||||
return true;
|
return true;
|
||||||
entry* first = e;
|
entry const* first = e;
|
||||||
rational const& max_value = s.var2pdd(v).max_value();
|
rational const& max_value = s.var2pdd(v).max_value();
|
||||||
rational mod_value = max_value + 1;
|
rational mod_value = max_value + 1;
|
||||||
|
|
||||||
|
@ -380,10 +383,10 @@ namespace polysat {
|
||||||
|
|
||||||
bool viable::refine_disequal_lin(pvar v, rational const& val) {
|
bool viable::refine_disequal_lin(pvar v, rational const& val) {
|
||||||
// LOG_H2("refine-disequal-lin with v" << v << ", val = " << val);
|
// LOG_H2("refine-disequal-lin with v" << v << ", val = " << val);
|
||||||
auto* e = m_diseq_lin[v];
|
entry const* e = m_diseq_lin[v];
|
||||||
if (!e)
|
if (!e)
|
||||||
return true;
|
return true;
|
||||||
entry* first = e;
|
entry const* first = e;
|
||||||
rational const& max_value = s.var2pdd(v).max_value();
|
rational const& max_value = s.var2pdd(v).max_value();
|
||||||
rational const mod_value = max_value + 1;
|
rational const mod_value = max_value + 1;
|
||||||
|
|
||||||
|
@ -632,9 +635,9 @@ namespace polysat {
|
||||||
bool viable::resolve(pvar v, conflict& core) {
|
bool viable::resolve(pvar v, conflict& core) {
|
||||||
if (has_viable(v))
|
if (has_viable(v))
|
||||||
return false;
|
return false;
|
||||||
auto* e = m_units[v];
|
entry const* e = m_units[v];
|
||||||
// TODO: in the forbidden interval paper, they start with the longest interval. We should also try that at some point.
|
// TODO: in the forbidden interval paper, they start with the longest interval. We should also try that at some point.
|
||||||
entry* first = e;
|
entry const* first = e;
|
||||||
SASSERT(e);
|
SASSERT(e);
|
||||||
// If there is a full interval, all others would have been removed
|
// If there is a full interval, all others would have been removed
|
||||||
SASSERT(!e->interval.is_full() || e->next() == e);
|
SASSERT(!e->interval.is_full() || e->next() == e);
|
||||||
|
@ -642,7 +645,7 @@ namespace polysat {
|
||||||
do {
|
do {
|
||||||
// Build constraint: upper bound of each interval is not contained in the next interval,
|
// Build constraint: upper bound of each interval is not contained in the next interval,
|
||||||
// using the equivalence: t \in [l;h[ <=> t-l < h-l
|
// using the equivalence: t \in [l;h[ <=> t-l < h-l
|
||||||
entry* n = e->next();
|
entry const* n = e->next();
|
||||||
|
|
||||||
// Choose the next interval which furthest extends the covered region.
|
// Choose the next interval which furthest extends the covered region.
|
||||||
// Example:
|
// Example:
|
||||||
|
@ -666,7 +669,7 @@ namespace polysat {
|
||||||
//
|
//
|
||||||
// The interval 'first' is always part of the lemma. If we reach first again here, we have covered the complete domain.
|
// The interval 'first' is always part of the lemma. If we reach first again here, we have covered the complete domain.
|
||||||
while (n != first) {
|
while (n != first) {
|
||||||
entry* n1 = n->next();
|
entry const* n1 = n->next();
|
||||||
// Check if n1 is eligible; if yes, then n1 is better than n.
|
// Check if n1 is eligible; if yes, then n1 is better than n.
|
||||||
//
|
//
|
||||||
// Case 1, n1 overlaps e (unless n1 == e):
|
// Case 1, n1 overlaps e (unless n1 == e):
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace polysat {
|
||||||
solver& s;
|
solver& s;
|
||||||
forbidden_intervals m_forbidden_intervals;
|
forbidden_intervals m_forbidden_intervals;
|
||||||
|
|
||||||
struct entry : public dll_base<entry>, public fi_record {};
|
struct entry final : public dll_base<entry>, public fi_record {};
|
||||||
enum class entry_kind { unit_e, equal_e, diseq_e };
|
enum class entry_kind { unit_e, equal_e, diseq_e };
|
||||||
|
|
||||||
ptr_vector<entry> m_alloc;
|
ptr_vector<entry> m_alloc;
|
||||||
|
|
|
@ -19,6 +19,7 @@ Revision History:
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
void enable_assertions(bool f);
|
void enable_assertions(bool f);
|
||||||
bool assertions_enabled();
|
bool assertions_enabled();
|
||||||
|
|
|
@ -18,14 +18,25 @@ Revision History:
|
||||||
--*/
|
--*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include "util/debug.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
template <typename T> class dll_iterator;
|
template <typename T> class dll_iterator;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class dll_base {
|
class dll_base {
|
||||||
T* m_next { nullptr };
|
T* m_next = nullptr;
|
||||||
T* m_prev { nullptr };
|
T* m_prev = nullptr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
dll_base() = default;
|
||||||
|
~dll_base() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
dll_base(dll_base const&) = delete;
|
||||||
|
dll_base(dll_base&&) = delete;
|
||||||
|
dll_base& operator=(dll_base const&) = delete;
|
||||||
|
dll_base& operator=(dll_base&&) = delete;
|
||||||
|
|
||||||
T* prev() { return m_prev; }
|
T* prev() { return m_prev; }
|
||||||
T* next() { return m_next; }
|
T* next() { return m_next; }
|
||||||
|
@ -35,6 +46,7 @@ public:
|
||||||
void init(T* t) {
|
void init(T* t) {
|
||||||
m_next = t;
|
m_next = t;
|
||||||
m_prev = t;
|
m_prev = t;
|
||||||
|
SASSERT(invariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
static T* pop(T*& list) {
|
static T* pop(T*& list) {
|
||||||
|
@ -45,23 +57,61 @@ public:
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_after(T* elem) {
|
void insert_after(T* other) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
SASSERT(other);
|
||||||
|
SASSERT(invariant());
|
||||||
|
SASSERT(other->invariant());
|
||||||
|
unsigned const old_sz1 = count_if(*static_cast<T*>(this), [](T const&) { return true; });
|
||||||
|
unsigned const old_sz2 = count_if(*other, [](T const&) { return true; });
|
||||||
|
#endif
|
||||||
|
// have: this -> next -> ...
|
||||||
|
// insert: other -> ... -> other_end
|
||||||
|
// result: this -> other -> ... -> other_end -> next -> ...
|
||||||
T* next = this->m_next;
|
T* next = this->m_next;
|
||||||
elem->m_prev = next->m_prev;
|
T* other_end = other->m_prev;
|
||||||
elem->m_next = next;
|
this->m_next = other;
|
||||||
this->m_next = elem;
|
other->m_prev = static_cast<T*>(this);
|
||||||
next->m_prev = elem;
|
other_end->m_next = next;
|
||||||
|
next->m_prev = other_end;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
SASSERT(invariant());
|
||||||
|
SASSERT(other->invariant());
|
||||||
|
unsigned const new_sz = count_if(*static_cast<T*>(this), [](T const&) { return true; });
|
||||||
|
SASSERT_EQ(new_sz, old_sz1 + old_sz2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert_before(T* elem) {
|
void insert_before(T* other) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
SASSERT(other);
|
||||||
|
SASSERT(invariant());
|
||||||
|
SASSERT(other->invariant());
|
||||||
|
unsigned const old_sz1 = count_if(*static_cast<T*>(this), [](T const&) { return true; });
|
||||||
|
unsigned const old_sz2 = count_if(*other, [](T const&) { return true; });
|
||||||
|
#endif
|
||||||
|
// have: prev -> this -> ...
|
||||||
|
// insert: other -> ... -> other_end
|
||||||
|
// result: prev -> other -> ... -> other_end -> this -> ...
|
||||||
T* prev = this->m_prev;
|
T* prev = this->m_prev;
|
||||||
elem->m_next = prev->m_next;
|
T* other_end = other->m_prev;
|
||||||
elem->m_prev = prev;
|
prev->m_next = other;
|
||||||
prev->m_next = elem;
|
other->m_prev = prev;
|
||||||
this->m_prev = elem;
|
other_end->m_next = static_cast<T*>(this);
|
||||||
|
this->m_prev = other_end;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
SASSERT(invariant());
|
||||||
|
SASSERT(other->invariant());
|
||||||
|
unsigned const new_sz = count_if(*static_cast<T*>(this), [](T const&) { return true; });
|
||||||
|
SASSERT_EQ(new_sz, old_sz1 + old_sz2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_from(T*& list, T* elem) {
|
static void remove_from(T*& list, T* elem) {
|
||||||
|
SASSERT(list);
|
||||||
|
SASSERT(elem);
|
||||||
|
SASSERT(list->invariant());
|
||||||
|
SASSERT(elem->invariant());
|
||||||
if (list->m_next == list) {
|
if (list->m_next == list) {
|
||||||
SASSERT(elem == list);
|
SASSERT(elem == list);
|
||||||
list = nullptr;
|
list = nullptr;
|
||||||
|
@ -73,6 +123,7 @@ public:
|
||||||
auto* prev = elem->m_prev;
|
auto* prev = elem->m_prev;
|
||||||
prev->m_next = next;
|
prev->m_next = next;
|
||||||
next->m_prev = prev;
|
next->m_prev = prev;
|
||||||
|
SASSERT(list->invariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void push_to_front(T*& list, T* elem) {
|
static void push_to_front(T*& list, T* elem) {
|
||||||
|
@ -141,10 +192,11 @@ public:
|
||||||
return {elem, false};
|
return {elem, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
// using value_type = T;
|
using value_type = T;
|
||||||
// using pointer = T const*;
|
using pointer = T const*;
|
||||||
// using reference = T const&;
|
using reference = T const&;
|
||||||
// using iterator_category = std::input_iterator_tag;
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
dll_iterator& operator++() {
|
dll_iterator& operator++() {
|
||||||
m_elem = m_elem->next();
|
m_elem = m_elem->next();
|
||||||
|
|
|
@ -379,10 +379,10 @@ inline size_t megabytes_to_bytes(unsigned mb) {
|
||||||
|
|
||||||
/** Compact version of std::all_of */
|
/** Compact version of std::all_of */
|
||||||
template <typename Container, typename Predicate>
|
template <typename Container, typename Predicate>
|
||||||
bool all_of(Container const& c, Predicate f)
|
bool all_of(Container const& c, Predicate p)
|
||||||
{
|
{
|
||||||
using std::begin, std::end; // allows begin(c) to also find c.begin()
|
using std::begin, std::end; // allows begin(c) to also find c.begin()
|
||||||
return std::all_of(begin(c), end(c), std::forward<Predicate>(f));
|
return std::all_of(begin(c), end(c), std::forward<Predicate>(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compact version of std::count */
|
/** Compact version of std::count */
|
||||||
|
@ -392,3 +392,11 @@ std::size_t count(Container const& c, Item x)
|
||||||
using std::begin, std::end; // allows begin(c) to also find c.begin()
|
using std::begin, std::end; // allows begin(c) to also find c.begin()
|
||||||
return std::count(begin(c), end(c), std::forward<Item>(x));
|
return std::count(begin(c), end(c), std::forward<Item>(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compact version of std::count_if */
|
||||||
|
template <typename Container, typename Predicate>
|
||||||
|
std::size_t count_if(Container const& c, Predicate p)
|
||||||
|
{
|
||||||
|
using std::begin, std::end; // allows begin(c) to also find c.begin()
|
||||||
|
return std::count_if(begin(c), end(c), std::forward<Predicate>(p));
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue