#ifndef TYPES_HPP
#define TYPES_HPP
#include <cstdint>
#include <limits>
#include <ostream>
#include <set>
#include <map>
#include "./subsat_config.hpp"
#include "./vector_map.hpp"
#include "Debug/Assertion.hpp"
namespace subsat {
using std::uint8_t;
using std::uint32_t;
template <typename T>
using allocator_type = std::allocator<T>;
using string = std::basic_string<char, std::char_traits<char>, allocator_type<char>>;
template <typename T>
using vector = std::vector<T, allocator_type<T>>;
template <typename K, typename T>
using vector_map = subsat::vector_map_t<K, T, allocator_type<T>>;
#ifndef NDEBUG
template <typename Key, typename Compare = std::less<Key>>
using set = typename ::std::set<Key, Compare, allocator_type<Key>>;
template <typename Key, typename T, typename Compare = std::less<Key>>
using map = typename ::std::map<Key, T, Compare, allocator_type<std::pair<Key const, T>>>;
#endif
class Lit;
class Solver;
enum class Value : signed char {
False = -1,
Unassigned = 0,
True = 1,
};
constexpr Value operator~(Value v) {
return static_cast<Value>(-static_cast<signed char>(v));
}
std::ostream& operator<<(std::ostream& os, Value v);
enum class Result : int {
Unknown = 0,
Sat = 10,
Unsat = 20,
};
std::ostream& operator<<(std::ostream& os, Result r);
class Var final {
public:
using index_type = std::uint32_t;
explicit constexpr Var(index_type index) noexcept
: m_index{index}
{
}
[[nodiscard]] constexpr index_type index() const noexcept
{
return m_index;
}
[[nodiscard]] static constexpr index_type max_index() noexcept
{
return (1u << 31) - 2;
}
[[nodiscard]] static constexpr Var invalid() noexcept
{
return Var{std::numeric_limits<index_type>::max()};
}
[[nodiscard]] constexpr bool is_valid() const noexcept
{
return m_index <= max_index();
}
[[nodiscard]] constexpr Lit operator~() const noexcept;
private:
index_type m_index;
};
static_assert(Var::max_index() == static_cast<uint32_t>(INT32_MAX - 1), "unexpected max variable index");
static_assert(Var::max_index() < Var::invalid().index(), "valid variable indices overlap with invalid sentinel value");
static_assert(!Var::invalid().is_valid(), "");
static_assert(Var{Var::max_index()}.is_valid(), "");
static_assert(std::is_nothrow_copy_constructible<Var>::value, "");
static_assert(std::is_nothrow_copy_assignable<Var>::value, "");
static_assert(std::is_nothrow_move_constructible<Var>::value, "");
static_assert(std::is_nothrow_move_assignable<Var>::value, "");
static_assert(std::is_trivially_destructible<Var>::value, "");
[[nodiscard]] static constexpr bool operator==(Var lhs, Var rhs) noexcept
{
return lhs.index() == rhs.index();
}
[[nodiscard]] static constexpr bool operator!=(Var lhs, Var rhs) noexcept
{
return !operator==(lhs, rhs);
}
#ifndef NDEBUG
[[nodiscard]] static constexpr bool operator<(Var lhs, Var rhs) noexcept
{
return lhs.index() < rhs.index();
}
#endif
std::ostream& operator<<(std::ostream& os, Var var);
class Lit final {
public:
using index_type = Var::index_type;
private:
friend class Constraint;
Lit() noexcept = default;
explicit constexpr Lit(index_type index) noexcept
: m_index{index}
{
}
public:
constexpr Lit(Var var, bool positive = true) noexcept
: Lit{2 * var.index() + static_cast<index_type>(!positive)}
{
}
[[nodiscard]] static constexpr Lit from_index(index_type index) noexcept
{
ASS(index <= Lit::max_index());
return Lit{index};
}
[[nodiscard]] static constexpr Lit pos(Var var) noexcept
{
return Lit{var, true};
}
[[nodiscard]] static constexpr Lit neg(Var var) noexcept
{
return Lit{var, false};
}
[[nodiscard]] constexpr index_type index() const noexcept
{
return m_index;
}
[[nodiscard]] static constexpr index_type max_index() noexcept
{
static_assert(Var::max_index() < (std::numeric_limits<index_type>::max() - 1) / 2, "cannot represent all literals");
return 2 * Var::max_index() + 1;
}
[[nodiscard]] static constexpr Lit invalid() noexcept
{
return Lit{std::numeric_limits<index_type>::max()};
}
[[nodiscard]] constexpr bool is_valid() const noexcept
{
return m_index <= max_index();
}
[[nodiscard]] constexpr bool is_positive() const noexcept
{
return (m_index & 1) == 0;
}
[[nodiscard]] constexpr bool is_negative() const noexcept
{
return !is_positive();
}
[[nodiscard]] constexpr Lit operator~() const noexcept
{
return Lit{m_index ^ 1};
}
[[nodiscard]] constexpr Var var() const noexcept
{
return Var{m_index / 2};
}
private:
index_type m_index;
};
static_assert(Lit::max_index() < Lit::invalid().index(), "valid literal indices overlap with invalid sentinel value");
static_assert(!Lit::invalid().is_valid(), "");
static_assert(Lit{Var{0}, true}.index() == 0, "");
static_assert(Lit{Var{0}, false}.index() == 1, "");
static_assert(Lit{Var{Var::max_index()}, true}.is_valid(), "");
static_assert(Lit{Var{Var::max_index()}, false}.is_valid(), "");
static_assert(std::is_nothrow_copy_constructible<Lit>::value, "");
static_assert(std::is_nothrow_copy_assignable<Lit>::value, "");
static_assert(std::is_nothrow_move_constructible<Lit>::value, "");
static_assert(std::is_nothrow_move_assignable<Lit>::value, "");
static_assert(std::is_trivially_destructible<Lit>::value, "");
[[nodiscard]] static constexpr bool operator==(Lit lhs, Lit rhs) noexcept
{
return lhs.index() == rhs.index();
}
[[nodiscard]] static constexpr bool operator!=(Lit lhs, Lit rhs) noexcept
{
return !operator==(lhs, rhs);
}
#ifndef NDEBUG
[[nodiscard]] static constexpr bool operator<(Lit lhs, Lit rhs) noexcept
{
return lhs.index() < rhs.index();
}
#endif
std::ostream& operator<<(std::ostream& os, Lit lit);
[[nodiscard]] constexpr Lit Var::operator~() const noexcept
{
return Lit{*this, false};
}
template <> struct DefaultIndex<Var> {
using type = IndexMember<Var>;
};
template <> struct DefaultIndex<Lit> {
using type = IndexMember<Lit>;
};
}
#endif