pub mod constraint;
pub mod error;
pub mod expression;
use std::{
borrow::Cow,
collections::{HashMap, VecDeque},
fmt::{self, Display},
hash::Hash,
marker::PhantomData,
ops::RangeInclusive,
};
use itertools::Itertools;
use nom::{
branch::alt,
bytes::streaming::tag,
character::complete::{char, digit1},
combinator::{all_consuming, map, map_res, opt, recognize},
multi::many0,
sequence::{delimited, pair, preceded},
IResult, Parser,
};
pub use rangelist::RangeList;
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use crate::{
constraint::{Constraint, MetaConstraint},
error::UnrollError,
expression::{identifier, int, range, sequence, whitespace_seperated, Exp, IntExp},
};
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Array<Identifier = String, Var = VarRef<Identifier>> {
pub identifier: Identifier,
pub note: Option<String>,
pub size: Vec<usize>,
pub domains: Vec<(Vec<Var>, RangeList<IntVal>)>,
}
#[derive(Clone, Debug, Default, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum CombinationType {
#[default]
Lexico,
Pareto,
}
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug, Deserialize, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum FrameworkType {
#[default]
Csp,
Cop,
Wcsp,
Fcsp,
Qcsp,
QcspPlus,
Qcop,
QcopPlus,
Scsp,
Scop,
Qstr,
Tcsp,
Ncsp,
Ncop,
DisCsp,
DisWcsp,
}
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub enum Indexing {
Single(usize),
Range(usize, usize),
Full,
}
#[derive(Clone, PartialEq, Debug, Hash)]
pub struct Instance<Identifier = String, Var = VarRef<Identifier>> {
pub ty: FrameworkType,
pub variables: Vec<Variable<Identifier>>,
pub arrays: Vec<Array<Identifier, Var>>,
pub constraints: Vec<MetaConstraint<Identifier, Var>>,
pub objectives: Objectives<Identifier, Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
pub struct Instantiation<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(rename = "@type", default, skip_serializing_if = "Option::is_none")]
pub ty: Option<InstantiationType>,
#[serde(rename = "@cost", default, skip_serializing_if = "Option::is_none")]
pub cost: Option<IntVal>,
#[serde(
deserialize_with = "VarRef::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<Var>,
#[serde(
deserialize_with = "deserialize_opt_int_vals",
serialize_with = "serialize_opt_list"
)]
pub values: Vec<Option<IntVal>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum InstantiationType {
Solution,
Optimum,
}
pub trait IntoVar {
fn into_var(var: VarRef) -> Self;
}
pub type IntVal = i64;
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>",
serialize = "Identifier: Display"
))]
pub struct MetaInfo<Identifier> {
#[serde(
rename = "@id",
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_ident",
serialize_with = "serialize_ident"
)]
pub identifier: Option<Identifier>,
#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(
rename_all = "camelCase",
bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
)
)]
pub enum Objective<Identifier = String, Var = VarRef<Identifier>> {
#[serde(rename = "minimize")]
Minimize(ObjExp<Identifier, Var>),
#[serde(rename = "maximize")]
Maximize(ObjExp<Identifier, Var>),
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Objectives<Identifier = String, Var = VarRef<Identifier>> {
#[serde(default, rename = "@combination")]
pub combination: CombinationType,
#[serde(rename = "$value")]
pub objectives: Vec<Objective<Identifier, Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct ObjExp<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(alias = "@type", default)]
pub ty: ObjType,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub coeffs: Vec<IntVal>,
}
#[derive(Clone, Debug, Default, PartialEq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ObjType {
#[default]
Sum,
Minimum,
Maximum,
NValues,
Lex,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Placeholder {
Position(usize),
Remainder,
}
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub enum SimpleRef<Identifier> {
Ident(Identifier),
ArrayAccess(Identifier, Vec<usize>),
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>",
serialize = "Identifier: Display"
))]
pub struct Variable<Identifier = String> {
#[serde(
rename = "@id",
deserialize_with = "from_string",
serialize_with = "as_str"
)]
pub identifier: Identifier,
#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
#[serde(
rename = "$text",
deserialize_with = "deserialize_range_list",
serialize_with = "serialize_range_list"
)]
pub domain: RangeList<IntVal>,
}
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub enum VarRef<Identifier = String> {
Ident(Identifier),
ArrayAccess(Identifier, Vec<Indexing>),
Placeholder(Placeholder),
}
fn as_str<S: Serializer, I: Display>(value: &I, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&value.to_string())
}
fn collect_range_list<I: IntoIterator<Item = RangeInclusive<IntVal>>>(
iter: I,
) -> RangeList<IntVal> {
let mut r: Vec<_> = iter.into_iter().collect();
r.sort_by_key(|i| *i.start());
let mut it = r.into_iter();
let mut ranges = Vec::new();
let mut cur = it.next().unwrap();
for next in it {
if *cur.end() >= (next.start() - 1) {
cur = *cur.start()..=*next.end()
} else {
ranges.push(cur);
cur = next;
}
}
ranges.push(cur);
ranges.into_iter().collect()
}
fn deserialize_ident<'de, D: Deserializer<'de>, Identifier: From<String>>(
deserializer: D,
) -> Result<Option<Identifier>, D::Error> {
struct V<X>(PhantomData<X>);
impl<X: From<String>> Visitor<'_> for V<X> {
type Value = Option<X>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an identfier")
}
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
Ok(Some(s.trim().to_owned().into()))
}
}
let visitor = V::<Identifier>(PhantomData);
deserializer.deserialize_str(visitor)
}
fn deserialize_int_vals<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<IntVal>, D::Error> {
struct V;
impl Visitor<'_> for V {
type Value = Vec<IntVal>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a list of integers")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, vals) = all_consuming(whitespace_seperated(repeated(int)))
.parse(v)
.map_err(|_| E::custom(format!("invalid list of integers {v}")))?;
Ok(vals.into_iter().flatten().collect())
}
}
deserializer.deserialize_str(V)
}
fn deserialize_opt_int_vals<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<Option<IntVal>>, D::Error> {
struct V;
impl Visitor<'_> for V {
type Value = Vec<Option<IntVal>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a list of integers")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, vals) = all_consuming(whitespace_seperated(repeated(alt((
map(char('*'), |_| None),
map(int, Some),
)))))
.parse(v)
.map_err(|_| E::custom(format!("invalid list of integers {v}")))?;
Ok(vals.into_iter().flatten().collect())
}
}
deserializer.deserialize_str(V)
}
fn repeated<'a, O: Clone>(
p: impl Parser<&'a str, Output = O, Error = nom::error::Error<&'a str>>,
) -> impl Parser<&'a str, Output = Vec<O>> {
map(pair(p, opt(preceded(char('x'), idx_int))), |(v, n)| {
vec![v; n.unwrap_or(1)]
})
}
fn deserialize_range_list<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<RangeList<IntVal>, D::Error> {
struct V;
impl Visitor<'_> for V {
type Value = RangeList<IntVal>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a list of ranges")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, r) = all_consuming(whitespace_seperated(range))
.parse(v)
.map_err(|_| E::custom(format!("invalid list of ranges `{v}")))?;
Ok(collect_range_list(r))
}
}
let visitor = V;
deserializer.deserialize_str(visitor)
}
fn deserialize_size<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<usize>, D::Error> {
struct V;
impl Visitor<'_> for V {
type Value = Vec<usize>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an array size expression")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, r) = all_consuming(sequence(delimited(
char::<_, nom::error::Error<&str>>('['),
map_res(recognize(digit1), str::parse),
char(']'),
)))
.parse(v)
.map_err(|_| E::custom(format!("invalid array size expression `{v}'")))?;
Ok(r)
}
}
let visitor = V;
deserializer.deserialize_str(visitor)
}
fn from_string<'de, D: Deserializer<'de>, I: From<String>>(deserializer: D) -> Result<I, D::Error> {
let s: Cow<'_, str> = Deserialize::deserialize(deserializer)?;
Ok(s.trim().to_owned().into())
}
fn idx_int(input: &str) -> IResult<&str, usize> {
let (input, i): (_, usize) = map_res(recognize(digit1), str::parse).parse(input)?;
Ok((input, i))
}
fn idx_range(input: &str) -> IResult<&str, RangeInclusive<usize>> {
let (input, lb) = idx_int(input)?;
if let (input, Some(_)) = opt(tag("..")).parse(input)? {
let (input, ub) = idx_int(input)?;
Ok((input, lb..=ub))
} else {
Ok((input, lb..=lb))
}
}
fn serialize_list<S: Serializer, T: Display>(exps: &[T], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(
&exps
.iter()
.map(|e| format!("{}", e))
.collect::<Vec<_>>()
.join(" "),
)
}
fn serialize_opt_list<S: Serializer, T: Display>(
exps: &[Option<T>],
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(
&exps
.iter()
.map(|e| match e {
Some(e) => e.to_string(),
None => "*".to_owned(),
})
.collect::<Vec<_>>()
.join(" "),
)
}
fn serialize_ident<S: Serializer, Identifier: Display>(
identifier: &Option<Identifier>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&format!("{}", identifier.as_ref().unwrap()))
}
fn serialize_range_list<S: Serializer>(
exps: &RangeList<IntVal>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(
&exps
.into_iter()
.map(|e| {
if e.start() == e.end() {
e.start().to_string()
} else {
format!("{}..{}", e.start(), e.end())
}
})
.collect::<Vec<_>>()
.join(" "),
)
}
fn serialize_size<S: Serializer>(exps: &[usize], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(
&exps
.iter()
.map(|e| format!("[{}]", e))
.collect::<Vec<_>>()
.join(""),
)
}
impl<Identifier: Clone + Hash + Eq + ToString> Array<Identifier, VarRef<Identifier>> {
pub fn unroll(&self) -> Result<Array<Identifier, SimpleRef<Identifier>>, UnrollError> {
let size_wrap: HashMap<_, _> = Some((self.identifier.clone(), &self.size[..]))
.into_iter()
.collect();
let mut domains = Vec::with_capacity(self.domains.len());
for (v, d) in &self.domains {
let mut res: Vec<SimpleRef<_>> = Vec::new();
for x in v {
res.extend(
x.unroll(&size_wrap, &[], &[])?
.into_iter()
.map(|x| match x {
Exp::Var(v) => v,
_ => unreachable!(),
}),
);
}
domains.push((res, d.clone()));
}
Ok(Array {
identifier: self.identifier.clone(),
note: self.note.clone(),
size: self.size.clone(),
domains,
})
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Array<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound = "Var: IntoVar")]
struct DomainStruct<Var> {
#[serde(rename = "@for", deserialize_with = "VarRef::parse_vec")]
vars: Vec<Var>,
#[serde(rename = "$text", deserialize_with = "deserialize_range_list")]
domain: RangeList<IntVal>,
}
#[derive(Deserialize)]
#[serde(bound = " Var: IntoVar")]
enum Domain<'a, Var> {
#[serde(rename = "domain")]
Domain(Vec<DomainStruct<Var>>),
#[serde(rename = "$text")]
Direct(Cow<'a, str>),
}
#[derive(Deserialize)]
#[serde(bound = "Identifier: From<String>, Var: IntoVar")]
struct Array<'a, Identifier, Var> {
#[serde(rename = "@id", deserialize_with = "from_string")]
identifier: Identifier,
#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
note: Option<String>,
#[serde(rename = "@size", deserialize_with = "deserialize_size")]
size: Vec<usize>,
#[serde(rename = "$value")]
domain: Domain<'a, Var>,
}
let x = Array::deserialize(deserializer)?;
let domains = match x.domain {
Domain::Domain(v) => v.into_iter().map(|d| (d.vars, d.domain)).collect(),
Domain::Direct(s) => {
let s = s.trim();
let s = all_consuming(whitespace_seperated(range))
.parse(s.as_ref())
.map_err(|_| {
serde::de::Error::custom(format!("unable to parse ranges from `{s}'"))
})?;
vec![(
vec![Var::into_var(VarRef::Ident("others".to_owned()))],
collect_range_list(s.1),
)]
}
};
Ok(Self {
identifier: x.identifier,
note: x.note,
size: x.size,
domains,
})
}
}
impl<Identifier: Display> Serialize for Array<Identifier> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(bound = "Identifier: Display")]
struct DomainStruct<'a, Identifier: Display> {
#[serde(rename = "@for", serialize_with = "serialize_list")]
vars: &'a Vec<VarRef<Identifier>>,
#[serde(rename = "$text", serialize_with = "serialize_range_list")]
domain: &'a RangeList<IntVal>,
}
#[derive(Serialize)]
#[serde(bound = "Identifier: Display")]
enum Domain<'a, Identifier: Display> {
#[serde(rename = "domain")]
Domain(DomainStruct<'a, Identifier>),
}
#[derive(Serialize)]
#[serde(bound = "Identifier: Display")]
struct Array<'a, Identifier: Display> {
#[serde(rename = "@id", serialize_with = "as_str")]
identifier: &'a Identifier,
#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
note: &'a Option<String>,
#[serde(rename = "@size", serialize_with = "serialize_size")]
size: &'a Vec<usize>,
#[serde(rename = "$value")]
domain: Vec<Domain<'a, Identifier>>,
}
let domain = self
.domains
.iter()
.map(|(v, d)| Domain::Domain(DomainStruct { vars: v, domain: d }))
.collect();
let x = Array {
identifier: &self.identifier,
note: &self.note,
size: &self.size,
domain,
};
x.serialize(serializer)
}
}
impl<Identifier: Clone + Eq + Hash + ToString> Instance<Identifier, VarRef<Identifier>> {
pub fn unroll_constraints(
&self,
) -> Result<Vec<Constraint<Identifier, SimpleRef<Identifier>>>, UnrollError> {
let arrays: HashMap<Identifier, &[usize]> = self
.arrays
.iter()
.map(|arr| (arr.identifier.clone(), &arr.size[..]))
.collect();
let mut flat = Vec::new();
let mut metas = VecDeque::new();
metas.push_back(&self.constraints);
while let Some(cons) = metas.pop_front() {
for con in cons {
match con {
MetaConstraint::Group(group) => flat.extend(group.unroll(&arrays)?),
MetaConstraint::Slide(slide) => flat.extend(slide.unroll(&arrays)?),
MetaConstraint::Block(block) => metas.push_back(&block.constraints),
MetaConstraint::Constraint(c) => flat.push(c.unroll(&arrays, &[], &[])?),
}
}
}
Ok(flat)
}
}
impl<Identifier> Default for Instance<Identifier> {
fn default() -> Self {
Self {
ty: Default::default(),
variables: Default::default(),
arrays: Default::default(),
constraints: Default::default(),
objectives: Default::default(),
}
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Instance<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
enum V<Identifier, Var> {
#[serde(rename = "var")]
Variable(Variable<Identifier>),
#[serde(rename = "array")]
Array(Array<Identifier, Var>),
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Variables<Identifier, Var> {
#[serde(rename = "$value")]
vars: Vec<V<Identifier, Var>>,
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Constraints<Identifier, Var> {
#[serde(rename = "$value")]
content: Vec<MetaConstraint<Identifier, Var>>,
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Instance<Identifier, Var> {
#[serde(rename = "@type")]
ty: FrameworkType,
variables: Option<Variables<Identifier, Var>>,
constraints: Option<Constraints<Identifier, Var>>,
#[serde(default = "Objectives::default")]
objectives: Objectives<Identifier, Var>,
}
let inst: Instance<Identifier, Var> = Deserialize::deserialize(deserializer)?;
let mut variables = Vec::new();
let mut arrays = Vec::new();
for v in inst.variables.map(|v| v.vars).into_iter().flatten() {
match v {
V::Variable(var) => variables.push(var),
V::Array(arr) => arrays.push(arr),
}
}
Ok(Self {
ty: inst.ty,
variables,
arrays,
constraints: inst.constraints.map_or_else(Vec::new, |c| c.content),
objectives: inst.objectives,
})
}
}
impl<Identifier: Serialize + Display> Serialize for Instance<Identifier> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
struct Variables<'a, Identifier: Display> {
var: &'a Vec<Variable<Identifier>>,
array: &'a Vec<Array<Identifier>>,
}
impl<Identifier: Display> Variables<'_, Identifier> {
fn is_empty(&self) -> bool {
self.var.is_empty() && self.array.is_empty()
}
}
#[derive(Serialize)]
struct Constraints<'a, Identifier: Display> {
#[serde(rename = "$value")]
content: &'a Vec<MetaConstraint<Identifier>>,
}
impl<Identifier: Display> Constraints<'_, Identifier> {
fn is_empty(&self) -> bool {
self.content.is_empty()
}
}
#[derive(Serialize)]
#[serde(rename = "instance")]
struct Instance<'a, Identifier: Display> {
#[serde(rename = "@type")]
ty: FrameworkType,
#[serde(skip_serializing_if = "Variables::is_empty")]
variables: Variables<'a, Identifier>,
#[serde(skip_serializing_if = "Constraints::is_empty")]
constraints: Constraints<'a, Identifier>,
#[serde(skip_serializing_if = "Objectives::is_empty")]
objectives: &'a Objectives<Identifier>,
}
let x = Instance {
ty: self.ty,
variables: Variables {
var: &self.variables,
array: &self.arrays,
},
constraints: Constraints {
content: &self.constraints,
},
objectives: &self.objectives,
};
Serialize::serialize(&x, serializer)
}
}
impl<Identifier: Display, Var: Display> Serialize for Instantiation<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(
rename = "instantiation",
bound(serialize = "Identifier: Display, Var: Display")
)]
struct Instantiation<'a, Identifier, Var> {
#[serde(
rename = "@id",
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_ident"
)]
identifier: &'a Option<Identifier>,
#[serde(rename = "@note", skip_serializing_if = "Option::is_none")]
note: &'a Option<String>,
#[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
ty: &'a Option<InstantiationType>,
#[serde(rename = "@cost", skip_serializing_if = "Option::is_none")]
cost: &'a Option<IntVal>,
#[serde(serialize_with = "serialize_list")]
list: &'a Vec<Var>,
#[serde(serialize_with = "serialize_opt_list")]
values: &'a Vec<Option<IntVal>>,
}
Instantiation {
identifier: &self.info.identifier,
note: &self.info.note,
ty: &self.ty,
cost: &self.cost,
list: &self.list,
values: &self.values,
}
.serialize(serializer)
}
}
impl<Identifier> Objectives<Identifier> {
pub fn is_empty(&self) -> bool {
self.objectives.is_empty()
}
}
impl<Identifier: Clone + Hash + Eq + ToString> ObjExp<Identifier, VarRef<Identifier>> {
pub fn unroll(
&self,
instance: &Instance<Identifier, VarRef<Identifier>>,
) -> Result<ObjExp<Identifier, SimpleRef<Identifier>>, UnrollError> {
let arrays: HashMap<Identifier, &[usize]> = instance
.arrays
.iter()
.map(|arr| (arr.identifier.clone(), &arr.size[..]))
.collect();
let list = self
.list
.iter()
.map(|v| v.unroll(&arrays, &[], &[]))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.collect();
Ok(ObjExp {
info: self.info.clone(),
ty: self.ty.clone(),
list,
coeffs: self.coeffs.clone(),
})
}
}
impl<Identifier, Var> Default for Objectives<Identifier, Var> {
fn default() -> Self {
Self {
combination: CombinationType::default(),
objectives: Vec::new(),
}
}
}
impl Display for Placeholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Placeholder::Position(i) => write!(f, "%{}", i),
Placeholder::Remainder => write!(f, "%..."),
}
}
}
impl<Identifier: Clone + Hash + Eq + ToString> VarRef<Identifier> {
pub(crate) fn unroll(
&self,
arrays: &HashMap<Identifier, &[usize]>,
args: &[Vec<Exp<SimpleRef<Identifier>>>],
remainder: &[Exp<SimpleRef<Identifier>>],
) -> Result<Vec<Exp<SimpleRef<Identifier>>>, UnrollError> {
match self {
&VarRef::Placeholder(Placeholder::Position(i)) if i < args.len() => Ok(args[i].clone()),
&VarRef::Placeholder(Placeholder::Position(i)) => Err(UnrollError::ArgMissing {
placeholder: i,
args_len: args.len(),
}),
VarRef::Placeholder(Placeholder::Remainder) => Ok(remainder.to_vec()),
VarRef::Ident(ident) => Ok(vec![Exp::Var(SimpleRef::Ident(ident.clone()))]),
VarRef::ArrayAccess(ident, indexings) => {
let Some(size) = arrays.get(ident) else {
return Err(UnrollError::UnknownIdentifier(ident.to_string()));
};
if indexings.len() != size.len() {
return Err(UnrollError::UnexpectedIndexes {
expected_len: size.len(),
args_len: indexings.len(),
});
}
Ok(indexings
.iter()
.enumerate()
.map(|(i, idx)| match idx {
&Indexing::Single(i) => i..=i,
&Indexing::Range(start, end) => start..=end,
Indexing::Full => 0..=(size[i] - 1),
})
.multi_cartesian_product()
.map(|idxs| Exp::Var(SimpleRef::ArrayAccess(ident.clone(), idxs)))
.collect())
}
}
}
pub(crate) fn unroll_matrix(
&self,
arrays: &HashMap<Identifier, &[usize]>,
args: &[Vec<Exp<SimpleRef<Identifier>>>],
remainder: &[Exp<SimpleRef<Identifier>>],
) -> Result<Vec<Vec<Exp<SimpleRef<Identifier>>>>, UnrollError> {
let VarRef::ArrayAccess(ident, indexings) = self else {
return Err(UnrollError::UnexpectedIndexes {
expected_len: 2,
args_len: 0,
});
};
let Some(size) = arrays.get(ident) else {
return Err(UnrollError::UnknownIdentifier(ident.to_string()));
};
let flat = self.unroll(arrays, args, remainder)?;
let row_len = match indexings.last() {
Some(&Indexing::Single(_)) => 1,
Some(&Indexing::Range(start, end)) => end - start + 1,
Some(Indexing::Full) => size[indexings.len() - 1],
None => {
return Err(UnrollError::UnexpectedIndexes {
expected_len: 2,
args_len: 0,
})
}
};
Ok(flat.chunks(row_len).map(<[_]>::to_vec).collect())
}
pub(crate) fn unroll_single(
&self,
arrays: &HashMap<Identifier, &[usize]>,
args: &[Vec<Exp<SimpleRef<Identifier>>>],
remainder: &[Exp<SimpleRef<Identifier>>],
) -> Result<Exp<SimpleRef<Identifier>>, UnrollError> {
let res = self.unroll(arrays, args, remainder)?;
match &res[..] {
[exp] => Ok(exp.clone()),
_ => Err(UnrollError::UnexpectedLength {
expected_len: 1,
args_len: res.len(),
}),
}
}
}
impl VarRef {
fn parse_vec<'de, D: Deserializer<'de>, R: IntoVar>(
deserializer: D,
) -> Result<Vec<R>, D::Error> {
struct V<X>(PhantomData<X>);
impl<X: From<String>> Visitor<'_> for V<X> {
type Value = Vec<VarRef<X>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a list of variable references")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, v) = all_consuming(whitespace_seperated(VarRef::parse))
.parse(v)
.map_err(|_| E::custom(format!("invalid variable references `{v}'")))?;
Ok(v)
}
}
let visitor = V::<String>(PhantomData);
Ok(deserializer
.deserialize_str(visitor)?
.into_iter()
.map(R::into_var)
.collect())
}
}
impl<Identifier: From<String>> VarRef<Identifier> {
pub(crate) fn parse(input: &str) -> IResult<&str, Self> {
let placeholder: IResult<&str, Placeholder> = preceded(
char('%'),
alt((
map(digit1, |p: &str| Placeholder::Position(p.parse().unwrap())),
map(tag("..."), |_| Placeholder::Remainder),
)),
)
.parse(input);
if let Ok((input, placeholder)) = placeholder {
return Ok((input, Self::Placeholder(placeholder)));
}
let (input, ident) = identifier(input)?;
let (input, v) = many0(delimited(char('['), opt(idx_range), char(']'))).parse(input)?;
Ok((
input,
if v.is_empty() {
VarRef::Ident(ident)
} else {
let v = v
.into_iter()
.map(|r| {
r.map(|r| {
if r.start() == r.end() {
Indexing::Single(*r.start())
} else {
Indexing::Range(*r.start(), *r.end())
}
})
.unwrap_or(Indexing::Full)
})
.collect();
VarRef::ArrayAccess(ident, v)
},
))
}
}
impl<Identifier: Display> Display for VarRef<Identifier> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VarRef::Ident(ident) => ident.fmt(f),
VarRef::ArrayAccess(ident, v) => {
write!(
f,
"{}{}",
ident,
v.iter()
.map(|i| format!(
"[{}]",
match i {
Indexing::Single(v) => v.to_string(),
Indexing::Range(a, b) => format!("{}..{}", a, b),
Indexing::Full => String::new(),
}
))
.collect::<Vec<_>>()
.join("")
)
}
VarRef::Placeholder(placeholder) => placeholder.fmt(f),
}
}
}
impl<I: From<String>> IntoVar for VarRef<I> {
fn into_var(var: VarRef) -> Self {
match var {
VarRef::Ident(s) => VarRef::Ident(I::from(s)),
VarRef::ArrayAccess(s, idxs) => VarRef::ArrayAccess(I::from(s), idxs),
VarRef::Placeholder(p) => VarRef::Placeholder(p),
}
}
}
#[cfg(test)]
mod tests {
use std::{fmt::Debug, fs::File, io::BufReader, path::Path};
use expect_test::ExpectFile;
use serde::{de::DeserializeOwned, Serialize};
use crate::{Instance, Instantiation};
fn test_successful_serialization<T: Debug + DeserializeOwned + Serialize + PartialEq>(
file: &Path,
exp: ExpectFile,
) {
let rdr = BufReader::new(File::open(file).unwrap());
let inst: T = quick_xml::de::from_reader(rdr).unwrap();
exp.assert_debug_eq(&inst);
let output = quick_xml::se::to_string(&inst).unwrap();
let inst2: T = quick_xml::de::from_str(&output).unwrap();
assert_eq!(inst, inst2)
}
fn test_successful_unroll(file: &Path, exp: ExpectFile, unrolled: ExpectFile) {
test_successful_serialization::<Instance>(file, exp);
let rdr = BufReader::new(File::open(file).unwrap());
let inst: Instance = quick_xml::de::from_reader(rdr).unwrap();
unrolled.assert_debug_eq(&inst.unroll_constraints().unwrap());
}
macro_rules! test_file {
($file:ident) => {
test_file!($file, Instance);
};
($file:ident, $t:ident) => {
#[test]
fn $file() {
test_successful_serialization::<$t>(
std::path::Path::new(&format!("./corpus/{}.xml", stringify!($file))),
expect_test::expect_file![&format!(
"../corpus/{}.debug.txt",
stringify!($file)
)],
)
}
};
}
macro_rules! test_unroll {
($file:ident) => {
#[test]
fn $file() {
test_successful_unroll(
std::path::Path::new(&format!("./corpus/{}.xml", stringify!($file))),
expect_test::expect_file![&format!(
"../corpus/{}.debug.txt",
stringify!($file)
)],
expect_test::expect_file![&format!(
"../corpus/{}.unroll.txt",
stringify!($file)
)],
)
}
};
}
test_file!(knapsack);
test_unroll!(group_list_arg);
test_file!(xcsp3_ex_001);
test_file!(xcsp3_ex_002);
test_file!(xcsp3_ex_003);
test_file!(xcsp3_ex_004);
test_file!(xcsp3_ex_005);
test_file!(xcsp3_ex_006);
test_file!(xcsp3_ex_007);
test_file!(xcsp3_ex_018);
test_file!(xcsp3_ex_019);
test_file!(xcsp3_ex_021);
test_file!(xcsp3_ex_022);
test_file!(xcsp3_ex_023, Instantiation);
test_file!(xcsp3_ex_024);
test_file!(xcsp3_ex_025, Instantiation);
test_file!(xcsp3_ex_026, Instantiation);
test_file!(xcsp3_ex_027, Instantiation);
test_file!(xcsp3_ex_028, Instantiation);
test_file!(xcsp3_ex_029);
test_file!(xcsp3_ex_030);
test_file!(xcsp3_ex_031);
test_file!(xcsp3_ex_032);
test_file!(xcsp3_ex_033);
test_file!(xcsp3_ex_034);
test_file!(xcsp3_ex_035);
test_file!(xcsp3_ex_036);
test_file!(xcsp3_ex_037);
test_file!(xcsp3_ex_038);
test_file!(xcsp3_ex_039);
test_file!(xcsp3_ex_041);
test_file!(xcsp3_ex_043);
test_file!(xcsp3_ex_044);
test_file!(xcsp3_ex_045);
test_file!(xcsp3_ex_046);
test_file!(xcsp3_ex_047);
test_file!(xcsp3_ex_049);
test_file!(xcsp3_ex_051);
test_file!(xcsp3_ex_052);
test_file!(xcsp3_ex_053);
test_file!(xcsp3_ex_054);
test_file!(xcsp3_ex_055);
test_file!(xcsp3_ex_056);
test_file!(xcsp3_ex_057);
test_file!(xcsp3_ex_058);
test_file!(xcsp3_ex_059);
test_file!(xcsp3_ex_060);
test_file!(xcsp3_ex_063);
test_file!(xcsp3_ex_064);
test_file!(xcsp3_ex_065);
test_file!(xcsp3_ex_066);
test_file!(xcsp3_ex_067);
test_file!(xcsp3_ex_068);
test_file!(xcsp3_ex_069);
test_file!(xcsp3_ex_072);
test_unroll!(xcsp3_ex_073);
test_file!(xcsp3_ex_074);
test_file!(xcsp3_ex_075);
test_file!(xcsp3_ex_076);
test_file!(xcsp3_ex_077);
test_file!(xcsp3_ex_078);
test_unroll!(xcsp3_ex_084);
test_file!(xcsp3_ex_085);
test_file!(xcsp3_ex_086);
test_file!(xcsp3_ex_089);
test_file!(xcsp3_ex_091);
test_file!(xcsp3_ex_097);
test_file!(xcsp3_ex_100);
test_file!(xcsp3_ex_101);
test_unroll!(xcsp3_ex_113);
test_unroll!(xcsp3_ex_115);
test_unroll!(xcsp3_ex_116);
test_unroll!(xcsp3_ex_117);
test_unroll!(xcsp3_ex_118);
test_unroll!(xcsp3_ex_127);
test_unroll!(xcsp3_ex_128);
test_unroll!(xcsp3_ex_130);
test_unroll!(xcsp3_ex_131);
test_unroll!(xcsp3_ex_152);
test_unroll!(xcsp3_ex_153);
test_unroll!(xcsp3_ex_154);
test_unroll!(xcsp3_ex_155);
test_unroll!(xcsp3_ex_156);
test_unroll!(xcsp3_ex_157);
test_unroll!(xcsp3_ex_158);
test_unroll!(xcsp3_ex_161);
test_unroll!(xcsp3_ex_166);
test_file!(xcsp3_ex_167);
}