use std::ops::Not;
use enumset::EnumSet;
use pumpkin_checking::CheckerVariable;
use pumpkin_checking::IntExt;
use pumpkin_checking::VariableState;
use super::DomainId;
use super::IntegerVariable;
use super::TransformableVariable;
use crate::engine::Assignments;
use crate::engine::notifications::DomainEvent;
use crate::engine::notifications::OpaqueDomainEvent;
use crate::engine::notifications::Watchers;
use crate::engine::predicates::predicate::Predicate;
use crate::engine::predicates::predicate_constructor::PredicateConstructor;
use crate::engine::variables::AffineView;
use crate::propagation::EventDispatcher;
use crate::propagation::EventTarget;
use crate::propagation::LocalId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Literal {
integer_variable: AffineView<DomainId>,
}
impl Literal {
pub fn new(domain_id: DomainId) -> Literal {
Literal {
integer_variable: domain_id.scaled(1),
}
}
pub fn get_integer_variable(&self) -> AffineView<DomainId> {
self.integer_variable
}
pub fn get_true_predicate(&self) -> Predicate {
self.lower_bound_predicate(1)
}
pub fn get_false_predicate(&self) -> Predicate {
self.upper_bound_predicate(0)
}
}
impl Not for Literal {
type Output = Literal;
fn not(self) -> Self::Output {
Literal {
integer_variable: self.integer_variable.scaled(-1).offset(1),
}
}
}
macro_rules! forward {
(
$field:ident,
fn $(<$($lt:lifetime),+>)? $name:ident(
& $($lt_self:lifetime)? self,
$($param_name:ident : $param_type:ty),*
) -> $return_type:ty
$(where $($where_clause:tt)*)?
) => {
fn $name$(<$($lt),+>)?(
& $($lt_self)? self,
$($param_name: $param_type),*
) -> $return_type $(where $($where_clause)*)? {
self.$field.$name($($param_name),*)
}
}
}
impl EventTarget for Literal {
fn register(
&self,
registration: &mut impl EventDispatcher,
events: EnumSet<DomainEvent>,
local_id: LocalId,
) {
self.integer_variable
.register(registration, events, local_id);
}
}
impl CheckerVariable<Predicate> for Literal {
forward!(integer_variable, fn does_atomic_constrain_self(&self, atomic: &Predicate) -> bool);
forward!(integer_variable, fn atomic_less_than(&self, value: i32) -> Predicate);
forward!(integer_variable, fn atomic_greater_than(&self, value: i32) -> Predicate);
forward!(integer_variable, fn atomic_not_equal(&self, value: i32) -> Predicate);
forward!(integer_variable, fn atomic_equal(&self, value: i32) -> Predicate);
forward!(integer_variable, fn induced_lower_bound(&self, variable_state: &VariableState<Predicate>) -> IntExt);
forward!(integer_variable, fn induced_upper_bound(&self, variable_state: &VariableState<Predicate>) -> IntExt);
forward!(integer_variable, fn induced_fixed_value(&self, variable_state: &VariableState<Predicate>) -> Option<i32>);
forward!(integer_variable, fn induced_domain_contains(&self, variable_state: &VariableState<Predicate>, value: i32) -> bool);
forward!(
integer_variable,
fn <'this, 'state> induced_holes(
&'this self,
variable_state: &'state VariableState<Predicate>
) -> impl Iterator<Item = i32> + 'state
where
'this: 'state,
);
forward!(
integer_variable,
fn <'this, 'state> iter_induced_domain(
&'this self,
variable_state: &'state VariableState<Predicate>
) -> Option<impl Iterator<Item = i32> + 'state>
where
'this: 'state,
);
}
impl IntegerVariable for Literal {
type AffineView = AffineView<Self>;
fn lower_bound(&self, assignment: &Assignments) -> i32 {
self.integer_variable.lower_bound(assignment)
}
fn lower_bound_at_trail_position(
&self,
assignment: &Assignments,
trail_position: usize,
) -> i32 {
self.integer_variable
.lower_bound_at_trail_position(assignment, trail_position)
}
fn upper_bound(&self, assignment: &Assignments) -> i32 {
self.integer_variable.upper_bound(assignment)
}
fn upper_bound_at_trail_position(
&self,
assignment: &Assignments,
trail_position: usize,
) -> i32 {
self.integer_variable
.upper_bound_at_trail_position(assignment, trail_position)
}
fn contains(&self, assignment: &Assignments, value: i32) -> bool {
self.integer_variable.contains(assignment, value)
}
fn contains_at_trail_position(
&self,
assignment: &Assignments,
value: i32,
trail_position: usize,
) -> bool {
self.integer_variable
.contains_at_trail_position(assignment, value, trail_position)
}
fn iterate_domain(&self, assignment: &Assignments) -> impl Iterator<Item = i32> {
self.integer_variable.iterate_domain(assignment)
}
fn unwatch_all(&self, watchers: &mut Watchers<'_>) {
self.integer_variable.unwatch_all(watchers)
}
fn unpack_event(&self, event: OpaqueDomainEvent) -> DomainEvent {
self.integer_variable.unpack_event(event)
}
fn watch_all_backtrack(&self, watchers: &mut Watchers<'_>, events: EnumSet<DomainEvent>) {
self.integer_variable.watch_all_backtrack(watchers, events)
}
fn get_holes_at_current_checkpoint(
&self,
assignments: &Assignments,
) -> impl Iterator<Item = i32> {
self.integer_variable
.get_holes_at_current_checkpoint(assignments)
}
fn get_holes(&self, assignments: &Assignments) -> impl Iterator<Item = i32> {
self.integer_variable.get_holes(assignments)
}
}
impl PredicateConstructor for Literal {
type Value = i32;
fn lower_bound_predicate(&self, bound: Self::Value) -> Predicate {
self.integer_variable.lower_bound_predicate(bound)
}
fn upper_bound_predicate(&self, bound: Self::Value) -> Predicate {
self.integer_variable.upper_bound_predicate(bound)
}
fn equality_predicate(&self, bound: Self::Value) -> Predicate {
self.integer_variable.equality_predicate(bound)
}
fn disequality_predicate(&self, bound: Self::Value) -> Predicate {
self.integer_variable.disequality_predicate(bound)
}
}
impl TransformableVariable<AffineView<Literal>> for Literal {
fn scaled(&self, scale: i32) -> AffineView<Literal> {
AffineView::new(*self, scale, 0)
}
fn offset(&self, offset: i32) -> AffineView<Literal> {
AffineView::new(*self, 1, offset)
}
}