diff --git a/doz/src/constraint.rs b/doz/src/constraint.rs new file mode 100644 index 0000000..5e805a7 --- /dev/null +++ b/doz/src/constraint.rs @@ -0,0 +1,103 @@ +pub mod resolution; + +use std::collections::{HashMap, VecDeque}; + +use crate::domain::{Domain, DomainRange}; + +pub struct Indexical +{ + pub variable: usize, + pub dependencies: Vec, + + #[allow(clippy::type_complexity)] + pub propagator: Box DomainRange>, +} + +impl Indexical +{ + pub fn new(variable: usize, dependencies: &[usize], propagator: T) -> Indexical + where + T: Fn(&[DomainRange]) -> DomainRange + 'static, + { + Indexical { + variable, + dependencies: dependencies.to_vec(), + propagator: Box::new(propagator), + } + } +} + +pub struct ClpContext +{ + pub variables: usize, + pub domains: HashMap, + pub used_by: HashMap>, + pub constraints: HashMap>, +} + +impl ClpContext +{ + pub fn new() -> Self + { + ClpContext { + variables: 0, + domains: HashMap::new(), + used_by: HashMap::new(), + constraints: HashMap::new(), + } + } + + pub fn get_var(&mut self) -> usize + { + let k = self.variables; + self.variables += 1; + self.domains.insert(k, Domain::from(..)); + self.used_by.insert(k, vec![]); + k + } + + pub fn insert_constraint(&mut self, indexical: Indexical) + { + let vec = self.constraints.entry(indexical.variable).or_insert(vec![]); + for x in indexical.dependencies.iter() + { + self.used_by.get_mut(x).unwrap().push(indexical.variable); + } + vec.push(indexical); + } + + pub fn prune(&mut self) -> bool + { + let mut queue = VecDeque::from_iter(0..self.variables); + + while !queue.is_empty() + { + // Apply unary constraints + let var = queue.pop_front().unwrap(); + let constraints = self.constraints.get(&var); + if constraints.is_none() + { + continue; + } + let constraints = constraints.unwrap(); + + for c in constraints.iter() + { + if c.dependencies.is_empty() + { + // Is unary constraint + let domain = self.domains.get(&var).unwrap(); + } + } + } + todo!(); + } +} + +impl Default for ClpContext +{ + fn default() -> Self + { + Self::new() + } +} diff --git a/doz/src/constraint/resolution.rs b/doz/src/constraint/resolution.rs new file mode 100644 index 0000000..e69de29 diff --git a/doz/src/domain.rs b/doz/src/domain.rs index 09aefe2..7176cb8 100644 --- a/doz/src/domain.rs +++ b/doz/src/domain.rs @@ -1,9 +1,10 @@ -pub mod simple_range; -pub mod union; +pub mod domain_ops; +pub mod range_ops; use std::fmt::Display; use std::ops::Range; use std::ops::RangeFrom; +use std::ops::RangeFull; use std::ops::RangeTo; pub struct Domain @@ -15,16 +16,6 @@ pub struct Domain /// $$\{x \in [\text{start}; \text{end}[ | x \equiv \text{congruent} \text{mod} \text{modulo}}$$ #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct DomainRange -{ - pub start: LowerBound, - pub end: HigherBound, - - pub modulo: u64, - pub congruent: i64, -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct SimpleRange { pub start: LowerBound, pub end: HigherBound, @@ -70,23 +61,6 @@ impl DomainRange DomainRange { start: from, end: to, - modulo: 1, - congruent: 0, - } - } - - pub fn is_simple(&self) -> Option - { - if self.modulo <= 1 - { - Some(SimpleRange { - start: self.start, - end: self.end, - }) - } - else - { - None } } } @@ -101,6 +75,16 @@ impl From> for Domain } } +impl From for Domain +{ + fn from(value: RangeFull) -> Self + { + Domain { + ranges: vec![value.into()], + } + } +} + impl From> for Domain { fn from(value: RangeTo) -> Self @@ -148,6 +132,14 @@ impl From> for DomainRange } } +impl From for DomainRange +{ + fn from(_: RangeFull) -> Self + { + DomainRange::range(LowerBound::Infinity, HigherBound::Infinity) + } +} + impl Display for LowerBound { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result @@ -176,12 +168,7 @@ impl Display for DomainRange { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}..{}", self.start, self.end)?; - if self.modulo > 1 - { - write!(f, " ≡ {} [{}]", self.congruent, self.modulo)?; - } - Ok(()) + write!(f, "{}..{}", self.start, self.end) } } diff --git a/doz/src/domain/domain_ops.rs b/doz/src/domain/domain_ops.rs new file mode 100644 index 0000000..60f1e36 --- /dev/null +++ b/doz/src/domain/domain_ops.rs @@ -0,0 +1,90 @@ +use crate::domain::{Domain, DomainRange}; + +impl Domain +{ + pub fn intersection(&self, domain: &Domain) -> Domain + { + let mut i = 0; + let mut j = 0; + let mut stack = vec![]; + + while i < self.ranges.len() || j < domain.ranges.len() + { + if i < self.ranges.len() && j < domain.ranges.len() + { + let a = self.ranges[i]; + let b = domain.ranges[j]; + + if a.disjoint(&b) + { + if a.start < b.start + { + i += 1; + } + else + { + j += 1; + } + } + else + { + let inter = a.intersection(&b); + if let Some(range) = inter + { + stack.push(range); + }; + if a.end > b.end + { + i += 1; + } + else + { + j += 1; + } + } + } + else + { + break; + } + } + + Domain { ranges: stack } + } + + pub fn union(&self, domain: &Domain) -> Domain + { + let mut stack = self + .ranges + .iter() + .copied() + .chain(domain.ranges.iter().copied()) + .collect::>(); + + stack.sort_by(|a, b| b.start.cmp(&a.start)); + let mut ranges = vec![]; + + while !stack.is_empty() + { + if stack.len() >= 2 + { + let (a, b) = (stack.pop().unwrap(), stack.pop().unwrap()); + match a.union(&b) + { + crate::domain::UnionResult::Single(x) => stack.push(x), + crate::domain::UnionResult::Union(x, y) => + { + ranges.push(x); + stack.push(y); + } + } + } + else if stack.len() == 1 + { + ranges.push(stack.pop().unwrap()); + } + } + + Domain { ranges } + } +} diff --git a/doz/src/domain/simple_range.rs b/doz/src/domain/range_ops.rs similarity index 57% rename from doz/src/domain/simple_range.rs rename to doz/src/domain/range_ops.rs index e4190ce..d8cf4fc 100644 --- a/doz/src/domain/simple_range.rs +++ b/doz/src/domain/range_ops.rs @@ -1,54 +1,51 @@ -use std::ops::Range; -use std::ops::RangeFrom; -use std::ops::RangeFull; -use std::ops::RangeTo; +// Module for computing intersection of domains +use crate::domain::DomainRange; use crate::domain::HigherBound; use crate::domain::LowerBound; -use crate::domain::SimpleRange; use crate::domain::UnionResult; -impl SimpleRange +impl DomainRange { - pub fn union(&self, range: &SimpleRange) -> UnionResult + pub fn union(&self, range: &DomainRange) -> UnionResult { let (a, b) = (self.min_by_start(range), self.max_by_start(range)); match (a.end, b.start) { (HigherBound::Infinity, LowerBound::Infinity) => { - UnionResult::Single(SimpleRange::from(..)) + UnionResult::Single(DomainRange::from(..)) } - (HigherBound::Infinity, LowerBound::Bounded(_)) => UnionResult::Single(SimpleRange { + (HigherBound::Infinity, LowerBound::Bounded(_)) => UnionResult::Single(DomainRange { start: a.start, end: HigherBound::Infinity, }), - (HigherBound::Bounded(_), LowerBound::Infinity) => UnionResult::Single(SimpleRange { + (HigherBound::Bounded(_), LowerBound::Infinity) => UnionResult::Single(DomainRange { start: LowerBound::Infinity, end: b.end, }), (HigherBound::Bounded(c), LowerBound::Bounded(d)) if c < d => UnionResult::Union(a, b), - (HigherBound::Bounded(_), LowerBound::Bounded(_)) => UnionResult::Single(SimpleRange { + (HigherBound::Bounded(_), LowerBound::Bounded(_)) => UnionResult::Single(DomainRange { start: a.start, end: b.end, }), } } - pub fn intersection(&self, range: &SimpleRange) -> Option + pub fn intersection(&self, range: &DomainRange) -> Option { let (a, b) = (self.min_by_start(range), self.max_by_start(range)); match (a.end, b.start) { - (HigherBound::Infinity, LowerBound::Infinity) => Some(SimpleRange::from(..)), - (HigherBound::Infinity, LowerBound::Bounded(a)) => Some(SimpleRange::from(a..)), - (HigherBound::Bounded(a), LowerBound::Infinity) => Some(SimpleRange::from(..a)), + (HigherBound::Infinity, LowerBound::Infinity) => Some(DomainRange::from(..)), + (HigherBound::Infinity, LowerBound::Bounded(a)) => Some(DomainRange::from(a..)), + (HigherBound::Bounded(a), LowerBound::Infinity) => Some(DomainRange::from(..a)), (HigherBound::Bounded(a), LowerBound::Bounded(b)) if a <= b => None, - (HigherBound::Bounded(a), LowerBound::Bounded(b)) => Some(SimpleRange::from(a..b)), + (HigherBound::Bounded(a), LowerBound::Bounded(b)) => Some(DomainRange::from(a..b)), } } - pub fn without(&self, range: &SimpleRange) -> SimpleRange + pub fn without(&self, range: &DomainRange) -> DomainRange { match self.intersection(range) { @@ -61,7 +58,7 @@ impl SimpleRange } } - pub fn symetrical_difference(&self, range: &SimpleRange) -> Option> + pub fn symetrical_difference(&self, range: &DomainRange) -> Option> { match self.intersection(range) { @@ -73,7 +70,25 @@ impl SimpleRange } } - pub fn min_by_start(&self, range: &SimpleRange) -> SimpleRange + pub fn disjoint(&self, range: &DomainRange) -> bool + { + self.intersection(range).is_none() + } + + pub fn included_in(&self, range: &DomainRange) -> bool + { + if let UnionResult::Single(x) = self.union(range) + && x == *range + { + true + } + else + { + false + } + } + + pub fn min_by_start(&self, range: &DomainRange) -> DomainRange { if self.start < range.start { @@ -85,7 +100,7 @@ impl SimpleRange } } - pub fn max_by_start(&self, range: &SimpleRange) -> SimpleRange + pub fn max_by_start(&self, range: &DomainRange) -> DomainRange { if self.start < range.start { @@ -97,57 +112,13 @@ impl SimpleRange } } - pub fn min_by_end(&self, range: &SimpleRange) -> SimpleRange + pub fn min_by_end(&self, range: &DomainRange) -> DomainRange { if self.end < range.end { *self } else { *range } } - pub fn max_by_end(&self, range: &SimpleRange) -> SimpleRange + pub fn max_by_end(&self, range: &DomainRange) -> DomainRange { if self.end < range.end { *range } else { *self } } } - -impl From> for SimpleRange -{ - fn from(value: Range) -> Self - { - SimpleRange { - start: LowerBound::Bounded(value.start), - end: HigherBound::Bounded(value.end), - } - } -} - -impl From> for SimpleRange -{ - fn from(value: RangeTo) -> Self - { - SimpleRange { - start: LowerBound::Infinity, - end: HigherBound::Bounded(value.end), - } - } -} - -impl From> for SimpleRange -{ - fn from(value: RangeFrom) -> Self - { - SimpleRange { - start: LowerBound::Bounded(value.start), - end: HigherBound::Infinity, - } - } -} - -impl From for SimpleRange -{ - fn from(_: RangeFull) -> Self - { - SimpleRange { - start: LowerBound::Infinity, - end: HigherBound::Infinity, - } - } -} diff --git a/doz/src/domain/union.rs b/doz/src/domain/union.rs deleted file mode 100644 index a8db2f3..0000000 --- a/doz/src/domain/union.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Module for computing intersection of domains - -use crate::domain::Domain; -use crate::domain::DomainRange; - -impl DomainRange -{ - pub fn union(&self, domain: &DomainRange) -> Domain - { - if let Some(simple_a) = self.is_simple() - && let Some(simple_b) = self.is_simple() - { - simple_a.union(&simple_b) - } - } -} diff --git a/doz/src/lib.rs b/doz/src/lib.rs index d7abca1..8871d95 100644 --- a/doz/src/lib.rs +++ b/doz/src/lib.rs @@ -1 +1,2 @@ +pub mod constraint; pub mod domain; diff --git a/doz/src/main.rs b/doz/src/main.rs index 487e411..db3758c 100644 --- a/doz/src/main.rs +++ b/doz/src/main.rs @@ -1,5 +1,7 @@ +use doz::constraint::Indexical; use doz::domain::Domain; use doz::domain::DomainRange; +use doz::indexical; fn main() { @@ -7,10 +9,13 @@ fn main() ranges: vec![DomainRange { start: doz::domain::LowerBound::Infinity, end: doz::domain::HigherBound::Infinity, - modulo: 2, - congruent: 0, }], }; + //let k = Indexical::new([Box::new(|a, b, c| a), Box::new(|a, b, c| b)]); + // + + let k = indexical![|[a, _b]| { a }, |[_a, b]| { b }]; + println!("{}", even); }