use std::num::NonZero;
use pindakaas::Var as RawVar;
use crate::{
IntSet, IntVal,
actions::{
BoolInitActions, BoolInspectionActions, InitActions, IntInitActions, IntInspectionActions,
IntPropCond, ReasoningContext, ReasoningEngine,
},
solver::{
IntLitMeaning,
activation_list::ActivationAction,
decision::Decision,
engine::{AdvRef, AdvisorDef, Engine, PropRef, State},
queue::PriorityLevel,
view::{View, boolean::BoolView, integer::IntView},
},
views::{LinearBoolView, LinearView, OffsetView},
};
#[derive(Debug)]
pub struct InitializationContext<'a> {
state: &'a mut State,
prop: PropRef,
priority: PriorityLevel,
semantic_enqueue: bool,
decision_enqueue: Option<bool>,
pub(crate) observed_variables: Vec<RawVar>,
}
impl BoolInitActions<InitializationContext<'_>> for Decision<bool> {
fn advise_when_fixed(&self, ctx: &mut InitializationContext<'_>, data: u64) {
if self.val(ctx.state).is_some() {
return;
}
ctx.add_lit_advisor(*self, data, false);
}
fn enqueue_when_fixed(&self, ctx: &mut InitializationContext<'_>) {
if self.val(ctx.state).is_some() {
ctx.semantic_enqueue = true;
} else {
ctx.state
.bool_activation
.entry(self.0.var())
.or_insert_with(|| {
ctx.observed_variables.push(self.0.var());
Vec::new()
})
.push(ActivationAction::Enqueue(ctx.prop).into());
}
}
}
impl BoolInspectionActions<InitializationContext<'_>> for Decision<bool> {
fn val(&self, ctx: &InitializationContext<'_>) -> Option<bool> {
self.val(ctx.state)
}
}
impl IntInitActions<InitializationContext<'_>> for Decision<IntVal> {
fn advise_when(&self, ctx: &mut InitializationContext<'_>, condition: IntPropCond, data: u64) {
View::from(*self).advise_when(ctx, condition, data);
}
fn enqueue_when(&self, ctx: &mut InitializationContext<'_>, condition: IntPropCond) {
if self.val(ctx.state).is_some() {
ctx.semantic_enqueue = true;
return;
}
if condition != IntPropCond::Fixed {
ctx.semantic_enqueue = true;
}
ctx.state.int_activation[self.idx()].add(ActivationAction::Enqueue(ctx.prop), condition);
}
}
impl IntInspectionActions<InitializationContext<'_>> for Decision<IntVal> {
fn bounds(&self, ctx: &InitializationContext<'_>) -> (IntVal, IntVal) {
self.bounds(ctx.state)
}
fn domain(&self, ctx: &InitializationContext<'_>) -> IntSet {
self.domain(ctx.state)
}
fn in_domain(&self, ctx: &InitializationContext<'_>, val: IntVal) -> bool {
self.in_domain(ctx.state, val)
}
fn lit_meaning(
&self,
ctx: &InitializationContext<'_>,
lit: View<bool>,
) -> Option<IntLitMeaning> {
self.lit_meaning(ctx.state, lit)
}
fn max(&self, ctx: &InitializationContext<'_>) -> IntVal {
self.max(ctx.state)
}
fn max_lit(&self, ctx: &InitializationContext<'_>) -> View<bool> {
self.max_lit(ctx.state)
}
fn min(&self, ctx: &InitializationContext<'_>) -> IntVal {
self.min(ctx.state)
}
fn min_lit(&self, ctx: &InitializationContext<'_>) -> View<bool> {
self.min_lit(ctx.state)
}
fn try_lit(
&self,
ctx: &InitializationContext<'_>,
meaning: IntLitMeaning,
) -> Option<View<bool>> {
self.try_lit(ctx.state, meaning)
}
fn val(&self, ctx: &InitializationContext<'_>) -> Option<IntVal> {
self.val(ctx.state)
}
}
impl InitializationContext<'_> {
fn add_lit_advisor(&mut self, lit: Decision<bool>, data: u64, bool2int: bool) {
self.state.advisors.push(AdvisorDef {
bool2int,
data,
negated: false,
propagator: self.prop,
});
let adv = AdvRef::new(self.state.advisors.len() - 1);
self.state
.bool_activation
.entry(lit.0.var())
.or_insert_with(|| {
self.observed_variables.push(lit.0.var());
Vec::new()
})
.push(ActivationAction::<_, PropRef>::Advise(adv).into());
}
}
impl<'a> InitializationContext<'a> {
pub(crate) fn enqueue(&self, from_model: bool) -> bool {
if let Some(enqueue) = self.decision_enqueue {
enqueue
} else if !from_model {
self.semantic_enqueue
} else {
false
}
}
pub(crate) fn new(state: &'a mut State, prop: PropRef) -> Self {
Self {
state,
prop,
priority: PriorityLevel::Medium,
semantic_enqueue: false,
decision_enqueue: None,
observed_variables: Vec::new(),
}
}
pub(crate) fn priority(&self) -> PriorityLevel {
self.priority
}
}
impl InitActions for InitializationContext<'_> {
fn advise_on_backtrack(&mut self) {
self.state.notify_of_backtrack.push(self.prop);
}
fn enqueue_now(&mut self, option: bool) {
self.decision_enqueue = Some(option);
}
fn set_priority(&mut self, priority: PriorityLevel) {
self.priority = priority;
}
}
impl ReasoningContext for InitializationContext<'_> {
type Atom = <Engine as ReasoningEngine>::Atom;
type Conflict = <Engine as ReasoningEngine>::Conflict;
}
impl IntInitActions<InitializationContext<'_>> for IntVal {
fn advise_when(&self, _: &mut InitializationContext<'_>, _: IntPropCond, _: u64) {
}
fn enqueue_when(&self, ctx: &mut InitializationContext<'_>, _: IntPropCond) {
ctx.semantic_enqueue = true;
}
}
impl<'a> IntInitActions<InitializationContext<'a>>
for LinearBoolView<NonZero<IntVal>, IntVal, Decision<bool>>
{
fn advise_when(&self, ctx: &mut InitializationContext<'a>, _: IntPropCond, data: u64) {
ctx.add_lit_advisor(self.var, data, true);
}
fn enqueue_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond) {
if condition != IntPropCond::Fixed {
ctx.semantic_enqueue = true;
}
self.var.enqueue_when_fixed(ctx);
}
}
impl<'a> IntInitActions<InitializationContext<'a>>
for LinearView<NonZero<IntVal>, IntVal, Decision<IntVal>>
{
fn advise_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond, data: u64) {
let negated = self.scale.is_negative();
let cond = match condition {
IntPropCond::LowerBound if self.scale.is_negative() => IntPropCond::UpperBound,
IntPropCond::UpperBound if self.scale.is_negative() => IntPropCond::LowerBound,
_ => condition,
};
ctx.state.advisors.push(AdvisorDef {
bool2int: false,
data,
negated,
propagator: ctx.prop,
});
let adv = AdvRef::new(ctx.state.advisors.len() - 1);
ctx.state.int_activation[self.var.idx()]
.add(ActivationAction::<_, PropRef>::Advise(adv), cond);
}
fn enqueue_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond) {
let condition = match condition {
IntPropCond::LowerBound if self.scale.is_negative() => IntPropCond::UpperBound,
IntPropCond::UpperBound if self.scale.is_negative() => IntPropCond::LowerBound,
_ => condition,
};
self.var.enqueue_when(ctx, condition);
}
}
impl<'a, Var> IntInitActions<InitializationContext<'a>> for OffsetView<IntVal, Var>
where
Var: IntInitActions<InitializationContext<'a>>,
{
fn advise_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond, data: u64) {
self.var.advise_when(ctx, condition, data);
}
fn enqueue_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond) {
self.var.enqueue_when(ctx, condition);
}
}
impl BoolInitActions<InitializationContext<'_>> for View<bool> {
fn advise_when_fixed(&self, ctx: &mut InitializationContext<'_>, data: u64) {
match self.0 {
BoolView::Lit(lit) => lit.advise_when_fixed(ctx, data),
BoolView::Const(_) => {
}
}
}
fn enqueue_when_fixed(&self, ctx: &mut InitializationContext<'_>) {
match self.0 {
BoolView::Lit(lit) => lit.enqueue_when_fixed(ctx),
BoolView::Const(_) => {
ctx.semantic_enqueue = true;
}
}
}
}
impl<'a> IntInitActions<InitializationContext<'a>> for View<IntVal> {
fn advise_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond, data: u64) {
match self.0 {
IntView::Linear(lin) => {
lin.advise_when(ctx, condition, data);
}
IntView::Const(_) => {
}
IntView::Bool(lin) => {
lin.advise_when(ctx, condition, data);
}
}
}
fn enqueue_when(&self, ctx: &mut InitializationContext<'a>, condition: IntPropCond) {
match self.0 {
IntView::Const(_) => {
ctx.semantic_enqueue = true;
}
IntView::Linear(lin) => {
lin.enqueue_when(ctx, condition);
}
IntView::Bool(lin) => {
lin.enqueue_when(ctx, condition);
}
}
}
}
impl BoolInitActions<InitializationContext<'_>> for bool {
fn advise_when_fixed(&self, _: &mut InitializationContext<'_>, _: u64) {
}
fn enqueue_when_fixed(&self, ctx: &mut InitializationContext<'_>) {
ctx.semantic_enqueue = true;
}
}