mod error;
#[cfg(feature = "fzn")]
mod fzn;
pub mod helpers;
#[cfg(any(feature = "fzn", feature = "serde"))]
mod intermediate;
#[cfg(feature = "serde")]
mod serde_impl;
use std::{
cmp::Ordering,
collections::HashSet,
fmt::{Debug, Display},
hash::{Hash, Hasher},
sync::{Arc, Weak},
};
pub use rangelist::RangeList;
#[cfg(feature = "serde")]
use serde::{Deserializer, Serialize};
pub use crate::error::{FznParseError, LinkError};
use crate::helpers::ArcKey;
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Clone, PartialEq, Debug)]
pub enum Annotation<Identifier = String> {
Atom(Identifier),
Call(AnnotationCall<Identifier>),
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Clone, Debug)]
pub enum AnnotationArgument<Identifier = String> {
Array(Vec<AnnotationLiteral<Identifier>>),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_array_weak")
)]
ArrayNamed(Weak<Array<Identifier>>),
Literal(AnnotationLiteral<Identifier>),
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename = "annotation_call"))]
#[derive(Clone, PartialEq, Debug)]
pub struct AnnotationCall<Identifier = String> {
pub id: Identifier,
pub args: Vec<AnnotationArgument<Identifier>>,
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Clone, Debug)]
pub enum AnnotationLiteral<Identifier = String> {
Int(i64),
Float(f64),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_variable_weak")
)]
Variable(Weak<Variable<Identifier>>),
Bool(bool),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_encapsulate_set")
)]
IntSet(RangeList<i64>),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_encapsulate_set")
)]
FloatSet(RangeList<f64>),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_encapsulate_string")
)]
String(String),
Annotation(Annotation<Identifier>),
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Clone, PartialEq, Debug)]
pub enum Argument<Identifier = String> {
Array(Vec<Literal<Identifier>>),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_array_arc",)
)]
ArrayNamed(Arc<Array<Identifier>>),
Literal(Literal<Identifier>),
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename = "array"))]
#[derive(Clone, PartialEq, Debug)]
pub struct Array<Identifier = String> {
#[cfg_attr(feature = "serde", serde(skip))]
pub name: String,
#[cfg_attr(feature = "serde", serde(rename = "a"))]
pub contents: Vec<Literal<Identifier>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub ann: Vec<Annotation<Identifier>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "serde_impl::is_false"))]
pub defined: bool,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "serde_impl::is_false"))]
pub introduced: bool,
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename = "constraint"))]
#[derive(Clone, PartialEq, Debug)]
pub struct Constraint<Identifier = String> {
pub id: Identifier,
pub args: Vec<Argument<Identifier>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub defines: Option<NamedRef<Identifier>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub ann: Vec<Annotation<Identifier>>,
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(Clone, PartialEq, Debug)]
pub struct FlatZinc<Identifier = String> {
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_variable_map")
)]
pub variables: Vec<Arc<Variable<Identifier>>>,
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_array_map")
)]
pub arrays: Vec<Arc<Array<Identifier>>>,
pub constraints: Vec<Constraint<Identifier>>,
pub output: Vec<NamedRef<Identifier>>,
pub solve: SolveObjective<Identifier>,
pub version: String,
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
#[derive(Clone, PartialEq, Debug)]
pub enum Literal<Identifier = String> {
Int(i64),
Float(f64),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_variable_arc",)
)]
Variable(Arc<Variable<Identifier>>),
Bool(bool),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_encapsulate_set",)
)]
IntSet(RangeList<i64>),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_encapsulate_set",)
)]
FloatSet(RangeList<f64>),
#[cfg_attr(
feature = "serde",
serde(serialize_with = "serde_impl::serialize_encapsulate_string",)
)]
String(String),
}
#[derive(Clone, Debug, Default, PartialEq)]
pub enum Method<Identifier = String> {
#[default]
Satisfy,
Minimize(Literal<Identifier>),
Maximize(Literal<Identifier>),
}
#[derive(Clone, Debug)]
pub enum NamedRef<Identifier = String> {
Variable(Arc<Variable<Identifier>>),
Array(Arc<Array<Identifier>>),
}
#[derive(Clone, PartialEq, Debug)]
pub struct SolveObjective<Identifier = String> {
pub method: Method<Identifier>,
pub ann: Vec<Annotation<Identifier>>,
}
#[derive(Clone, PartialEq, Debug)]
pub enum Type {
Bool,
Int(Option<RangeList<i64>>),
Float(Option<RangeList<f64>>),
IntSet(Option<RangeList<i64>>),
}
#[derive(Clone, PartialEq, Debug)]
pub struct Variable<Identifier = String> {
pub name: String,
pub ty: Type,
pub ann: Vec<Annotation<Identifier>>,
pub defined: bool,
pub introduced: bool,
}
impl<Identifier: Display> Display for Annotation<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Annotation::Atom(a) => write!(f, "{a}"),
Annotation::Call(c) => write!(f, "{c}"),
}
}
}
impl<Idenfier: Display> Display for AnnotationArgument<Idenfier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AnnotationArgument::Array(arr) => {
write!(f, "[")?;
let mut first = true;
for v in arr {
if !first {
write!(f, ", ")?
}
write!(f, "{v}")?;
first = false;
}
write!(f, "]")
}
AnnotationArgument::ArrayNamed(array) => match array.upgrade() {
Some(array) => write!(f, "{}", &array.name),
None => write!(f, "[/* dangling array ref */]"),
},
AnnotationArgument::Literal(lit) => write!(f, "{lit}"),
}
}
}
impl<Identifier> From<Argument<Identifier>> for AnnotationArgument<Identifier> {
fn from(value: Argument<Identifier>) -> Self {
match value {
Argument::Array(arr) => {
AnnotationArgument::Array(arr.into_iter().map(|l| l.into()).collect())
}
Argument::ArrayNamed(arr) => AnnotationArgument::ArrayNamed(Arc::downgrade(&arr)),
Argument::Literal(l) => AnnotationArgument::Literal(l.into()),
}
}
}
impl<Identifier: PartialEq> PartialEq for AnnotationArgument<Identifier> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(AnnotationArgument::Array(lhs), AnnotationArgument::Array(rhs)) => lhs == rhs,
(AnnotationArgument::ArrayNamed(lhs), AnnotationArgument::ArrayNamed(rhs)) => {
match (lhs.upgrade(), rhs.upgrade()) {
(Some(lhs), Some(rhs)) => lhs == rhs,
(None, None) => true,
_ => false,
}
}
(AnnotationArgument::Literal(lhs), AnnotationArgument::Literal(rhs)) => lhs == rhs,
_ => false,
}
}
}
impl<Identifier: Display> Display for AnnotationCall<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}(", self.id)?;
let mut first = true;
for arg in &self.args {
if !first {
write!(f, ", ")?
}
write!(f, "{arg}")?;
first = false;
}
write!(f, ")")
}
}
impl<Idenfier: Display> Display for AnnotationLiteral<Idenfier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AnnotationLiteral::Int(i) => write!(f, "{i}"),
AnnotationLiteral::Float(x) => write!(f, "{x:?}"),
AnnotationLiteral::Variable(var) => match var.upgrade() {
Some(var) => write!(f, "{}", var.name),
None => write!(f, "DANGLING_VARIABLE_REFERENCE"),
},
AnnotationLiteral::Bool(b) => write!(f, "{b}"),
AnnotationLiteral::IntSet(is) => write!(f, "{is}"),
AnnotationLiteral::FloatSet(fs) => write!(f, "{fs}"),
AnnotationLiteral::String(s) => write!(f, "{s:?}"),
AnnotationLiteral::Annotation(ann) => write!(f, "{ann}"),
}
}
}
impl<Identifier> From<Literal<Identifier>> for AnnotationLiteral<Identifier> {
fn from(value: Literal<Identifier>) -> Self {
match value {
Literal::Int(i) => AnnotationLiteral::Int(i),
Literal::Float(f) => AnnotationLiteral::Float(f),
Literal::Bool(b) => AnnotationLiteral::Bool(b),
Literal::String(s) => AnnotationLiteral::String(s),
Literal::Variable(var) => AnnotationLiteral::Variable(Arc::downgrade(&var)),
Literal::IntSet(set) => AnnotationLiteral::IntSet(set),
Literal::FloatSet(set) => AnnotationLiteral::FloatSet(set),
}
}
}
impl<Identifier: PartialEq> PartialEq for AnnotationLiteral<Identifier> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Int(lhs), Self::Int(rhs)) => lhs == rhs,
(Self::Float(lhs), Self::Float(rhs)) => lhs == rhs,
(Self::Variable(lhs), Self::Variable(rhs)) => match (lhs.upgrade(), rhs.upgrade()) {
(Some(lhs), Some(rhs)) => lhs == rhs,
(None, None) => true,
_ => false,
},
(Self::Bool(lhs), Self::Bool(rhs)) => lhs == rhs,
(Self::IntSet(lhs), Self::IntSet(rhs)) => lhs == rhs,
(Self::FloatSet(lhs), Self::FloatSet(rhs)) => lhs == rhs,
(Self::String(lhs), Self::String(rhs)) => lhs == rhs,
(Self::Annotation(lhs), Self::Annotation(rhs)) => lhs == rhs,
_ => false,
}
}
}
impl<Identifier: Display> Display for Argument<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Argument::Array(arr) => {
write!(f, "[")?;
let mut first = true;
for v in arr {
if !first {
write!(f, ", ")?
}
write!(f, "{v}")?;
first = false;
}
write!(f, "]")
}
Argument::ArrayNamed(arr) => write!(f, "{}", &arr.name),
Argument::Literal(lit) => write!(f, "{lit}"),
}
}
}
impl<Identifier> Array<Identifier> {
pub fn cloned_key(self: &Arc<Self>) -> ArcKey<Self> {
ArcKey::new(Arc::clone(self))
}
fn determine_type(&self) -> (&str, bool) {
let ty = match self.contents.first().unwrap() {
Literal::Int(_) => "int",
Literal::Float(_) => "float",
Literal::Variable(var) => return (var.ty.base_name(), true),
Literal::Bool(_) => "bool",
Literal::IntSet(_) => "set of int",
Literal::FloatSet(_) => "set of float",
Literal::String(_) => "string",
};
let is_var = self
.contents
.iter()
.any(|lit| matches!(lit, Literal::Variable(_)));
(ty, is_var)
}
}
impl<Identifier: Display> Display for Constraint<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}(", self.id)?;
let mut first = true;
for arg in &self.args {
if !first {
write!(f, ", ")?
}
write!(f, "{arg}")?;
first = false;
}
write!(f, ")")?;
if let Some(defines) = &self.defines {
write!(f, " ::defines_var({})", defines.name())?
}
for a in &self.ann {
write!(f, " ::{a}")?
}
Ok(())
}
}
impl<Identifier> FlatZinc<Identifier>
where
Identifier: Clone + Debug,
{
#[cfg(feature = "serde")]
pub fn deserialize_with_interner<'de, D, F, E>(
deserializer: D,
interner: F,
) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
F: FnMut(&str) -> Result<Identifier, E>,
E: Display,
{
use serde::de::{self, DeserializeSeed};
use crate::intermediate::ParserState;
let (model, interner) = ParserState::new(interner).deserialize(deserializer)?;
FlatZinc::from_intermediate(model, interner).map_err(de::Error::custom)
}
#[cfg(feature = "fzn")]
pub fn from_fzn<E>(source: impl std::io::BufRead) -> Result<Self, FznParseError>
where
for<'a> Identifier: TryFrom<&'a str, Error = E>,
E: Display,
{
fzn::parse(source)
}
#[cfg(feature = "fzn")]
pub fn from_fzn_with_interner<F, E>(
source: impl std::io::BufRead,
interner: F,
) -> Result<Self, FznParseError>
where
F: FnMut(&str) -> Result<Identifier, E>,
E: Display,
{
fzn::parse_with_interner(source, interner)
}
}
impl<Identifier> Default for FlatZinc<Identifier> {
fn default() -> Self {
Self {
variables: Vec::new(),
arrays: Vec::new(),
constraints: Vec::new(),
output: Vec::new(),
solve: Default::default(),
version: "1.0".into(),
}
}
}
impl<Identifier: Display> Display for FlatZinc<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let output_map: HashSet<_> = self.output.iter().collect();
for var in &self.variables {
write!(f, "var {}", var.ty)?;
write!(f, ": {}", var.name)?;
let name_ref: NamedRef<_> = Arc::clone(var).into();
if output_map.contains(&name_ref) {
write!(f, " ::output_var")?;
}
if var.defined {
write!(f, " ::is_defined_var")?;
}
if var.introduced {
write!(f, " ::var_is_introduced")?;
}
for ann in &var.ann {
write!(f, " ::{ann}")?
}
writeln!(f, ";")?
}
for arr in &self.arrays {
let (ty, is_var) = arr.determine_type();
write!(
f,
"array[1..{}] of {}{ty}: {}",
arr.contents.len(),
if is_var { "var " } else { "" },
arr.name
)?;
let name_ref: NamedRef<_> = Arc::clone(arr).into();
if output_map.contains(&name_ref) {
write!(f, " ::output_array([1..{}])", arr.contents.len())?;
}
if arr.defined {
write!(f, " ::is_defined_var")?;
}
if arr.introduced {
write!(f, " ::var_is_introduced")?;
}
for ann in &arr.ann {
write!(f, " ::{ann}")?
}
write!(f, " = [")?;
let mut first = true;
for v in &arr.contents {
if !first {
write!(f, ", ")?;
}
write!(f, "{v}")?;
first = false;
}
writeln!(f, "];")?
}
for c in &self.constraints {
writeln!(f, "constraint {c};")?;
}
writeln!(f, "{};", self.solve)
}
}
impl<Identifier: Display> Display for Literal<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Literal::Int(i) => write!(f, "{i}"),
Literal::Float(x) => write!(f, "{x:?}"),
Literal::Variable(var) => write!(f, "{}", var.name),
Literal::Bool(b) => write!(f, "{b}"),
Literal::IntSet(is) => write!(f, "{is}"),
Literal::FloatSet(fs) => write!(f, "{fs}"),
Literal::String(s) => write!(f, "{s:?}"),
}
}
}
impl<Identifier: Display> Display for Method<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Method::Satisfy => write!(f, "satisfy"),
Method::Minimize(objective) => write!(f, "minimize {objective}"),
Method::Maximize(objective) => write!(f, "maximize {objective}"),
}
}
}
impl<Identifier> NamedRef<Identifier> {
pub fn name(&self) -> &str {
match self {
NamedRef::Variable(var) => &var.name,
NamedRef::Array(array) => &array.name,
}
}
}
impl<Identifier> Eq for NamedRef<Identifier> {}
impl<Identifier> From<Arc<Array<Identifier>>> for NamedRef<Identifier> {
fn from(arc: Arc<Array<Identifier>>) -> Self {
NamedRef::Array(arc)
}
}
impl<Identifier> From<Arc<Variable<Identifier>>> for NamedRef<Identifier> {
fn from(arc: Arc<Variable<Identifier>>) -> Self {
NamedRef::Variable(arc)
}
}
impl<Identifier> Hash for NamedRef<Identifier> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name().hash(state);
}
}
impl<Identifier> Ord for NamedRef<Identifier> {
fn cmp(&self, other: &Self) -> Ordering {
self.name().cmp(other.name())
}
}
impl<Identifier> PartialEq for NamedRef<Identifier> {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
}
}
impl<Identifier> PartialOrd for NamedRef<Identifier> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<Identifier> Default for SolveObjective<Identifier> {
fn default() -> Self {
Self {
method: Default::default(),
ann: Vec::new(),
}
}
}
impl<Identifier: Display> Display for SolveObjective<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "solve ")?;
for a in &self.ann {
write!(f, "::{a} ")?;
}
write!(f, "{}", self.method)
}
}
impl Type {
fn base_name(&self) -> &'static str {
match self {
Type::Bool => "bool",
Type::Int(_) => "int",
Type::Float(_) => "float",
Type::IntSet(_) => "set of int",
}
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Type::Bool => write!(f, "bool"),
Type::Int(Some(domain)) => write!(f, "{domain}"),
Type::Int(None) => write!(f, "int"),
Type::Float(Some(domain)) => write!(f, "{domain}"),
Type::Float(None) => write!(f, "float"),
Type::IntSet(Some(domain)) => write!(f, "set of {domain}"),
Type::IntSet(None) => write!(f, "set of int"),
}
}
}
impl<Identifier> Variable<Identifier> {
pub fn cloned_key(self: &Arc<Self>) -> ArcKey<Self> {
ArcKey::new(Arc::clone(self))
}
}