Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separated integers from rationals and added simple FastInteger wrapper #751

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-files
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
./src/cnfizers/Tseitin.h

./src/common/numbers/Integer.h
./src/common/numbers/Number.cc
./src/common/numbers/Number.h
./src/common/numbers/Real.h
./src/common/ApiException.h
./src/common/FlaPartitionMap.cc
./src/common/FlaPartitionMap.h
./src/common/IColor.h
./src/common/FunUtils.h
./src/common/InternalException.h
./src/common/PartitionInfo.cc
./src/common/PartitionInfo.h
Expand Down
56 changes: 56 additions & 0 deletions src/common/FunUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef OPENSMT_FUNUTILS_H
#define OPENSMT_FUNUTILS_H

#include <compare>
#include <concepts>
#include <functional>
#include <utility>

#define FORWARD(arg) std::forward<decltype(arg)>(arg)

namespace opensmt {
template<typename Op>
struct CompoundAssignOf;

template<>
struct CompoundAssignOf<std::plus<void>> {
constexpr auto & operator()(auto & lhs, auto const & rhs) const {
lhs += rhs;
return lhs;
}
};
template<>
struct CompoundAssignOf<std::minus<void>> {
constexpr auto & operator()(auto & lhs, auto const & rhs) const {
lhs -= rhs;
return lhs;
}
};
template<>
struct CompoundAssignOf<std::multiplies<void>> {
constexpr auto & operator()(auto & lhs, auto const & rhs) const {
lhs *= rhs;
return lhs;
}
};
template<>
struct CompoundAssignOf<std::divides<void>> {
constexpr auto & operator()(auto & lhs, auto const & rhs) const {
lhs *= rhs;
return lhs;
}
};

template<typename O = std::strong_ordering>
inline O intToOrdering(std::integral auto cmp) {
if (cmp == 0) {
return O::equivalent;
} else if (cmp < 0) {
return O::less;
} else {
return O::greater;
}
}
} // namespace opensmt

#endif // OPENSMT_FUNUTILS_H
6 changes: 6 additions & 0 deletions src/common/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class span {
T * _beg;
uint32_t _size;
};

// This is useful e.g. for std::visit(..., std::variant)
template<typename... Ts>
struct Overload : Ts... {
using Ts::operator()...;
};
} // namespace opensmt

#endif // OPENSMT_TYPEUTILS_H
3 changes: 3 additions & 0 deletions src/common/numbers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
target_sources(common
PUBLIC
"${CMAKE_CURRENT_LIST_DIR}/FastInteger.cc"
"${CMAKE_CURRENT_LIST_DIR}/FastRational.cc"
"${CMAKE_CURRENT_LIST_DIR}/Integer.h"
"${CMAKE_CURRENT_LIST_DIR}/Number.cc"
"${CMAKE_CURRENT_LIST_DIR}/Number.h"
"${CMAKE_CURRENT_LIST_DIR}/Real.h"
PRIVATE
Expand All @@ -11,6 +13,7 @@ PRIVATE
install(FILES
${CMAKE_CURRENT_LIST_DIR}/Integer.h
${CMAKE_CURRENT_LIST_DIR}/Number.h
${CMAKE_CURRENT_LIST_DIR}/FastInteger.h
${CMAKE_CURRENT_LIST_DIR}/FastRational.h
${CMAKE_CURRENT_LIST_DIR}/Real.h
${CMAKE_CURRENT_LIST_DIR}/NumberUtils.h
Expand Down
88 changes: 88 additions & 0 deletions src/common/numbers/FastInteger.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "FastInteger.h"

namespace opensmt {
FastInteger::FastInteger(const char* str, const int base) : FastRational(str, base) {
assert(isIntegerValue());
}

FastInteger gcd(FastInteger const & a, FastInteger const & b)
{
assert(a.isIntegerValue() and b.isIntegerValue());
if (a.wordPartValid() && b.wordPartValid()) {
// Refers to FastRational.h:gcd
return FastInteger(gcd(a.num, b.num));
}
else {
a.ensure_mpq_valid();
b.ensure_mpq_valid();
mpz_gcd(FastInteger::mpz(), mpq_numref(a.mpq), mpq_numref(b.mpq));
return FastInteger(FastInteger::mpz());
}
}

FastInteger lcm(FastInteger const & a, FastInteger const & b)
{
assert(a.isIntegerValue() and b.isIntegerValue());
if (a.wordPartValid() && b.wordPartValid()) {
// Refers to FastRational.h:lcm
return lcm(a.num, b.num);
}
else {
a.ensure_mpq_valid();
b.ensure_mpq_valid();
mpz_lcm(FastInteger::mpz(), mpq_numref(a.mpq), mpq_numref(b.mpq));
return FastInteger(FastInteger::mpz());
}
}

// The quotient of n and d using the fast rationals.
// Divide n by d, forming a quotient q.
// Rounds q down towards -infinity, and q will satisfy n = q*d + r for some 0 <= abs(r) <= abs(d)
FastInteger fastint_fdiv_q(FastInteger const & n, FastInteger const & d) {
assert(n.isIntegerValue() && d.isIntegerValue());
if (n.wordPartValid() && d.wordPartValid()) {
word num = n.num;
word den = d.num;
word quo;
if (num == INT_MIN) // The abs is guaranteed to overflow. Otherwise this is always fine
goto overflow;
// After this -INT_MIN+1 <= numerator <= INT_MAX, and therefore the result always fits into a word.
quo = num / den;
if (num % den != 0 && ((num < 0 && den >=0) || (den < 0 && num >= 0))) // The result should be negative
quo--; // INT_MAX-1 >= quo >= -INT_MIN

return quo;
}
overflow:
n.ensure_mpq_valid();
d.ensure_mpq_valid();
mpz_fdiv_q(FastInteger::mpz(), mpq_numref(n.mpq), mpq_numref(d.mpq));
return FastInteger(FastInteger::mpz());
}

//void mpz_divexact (mpz_ptr, mpz_srcptr, mpz_srcptr);
FastInteger divexact(FastInteger const & n, FastInteger const & d) {
assert(d != 0);
assert(n.isIntegerValue() && d.isIntegerValue());
if (n.wordPartValid() && d.wordPartValid()) {
word num = n.num;
word den = d.num;
word quo;
if (den != 0){
quo = num / den;
return quo;
}
else {
// Division by zero
assert(false);
return FastInteger(0);
}
} else {
assert(n.mpqPartValid() || d.mpqPartValid());
n.ensure_mpq_valid();
d.ensure_mpq_valid();
mpz_divexact(FastInteger::mpz(), mpq_numref(n.mpq), mpq_numref(d.mpq));
return FastInteger(FastInteger::mpz());
}
}
}
121 changes: 121 additions & 0 deletions src/common/numbers/FastInteger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//
// Created by Tomas Kolarik in 08/2024.
//

#ifndef OPENSMT_FAST_INTEGER_H
#define OPENSMT_FAST_INTEGER_H

#include "FastRational.h"

#include <concepts>

namespace opensmt {
// TODO: inefficient, rational representation & uses mpq instead of mpz
class FastInteger : public FastRational {
public:
using FastRational::FastRational;
explicit FastInteger(FastRational rat) : FastRational(std::move(rat)) { assert(isIntegerValue()); }
explicit FastInteger(char const *, int const base = 10);
FastInteger & operator=(FastRational const & other) {
assert(this != &other);
assert(other.isIntegerValue());
FastRational::operator=(other);
return *this;
}
FastInteger & operator=(FastRational && other) {
assert(other.isIntegerValue());
FastRational::operator=(std::move(other));
return *this;
}
FastInteger & operator=(std::integral auto i) { return operator=(FastInteger(i)); }

FastInteger ceil() const noexcept { return *this; }
FastInteger floor() const noexcept { return *this; }

FastInteger operator-() const { return static_cast<FastInteger &&>(FastRational::operator-()); }
FastInteger operator+(FastInteger const & b) const {
return static_cast<FastInteger &&>(FastRational::operator+(b));
}
FastInteger operator-(FastInteger const & b) const {
return static_cast<FastInteger &&>(FastRational::operator-(b));
}
FastInteger operator*(FastInteger const & b) const {
return static_cast<FastInteger &&>(FastRational::operator*(b));
}
FastInteger & operator+=(FastInteger const & b) {
FastRational::operator+=(b);
return *this;
}
FastInteger & operator-=(FastInteger const & b) {
FastRational::operator-=(b);
return *this;
}
FastInteger & operator*=(FastInteger const & b) {
FastRational::operator*=(b);
return *this;
}
FastInteger & operator+=(std::integral auto i) { return operator+=(FastInteger(i)); }
FastInteger & operator-=(std::integral auto i) { return operator-=(FastInteger(i)); }
FastInteger & operator*=(std::integral auto i) { return operator*=(FastInteger(i)); }
FastRational & operator+=(FastRational const &) = delete;
FastRational & operator-=(FastRational const &) = delete;
FastRational & operator*=(FastRational const &) = delete;

FastRational operator/(FastInteger const & b) const { return FastRational::operator/(b); }
void operator/=(FastInteger const &) = delete;
FastRational & operator/=(FastRational const &) = delete;

// The return value will have the sign of d
FastInteger operator%(FastInteger const & d) const {
assert(isIntegerValue() && d.isIntegerValue());
if (wordPartValid() && d.wordPartValid()) {
uword w = absVal(num % d.num); // Largest value is absVal(INT_MAX % INT_MIN) = INT_MAX
return (word)(d.num > 0 ? w : -w); // No overflow since 0 <= w <= INT_MAX
}
FastRational r = operator/(d);
auto i = FastInteger(r.floor());
return operator-(i * d);
}
FastInteger & operator%=(FastInteger const & d) {
//+ it would be more efficient the other way around
return operator=(operator%(d));
}

std::optional<word> tryGetValue() const {
if (!wordPartValid()) return {};
return num;
}

private:
FastInteger(std::integral auto, std::integral auto) = delete;

using FastRational::get_d;
using FastRational::get_den;
using FastRational::get_num;
using FastRational::tryGetNumDen;

friend FastInteger gcd(FastInteger const &, FastInteger const &);
friend FastInteger lcm(FastInteger const &, FastInteger const &);
friend FastInteger fastint_fdiv_q(FastInteger const &, FastInteger const &);
friend FastInteger divexact(FastInteger const &, FastInteger const &);
};

static_assert(!std::integral<FastInteger>);

// The result could not fit into integer -> FastInteger
template<std::integral integer>
FastInteger lcm(integer a, integer b) {
if (a == 0) return 0;
if (b == 0) return 0;
FastRational rat = (b > a) ? FastRational(b / gcd(a, b)) * a : FastRational(a / gcd(a, b)) * b;
assert(rat.isIntegerValue());
return static_cast<FastInteger&&>(rat);
}

FastInteger gcd(FastInteger const &, FastInteger const &);
FastInteger lcm(FastInteger const &, FastInteger const &);
FastInteger fastint_fdiv_q(FastInteger const & n, FastInteger const & d);
FastInteger divexact(FastInteger const & n, FastInteger const & d);
} // namespace opensmt

#endif // OPENSMT_FAST_INTEGER_H
Loading