3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-06 07:16:13 +00:00

Revert "Derive with ranges" (#9964)

Reverts Z3Prover/z3#9963
This commit is contained in:
Nikolaj Bjorner 2026-06-25 18:57:30 -07:00 committed by GitHub
parent 22c2635786
commit f034616950
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 1000 additions and 3462 deletions

View file

@ -1,260 +0,0 @@
/*++
Copyright (c) 2026 Microsoft Corporation
Module Name:
test/range_predicate.cpp
Abstract:
Unit tests for the range-algebra value type seq::range_predicate.
The tests exercise:
* factory constructors and canonical-form invariants,
* extensional equality and total ordering,
* Boolean operations (|, &, ~, -, ^) on hand-picked instances,
* exhaustive verification of de-Morgan and lattice laws on a
small character domain, by enumerating every subset.
Author:
Margus Veanes (veanes) 2026
--*/
#include "ast/rewriter/seq_range_predicate.h"
#include "util/debug.h"
#include <cstdint>
#include <iostream>
#include <sstream>
using seq::range_predicate;
namespace {
// Build a range_predicate from a bitmask over [0, max_char] for testing.
range_predicate from_mask(uint64_t mask, unsigned max_char) {
range_predicate r = range_predicate::empty(max_char);
for (unsigned c = 0; c <= max_char; ++c)
if ((mask >> c) & 1u)
r = r | range_predicate::singleton(c, max_char);
return r;
}
// Convert a range_predicate back to a bitmask for cross-checking.
uint64_t to_mask(range_predicate const& r) {
uint64_t mask = 0;
for (unsigned c = 0; c <= r.max_char(); ++c)
if (r.contains(c))
mask |= (uint64_t(1) << c);
return mask;
}
void test_factories() {
auto e = range_predicate::empty(255);
ENSURE(e.is_empty());
ENSURE(!e.is_top());
ENSURE(e.num_ranges() == 0);
ENSURE(e.cardinality() == 0);
auto t = range_predicate::top(255);
ENSURE(!t.is_empty());
ENSURE(t.is_top());
ENSURE(t.num_ranges() == 1);
ENSURE(t.cardinality() == 256);
ENSURE(t.contains(0));
ENSURE(t.contains(255));
auto s = range_predicate::singleton(42, 255);
ENSURE(s.num_ranges() == 1);
ENSURE(s.cardinality() == 1);
ENSURE(s.contains(42));
ENSURE(!s.contains(41));
unsigned c = 0;
ENSURE(s.is_singleton(c));
ENSURE(c == 42);
auto r = range_predicate::range(10, 20, 255);
ENSURE(r.num_ranges() == 1);
ENSURE(r.cardinality() == 11);
ENSURE(r.contains(10));
ENSURE(r.contains(20));
ENSURE(!r.contains(9));
ENSURE(!r.contains(21));
// Reversed bounds produce empty.
auto bad = range_predicate::range(20, 10, 255);
ENSURE(bad.is_empty());
// Clipping at max_char.
auto clipped = range_predicate::range(200, 1000, 255);
ENSURE(clipped.num_ranges() == 1);
ENSURE(clipped[0] == std::make_pair(200u, 255u));
}
void test_equality_and_order() {
auto a = range_predicate::range(1, 5, 31);
auto b = range_predicate::range(1, 5, 31);
auto c = range_predicate::range(1, 6, 31);
ENSURE(a == b);
ENSURE(a != c);
ENSURE(a.hash() == b.hash());
ENSURE(a < c || c < a);
ENSURE(!(a < a));
auto empty = range_predicate::empty(31);
ENSURE(empty < a);
// Canonical merging of adjacent ranges.
auto d = range_predicate::range(0, 4, 31) | range_predicate::range(5, 10, 31);
auto e = range_predicate::range(0, 10, 31);
ENSURE(d == e);
}
void test_union_intersection_hand() {
unsigned const M = 31;
auto a = range_predicate::range(0, 4, M) | range_predicate::range(10, 14, M);
auto b = range_predicate::range(3, 11, M);
auto u = a | b; // [0,14]
ENSURE(u.num_ranges() == 1);
ENSURE(u[0] == std::make_pair(0u, 14u));
auto i = a & b; // [3,4] U [10,11]
ENSURE(i.num_ranges() == 2);
ENSURE(i[0] == std::make_pair(3u, 4u));
ENSURE(i[1] == std::make_pair(10u, 11u));
auto d = a - b; // [0,2] U [12,14]
ENSURE(d.num_ranges() == 2);
ENSURE(d[0] == std::make_pair(0u, 2u));
ENSURE(d[1] == std::make_pair(12u, 14u));
auto x = a ^ b; // [0,2] U [5,9] U [12,14]
ENSURE(x.num_ranges() == 3);
ENSURE(x[0] == std::make_pair(0u, 2u));
ENSURE(x[1] == std::make_pair(5u, 9u));
ENSURE(x[2] == std::make_pair(12u, 14u));
}
void test_complement_hand() {
unsigned const M = 10;
auto e = range_predicate::empty(M);
ENSURE((~e).is_top());
auto t = range_predicate::top(M);
ENSURE((~t).is_empty());
// ~([2,3] U [7,8]) = [0,1] U [4,6] U [9,10]
auto a = range_predicate::range(2, 3, M) | range_predicate::range(7, 8, M);
auto na = ~a;
ENSURE(na.num_ranges() == 3);
ENSURE(na[0] == std::make_pair(0u, 1u));
ENSURE(na[1] == std::make_pair(4u, 6u));
ENSURE(na[2] == std::make_pair(9u, 10u));
// ~([0,4]) = [5,10]
auto b = range_predicate::range(0, 4, M);
auto nb = ~b;
ENSURE(nb.num_ranges() == 1);
ENSURE(nb[0] == std::make_pair(5u, 10u));
// ~([5,10]) = [0,4]
auto cnb = ~nb;
ENSURE(cnb == b);
}
// Exhaustively verify the lattice / de-Morgan laws on a small domain
// by enumerating every possible subset (bitmask).
void test_exhaustive_laws() {
unsigned const M = 5; // 6 characters -> 64 subsets
unsigned const N = 1u << (M + 1);
for (unsigned i = 0; i < N; ++i) {
range_predicate A = from_mask(i, M);
ENSURE(to_mask(A) == i);
// ~ ~ A == A
ENSURE(~~A == A);
// A | ~A == top
ENSURE((A | ~A).is_top());
// A & ~A == empty
ENSURE((A & ~A).is_empty());
// cardinality matches popcount
unsigned pop = 0;
for (unsigned k = 0; k <= M; ++k) if ((i >> k) & 1u) ++pop;
ENSURE(A.cardinality() == pop);
}
for (unsigned i = 0; i < N; ++i) {
range_predicate A = from_mask(i, M);
for (unsigned j = 0; j < N; ++j) {
range_predicate B = from_mask(j, M);
// Bitmask reference semantics.
ENSURE(to_mask(A | B) == (i | j));
ENSURE(to_mask(A & B) == (i & j));
ENSURE(to_mask(A - B) == (i & ~j & ((1u << (M + 1)) - 1u)));
ENSURE(to_mask(A ^ B) == (i ^ j));
// de-Morgan
ENSURE(~(A | B) == (~A & ~B));
ENSURE(~(A & B) == (~A | ~B));
// Commutativity
ENSURE((A | B) == (B | A));
ENSURE((A & B) == (B & A));
// (A - B) == A & ~B
ENSURE((A - B) == (A & ~B));
// (A ^ B) == (A | B) - (A & B)
ENSURE((A ^ B) == ((A | B) - (A & B)));
// Extensional equality is reflexive on equal masks.
if (i == j) {
ENSURE(A == B);
ENSURE(A.hash() == B.hash());
}
}
}
}
void test_total_order_strict() {
unsigned const M = 5;
unsigned const N = 1u << (M + 1);
// Strict total order: for any distinct A, B exactly one of A<B, B<A holds.
for (unsigned i = 0; i < N; ++i) {
range_predicate A = from_mask(i, M);
ENSURE(!(A < A));
for (unsigned j = i + 1; j < N; ++j) {
range_predicate B = from_mask(j, M);
bool lt = A < B;
bool gt = B < A;
ENSURE(lt != gt);
ENSURE(lt || gt);
}
}
}
void test_display() {
std::ostringstream oss;
oss << range_predicate::empty(31);
ENSURE(oss.str() == "[]");
oss.str("");
oss << range_predicate::range(3, 7, 31);
ENSURE(oss.str() == "[3-7]");
oss.str("");
oss << range_predicate::singleton(9, 31);
ENSURE(oss.str() == "[9]");
oss.str("");
auto p = range_predicate::range(0, 2, 31) | range_predicate::singleton(5, 31);
oss << p;
ENSURE(oss.str() == "[0-2,5]");
}
}
void tst_range_predicate() {
test_factories();
test_equality_and_order();
test_union_intersection_hand();
test_complement_hand();
test_exhaustive_laws();
test_total_order_strict();
test_display();
std::cout << "range_predicate unit tests passed\n";
}