From 49051358f008432fe9d1aa98fe426baa759c777a Mon Sep 17 00:00:00 2001 From: elvis Date: Sun, 7 Sep 2025 17:55:53 +0200 Subject: [PATCH] rustfmt, fixed prohibiting set generation --- src/main.rs | 6 +- src/rsprocess/assert/dsl.rs | 1553 ++++++++------- src/rsprocess/assert/fmt.rs | 727 +++---- src/rsprocess/assert/rsassert.rs | 334 ++-- src/rsprocess/assert/tests.rs | 1677 ++++++++--------- .../bisimilarity_kanellakis_smolka.rs | 203 +- .../bisimilarity/bisimilarity_paige_tarkan.rs | 806 ++++---- .../bisimilarity/test_paige_tarjan.rs | 3 +- src/rsprocess/choices.rs | 231 +-- src/rsprocess/dot.rs | 249 ++- src/rsprocess/element.rs | 55 +- src/rsprocess/environment.rs | 930 +++++---- src/rsprocess/format_helpers.rs | 730 ++++--- src/rsprocess/frequency.rs | 412 ++-- src/rsprocess/graph.rs | 876 +++++---- src/rsprocess/label.rs | 227 ++- src/rsprocess/mod.rs | 6 +- src/rsprocess/presets.rs | 429 ++--- src/rsprocess/process.rs | 710 +++---- src/rsprocess/reaction.rs | 266 ++- src/rsprocess/serialize.rs | 22 +- src/rsprocess/set.rs | 657 ++++--- src/rsprocess/set_test.rs | 117 +- src/rsprocess/system.rs | 858 ++++----- src/rsprocess/system_test.rs | 348 ++-- src/rsprocess/transitions.rs | 103 +- src/rsprocess/translator.rs | 65 +- 27 files changed, 6138 insertions(+), 6462 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3390062..c104907 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,11 +5,13 @@ fn main() { std::io::stdin().read_line(&mut input).unwrap(); input = input.trim().into(); + // let input = "testing/medical.system"; + let now = std::time::Instant::now(); match presets::run(input) { - Ok(()) => {}, - Err(e) => println!("{e}") + Ok(()) => {} + Err(e) => println!("{e}"), } println!("{} milliseconds elapsed", now.elapsed().as_millis()); diff --git a/src/rsprocess/assert/dsl.rs b/src/rsprocess/assert/dsl.rs index b2fe12b..c8d1d52 100644 --- a/src/rsprocess/assert/dsl.rs +++ b/src/rsprocess/assert/dsl.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; -use super::super::{translator, graph, set, process, system, label, element}; use super::super::set::BasicSet; +use super::super::{element, graph, label, process, set, system, translator}; /// If changing IntegerType in assert.rs, also change from Num to another /// similar parser with different return type in grammar.lalrpop in @@ -10,7 +10,7 @@ type IntegerType = i64; #[derive(Clone)] pub struct Assert { - pub tree: Tree + pub tree: Tree, } #[derive(Clone)] @@ -26,12 +26,12 @@ pub enum Tree { #[derive(Clone, PartialEq, Eq, Hash)] pub enum Variable { Id(String), - Special(S) + Special(S), } /// Trait needed for special variables. -pub(super) trait SpecialVariables: translator::PrintableWithTranslator - + std::fmt::Debug + Sized + Eq + Copy + std::hash::Hash +pub(super) trait SpecialVariables: + translator::PrintableWithTranslator + std::fmt::Debug + Sized + Eq + Copy + std::hash::Hash { /// Returns the type of the specific special variable. fn type_of(&self) -> AssertionTypes; @@ -40,8 +40,7 @@ pub(super) trait SpecialVariables: translator::PrintableWithTranslator fn type_qualified(&self, q: &Qualifier) -> Result; /// Creates a new context. - fn new_context(input: HashMap) - -> HashMap; + fn new_context(input: HashMap) -> HashMap; /// Returns true if fn correct_type(&self, other: &AssertReturnValue) -> bool; @@ -189,326 +188,258 @@ pub enum AssertReturnValue { // ----------------------------------------------------------------------------- impl QualifierRestricted { - pub(super) fn referenced_mut<'a>( - &self, - label: &'a mut label::Label, - ) -> &'a mut set::Set { - match self { - Self::Entities => {&mut label.available_entities}, - Self::Context => {&mut label.context}, - Self::Reactants => {&mut label.reactants}, - Self::ReactantsAbsent => {&mut label.reactants_absent}, - Self::Inhibitors => {&mut label.inhibitors}, - Self::InhibitorsPresent => {&mut label.inhibitors_present}, - Self::Products => {&mut label.products}, - } + pub(super) fn referenced_mut<'a>(&self, label: &'a mut label::Label) -> &'a mut set::Set { + match self { + Self::Entities => &mut label.available_entities, + Self::Context => &mut label.context, + Self::Reactants => &mut label.reactants, + Self::ReactantsAbsent => &mut label.reactants_absent, + Self::Inhibitors => &mut label.inhibitors, + Self::InhibitorsPresent => &mut label.inhibitors_present, + Self::Products => &mut label.products, + } } - pub(super) fn referenced<'a>( - &self, - label: &'a label::Label, - ) -> &'a set::Set { - match self { - Self::Entities => {&label.available_entities}, - Self::Context => {&label.context}, - Self::Reactants => {&label.reactants}, - Self::ReactantsAbsent => {&label.reactants_absent}, - Self::Inhibitors => {&label.inhibitors}, - Self::InhibitorsPresent => {&label.inhibitors_present}, - Self::Products => {&label.products}, - } + pub(super) fn referenced<'a>(&self, label: &'a label::Label) -> &'a set::Set { + match self { + Self::Entities => &label.available_entities, + Self::Context => &label.context, + Self::Reactants => &label.reactants, + Self::ReactantsAbsent => &label.reactants_absent, + Self::Inhibitors => &label.inhibitors, + Self::InhibitorsPresent => &label.inhibitors_present, + Self::Products => &label.products, + } } - pub(super) fn get( - &self, - label: &label::Label, - ) -> AssertReturnValue { - AssertReturnValue::Set(self.referenced(label).clone()) + pub(super) fn get(&self, label: &label::Label) -> AssertReturnValue { + AssertReturnValue::Set(self.referenced(label).clone()) } } impl QualifierLabel { - pub(super) fn get( - &self, - l: &label::Label, - ) -> AssertReturnValue { - match self { - QualifierLabel::AvailableEntities => { - AssertReturnValue::Set(l.t.clone()) - }, - QualifierLabel::AllReactants => { - AssertReturnValue::Set(l.reactants.union(&l.reactants_absent)) - }, - QualifierLabel::AllInhibitors => { - AssertReturnValue::Set( - l.inhibitors.union(&l.inhibitors_present)) - }, - } + pub(super) fn get(&self, l: &label::Label) -> AssertReturnValue { + match self { + QualifierLabel::AvailableEntities => AssertReturnValue::Set(l.t.clone()), + QualifierLabel::AllReactants => { + AssertReturnValue::Set(l.reactants.union(&l.reactants_absent)) + } + QualifierLabel::AllInhibitors => { + AssertReturnValue::Set(l.inhibitors.union(&l.inhibitors_present)) + } + } } } impl QualifierSystem { - pub(super) fn get( - &self, - l: &system::System, - ) -> AssertReturnValue { - match self { - Self::Context => { - AssertReturnValue::Context(l.context_process.clone()) - }, - Self::Entities => { - AssertReturnValue::Set(l.available_entities.clone()) - } - } + pub(super) fn get(&self, l: &system::System) -> AssertReturnValue { + match self { + Self::Context => AssertReturnValue::Context(l.context_process.clone()), + Self::Entities => AssertReturnValue::Set(l.available_entities.clone()), + } } } impl Unary { pub(super) fn is_prefix(&self) -> bool { - match self { - Self::Not | - Self::Rand => true, - Self::Empty | - Self::Length | - Self::ToStr | - Self::Qualifier(_) | - Self::ToEl => false, - } + match self { + Self::Not | Self::Rand => true, + Self::Empty | Self::Length | Self::ToStr | Self::Qualifier(_) | Self::ToEl => false, + } } pub(super) fn is_suffix(&self) -> bool { - !self.is_prefix() + !self.is_prefix() } - pub(super) fn associate( - &self, - type_exp: &AssertionTypes - ) -> Result { - match (self, type_exp) { - (Self::Not, AssertionTypes::Boolean) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Rand, AssertionTypes::Integer) => { - Ok(AssertionTypes::Integer) - }, - (Self::Empty, AssertionTypes::Set) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Length, AssertionTypes::Set) | - (Self::Length, AssertionTypes::String) => { - Ok(AssertionTypes::Integer) - }, - (Self::ToStr, AssertionTypes::Boolean) | - (Self::ToStr, AssertionTypes::Element) | - (Self::ToStr, AssertionTypes::Integer) => { - Ok(AssertionTypes::String) - }, - (Self::Qualifier(Qualifier::Label(_)), AssertionTypes::Label) => { - Ok(AssertionTypes::Set) - }, - (Self::Qualifier(Qualifier::Restricted(_)), - AssertionTypes::Label) => { - Ok(AssertionTypes::Set) - }, - (Self::ToEl, AssertionTypes::String) => { - Ok(AssertionTypes::Element) - }, - (Self::Qualifier(Qualifier::Edge(_)), AssertionTypes::Edge) => { - Ok(AssertionTypes::Node) - }, - (Self::Qualifier(Qualifier::Node(QualifierNode::Neighbours)), - AssertionTypes::Node) => { - Ok(AssertionTypes::RangeNeighbours) - }, - (Self::Qualifier( - Qualifier::System(QualifierSystem::Entities)), - AssertionTypes::System) => { - Ok(AssertionTypes::Set) - }, - (Self::Qualifier( - Qualifier::System(QualifierSystem::Context)), - AssertionTypes::System) => { - Ok(AssertionTypes::Context) - }, - (Self::Qualifier(Qualifier::Node(QualifierNode::System)), - AssertionTypes::Node) => { - Ok(AssertionTypes::System) - }, - (op, type_exp) => { - Err(format!("Expression has incompatible type with operation: \ - {type_exp:?} with operation {op:?}.")) - } - } + pub(super) fn associate(&self, type_exp: &AssertionTypes) -> Result { + match (self, type_exp) { + (Self::Not, AssertionTypes::Boolean) => Ok(AssertionTypes::Boolean), + (Self::Rand, AssertionTypes::Integer) => Ok(AssertionTypes::Integer), + (Self::Empty, AssertionTypes::Set) => Ok(AssertionTypes::Boolean), + (Self::Length, AssertionTypes::Set) | (Self::Length, AssertionTypes::String) => { + Ok(AssertionTypes::Integer) + } + (Self::ToStr, AssertionTypes::Boolean) + | (Self::ToStr, AssertionTypes::Element) + | (Self::ToStr, AssertionTypes::Integer) => Ok(AssertionTypes::String), + (Self::Qualifier(Qualifier::Label(_)), AssertionTypes::Label) => { + Ok(AssertionTypes::Set) + } + (Self::Qualifier(Qualifier::Restricted(_)), AssertionTypes::Label) => { + Ok(AssertionTypes::Set) + } + (Self::ToEl, AssertionTypes::String) => Ok(AssertionTypes::Element), + (Self::Qualifier(Qualifier::Edge(_)), AssertionTypes::Edge) => Ok(AssertionTypes::Node), + (Self::Qualifier(Qualifier::Node(QualifierNode::Neighbours)), AssertionTypes::Node) => { + Ok(AssertionTypes::RangeNeighbours) + } + ( + Self::Qualifier(Qualifier::System(QualifierSystem::Entities)), + AssertionTypes::System, + ) => Ok(AssertionTypes::Set), + ( + Self::Qualifier(Qualifier::System(QualifierSystem::Context)), + AssertionTypes::System, + ) => Ok(AssertionTypes::Context), + (Self::Qualifier(Qualifier::Node(QualifierNode::System)), AssertionTypes::Node) => { + Ok(AssertionTypes::System) + } + (op, type_exp) => Err(format!( + "Expression has incompatible type with operation: \ + {type_exp:?} with operation {op:?}." + )), + } } } impl Binary { pub(super) fn is_prefix(&self) -> bool { - match self { - Self::And | - Self::Or | - Self::Xor | - Self::Less | - Self::LessEq | - Self::More | - Self::MoreEq | - Self::Eq | - Self::NotEq | - Self::Plus | - Self::Minus | - Self::Times | - Self::Exponential | - Self::Quotient | - Self::Reminder | - Self::Concat => false, - Self::SubStr | - Self::Min | - Self::Max | - Self::CommonSubStr => true, - } + match self { + Self::And + | Self::Or + | Self::Xor + | Self::Less + | Self::LessEq + | Self::More + | Self::MoreEq + | Self::Eq + | Self::NotEq + | Self::Plus + | Self::Minus + | Self::Times + | Self::Exponential + | Self::Quotient + | Self::Reminder + | Self::Concat => false, + Self::SubStr | Self::Min | Self::Max | Self::CommonSubStr => true, + } } pub(super) fn is_suffix(&self) -> bool { - false + false } pub(super) fn is_infix(&self) -> bool { - match self { - Self::And | - Self::Or | - Self::Xor | - Self::Less | - Self::LessEq | - Self::More | - Self::MoreEq | - Self::Eq | - Self::NotEq | - Self::Plus | - Self::Minus | - Self::Times | - Self::Exponential | - Self::Quotient | - Self::Reminder | - Self::Concat => true, - Self::SubStr | - Self::Min | - Self::Max | - Self::CommonSubStr => false, - } + match self { + Self::And + | Self::Or + | Self::Xor + | Self::Less + | Self::LessEq + | Self::More + | Self::MoreEq + | Self::Eq + | Self::NotEq + | Self::Plus + | Self::Minus + | Self::Times + | Self::Exponential + | Self::Quotient + | Self::Reminder + | Self::Concat => true, + Self::SubStr | Self::Min | Self::Max | Self::CommonSubStr => false, + } } pub(super) fn associate( - &self, - t1: &AssertionTypes, - t2: &AssertionTypes + &self, + t1: &AssertionTypes, + t2: &AssertionTypes, ) -> Result { - match (self, t1, t2) { - (Self::And, AssertionTypes::Boolean, AssertionTypes::Boolean) | - (Self::Or, AssertionTypes::Boolean, AssertionTypes::Boolean) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Xor, AssertionTypes::Boolean, AssertionTypes::Boolean) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Xor, AssertionTypes::Set, AssertionTypes::Set)=> { - Ok(AssertionTypes::Set) - }, - (Self::Less, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::Less, AssertionTypes::Set, AssertionTypes::Set) | - (Self::LessEq, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::LessEq, AssertionTypes::Set, AssertionTypes::Set) | - (Self::More, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::More, AssertionTypes::Set, AssertionTypes::Set) | - (Self::MoreEq, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::MoreEq, AssertionTypes::Set, AssertionTypes::Set ) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Eq, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::Eq, AssertionTypes::Boolean, AssertionTypes::Boolean) | - (Self::Eq, AssertionTypes::Element, AssertionTypes::Element) | - (Self::Eq, AssertionTypes::Label, AssertionTypes::Label) | - (Self::Eq, AssertionTypes::String, AssertionTypes::String) | - (Self::Eq, AssertionTypes::Set, AssertionTypes::Set) | - (Self::NotEq, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::NotEq, AssertionTypes::Boolean, AssertionTypes::Boolean) | - (Self::NotEq, AssertionTypes::Element, AssertionTypes::Element) | - (Self::NotEq, AssertionTypes::Label, AssertionTypes::Label) | - (Self::NotEq, AssertionTypes::String, AssertionTypes::String) | - (Self::NotEq, AssertionTypes::Set, AssertionTypes::Set) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Plus, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::Minus, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::Times, AssertionTypes::Integer, AssertionTypes::Integer) => { - Ok(AssertionTypes::Integer) - }, - (Self::Plus, AssertionTypes::Set, AssertionTypes::Set) | - (Self::Minus, AssertionTypes::Set, AssertionTypes::Set) | - (Self::Times, AssertionTypes::Set, AssertionTypes::Set) => { - Ok(AssertionTypes::Set) - }, - (Self::Exponential, - AssertionTypes::Integer, - AssertionTypes::Integer) | - (Self::Quotient, - AssertionTypes::Integer, - AssertionTypes::Integer) | - (Self::Reminder, - AssertionTypes::Integer, - AssertionTypes::Integer) => { - Ok(AssertionTypes::Integer) - }, - (Self::Concat, AssertionTypes::String, AssertionTypes::String) => { - Ok(AssertionTypes::String) - }, - (Self::SubStr, AssertionTypes::String, AssertionTypes::String) => { - Ok(AssertionTypes::Boolean) - }, - (Self::Min, AssertionTypes::Integer, AssertionTypes::Integer) | - (Self::Max, AssertionTypes::Integer, AssertionTypes::Integer) => { - Ok(AssertionTypes::Integer) - }, - (Self::CommonSubStr, - AssertionTypes::String, - AssertionTypes::String) => { - Ok(AssertionTypes::String) - }, - _ => { - Err(format!("Expressions have incompatible types: {t1:?} and \ - {t2:?} with operation {self:?}.")) - } - } + match (self, t1, t2) { + (Self::And, AssertionTypes::Boolean, AssertionTypes::Boolean) + | (Self::Or, AssertionTypes::Boolean, AssertionTypes::Boolean) => { + Ok(AssertionTypes::Boolean) + } + (Self::Xor, AssertionTypes::Boolean, AssertionTypes::Boolean) => { + Ok(AssertionTypes::Boolean) + } + (Self::Xor, AssertionTypes::Set, AssertionTypes::Set) => Ok(AssertionTypes::Set), + (Self::Less, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Less, AssertionTypes::Set, AssertionTypes::Set) + | (Self::LessEq, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::LessEq, AssertionTypes::Set, AssertionTypes::Set) + | (Self::More, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::More, AssertionTypes::Set, AssertionTypes::Set) + | (Self::MoreEq, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::MoreEq, AssertionTypes::Set, AssertionTypes::Set) => { + Ok(AssertionTypes::Boolean) + } + (Self::Eq, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Eq, AssertionTypes::Boolean, AssertionTypes::Boolean) + | (Self::Eq, AssertionTypes::Element, AssertionTypes::Element) + | (Self::Eq, AssertionTypes::Label, AssertionTypes::Label) + | (Self::Eq, AssertionTypes::String, AssertionTypes::String) + | (Self::Eq, AssertionTypes::Set, AssertionTypes::Set) + | (Self::NotEq, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::NotEq, AssertionTypes::Boolean, AssertionTypes::Boolean) + | (Self::NotEq, AssertionTypes::Element, AssertionTypes::Element) + | (Self::NotEq, AssertionTypes::Label, AssertionTypes::Label) + | (Self::NotEq, AssertionTypes::String, AssertionTypes::String) + | (Self::NotEq, AssertionTypes::Set, AssertionTypes::Set) => { + Ok(AssertionTypes::Boolean) + } + (Self::Plus, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Minus, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Times, AssertionTypes::Integer, AssertionTypes::Integer) => { + Ok(AssertionTypes::Integer) + } + (Self::Plus, AssertionTypes::Set, AssertionTypes::Set) + | (Self::Minus, AssertionTypes::Set, AssertionTypes::Set) + | (Self::Times, AssertionTypes::Set, AssertionTypes::Set) => Ok(AssertionTypes::Set), + (Self::Exponential, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Quotient, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Reminder, AssertionTypes::Integer, AssertionTypes::Integer) => { + Ok(AssertionTypes::Integer) + } + (Self::Concat, AssertionTypes::String, AssertionTypes::String) => { + Ok(AssertionTypes::String) + } + (Self::SubStr, AssertionTypes::String, AssertionTypes::String) => { + Ok(AssertionTypes::Boolean) + } + (Self::Min, AssertionTypes::Integer, AssertionTypes::Integer) + | (Self::Max, AssertionTypes::Integer, AssertionTypes::Integer) => { + Ok(AssertionTypes::Integer) + } + (Self::CommonSubStr, AssertionTypes::String, AssertionTypes::String) => { + Ok(AssertionTypes::String) + } + _ => Err(format!( + "Expressions have incompatible types: {t1:?} and \ + {t2:?} with operation {self:?}." + )), + } } } impl AssertReturnValue { pub(super) fn assign_qualified( - &mut self, q: Qualifier, val: AssertReturnValue + &mut self, + q: Qualifier, + val: AssertReturnValue, ) -> Result<(), String> { - match (self, q, val) { - (Self::Label(l), - Qualifier::Restricted(q), - AssertReturnValue::Set(set)) => { - *q.referenced_mut(l) = set; - Ok(()) - }, - (s, q, val) => { - Err(format!("Cannot assign {val:?} to {s:?} with qualifier \ - {q:?}")) - } - } + match (self, q, val) { + (Self::Label(l), Qualifier::Restricted(q), AssertReturnValue::Set(set)) => { + *q.referenced_mut(l) = set; + Ok(()) + } + (s, q, val) => Err(format!( + "Cannot assign {val:?} to {s:?} with qualifier \ + {q:?}" + )), + } } } - - // ----------------------------------------------------------------------------- // Typechecking and Evaluation // ----------------------------------------------------------------------------- pub(super) struct TypeContext { data: HashMap, - return_ty: Option + return_ty: Option, } pub(super) struct Context { @@ -518,453 +449,440 @@ pub(super) struct Context { impl TypeContext { pub(super) fn new() -> Self { - TypeContext { - data: HashMap::new(), - return_ty: None - } + TypeContext { + data: HashMap::new(), + return_ty: None, + } } - fn return_type( - &mut self, - ty: AssertionTypes - ) -> Result<(), String> { - if let Some(ty_return) = self.return_ty { - if ty_return == ty { - Ok(()) - } else { - Err(format!("Return statements don't agree: {ty_return:?} and \ - {ty:?} found.")) - } - } else { - self.return_ty = Some(ty); - Ok(()) - } + fn return_type(&mut self, ty: AssertionTypes) -> Result<(), String> { + if let Some(ty_return) = self.return_ty { + if ty_return == ty { + Ok(()) + } else { + Err(format!( + "Return statements don't agree: {ty_return:?} and \ + {ty:?} found." + )) + } + } else { + self.return_ty = Some(ty); + Ok(()) + } } } impl TypeContext { fn assign( - &mut self, - v: &Variable, - q: Option<&Qualifier>, - ty: AssertionTypes + &mut self, + v: &Variable, + q: Option<&Qualifier>, + ty: AssertionTypes, ) -> Result<(), String> - where S: SpecialVariables { - match (v, q) { - (Variable::Id(v), None) => { - self.data.insert(v.clone(), ty); - Ok(()) - }, - (Variable::Id(v), Some(q)) => { - match self.data.entry(v.clone()) { - std::collections::hash_map::Entry::Vacant(_ve) => { - Err(format!("Variable {v:?} as no assignment while \ + where + S: SpecialVariables, + { + match (v, q) { + (Variable::Id(v), None) => { + self.data.insert(v.clone(), ty); + Ok(()) + } + (Variable::Id(v), Some(q)) => match self.data.entry(v.clone()) { + std::collections::hash_map::Entry::Vacant(_ve) => Err(format!( + "Variable {v:?} as no assignment while \ trying to assign to qualification {q:?}, \ - assign first a value.")) - }, - std::collections::hash_map::Entry::Occupied(oe) => { - match (oe.get(), q, ty) { - (AssertionTypes::Label, - Qualifier::Restricted(_), - AssertionTypes::Set) => { - Ok(()) - }, - (t, q, ty) => { - Err(format!("Variable {v:?} has type {t:?}, \ + assign first a value." + )), + std::collections::hash_map::Entry::Occupied(oe) => match (oe.get(), q, ty) { + (AssertionTypes::Label, Qualifier::Restricted(_), AssertionTypes::Set) => { + Ok(()) + } + (t, q, ty) => Err(format!( + "Variable {v:?} has type {t:?}, \ but was assigned with qualifier \ - {q:?} value with type {ty:?}.")) - } - } - } - } - }, - (Variable::Special(s), None) => { - if s.type_of() == ty { - Ok(()) - } else { - Err(format!("Variable {s:?} has type {:?} but was \ + {q:?} value with type {ty:?}." + )), + }, + }, + (Variable::Special(s), None) => { + if s.type_of() == ty { + Ok(()) + } else { + Err(format!( + "Variable {s:?} has type {:?} but was \ assigned a value of type {ty:?}.", - s.type_of())) - } - }, - (Variable::Special(s), Some(q)) => { - if s.type_qualified(q)? == ty { - Ok(()) - } else { - Err(format!("Variable {s:?} has type {:?} but was \ + s.type_of() + )) + } + } + (Variable::Special(s), Some(q)) => { + if s.type_qualified(q)? == ty { + Ok(()) + } else { + Err(format!( + "Variable {s:?} has type {:?} but was \ assigned a value of type {ty:?} with \ - qualifier {q:?}.", s.type_of())) - } - } - } + qualifier {q:?}.", + s.type_of() + )) + } + } + } } - fn assign_range( - &mut self, - v: &Variable, - ty: AssertionTypes - ) -> Result<(), String> - where S: SpecialVariables { - let v = match v { - Variable::Special(s) => - return Err(format!("Protected word {s:?} used in for \ - assignment.")), - Variable::Id(v) => v - }; - match ty { - AssertionTypes::RangeSet => { - self.data.insert(v.clone(), AssertionTypes::Element); - Ok(()) - }, - AssertionTypes::RangeInteger => { - self.data.insert(v.clone(), AssertionTypes::Integer); - Ok(()) - }, - AssertionTypes::RangeNeighbours => { - self.data.insert(v.clone(), AssertionTypes::Edge); - Ok(()) - }, - _ => { - Err(format!("Range has incorrect type {ty:?}.")) - }, - } + fn assign_range(&mut self, v: &Variable, ty: AssertionTypes) -> Result<(), String> + where + S: SpecialVariables, + { + let v = match v { + Variable::Special(s) => { + return Err(format!( + "Protected word {s:?} used in for \ + assignment." + )); + } + Variable::Id(v) => v, + }; + match ty { + AssertionTypes::RangeSet => { + self.data.insert(v.clone(), AssertionTypes::Element); + Ok(()) + } + AssertionTypes::RangeInteger => { + self.data.insert(v.clone(), AssertionTypes::Integer); + Ok(()) + } + AssertionTypes::RangeNeighbours => { + self.data.insert(v.clone(), AssertionTypes::Edge); + Ok(()) + } + _ => Err(format!("Range has incorrect type {ty:?}.")), + } } - fn get( - &self, - v: &Variable, - ) -> Result - where S: SpecialVariables { - match v { - Variable::Special(s) => { - Ok(s.type_of()) - }, - Variable::Id(v) => { - if let Some(ty) = self.data.get(v) { - Ok(*ty) - } else { - Err(format!("Could not find variable {v:?}.")) - } - }, - } + fn get(&self, v: &Variable) -> Result + where + S: SpecialVariables, + { + match v { + Variable::Special(s) => Ok(s.type_of()), + Variable::Id(v) => { + if let Some(ty) = self.data.get(v) { + Ok(*ty) + } else { + Err(format!("Could not find variable {v:?}.")) + } + } + } } } impl Context { - pub(super) fn new( - input: HashMap, - ) -> Self - where S: SpecialVariables { - Self { data: HashMap::new(), - special: S::new_context(input) } + pub(super) fn new(input: HashMap) -> Self + where + S: SpecialVariables, + { + Self { + data: HashMap::new(), + special: S::new_context(input), + } } fn assign( - &mut self, - v: &Variable, - q: Option<&Qualifier>, - val: AssertReturnValue, + &mut self, + v: &Variable, + q: Option<&Qualifier>, + val: AssertReturnValue, ) -> Result<(), String> - where S: SpecialVariables { - match (v, q) { - (Variable::Id(v), None) => { - self.data.insert(v.clone(), val); - Ok(()) - }, - (Variable::Id(v), Some(q)) => { - match self.data.entry(v.clone()) { - std::collections::hash_map::Entry::Vacant(_ve) => { - Err(format!("Variable {v:?} as no assignment while \ + where + S: SpecialVariables, + { + match (v, q) { + (Variable::Id(v), None) => { + self.data.insert(v.clone(), val); + Ok(()) + } + (Variable::Id(v), Some(q)) => match self.data.entry(v.clone()) { + std::collections::hash_map::Entry::Vacant(_ve) => Err(format!( + "Variable {v:?} as no assignment while \ trying to assign to qualification {q:?}, \ - assign first a value.")) - }, - std::collections::hash_map::Entry::Occupied(mut oe) => { - match (oe.get_mut(), q, val) { - (&mut AssertReturnValue::Label(ref mut l), - Qualifier::Restricted(q), - AssertReturnValue::Set(set)) => { - *q.referenced_mut(l) = set; - Ok(()) - }, - (val, q, newval) => { - Err(format!("Variable {v:?} has value {val:?}, \ + assign first a value." + )), + std::collections::hash_map::Entry::Occupied(mut oe) => { + match (oe.get_mut(), q, val) { + ( + &mut AssertReturnValue::Label(ref mut l), + Qualifier::Restricted(q), + AssertReturnValue::Set(set), + ) => { + *q.referenced_mut(l) = set; + Ok(()) + } + (val, q, newval) => Err(format!( + "Variable {v:?} has value {val:?}, \ but was assigned with qualifier \ - {q:?} new value {newval:?}.")) - } - } - } - } - }, - (Variable::Special(s), None) => { - if s.correct_type(&val) { - if let Some(s) = self.special.get_mut(s) { - *s = val; - } else { - self.special.insert(*s, val); - } - Ok(()) - } else { - Err(format!("Trying to assign {val:?} to variable {s:?}.")) - } - }, - (Variable::Special(s), Some(q)) => { - if let Some(s) = self.special.get_mut(s) { - s.assign_qualified(*q, val) - } else { - Err(format!("Trying to assign {val:?} to variable {s:?} \ + {q:?} new value {newval:?}." + )), + } + } + }, + (Variable::Special(s), None) => { + if s.correct_type(&val) { + if let Some(s) = self.special.get_mut(s) { + *s = val; + } else { + self.special.insert(*s, val); + } + Ok(()) + } else { + Err(format!("Trying to assign {val:?} to variable {s:?}.")) + } + } + (Variable::Special(s), Some(q)) => { + if let Some(s) = self.special.get_mut(s) { + s.assign_qualified(*q, val) + } else { + Err(format!( + "Trying to assign {val:?} to variable {s:?} \ with qualifier {q:?} but no value for {val:?} \ - was found.")) - } - } - } + was found." + )) + } + } + } } - fn get( - &self, - v: &Variable, - ) -> Result - where S: SpecialVariables { - match v { - Variable::Id(var) => { - self.data.get(var) - .cloned() - .ok_or(format!("Variable {v:?} used, but no value \ - assigned.")) - }, - Variable::Special(s) => { - self.special.get(s) - .cloned() - .ok_or(format!("Variable {v:?} used but no value \ - assigned.")) - }, - } + fn get(&self, v: &Variable) -> Result + where + S: SpecialVariables, + { + match v { + Variable::Id(var) => self.data.get(var).cloned().ok_or(format!( + "Variable {v:?} used, but no value \ + assigned." + )), + Variable::Special(s) => self.special.get(s).cloned().ok_or(format!( + "Variable {v:?} used but no value \ + assigned." + )), + } } } impl AssertReturnValue { fn unary( - self, - u: &Unary, - translator: &mut translator::Translator, - graph: &graph::SystemGraph, + self, + u: &Unary, + translator: &mut translator::Translator, + graph: &graph::SystemGraph, ) -> Result { - match (self, u) { - (AssertReturnValue::Boolean(b), Unary::Not) => { - Ok(AssertReturnValue::Boolean(!b)) - }, - (AssertReturnValue::Integer(i), Unary::Rand) => { - Ok(AssertReturnValue::Integer(rand::random_range(0..i))) - }, - (AssertReturnValue::Set(set), Unary::Empty) => { - Ok(AssertReturnValue::Boolean(set.is_empty())) - }, - (AssertReturnValue::String(s), Unary::Empty) => { - Ok(AssertReturnValue::Boolean(s.is_empty())) - }, - (AssertReturnValue::Set(set), Unary::Length) => { - Ok(AssertReturnValue::Integer(set.len() as i64)) - }, - (AssertReturnValue::String(s), Unary::Length) => { - Ok(AssertReturnValue::Integer(s.len() as i64)) - }, - (AssertReturnValue::Boolean(b), Unary::ToStr) => { - Ok(AssertReturnValue::String(format!("{b}"))) - }, - (AssertReturnValue::Integer(i), Unary::ToStr) => { - Ok(AssertReturnValue::String(format!("{i}"))) - }, - (AssertReturnValue::Element(el), Unary::ToStr) => { - Ok(AssertReturnValue::String( - translator.decode(el).ok_or( - format!("Could not find element {el:?}.") - )? - )) - }, - (AssertReturnValue::Label(l), - Unary::Qualifier(Qualifier::Label(q))) => { - Ok(q.get(&l)) - }, - (AssertReturnValue::Label(l), - Unary::Qualifier(Qualifier::Restricted(q))) => { - Ok(q.get(&l)) - }, - (AssertReturnValue::String(s), Unary::ToEl) => { - Ok(AssertReturnValue::Element(translator.encode(s))) - }, - (AssertReturnValue::Edge(edge), - Unary::Qualifier(Qualifier::Edge(QualifierEdge::Source))) => { - Ok(AssertReturnValue::Node( - graph.edge_endpoints(edge).unwrap().0)) - }, - (AssertReturnValue::Edge(edge), - Unary::Qualifier(Qualifier::Edge(QualifierEdge::Target))) => { - Ok(AssertReturnValue::Node( - graph.edge_endpoints(edge).unwrap().1)) - }, - (AssertReturnValue::Node(node), - Unary::Qualifier(Qualifier::Node(QualifierNode::Neighbours))) => { - Ok(AssertReturnValue::Neighbours(node)) - }, - (AssertReturnValue::Node(node), - Unary::Qualifier(Qualifier::Node(QualifierNode::System))) => { - Ok(AssertReturnValue::System( - graph.node_weight(node).unwrap().clone() - )) - }, - (AssertReturnValue::System(sys), - Unary::Qualifier(Qualifier::System(q))) => { - Ok(q.get(&sys)) - } - (val, u) => { - Err(format!("Incompatible unary operation {u:?} on value \ - {val:?}.")) - } - } + match (self, u) { + (AssertReturnValue::Boolean(b), Unary::Not) => Ok(AssertReturnValue::Boolean(!b)), + (AssertReturnValue::Integer(i), Unary::Rand) => { + Ok(AssertReturnValue::Integer(rand::random_range(0..i))) + } + (AssertReturnValue::Set(set), Unary::Empty) => { + Ok(AssertReturnValue::Boolean(set.is_empty())) + } + (AssertReturnValue::String(s), Unary::Empty) => { + Ok(AssertReturnValue::Boolean(s.is_empty())) + } + (AssertReturnValue::Set(set), Unary::Length) => { + Ok(AssertReturnValue::Integer(set.len() as i64)) + } + (AssertReturnValue::String(s), Unary::Length) => { + Ok(AssertReturnValue::Integer(s.len() as i64)) + } + (AssertReturnValue::Boolean(b), Unary::ToStr) => { + Ok(AssertReturnValue::String(format!("{b}"))) + } + (AssertReturnValue::Integer(i), Unary::ToStr) => { + Ok(AssertReturnValue::String(format!("{i}"))) + } + (AssertReturnValue::Element(el), Unary::ToStr) => Ok(AssertReturnValue::String( + translator + .decode(el) + .ok_or(format!("Could not find element {el:?}."))?, + )), + (AssertReturnValue::Label(l), Unary::Qualifier(Qualifier::Label(q))) => Ok(q.get(&l)), + (AssertReturnValue::Label(l), Unary::Qualifier(Qualifier::Restricted(q))) => { + Ok(q.get(&l)) + } + (AssertReturnValue::String(s), Unary::ToEl) => { + Ok(AssertReturnValue::Element(translator.encode(s))) + } + ( + AssertReturnValue::Edge(edge), + Unary::Qualifier(Qualifier::Edge(QualifierEdge::Source)), + ) => Ok(AssertReturnValue::Node( + graph.edge_endpoints(edge).unwrap().0, + )), + ( + AssertReturnValue::Edge(edge), + Unary::Qualifier(Qualifier::Edge(QualifierEdge::Target)), + ) => Ok(AssertReturnValue::Node( + graph.edge_endpoints(edge).unwrap().1, + )), + ( + AssertReturnValue::Node(node), + Unary::Qualifier(Qualifier::Node(QualifierNode::Neighbours)), + ) => Ok(AssertReturnValue::Neighbours(node)), + ( + AssertReturnValue::Node(node), + Unary::Qualifier(Qualifier::Node(QualifierNode::System)), + ) => Ok(AssertReturnValue::System( + graph.node_weight(node).unwrap().clone(), + )), + (AssertReturnValue::System(sys), Unary::Qualifier(Qualifier::System(q))) => { + Ok(q.get(&sys)) + } + (val, u) => Err(format!( + "Incompatible unary operation {u:?} on value \ + {val:?}." + )), + } } fn binary( - self, - b: &Binary, - other: AssertReturnValue, - _translator: &mut translator::Translator + self, + b: &Binary, + other: AssertReturnValue, + _translator: &mut translator::Translator, ) -> Result { - use AssertReturnValue::*; - Ok(match (b, self, other) { - (Binary::And, Boolean(b1), Boolean(b2)) => {Boolean(b1 && b2)}, - (Binary::Or, Boolean(b1), Boolean(b2)) => {Boolean(b1 || b2)}, - (Binary::Xor, Boolean(b1), Boolean(b2)) => {Boolean(b1 ^ b2)}, - (Binary::Xor, Set(s1), Set(s2)) => { - Set(s1.union(&s2).subtraction(&s1.intersection(&s2))) - }, - (Binary::Less, Integer(i1), Integer(i2)) => {Boolean(i1 < i2)}, - (Binary::Less, Set(s1), Set(s2)) => { - Boolean(s1.is_subset(&s2) && !s2.is_subset(&s1))}, - (Binary::LessEq, Integer(i1), Integer(i2)) => {Boolean(i1 <= i2)}, - (Binary::LessEq, Set(s1), Set(s2)) => { - Boolean(s1.is_subset(&s2))}, - (Binary::More, Integer(i1), Integer(i2)) => {Boolean(i1 > i2)}, - (Binary::More, Set(s1), Set(s2)) => { - Boolean(s2.is_subset(&s1) && !s1.is_subset(&s2))}, - (Binary::MoreEq, Integer(i1), Integer(i2)) => {Boolean(i1 >= i2)}, - (Binary::MoreEq, Set(s1), Set(s2)) => { - Boolean(s1.is_subset(&s2))}, - (Binary::Eq, Integer(i1), Integer(i2)) => {Boolean(i1 == i2)}, - (Binary::Eq, Boolean(b1), Boolean(b2)) => {Boolean(b1 == b2)}, - (Binary::Eq, Element(el1), Element(el2)) => {Boolean(el1 == el2)}, - (Binary::Eq, Label(l1), Label(l2)) => {Boolean(l1 == l2)}, - (Binary::Eq, String(s1), String(s2)) => {Boolean(s1 == s2)}, - (Binary::Eq, Set(set1), Set(set2)) => {Boolean(set1 == set2)}, - (Binary::NotEq, Integer(i1), Integer(i2)) => {Boolean(i1 != i2)}, - (Binary::NotEq, Boolean(b1), Boolean(b2)) => {Boolean(b1 != b2)}, - (Binary::NotEq, Element(el1), Element(el2)) => { - Boolean(el1 != el2)}, - (Binary::NotEq, Label(l1), Label(l2)) => {Boolean(l1 != l2)}, - (Binary::NotEq, String(s1), String(s2)) => {Boolean(s1 != s2)}, - (Binary::NotEq, Set(set1), Set(set2)) => {Boolean(set1 != set2)}, - (Binary::Plus, Integer(i1), Integer(i2)) => {Integer(i1 + i2)}, - (Binary::Plus, Set(set1), Set(set2)) => {Set(set1.union(&set2))}, - (Binary::Minus, Integer(i1), Integer(i2)) => {Integer(i1 - i2)}, - (Binary::Minus, Set(set1), Set(set2)) => { - Set(set1.subtraction(&set2))}, - (Binary::Times, Integer(i1), Integer(i2)) => {Integer(i1 * i2)}, - (Binary::Times, Set(set1), Set(set2)) => { - Set(set1.intersection(&set2))}, - (Binary::Exponential, Integer(i1), Integer(i2)) => { - if i2 < 0 { - Integer(0) - } else { - Integer(i1.pow(i2 as u32))} - }, - (Binary::Quotient, Integer(i1), Integer(i2)) => { - Integer(i1.div_euclid(i2))}, - (Binary::Reminder, Integer(i1), Integer(i2)) => { - Integer(i1.rem_euclid(i2))}, - (Binary::Concat, String(s1), String(s2)) => {String(s1 + &s2)}, - (Binary::SubStr, String(s1), String(s2)) => { - let mut len = s1.len() as i64; - for (p, c) in s1.chars().enumerate() { - if s2.chars().nth(p) != Some(c) { - len = p as i64; - break; - } - } - Integer(len) - }, - (Binary::Min, Integer(i1), Integer(i2)) => {Integer(i1.min(i2))}, - (Binary::Max, Integer(i1), Integer(i2)) => {Integer(i1.max(i2))}, - (Binary::CommonSubStr, String(s1), String(s2)) => { - let mut s = std::string::String::new(); - for (p, c) in s1.chars().enumerate() { - if s2.chars().nth(p) != Some(c) { - break; - } - s.push(c); - } - String(s) - }, - (b, val1, val2) => - return Err(format!("Operation {b:?} on values {val1:?} and \ - {val2:?} could not be executed.")) - }) + use AssertReturnValue::*; + Ok(match (b, self, other) { + (Binary::And, Boolean(b1), Boolean(b2)) => Boolean(b1 && b2), + (Binary::Or, Boolean(b1), Boolean(b2)) => Boolean(b1 || b2), + (Binary::Xor, Boolean(b1), Boolean(b2)) => Boolean(b1 ^ b2), + (Binary::Xor, Set(s1), Set(s2)) => { + Set(s1.union(&s2).subtraction(&s1.intersection(&s2))) + } + (Binary::Less, Integer(i1), Integer(i2)) => Boolean(i1 < i2), + (Binary::Less, Set(s1), Set(s2)) => Boolean(s1.is_subset(&s2) && !s2.is_subset(&s1)), + (Binary::LessEq, Integer(i1), Integer(i2)) => Boolean(i1 <= i2), + (Binary::LessEq, Set(s1), Set(s2)) => Boolean(s1.is_subset(&s2)), + (Binary::More, Integer(i1), Integer(i2)) => Boolean(i1 > i2), + (Binary::More, Set(s1), Set(s2)) => Boolean(s2.is_subset(&s1) && !s1.is_subset(&s2)), + (Binary::MoreEq, Integer(i1), Integer(i2)) => Boolean(i1 >= i2), + (Binary::MoreEq, Set(s1), Set(s2)) => Boolean(s1.is_subset(&s2)), + (Binary::Eq, Integer(i1), Integer(i2)) => Boolean(i1 == i2), + (Binary::Eq, Boolean(b1), Boolean(b2)) => Boolean(b1 == b2), + (Binary::Eq, Element(el1), Element(el2)) => Boolean(el1 == el2), + (Binary::Eq, Label(l1), Label(l2)) => Boolean(l1 == l2), + (Binary::Eq, String(s1), String(s2)) => Boolean(s1 == s2), + (Binary::Eq, Set(set1), Set(set2)) => Boolean(set1 == set2), + (Binary::NotEq, Integer(i1), Integer(i2)) => Boolean(i1 != i2), + (Binary::NotEq, Boolean(b1), Boolean(b2)) => Boolean(b1 != b2), + (Binary::NotEq, Element(el1), Element(el2)) => Boolean(el1 != el2), + (Binary::NotEq, Label(l1), Label(l2)) => Boolean(l1 != l2), + (Binary::NotEq, String(s1), String(s2)) => Boolean(s1 != s2), + (Binary::NotEq, Set(set1), Set(set2)) => Boolean(set1 != set2), + (Binary::Plus, Integer(i1), Integer(i2)) => Integer(i1 + i2), + (Binary::Plus, Set(set1), Set(set2)) => Set(set1.union(&set2)), + (Binary::Minus, Integer(i1), Integer(i2)) => Integer(i1 - i2), + (Binary::Minus, Set(set1), Set(set2)) => Set(set1.subtraction(&set2)), + (Binary::Times, Integer(i1), Integer(i2)) => Integer(i1 * i2), + (Binary::Times, Set(set1), Set(set2)) => Set(set1.intersection(&set2)), + (Binary::Exponential, Integer(i1), Integer(i2)) => { + if i2 < 0 { + Integer(0) + } else { + Integer(i1.pow(i2 as u32)) + } + } + (Binary::Quotient, Integer(i1), Integer(i2)) => Integer(i1.div_euclid(i2)), + (Binary::Reminder, Integer(i1), Integer(i2)) => Integer(i1.rem_euclid(i2)), + (Binary::Concat, String(s1), String(s2)) => String(s1 + &s2), + (Binary::SubStr, String(s1), String(s2)) => { + let mut len = s1.len() as i64; + for (p, c) in s1.chars().enumerate() { + if s2.chars().nth(p) != Some(c) { + len = p as i64; + break; + } + } + Integer(len) + } + (Binary::Min, Integer(i1), Integer(i2)) => Integer(i1.min(i2)), + (Binary::Max, Integer(i1), Integer(i2)) => Integer(i1.max(i2)), + (Binary::CommonSubStr, String(s1), String(s2)) => { + let mut s = std::string::String::new(); + for (p, c) in s1.chars().enumerate() { + if s2.chars().nth(p) != Some(c) { + break; + } + s.push(c); + } + String(s) + } + (b, val1, val2) => { + return Err(format!( + "Operation {b:?} on values {val1:?} and \ + {val2:?} could not be executed." + )); + } + }) } } -fn typecheck_helper( - tree: &Tree, - c: &mut TypeContext -) -> Result -where S: SpecialVariables +fn typecheck_helper(tree: &Tree, c: &mut TypeContext) -> Result +where + S: SpecialVariables, { match tree { - Tree::Concat(t1, t2) => { - typecheck_helper(t1, c)?; - typecheck_helper(t2, c) - }, - Tree::If(exp, t) => { - match typecheck_expression(exp, c)? { - AssertionTypes::Boolean => {}, - _ => {return Err("Expression in if statement doesn't return a \ - boolean.".to_string())} - }; - typecheck_helper(t, c) - }, - Tree::IfElse(exp, t1, t2) => { - match typecheck_expression(exp, c)? { - AssertionTypes::Boolean => {}, - _ => {return Err("Expression in if statement doesn't return a \ - boolean.".into())} - }; - let type_t1 = typecheck_helper(t1, c)?; - let type_t2 = typecheck_helper(t2, c)?; - if type_t1 == type_t2 { - Ok(type_t1) - } else { - Err("Branches of if statement do not match.".into()) - } - }, - Tree::Assignment(assignvar, q, exp) => { - let type_exp = typecheck_expression(exp, c)?; - c.assign(assignvar, q.into(), type_exp)?; - Ok(AssertionTypes::NoType) - }, - Tree::Return(exp) => { - let type_exp = typecheck_expression(exp, c)?; - c.return_type(type_exp)?; - Ok(AssertionTypes::NoType) - }, - Tree::For(var, range, t) => { - let type_range = typecheck_range(range, c)?; - c.assign_range(var, type_range)?; - typecheck_helper(t, c) - }, + Tree::Concat(t1, t2) => { + typecheck_helper(t1, c)?; + typecheck_helper(t2, c) + } + Tree::If(exp, t) => { + match typecheck_expression(exp, c)? { + AssertionTypes::Boolean => {} + _ => { + return Err("Expression in if statement doesn't return a \ + boolean." + .to_string()); + } + }; + typecheck_helper(t, c) + } + Tree::IfElse(exp, t1, t2) => { + match typecheck_expression(exp, c)? { + AssertionTypes::Boolean => {} + _ => { + return Err("Expression in if statement doesn't return a \ + boolean." + .into()); + } + }; + let type_t1 = typecheck_helper(t1, c)?; + let type_t2 = typecheck_helper(t2, c)?; + if type_t1 == type_t2 { + Ok(type_t1) + } else { + Err("Branches of if statement do not match.".into()) + } + } + Tree::Assignment(assignvar, q, exp) => { + let type_exp = typecheck_expression(exp, c)?; + c.assign(assignvar, q.into(), type_exp)?; + Ok(AssertionTypes::NoType) + } + Tree::Return(exp) => { + let type_exp = typecheck_expression(exp, c)?; + c.return_type(type_exp)?; + Ok(AssertionTypes::NoType) + } + Tree::For(var, range, t) => { + let type_range = typecheck_range(range, c)?; + c.assign_range(var, type_range)?; + typecheck_helper(t, c) + } } } -pub(super) fn typecheck( - tree: &Tree, - c: &mut TypeContext -) -> Result -where S: SpecialVariables +pub(super) fn typecheck(tree: &Tree, c: &mut TypeContext) -> Result +where + S: SpecialVariables, { typecheck_helper(tree, c)?; Ok(c.return_ty.unwrap_or(AssertionTypes::NoType)) @@ -972,62 +890,61 @@ where S: SpecialVariables fn typecheck_expression( exp: &Expression, - c: &TypeContext + c: &TypeContext, ) -> Result -where S: SpecialVariables { +where + S: SpecialVariables, +{ match exp { - Expression::True | - Expression::False => Ok(AssertionTypes::Boolean), - Expression::Integer(_) => Ok(AssertionTypes::Integer), - Expression::Label(_) => Ok(AssertionTypes::Label), - Expression::Set(_) => Ok(AssertionTypes::Set), - Expression::Element(_) => Ok(AssertionTypes::Element), - Expression::String(_) => Ok(AssertionTypes::String), - Expression::Var(v) => c.get(v), + Expression::True | Expression::False => Ok(AssertionTypes::Boolean), + Expression::Integer(_) => Ok(AssertionTypes::Integer), + Expression::Label(_) => Ok(AssertionTypes::Label), + Expression::Set(_) => Ok(AssertionTypes::Set), + Expression::Element(_) => Ok(AssertionTypes::Element), + Expression::String(_) => Ok(AssertionTypes::String), + Expression::Var(v) => c.get(v), - Expression::Unary(u, exp) => { - let type_exp = typecheck_expression(exp, c)?; - u.associate(&type_exp) - }, + Expression::Unary(u, exp) => { + let type_exp = typecheck_expression(exp, c)?; + u.associate(&type_exp) + } - Expression::Binary(b, exp1, exp2) => { - let type_exp1 = typecheck_expression(exp1, c)?; - let type_exp2 = typecheck_expression(exp2, c)?; - b.associate(&type_exp1, &type_exp2) - } + Expression::Binary(b, exp1, exp2) => { + let type_exp1 = typecheck_expression(exp1, c)?; + let type_exp2 = typecheck_expression(exp2, c)?; + b.associate(&type_exp1, &type_exp2) + } } } - -fn typecheck_range( - range: &Range, - c: &mut TypeContext -) -> Result -where S: SpecialVariables { +fn typecheck_range(range: &Range, c: &mut TypeContext) -> Result +where + S: SpecialVariables, +{ match range { - Range::IterateInRange(exp1, exp2) => { - let type_exp1 = typecheck_expression(exp1, c)?; - let type_exp2 = typecheck_expression(exp2, c)?; - if let (AssertionTypes::Integer, AssertionTypes::Integer) = - (type_exp1, type_exp2) - { - Ok(AssertionTypes::RangeInteger) - } else { - Err(format!("Expressions in range are not integers, but are: \ - {type_exp1:?} and {type_exp2:?}.")) - } - }, - Range::IterateOverSet(exp) => { - let type_exp = typecheck_expression(exp, c)?; - match type_exp { - AssertionTypes::Set => - Ok(AssertionTypes::RangeSet), - AssertionTypes::RangeNeighbours => - Ok(AssertionTypes::RangeNeighbours), - _ => Err(format!("Expressions in range is not a set or \ - neighbours of a node, but is: {type_exp:?}.")) - } - } + Range::IterateInRange(exp1, exp2) => { + let type_exp1 = typecheck_expression(exp1, c)?; + let type_exp2 = typecheck_expression(exp2, c)?; + if let (AssertionTypes::Integer, AssertionTypes::Integer) = (type_exp1, type_exp2) { + Ok(AssertionTypes::RangeInteger) + } else { + Err(format!( + "Expressions in range are not integers, but are: \ + {type_exp1:?} and {type_exp2:?}." + )) + } + } + Range::IterateOverSet(exp) => { + let type_exp = typecheck_expression(exp, c)?; + match type_exp { + AssertionTypes::Set => Ok(AssertionTypes::RangeSet), + AssertionTypes::RangeNeighbours => Ok(AssertionTypes::RangeNeighbours), + _ => Err(format!( + "Expressions in range is not a set or \ + neighbours of a node, but is: {type_exp:?}." + )), + } + } } } @@ -1037,49 +954,49 @@ pub(super) fn execute( translator: &mut translator::Translator, graph: &graph::SystemGraph, ) -> Result, String> -where S: SpecialVariables { +where + S: SpecialVariables, +{ match tree { - Tree::Concat(t1, t2) => { - if let Some(val) = execute(t1, c, translator, graph)? { - Ok(Some(val)) - } else { - execute(t2, c, translator, graph) - } - }, - Tree::If(exp, t) => { - let guard = execute_exp(exp, c, translator, graph)?; - if let AssertReturnValue::Boolean(true) = guard { - execute(t, c, translator, graph) - } else { - Ok(None) - } - }, - Tree::IfElse(exp, t1, t2) => { - let guard = execute_exp(exp, c, translator, graph)?; - if let AssertReturnValue::Boolean(true) = guard { - execute(t1, c, translator, graph) - } else { - execute(t2, c, translator, graph) - } - }, - Tree::Assignment(v, q, exp) => { - let val = execute_exp(exp, c, translator, graph)?; - c.assign(v, q.into(), val)?; - Ok(None) - }, - Tree::Return(exp) => { - Ok(Some(execute_exp(exp, c, translator, graph)?)) - }, - Tree::For(v, r, t) => { - let range = range_into_iter(r, c, translator, graph)?; - for val in range { - c.assign(v, None, val)?; - if let Some(v) = execute(t, c, translator, graph)? { - return Ok(Some(v)) - } - } - Ok(None) - }, + Tree::Concat(t1, t2) => { + if let Some(val) = execute(t1, c, translator, graph)? { + Ok(Some(val)) + } else { + execute(t2, c, translator, graph) + } + } + Tree::If(exp, t) => { + let guard = execute_exp(exp, c, translator, graph)?; + if let AssertReturnValue::Boolean(true) = guard { + execute(t, c, translator, graph) + } else { + Ok(None) + } + } + Tree::IfElse(exp, t1, t2) => { + let guard = execute_exp(exp, c, translator, graph)?; + if let AssertReturnValue::Boolean(true) = guard { + execute(t1, c, translator, graph) + } else { + execute(t2, c, translator, graph) + } + } + Tree::Assignment(v, q, exp) => { + let val = execute_exp(exp, c, translator, graph)?; + c.assign(v, q.into(), val)?; + Ok(None) + } + Tree::Return(exp) => Ok(Some(execute_exp(exp, c, translator, graph)?)), + Tree::For(v, r, t) => { + let range = range_into_iter(r, c, translator, graph)?; + for val in range { + c.assign(v, None, val)?; + if let Some(v) = execute(t, c, translator, graph)? { + return Ok(Some(v)); + } + } + Ok(None) + } } } @@ -1091,43 +1008,42 @@ fn range_into_iter( translator: &mut translator::Translator, graph: &graph::SystemGraph, ) -> Result -where S: SpecialVariables { +where + S: SpecialVariables, +{ use petgraph::visit::EdgeRef; match range { - Range::IterateOverSet(exp) => { - let val = execute_exp(exp, c, translator, graph)?; - match val { - AssertReturnValue::Set(set) => { - Ok(set - .into_iter() - .map(AssertReturnValue::Element) - .collect::>() - .into_iter()) - }, - AssertReturnValue::Neighbours(node) => { - Ok(graph - .edges(node) - .map(|x| AssertReturnValue::Edge(x.id())) - .collect::>() - .into_iter()) - } - _ => Err(format!("{val:?} is not a set in for cycle.")) - } - }, - Range::IterateInRange(exp1, exp2) => { - let val1 = execute_exp(exp1, c, translator, graph)?; - let val2 = execute_exp(exp2, c, translator, graph)?; - match (val1, val2) { - (AssertReturnValue::Integer(i1), - AssertReturnValue::Integer(i2)) => - Ok((i1..i2).map(AssertReturnValue::Integer) - .collect::>().into_iter()), - (val1, val2) => - Err(format!("{val1:?}..{val2:?} is not a valid integer \ - range in for cycle.")) - } - } + Range::IterateOverSet(exp) => { + let val = execute_exp(exp, c, translator, graph)?; + match val { + AssertReturnValue::Set(set) => Ok(set + .into_iter() + .map(AssertReturnValue::Element) + .collect::>() + .into_iter()), + AssertReturnValue::Neighbours(node) => Ok(graph + .edges(node) + .map(|x| AssertReturnValue::Edge(x.id())) + .collect::>() + .into_iter()), + _ => Err(format!("{val:?} is not a set in for cycle.")), + } + } + Range::IterateInRange(exp1, exp2) => { + let val1 = execute_exp(exp1, c, translator, graph)?; + let val2 = execute_exp(exp2, c, translator, graph)?; + match (val1, val2) { + (AssertReturnValue::Integer(i1), AssertReturnValue::Integer(i2)) => Ok((i1..i2) + .map(AssertReturnValue::Integer) + .collect::>() + .into_iter()), + (val1, val2) => Err(format!( + "{val1:?}..{val2:?} is not a valid integer \ + range in for cycle." + )), + } + } } } @@ -1137,25 +1053,26 @@ fn execute_exp( translator: &mut translator::Translator, graph: &graph::SystemGraph, ) -> Result -where S: SpecialVariables { +where + S: SpecialVariables, +{ match exp { - Expression::True => Ok(AssertReturnValue::Boolean(true)), - Expression::False => Ok(AssertReturnValue::Boolean(false)), - Expression::Integer(i) => Ok(AssertReturnValue::Integer(*i)), - Expression::Label(l) => Ok(AssertReturnValue::Label(*l.clone())), - Expression::Set(set) => Ok(AssertReturnValue::Set(set.clone())), - Expression::Element(el) => - Ok(AssertReturnValue::Element(*el)), - Expression::String(s) => Ok(AssertReturnValue::String(s.clone())), - Expression::Var(var) => c.get(var), - Expression::Unary(u, exp) => { - let val = execute_exp(exp, c, translator, graph)?; - val.unary(u, translator, graph) - }, - Expression::Binary(b, exp1, exp2) => { - let val1 = execute_exp(exp1, c, translator, graph)?; - let val2 = execute_exp(exp2, c, translator, graph)?; - val1.binary(b, val2, translator) - }, + Expression::True => Ok(AssertReturnValue::Boolean(true)), + Expression::False => Ok(AssertReturnValue::Boolean(false)), + Expression::Integer(i) => Ok(AssertReturnValue::Integer(*i)), + Expression::Label(l) => Ok(AssertReturnValue::Label(*l.clone())), + Expression::Set(set) => Ok(AssertReturnValue::Set(set.clone())), + Expression::Element(el) => Ok(AssertReturnValue::Element(*el)), + Expression::String(s) => Ok(AssertReturnValue::String(s.clone())), + Expression::Var(var) => c.get(var), + Expression::Unary(u, exp) => { + let val = execute_exp(exp, c, translator, graph)?; + val.unary(u, translator, graph) + } + Expression::Binary(b, exp1, exp2) => { + let val1 = execute_exp(exp1, c, translator, graph)?; + let val2 = execute_exp(exp2, c, translator, graph)?; + val1.binary(b, val2, translator) + } } } diff --git a/src/rsprocess/assert/fmt.rs b/src/rsprocess/assert/fmt.rs index 4dd1c4f..0cbd545 100644 --- a/src/rsprocess/assert/fmt.rs +++ b/src/rsprocess/assert/fmt.rs @@ -1,472 +1,527 @@ // ----------------------------------------------------------------------------- // Display Implementation for all types // ----------------------------------------------------------------------------- -use std::fmt; -use super::dsl::*; use super::super::translator::{Formatter, PrintableWithTranslator, Translator}; +use super::dsl::*; +use std::fmt; -impl fmt::Debug for Assert where S: fmt::Debug { +impl fmt::Debug for Assert +where + S: fmt::Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "label {{\n{:?}\n}}", self.tree) + write!(f, "label {{\n{:?}\n}}", self.tree) } } -impl fmt::Debug for Tree where S: fmt::Debug { +impl fmt::Debug for Tree +where + S: fmt::Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Concat(t1, t2) => {write!(f, "{t1:?};\n{t2:?}")}, - Self::If(exp, t) => {write!(f, "if {exp:?} {{\n{t:?}\n}}")}, - Self::IfElse(exp, t1, t2) => { - write!(f, "if {exp:?} {{\n{t1:?}\n}} else {{\n{t2:?}\n}}") - }, - Self::Assignment(v, q, exp) => { - if let Some(q) = q { - write!(f, "{v:?}.{q:?} = {exp:?}") - } else { - write!(f, "{v:?} = {exp:?}") - } - }, - Self::Return(exp) => {write!(f, "return {exp:?}")}, - Self::For(v, r, t) => { - write!(f, "for {v:?} in {r:?} {{\n{t:?}\n}}") - }, - } + match self { + Self::Concat(t1, t2) => { + write!(f, "{t1:?};\n{t2:?}") + } + Self::If(exp, t) => { + write!(f, "if {exp:?} {{\n{t:?}\n}}") + } + Self::IfElse(exp, t1, t2) => { + write!(f, "if {exp:?} {{\n{t1:?}\n}} else {{\n{t2:?}\n}}") + } + Self::Assignment(v, q, exp) => { + if let Some(q) = q { + write!(f, "{v:?}.{q:?} = {exp:?}") + } else { + write!(f, "{v:?} = {exp:?}") + } + } + Self::Return(exp) => { + write!(f, "return {exp:?}") + } + Self::For(v, r, t) => { + write!(f, "for {v:?} in {r:?} {{\n{t:?}\n}}") + } + } } } -impl fmt::Debug for Variable where S: fmt::Debug { +impl fmt::Debug for Variable +where + S: fmt::Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Special(s) => {write!(f, "{s:?}")}, - Self::Id(s) => {write!(f, "{s:?}")} - } + match self { + Self::Special(s) => { + write!(f, "{s:?}") + } + Self::Id(s) => { + write!(f, "{s:?}") + } + } } } -impl fmt::Debug for Expression where S: fmt::Debug { +impl fmt::Debug for Expression +where + S: fmt::Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::True => {write!(f, "True")}, - Self::False => {write!(f, "False")}, - Self::Integer(i) => {write!(f, "{i}")}, - Self::Label(rslabel) => {write!(f, "{{debug: {rslabel:?}}}")}, - Self::Set(set) => {write!(f, "{{debug: {set:?}}}")}, - Self::Element(el) => {write!(f, "'{{debug: {el:?}}}'")}, - Self::String(s) => {write!(f, r#""{s:?}""#)}, - Self::Var(v) => {write!(f, "{v:?}")}, - Self::Unary(u, exp) => { - if u.is_prefix() { - write!(f, "{u:?}({exp:?})") - } else if u.is_suffix() { - write!(f, "{exp:?}{u:?}") - } else { - unreachable!() - } - }, - Self::Binary(b, exp1, exp2) => { - if b.is_prefix() { - write!(f, "{b:?}({exp1:?}, {exp2:?})") - } else if b.is_suffix() { - write!(f, "({exp1:?}, {exp2:?}){b:?}") - } else if b.is_infix() { - write!(f, "({exp1:?} {b:?} {exp2:?})") - } else { - unreachable!() - } - }, - } + match self { + Self::True => { + write!(f, "True") + } + Self::False => { + write!(f, "False") + } + Self::Integer(i) => { + write!(f, "{i}") + } + Self::Label(rslabel) => { + write!(f, "{{debug: {rslabel:?}}}") + } + Self::Set(set) => { + write!(f, "{{debug: {set:?}}}") + } + Self::Element(el) => { + write!(f, "'{{debug: {el:?}}}'") + } + Self::String(s) => { + write!(f, r#""{s:?}""#) + } + Self::Var(v) => { + write!(f, "{v:?}") + } + Self::Unary(u, exp) => { + if u.is_prefix() { + write!(f, "{u:?}({exp:?})") + } else if u.is_suffix() { + write!(f, "{exp:?}{u:?}") + } else { + unreachable!() + } + } + Self::Binary(b, exp1, exp2) => { + if b.is_prefix() { + write!(f, "{b:?}({exp1:?}, {exp2:?})") + } else if b.is_suffix() { + write!(f, "({exp1:?}, {exp2:?}){b:?}") + } else if b.is_infix() { + write!(f, "({exp1:?} {b:?} {exp2:?})") + } else { + unreachable!() + } + } + } } } -impl fmt::Debug for Range where S: fmt::Debug { +impl fmt::Debug for Range +where + S: fmt::Debug, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::IterateOverSet(exp) => write!(f, "{{{exp:?}}}"), - Self::IterateInRange(exp1, exp2) => write!(f, "{exp1:?}..{exp2:?}") - } + match self { + Self::IterateOverSet(exp) => write!(f, "{{{exp:?}}}"), + Self::IterateInRange(exp1, exp2) => write!(f, "{exp1:?}..{exp2:?}"), + } } } impl fmt::Debug for Unary { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Not => write!(f, "not"), - Self::Rand => write!(f, "rand"), - Self::Empty => write!(f, ".empty"), - Self::Length => write!(f, ".length"), - Self::ToStr => write!(f, ".tostr"), - Self::ToEl => write!(f, ".toel"), - Self::Qualifier(q) => write!(f, ".{q:?}"), - } + match self { + Self::Not => write!(f, "not"), + Self::Rand => write!(f, "rand"), + Self::Empty => write!(f, ".empty"), + Self::Length => write!(f, ".length"), + Self::ToStr => write!(f, ".tostr"), + Self::ToEl => write!(f, ".toel"), + Self::Qualifier(q) => write!(f, ".{q:?}"), + } } } impl fmt::Debug for QualifierRestricted { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Entities => write!(f, "Entities"), - Self::Context => write!(f, "Context"), - Self::Reactants => write!(f, "Reactants"), - Self::ReactantsAbsent => write!(f, "ReactantsAbsent"), - Self::Inhibitors => write!(f, "Inhibitors"), - Self::InhibitorsPresent => write!(f, "InhibitorsPresent"), - Self::Products => write!(f, "Products"), - } + match self { + Self::Entities => write!(f, "Entities"), + Self::Context => write!(f, "Context"), + Self::Reactants => write!(f, "Reactants"), + Self::ReactantsAbsent => write!(f, "ReactantsAbsent"), + Self::Inhibitors => write!(f, "Inhibitors"), + Self::InhibitorsPresent => write!(f, "InhibitorsPresent"), + Self::Products => write!(f, "Products"), + } } } impl fmt::Debug for QualifierLabel { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::AvailableEntities => write!(f, "AvailableEntities"), - Self::AllReactants => write!(f, "AllReactants"), - Self::AllInhibitors => write!(f, "AllInhibitors"), - } + match self { + Self::AvailableEntities => write!(f, "AvailableEntities"), + Self::AllReactants => write!(f, "AllReactants"), + Self::AllInhibitors => write!(f, "AllInhibitors"), + } } } impl fmt::Debug for QualifierSystem { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Context => write!(f, "context"), - Self::Entities => write!(f, "entities"), - } + match self { + Self::Context => write!(f, "context"), + Self::Entities => write!(f, "entities"), + } } } impl fmt::Debug for QualifierEdge { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Source => write!(f, "source"), - Self::Target => write!(f, "target"), - } + match self { + Self::Source => write!(f, "source"), + Self::Target => write!(f, "target"), + } } } impl fmt::Debug for QualifierNode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Neighbours => write!(f, "neighbours"), - Self::System => write!(f, "system"), - } + match self { + Self::Neighbours => write!(f, "neighbours"), + Self::System => write!(f, "system"), + } } } impl fmt::Debug for Qualifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Label(q) => write!(f, "{q:?}"), - Self::Restricted(q) => write!(f, "{q:?}"), - Self::System(q) => write!(f, "{q:?}"), - Self::Edge(q) => write!(f, "{q:?}"), - Self::Node(q) => write!(f, "{q:?}"), - } + match self { + Self::Label(q) => write!(f, "{q:?}"), + Self::Restricted(q) => write!(f, "{q:?}"), + Self::System(q) => write!(f, "{q:?}"), + Self::Edge(q) => write!(f, "{q:?}"), + Self::Node(q) => write!(f, "{q:?}"), + } } } impl fmt::Debug for Binary { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::And => write!(f, "&&"), - Self::Or => write!(f, "||"), - Self::Xor => write!(f, "^^"), - Self::Less => write!(f, "<"), - Self::LessEq => write!(f, "<="), - Self::More => write!(f, ">"), - Self::MoreEq => write!(f, ">="), - Self::Eq => write!(f, "=="), - Self::NotEq => write!(f, "!="), - Self::Plus => write!(f, "+"), - Self::Minus => write!(f, "-"), - Self::Times => write!(f, "*"), - Self::Exponential => write!(f, "^"), - Self::Quotient => write!(f, "/"), - Self::Reminder => write!(f, "%"), - Self::Concat => write!(f, "::"), - Self::SubStr => write!(f, "substr"), - Self::Min => write!(f, "min"), - Self::Max => write!(f, "max"), - Self::CommonSubStr => write!(f, "commonsubstr"), - } + match self { + Self::And => write!(f, "&&"), + Self::Or => write!(f, "||"), + Self::Xor => write!(f, "^^"), + Self::Less => write!(f, "<"), + Self::LessEq => write!(f, "<="), + Self::More => write!(f, ">"), + Self::MoreEq => write!(f, ">="), + Self::Eq => write!(f, "=="), + Self::NotEq => write!(f, "!="), + Self::Plus => write!(f, "+"), + Self::Minus => write!(f, "-"), + Self::Times => write!(f, "*"), + Self::Exponential => write!(f, "^"), + Self::Quotient => write!(f, "/"), + Self::Reminder => write!(f, "%"), + Self::Concat => write!(f, "::"), + Self::SubStr => write!(f, "substr"), + Self::Min => write!(f, "min"), + Self::Max => write!(f, "max"), + Self::CommonSubStr => write!(f, "commonsubstr"), + } } } impl fmt::Debug for AssertReturnValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Boolean(b) => write!(f, "{b:?}"), - Self::Integer(i) => write!(f, "{i:?}"), - Self::String(s) => write!(f, r#""{s:?}""#), - Self::Label(l) => write!(f, "{{debug: {l:?}}}"), - Self::Set(set) => write!(f, "{{debug: {set:?}}}"), - Self::Element(el) => write!(f, "{{debug: {el:?}}}"), - Self::Edge(edge) => write!(f, "{{debug: {edge:?}}}"), - Self::Node(node) => write!(f, "{{debug: {node:?}}}"), - Self::Neighbours(node) => - write!(f, "{{debug: {node:?}}}.neighbours"), - Self::System(sys) => write!(f, "{{debug: {sys:?}}}"), - Self::Context(ctx) => write!(f, "{{debug: {ctx:?}}}"), - } + match self { + Self::Boolean(b) => write!(f, "{b:?}"), + Self::Integer(i) => write!(f, "{i:?}"), + Self::String(s) => write!(f, r#""{s:?}""#), + Self::Label(l) => write!(f, "{{debug: {l:?}}}"), + Self::Set(set) => write!(f, "{{debug: {set:?}}}"), + Self::Element(el) => write!(f, "{{debug: {el:?}}}"), + Self::Edge(edge) => write!(f, "{{debug: {edge:?}}}"), + Self::Node(node) => write!(f, "{{debug: {node:?}}}"), + Self::Neighbours(node) => write!(f, "{{debug: {node:?}}}.neighbours"), + Self::System(sys) => write!(f, "{{debug: {sys:?}}}"), + Self::Context(ctx) => write!(f, "{{debug: {ctx:?}}}"), + } } } impl fmt::Debug for AssertionTypes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Boolean => write!(f, "boolean"), - Self::Integer => write!(f, "integer"), - Self::String => write!(f, "string"), - Self::Label => write!(f, "label"), - Self::Set => write!(f, "set"), - Self::Element => write!(f, "element"), - Self::System => write!(f, "system"), - Self::Context => write!(f, "context"), - Self::NoType => write!(f, "no type"), - Self::RangeInteger => write!(f, "range of integers"), - Self::RangeSet => write!(f, "range of set"), - Self::RangeNeighbours => write!(f, "range of edges"), - Self::Edge => write!(f, "edge"), - Self::Node => write!(f, "node"), - } + match self { + Self::Boolean => write!(f, "boolean"), + Self::Integer => write!(f, "integer"), + Self::String => write!(f, "string"), + Self::Label => write!(f, "label"), + Self::Set => write!(f, "set"), + Self::Element => write!(f, "element"), + Self::System => write!(f, "system"), + Self::Context => write!(f, "context"), + Self::NoType => write!(f, "no type"), + Self::RangeInteger => write!(f, "range of integers"), + Self::RangeSet => write!(f, "range of set"), + Self::RangeNeighbours => write!(f, "range of edges"), + Self::Edge => write!(f, "edge"), + Self::Node => write!(f, "node"), + } } } // ----------------------------------------------------------------------------- impl PrintableWithTranslator for Assert -where S: PrintableWithTranslator { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - write!(f, "label {{\n{}\n}}", Formatter::from(translator, &self.tree)) +where + S: PrintableWithTranslator, +{ + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + write!( + f, + "label {{\n{}\n}}", + Formatter::from(translator, &self.tree) + ) } } - impl PrintableWithTranslator for Tree -where S: PrintableWithTranslator { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::Concat(t1, t2) => - write!(f, "{};\n{}", - Formatter::from(translator, &**t1), - Formatter::from(translator, &**t2)), - Self::If(exp, t) => - write!(f, "if {} {{\n{}\n}}", - Formatter::from(translator, &**exp), - Formatter::from(translator, &**t)), - Self::IfElse(exp, t1, t2) => { - write!(f, "if {} {{\n{}\n}} else {{\n{}\n}}", - Formatter::from(translator, &**exp), - Formatter::from(translator, &**t1), - Formatter::from(translator, &**t2)) - }, - Self::Assignment(v, q, exp) => { - if let Some(q) = q { - write!(f, "{}.{} = {}", - Formatter::from(translator, v), - Formatter::from(translator, q), - Formatter::from(translator, &**exp)) - } else { - write!(f, "{} = {}", - Formatter::from(translator, v), - Formatter::from(translator, &**exp)) - } - }, - Self::Return(exp) => - write!(f, "return {}", Formatter::from(translator, &**exp)), - Self::For(v, r, t) => { - write!(f, "for {} in {} {{\n{}\n}}", - Formatter::from(translator, v), - Formatter::from(translator, r), - Formatter::from(translator, &**t)) - }, - } +where + S: PrintableWithTranslator, +{ + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::Concat(t1, t2) => write!( + f, + "{};\n{}", + Formatter::from(translator, &**t1), + Formatter::from(translator, &**t2) + ), + Self::If(exp, t) => write!( + f, + "if {} {{\n{}\n}}", + Formatter::from(translator, &**exp), + Formatter::from(translator, &**t) + ), + Self::IfElse(exp, t1, t2) => { + write!( + f, + "if {} {{\n{}\n}} else {{\n{}\n}}", + Formatter::from(translator, &**exp), + Formatter::from(translator, &**t1), + Formatter::from(translator, &**t2) + ) + } + Self::Assignment(v, q, exp) => { + if let Some(q) = q { + write!( + f, + "{}.{} = {}", + Formatter::from(translator, v), + Formatter::from(translator, q), + Formatter::from(translator, &**exp) + ) + } else { + write!( + f, + "{} = {}", + Formatter::from(translator, v), + Formatter::from(translator, &**exp) + ) + } + } + Self::Return(exp) => write!(f, "return {}", Formatter::from(translator, &**exp)), + Self::For(v, r, t) => { + write!( + f, + "for {} in {} {{\n{}\n}}", + Formatter::from(translator, v), + Formatter::from(translator, r), + Formatter::from(translator, &**t) + ) + } + } } } impl PrintableWithTranslator for Variable -where S: PrintableWithTranslator { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::Special(s) => write!(f, "{}", Formatter::from(translator, s)), - Self::Id(s) => write!(f, "{s}") - } +where + S: PrintableWithTranslator, +{ + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::Special(s) => write!(f, "{}", Formatter::from(translator, s)), + Self::Id(s) => write!(f, "{s}"), + } } } impl PrintableWithTranslator for Expression -where S: PrintableWithTranslator { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::True => write!(f, "True"), - Self::False => write!(f, "False"), - Self::Integer(i) => write!(f, "{i}"), - Self::Label(l) => - write!(f, "{}", Formatter::from(translator, &**l)), - Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)), - Self::Element(el) => - write!(f, "'{}'", Formatter::from(translator, el)), - Self::String(s) => write!(f, r#""{s}""#), - Self::Var(v) => write!(f, "{}", Formatter::from(translator, v)), - Self::Unary(u, exp) => { - if u.is_prefix() { - write!(f, "{}({})", - Formatter::from(translator, u), - Formatter::from(translator, &**exp)) - } else if u.is_suffix() { - write!(f, "{}{}", - Formatter::from(translator, &**exp), - Formatter::from(translator, u)) - } else { - unreachable!() - } - }, - Self::Binary(b, exp1, exp2) => { - if b.is_prefix() { - write!(f, "{}({}, {})", - Formatter::from(translator, b), - Formatter::from(translator, &**exp1), - Formatter::from(translator, &**exp2)) - } else if b.is_suffix() { - write!(f, "({}, {}){}", - Formatter::from(translator, &**exp1), - Formatter::from(translator, &**exp2), - Formatter::from(translator, b)) - } else if b.is_infix() { - write!(f, "({} {} {})", - Formatter::from(translator, &**exp1), - Formatter::from(translator, b), - Formatter::from(translator, &**exp2)) - } else { - unreachable!() - } - }, - } +where + S: PrintableWithTranslator, +{ + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::True => write!(f, "True"), + Self::False => write!(f, "False"), + Self::Integer(i) => write!(f, "{i}"), + Self::Label(l) => write!(f, "{}", Formatter::from(translator, &**l)), + Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)), + Self::Element(el) => write!(f, "'{}'", Formatter::from(translator, el)), + Self::String(s) => write!(f, r#""{s}""#), + Self::Var(v) => write!(f, "{}", Formatter::from(translator, v)), + Self::Unary(u, exp) => { + if u.is_prefix() { + write!( + f, + "{}({})", + Formatter::from(translator, u), + Formatter::from(translator, &**exp) + ) + } else if u.is_suffix() { + write!( + f, + "{}{}", + Formatter::from(translator, &**exp), + Formatter::from(translator, u) + ) + } else { + unreachable!() + } + } + Self::Binary(b, exp1, exp2) => { + if b.is_prefix() { + write!( + f, + "{}({}, {})", + Formatter::from(translator, b), + Formatter::from(translator, &**exp1), + Formatter::from(translator, &**exp2) + ) + } else if b.is_suffix() { + write!( + f, + "({}, {}){}", + Formatter::from(translator, &**exp1), + Formatter::from(translator, &**exp2), + Formatter::from(translator, b) + ) + } else if b.is_infix() { + write!( + f, + "({} {} {})", + Formatter::from(translator, &**exp1), + Formatter::from(translator, b), + Formatter::from(translator, &**exp2) + ) + } else { + unreachable!() + } + } + } } } impl PrintableWithTranslator for Range -where S: PrintableWithTranslator { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::IterateOverSet(exp) => - write!(f, "{}", Formatter::from(translator, &**exp)), - Self::IterateInRange(exp1, exp2) => - write!(f, "{}..{}", - Formatter::from(translator, &**exp1), - Formatter::from(translator, &**exp2)) - } +where + S: PrintableWithTranslator, +{ + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::IterateOverSet(exp) => write!(f, "{}", Formatter::from(translator, &**exp)), + Self::IterateInRange(exp1, exp2) => write!( + f, + "{}..{}", + Formatter::from(translator, &**exp1), + Formatter::from(translator, &**exp2) + ), + } } } impl PrintableWithTranslator for Unary { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::Not => write!(f, "not"), - Self::Rand => write!(f, "rand"), - Self::Empty => write!(f, ".empty"), - Self::Length => write!(f, ".length"), - Self::ToStr => write!(f, ".tostr"), - Self::ToEl => write!(f, ".toel"), - Self::Qualifier(q) => - write!(f, ".{}", Formatter::from(translator, q)), - } + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::Not => write!(f, "not"), + Self::Rand => write!(f, "rand"), + Self::Empty => write!(f, ".empty"), + Self::Length => write!(f, ".length"), + Self::ToStr => write!(f, ".tostr"), + Self::ToEl => write!(f, ".toel"), + Self::Qualifier(q) => write!(f, ".{}", Formatter::from(translator, q)), + } } } impl PrintableWithTranslator for QualifierRestricted { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } impl PrintableWithTranslator for QualifierLabel { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } impl PrintableWithTranslator for QualifierSystem { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } impl PrintableWithTranslator for QualifierEdge { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } impl PrintableWithTranslator for QualifierNode { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } impl PrintableWithTranslator for Qualifier { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::Label(q) => - write!(f, "{}", Formatter::from(translator, q)), - Self::Restricted(q) => - write!(f, "{}", Formatter::from(translator, q)), - Self::System(q) => - write!(f, "{}", Formatter::from(translator, q)), - Self::Edge(q) => - write!(f, "{}", Formatter::from(translator, q)), - Self::Node(q) => - write!(f, "{}", Formatter::from(translator, q)), - } + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::Label(q) => write!(f, "{}", Formatter::from(translator, q)), + Self::Restricted(q) => write!(f, "{}", Formatter::from(translator, q)), + Self::System(q) => write!(f, "{}", Formatter::from(translator, q)), + Self::Edge(q) => write!(f, "{}", Formatter::from(translator, q)), + Self::Node(q) => write!(f, "{}", Formatter::from(translator, q)), + } } } impl PrintableWithTranslator for Binary { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } impl PrintableWithTranslator for AssertReturnValue { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result { - match self { - Self::Boolean(b) => write!(f, "{b}"), - Self::Integer(i) => write!(f, "{i}"), - Self::String(s) => write!(f, r#""{s}""#), - Self::Label(l) => - write!(f, "{}", Formatter::from(translator, l)), - Self::Set(set) => - write!(f, "{}", Formatter::from(translator, set)), - Self::Element(el) => - write!(f, "{}", Formatter::from(translator, el)), - Self::Edge(edge) => write!(f, "{{edge: {edge:?}}}"), - Self::Node(node) => write!(f, "{{node: {node:?}}}"), - Self::Neighbours(node) => - write!(f, "{{node: {node:?}}}.neighbours"), - Self::System(sys) => - write!(f, "{}", Formatter::from(translator, sys)), - Self::Context(ctx) => - write!(f, "{}", Formatter::from(translator, ctx)), - } + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + match self { + Self::Boolean(b) => write!(f, "{b}"), + Self::Integer(i) => write!(f, "{i}"), + Self::String(s) => write!(f, r#""{s}""#), + Self::Label(l) => write!(f, "{}", Formatter::from(translator, l)), + Self::Set(set) => write!(f, "{}", Formatter::from(translator, set)), + Self::Element(el) => write!(f, "{}", Formatter::from(translator, el)), + Self::Edge(edge) => write!(f, "{{edge: {edge:?}}}"), + Self::Node(node) => write!(f, "{{node: {node:?}}}"), + Self::Neighbours(node) => write!(f, "{{node: {node:?}}}.neighbours"), + Self::System(sys) => write!(f, "{}", Formatter::from(translator, sys)), + Self::Context(ctx) => write!(f, "{}", Formatter::from(translator, ctx)), + } } } impl PrintableWithTranslator for AssertionTypes { - fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) - -> fmt::Result { - write!(f, "{self:?}") + fn print(&self, f: &mut fmt::Formatter, _translator: &Translator) -> fmt::Result { + write!(f, "{self:?}") } } diff --git a/src/rsprocess/assert/rsassert.rs b/src/rsprocess/assert/rsassert.rs index 1b14f23..a382f15 100644 --- a/src/rsprocess/assert/rsassert.rs +++ b/src/rsprocess/assert/rsassert.rs @@ -1,13 +1,14 @@ use crate::rsprocess::translator::PrintableWithTranslator; +use super::super::{graph, label, set, system, translator}; use super::dsl::*; -use super::super::{translator, graph, set, system, label}; use std::collections::HashMap; // ---------------------------------------------------------------------------- // Specific Assert Implementation // ---------------------------------------------------------------------------- +/// Module that has all types and structures. pub mod useful_types_edge_relabeler { macro_rules! export_types { ( $( $x:ident ),* ) => { @@ -27,14 +28,21 @@ pub mod useful_types_edge_relabeler { export_types!(Assert, Tree, Variable, Expression, Range); - export_types_no_parameter!(Unary, QualifierRestricted, QualifierLabel, - QualifierSystem, QualifierEdge, QualifierNode, - Qualifier, Binary, AssertReturnValue); + export_types_no_parameter!( + Unary, + QualifierRestricted, + QualifierLabel, + QualifierSystem, + QualifierEdge, + QualifierNode, + Qualifier, + Binary, + AssertReturnValue + ); pub type Special = super::EdgeRelablerInput; } - // Implementation for graph labeling in bisimulation. #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -51,109 +59,114 @@ enum EdgeRelablerInputValues { impl SpecialVariables for EdgeRelablerInput { fn type_of(&self) -> AssertionTypes { - match self { - Self::Edge => AssertionTypes::Edge, - Self::Label => AssertionTypes::Label, - } + match self { + Self::Edge => AssertionTypes::Edge, + Self::Label => AssertionTypes::Label, + } } fn type_qualified(&self, q: &Qualifier) -> Result { - match (self, q) { - (Self::Label, Qualifier::Label(_)) | - (Self::Label, Qualifier::Restricted(_)) => - Ok(AssertionTypes::Set), - (s, q) => - Err(format!("Wrong use of qualifier {q:?} on variable {s:?}.")) - } + match (self, q) { + (Self::Label, Qualifier::Label(_)) | (Self::Label, Qualifier::Restricted(_)) => { + Ok(AssertionTypes::Set) + } + (s, q) => Err(format!("Wrong use of qualifier {q:?} on variable {s:?}.")), + } } - fn new_context(input: HashMap) - -> HashMap { - input.iter().map(|(key, value)| { - match value { - EdgeRelablerInputValues::Edge(e) => - (*key, AssertReturnValue::Edge(*e)), - EdgeRelablerInputValues::Label(l) => - (*key, AssertReturnValue::Label(l.clone())), - } - }).collect::>() + fn new_context( + input: HashMap, + ) -> HashMap { + input + .iter() + .map(|(key, value)| match value { + EdgeRelablerInputValues::Edge(e) => (*key, AssertReturnValue::Edge(*e)), + EdgeRelablerInputValues::Label(l) => (*key, AssertReturnValue::Label(l.clone())), + }) + .collect::>() } fn correct_type(&self, other: &AssertReturnValue) -> bool { - match (self, other) { - (Self::Edge, AssertReturnValue::Edge(_)) | - (Self::Label, AssertReturnValue::Label(_)) => true, - (_, _) => false - } + match (self, other) { + (Self::Edge, AssertReturnValue::Edge(_)) + | (Self::Label, AssertReturnValue::Label(_)) => true, + (_, _) => false, + } } } impl std::fmt::Debug for EdgeRelablerInput { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Label => write!(f, "label"), - Self::Edge => write!(f, "edge"), - } + match self { + Self::Label => write!(f, "label"), + Self::Edge => write!(f, "edge"), + } } } impl PrintableWithTranslator for EdgeRelablerInput { - fn print(&self, - f: &mut std::fmt::Formatter, - _translator: &translator::Translator) - -> std::fmt::Result { - write!(f, "{self:?}") + fn print( + &self, + f: &mut std::fmt::Formatter, + _translator: &translator::Translator, + ) -> std::fmt::Result { + write!(f, "{self:?}") } } impl Assert { pub fn typecheck(&self) -> Result<(), String> { - let mut context = TypeContext::new(); - let ty = typecheck(&self.tree, &mut context)?; - match ty { - AssertionTypes::Boolean | - AssertionTypes::Integer | - AssertionTypes::String | - AssertionTypes::Label | - AssertionTypes::Set | - AssertionTypes::Element | - AssertionTypes::Edge | - AssertionTypes::Node | - AssertionTypes::System | - AssertionTypes::Context => - Ok(()), - AssertionTypes::NoType => - Err("No return type, at least one return statement \ - required.".into()), - AssertionTypes::RangeInteger | - AssertionTypes::RangeSet | - AssertionTypes::RangeNeighbours => - Err(format!("Returned type {ty:?} is not a valid return \ - type.")), - } + let mut context = TypeContext::new(); + let ty = typecheck(&self.tree, &mut context)?; + match ty { + AssertionTypes::Boolean + | AssertionTypes::Integer + | AssertionTypes::String + | AssertionTypes::Label + | AssertionTypes::Set + | AssertionTypes::Element + | AssertionTypes::Edge + | AssertionTypes::Node + | AssertionTypes::System + | AssertionTypes::Context => Ok(()), + AssertionTypes::NoType => Err("No return type, at least one return statement \ + required." + .into()), + AssertionTypes::RangeInteger + | AssertionTypes::RangeSet + | AssertionTypes::RangeNeighbours => Err(format!( + "Returned type {ty:?} is not a valid return \ + type." + )), + } } pub fn execute( - &self, - graph: &graph::SystemGraph, - edge: &::EdgeId, - translator: &mut translator::Translator, + &self, + graph: &graph::SystemGraph, + edge: &::EdgeId, + translator: &mut translator::Translator, ) -> Result { - let label = graph.edge_weight(*edge) - .ok_or("Missing edge {{debug: {edge:?}}}")?; + let label = graph + .edge_weight(*edge) + .ok_or("Missing edge {{debug: {edge:?}}}")?; - let mut input_vals = HashMap::new(); - input_vals.insert(EdgeRelablerInput::Edge, - EdgeRelablerInputValues::Edge(*edge)); - input_vals.insert(EdgeRelablerInput::Label, - EdgeRelablerInputValues::Label(label.clone())); + let mut input_vals = HashMap::new(); + input_vals.insert( + EdgeRelablerInput::Edge, + EdgeRelablerInputValues::Edge(*edge), + ); + input_vals.insert( + EdgeRelablerInput::Label, + EdgeRelablerInputValues::Label(label.clone()), + ); - let mut context = Context::new(input_vals); - if let Some(v) = execute(&self.tree, &mut context, translator, graph)? { - Ok(v) - } else { - Err("No value returned.".into()) - } + let mut context = Context::new(input_vals); + if let Some(v) = execute(&self.tree, &mut context, translator, graph)? { + Ok(v) + } else { + Err("No value returned.".into()) + } } } @@ -175,110 +188,117 @@ enum NodeRelablerInputValues { impl SpecialVariables for NodeRelablerInput { fn type_of(&self) -> AssertionTypes { - match self { - Self::Entities => AssertionTypes::Set, - Self::Node => AssertionTypes::Node, - } + match self { + Self::Entities => AssertionTypes::Set, + Self::Node => AssertionTypes::Node, + } } fn type_qualified(&self, q: &Qualifier) -> Result { - match (self, q) { - (Self::Node, Qualifier::Node(QualifierNode::System)) => - Ok(AssertionTypes::System), - (Self::Node, Qualifier::Node(QualifierNode::Neighbours)) => - Ok(AssertionTypes::RangeNeighbours), - (s, q) => - Err(format!("Wrong use of qualifier {q:?} on variable {s:?}.")) - } + match (self, q) { + (Self::Node, Qualifier::Node(QualifierNode::System)) => Ok(AssertionTypes::System), + (Self::Node, Qualifier::Node(QualifierNode::Neighbours)) => { + Ok(AssertionTypes::RangeNeighbours) + } + (s, q) => Err(format!("Wrong use of qualifier {q:?} on variable {s:?}.")), + } } - fn new_context(input: HashMap) - -> HashMap { - input.iter().map(|(key, value)| { - match value { - NodeRelablerInputValues::Entities(e) => - (*key, AssertReturnValue::Set(e.clone())), - NodeRelablerInputValues::Node(n) => - (*key, AssertReturnValue::Node(*n)), - } - }).collect::>() + fn new_context( + input: HashMap, + ) -> HashMap { + input + .iter() + .map(|(key, value)| match value { + NodeRelablerInputValues::Entities(e) => (*key, AssertReturnValue::Set(e.clone())), + NodeRelablerInputValues::Node(n) => (*key, AssertReturnValue::Node(*n)), + }) + .collect::>() } fn correct_type(&self, other: &AssertReturnValue) -> bool { - match (self, other) { - (Self::Entities, AssertReturnValue::Set(_)) | - (Self::Node, AssertReturnValue::Node(_)) => true, - (_, _) => false - } + match (self, other) { + (Self::Entities, AssertReturnValue::Set(_)) + | (Self::Node, AssertReturnValue::Node(_)) => true, + (_, _) => false, + } } } impl std::fmt::Debug for NodeRelablerInput { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Entities => write!(f, "entities"), - Self::Node => write!(f, "node"), - } + match self { + Self::Entities => write!(f, "entities"), + Self::Node => write!(f, "node"), + } } } impl PrintableWithTranslator for NodeRelablerInput { - fn print(&self, - f: &mut std::fmt::Formatter, - _translator: &translator::Translator) - -> std::fmt::Result { - write!(f, "{self:?}") + fn print( + &self, + f: &mut std::fmt::Formatter, + _translator: &translator::Translator, + ) -> std::fmt::Result { + write!(f, "{self:?}") } } - impl Assert { pub fn typecheck(&self) -> Result<(), String> { - let mut context = TypeContext::new(); - let ty = typecheck(&self.tree, &mut context)?; - match ty { - AssertionTypes::Boolean | - AssertionTypes::Integer | - AssertionTypes::String | - AssertionTypes::Label | - AssertionTypes::Set | - AssertionTypes::Element | - AssertionTypes::Edge | - AssertionTypes::Node | - AssertionTypes::System | - AssertionTypes::Context => - Ok(()), - AssertionTypes::NoType => - Err("No return type, at least one return statement \ - required.".into()), - AssertionTypes::RangeInteger | - AssertionTypes::RangeSet | - AssertionTypes::RangeNeighbours => - Err(format!("Returned type {ty:?} is not a valid return \ - type.")), - } + let mut context = TypeContext::new(); + let ty = typecheck(&self.tree, &mut context)?; + match ty { + AssertionTypes::Boolean + | AssertionTypes::Integer + | AssertionTypes::String + | AssertionTypes::Label + | AssertionTypes::Set + | AssertionTypes::Element + | AssertionTypes::Edge + | AssertionTypes::Node + | AssertionTypes::System + | AssertionTypes::Context => Ok(()), + AssertionTypes::NoType => Err("No return type, at least one return statement \ + required." + .into()), + AssertionTypes::RangeInteger + | AssertionTypes::RangeSet + | AssertionTypes::RangeNeighbours => Err(format!( + "Returned type {ty:?} is not a valid return \ + type." + )), + } } pub fn execute( - &self, - graph: &graph::SystemGraph, - node: &::NodeId, - translator: &mut translator::Translator, + &self, + graph: &graph::SystemGraph, + node: &::NodeId, + translator: &mut translator::Translator, ) -> Result { - let system::System {available_entities: entities, ..} = - graph.node_weight(*node).ok_or("Missing node {{debug: {node:?}}}")?; + let system::System { + available_entities: entities, + .. + } = graph + .node_weight(*node) + .ok_or("Missing node {{debug: {node:?}}}")?; - let mut input_vals = HashMap::new(); - input_vals.insert(NodeRelablerInput::Entities, - NodeRelablerInputValues::Entities(entities.clone())); - input_vals.insert(NodeRelablerInput::Node, - NodeRelablerInputValues::Node(*node)); + let mut input_vals = HashMap::new(); + input_vals.insert( + NodeRelablerInput::Entities, + NodeRelablerInputValues::Entities(entities.clone()), + ); + input_vals.insert( + NodeRelablerInput::Node, + NodeRelablerInputValues::Node(*node), + ); - let mut context = Context::new(input_vals); - if let Some(v) = execute(&self.tree, &mut context, translator, graph)? { - Ok(v) - } else { - Err("No value returned.".into()) - } + let mut context = Context::new(input_vals); + if let Some(v) = execute(&self.tree, &mut context, translator, graph)? { + Ok(v) + } else { + Err("No value returned.".into()) + } } } diff --git a/src/rsprocess/assert/tests.rs b/src/rsprocess/assert/tests.rs index d95549d..a71cc4a 100644 --- a/src/rsprocess/assert/tests.rs +++ b/src/rsprocess/assert/tests.rs @@ -1,24 +1,20 @@ +use super::super::{environment, label, process, set, system, translator}; use super::dsl::*; -use super::super::{ environment, - process, - translator, - set, - system, - label }; use super::rsassert::*; type LocalAssert = Assert; #[test] fn return_true() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; - let tree = LocalAssert {tree: Tree::Return(Box::new(Expression::True))}; + let tree = LocalAssert { + tree: Tree::Return(Box::new(Expression::True)), + }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -26,28 +22,30 @@ fn return_true() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn concat_1() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::True))), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::True), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -55,28 +53,30 @@ fn concat_1() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn concat_2() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)))), - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -84,25 +84,26 @@ fn concat_2() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn return_1() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new(Tree::Return(Box::new(Expression::False))), - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Return(Box::new(Expression::False))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -110,17 +111,19 @@ fn return_1() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn return_incompatible_1() { let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new(Tree::Return(Box::new(Expression::Integer(10)))), - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Return(Box::new(Expression::Integer(10)))), + ), }; assert!(tree.typecheck().is_err()); } @@ -128,47 +131,46 @@ fn return_incompatible_1() { #[test] fn return_incompatible_2() { let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new( - Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)))), - Box::new(Tree::Return( - Box::new(Expression::Var(Variable::Id("a".into()))) - ))), - ) - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_err()); } #[test] fn return_2() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new( - Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::False))), - Box::new(Tree::Return( - Box::new(Expression::Var(Variable::Id("a".into()))) - ))), - ) - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::False), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -176,35 +178,35 @@ fn return_2() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } - #[test] fn return_3() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::False))), - Box::new(Tree::Return( - Box::new(Expression::Var(Variable::Id("a".into()))) - ))), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::False), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -212,36 +214,29 @@ fn return_3() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(false)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(false)) + )); } #[test] fn if_1() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new( - Tree::If( - Box::new( - Expression::True - ), - Box::new(Tree::Return( - Box::new( - Expression::True) - ) - ) - ), - ) - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::If( + Box::new(Expression::True), + Box::new(Tree::Return(Box::new(Expression::True))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -249,32 +244,26 @@ fn if_1() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn if_2() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::If( - Box::new( - Expression::True - ), - Box::new(Tree::Return( - Box::new( - Expression::False) - ) - ) - ), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::If( + Box::new(Expression::True), + Box::new(Tree::Return(Box::new(Expression::False))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_ok()); @@ -285,36 +274,29 @@ fn if_2() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(false)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(false)) + )); } #[test] fn if_3() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::If( - Box::new( - Expression::False - ), - Box::new(Tree::Return( - Box::new( - Expression::False) - ) - ) - ), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::If( + Box::new(Expression::False), + Box::new(Tree::Return(Box::new(Expression::False))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -322,61 +304,44 @@ fn if_3() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn if_4() { let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::If( - Box::new( - Expression::Integer(10) - ), - Box::new(Tree::Return( - Box::new( - Expression::True) - ) - ) - ), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::If( + Box::new(Expression::Integer(10)), + Box::new(Tree::Return(Box::new(Expression::True))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_err()); } #[test] fn if_else_1() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Return(Box::new(Expression::True))), - Box::new( - Tree::IfElse( - Box::new( - Expression::True - ), - Box::new(Tree::Return( - Box::new( - Expression::True) - )), - Box::new(Tree::Return( - Box::new( - Expression::False) - )), - ), - ) - ) + tree: Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::IfElse( + Box::new(Expression::True), + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Return(Box::new(Expression::False))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -384,39 +349,30 @@ fn if_else_1() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn if_else_2() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::IfElse( - Box::new( - Expression::False - ), - Box::new(Tree::Return( - Box::new( - Expression::True) - )), - Box::new(Tree::Return( - Box::new( - Expression::False) - )), - ), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::IfElse( + Box::new(Expression::False), + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Return(Box::new(Expression::False))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -424,31 +380,23 @@ fn if_else_2() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(false)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(false)) + )); } #[test] fn if_else_3() { let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::IfElse( - Box::new( - Expression::Integer(10) - ), - Box::new(Tree::Return( - Box::new( - Expression::True) - )), - Box::new(Tree::Return( - Box::new( - Expression::False) - )), - ), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::IfElse( + Box::new(Expression::Integer(10)), + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Return(Box::new(Expression::False))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_err()); } @@ -456,24 +404,14 @@ fn if_else_3() { #[test] fn if_else_4() { let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::IfElse( - Box::new( - Expression::True - ), - Box::new(Tree::Return( - Box::new( - Expression::True) - )), - Box::new(Tree::Return( - Box::new( - Expression::Integer(10)) - )), - ), - ), - Box::new(Tree::Return(Box::new(Expression::True))), - ) + tree: Tree::Concat( + Box::new(Tree::IfElse( + Box::new(Expression::True), + Box::new(Tree::Return(Box::new(Expression::True))), + Box::new(Tree::Return(Box::new(Expression::Integer(10)))), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_err()); } @@ -481,42 +419,29 @@ fn if_else_4() { #[test] fn assignment_1() { let tree = LocalAssert { - tree: Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::True) - ) + tree: Tree::Assignment(Variable::Id("a".into()), None, Box::new(Expression::True)), }; assert!(tree.typecheck().is_err()); } #[test] fn assignment_2() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::True) - ) - ), - Box::new( - Tree::Return( - Box::new( - Expression::True - ) - ) - ), - ) + tree: Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::True), + )), + Box::new(Tree::Return(Box::new(Expression::True))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -524,39 +449,32 @@ fn assignment_2() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn assignment_3() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::False) - ) - ), - Box::new( - Tree::Return( - Box::new( - Expression::Var( - Variable::Id("a".into()) - ) - ) - ) - ), - ) + tree: Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::False), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -564,65 +482,54 @@ fn assignment_3() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(false)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(false)) + )); } #[test] fn assignment_4() { let tree = LocalAssert { - tree: Tree::Concat( - Box::new( - Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::True) - ) - ), - Box::new( - Tree::Return( - Box::new( - Expression::Var( - Variable::Id("b".into()) - ) - ) - ) - ), - ) + tree: Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::True), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + ), }; assert!(tree.typecheck().is_err()); } #[test] fn assignment_5() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)) - )), - Box::new(Tree::Concat( - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -630,47 +537,44 @@ fn assignment_5() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(10)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(10)) + )); } #[test] fn assignment_6() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Integer(200)) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Integer(200)), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -678,45 +582,42 @@ fn assignment_6() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(10)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(10)) + )); } #[test] fn assignment_7() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)) - )), - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::True) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - Box::new(Tree::Return( - Box::new(Expression::False) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::True), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + Box::new(Tree::Return(Box::new(Expression::False))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -724,49 +625,44 @@ fn assignment_7() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } #[test] fn assignment_8() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Var(Variable::Id("a".into()))), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "a".into(), + ))))), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -774,47 +670,42 @@ fn assignment_8() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(10)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(10)) + )); } #[test] fn assignment_9() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )), - Box::new(Tree::Return( - Box::new(Expression::Integer(200)) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Var(Variable::Id("a".into()))), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + Box::new(Tree::Return(Box::new(Expression::Integer(200)))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -822,49 +713,46 @@ fn assignment_9() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(10)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(10)) + )); } #[test] fn assignment_10() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(10)) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(200)) - )), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(10)), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Var(Variable::Id("a".into()))), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(200)), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -872,50 +760,42 @@ fn assignment_10() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(10)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(10)) + )); } - #[test] fn for_1() { - use translator::Translator; + use label::Label; use set::Set; use system::System; - use label::Label; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Set(Set::default())) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Set(Set::default())) - )), - )), - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateOverSet( - Box::new( - Expression::Var( - Variable::Id("a".into()), - ) - ) - ), - Box::new(Tree::Return( - Box::new(Expression::Integer(200)) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Set(Set::default())), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Set(Set::default())), + )), + )), + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateOverSet(Box::new(Expression::Var(Variable::Id("a".into())))), + Box::new(Tree::Return(Box::new(Expression::Integer(200)))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -926,48 +806,38 @@ fn for_1() { assert!(tree.execute(&graph, &edge, &mut tr).is_err()); } - #[test] fn for_2() { - use translator::Translator; + use label::Label; use set::Set; use system::System; - use label::Label; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Set(Set::from([1, 2]))) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Set(Set::default())) - )), - )), - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateOverSet( - Box::new( - Expression::Var( - Variable::Id("a".into()) - ) - ) - ), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Set(Set::from([1, 2]))), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Set(Set::default())), + )), + )), + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateOverSet(Box::new(Expression::Var(Variable::Id("a".into())))), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); tr.encode("one"); tr.encode("two"); @@ -977,65 +847,56 @@ fn for_2() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Set(_)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Set(_)) + )); } #[test] fn for_3() { - use translator::Translator; + use label::Label; use set::Set; use system::System; - use label::Label; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Label( - Box::new(Label::from(Set::from([1, 2]), - Set::default(), - Set::from([1, 2]), - Set::default(), - Set::default(), - Set::default(), - Set::default(), - Set::default())) - )) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Set(Set::default())) - )), - )), - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateOverSet( - Box::new( - Expression::Unary( - Unary::Qualifier(Qualifier::Restricted( - QualifierRestricted::Entities - )), - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - ) - ) - ), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Label(Box::new(Label::from( + Set::from([1, 2]), + Set::default(), + Set::from([1, 2]), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + )))), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Set(Set::default())), + )), + )), + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateOverSet(Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Restricted(QualifierRestricted::Entities)), + Box::new(Expression::Var(Variable::Id("a".into()))), + ))), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); tr.encode("one"); tr.encode("two"); @@ -1045,65 +906,56 @@ fn for_3() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Set(_)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Set(_)) + )); } #[test] fn for_4() { - use translator::Translator; + use label::Label; use set::Set; use system::System; - use label::Label; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Label( - Box::new(Label::from(Set::from([1, 2]), - Set::from([3]), - Set::from([1, 2, 3]), - Set::default(), - Set::default(), - Set::default(), - Set::default(), - Set::default())) - )) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Set(Set::default())) - )), - )), - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateOverSet( - Box::new( - Expression::Unary( - Unary::Qualifier(Qualifier::Label( - QualifierLabel::AvailableEntities - )), - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - ) - ) - ), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("c".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Label(Box::new(Label::from( + Set::from([1, 2]), + Set::from([3]), + Set::from([1, 2, 3]), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + )))), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Set(Set::default())), + )), + )), + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateOverSet(Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Label(QualifierLabel::AvailableEntities)), + Box::new(Expression::Var(Variable::Id("a".into()))), + ))), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "c".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); tr.encode("one"); tr.encode("two"); @@ -1114,78 +966,67 @@ fn for_4() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Element(_)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Element(_)) + )); } #[test] fn for_5() { - use translator::Translator; + use label::Label; use set::Set; use system::System; - use label::Label; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Label( - Box::new(Label::from(Set::from([1, 2]), - Set::from([3]), - Set::from([1, 2, 3]), - Set::default(), - Set::default(), - Set::default(), - Set::default(), - Set::default())) - )) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Integer(0)) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateOverSet( - Box::new( - Expression::Unary( - Unary::Qualifier(Qualifier::Label( - QualifierLabel::AvailableEntities - )), - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - ) - ) - ), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Binary( - Binary::Plus, - Box::new(Expression::Var( - Variable::Id("b".into()) - )), - Box::new(Expression::Integer(1)) - )) - )), - )), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - )) - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Label(Box::new(Label::from( + Set::from([1, 2]), + Set::from([3]), + Set::from([1, 2, 3]), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + )))), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Integer(0)), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateOverSet(Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Label(QualifierLabel::AvailableEntities)), + Box::new(Expression::Var(Variable::Id("a".into()))), + ))), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Binary( + Binary::Plus, + Box::new(Expression::Var(Variable::Id("b".into()))), + Box::new(Expression::Integer(1)), + )), + )), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); tr.encode("one"); tr.encode("two"); @@ -1196,88 +1037,78 @@ fn for_5() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(3)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(3)) + )); } #[test] fn for_6() { - use translator::Translator; + use label::Label; use set::Set; use system::System; - use label::Label; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Label( - Box::new(Label::from(Set::from([1, 2]), - Set::from([3]), - Set::from([1, 2, 3]), - Set::default(), - Set::default(), - Set::default(), - Set::default(), - Set::default())) - )) - )), - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Set(Set::from([2]))) - )), - Box::new(Tree::Assignment( - Variable::Id("c".into()), - None, - Box::new(Expression::Integer(0)) - )), - )) - )), - Box::new(Tree::Concat( - Box::new(Tree::For( - Variable::Id("d".into()), - Range::IterateOverSet( - Box::new( - Expression::Binary( - Binary::Plus, - Box::new(Expression::Unary( - Unary::Qualifier(Qualifier::Restricted( - QualifierRestricted::Context - )), - Box::new(Expression::Var( - Variable::Id("a".into()) - )) - ) - ), - Box::new(Expression::Var( - Variable::Id("b".into()) - )) - ) - ) - ), - Box::new(Tree::Assignment( - Variable::Id("c".into()), - None, - Box::new(Expression::Binary( - Binary::Plus, - Box::new(Expression::Var(Variable::Id("c".into()))), - Box::new(Expression::Integer(1)) - )) - )), - )), - Box::new(Tree::Return( - Box::new(Expression::Var(Variable::Id("c".into()))) - )) - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Label(Box::new(Label::from( + Set::from([1, 2]), + Set::from([3]), + Set::from([1, 2, 3]), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + Set::default(), + )))), + )), + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Set(Set::from([2]))), + )), + Box::new(Tree::Assignment( + Variable::Id("c".into()), + None, + Box::new(Expression::Integer(0)), + )), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::For( + Variable::Id("d".into()), + Range::IterateOverSet(Box::new(Expression::Binary( + Binary::Plus, + Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Restricted(QualifierRestricted::Context)), + Box::new(Expression::Var(Variable::Id("a".into()))), + )), + Box::new(Expression::Var(Variable::Id("b".into()))), + ))), + Box::new(Tree::Assignment( + Variable::Id("c".into()), + None, + Box::new(Expression::Binary( + Binary::Plus, + Box::new(Expression::Var(Variable::Id("c".into()))), + Box::new(Expression::Integer(1)), + )), + )), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "c".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); tr.encode("one"); tr.encode("two"); @@ -1288,52 +1119,46 @@ fn for_6() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(2)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(2)) + )); } #[test] fn for_7() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Integer(0)) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Integer(10)) - )), - )), - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateInRange( - Box::new(Expression::Var( - Variable::Id("a".into()) - )), - Box::new(Expression::Var( - Variable::Id("b".into()), - )), - ), - Box::new(Tree::Return( - Box::new(Expression::Var( - Variable::Id("c".into()) - )) - )), - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Integer(0)), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Integer(10)), + )), + )), + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateInRange( + Box::new(Expression::Var(Variable::Id("a".into()))), + Box::new(Expression::Var(Variable::Id("b".into()))), + ), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "c".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -1341,68 +1166,60 @@ fn for_7() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(0)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(0)) + )); } #[test] fn for_8() { - use translator::Translator; - use system::System; use label::Label; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Unary( - Unary::Qualifier(Qualifier::Node( - QualifierNode::Neighbours)), - Box::new(Expression::Unary( - Unary::Qualifier(Qualifier::Edge( - QualifierEdge::Source)), - Box::new(Expression::Var( - Variable::Special(EdgeRelablerInput::Edge) - )) - )) - )) - )), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Integer(0)) - )), - )), - Box::new(Tree::Concat( - Box::new(Tree::For( - Variable::Id("c".into()), - Range::IterateOverSet( - Box::new(Expression::Var( - Variable::Id("a".into()) - )), - ), - Box::new(Tree::Assignment( - Variable::Id("b".into()), - None, - Box::new(Expression::Binary( - Binary::Plus, - Box::new(Expression::Var(Variable::Id("b".into()))), - Box::new(Expression::Integer(1)) - )) - )), - )), - Box::new(Tree::Return( - Box::new(Expression::Var(Variable::Id("b".into()))) - )) - )) - ) + tree: Tree::Concat( + Box::new(Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Node(QualifierNode::Neighbours)), + Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Edge(QualifierEdge::Source)), + Box::new(Expression::Var(Variable::Special(EdgeRelablerInput::Edge))), + )), + )), + )), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Integer(0)), + )), + )), + Box::new(Tree::Concat( + Box::new(Tree::For( + Variable::Id("c".into()), + Range::IterateOverSet(Box::new(Expression::Var(Variable::Id("a".into())))), + Box::new(Tree::Assignment( + Variable::Id("b".into()), + None, + Box::new(Expression::Binary( + Binary::Plus, + Box::new(Expression::Var(Variable::Id("b".into()))), + Box::new(Expression::Integer(1)), + )), + )), + )), + Box::new(Tree::Return(Box::new(Expression::Var(Variable::Id( + "b".into(), + ))))), + )), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); @@ -1410,9 +1227,10 @@ fn for_8() { let node_2 = graph.add_node(System::default()); let edge = graph.add_edge(node_1, node_2, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(1)))); - + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(1)) + )); let mut tr = Translator::new(); @@ -1423,72 +1241,63 @@ fn for_8() { let node_3 = graph.add_node(System::default()); graph.add_edge(node_1, node_3, Label::default()); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Integer(2)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Integer(2)) + )); } #[test] fn nodes() { - use translator::Translator; - use set::Set; - use process::Process; use environment::Environment; - use system::System; use label::Label; + use process::Process; + use set::Set; use std::rc::Rc; + use system::System; + use translator::Translator; let tree = LocalAssert { - tree: Tree::Concat( - Box::new(Tree::Assignment( - Variable::Id("a".into()), - None, - Box::new(Expression::Unary( - Unary::Qualifier( - Qualifier::System(QualifierSystem::Entities) - ), - Box::new(Expression::Unary( - Unary::Qualifier(Qualifier::Node( - QualifierNode::System)), - Box::new(Expression::Unary( - Unary::Qualifier(Qualifier::Edge( - QualifierEdge::Target)), - Box::new(Expression::Var( - Variable::Special(EdgeRelablerInput::Edge) - )) - )) - )) - )) - )), - Box::new(Tree::Return( - Box::new(Expression::Binary( - Binary::Less, - Box::new(Expression::Var( - Variable::Id("a".into()) - )), - Box::new(Expression::Set(Set::from([1, 2]))) - )) - )), - ) + tree: Tree::Concat( + Box::new(Tree::Assignment( + Variable::Id("a".into()), + None, + Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::System(QualifierSystem::Entities)), + Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Node(QualifierNode::System)), + Box::new(Expression::Unary( + Unary::Qualifier(Qualifier::Edge(QualifierEdge::Target)), + Box::new(Expression::Var(Variable::Special(EdgeRelablerInput::Edge))), + )), + )), + )), + )), + Box::new(Tree::Return(Box::new(Expression::Binary( + Binary::Less, + Box::new(Expression::Var(Variable::Id("a".into()))), + Box::new(Expression::Set(Set::from([1, 2]))), + )))), + ), }; assert!(tree.typecheck().is_ok()); - let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); let node_1 = graph.add_node(System::default()); - let node_2 = graph.add_node( - System::from( - Rc::new(Environment::default()), - Set::from([2]), - Process::Nill, - Rc::new(vec![]) - ) - ); + let node_2 = graph.add_node(System::from( + Rc::new(Environment::default()), + Set::from([2]), + Process::Nill, + Rc::new(vec![]), + )); let edge = graph.add_edge(node_1, node_2, Label::default()); println!("{:?}", tree.execute(&graph, &edge, &mut tr)); - assert!(matches!(tree.execute(&graph, &edge, &mut tr), - Ok(AssertReturnValue::Boolean(true)))); + assert!(matches!( + tree.execute(&graph, &edge, &mut tr), + Ok(AssertReturnValue::Boolean(true)) + )); } diff --git a/src/rsprocess/bisimilarity/bisimilarity_kanellakis_smolka.rs b/src/rsprocess/bisimilarity/bisimilarity_kanellakis_smolka.rs index ef283f8..1b1803a 100644 --- a/src/rsprocess/bisimilarity/bisimilarity_kanellakis_smolka.rs +++ b/src/rsprocess/bisimilarity/bisimilarity_kanellakis_smolka.rs @@ -4,9 +4,9 @@ use std::collections::{BTreeSet, HashMap, HashSet}; -use petgraph::visit::{ EdgeRef, GraphBase, IntoEdgeReferences, - IntoEdges, IntoNodeIdentifiers, - IntoNodeReferences }; +use petgraph::visit::{ + EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges, IntoNodeIdentifiers, IntoNodeReferences, +}; // ----------------------------------------------------------------------------- // Helper Functions @@ -15,18 +15,18 @@ use petgraph::visit::{ EdgeRef, GraphBase, IntoEdgeReferences, #[inline(always)] fn equal_vectors(a: &Vec, b: &Vec) -> bool where - T: PartialEq + T: PartialEq, { for el in a { - if !b.contains(el) { - return false; - } + if !b.contains(el) { + return false; + } } for el in b { - if !a.contains(el) { - return false; - } + if !a.contains(el) { + return false; + } } true @@ -45,47 +45,49 @@ where pub block_to_node: HashMap>, pub graphs: [&'a G; 2], last_block: u32, - blocks: BTreeSet + blocks: BTreeSet, } impl<'a, G> GraphPartition<'a, G> where G: GraphBase, - G::NodeId: std::cmp::Eq + std::hash::Hash + G::NodeId: std::cmp::Eq + std::hash::Hash, { pub fn new(graph_a: &'a G, graph_b: &'a G) -> Self { - GraphPartition { node_to_block: HashMap::new(), - block_to_node: HashMap::new(), - graphs: [graph_a, graph_b], - last_block: 0, - blocks: BTreeSet::new() } + GraphPartition { + node_to_block: HashMap::new(), + block_to_node: HashMap::new(), + graphs: [graph_a, graph_b], + last_block: 0, + blocks: BTreeSet::new(), + } } #[inline(always)] pub fn add_node_last_partition(&mut self, node: G::NodeId, graph: usize) { - self.node_to_block.insert((graph, node), self.last_block); - self.block_to_node - .entry(self.last_block) - .or_default() - .push((graph, node)); - self.blocks.insert(self.last_block); + self.node_to_block.insert((graph, node), self.last_block); + self.block_to_node + .entry(self.last_block) + .or_default() + .push((graph, node)); + self.blocks.insert(self.last_block); } #[inline(always)] pub fn iterate_blocks(&self) -> Vec { - self.blocks.iter().cloned().collect::>() + self.blocks.iter().cloned().collect::>() } pub fn bisimilar(&self) -> bool { - // if there is a block that has only elements from one graph then they - // are not bisimilar - for (_block, node_list) in self.block_to_node.iter() { - let graph_id = node_list.first().unwrap().0; - if node_list.iter().all(|el| el.0 == graph_id) { - return false; - } - } - true + // if there is a block that has only elements from one graph then they + // are not bisimilar + for (_block, node_list) in self.block_to_node.iter() { + let graph_id = node_list.first().unwrap().0; + if node_list.iter().all(|el| el.0 == graph_id) { + return false; + } + } + true } } @@ -94,104 +96,97 @@ where G: IntoEdges, G::NodeId: std::cmp::Eq + std::hash::Hash, { - fn reachable_blocks( - &self, - label: &G::EdgeWeight, - s: &(usize, G::NodeId) - ) -> Vec - where G::EdgeWeight: PartialEq + fn reachable_blocks(&self, label: &G::EdgeWeight, s: &(usize, G::NodeId)) -> Vec + where + G::EdgeWeight: PartialEq, { - let mut val = vec![]; - for el in self.graphs[s.0].edges(s.1).filter(|x| x.weight() == label) { - let tmp = (s.0, el.target()); - val.push(*self.node_to_block.get(&tmp).unwrap()); - } - val + let mut val = vec![]; + for el in self.graphs[s.0].edges(s.1).filter(|x| x.weight() == label) { + let tmp = (s.0, el.target()); + val.push(*self.node_to_block.get(&tmp).unwrap()); + } + val } pub fn split(&mut self, block: u32, label: &G::EdgeWeight) -> bool - where G::EdgeWeight: PartialEq + where + G::EdgeWeight: PartialEq, { - let Some(nodes) = self.block_to_node.get(&block) - else { - return true - }; - let mut nodes = nodes.iter(); - let s = nodes.next().unwrap(); + let Some(nodes) = self.block_to_node.get(&block) else { + return true; + }; + let mut nodes = nodes.iter(); + let s = nodes.next().unwrap(); - let mut b1 = vec![s]; - let mut b2 = vec![]; + let mut b1 = vec![s]; + let mut b2 = vec![]; - let reachable_blocks_s = self.reachable_blocks(label, s); + let reachable_blocks_s = self.reachable_blocks(label, s); - for t in nodes { - let reachable_blocks_t = self.reachable_blocks(label, t); - if equal_vectors(&reachable_blocks_s, &reachable_blocks_t) { - b1.push(t); - } else { - b2.push(*t); - } - } + for t in nodes { + let reachable_blocks_t = self.reachable_blocks(label, t); + if equal_vectors(&reachable_blocks_s, &reachable_blocks_t) { + b1.push(t); + } else { + b2.push(*t); + } + } - if b2.is_empty() { - // all elements go to the same block with label label, so no change - false - } else { - // some elements need to be split into a different block - self.last_block += 1; - let new_block = self.last_block; - self.blocks.insert(new_block); + if b2.is_empty() { + // all elements go to the same block with label label, so no change + false + } else { + // some elements need to be split into a different block + self.last_block += 1; + let new_block = self.last_block; + self.blocks.insert(new_block); - for b in b2 { - self.node_to_block.entry(b).and_modify(|e| *e = new_block); - self.block_to_node.entry(new_block).or_default().push(b); - self.block_to_node.entry(block).and_modify(|e| { - let index = e.iter().position(|x| *x == b).unwrap(); - e.remove(index); - }); - } - true - } + for b in b2 { + self.node_to_block.entry(b).and_modify(|e| *e = new_block); + self.block_to_node.entry(new_block).or_default().push(b); + self.block_to_node.entry(block).and_modify(|e| { + let index = e.iter().position(|x| *x == b).unwrap(); + e.remove(index); + }); + } + true + } } } -pub fn bisimilarity<'a, G>( - graph_a: &'a G, - graph_b: &'a G -) -> bool +pub fn bisimilarity<'a, G>(graph_a: &'a G, graph_b: &'a G) -> bool where G: IntoNodeReferences + IntoEdges, G::NodeId: std::cmp::Eq + std::hash::Hash, - G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone + G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone, { let graphs = [graph_a, graph_b]; - let mut partition: GraphPartition = - GraphPartition::new(graph_a, graph_b); + let mut partition: GraphPartition = GraphPartition::new(graph_a, graph_b); for (p, graph) in graphs.iter().enumerate() { - for node in graph.node_identifiers() { - partition.add_node_last_partition(node, p); - } + for node in graph.node_identifiers() { + partition.add_node_last_partition(node, p); + } } - let labels = - graph_a.edge_references() - .chain(graph_b.edge_references()) - .map(|e| e.weight().clone()) - .collect::>(); + let labels = graph_a + .edge_references() + .chain(graph_b.edge_references()) + .map(|e| e.weight().clone()) + .collect::>(); let mut changed = true; while changed { - changed = false; + changed = false; - for block in partition.iterate_blocks() { - for label in labels.iter() { - if partition.split(block, label) { - changed = true; - } - } - } + for block in partition.iterate_blocks() { + for label in labels.iter() { + if partition.split(block, label) { + changed = true; + } + } + } } partition.bisimilar() diff --git a/src/rsprocess/bisimilarity/bisimilarity_paige_tarkan.rs b/src/rsprocess/bisimilarity/bisimilarity_paige_tarkan.rs index d3bc9ad..0cf0061 100644 --- a/src/rsprocess/bisimilarity/bisimilarity_paige_tarkan.rs +++ b/src/rsprocess/bisimilarity/bisimilarity_paige_tarkan.rs @@ -7,11 +7,11 @@ use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; use std::rc::Rc; -use petgraph::visit::{ EdgeCount, EdgeRef, GraphBase, IntoEdgeReferences, - IntoNeighborsDirected, IntoNodeIdentifiers, - IntoNodeReferences, NodeCount }; use petgraph::Direction::{Incoming, Outgoing}; - +use petgraph::visit::{ + EdgeCount, EdgeRef, GraphBase, IntoEdgeReferences, IntoNeighborsDirected, IntoNodeIdentifiers, + IntoNodeReferences, NodeCount, +}; type NodeIdType = u32; type GraphIdType = u32; @@ -24,7 +24,7 @@ trait NextId { struct Translator where - State: NextId + State: NextId, { data: HashMap, reverse_data: HashMap, @@ -35,34 +35,34 @@ impl Translator where To: std::hash::Hash + std::cmp::Eq + Copy, From: std::hash::Hash + std::cmp::Eq + Clone, - State: NextId + State: NextId, { pub fn new() -> Self where - State: Default + State: Default, { - Translator { data: HashMap::new(), - reverse_data: HashMap::new(), - last_id: State::default() } + Translator { + data: HashMap::new(), + reverse_data: HashMap::new(), + last_id: State::default(), + } } - pub fn encode(&mut self, val: From) -> To - { - let id = *(self.data.entry(val.clone()) - .or_insert( - self.last_id.next_id_of_graph(val.clone()) - )); - self.reverse_data.insert(id, val); - id + pub fn encode(&mut self, val: From) -> To { + let id = *(self + .data + .entry(val.clone()) + .or_insert(self.last_id.next_id_of_graph(val.clone()))); + self.reverse_data.insert(id, val); + id } - pub fn get(&self, val: &From) -> Option<&To> - { - self.data.get(val) + pub fn get(&self, val: &From) -> Option<&To> { + self.data.get(val) } pub fn decode(&self, val: &To) -> Option<&From> { - self.reverse_data.get(val) + self.reverse_data.get(val) } } @@ -73,29 +73,28 @@ struct NodeState { impl NodeState { fn new() -> Self { - NodeState { last_ids: [0; N] } + NodeState { last_ids: [0; N] } } } impl Default for NodeState { fn default() -> Self { - Self::new() + Self::new() } } impl NextId<(T, GraphIdType), NodeType> for NodeState { fn next_id_of_graph(&mut self, val: (T, GraphIdType)) -> NodeType { - let graph_id_usize = val.1 as usize; - assert!(graph_id_usize < N); - self.last_ids[graph_id_usize] += 1; - (val.1, self.last_ids[graph_id_usize]) + let graph_id_usize = val.1 as usize; + assert!(graph_id_usize < N); + self.last_ids[graph_id_usize] += 1; + (val.1, self.last_ids[graph_id_usize]) } } type MyNodeTranslator = Translator<(From, GraphIdType), NodeType, NodeState>; - type EdgeIdType = u32; type EdgeType = EdgeIdType; @@ -106,26 +105,25 @@ struct EdgeState { impl EdgeState { fn new() -> Self { - EdgeState { last_ids: 0 } + EdgeState { last_ids: 0 } } } impl Default for EdgeState { fn default() -> Self { - Self::new() + Self::new() } } impl NextId for EdgeState { fn next_id_of_graph(&mut self, _val: T) -> EdgeType { - self.last_ids += 1; - self.last_ids + self.last_ids += 1; + self.last_ids } } type MyEdgeTranslator = Translator; - type Block = Vec; type BackEdges = HashMap>; type NodeToBlock = HashMap>>; @@ -136,7 +134,7 @@ type BackEdgesGrouped = HashMap; struct SimpleBlock { block: Block, - coarse_block_that_supersets_self: Rc + coarse_block_that_supersets_self: Rc, } #[derive(Clone)] @@ -147,17 +145,17 @@ struct CompoundBlock { impl CompoundBlock { fn add_simple_block(&self, fine_block: Rc>) { - self.simple_blocks_subsets_of_self - .borrow_mut() - .push(fine_block); + self.simple_blocks_subsets_of_self + .borrow_mut() + .push(fine_block); } fn remove_simple_block(&self, fine_block: &Rc>) { - self.simple_blocks_subsets_of_self - .borrow_mut() - .retain(|x| !Rc::ptr_eq(x, fine_block)); + self.simple_blocks_subsets_of_self + .borrow_mut() + .retain(|x| !Rc::ptr_eq(x, fine_block)); } fn simple_block_count(&self) -> usize { - self.simple_blocks_subsets_of_self.borrow().len() + self.simple_blocks_subsets_of_self.borrow().len() } } @@ -172,191 +170,169 @@ trait HasBlock { impl HasBlock for SimpleBlockPointer { fn block(&self) -> Block { - (**self).borrow().block.clone() + (**self).borrow().block.clone() } } impl HasBlock for CompoundBlock { fn block(&self) -> Block { - self.block.clone() + self.block.clone() } } #[allow(clippy::type_complexity)] fn initialization( - graphs: &[&G; N] -) -> ( (SimpleBlockPointer, SimpleBlockPointer), - CompoundPartition, - NodeToBlock, - MyNodeTranslator ) + graphs: &[&G; N], +) -> ( + (SimpleBlockPointer, SimpleBlockPointer), + CompoundPartition, + NodeToBlock, + MyNodeTranslator, +) where G: IntoNodeReferences + IntoNeighborsDirected, - G::NodeId: std::cmp::Eq + std::hash::Hash + G::NodeId: std::cmp::Eq + std::hash::Hash, { // translate into unique ids - let mut convert_nodes: MyNodeTranslator - = Translator::new(); + let mut convert_nodes: MyNodeTranslator = Translator::new(); let graph_node_indices = { - let mut tmp: Block = vec![]; + let mut tmp: Block = vec![]; - for (pos, graph) in graphs.iter().enumerate() { - tmp.extend( - graph.node_identifiers() - .map(|val| convert_nodes.encode((val, pos as u32))) - .collect::>() - ); - } + for (pos, graph) in graphs.iter().enumerate() { + tmp.extend( + graph + .node_identifiers() + .map(|val| convert_nodes.encode((val, pos as u32))) + .collect::>(), + ); + } - tmp + tmp }; let compound_initial_block_pointer: Rc = { - let compound_initial_block = CompoundBlock { - block: graph_node_indices.clone(), - simple_blocks_subsets_of_self: RefCell::new(vec![]), - }; + let compound_initial_block = CompoundBlock { + block: graph_node_indices.clone(), + simple_blocks_subsets_of_self: RefCell::new(vec![]), + }; - Rc::new(compound_initial_block) + Rc::new(compound_initial_block) }; // minor optimization: split nodes between those that have outgoing edges // and those that dont let (leaf_node_block_pointer, non_leaf_node_block_pointer) = { - let (leaf_node_indices, non_leaf_node_indices): (Block, Block) = - graph_node_indices - .clone() - .into_iter() - .partition( - |x| { - let (node_id, graph_id) = convert_nodes.decode(x).unwrap(); - graphs[*graph_id as usize] - .neighbors_directed( - *node_id, - Outgoing) - .count() == 0 - } - ); + let (leaf_node_indices, non_leaf_node_indices): (Block, Block) = + graph_node_indices.clone().into_iter().partition(|x| { + let (node_id, graph_id) = convert_nodes.decode(x).unwrap(); + graphs[*graph_id as usize] + .neighbors_directed(*node_id, Outgoing) + .count() + == 0 + }); - let leaf_node_block = SimpleBlock { - block: leaf_node_indices, + let leaf_node_block = SimpleBlock { + block: leaf_node_indices, - coarse_block_that_supersets_self: - Rc::clone(&compound_initial_block_pointer), - }; - let non_leaf_node_block = SimpleBlock { - block: non_leaf_node_indices, + coarse_block_that_supersets_self: Rc::clone(&compound_initial_block_pointer), + }; + let non_leaf_node_block = SimpleBlock { + block: non_leaf_node_indices, - coarse_block_that_supersets_self: - Rc::clone(&compound_initial_block_pointer), - }; + coarse_block_that_supersets_self: Rc::clone(&compound_initial_block_pointer), + }; - ( - Rc::new(RefCell::new(leaf_node_block)), - Rc::new(RefCell::new(non_leaf_node_block)), - ) + ( + Rc::new(RefCell::new(leaf_node_block)), + Rc::new(RefCell::new(non_leaf_node_block)), + ) }; compound_initial_block_pointer - .simple_blocks_subsets_of_self - .borrow_mut() - .extend([ - Rc::clone(&leaf_node_block_pointer), - Rc::clone(&non_leaf_node_block_pointer), - ]); + .simple_blocks_subsets_of_self + .borrow_mut() + .extend([ + Rc::clone(&leaf_node_block_pointer), + Rc::clone(&non_leaf_node_block_pointer), + ]); let node_to_block = { - let mut node_to_block = HashMap::new(); + let mut node_to_block = HashMap::new(); - (*non_leaf_node_block_pointer) - .borrow() - .block - .iter() - .copied() - .for_each( - |value| - { node_to_block.insert(value, - Rc::clone(&non_leaf_node_block_pointer)); - } - ); + (*non_leaf_node_block_pointer) + .borrow() + .block + .iter() + .copied() + .for_each(|value| { + node_to_block.insert(value, Rc::clone(&non_leaf_node_block_pointer)); + }); - (*leaf_node_block_pointer) - .borrow() - .block - .iter() - .copied() - .for_each( - |value| - { node_to_block.insert(value, - Rc::clone(&leaf_node_block_pointer)); - } - ); - node_to_block + (*leaf_node_block_pointer) + .borrow() + .block + .iter() + .copied() + .for_each(|value| { + node_to_block.insert(value, Rc::clone(&leaf_node_block_pointer)); + }); + node_to_block }; ( - (leaf_node_block_pointer, non_leaf_node_block_pointer), - vec![compound_initial_block_pointer], - node_to_block, - convert_nodes + (leaf_node_block_pointer, non_leaf_node_block_pointer), + vec![compound_initial_block_pointer], + node_to_block, + convert_nodes, ) } -fn build_backedges( +fn build_backedges( graphs: &[&G; N], block: IndexHolder, - convert_nodes: &MyNodeTranslator + convert_nodes: &MyNodeTranslator, ) -> BackEdges where G: IntoNeighborsDirected, - G::NodeId: std::cmp::Eq + std::hash::Hash + G::NodeId: std::cmp::Eq + std::hash::Hash, { let mut backedges = HashMap::new(); block.block().iter().for_each(|node_index_pointer| { - backedges.insert( - *node_index_pointer, - { - let (node_id, graph_id) = - convert_nodes.decode(node_index_pointer).unwrap(); - graphs[*graph_id as usize] - .neighbors_directed( - *node_id, - Incoming) - .collect::>() - .into_iter() - // the back edges should be all in the same graph - .map(|e| convert_nodes.get(&(e, *graph_id)).unwrap()) - .copied() - .collect::>() - } - ); + backedges.insert(*node_index_pointer, { + let (node_id, graph_id) = convert_nodes.decode(node_index_pointer).unwrap(); + graphs[*graph_id as usize] + .neighbors_directed(*node_id, Incoming) + .collect::>() + .into_iter() + // the back edges should be all in the same graph + .map(|e| convert_nodes.get(&(e, *graph_id)).unwrap()) + .copied() + .collect::>() + }); }); backedges } -fn group_by_backedges( - backedges: BackEdges, - node_to_block: &NodeToBlock, -) -> BackEdgesGrouped { +fn group_by_backedges(backedges: BackEdges, node_to_block: &NodeToBlock) -> BackEdgesGrouped { let mut backedges_grouped: BackEdgesGrouped = HashMap::new(); for incoming_neighbor_group in backedges.values() { - for node in incoming_neighbor_group { - let block = Rc::clone(node_to_block.get(node).unwrap()); - let key = (*block).borrow().block.clone(); + for node in incoming_neighbor_group { + let block = Rc::clone(node_to_block.get(node).unwrap()); + let key = (*block).borrow().block.clone(); - match backedges_grouped.entry(key) { - Entry::Occupied(mut entry) => - entry.get_mut().subblock.push(*node), - Entry::Vacant(entry) => { - entry.insert(BackEdgesGroup { - block: Rc::clone(&block), - subblock: Vec::from([*node]), - }); - } - } - } + match backedges_grouped.entry(key) { + Entry::Occupied(mut entry) => entry.get_mut().subblock.push(*node), + Entry::Vacant(entry) => { + entry.insert(BackEdgesGroup { + block: Rc::clone(&block), + subblock: Vec::from([*node]), + }); + } + } + } } backedges_grouped @@ -374,249 +350,236 @@ fn split_blocks_with_grouped_backedges( let mut new_compound_blocks: Vec> = vec![]; for (block, back_edges_group) in backedges_grouped.iter_mut() { - let borrowed_compound_block = Rc::clone( - &(*back_edges_group.block) - .borrow() - .coarse_block_that_supersets_self, - ); + let borrowed_compound_block = Rc::clone( + &(*back_edges_group.block) + .borrow() + .coarse_block_that_supersets_self, + ); - let proper_subblock = { - let simple_block = SimpleBlock { - block: back_edges_group.subblock.clone(), + let proper_subblock = { + let simple_block = SimpleBlock { + block: back_edges_group.subblock.clone(), - coarse_block_that_supersets_self: - Rc::clone(&borrowed_compound_block), - }; + coarse_block_that_supersets_self: Rc::clone(&borrowed_compound_block), + }; - Rc::new(RefCell::new(simple_block)) - }; - let prior_count = borrowed_compound_block.simple_block_count(); - borrowed_compound_block.add_simple_block(Rc::clone(&proper_subblock)); + Rc::new(RefCell::new(simple_block)) + }; + let prior_count = borrowed_compound_block.simple_block_count(); + borrowed_compound_block.add_simple_block(Rc::clone(&proper_subblock)); - if prior_count == 1 { - new_compound_blocks.push(Rc::clone(&borrowed_compound_block)); - } + if prior_count == 1 { + new_compound_blocks.push(Rc::clone(&borrowed_compound_block)); + } - for node in back_edges_group.subblock.iter() { - node_to_block.insert(*node, Rc::clone(&proper_subblock)); - } + for node in back_edges_group.subblock.iter() { + node_to_block.insert(*node, Rc::clone(&proper_subblock)); + } - // subtract subblock from block - (*back_edges_group.block).borrow_mut().block = - block - .iter() - .filter(|x| !(*proper_subblock).borrow().block.contains(x)) - .copied() - .collect(); + // subtract subblock from block + (*back_edges_group.block).borrow_mut().block = block + .iter() + .filter(|x| !(*proper_subblock).borrow().block.contains(x)) + .copied() + .collect(); - if (*back_edges_group.block).borrow().block.is_empty() { - borrowed_compound_block - .remove_simple_block(&back_edges_group.block); - all_removed_simple_blocks.push(Rc::clone(&back_edges_group.block)); - } - all_new_simple_blocks.push(Rc::clone(&proper_subblock)); + if (*back_edges_group.block).borrow().block.is_empty() { + borrowed_compound_block.remove_simple_block(&back_edges_group.block); + all_removed_simple_blocks.push(Rc::clone(&back_edges_group.block)); + } + all_new_simple_blocks.push(Rc::clone(&proper_subblock)); } ( - (all_new_simple_blocks, all_removed_simple_blocks), - new_compound_blocks, + (all_new_simple_blocks, all_removed_simple_blocks), + new_compound_blocks, ) } fn maximum_bisimulation( - graphs: &[&G; N] + graphs: &[&G; N], ) -> (Option>, MyNodeTranslator) where G: IntoNodeReferences + IntoNeighborsDirected, - G::NodeId: std::cmp::Eq + std::hash::Hash + G::NodeId: std::cmp::Eq + std::hash::Hash, { - let ((simple_block_0, simple_block_1), - initial_compound_partition, - mut node_to_block, - converter) = initialization(graphs); + let ( + (simple_block_0, simple_block_1), + initial_compound_partition, + mut node_to_block, + converter, + ) = initialization(graphs); let mut queue: CompoundPartition = initial_compound_partition; let mut all_simple_blocks = vec![simple_block_0, simple_block_1]; loop { - let (smaller_component, simple_splitter_block) = { - let splitter_block = match queue.pop() { - Some(coarse_block) => coarse_block, - None => break, - }; - let mut simple_blocks_in_splitter_block = splitter_block - .simple_blocks_subsets_of_self - .borrow() - .clone(); + let (smaller_component, simple_splitter_block) = { + let splitter_block = match queue.pop() { + Some(coarse_block) => coarse_block, + None => break, + }; + let mut simple_blocks_in_splitter_block = splitter_block + .simple_blocks_subsets_of_self + .borrow() + .clone(); - let smaller_component_index = { - match simple_blocks_in_splitter_block - .iter() - .enumerate() - .min_by(|(_, x), (_, y)| { - (***x) - .borrow() - .block - .len() - .cmp(&(***y).borrow().block.len()) - }) - .map(|(index, _)| index) { - Some(v) => v, - None => {return (None, converter)} - } - }; + let smaller_component_index = { + match simple_blocks_in_splitter_block + .iter() + .enumerate() + .min_by(|(_, x), (_, y)| { + (***x) + .borrow() + .block + .len() + .cmp(&(***y).borrow().block.len()) + }) + .map(|(index, _)| index) + { + Some(v) => v, + None => return (None, converter), + } + }; - let smaller_component = - simple_blocks_in_splitter_block.remove(smaller_component_index); + let smaller_component = simple_blocks_in_splitter_block.remove(smaller_component_index); - let simple_splitter_block_values: Block = splitter_block - .block - .clone() - .iter() - .filter(|x| !(*smaller_component).borrow().block.contains(x)) - .copied() - .collect(); + let simple_splitter_block_values: Block = splitter_block + .block + .clone() + .iter() + .filter(|x| !(*smaller_component).borrow().block.contains(x)) + .copied() + .collect(); - let simple_splitter_block = CompoundBlock { - block: simple_splitter_block_values, + let simple_splitter_block = CompoundBlock { + block: simple_splitter_block_values, - simple_blocks_subsets_of_self: - RefCell::new(simple_blocks_in_splitter_block), - }; - let simple_splitter_block_pointer = Rc::new(simple_splitter_block); + simple_blocks_subsets_of_self: RefCell::new(simple_blocks_in_splitter_block), + }; + let simple_splitter_block_pointer = Rc::new(simple_splitter_block); - if simple_splitter_block_pointer - .simple_blocks_subsets_of_self - .borrow() - .len() - > 1 - { - queue.push(Rc::clone(&simple_splitter_block_pointer)); - } + if simple_splitter_block_pointer + .simple_blocks_subsets_of_self + .borrow() + .len() + > 1 + { + queue.push(Rc::clone(&simple_splitter_block_pointer)); + } - (smaller_component, simple_splitter_block_pointer) - }; - simple_splitter_block - .simple_blocks_subsets_of_self - .borrow() - .iter() - .for_each(|x| { - (*x).borrow_mut().coarse_block_that_supersets_self = - Rc::clone(&simple_splitter_block); - }); + (smaller_component, simple_splitter_block_pointer) + }; + simple_splitter_block + .simple_blocks_subsets_of_self + .borrow() + .iter() + .for_each(|x| { + (*x).borrow_mut().coarse_block_that_supersets_self = + Rc::clone(&simple_splitter_block); + }); - let mut back_edges = - build_backedges(graphs, smaller_component, &converter); + let mut back_edges = build_backedges(graphs, smaller_component, &converter); - let back_edges_group = - group_by_backedges(back_edges.clone(), &node_to_block); - let ((new_simple_blocks, removeable_simple_blocks), - compound_block_that_are_now_compound) = - split_blocks_with_grouped_backedges(back_edges_group, - &mut node_to_block); + let back_edges_group = group_by_backedges(back_edges.clone(), &node_to_block); + let ((new_simple_blocks, removeable_simple_blocks), compound_block_that_are_now_compound) = + split_blocks_with_grouped_backedges(back_edges_group, &mut node_to_block); - all_simple_blocks.extend(new_simple_blocks); - all_simple_blocks.retain( - |x| !removeable_simple_blocks.iter().any(|y| Rc::ptr_eq(x, y)) ); - queue.extend(compound_block_that_are_now_compound); + all_simple_blocks.extend(new_simple_blocks); + all_simple_blocks.retain(|x| !removeable_simple_blocks.iter().any(|y| Rc::ptr_eq(x, y))); + queue.extend(compound_block_that_are_now_compound); - // back edges = E^{-1}(B) - E^{-1}(S-B) - { - let back_edges_splitter_complement = - build_backedges(graphs, - (*simple_splitter_block).clone(), - &converter); + // back edges = E^{-1}(B) - E^{-1}(S-B) + { + let back_edges_splitter_complement = + build_backedges(graphs, (*simple_splitter_block).clone(), &converter); - back_edges_splitter_complement.keys().for_each(|node| { - back_edges.remove(node); - }); - } + back_edges_splitter_complement.keys().for_each(|node| { + back_edges.remove(node); + }); + } - let back_edges_group = group_by_backedges(back_edges, &node_to_block); - let ((new_fine_blocks, removeable_fine_blocks), - coarse_block_that_are_now_compound) = - split_blocks_with_grouped_backedges(back_edges_group, - &mut node_to_block); + let back_edges_group = group_by_backedges(back_edges, &node_to_block); + let ((new_fine_blocks, removeable_fine_blocks), coarse_block_that_are_now_compound) = + split_blocks_with_grouped_backedges(back_edges_group, &mut node_to_block); - all_simple_blocks.extend(new_fine_blocks); - all_simple_blocks.retain( - |x| !removeable_fine_blocks.iter().any(|y| Rc::ptr_eq(x, y)) ); - queue.extend(coarse_block_that_are_now_compound); + all_simple_blocks.extend(new_fine_blocks); + all_simple_blocks.retain(|x| !removeable_fine_blocks.iter().any(|y| Rc::ptr_eq(x, y))); + queue.extend(coarse_block_that_are_now_compound); } - (Some( - all_simple_blocks - .iter() - .map(|x| (**x).borrow().block.clone()) - // remove leaf block when there are no leaves - .filter(|x| !x.is_empty()) - .collect(), - ), converter) + ( + Some( + all_simple_blocks + .iter() + .map(|x| (**x).borrow().block.clone()) + // remove leaf block when there are no leaves + .filter(|x| !x.is_empty()) + .collect(), + ), + converter, + ) } /// Creates a new graph with nodes as signifiers instead of different weights on /// the edges. fn create_modified_graph( graph: &G, - converter_edges: &MyEdgeTranslator + converter_edges: &MyEdgeTranslator, ) -> (petgraph::Graph, HashSet) where G: NodeCount + EdgeCount + IntoEdgeReferences + IntoNodeIdentifiers, G::NodeId: std::cmp::Eq + std::hash::Hash, - G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone + G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone, { let mut new_graph_a: petgraph::Graph<_, u32> = - petgraph::Graph::with_capacity(graph.node_count()*4, - graph.edge_count()*4); + petgraph::Graph::with_capacity(graph.node_count() * 4, graph.edge_count() * 4); let mut association_weight_id = HashMap::new(); let mut original_nodes = HashSet::new(); let mut last_id = 0; for edge in graph.edge_references() { - let source_id = - match association_weight_id.get(&edge.source()) { - Some(id) => *id, - None => { - let id = new_graph_a.add_node(last_id); - original_nodes.insert(last_id); - last_id += 1; - association_weight_id.insert(edge.source(), id); - id - } - }; - let target_id = - match association_weight_id.get(&edge.target()) { - Some(id) => *id, - None => { - let id = new_graph_a.add_node(last_id); - original_nodes.insert(last_id); - last_id += 1; - association_weight_id.insert(edge.target(), id); - id - } - }; - let weight = *converter_edges.get(edge.weight()).unwrap(); + let source_id = match association_weight_id.get(&edge.source()) { + Some(id) => *id, + None => { + let id = new_graph_a.add_node(last_id); + original_nodes.insert(last_id); + last_id += 1; + association_weight_id.insert(edge.source(), id); + id + } + }; + let target_id = match association_weight_id.get(&edge.target()) { + Some(id) => *id, + None => { + let id = new_graph_a.add_node(last_id); + original_nodes.insert(last_id); + last_id += 1; + association_weight_id.insert(edge.target(), id); + id + } + }; + let weight = *converter_edges.get(edge.weight()).unwrap(); - let middle_node_id = new_graph_a.add_node(0); + let middle_node_id = new_graph_a.add_node(0); - new_graph_a.add_edge(source_id, middle_node_id, weight); - new_graph_a.add_edge(middle_node_id, target_id, weight); + new_graph_a.add_edge(source_id, middle_node_id, weight); + new_graph_a.add_edge(middle_node_id, target_id, weight); - - let mut previous = middle_node_id; - for _ in 0..weight { - let path = new_graph_a.add_node(0); - new_graph_a.add_edge(previous, path, weight); - previous = path; - } + let mut previous = middle_node_id; + for _ in 0..weight { + let path = new_graph_a.add_node(0); + new_graph_a.add_edge(previous, path, weight); + previous = path; + } } for node in graph.node_identifiers() { - let mut previous = *association_weight_id.get(&node).unwrap(); - for _ in 0..converter_edges.last_id.last_ids+2 { - let path = new_graph_a.add_node(0); - new_graph_a.add_edge(previous, path, 0); - previous = path; - } + let mut previous = *association_weight_id.get(&node).unwrap(); + for _ in 0..converter_edges.last_id.last_ids + 2 { + let path = new_graph_a.add_node(0); + new_graph_a.add_edge(previous, path, 0); + previous = path; + } } (new_graph_a, original_nodes) @@ -625,9 +588,11 @@ where #[allow(clippy::type_complexity)] fn modify_graph( graph_a: &G, - graph_b: &G -) -> ( (petgraph::Graph, HashSet), - (petgraph::Graph, HashSet), ) + graph_b: &G, +) -> ( + (petgraph::Graph, HashSet), + (petgraph::Graph, HashSet), +) where G: IntoNodeReferences + IntoNeighborsDirected + NodeCount + EdgeCount, G: IntoEdgeReferences, @@ -635,25 +600,24 @@ where G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone, { let converter_edges: MyEdgeTranslator = { - let mut converter_edges = Translator::new(); - let mut labels: HashMap = HashMap::new(); + let mut converter_edges = Translator::new(); + let mut labels: HashMap = HashMap::new(); - for edge in graph_a.edge_references() { - *labels.entry(edge.weight().clone()).or_default() += 1; - } - for edge in graph_b.edge_references() { - *labels.entry(edge.weight().clone()).or_default() += 1; - } - // slight optimization: we reorder the edges such that edges with the - // most occurrences have smaller index - let mut labels: Vec<(G::EdgeWeight, u32)> = - labels.into_iter().collect(); - labels.sort_by(|a, b| b.1.cmp(&a.1)); + for edge in graph_a.edge_references() { + *labels.entry(edge.weight().clone()).or_default() += 1; + } + for edge in graph_b.edge_references() { + *labels.entry(edge.weight().clone()).or_default() += 1; + } + // slight optimization: we reorder the edges such that edges with the + // most occurrences have smaller index + let mut labels: Vec<(G::EdgeWeight, u32)> = labels.into_iter().collect(); + labels.sort_by(|a, b| b.1.cmp(&a.1)); - for (label, _) in labels.into_iter() { - let _ = converter_edges.encode(label); - } - converter_edges + for (label, _) in labels.into_iter() { + let _ = converter_edges.encode(label); + } + converter_edges }; let new_graph_a = create_modified_graph(graph_a, &converter_edges); @@ -662,41 +626,35 @@ where (new_graph_a, new_graph_b) } - /// check if every block contains either no original nodes or nodes from both /// graphs fn check_bisimilarity( val: Vec>, - converter_bisimulated_graph: - &MyNodeTranslator< as GraphBase>::NodeId, 2>, - original_nodes: [HashSet; 2] + converter_bisimulated_graph: &MyNodeTranslator< + as GraphBase>::NodeId, + 2, + >, + original_nodes: [HashSet; 2], ) -> bool where G: IntoEdgeReferences, G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone, { - val.into_iter() - .all( - |el| { - let mut keep_track = [false, false]; - for e in el { - let (_node_id, graph_id) = - converter_bisimulated_graph.decode(&e).unwrap(); - if original_nodes[*graph_id as usize].contains(&e.0) { - keep_track[*graph_id as usize] = true; - } - } - !(keep_track[0] ^ keep_track[1]) - } - ) + val.into_iter().all(|el| { + let mut keep_track = [false, false]; + for e in el { + let (_node_id, graph_id) = converter_bisimulated_graph.decode(&e).unwrap(); + if original_nodes[*graph_id as usize].contains(&e.0) { + keep_track[*graph_id as usize] = true; + } + } + !(keep_track[0] ^ keep_track[1]) + }) } // ----------------------------------------------------------------------------- -pub fn bisimilarity( - graph_a: &G, - graph_b: &G -) -> bool +pub fn bisimilarity(graph_a: &G, graph_b: &G) -> bool where G: IntoNodeReferences + IntoNeighborsDirected + NodeCount + EdgeCount, G: IntoEdgeReferences, @@ -704,64 +662,52 @@ where G::EdgeWeight: std::cmp::Eq + std::hash::Hash + Clone, { if graph_a.node_count() == 0 && graph_b.node_count() == 0 { - return true + return true; } if graph_a.node_count() == 0 || graph_b.node_count() == 0 { - return false + return false; } let ((new_graph_a, original_nodes_a), (new_graph_b, original_nodes_b)) = - modify_graph(graph_a, graph_b); + modify_graph(graph_a, graph_b); - let (result, _converter) = - match maximum_bisimulation(&[&&new_graph_a, &&new_graph_b]) { - (None, _) => { return false }, - (Some(val), converter) => { - (check_bisimilarity::(val, - &converter, - [original_nodes_a, original_nodes_b]), - converter) - - } - }; + let (result, _converter) = match maximum_bisimulation(&[&&new_graph_a, &&new_graph_b]) { + (None, _) => return false, + (Some(val), converter) => ( + check_bisimilarity::(val, &converter, [original_nodes_a, original_nodes_b]), + converter, + ), + }; result } -pub fn bisimilarity_ignore_labels( - graph_a: &G, - graph_b: &G -) -> bool +pub fn bisimilarity_ignore_labels(graph_a: &G, graph_b: &G) -> bool where G: IntoNodeReferences + IntoNeighborsDirected + NodeCount, - G::NodeId: std::cmp::Eq + std::hash::Hash + G::NodeId: std::cmp::Eq + std::hash::Hash, { if graph_a.node_count() == 0 && graph_b.node_count() == 0 { - return true + return true; } if graph_a.node_count() == 0 || graph_b.node_count() == 0 { - return false + return false; } - let (result, _converter) = - match maximum_bisimulation(&[graph_a, graph_b]) { - (None, _) => { return false }, - (Some(val), converter) => { - (val.into_iter() - .find( - |el| { - let mut keep_track = [false, false]; - for e in el { - let (_node_id, graph_id) = - converter.decode(e).unwrap(); - keep_track[*graph_id as usize] = true; - } - !keep_track[0] || !keep_track[1] - } - ), converter) - - } - }; + let (result, _converter) = match maximum_bisimulation(&[graph_a, graph_b]) { + (None, _) => return false, + (Some(val), converter) => ( + val.into_iter().find(|el| { + let mut keep_track = [false, false]; + for e in el { + let (_node_id, graph_id) = converter.decode(e).unwrap(); + keep_track[*graph_id as usize] = true; + } + !keep_track[0] || !keep_track[1] + }), + converter, + ), + }; result.is_none() } diff --git a/src/rsprocess/bisimilarity/test_paige_tarjan.rs b/src/rsprocess/bisimilarity/test_paige_tarjan.rs index 905cc6c..6d11437 100644 --- a/src/rsprocess/bisimilarity/test_paige_tarjan.rs +++ b/src/rsprocess/bisimilarity/test_paige_tarjan.rs @@ -1,5 +1,4 @@ -use super::bisimilarity_paige_tarkan::{bisimilarity, - bisimilarity_ignore_labels}; +use super::bisimilarity_paige_tarkan::{bisimilarity, bisimilarity_ignore_labels}; #[test] fn identity_paige_tarjan() { diff --git a/src/rsprocess/choices.rs b/src/rsprocess/choices.rs index 293c50d..4690a6e 100644 --- a/src/rsprocess/choices.rs +++ b/src/rsprocess/choices.rs @@ -3,10 +3,12 @@ use std::rc::Rc; use super::process::{BasicProcess, PositiveProcess, Process}; use super::set::{BasicSet, PositiveSet, Set}; -use super::translator::{Translator, PrintableWithTranslator, Formatter}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; pub trait BasicChoices -where Self: Clone + Debug + Default + IntoIterator + PrintableWithTranslator { +where + Self: Clone + Debug + Default + IntoIterator + PrintableWithTranslator, +{ type Process: BasicProcess; fn append(&mut self, other: &mut Self); @@ -25,44 +27,44 @@ impl BasicChoices for Choices { type Process = Process; fn append(&mut self, a: &mut Self) { - self.context_moves.append(&mut a.context_moves); + self.context_moves.append(&mut a.context_moves); } fn replace(&mut self, a: Rc) { - self.context_moves = self - .context_moves - .iter_mut() - .map(|(c1, _)| (Rc::clone(c1), Rc::clone(&a))) - .collect::>(); + self.context_moves = self + .context_moves + .iter_mut() + .map(|(c1, _)| (Rc::clone(c1), Rc::clone(&a))) + .collect::>(); } fn shuffle(&mut self, choices: Self) { - match ( - self.context_moves.is_empty(), - choices.context_moves.is_empty(), - ) { - (true, true) => {} - (true, false) => self.context_moves = choices.context_moves, - (false, true) => {} - (false, false) => { - let mut new_self = vec![]; - for item_self in &self.context_moves { - for item_choices in &choices.context_moves { - new_self.push(( - Rc::new(item_self.0.union(&item_choices.0)), - Rc::new(item_self.1.concat(&item_choices.1)), - )); - } - } - self.context_moves = new_self; - } - } + match ( + self.context_moves.is_empty(), + choices.context_moves.is_empty(), + ) { + (true, true) => {} + (true, false) => self.context_moves = choices.context_moves, + (false, true) => {} + (false, false) => { + let mut new_self = vec![]; + for item_self in &self.context_moves { + for item_choices in &choices.context_moves { + new_self.push(( + Rc::new(item_self.0.union(&item_choices.0)), + Rc::new(item_self.1.concat(&item_choices.1)), + )); + } + } + self.context_moves = new_self; + } + } } } impl Choices { fn iter(&self) -> std::slice::Iter<'_, (Rc, Rc)> { - self.context_moves.iter() + self.context_moves.iter() } } @@ -71,55 +73,54 @@ impl IntoIterator for Choices { type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.context_moves.into_iter() + self.context_moves.into_iter() } } impl From<[(Rc, Rc); N]> for Choices { fn from(arr: [(Rc, Rc); N]) -> Self { - Choices { - context_moves: arr.to_vec(), - } + Choices { + context_moves: arr.to_vec(), + } } } impl From<&[(Rc, Rc)]> for Choices { fn from(arr: &[(Rc, Rc)]) -> Self { - Choices { - context_moves: arr.to_vec(), - } + Choices { + context_moves: arr.to_vec(), + } } } impl From, Rc)>> for Choices { fn from(arr: Vec<(Rc, Rc)>) -> Self { - Choices { context_moves: arr } + Choices { context_moves: arr } } } impl PrintableWithTranslator for Choices { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!(f, "[")?; - let mut it = self.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!( - f, - "[set: {}, process: {}]", - Formatter::from(translator, &*el.0), - Formatter::from(translator, &*el.1) - )?; - } else { - write!( - f, - "[set: {}, process: {}], ", - Formatter::from(translator, &*el.0), - Formatter::from(translator, &*el.1) - )?; - } - } - write!(f, "]") + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!(f, "[")?; + let mut it = self.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!( + f, + "[set: {}, process: {}]", + Formatter::from(translator, &*el.0), + Formatter::from(translator, &*el.1) + )?; + } else { + write!( + f, + "[set: {}, process: {}], ", + Formatter::from(translator, &*el.0), + Formatter::from(translator, &*el.1) + )?; + } + } + write!(f, "]") } } @@ -134,38 +135,38 @@ impl BasicChoices for PositiveChoices { type Process = PositiveProcess; fn append(&mut self, a: &mut Self) { - self.context_moves.append(&mut a.context_moves); + self.context_moves.append(&mut a.context_moves); } fn replace(&mut self, a: Rc) { - self.context_moves = self - .context_moves - .iter_mut() - .map(|(c1, _)| (Rc::clone(c1), Rc::clone(&a))) - .collect::>(); + self.context_moves = self + .context_moves + .iter_mut() + .map(|(c1, _)| (Rc::clone(c1), Rc::clone(&a))) + .collect::>(); } fn shuffle(&mut self, choices: Self) { - match ( - self.context_moves.is_empty(), - choices.context_moves.is_empty(), - ) { - (true, true) => {} - (true, false) => self.context_moves = choices.context_moves, - (false, true) => {} - (false, false) => { - let mut new_self = vec![]; - for item_self in &self.context_moves { - for item_choices in &choices.context_moves { - new_self.push(( - Rc::new(item_self.0.union(&item_choices.0)), - Rc::new(item_self.1.concat(&item_choices.1)), - )); - } - } - self.context_moves = new_self; - } - } + match ( + self.context_moves.is_empty(), + choices.context_moves.is_empty(), + ) { + (true, true) => {} + (true, false) => self.context_moves = choices.context_moves, + (false, true) => {} + (false, false) => { + let mut new_self = vec![]; + for item_self in &self.context_moves { + for item_choices in &choices.context_moves { + new_self.push(( + Rc::new(item_self.0.union(&item_choices.0)), + Rc::new(item_self.1.concat(&item_choices.1)), + )); + } + } + self.context_moves = new_self; + } + } } } @@ -174,57 +175,59 @@ impl IntoIterator for PositiveChoices { type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.context_moves.into_iter() + self.context_moves.into_iter() } } impl PrintableWithTranslator for PositiveChoices { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!(f, "[")?; - let mut it = self.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!( - f, - "[set: {}, process: {}]", - Formatter::from(translator, &*el.0), - Formatter::from(translator, &*el.1) - )?; - } else { - write!( - f, - "[set: {}, process: {}], ", - Formatter::from(translator, &*el.0), - Formatter::from(translator, &*el.1) - )?; - } - } - write!(f, "]") + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!(f, "[")?; + let mut it = self.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!( + f, + "[set: {}, process: {}]", + Formatter::from(translator, &*el.0), + Formatter::from(translator, &*el.1) + )?; + } else { + write!( + f, + "[set: {}, process: {}], ", + Formatter::from(translator, &*el.0), + Formatter::from(translator, &*el.1) + )?; + } + } + write!(f, "]") } } impl PositiveChoices { - fn iter(&self) - -> std::slice::Iter<'_, (Rc, Rc)> { - self.context_moves.iter() + fn iter(&self) -> std::slice::Iter<'_, (Rc, Rc)> { + self.context_moves.iter() } } impl From<[(Rc, Rc); N]> for PositiveChoices { fn from(arr: [(Rc, Rc); N]) -> Self { - Self { context_moves: arr.to_vec() } + Self { + context_moves: arr.to_vec(), + } } } impl From<&[(Rc, Rc)]> for PositiveChoices { fn from(arr: &[(Rc, Rc)]) -> Self { - Self { context_moves: arr.to_vec() } + Self { + context_moves: arr.to_vec(), + } } } impl From, Rc)>> for PositiveChoices { fn from(arr: Vec<(Rc, Rc)>) -> Self { - Self { context_moves: arr } + Self { context_moves: arr } } } diff --git a/src/rsprocess/dot.rs b/src/rsprocess/dot.rs index 1f30625..7606dbe 100644 --- a/src/rsprocess/dot.rs +++ b/src/rsprocess/dot.rs @@ -4,17 +4,10 @@ static PRINTNAMES: bool = false; use core::fmt::{self, Display, Write}; -use petgraph:: -{ +use petgraph::{ data::DataMap, - visit::{ - EdgeRef, - GraphProp, - IntoEdgeReferences, - IntoNodeReferences, - NodeIndexable, - NodeRef, -}}; + visit::{EdgeRef, GraphProp, IntoEdgeReferences, IntoNodeReferences, NodeIndexable, NodeRef}, +}; pub struct Dot<'a, G> where @@ -37,40 +30,40 @@ where /// Create a `Dot` formatting wrapper with default configuration. #[inline] pub fn new(graph: G) -> Self { - Dot { - graph, - get_edge_attributes: &|_, _| String::new(), - get_node_attributes: &|_, _| String::new(), - config: Configs::default(), - } + Dot { + graph, + get_edge_attributes: &|_, _| String::new(), + get_node_attributes: &|_, _| String::new(), + config: Configs::default(), + } } /// Create a `Dot` formatting wrapper with custom configuration. #[inline] pub fn with_config(graph: G, config: &'a [Config]) -> Self { - let config = Configs::extract(config); - Dot { - graph, - get_edge_attributes: &|_, _| String::new(), - get_node_attributes: &|_, _| String::new(), - config, - } + let config = Configs::extract(config); + Dot { + graph, + get_edge_attributes: &|_, _| String::new(), + get_node_attributes: &|_, _| String::new(), + config, + } } #[inline] pub fn with_attr_getters( - graph: G, - config: &'a [Config], - get_edge_attributes: &'a dyn Fn(G, G::EdgeRef) -> String, - get_node_attributes: &'a dyn Fn(G, G::NodeRef) -> String, + graph: G, + config: &'a [Config], + get_edge_attributes: &'a dyn Fn(G, G::EdgeRef) -> String, + get_node_attributes: &'a dyn Fn(G, G::NodeRef) -> String, ) -> Self { - let config = Configs::extract(config); - Dot { - graph, - get_edge_attributes, - get_node_attributes, - config, - } + let config = Configs::extract(config); + Dot { + graph, + get_edge_attributes, + get_node_attributes, + config, + } } } @@ -93,24 +86,28 @@ pub enum RankDir { #[derive(Debug, Clone, PartialEq, Eq)] pub struct NodeStyle { shape: String, - style: String + style: String, } impl Default for NodeStyle { fn default() -> Self { - NodeStyle { shape: "box".to_string(), - style: "filled, rounded".to_string() } + NodeStyle { + shape: "box".to_string(), + style: "filled, rounded".to_string(), + } } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct EdgeStyle { - arrowhead: String + arrowhead: String, } impl Default for EdgeStyle { fn default() -> Self { - EdgeStyle { arrowhead: "vee".to_string() } + EdgeStyle { + arrowhead: "vee".to_string(), + } } } @@ -171,86 +168,82 @@ impl Dot<'_, G> where G: IntoNodeReferences + IntoEdgeReferences + NodeIndexable + GraphProp + DataMap, { - fn graph_fmt( - &self, - f: &mut fmt::Formatter, - node_fmt: NF, - edge_fmt: EF - ) -> fmt::Result + fn graph_fmt(&self, f: &mut fmt::Formatter, node_fmt: NF, edge_fmt: EF) -> fmt::Result where - NF: Fn(&G::NodeWeight, &mut fmt::Formatter) -> fmt::Result, - EF: Fn(&G::EdgeWeight, &mut fmt::Formatter) -> fmt::Result, + NF: Fn(&G::NodeWeight, &mut fmt::Formatter) -> fmt::Result, + EF: Fn(&G::EdgeWeight, &mut fmt::Formatter) -> fmt::Result, { - let g = self.graph; - writeln!(f, "{} {{", TYPE[g.is_directed() as usize])?; + let g = self.graph; + writeln!(f, "{} {{", TYPE[g.is_directed() as usize])?; - if let Some(rank_dir) = &self.config.RankDir { - let value = match rank_dir { - RankDir::TB => "TB", - RankDir::BT => "BT", - RankDir::LR => "LR", - RankDir::RL => "RL", - }; - writeln!(f, "{INDENT}rankdir=\"{value}\"\n")?; - } + if let Some(rank_dir) = &self.config.RankDir { + let value = match rank_dir { + RankDir::TB => "TB", + RankDir::BT => "BT", + RankDir::LR => "LR", + RankDir::RL => "RL", + }; + writeln!(f, "{INDENT}rankdir=\"{value}\"\n")?; + } - if let Some(style) = &self.config.NodeStyle { - writeln!(f, - "{INDENT}node [shape=\"{}\", style=\"{}\"]", - style.shape, - style.style)?; - } + if let Some(style) = &self.config.NodeStyle { + writeln!( + f, + "{INDENT}node [shape=\"{}\", style=\"{}\"]", + style.shape, style.style + )?; + } - if let Some(style) = &self.config.EdgeStyle { - writeln!(f, "{INDENT}edge [arrowhead=\"{}\"]\n", style.arrowhead)?; - } + if let Some(style) = &self.config.EdgeStyle { + writeln!(f, "{INDENT}edge [arrowhead=\"{}\"]\n", style.arrowhead)?; + } - // output all labels - for node in g.node_references() { - if PRINTNAMES { - write!(f, "{INDENT}\"")?; - Escaped(FnFmt(node.weight(), &node_fmt)).fmt(f)?; - write!(f, "\" [ ")?; - } else { - write!(f, "{INDENT}")?; - write!(f, "{}", g.to_index(node.id()))?; - write!(f, " [ ")?; - } + // output all labels + for node in g.node_references() { + if PRINTNAMES { + write!(f, "{INDENT}\"")?; + Escaped(FnFmt(node.weight(), &node_fmt)).fmt(f)?; + write!(f, "\" [ ")?; + } else { + write!(f, "{INDENT}")?; + write!(f, "{}", g.to_index(node.id()))?; + write!(f, " [ ")?; + } - write!(f, "label = \"")?; - Escaped(FnFmt(node.weight(), &node_fmt)).fmt(f)?; - write!(f, "\" ")?; + write!(f, "label = \"")?; + Escaped(FnFmt(node.weight(), &node_fmt)).fmt(f)?; + write!(f, "\" ")?; - writeln!(f, "{}]", (self.get_node_attributes)(g, node))?; - } - // output all edges - for edge in g.edge_references() { - if PRINTNAMES { - write!(f, "{INDENT}\"")?; - let node_source_weight = g.node_weight(edge.source()).unwrap(); - Escaped(FnFmt(node_source_weight, &node_fmt)).fmt(f)?; - write!(f, "\" {} \"", EDGE[g.is_directed() as usize])?; - let node_target_weight = g.node_weight(edge.target()).unwrap(); - Escaped(FnFmt(node_target_weight, &node_fmt)).fmt(f)?; - write!(f, "\" [ ")?; - } else { - write!(f, "{INDENT}")?; - write!(f, "{} ", g.to_index(edge.source()))?; - write!(f, "{} ", EDGE[g.is_directed() as usize])?; - write!(f, "{} ", g.to_index(edge.target()))?; - write!(f, "[ ")?; - } + writeln!(f, "{}]", (self.get_node_attributes)(g, node))?; + } + // output all edges + for edge in g.edge_references() { + if PRINTNAMES { + write!(f, "{INDENT}\"")?; + let node_source_weight = g.node_weight(edge.source()).unwrap(); + Escaped(FnFmt(node_source_weight, &node_fmt)).fmt(f)?; + write!(f, "\" {} \"", EDGE[g.is_directed() as usize])?; + let node_target_weight = g.node_weight(edge.target()).unwrap(); + Escaped(FnFmt(node_target_weight, &node_fmt)).fmt(f)?; + write!(f, "\" [ ")?; + } else { + write!(f, "{INDENT}")?; + write!(f, "{} ", g.to_index(edge.source()))?; + write!(f, "{} ", EDGE[g.is_directed() as usize])?; + write!(f, "{} ", g.to_index(edge.target()))?; + write!(f, "[ ")?; + } - write!(f, "label = \"")?; - Escaped(FnFmt(edge.weight(), &edge_fmt)).fmt(f)?; - write!(f, "\" ")?; + write!(f, "label = \"")?; + Escaped(FnFmt(edge.weight(), &edge_fmt)).fmt(f)?; + write!(f, "\" ")?; - writeln!(f, "{}]", (self.get_edge_attributes)(g, edge))?; - } + writeln!(f, "{}]", (self.get_edge_attributes)(g, edge))?; + } - writeln!(f, "}}")?; + writeln!(f, "}}")?; - Ok(()) + Ok(()) } } @@ -261,7 +254,7 @@ where G::NodeWeight: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.graph_fmt(f, fmt::Display::fmt, fmt::Display::fmt) + self.graph_fmt(f, fmt::Display::fmt, fmt::Display::fmt) } } @@ -272,7 +265,7 @@ where G::NodeWeight: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.graph_fmt(f, fmt::LowerHex::fmt, fmt::LowerHex::fmt) + self.graph_fmt(f, fmt::LowerHex::fmt, fmt::LowerHex::fmt) } } @@ -283,7 +276,7 @@ where G::NodeWeight: fmt::UpperHex, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.graph_fmt(f, fmt::UpperHex::fmt, fmt::UpperHex::fmt) + self.graph_fmt(f, fmt::UpperHex::fmt, fmt::UpperHex::fmt) } } @@ -294,7 +287,7 @@ where G::NodeWeight: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.graph_fmt(f, fmt::Debug::fmt, fmt::Debug::fmt) + self.graph_fmt(f, fmt::Debug::fmt, fmt::Debug::fmt) } } @@ -306,20 +299,20 @@ where W: fmt::Write, { fn write_str(&mut self, s: &str) -> fmt::Result { - for c in s.chars() { - self.write_char(c)?; - } - Ok(()) + for c in s.chars() { + self.write_char(c)?; + } + Ok(()) } fn write_char(&mut self, c: char) -> fmt::Result { - match c { - '"' | '\\' => self.0.write_char('\\')?, - // \l is for left justified linebreak - '\n' => return self.0.write_str("\\l"), - _ => {} - } - self.0.write_char(c) + match c { + '"' | '\\' => self.0.write_char('\\')?, + // \l is for left justified linebreak + '\n' => return self.0.write_str("\\l"), + _ => {} + } + self.0.write_char(c) } } @@ -331,11 +324,11 @@ where T: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if f.alternate() { - writeln!(&mut Escaper(f), "{:#}", &self.0) - } else { - write!(&mut Escaper(f), "{}", &self.0) - } + if f.alternate() { + writeln!(&mut Escaper(f), "{:#}", &self.0) + } else { + write!(&mut Escaper(f), "{}", &self.0) + } } } @@ -347,6 +340,6 @@ where F: Fn(&'a T, &mut fmt::Formatter<'_>) -> fmt::Result, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.1(self.0, f) + self.1(self.0, f) } } diff --git a/src/rsprocess/element.rs b/src/rsprocess/element.rs index a8bf568..c3769aa 100644 --- a/src/rsprocess/element.rs +++ b/src/rsprocess/element.rs @@ -1,4 +1,4 @@ -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use std::fmt; use super::translator::PrintableWithTranslator; @@ -6,11 +6,16 @@ use super::translator::PrintableWithTranslator; pub type IdType = u32; impl PrintableWithTranslator for IdType { - fn print(&self, - f: &mut fmt::Formatter, - translator: &super::translator::Translator + fn print( + &self, + f: &mut fmt::Formatter, + translator: &super::translator::Translator, ) -> fmt::Result { - write!(f, "{}", translator.decode(*self).unwrap_or("Missing".into())) + write!( + f, + "{}", + translator.decode(*self).unwrap_or("Missing".into()) + ) } } @@ -19,15 +24,15 @@ impl PrintableWithTranslator for IdType { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum IdState { Positive, - Negative + Negative, } impl fmt::Display for IdState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Positive => write!(f, "+"), - Self::Negative => write!(f, "-") - } + match self { + Self::Positive => write!(f, "+"), + Self::Negative => write!(f, "-"), + } } } @@ -35,28 +40,30 @@ impl std::ops::Not for IdState { type Output = Self; fn not(self) -> Self::Output { - match self { - Self::Positive => Self::Negative, - Self::Negative => Self::Positive - } + match self { + Self::Positive => Self::Negative, + Self::Negative => Self::Positive, + } } } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct PositiveType { pub id: IdType, - pub state: IdState + pub state: IdState, } impl PrintableWithTranslator for PositiveType { - fn print(&self, - f: &mut fmt::Formatter, - translator: &super::translator::Translator) - -> std::fmt::Result { - write!(f, - "{}{}", - self.state, - translator.decode(self.id).unwrap_or("Missing".into()) - ) + fn print( + &self, + f: &mut fmt::Formatter, + translator: &super::translator::Translator, + ) -> std::fmt::Result { + write!( + f, + "{}{}", + self.state, + translator.decode(self.id).unwrap_or("Missing".into()) + ) } } diff --git a/src/rsprocess/environment.rs b/src/rsprocess/environment.rs index 817a00f..825b2fe 100644 --- a/src/rsprocess/environment.rs +++ b/src/rsprocess/environment.rs @@ -5,15 +5,17 @@ use std::fmt::Debug; use std::rc::Rc; use super::choices::{BasicChoices, Choices, PositiveChoices}; +use super::element::IdType; use super::process::{BasicProcess, PositiveProcess, Process}; use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction}; use super::set::{BasicSet, PositiveSet, Set}; -use super::element::IdType; -use super::translator::{Translator, PrintableWithTranslator, Formatter}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; pub trait BasicEnvironment -where Self: Clone + Debug + Default + Serialize + PrintableWithTranslator, -for<'a> Self: Deserialize<'a> { +where + Self: Clone + Debug + Default + Serialize + PrintableWithTranslator, + for<'a> Self: Deserialize<'a>, +{ type Id; type Set: BasicSet; type Choices: BasicChoices; @@ -23,25 +25,24 @@ for<'a> Self: Deserialize<'a> { fn get(&self, k: Self::Id) -> Option<&Self::Process>; fn all_elements(&self) -> Self::Set; fn unfold( - &self, - context: &Self::Process, - entities: &Self::Set, + &self, + context: &Self::Process, + entities: &Self::Set, ) -> Result; } pub trait ExtensionsEnvironment: BasicEnvironment { - fn iter( - &self - ) -> <&Self as IntoIterator>::IntoIter - where for<'b> &'b Self: IntoIterator; + fn iter(&self) -> <&Self as IntoIterator>::IntoIter + where + for<'b> &'b Self: IntoIterator; } impl ExtensionsEnvironment for T { - fn iter( - &self - ) -> <&Self as IntoIterator>::IntoIter - where for<'b> &'b Self: IntoIterator { - self.into_iter() + fn iter(&self) -> <&Self as IntoIterator>::IntoIter + where + for<'b> &'b Self: IntoIterator, + { + self.into_iter() } } @@ -52,50 +53,50 @@ impl ExtensionsEnvironment for T { pub trait LoopEnvironment: BasicEnvironment { #[allow(clippy::type_complexity)] fn lollipops_decomposed( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, ) -> Vec<(Vec, Vec)>; fn lollipops_prefix_len_loop_decomposed( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, ) -> Vec<(usize, Vec)>; fn lollipops_only_loop_decomposed( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, ) -> Vec>; #[allow(clippy::type_complexity)] fn lollipops_decomposed_named( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, - symb: Self::Id, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, ) -> Option<(Vec, Vec)>; fn lollipops_prefix_len_loop_decomposed_named( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, - symb: Self::Id, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, ) -> Option<(usize, Vec)>; fn lollipops_only_loop_decomposed_named( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, - symb: Self::Id, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, ) -> Option>; } - impl LoopEnvironment for T -where for<'a> &'a T: IntoIterator, - T::Id: Eq +where + for<'a> &'a T: IntoIterator, + T::Id: Eq, { /// A special case of systems is when the context recursively provides /// always the same set of entities. The corresponding computation is @@ -107,57 +108,46 @@ where for<'a> &'a T: IntoIterator, /// the Loops sequences of entities. /// see lollipop fn lollipops_decomposed( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, ) -> Vec<(Vec, Vec)> { - // FIXME: i think we are only interested in "x", not all symbols that - // satisfy X = pre(Q, rec(X)) - let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0)); + // FIXME: i think we are only interested in "x", not all symbols that + // satisfy X = pre(Q, rec(X)) + let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0)); - let find_loop_fn = - |q| T::Reaction::find_loop(reaction_rules, - available_entities.clone(), - q); + let find_loop_fn = + |q| T::Reaction::find_loop(reaction_rules, available_entities.clone(), q); - filtered.map(find_loop_fn).collect::>() + filtered.map(find_loop_fn).collect::>() } - fn lollipops_prefix_len_loop_decomposed( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, ) -> Vec<(usize, Vec)> { - let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0)); + let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0)); - let find_loop_fn = - |q| T::Reaction::find_prefix_len_loop(reaction_rules, - available_entities.clone(), - q); + let find_loop_fn = + |q| T::Reaction::find_prefix_len_loop(reaction_rules, available_entities.clone(), q); - filtered.map(find_loop_fn).collect::>() + filtered.map(find_loop_fn).collect::>() } - /// see loop fn lollipops_only_loop_decomposed( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, ) -> Vec> { - let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0)); + let filtered = self.iter().filter_map(|l| l.1.filter_delta(l.0)); - let find_loop_fn = - |q| T::Reaction::find_only_loop(reaction_rules, - available_entities, - q); + let find_loop_fn = |q| T::Reaction::find_only_loop(reaction_rules, available_entities, q); - filtered.map(find_loop_fn).collect::>() + filtered.map(find_loop_fn).collect::>() } - - /// A special case of systems is when the context recursively provides /// always the same set of entities. The corresponding computation is /// infinite. It consists of a finite sequence of states followed by a @@ -168,88 +158,75 @@ where for<'a> &'a T: IntoIterator, /// the Loops sequences of entities. /// see lollipop fn lollipops_decomposed_named( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, - symb: Self::Id, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, ) -> Option<(Vec, Vec)> { - let filtered = self - .iter() - .filter_map( - |l| - if *l.0 == symb { - l.1.filter_delta(&symb) - } else { - None - } - ) - .next(); + let filtered = self + .iter() + .filter_map(|l| { + if *l.0 == symb { + l.1.filter_delta(&symb) + } else { + None + } + }) + .next(); - let find_loop_fn = |q| T::Reaction::find_loop(reaction_rules, - available_entities.clone(), - q); + let find_loop_fn = + |q| T::Reaction::find_loop(reaction_rules, available_entities.clone(), q); - filtered.map(find_loop_fn) + filtered.map(find_loop_fn) } - - fn lollipops_prefix_len_loop_decomposed_named( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, - symb: Self::Id, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, ) -> Option<(usize, Vec)> { - let filtered = self - .iter() - .filter_map( - |l| - if *l.0 == symb { - l.1.filter_delta(&symb) - } else { - None - } - ) - .next(); + let filtered = self + .iter() + .filter_map(|l| { + if *l.0 == symb { + l.1.filter_delta(&symb) + } else { + None + } + }) + .next(); - let find_loop_fn = |q| - T::Reaction::find_prefix_len_loop(reaction_rules, - available_entities.clone(), - q); + let find_loop_fn = + |q| T::Reaction::find_prefix_len_loop(reaction_rules, available_entities.clone(), q); - filtered.map(find_loop_fn) + filtered.map(find_loop_fn) } - /// see loop fn lollipops_only_loop_decomposed_named( - &self, - reaction_rules: &[Self::Reaction], - available_entities: &Self::Set, - symb: Self::Id, + &self, + reaction_rules: &[Self::Reaction], + available_entities: &Self::Set, + symb: Self::Id, ) -> Option> { - let filtered = self - .iter() - .filter_map( - |l| - if *l.0 == symb { - l.1.filter_delta(&symb) - } else { - None - } - ) - .next(); + let filtered = self + .iter() + .filter_map(|l| { + if *l.0 == symb { + l.1.filter_delta(&symb) + } else { + None + } + }) + .next(); - let find_loop_fn = - |q| T::Reaction::find_only_loop(reaction_rules, - available_entities, - q); + let find_loop_fn = |q| T::Reaction::find_only_loop(reaction_rules, available_entities, q); - filtered.map(find_loop_fn) + filtered.map(find_loop_fn) } } - // ----------------------------------------------------------------------------- #[derive(Clone, Debug, Default, Serialize, Deserialize)] @@ -265,127 +242,131 @@ impl BasicEnvironment for Environment { type Reaction = Reaction; fn get(&self, k: IdType) -> Option<&Process> { - self.definitions.get(&k) + self.definitions.get(&k) } fn all_elements(&self) -> Set { - let mut acc = Set::default(); - for (_, process) in self.definitions.iter() { - acc.push(&process.all_elements()); - } - acc + let mut acc = Set::default(); + for (_, process) in self.definitions.iter() { + acc.push(&process.all_elements()); + } + acc } /// unfold returns the list of choices for the context given the process /// definitions environment. choices::Choices is a list of context moves /// mapping a set of entities and the continuation. /// see unfold - fn unfold( - &self, - context_process: &Process, - current_entities: &Set, - ) -> Result { - match context_process { - Process::Nill => { - Ok(Choices::default()) - }, - Process::RecursiveIdentifier { identifier } => { - let newprocess = self.get(*identifier); - if let Some(newprocess) = newprocess { - self.unfold(newprocess, current_entities) - } else { - Err(format!("Missing symbol in context: {identifier}")) - } - } - Process::EntitySet { entities, next_process, } => { - Ok(Choices::from([( - Rc::new(entities.clone()), - Rc::clone(next_process), - )])) - }, - Process::Guarded { reaction, next_process } => { - if reaction.enabled(current_entities) { - Ok(Choices::from([(Rc::new(reaction.products.clone()), - Rc::clone(next_process))])) - } else { - Ok(Choices::default()) - } - } - Process::WaitEntity { repeat, repeated_process: _, next_process, } - if *repeat <= 0 => { - self.unfold(next_process, current_entities) - }, - Process::WaitEntity { repeat, repeated_process, next_process, } - if *repeat == 1 => { - let mut choices1 = self.unfold(repeated_process, - current_entities)?; - choices1.replace(Rc::clone(next_process)); - Ok(choices1) - } - Process::WaitEntity { repeat, repeated_process, next_process, } => - { - let mut choices1 = self.unfold(repeated_process, - current_entities)?; - choices1.replace(Rc::new(Process::WaitEntity { - repeat: (*repeat - 1), - repeated_process: Rc::clone(repeated_process), - next_process: Rc::clone(next_process), - })); - Ok(choices1) - } - Process::Summation { children } => { - // short-circuits with try_fold. - children.iter().try_fold(Choices::default(), |mut acc, x| { - match self.unfold(x, current_entities) { - Ok(mut choices) => { - acc.append(&mut choices); - Ok(acc) - } - Err(e) => Err(e), - } - }) - } - Process::NondeterministicChoice { children } => { - // short-circuits with try_fold. - if children.is_empty() { - Ok(Choices::from(vec![( - Rc::new(Set::default()), - Rc::new(Process::Nill), - )])) - } else { - children.iter().try_fold(Choices::default(), |mut acc, x| { - acc.shuffle(self.unfold(x, current_entities)?); - Ok(acc) - }) - } - } - } + fn unfold(&self, context_process: &Process, current_entities: &Set) -> Result { + match context_process { + Process::Nill => Ok(Choices::default()), + Process::RecursiveIdentifier { identifier } => { + let newprocess = self.get(*identifier); + if let Some(newprocess) = newprocess { + self.unfold(newprocess, current_entities) + } else { + Err(format!("Missing symbol in context: {identifier}")) + } + } + Process::EntitySet { + entities, + next_process, + } => Ok(Choices::from([( + Rc::new(entities.clone()), + Rc::clone(next_process), + )])), + Process::Guarded { + reaction, + next_process, + } => { + if reaction.enabled(current_entities) { + Ok(Choices::from([( + Rc::new(reaction.products.clone()), + Rc::clone(next_process), + )])) + } else { + Ok(Choices::default()) + } + } + Process::WaitEntity { + repeat, + repeated_process: _, + next_process, + } if *repeat <= 0 => self.unfold(next_process, current_entities), + Process::WaitEntity { + repeat, + repeated_process, + next_process, + } if *repeat == 1 => { + let mut choices1 = self.unfold(repeated_process, current_entities)?; + choices1.replace(Rc::clone(next_process)); + Ok(choices1) + } + Process::WaitEntity { + repeat, + repeated_process, + next_process, + } => { + let mut choices1 = self.unfold(repeated_process, current_entities)?; + choices1.replace(Rc::new(Process::WaitEntity { + repeat: (*repeat - 1), + repeated_process: Rc::clone(repeated_process), + next_process: Rc::clone(next_process), + })); + Ok(choices1) + } + Process::Summation { children } => { + // short-circuits with try_fold. + children.iter().try_fold(Choices::default(), |mut acc, x| { + match self.unfold(x, current_entities) { + Ok(mut choices) => { + acc.append(&mut choices); + Ok(acc) + } + Err(e) => Err(e), + } + }) + } + Process::NondeterministicChoice { children } => { + // short-circuits with try_fold. + if children.is_empty() { + Ok(Choices::from(vec![( + Rc::new(Set::default()), + Rc::new(Process::Nill), + )])) + } else { + children.iter().try_fold(Choices::default(), |mut acc, x| { + acc.shuffle(self.unfold(x, current_entities)?); + Ok(acc) + }) + } + } + } } } impl PrintableWithTranslator for Environment { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!(f, "{{env:")?; - let mut it = self.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!( - f, - "({} -> {})", - Formatter::from(translator, el.0), - Formatter::from(translator, el.1) - )?; - } else { - write!( - f, - "({} -> {}), ", - Formatter::from(translator, el.0), - Formatter::from(translator, el.1) - )?; - } - } - write!(f, "}}") + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!(f, "{{env:")?; + let mut it = self.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!( + f, + "({} -> {})", + Formatter::from(translator, el.0), + Formatter::from(translator, el.1) + )?; + } else { + write!( + f, + "({} -> {}), ", + Formatter::from(translator, el.0), + Formatter::from(translator, el.1) + )?; + } + } + write!(f, "}}") } } @@ -394,7 +375,7 @@ impl IntoIterator for Environment { type IntoIter = std::collections::hash_map::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.definitions.into_iter() + self.definitions.into_iter() } } @@ -403,35 +384,34 @@ impl<'a> IntoIterator for &'a Environment { type IntoIter = std::collections::hash_map::Iter<'a, IdType, Process>; fn into_iter(self) -> Self::IntoIter { - self.definitions.iter() + self.definitions.iter() } } impl From<[(IdType, Process); N]> for Environment { fn from(arr: [(IdType, Process); N]) -> Self { - Environment { - definitions: HashMap::from(arr), - } + Environment { + definitions: HashMap::from(arr), + } } } impl From<&[(IdType, Process)]> for Environment { fn from(arr: &[(IdType, Process)]) -> Self { - Environment { - definitions: HashMap::from_iter(arr.to_vec()), - } + Environment { + definitions: HashMap::from_iter(arr.to_vec()), + } } } impl From> for Environment { fn from(arr: Vec<(IdType, Process)>) -> Self { - Environment { - definitions: HashMap::from_iter(arr), - } + Environment { + definitions: HashMap::from_iter(arr), + } } } - // ----------------------------------------------------------------------------- // Confluence // ----------------------------------------------------------------------------- @@ -444,32 +424,29 @@ impl Environment { /// loop, its dimension (length) and the loop. /// see confluent, confluents pub fn confluent( - &self, - reaction_rules: &[Reaction], - entities: &[Set], + &self, + reaction_rules: &[Reaction], + entities: &[Set], ) -> Option<(usize, usize, Vec)> { - let all_loops = - self.lollipops_prefix_len_loop_decomposed(reaction_rules, - entities.first()?); - let (prefix_len, hoop) = all_loops.first()?.clone(); - let dimension = hoop.len(); - let mut max_distance = prefix_len; + let all_loops = + self.lollipops_prefix_len_loop_decomposed(reaction_rules, entities.first()?); + let (prefix_len, hoop) = all_loops.first()?.clone(); + let dimension = hoop.len(); + let mut max_distance = prefix_len; - for available_entities in entities.iter().skip(1) { - let all_loops = - self.lollipops_prefix_len_loop_decomposed(reaction_rules, - available_entities); - let (prefix_len, new_hoop) = all_loops.first()?; + for available_entities in entities.iter().skip(1) { + let all_loops = + self.lollipops_prefix_len_loop_decomposed(reaction_rules, available_entities); + let (prefix_len, new_hoop) = all_loops.first()?; - if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { - return None; - } - max_distance = cmp::max(max_distance, *prefix_len); - } - Some((max_distance, dimension, hoop)) + if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { + return None; + } + max_distance = cmp::max(max_distance, *prefix_len); + } + Some((max_distance, dimension, hoop)) } - /// Two set of entities E1 and E2 are confluent w.r.t. the perpetual context Q /// iff they reach the same loop. /// The predicate confluent(Rs,Q,Es,Loop,Distance,Dimension) checks if all the @@ -477,77 +454,71 @@ impl Environment { /// length of prefixes traversed to reached the loop and its dimension (length). /// see confluent, confluents pub fn confluent_named( - &self, - reaction_rules: &[Reaction], - entities: &[Set], - symb: IdType, + &self, + reaction_rules: &[Reaction], + entities: &[Set], + symb: IdType, ) -> Option<(usize, usize, Vec)> { - let (prefix_len, first_hoop) = - self.lollipops_prefix_len_loop_decomposed_named(reaction_rules, - entities.first()?, - symb)?; - let dimension = first_hoop.len(); - let mut max_distance = prefix_len; - let hoop = first_hoop; + let (prefix_len, first_hoop) = self.lollipops_prefix_len_loop_decomposed_named( + reaction_rules, + entities.first()?, + symb, + )?; + let dimension = first_hoop.len(); + let mut max_distance = prefix_len; + let hoop = first_hoop; - for available_entities in entities.iter().skip(1) { - let (prefix_len, new_hoop) = - self.lollipops_prefix_len_loop_decomposed_named( - reaction_rules, - available_entities, - symb, - )?; + for available_entities in entities.iter().skip(1) { + let (prefix_len, new_hoop) = self.lollipops_prefix_len_loop_decomposed_named( + reaction_rules, + available_entities, + symb, + )?; - if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { - return None; - } - max_distance = cmp::max(max_distance, prefix_len); - } - Some((max_distance, dimension, hoop)) + if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { + return None; + } + max_distance = cmp::max(max_distance, prefix_len); + } + Some((max_distance, dimension, hoop)) } - /// invariant_named checks if all the sets of entities in ```entities``` are /// confluent and if so returns the set of all traversed states, together with /// the loop. /// see invariant pub fn invariant_named( - &self, - reaction_rules: &[Reaction], - entities: &[Set], - symb: IdType, + &self, + reaction_rules: &[Reaction], + entities: &[Set], + symb: IdType, ) -> Option<(Vec, Vec)> { - let (prefix, hoop) = - self.lollipops_decomposed_named(reaction_rules, - entities.first()?, - symb)?; - let mut invariant = vec![]; - invariant.append(&mut prefix.clone()); - invariant.append(&mut hoop.clone()); - let dimension = hoop.len(); + let (prefix, hoop) = + self.lollipops_decomposed_named(reaction_rules, entities.first()?, symb)?; + let mut invariant = vec![]; + invariant.append(&mut prefix.clone()); + invariant.append(&mut hoop.clone()); + let dimension = hoop.len(); - for available_entities in entities { - let (new_prefix, new_hoop) = - self.lollipops_decomposed_named(reaction_rules, - available_entities, - symb)?; - if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { - return None; - } - invariant.append(&mut new_prefix.clone()); - } - // remove duplicates, maybe better with sorting? - invariant = invariant - .iter() - .cloned() - .collect::>() - .iter() - .cloned() - .collect::>(); - Some((invariant, hoop)) + for available_entities in entities { + let (new_prefix, new_hoop) = + self.lollipops_decomposed_named(reaction_rules, available_entities, symb)?; + if new_hoop.len() != dimension || !hoop.contains(new_hoop.first()?) { + return None; + } + invariant.append(&mut new_prefix.clone()); + } + // remove duplicates, maybe better with sorting? + invariant = invariant + .iter() + .cloned() + .collect::>() + .iter() + .cloned() + .collect::>(); + Some((invariant, hoop)) } - /// Suppose the context has the form /// Q1. ... Q1.Q2. ... Q2. ... Qn. ... Qn. ... /// and that each context Q1, Q2, ... , Q(n-1) is provided for a large number @@ -561,18 +532,17 @@ impl Environment { /// all Qi's. /// see loop_confluent pub fn loop_confluent_named( - deltas: &[Self], - reaction_rules: &[Reaction], - entities: &[Set], - symb: IdType, + deltas: &[Self], + reaction_rules: &[Reaction], + entities: &[Set], + symb: IdType, ) -> Option)>> { - deltas - .iter() - .map(|q| q.confluent_named(reaction_rules, entities, symb)) - .collect::>>() + deltas + .iter() + .map(|q| q.confluent_named(reaction_rules, entities, symb)) + .collect::>>() } - /// "strong confluence" requires loop confluence and additionally check /// that even if the context is switched BEFORE REACHING THE LOOP for Qi /// the traversed states are still confluent for Q(i+1) @@ -581,21 +551,19 @@ impl Environment { /// see strong_confluent #[allow(clippy::type_complexity)] pub fn strong_confluent_named( - deltas: &[Self], - reaction_rules: &[Reaction], - entities: &[Set], - symb: IdType, + deltas: &[Self], + reaction_rules: &[Reaction], + entities: &[Set], + symb: IdType, ) -> Option, usize, Vec)>> { - deltas - .iter() - .map(|q| { - let (invariant, hoop) = q.invariant_named(reaction_rules, - entities, - symb)?; - let length = invariant.len(); - Some((invariant, length, hoop)) - }) - .collect::>>() + deltas + .iter() + .map(|q| { + let (invariant, hoop) = q.invariant_named(reaction_rules, entities, symb)?; + let length = invariant.len(); + Some((invariant, length, hoop)) + }) + .collect::>>() } // TODO: weak confluence @@ -616,127 +584,135 @@ impl BasicEnvironment for PositiveEnvironment { type Reaction = PositiveReaction; fn get(&self, k: Self::Id) -> Option<&Self::Process> { - self.definitions.get(&k) + self.definitions.get(&k) } fn all_elements(&self) -> Self::Set { - let mut acc = Self::Set::default(); - for (_, process) in self.definitions.iter() { - acc.push(&process.all_elements()); - } - acc + let mut acc = Self::Set::default(); + for (_, process) in self.definitions.iter() { + acc.push(&process.all_elements()); + } + acc } fn unfold( - &self, - context: &Self::Process, - entities: &Self::Set, + &self, + context: &Self::Process, + entities: &Self::Set, ) -> Result { - match context { - PositiveProcess::Nill => { - Ok(Self::Choices::default()) - }, - PositiveProcess::RecursiveIdentifier { identifier } => { - let newprocess = self.get(*identifier); - if let Some(newprocess) = newprocess { - self.unfold(newprocess, entities) - } else { - Err(format!("Missing symbol in context: {identifier}")) - } - } - PositiveProcess::EntitySet { entities, next_process, } => { - Ok(Self::Choices::from([( - Rc::new(entities.clone()), - Rc::clone(next_process), - )])) - }, - PositiveProcess::Guarded { reaction, next_process } => { - if reaction.enabled(entities) { - Ok(Self::Choices::from([(Rc::new(reaction.products.clone()), - Rc::clone(next_process))])) - } else { - Ok(Self::Choices::default()) - } - } - PositiveProcess::WaitEntity { repeat, repeated_process: _, next_process, } - if *repeat <= 0 => { - self.unfold(next_process, entities) - }, - PositiveProcess::WaitEntity { repeat, repeated_process, next_process, } - if *repeat == 1 => { - let mut choices1 = self.unfold(repeated_process, - entities)?; - choices1.replace(Rc::clone(next_process)); - Ok(choices1) - } - PositiveProcess::WaitEntity { repeat, repeated_process, next_process, } => - { - let mut choices1 = self.unfold(repeated_process, - entities)?; - choices1.replace(Rc::new(PositiveProcess::WaitEntity { - repeat: (*repeat - 1), - repeated_process: Rc::clone(repeated_process), - next_process: Rc::clone(next_process), - })); - Ok(choices1) - } - PositiveProcess::Summation { children } => { - // short-circuits with try_fold. - children.iter().try_fold( - Self::Choices::default(), - |mut acc, x| { - match self.unfold(x, entities) { - Ok(mut choices) => { - acc.append(&mut choices); - Ok(acc) - } - Err(e) => Err(e), - } - }) - } - PositiveProcess::NondeterministicChoice { children } => { - // short-circuits with try_fold. - if children.is_empty() { - Ok(Self::Choices::from(vec![( - Rc::new(Self::Set::default()), - Rc::new(Self::Process::default()), - )])) - } else { - children.iter().try_fold( - Self::Choices::default(), - |mut acc, x| { - acc.shuffle(self.unfold(x, entities)?); - Ok(acc) - }) - } - } - } + match context { + PositiveProcess::Nill => Ok(Self::Choices::default()), + PositiveProcess::RecursiveIdentifier { identifier } => { + let newprocess = self.get(*identifier); + if let Some(newprocess) = newprocess { + self.unfold(newprocess, entities) + } else { + Err(format!("Missing symbol in context: {identifier}")) + } + } + PositiveProcess::EntitySet { + entities, + next_process, + } => Ok(Self::Choices::from([( + Rc::new(entities.clone()), + Rc::clone(next_process), + )])), + PositiveProcess::Guarded { + reaction, + next_process, + } => { + if reaction.enabled(entities) { + Ok(Self::Choices::from([( + Rc::new(reaction.products.clone()), + Rc::clone(next_process), + )])) + } else { + Ok(Self::Choices::default()) + } + } + PositiveProcess::WaitEntity { + repeat, + repeated_process: _, + next_process, + } if *repeat <= 0 => self.unfold(next_process, entities), + PositiveProcess::WaitEntity { + repeat, + repeated_process, + next_process, + } if *repeat == 1 => { + let mut choices1 = self.unfold(repeated_process, entities)?; + choices1.replace(Rc::clone(next_process)); + Ok(choices1) + } + PositiveProcess::WaitEntity { + repeat, + repeated_process, + next_process, + } => { + let mut choices1 = self.unfold(repeated_process, entities)?; + choices1.replace(Rc::new(PositiveProcess::WaitEntity { + repeat: (*repeat - 1), + repeated_process: Rc::clone(repeated_process), + next_process: Rc::clone(next_process), + })); + Ok(choices1) + } + PositiveProcess::Summation { children } => { + // short-circuits with try_fold. + children + .iter() + .try_fold(Self::Choices::default(), |mut acc, x| { + match self.unfold(x, entities) { + Ok(mut choices) => { + acc.append(&mut choices); + Ok(acc) + } + Err(e) => Err(e), + } + }) + } + PositiveProcess::NondeterministicChoice { children } => { + // short-circuits with try_fold. + if children.is_empty() { + Ok(Self::Choices::from(vec![( + Rc::new(Self::Set::default()), + Rc::new(Self::Process::default()), + )])) + } else { + children + .iter() + .try_fold(Self::Choices::default(), |mut acc, x| { + acc.shuffle(self.unfold(x, entities)?); + Ok(acc) + }) + } + } + } } } impl PrintableWithTranslator for PositiveEnvironment { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!(f, "{{env:")?; - let mut it = self.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!( - f, - "({} -> {})", - Formatter::from(translator, el.0), - Formatter::from(translator, el.1) - )?; - } else { - write!( - f, - "({} -> {}), ", - Formatter::from(translator, el.0), - Formatter::from(translator, el.1) - )?; - } - } - write!(f, "}}") + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!(f, "{{env:")?; + let mut it = self.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!( + f, + "({} -> {})", + Formatter::from(translator, el.0), + Formatter::from(translator, el.1) + )?; + } else { + write!( + f, + "({} -> {}), ", + Formatter::from(translator, el.0), + Formatter::from(translator, el.1) + )?; + } + } + write!(f, "}}") } } @@ -745,7 +721,7 @@ impl IntoIterator for PositiveEnvironment { type IntoIter = std::collections::hash_map::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.definitions.into_iter() + self.definitions.into_iter() } } @@ -754,24 +730,24 @@ impl<'a> IntoIterator for &'a PositiveEnvironment { type IntoIter = std::collections::hash_map::Iter<'a, IdType, PositiveProcess>; fn into_iter(self) -> Self::IntoIter { - self.definitions.iter() + self.definitions.iter() } } impl From<&Environment> for PositiveEnvironment { fn from(value: &Environment) -> Self { - PositiveEnvironment { - definitions: value - .definitions - .iter() - .map(|(id, proc)| (*id, proc.into())) - .collect::>() - } + PositiveEnvironment { + definitions: value + .definitions + .iter() + .map(|(id, proc)| (*id, proc.into())) + .collect::>(), + } } } impl From for PositiveEnvironment { fn from(value: Environment) -> Self { - (&value).into() + (&value).into() } } diff --git a/src/rsprocess/format_helpers.rs b/src/rsprocess/format_helpers.rs index 43e1700..9f5af71 100644 --- a/src/rsprocess/format_helpers.rs +++ b/src/rsprocess/format_helpers.rs @@ -4,539 +4,471 @@ pub mod graph_map_nodes_ty_from { use super::super::translator; use std::rc::Rc; - type GraphMapNodesFnTy = - dyn Fn(petgraph::prelude::NodeIndex, &System) -> String; + type GraphMapNodesFnTy = dyn Fn(petgraph::prelude::NodeIndex, &System) -> String; - pub fn format_string( - s: String - ) -> Box { - Box::new(move |_, _| s.clone()) + pub fn format_string(s: String) -> Box { + Box::new(move |_, _| s.clone()) } - pub fn format_hide( - _translator: Rc - ) -> Box { - Box::new(|_, _| String::new()) + pub fn format_hide(_translator: Rc) -> Box { + Box::new(|_, _| String::new()) } - pub fn format_entities( - translator: Rc - ) -> Box { - Box::new( - move |_, node: &System| - format!("{}", - translator::Formatter::from(&translator, - &node.available_entities)) - ) + pub fn format_entities(translator: Rc) -> Box { + Box::new(move |_, node: &System| { + format!( + "{}", + translator::Formatter::from(&translator, &node.available_entities) + ) + }) } pub fn format_mask_entities( - translator: Rc, - mask: Set + translator: Rc, + mask: Set, ) -> Box { - Box::new( - move |_, node: &System| { - let masked_entities = - node.available_entities.intersection(&mask); - format!("{}", - translator::Formatter::from(&translator, - &masked_entities)) - } - ) + Box::new(move |_, node: &System| { + let masked_entities = node.available_entities.intersection(&mask); + format!( + "{}", + translator::Formatter::from(&translator, &masked_entities) + ) + }) } pub fn format_exclude_entities( - translator: Rc, - mask: Set + translator: Rc, + mask: Set, ) -> Box { - Box::new( - move |_, node: &System| { - let masked_entities = - node.available_entities.subtraction(&mask); - format!("{}", - translator::Formatter::from(&translator, - &masked_entities)) - } - ) + Box::new(move |_, node: &System| { + let masked_entities = node.available_entities.subtraction(&mask); + format!( + "{}", + translator::Formatter::from(&translator, &masked_entities) + ) + }) } - pub fn format_context( - translator: Rc - ) -> Box { - Box::new( - move |_, node: &System| - format!("{}", - translator::Formatter::from(&translator, - &node.context_process)) - ) + pub fn format_context(translator: Rc) -> Box { + Box::new(move |_, node: &System| { + format!( + "{}", + translator::Formatter::from(&translator, &node.context_process) + ) + }) } } - pub mod graph_map_edges_ty_from { - use super::super::set::{BasicSet, Set}; use super::super::label::Label; + use super::super::set::{BasicSet, Set}; use super::super::translator; use std::rc::Rc; - type GraphMapEdgesFnTy<'a> = - dyn Fn(petgraph::prelude::EdgeIndex, &'a Label) -> String + 'a; + type GraphMapEdgesFnTy<'a> = dyn Fn(petgraph::prelude::EdgeIndex, &'a Label) -> String + 'a; pub fn format_string<'a>( - _translator: Rc, - s: String + _translator: Rc, + s: String, ) -> Box> { - Box::new(move |_, _| s.clone()) + Box::new(move |_, _| s.clone()) } - pub fn format_hide<'a>( - _translator: Rc - ) -> Box> { - Box::new(|_, _| String::new()) + pub fn format_hide<'a>(_translator: Rc) -> Box> { + Box::new(|_, _| String::new()) } macro_rules! create_format_edge { - ( $name:ident, + ( $name:ident, [$edge_name:ident, $mask_name:ident, $common_name:ident], $mask_common:expr, $mask:expr, $common:expr, - $default:expr ) - => - { - pub fn $name<'a>( - translator: Rc, - $mask_name: Option, - $common_name: Option - ) -> Box> { - if let Some($mask_name) = $mask_name { - if let Some($common_name) = $common_name { - Box::new( - move |_, $edge_name: &Label| - format!("{}", - translator::Formatter::from( - &translator, $mask_common - )) - ) - } else { - Box::new( - move |_, $edge_name: &Label| - format!("{}", - translator::Formatter::from( - &translator, $mask - )) - ) - } - } else { - if let Some($common_name) = $common_name { - Box::new( - move |_, $edge_name: &Label| - format!("{}", - translator::Formatter::from( - &translator, $common - )) - ) - } else { - Box::new( - move |_, $edge_name: &Label| - format!("{}", - translator::Formatter::from( - &translator, $default - )) - ) - } - } - } - } + $default:expr ) => { + pub fn $name<'a>( + translator: Rc, + $mask_name: Option, + $common_name: Option, + ) -> Box> { + if let Some($mask_name) = $mask_name { + if let Some($common_name) = $common_name { + Box::new(move |_, $edge_name: &Label| { + format!("{}", translator::Formatter::from(&translator, $mask_common)) + }) + } else { + Box::new(move |_, $edge_name: &Label| { + format!("{}", translator::Formatter::from(&translator, $mask)) + }) + } + } else { + if let Some($common_name) = $common_name { + Box::new(move |_, $edge_name: &Label| { + format!("{}", translator::Formatter::from(&translator, $common)) + }) + } else { + Box::new(move |_, $edge_name: &Label| { + format!("{}", translator::Formatter::from(&translator, $default)) + }) + } + } + } + }; } create_format_edge!( - format_products, - [edge, mask, common], - &mask.intersection(&edge.products).subtraction(&common), - &mask.intersection(&edge.products), - &edge.products.subtraction(&common), - &edge.products + format_products, + [edge, mask, common], + &mask.intersection(&edge.products).subtraction(&common), + &mask.intersection(&edge.products), + &edge.products.subtraction(&common), + &edge.products ); create_format_edge!( - format_entities, - [edge, mask, common], - &mask.intersection(&edge.available_entities).subtraction(&common), - &mask.intersection(&edge.available_entities), - &edge.available_entities.subtraction(&common), - &edge.available_entities + format_entities, + [edge, mask, common], + &mask + .intersection(&edge.available_entities) + .subtraction(&common), + &mask.intersection(&edge.available_entities), + &edge.available_entities.subtraction(&common), + &edge.available_entities ); create_format_edge!( - format_context, - [edge, mask, common], - &mask.intersection(&edge.context).subtraction(&common), - &mask.intersection(&edge.context), - &edge.context.subtraction(&common), - &edge.context + format_context, + [edge, mask, common], + &mask.intersection(&edge.context).subtraction(&common), + &mask.intersection(&edge.context), + &edge.context.subtraction(&common), + &edge.context ); create_format_edge!( - format_union, - [edge, mask, common], - &mask.intersection(&edge.t).subtraction(&common), - &mask.intersection(&edge.t), - &edge.t.subtraction(&common), - &edge.t + format_union, + [edge, mask, common], + &mask.intersection(&edge.t).subtraction(&common), + &mask.intersection(&edge.t), + &edge.t.subtraction(&common), + &edge.t ); create_format_edge!( - format_difference, - [edge, mask, common], - &mask.intersection(&edge.context.subtraction(&edge.available_entities)) - .subtraction(&common), - &mask.intersection(&edge.context.subtraction(&edge.available_entities)), - &edge.context.subtraction(&edge.available_entities).subtraction(&common), - &edge.context.subtraction(&edge.available_entities) + format_difference, + [edge, mask, common], + &mask + .intersection(&edge.context.subtraction(&edge.available_entities)) + .subtraction(&common), + &mask.intersection(&edge.context.subtraction(&edge.available_entities)), + &edge + .context + .subtraction(&edge.available_entities) + .subtraction(&common), + &edge.context.subtraction(&edge.available_entities) ); create_format_edge!( - format_entities_deleted, - [edge, mask, common], - &mask.intersection(&edge.available_entities.subtraction(&edge.products)) - .subtraction(&common), - &mask.intersection(&edge.available_entities.subtraction(&edge.products)), - &edge.available_entities.subtraction(&edge.products).subtraction(&common), - &edge.available_entities.subtraction(&edge.products) + format_entities_deleted, + [edge, mask, common], + &mask + .intersection(&edge.available_entities.subtraction(&edge.products)) + .subtraction(&common), + &mask.intersection(&edge.available_entities.subtraction(&edge.products)), + &edge + .available_entities + .subtraction(&edge.products) + .subtraction(&common), + &edge.available_entities.subtraction(&edge.products) ); create_format_edge!( - format_entities_added, - [edge, mask, common], - &mask.intersection(&edge.products.subtraction(&edge.available_entities)) - .subtraction(&common), - &mask.intersection(&edge.products.subtraction(&edge.available_entities)), - &edge.products.subtraction(&edge.available_entities).subtraction(&common), - &edge.products.subtraction(&edge.available_entities) + format_entities_added, + [edge, mask, common], + &mask + .intersection(&edge.products.subtraction(&edge.available_entities)) + .subtraction(&common), + &mask.intersection(&edge.products.subtraction(&edge.available_entities)), + &edge + .products + .subtraction(&edge.available_entities) + .subtraction(&common), + &edge.products.subtraction(&edge.available_entities) ); } - pub mod node_formatter { - use std::rc::Rc; - use petgraph::{Graph, Directed}; use petgraph::visit::IntoNodeReferences; + use petgraph::{Directed, Graph}; + use std::rc::Rc; use super::super::element::IdType; - use super::super::graph::{SystemGraph, OperationType}; - use super::super::set::Set; + use super::super::graph::{OperationType, SystemGraph}; use super::super::process::Process; - + use super::super::set::Set; type RSdotGraph = Graph; type RSformatNodeTy = - dyn Fn( - &RSdotGraph, - <&RSdotGraph as IntoNodeReferences>::NodeRef - ) -> Option; + dyn Fn(&RSdotGraph, <&RSdotGraph as IntoNodeReferences>::NodeRef) -> Option; pub fn format_nill( - original_graph: Rc, - color: String, - _star: Option, + original_graph: Rc, + color: String, + _star: Option, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - if rssystem.context_process == Process::Nill { - Some(", fillcolor=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if rssystem.context_process == Process::Nill { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) } pub fn format_recursive_identifier( - original_graph: Rc, - color: String, - star: Option, - s: IdType + original_graph: Rc, + color: String, + star: Option, + s: IdType, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - match (Some(s) == star, &rssystem.context_process) { - (true, Process::RecursiveIdentifier { identifier: _ }) - => { - Some(", fillcolor=".to_string() + &color) - }, - (false, Process::RecursiveIdentifier { identifier: id }) - if id == &s => { - Some(", fillcolor=".to_string() + &color) - }, - _ => {None} - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + match (Some(s) == star, &rssystem.context_process) { + (true, Process::RecursiveIdentifier { identifier: _ }) => { + Some(", fillcolor=".to_string() + &color) + } + (false, Process::RecursiveIdentifier { identifier: id }) if id == &s => { + Some(", fillcolor=".to_string() + &color) + } + _ => None, + } + }) } pub fn format_entity_set( - original_graph: Rc, - color: String, - _star: Option, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + _star: Option, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - match &rssystem.context_process { - Process::EntitySet { entities, next_process: _ } - if ot.evaluate(entities, &set) => { - Some(", fillcolor=".to_string() + &color) - }, - _ => {None} - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + match &rssystem.context_process { + Process::EntitySet { + entities, + next_process: _, + } if ot.evaluate(entities, &set) => Some(", fillcolor=".to_string() + &color), + _ => None, + } + }) } - pub fn format_non_deterministic_choice( - original_graph: Rc, - color: String, - _star: Option, + original_graph: Rc, + color: String, + _star: Option, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - if let Process::NondeterministicChoice { children: _ } = - rssystem.context_process - { - Some(", fillcolor=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if let Process::NondeterministicChoice { children: _ } = rssystem.context_process { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) } pub fn format_summation( - original_graph: Rc, - color: String, - _star: Option, + original_graph: Rc, + color: String, + _star: Option, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - if let Process::Summation { children: _ } = - rssystem.context_process - { - Some(", fillcolor=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if let Process::Summation { children: _ } = rssystem.context_process { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) } - pub fn format_wait_entity( - original_graph: Rc, - color: String, - _star: Option, + original_graph: Rc, + color: String, + _star: Option, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - if let Process::WaitEntity { repeat: _, - repeated_process: _, - next_process: _ } = - &rssystem.context_process - { - Some(", fillcolor=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if let Process::WaitEntity { + repeat: _, + repeated_process: _, + next_process: _, + } = &rssystem.context_process + { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) } pub fn format_entities_conditional( - original_graph: Rc, - color: String, - _star: Option, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + _star: Option, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, n| { - let rssystem = original_graph.node_weight(n.0).unwrap(); - if ot.evaluate(&rssystem.available_entities, &set) { - Some(", fillcolor=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if ot.evaluate(&rssystem.available_entities, &set) { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) } } pub mod edge_formatter { + use petgraph::visit::{EdgeRef, IntoEdgeReferences}; + use petgraph::{Directed, Graph}; use std::rc::Rc; - use petgraph::{Graph, Directed}; - use petgraph::visit::{IntoEdgeReferences, EdgeRef}; - use super::super::graph::{SystemGraph, OperationType}; + use super::super::graph::{OperationType, SystemGraph}; use super::super::set::Set; - type RSdotGraph = Graph; type RSformatEdgeTy = - dyn Fn( - &RSdotGraph, - <&RSdotGraph as IntoEdgeReferences>::EdgeRef - ) -> Option; - + dyn Fn(&RSdotGraph, <&RSdotGraph as IntoEdgeReferences>::EdgeRef) -> Option; pub fn format_entities( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.available_entities, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.available_entities, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_context( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.context, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.context, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_t( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.t, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.t, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_reactants( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.reactants, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.reactants, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_reactants_absent( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.reactants_absent, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.reactants_absent, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_inhibitors( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.inhibitors, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.inhibitors, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_inhibitors_present( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.inhibitors_present, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.inhibitors_present, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } pub fn format_products( - original_graph: Rc, - color: String, - ot: OperationType, - set: Set + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, ) -> Box { - Box::new( - move |_, e| { - let rssystem = original_graph.edge_weight(e.id()).unwrap(); - if ot.evaluate(&rssystem.products, &set) { - Some(", color=".to_string() + &color) - } else { - None - } - } - ) + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate(&rssystem.products, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) } } diff --git a/src/rsprocess/frequency.rs b/src/rsprocess/frequency.rs index 9409f89..447167e 100644 --- a/src/rsprocess/frequency.rs +++ b/src/rsprocess/frequency.rs @@ -8,32 +8,31 @@ use super::environment::{BasicEnvironment, Environment, PositiveEnvironment}; use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction}; use super::set::{BasicSet, ExtensionsSet, PositiveSet, Set}; use super::system::{BasicSystem, ExtensionsSystem, LoopSystem, PositiveSystem, System}; -use super::translator::{Translator, PrintableWithTranslator, PRECISION, - Formatter}; +use super::translator::{Formatter, PRECISION, PrintableWithTranslator, Translator}; pub trait BasicFrequency: Debug + Clone + Default + PrintableWithTranslator { type Set: BasicSet; - type Sys: BasicSystem - + LoopSystem; - type Env: BasicEnvironment; + type Sys: BasicSystem + LoopSystem; + type Env: BasicEnvironment; type R: BasicReaction; type Id; fn naive_frequency(system: &Self::Sys) -> Result; - fn loop_frequency(system: &Self::Sys, - symb: Self::Id) -> Self; + fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self; - fn limit_frequency(q: &[Self::Set], - reactions: &[Self::R], - available_entities: &Self::Set) -> Option; + fn limit_frequency( + q: &[Self::Set], + reactions: &[Self::R], + available_entities: &Self::Set, + ) -> Option; - fn fast_frequency(q: &[Self::Set], - reactions: &[Self::R], - available_entities: &Self::Set, - weights: &[u32]) -> Option; + fn fast_frequency( + q: &[Self::Set], + reactions: &[Self::R], + available_entities: &Self::Set, + weights: &[u32], + ) -> Option; } /// Structure that holds the frequency of elements of a run or multiple runs, @@ -47,74 +46,72 @@ pub struct Frequency { impl Frequency { fn add(&mut self, e: Set, run: usize) { - for el in e.iter() { - let entry = - self.frequency_map.entry(*el).or_insert(vec![0; run + 1]); - if entry.len() < run +1 { - entry.resize(run + 1, 0); - } - entry[run] += 1 - } - // TODO resize clones all prev values, replace with in place method - if self.totals.len() < run + 1 { - self.totals.resize(run + 1, 0); - } - self.totals[run] += 1 + for el in e.iter() { + let entry = self.frequency_map.entry(*el).or_insert(vec![0; run + 1]); + if entry.len() < run + 1 { + entry.resize(run + 1, 0); + } + entry[run] += 1 + } + // TODO resize clones all prev values, replace with in place method + if self.totals.len() < run + 1 { + self.totals.resize(run + 1, 0); + } + self.totals[run] += 1 } fn append_weight(&mut self, new_weight: u32) { - self.weights.push(new_weight) + self.weights.push(new_weight) } fn total_weights(&self) -> u32 { - self.weights.iter().sum() + self.weights.iter().sum() } } impl PrintableWithTranslator for Frequency { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - use std::cmp::max; + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + use std::cmp::max; - write!(f, "[")?; - let mut freq_it = self.frequency_map.iter().peekable(); + write!(f, "[")?; + let mut freq_it = self.frequency_map.iter().peekable(); - let totals = &self.totals; - let weights = &self.weights; + let totals = &self.totals; + let weights = &self.weights; - while let Some((e, freq)) = freq_it.next() { - write!(f, "{} -> ", Formatter::from(translator, e))?; + while let Some((e, freq)) = freq_it.next() { + write!(f, "{} -> ", Formatter::from(translator, e))?; - let mut total_freq = 0.; + let mut total_freq = 0.; - let end = max(freq.len(), max(totals.len(), weights.len())); + let end = max(freq.len(), max(totals.len(), weights.len())); - for pos in 0..end { - let freq_e = freq.get(pos).copied().unwrap_or(0) as f32; - let weight = weights.get(pos).copied().unwrap_or(1) as f32; - let total = totals.get(pos).copied().unwrap_or(1) as f32; + for pos in 0..end { + let freq_e = freq.get(pos).copied().unwrap_or(0) as f32; + let weight = weights.get(pos).copied().unwrap_or(1) as f32; + let total = totals.get(pos).copied().unwrap_or(1) as f32; - let weighted_freq = (freq_e * weight * 100.) / (total); - if pos == end-1 { - #[allow(clippy::uninlined_format_args)] - write!(f, "{weighted_freq:.*}", PRECISION)?; - } else { - #[allow(clippy::uninlined_format_args)] - write!(f, "{weighted_freq:.*}, ", PRECISION)?; - } - total_freq += weighted_freq; - } + let weighted_freq = (freq_e * weight * 100.) / (total); + if pos == end - 1 { + #[allow(clippy::uninlined_format_args)] + write!(f, "{weighted_freq:.*}", PRECISION)?; + } else { + #[allow(clippy::uninlined_format_args)] + write!(f, "{weighted_freq:.*}, ", PRECISION)?; + } + total_freq += weighted_freq; + } - total_freq /= self.total_weights() as f32; + total_freq /= self.total_weights() as f32; - #[allow(clippy::uninlined_format_args)] - write!(f, " (total: {total_freq:.*})", PRECISION)?; + #[allow(clippy::uninlined_format_args)] + write!(f, " (total: {total_freq:.*})", PRECISION)?; - if freq_it.peek().is_some() { - writeln!(f, ",")?; - } - } - write!(f, "]") + if freq_it.peek().is_some() { + writeln!(f, ",")?; + } + } + write!(f, "]") } } @@ -129,27 +126,27 @@ impl BasicFrequency for Frequency { /// in all traversed states. /// see naiveFreq fn naive_frequency(system: &Self::Sys) -> Result { - let ect = system.run_separated()?; + let ect = system.run_separated()?; - let mut freq = Self::default(); - freq.append_weight(1); + let mut freq = Self::default(); + freq.append_weight(1); - ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0)); + ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0)); - Ok(freq) + Ok(freq) } /// Assume the system stabilizes in a loop, calculates the frequency of each /// symbol in all states of the loop. /// see loopFreq fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self { - let mut freq = Self::default(); - freq.append_weight(1); + let mut freq = Self::default(); + freq.append_weight(1); - if let Some(hoop) = system.lollipops_only_loop_named(symb) { - hoop.iter().for_each(|e| freq.add(e.clone(), 0)); - } - freq + if let Some(hoop) = system.lollipops_only_loop_named(symb) { + hoop.iter().for_each(|e| freq.add(e.clone(), 0)); + } + freq } /// Assuming ```q[i]``` is given enough times such that the system @@ -157,30 +154,30 @@ impl BasicFrequency for Frequency { /// state in the last loop. /// see limitFreq fn limit_frequency( - q: &[Self::Set], - reaction_rules: &[Self::R], - available_entities: &Self::Set, + q: &[Self::Set], + reaction_rules: &[Self::R], + available_entities: &Self::Set, ) -> Option { - let mut available_entities = available_entities.clone(); + let mut available_entities = available_entities.clone(); - for q in q.iter().rev().skip(1).rev() { - let res = - Self::R::lollipops_only_loop_decomposed_q(reaction_rules, - q, - &available_entities); - available_entities = res.into_iter().next()?; - } + for q in q.iter().rev().skip(1).rev() { + let res = + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, q, &available_entities); + available_entities = res.into_iter().next()?; + } - let mut freq = Self::default(); - freq.append_weight(1); + let mut freq = Self::default(); + freq.append_weight(1); - Self::R::lollipops_only_loop_decomposed_q(reaction_rules, - q.last().unwrap(), - &available_entities) - .iter() - .cloned() - .for_each(|e| freq.add(e, 0)); - Some(freq) + Self::R::lollipops_only_loop_decomposed_q( + reaction_rules, + q.last().unwrap(), + &available_entities, + ) + .iter() + .cloned() + .for_each(|e| freq.add(e, 0)); + Some(freq) } /// Assuming ```q[i]``` is given enough times such that the system @@ -188,26 +185,24 @@ impl BasicFrequency for Frequency { /// state in any loop, weighted. /// see fastFreq fn fast_frequency( - q: &[Self::Set], - reaction_rules: &[Self::R], - available_entities: &Self::Set, - weights: &[u32], + q: &[Self::Set], + reaction_rules: &[Self::R], + available_entities: &Self::Set, + weights: &[u32], ) -> Option { - // FIXME: we return the empty frequency or do we not return anything? - let mut available_entities = available_entities.clone(); + // FIXME: we return the empty frequency or do we not return anything? + let mut available_entities = available_entities.clone(); - let mut freq = Self::default(); + let mut freq = Self::default(); - for (pos, (q, &w)) in q.iter().zip(weights).enumerate() { - freq.append_weight(w); - let hoop = - Self::R::lollipops_only_loop_decomposed_q(reaction_rules, - q, - &available_entities); - hoop.iter().cloned().for_each(|e| freq.add(e, pos)); - available_entities = hoop.into_iter().next()?; - } - Some(freq) + for (pos, (q, &w)) in q.iter().zip(weights).enumerate() { + freq.append_weight(w); + let hoop = + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, q, &available_entities); + hoop.iter().cloned().for_each(|e| freq.add(e, pos)); + available_entities = hoop.into_iter().next()?; + } + Some(freq) } } @@ -224,76 +219,75 @@ pub struct PositiveFrequency { impl PositiveFrequency { fn add(&mut self, e: PositiveSet, run: usize) { - for (&id, &state) in e.iter() { - let entry = - self.frequency_map - .entry(PositiveType { id, state }) - .or_insert(vec![0; run + 1]); - if entry.len() < run +1 { - entry.resize(run + 1, 0); - } - entry[run] += 1 - } - // TODO resize clones all prev values, replace with in place method - if self.totals.len() < run + 1 { - self.totals.resize(run + 1, 0); - } - self.totals[run] += 1 + for (&id, &state) in e.iter() { + let entry = self + .frequency_map + .entry(PositiveType { id, state }) + .or_insert(vec![0; run + 1]); + if entry.len() < run + 1 { + entry.resize(run + 1, 0); + } + entry[run] += 1 + } + // TODO resize clones all prev values, replace with in place method + if self.totals.len() < run + 1 { + self.totals.resize(run + 1, 0); + } + self.totals[run] += 1 } fn append_weight(&mut self, new_weight: u32) { - self.weights.push(new_weight) + self.weights.push(new_weight) } fn total_weights(&self) -> u32 { - self.weights.iter().sum() + self.weights.iter().sum() } } impl PrintableWithTranslator for PositiveFrequency { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - use std::cmp::max; + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + use std::cmp::max; - write!(f, "[")?; - let mut freq_it = self.frequency_map.iter().peekable(); + write!(f, "[")?; + let mut freq_it = self.frequency_map.iter().peekable(); - let totals = &self.totals; - let weights = &self.weights; + let totals = &self.totals; + let weights = &self.weights; - while let Some((e, freq)) = freq_it.next() { - write!(f, "{} -> ", Formatter::from(translator, e))?; + while let Some((e, freq)) = freq_it.next() { + write!(f, "{} -> ", Formatter::from(translator, e))?; - let mut total_freq = 0.; + let mut total_freq = 0.; - let end = max(freq.len(), max(totals.len(), weights.len())); + let end = max(freq.len(), max(totals.len(), weights.len())); - for pos in 0..end { - let freq_e = freq.get(pos).copied().unwrap_or(0) as f32; - let weight = weights.get(pos).copied().unwrap_or(1) as f32; - let total = totals.get(pos).copied().unwrap_or(1) as f32; + for pos in 0..end { + let freq_e = freq.get(pos).copied().unwrap_or(0) as f32; + let weight = weights.get(pos).copied().unwrap_or(1) as f32; + let total = totals.get(pos).copied().unwrap_or(1) as f32; - let weighted_freq = (freq_e * weight * 100.) / (total); - if pos == end-1 { - #[allow(clippy::uninlined_format_args)] - write!(f, "{weighted_freq:.*}", PRECISION)?; - } else { - #[allow(clippy::uninlined_format_args)] - write!(f, "{weighted_freq:.*}, ", PRECISION)?; - } - total_freq += weighted_freq; - } + let weighted_freq = (freq_e * weight * 100.) / (total); + if pos == end - 1 { + #[allow(clippy::uninlined_format_args)] + write!(f, "{weighted_freq:.*}", PRECISION)?; + } else { + #[allow(clippy::uninlined_format_args)] + write!(f, "{weighted_freq:.*}, ", PRECISION)?; + } + total_freq += weighted_freq; + } - total_freq /= self.total_weights() as f32; + total_freq /= self.total_weights() as f32; - #[allow(clippy::uninlined_format_args)] - write!(f, " (total: {total_freq:.*})", PRECISION)?; + #[allow(clippy::uninlined_format_args)] + write!(f, " (total: {total_freq:.*})", PRECISION)?; - if freq_it.peek().is_some() { - writeln!(f, ",")?; - } - } - write!(f, "]") + if freq_it.peek().is_some() { + writeln!(f, ",")?; + } + } + write!(f, "]") } } @@ -308,27 +302,27 @@ impl BasicFrequency for PositiveFrequency { /// in all traversed states. /// see naiveFreq fn naive_frequency(system: &Self::Sys) -> Result { - let ect = system.run_separated()?; + let ect = system.run_separated()?; - let mut freq = Self::default(); - freq.append_weight(1); + let mut freq = Self::default(); + freq.append_weight(1); - ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0)); + ect.into_iter().for_each(|(e, _, _)| freq.add(e, 0)); - Ok(freq) + Ok(freq) } /// Assume the system stabilizes in a loop, calculates the frequency of each /// symbol in all states of the loop. /// see loopFreq fn loop_frequency(system: &Self::Sys, symb: Self::Id) -> Self { - let mut freq = Self::default(); - freq.append_weight(1); + let mut freq = Self::default(); + freq.append_weight(1); - if let Some(hoop) = system.lollipops_only_loop_named(symb) { - hoop.iter().for_each(|e| freq.add(e.clone(), 0)); - } - freq + if let Some(hoop) = system.lollipops_only_loop_named(symb) { + hoop.iter().for_each(|e| freq.add(e.clone(), 0)); + } + freq } /// Assuming ```q[i]``` is given enough times such that the system @@ -336,30 +330,30 @@ impl BasicFrequency for PositiveFrequency { /// state in the last loop. /// see limitFreq fn limit_frequency( - q: &[Self::Set], - reaction_rules: &[Self::R], - available_entities: &Self::Set, + q: &[Self::Set], + reaction_rules: &[Self::R], + available_entities: &Self::Set, ) -> Option { - let mut available_entities = available_entities.clone(); + let mut available_entities = available_entities.clone(); - for q in q.iter().rev().skip(1).rev() { - let res = - Self::R::lollipops_only_loop_decomposed_q(reaction_rules, - q, - &available_entities); - available_entities = res.into_iter().next()?; - } + for q in q.iter().rev().skip(1).rev() { + let res = + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, q, &available_entities); + available_entities = res.into_iter().next()?; + } - let mut freq = Self::default(); - freq.append_weight(1); + let mut freq = Self::default(); + freq.append_weight(1); - Self::R::lollipops_only_loop_decomposed_q(reaction_rules, - q.last().unwrap(), - &available_entities) - .iter() - .cloned() - .for_each(|e| freq.add(e, 0)); - Some(freq) + Self::R::lollipops_only_loop_decomposed_q( + reaction_rules, + q.last().unwrap(), + &available_entities, + ) + .iter() + .cloned() + .for_each(|e| freq.add(e, 0)); + Some(freq) } /// Assuming ```q[i]``` is given enough times such that the system @@ -367,25 +361,23 @@ impl BasicFrequency for PositiveFrequency { /// state in any loop, weighted. /// see fastFreq fn fast_frequency( - q: &[Self::Set], - reaction_rules: &[Self::R], - available_entities: &Self::Set, - weights: &[u32], + q: &[Self::Set], + reaction_rules: &[Self::R], + available_entities: &Self::Set, + weights: &[u32], ) -> Option { - // FIXME: we return the empty frequency or do we not return anything? - let mut available_entities = available_entities.clone(); + // FIXME: we return the empty frequency or do we not return anything? + let mut available_entities = available_entities.clone(); - let mut freq = Self::default(); + let mut freq = Self::default(); - for (pos, (q, &w)) in q.iter().zip(weights).enumerate() { - freq.append_weight(w); - let hoop = - Self::R::lollipops_only_loop_decomposed_q(reaction_rules, - q, - &available_entities); - hoop.iter().cloned().for_each(|e| freq.add(e, pos)); - available_entities = hoop.into_iter().next()?; - } - Some(freq) + for (pos, (q, &w)) in q.iter().zip(weights).enumerate() { + freq.append_weight(w); + let hoop = + Self::R::lollipops_only_loop_decomposed_q(reaction_rules, q, &available_entities); + hoop.iter().cloned().for_each(|e| freq.add(e, pos)); + available_entities = hoop.into_iter().next()?; + } + Some(freq) } } diff --git a/src/rsprocess/graph.rs b/src/rsprocess/graph.rs index 82b0cfa..4597e88 100644 --- a/src/rsprocess/graph.rs +++ b/src/rsprocess/graph.rs @@ -1,26 +1,25 @@ //! Definitions for generating graphs from a simulation. use petgraph::visit::{IntoEdgeReferences, IntoNodeReferences}; -use petgraph::{Graph, Directed}; +use petgraph::{Directed, Graph}; use std::rc::Rc; +use super::element::IdType; use super::label::Label; use super::set::{BasicSet, Set}; -use super::element::IdType; use super::system::System; use super::translator; pub type SystemGraph = Graph; fn common_system_entities(graph: &SystemGraph) -> Set { - graph.node_references().fold( - None, - |acc, node| - match acc { - None => Some(node.1.available_entities.clone()), - Some(acc) => Some(node.1.available_entities.intersection(&acc)) - } - ).unwrap_or(Set::default()) + graph + .node_references() + .fold(None, |acc, node| match acc { + None => Some(node.1.available_entities.clone()), + Some(acc) => Some(node.1.available_entities.intersection(&acc)), + }) + .unwrap_or(Set::default()) } macro_rules! common_label { @@ -30,18 +29,18 @@ macro_rules! common_label { $empty_expr:expr, $some_expr:expr ) => { - fn $name(graph: &SystemGraph) -> Set { - graph.edge_references().fold( - None, - |$acc_name, $edge_name| { - let $edge_name = $edge_name.weight(); - match $acc_name { - None => Some($empty_expr), - Some($acc_name) => Some($some_expr) - } - } - ).unwrap_or(Set::default()) - } + fn $name(graph: &SystemGraph) -> Set { + graph + .edge_references() + .fold(None, |$acc_name, $edge_name| { + let $edge_name = $edge_name.weight(); + match $acc_name { + None => Some($empty_expr), + Some($acc_name) => Some($some_expr), + } + }) + .unwrap_or(Set::default()) + } }; } @@ -73,19 +72,25 @@ common_label!( common_label_difference, [edge, acc], edge.context.subtraction(&edge.available_entities), - edge.context.subtraction(&edge.available_entities).intersection(&acc) + edge.context + .subtraction(&edge.available_entities) + .intersection(&acc) ); common_label!( common_label_entities_deleted, [edge, acc], edge.available_entities.subtraction(&edge.products), - edge.available_entities.subtraction(&edge.products).intersection(&acc) + edge.available_entities + .subtraction(&edge.products) + .intersection(&acc) ); common_label!( common_label_entities_added, [edge, acc], edge.products.subtraction(&edge.available_entities), - edge.products.subtraction(&edge.available_entities).intersection(&acc) + edge.products + .subtraction(&edge.available_entities) + .intersection(&acc) ); // ----------------------------------------------------------------------------- @@ -97,50 +102,49 @@ common_label!( pub trait MapEdges<'a, N: 'a, E, Ty, Ix> where Ty: petgraph::EdgeType, - Ix: petgraph::graph::IndexType + Ix: petgraph::graph::IndexType, { fn map_edges( - &self, - edge_map: &super::assert::types::Assert, - translator: &mut super::translator::Translator - ) -> Result< - Graph - , String>; + &self, + edge_map: &super::assert::types::Assert, + translator: &mut super::translator::Translator, + ) -> Result, String>; } -impl<'a> MapEdges<'a, System, Label, Directed, u32> - for SystemGraph -{ +impl<'a> MapEdges<'a, System, Label, Directed, u32> for SystemGraph { fn map_edges( - &self, - edge_map: &super::assert::types::Assert, - translator: &mut super::translator::Translator - )-> Result - , String> { - use petgraph::graph::EdgeIndex; + &self, + edge_map: &super::assert::types::Assert, + translator: &mut super::translator::Translator, + ) -> Result, String> { + use petgraph::graph::EdgeIndex; - let mut g = Graph::with_capacity(self.node_count(), self.edge_count()); - let nodes = self.raw_nodes(); - let edges = self.raw_edges(); + let mut g = Graph::with_capacity(self.node_count(), self.edge_count()); + let nodes = self.raw_nodes(); + let edges = self.raw_edges(); - let edges = edges.iter().enumerate().map( - |(i, edge)| - match edge_map.execute(self, &EdgeIndex::new(i), translator) { - Err(e) => Err(e), - Ok(val) => Ok((edge.source(), edge.target(), val)) - } - ).collect::, _>>()?; - nodes.iter().for_each(|node| { g.add_node(node.weight.clone()); }); + let edges = edges + .iter() + .enumerate() + .map( + |(i, edge)| match edge_map.execute(self, &EdgeIndex::new(i), translator) { + Err(e) => Err(e), + Ok(val) => Ok((edge.source(), edge.target(), val)), + }, + ) + .collect::, _>>()?; + nodes.iter().for_each(|node| { + g.add_node(node.weight.clone()); + }); - edges.into_iter().for_each(|(source, target, v)| { g.add_edge(source, target, v); }); + edges.into_iter().for_each(|(source, target, v)| { + g.add_edge(source, target, v); + }); - Ok(g) + Ok(g) } } - // Nodes ----------------------------------------------------------------------- /// Helper structure that specifies what information to display for nodes. @@ -153,113 +157,114 @@ pub enum NodeDisplayBase { ExcludeEntities { mask: Set }, Context, UncommonEntities, - MaskUncommonEntities { mask: Set } + MaskUncommonEntities { mask: Set }, } pub struct NodeDisplay { - pub base: Vec + pub base: Vec, } -type GraphMapNodesFnTy<'a> = - dyn Fn(petgraph::prelude::NodeIndex, &'a System) -> String + 'a; - +type GraphMapNodesFnTy<'a> = dyn Fn(petgraph::prelude::NodeIndex, &'a System) -> String + 'a; fn match_node_display<'a>( base: &NodeDisplayBase, common_entities: Rc, - translator: Rc + translator: Rc, ) -> Box> { - use NodeDisplayBase::*; use super::format_helpers::graph_map_nodes_ty_from::*; + use NodeDisplayBase::*; match base { - String { string } => { - format_string(string.clone()) - }, - Hide => { - format_hide(translator) - }, - Entities => { - format_entities(translator) - }, - MaskEntities { mask } => { - format_mask_entities(translator, mask.clone()) - }, - ExcludeEntities { mask } => { - format_exclude_entities(translator, mask.clone()) - }, - Context => { - format_context(translator) - }, - UncommonEntities => { - format_exclude_entities(translator, (*common_entities).clone()) - }, - MaskUncommonEntities { mask } => { - format_exclude_entities(translator, - mask.intersection(&common_entities)) - } + String { string } => format_string(string.clone()), + Hide => format_hide(translator), + Entities => format_entities(translator), + MaskEntities { mask } => format_mask_entities(translator, mask.clone()), + ExcludeEntities { mask } => format_exclude_entities(translator, mask.clone()), + Context => format_context(translator), + UncommonEntities => format_exclude_entities(translator, (*common_entities).clone()), + MaskUncommonEntities { mask } => { + format_exclude_entities(translator, mask.intersection(&common_entities)) + } } } - impl NodeDisplay { fn contains_uncommon(&self) -> bool { - self.base.iter().any( - |b| - matches!(b, NodeDisplayBase::UncommonEntities | - NodeDisplayBase::MaskUncommonEntities { mask: _ })) + self.base.iter().any(|b| { + matches!( + b, + NodeDisplayBase::UncommonEntities + | NodeDisplayBase::MaskUncommonEntities { mask: _ } + ) + }) } pub fn generate<'a>( - self, - translator: Rc, - current_graph: &SystemGraph + self, + translator: Rc, + current_graph: &SystemGraph, ) -> Box> { - let common_entities = - if self.contains_uncommon() { - Rc::new(common_system_entities(current_graph)) - } else { - Rc::new(Set::default()) - }; + let common_entities = if self.contains_uncommon() { + Rc::new(common_system_entities(current_graph)) + } else { + Rc::new(Set::default()) + }; - Box::new( - move |i, n| { - let mut accumulator = String::new(); - for b in &self.base { - let f = match_node_display(b, - Rc::clone(&common_entities), - Rc::clone(&translator)); + Box::new(move |i, n| { + let mut accumulator = String::new(); + for b in &self.base { + let f = match_node_display(b, Rc::clone(&common_entities), Rc::clone(&translator)); - accumulator.push_str(&(f)(i, n)); - } - accumulator - } - ) + accumulator.push_str(&(f)(i, n)); + } + accumulator + }) } } - // Edges ----------------------------------------------------------------------- #[derive(Clone)] pub enum EdgeDisplayBase { - String { string: String }, + String { + string: String, + }, Hide, - Products { mask: Option, filter_common: bool }, - Entities { mask: Option, filter_common: bool }, - Context { mask: Option, filter_common: bool }, - Union { mask: Option, filter_common: bool }, - Difference { mask: Option, filter_common: bool }, - EntitiesDeleted { mask: Option, filter_common: bool }, - EntitiesAdded { mask: Option, filter_common: bool }, + Products { + mask: Option, + filter_common: bool, + }, + Entities { + mask: Option, + filter_common: bool, + }, + Context { + mask: Option, + filter_common: bool, + }, + Union { + mask: Option, + filter_common: bool, + }, + Difference { + mask: Option, + filter_common: bool, + }, + EntitiesDeleted { + mask: Option, + filter_common: bool, + }, + EntitiesAdded { + mask: Option, + filter_common: bool, + }, } pub struct EdgeDisplay { pub base: Vec, } -type GraphMapEdgesFnTy<'a> = - dyn Fn(petgraph::prelude::EdgeIndex, &'a Label) -> String + 'a; +type GraphMapEdgesFnTy<'a> = dyn Fn(petgraph::prelude::EdgeIndex, &'a Label) -> String + 'a; #[derive(Default, Clone)] struct CommonEntities { @@ -275,161 +280,203 @@ struct CommonEntities { fn match_edge_display<'a>( base: &'a EdgeDisplayBase, translator: Rc, - common: CommonEntities + common: CommonEntities, ) -> Box> { - use EdgeDisplayBase::*; use super::format_helpers::graph_map_edges_ty_from::*; + use EdgeDisplayBase::*; match base { - String { string } => { - format_string(translator, string.clone()) - } - Hide => { - format_hide(translator) - }, - Products { mask, filter_common } => { - if *filter_common { - format_products(translator, mask.clone(), - Some(common.common_products)) - } else { - format_products(translator, mask.clone(), None) - } - }, - Entities { mask, filter_common } => { - if *filter_common { - format_entities(translator, mask.clone(), - Some(common.common_entities)) - } else { - format_entities(translator, mask.clone(), None) - } - }, - Context { mask, filter_common } => { - if *filter_common { - format_context(translator, mask.clone(), - Some(common.common_context)) - } else { - format_context(translator, mask.clone(), None) - } - }, - Union { mask, filter_common } => { - if *filter_common { - format_union(translator, mask.clone(), - Some(common.common_union)) - } else { - format_union(translator, mask.clone(), None) - } - }, - Difference { mask, filter_common } => { - if *filter_common { - format_difference(translator, mask.clone(), - Some(common.common_difference)) - } else { - format_difference(translator, mask.clone(), None) - } - }, - EntitiesDeleted { mask, filter_common } => { - if *filter_common { - format_entities_deleted(translator, mask.clone(), - Some(common.common_entities_deleted)) - } else { - format_entities_deleted(translator, mask.clone(), None) - } - }, - EntitiesAdded { mask, filter_common } => { - if *filter_common { - format_entities_added(translator, mask.clone(), - Some(common.common_entities_added)) - } else { - format_entities_added(translator, mask.clone(), None) - } - }, + String { string } => format_string(translator, string.clone()), + Hide => format_hide(translator), + Products { + mask, + filter_common, + } => { + if *filter_common { + format_products(translator, mask.clone(), Some(common.common_products)) + } else { + format_products(translator, mask.clone(), None) + } + } + Entities { + mask, + filter_common, + } => { + if *filter_common { + format_entities(translator, mask.clone(), Some(common.common_entities)) + } else { + format_entities(translator, mask.clone(), None) + } + } + Context { + mask, + filter_common, + } => { + if *filter_common { + format_context(translator, mask.clone(), Some(common.common_context)) + } else { + format_context(translator, mask.clone(), None) + } + } + Union { + mask, + filter_common, + } => { + if *filter_common { + format_union(translator, mask.clone(), Some(common.common_union)) + } else { + format_union(translator, mask.clone(), None) + } + } + Difference { + mask, + filter_common, + } => { + if *filter_common { + format_difference(translator, mask.clone(), Some(common.common_difference)) + } else { + format_difference(translator, mask.clone(), None) + } + } + EntitiesDeleted { + mask, + filter_common, + } => { + if *filter_common { + format_entities_deleted( + translator, + mask.clone(), + Some(common.common_entities_deleted), + ) + } else { + format_entities_deleted(translator, mask.clone(), None) + } + } + EntitiesAdded { + mask, + filter_common, + } => { + if *filter_common { + format_entities_added(translator, mask.clone(), Some(common.common_entities_added)) + } else { + format_entities_added(translator, mask.clone(), None) + } + } } } macro_rules! common_entity { ($name:ident, $match:pat, $filter_common:ident) => { - fn $name(&self) -> bool { - self.base.iter().any( - |b| - if let $match = b { - *$filter_common - } else { - false - } - ) - } + fn $name(&self) -> bool { + self.base.iter().any(|b| { + if let $match = b { + *$filter_common + } else { + false + } + }) + } }; } - impl EdgeDisplay { - common_entity!(common_products, - EdgeDisplayBase::Products {mask: _, filter_common}, - filter_common); - common_entity!(common_entities, - EdgeDisplayBase::Entities {mask: _, filter_common}, - filter_common); - common_entity!(common_context, - EdgeDisplayBase::Context {mask: _, filter_common}, - filter_common); - common_entity!(common_union, - EdgeDisplayBase::Union {mask: _, filter_common}, - filter_common); - common_entity!(common_difference, - EdgeDisplayBase::Difference {mask: _, filter_common}, - filter_common); - common_entity!(common_entities_deleted, - EdgeDisplayBase::EntitiesDeleted {mask: _, filter_common}, - filter_common); - common_entity!(common_entities_added, - EdgeDisplayBase::EntitiesAdded {mask: _, filter_common}, - filter_common); - + common_entity!( + common_products, + EdgeDisplayBase::Products { + mask: _, + filter_common + }, + filter_common + ); + common_entity!( + common_entities, + EdgeDisplayBase::Entities { + mask: _, + filter_common + }, + filter_common + ); + common_entity!( + common_context, + EdgeDisplayBase::Context { + mask: _, + filter_common + }, + filter_common + ); + common_entity!( + common_union, + EdgeDisplayBase::Union { + mask: _, + filter_common + }, + filter_common + ); + common_entity!( + common_difference, + EdgeDisplayBase::Difference { + mask: _, + filter_common + }, + filter_common + ); + common_entity!( + common_entities_deleted, + EdgeDisplayBase::EntitiesDeleted { + mask: _, + filter_common + }, + filter_common + ); + common_entity!( + common_entities_added, + EdgeDisplayBase::EntitiesAdded { + mask: _, + filter_common + }, + filter_common + ); pub fn generate<'a>( - self, - translator: Rc, - current_graph: &SystemGraph + self, + translator: Rc, + current_graph: &SystemGraph, ) -> Box> { - // create the structure for common entities if required - let common = { - let mut tmp = CommonEntities::default(); - if self.common_products() { - tmp.common_products = common_label_products(current_graph); - } - if self.common_entities() { - tmp.common_entities = common_label_entities(current_graph); - } - if self.common_context() { - tmp.common_context = common_label_context(current_graph); - } - if self.common_union() { - tmp.common_union = common_label_union(current_graph); - } - if self.common_difference() { - tmp.common_difference = common_label_difference(current_graph); - } - if self.common_entities_deleted() { - tmp.common_entities_deleted = common_label_entities_deleted(current_graph); - } - if self.common_entities_added() { - tmp.common_entities_added = common_label_entities_added(current_graph); - } - tmp - }; + // create the structure for common entities if required + let common = { + let mut tmp = CommonEntities::default(); + if self.common_products() { + tmp.common_products = common_label_products(current_graph); + } + if self.common_entities() { + tmp.common_entities = common_label_entities(current_graph); + } + if self.common_context() { + tmp.common_context = common_label_context(current_graph); + } + if self.common_union() { + tmp.common_union = common_label_union(current_graph); + } + if self.common_difference() { + tmp.common_difference = common_label_difference(current_graph); + } + if self.common_entities_deleted() { + tmp.common_entities_deleted = common_label_entities_deleted(current_graph); + } + if self.common_entities_added() { + tmp.common_entities_added = common_label_entities_added(current_graph); + } + tmp + }; - Box::new( - move |i, n| { - let mut accumulator = String::new(); - for b in &self.base { - let f = match_edge_display(b, - Rc::clone(&translator), - common.clone()); - accumulator.push_str(&(f)(i, n)); - } - accumulator - } - ) + Box::new(move |i, n| { + let mut accumulator = String::new(); + for b in &self.base { + let f = match_edge_display(b, Rc::clone(&translator), common.clone()); + accumulator.push_str(&(f)(i, n)); + } + accumulator + }) } } @@ -437,19 +484,12 @@ impl EdgeDisplay { // Color Nodes & Edges // ----------------------------------------------------------------------------- - // Node ------------------------------------------------------------------------ type RSdotGraph = Graph; type RSformatNodeTy<'a> = - dyn Fn( - &'a RSdotGraph, - <&'a RSdotGraph as IntoNodeReferences>::NodeRef - ) -> String + 'a; + dyn Fn(&'a RSdotGraph, <&'a RSdotGraph as IntoNodeReferences>::NodeRef) -> String + 'a; type RSformatNodeTyOpt<'a> = - dyn Fn( - &'a RSdotGraph, - <&'a RSdotGraph as IntoNodeReferences>::NodeRef - ) -> Option + 'a; + dyn Fn(&'a RSdotGraph, <&'a RSdotGraph as IntoNodeReferences>::NodeRef) -> Option + 'a; #[derive(Clone, Copy)] pub enum OperationType { @@ -457,28 +497,18 @@ pub enum OperationType { Subset, SubsetEqual, Superset, - SupersetEqual + SupersetEqual, } impl OperationType { pub fn evaluate(&self, a: &Set, b: &Set) -> bool { - match self { - Self::Equals => { - a.is_subset(b) && b.is_subset(a) - }, - Self::Subset => { - a.is_subset(b) && !b.is_subset(a) - }, - Self::SubsetEqual => { - a.is_subset(b) - }, - Self::Superset => { - b.is_subset(a) && !a.is_subset(b) - }, - Self::SupersetEqual => { - b.is_subset(a) - } - } + match self { + Self::Equals => a.is_subset(b) && b.is_subset(a), + Self::Subset => a.is_subset(b) && !b.is_subset(a), + Self::SubsetEqual => a.is_subset(b), + Self::Superset => b.is_subset(a) && !a.is_subset(b), + Self::SupersetEqual => b.is_subset(a), + } } } @@ -489,13 +519,13 @@ pub enum ContextColorConditional { EntitySet(OperationType, Set), NonDeterministicChoice, Summation, - WaitEntity + WaitEntity, } #[derive(Clone)] pub enum NodeColorConditional { ContextConditional(ContextColorConditional), - EntitiesConditional(OperationType, Set) + EntitiesConditional(OperationType, Set), } #[derive(Clone)] @@ -505,10 +535,7 @@ pub struct NodeColor { } #[inline(always)] -fn node_formatter_base_color( - base_color: String -) -> String -{ +fn node_formatter_base_color(base_color: String) -> String { ", fillcolor=".to_string() + &base_color } @@ -517,97 +544,69 @@ fn match_node_color_conditional<'a>( rule: &'a NodeColorConditional, color: &'a String, original_graph: Rc, - star: Option + star: Option, ) -> Box> { use super::format_helpers::node_formatter::*; match rule { - NodeColorConditional::ContextConditional(ccc) => { - match ccc { - ContextColorConditional::Nill => { - format_nill(Rc::clone(&original_graph), - color.to_string(), - star) - }, - ContextColorConditional::RecursiveIdentifier(s) => { - format_recursive_identifier(Rc::clone(&original_graph), - color.to_string(), - star, - *s) - }, - ContextColorConditional::EntitySet(ot, set) => { - format_entity_set(Rc::clone(&original_graph), - color.to_string(), - star, - *ot, - set.clone()) - }, - ContextColorConditional::NonDeterministicChoice => { - format_non_deterministic_choice(Rc::clone(&original_graph), - color.to_string(), - star) - }, - ContextColorConditional::Summation => { - format_summation(Rc::clone(&original_graph), - color.to_string(), - star) - }, - ContextColorConditional::WaitEntity => { - format_wait_entity(Rc::clone(&original_graph), - color.to_string(), - star) - }, - } - }, - NodeColorConditional::EntitiesConditional(ot, set) => { - format_entities_conditional(Rc::clone(&original_graph), - color.to_string(), - star, - *ot, - set.clone()) - }, + NodeColorConditional::ContextConditional(ccc) => match ccc { + ContextColorConditional::Nill => { + format_nill(Rc::clone(&original_graph), color.to_string(), star) + } + ContextColorConditional::RecursiveIdentifier(s) => { + format_recursive_identifier(Rc::clone(&original_graph), color.to_string(), star, *s) + } + ContextColorConditional::EntitySet(ot, set) => format_entity_set( + Rc::clone(&original_graph), + color.to_string(), + star, + *ot, + set.clone(), + ), + ContextColorConditional::NonDeterministicChoice => { + format_non_deterministic_choice(Rc::clone(&original_graph), color.to_string(), star) + } + ContextColorConditional::Summation => { + format_summation(Rc::clone(&original_graph), color.to_string(), star) + } + ContextColorConditional::WaitEntity => { + format_wait_entity(Rc::clone(&original_graph), color.to_string(), star) + } + }, + NodeColorConditional::EntitiesConditional(ot, set) => format_entities_conditional( + Rc::clone(&original_graph), + color.to_string(), + star, + *ot, + set.clone(), + ), } } impl NodeColor { pub fn generate<'a>( - self, - original_graph: Rc, - star: Option + self, + original_graph: Rc, + star: Option, ) -> Box> { - Box::new( - move |i, n| { - for (rule, color) in &self.conditionals { - let f = match_node_color_conditional( - rule, - color, - Rc::clone(&original_graph), - star - ); + Box::new(move |i, n| { + for (rule, color) in &self.conditionals { + let f = match_node_color_conditional(rule, color, Rc::clone(&original_graph), star); - if let Some(s) = (f)(i, n) { - return s - } - } - node_formatter_base_color(self.base_color.clone()) - } - ) + if let Some(s) = (f)(i, n) { + return s; + } + } + node_formatter_base_color(self.base_color.clone()) + }) } } - // Edge ------------------------------------------------------------------------ type RSformatEdgeTy<'a> = - dyn Fn( - &'a RSdotGraph, - <&'a RSdotGraph as IntoEdgeReferences>::EdgeRef - ) -> String + 'a; + dyn Fn(&'a RSdotGraph, <&'a RSdotGraph as IntoEdgeReferences>::EdgeRef) -> String + 'a; type RSformatEdgeTyOpt<'a> = - dyn Fn( - &'a RSdotGraph, - <&'a RSdotGraph as IntoEdgeReferences>::EdgeRef - ) -> Option + 'a; - + dyn Fn(&'a RSdotGraph, <&'a RSdotGraph as IntoEdgeReferences>::EdgeRef) -> Option + 'a; #[derive(Clone)] pub enum EdgeColorConditional { @@ -624,95 +623,82 @@ pub enum EdgeColorConditional { #[derive(Clone)] pub struct EdgeColor { pub conditionals: Vec<(EdgeColorConditional, String)>, - pub base_color: String + pub base_color: String, } - -fn edge_formatter_base_color( - base_color: String -) -> String -{ +fn edge_formatter_base_color(base_color: String) -> String { ", color=".to_string() + &base_color } fn match_edge_color_conditional<'a>( rule: &'a EdgeColorConditional, color: &'a String, - original_graph: Rc + original_graph: Rc, ) -> Box> { use super::format_helpers::edge_formatter::*; match rule { - EdgeColorConditional::Entities(ot, set) => { - format_entities(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::Context(ot, set) => { - format_context(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::T(ot, set) => { - format_t(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::Reactants(ot, set) => { - format_reactants(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::ReactantsAbsent(ot, set) => { - format_reactants_absent(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::Inhibitors(ot, set) => { - format_inhibitors(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::InhibitorsPresent(ot, set) => { - format_inhibitors_present(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, - EdgeColorConditional::Products(ot, set) => { - format_products(Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone()) - }, + EdgeColorConditional::Entities(ot, set) => format_entities( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::Context(ot, set) => format_context( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::T(ot, set) => format_t( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::Reactants(ot, set) => format_reactants( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::ReactantsAbsent(ot, set) => format_reactants_absent( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::Inhibitors(ot, set) => format_inhibitors( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::InhibitorsPresent(ot, set) => format_inhibitors_present( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + EdgeColorConditional::Products(ot, set) => format_products( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), } } impl EdgeColor { - pub fn generate<'a>( - self, - original_graph: Rc, - ) -> Box> { - Box::new( - move |i, n| { - for (rule, color) in &self.conditionals { - let f = match_edge_color_conditional( - rule, - color, - Rc::clone(&original_graph), - ); + pub fn generate<'a>(self, original_graph: Rc) -> Box> { + Box::new(move |i, n| { + for (rule, color) in &self.conditionals { + let f = match_edge_color_conditional(rule, color, Rc::clone(&original_graph)); - if let Some(s) = (f)(i, n) { - return s - } - } - edge_formatter_base_color(self.base_color.clone()) - } - ) + if let Some(s) = (f)(i, n) { + return s; + } + } + edge_formatter_base_color(self.base_color.clone()) + }) } } diff --git a/src/rsprocess/label.rs b/src/rsprocess/label.rs index 53adac4..73466e2 100644 --- a/src/rsprocess/label.rs +++ b/src/rsprocess/label.rs @@ -3,12 +3,13 @@ use std::fmt::Debug; use std::hash::Hash; use super::set::{BasicSet, PositiveSet, Set}; -use super::translator::{Translator, PrintableWithTranslator, Formatter}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; pub trait BasicLabel -where Self: Default + Clone + Debug + Serialize + Eq + Ord + Hash + - PrintableWithTranslator, -for<'a> Self: Deserialize<'a> { +where + Self: Default + Clone + Debug + Serialize + Eq + Ord + Hash + PrintableWithTranslator, + for<'a> Self: Deserialize<'a>, +{ type Set: BasicSet; fn get_context(&self) -> (&Self::Set, &Self::Set, &Self::Set); @@ -32,64 +33,60 @@ impl BasicLabel for Label { type Set = Set; fn get_context(&self) -> (&Set, &Set, &Set) { - ( - &self.available_entities, - &self.context, - &self.t, - ) + (&self.available_entities, &self.context, &self.t) } } impl Label { #[allow(clippy::too_many_arguments)] pub fn from( - available_entities: Set, - context: Set, - t: Set, - reactants: Set, - reactants_absent: Set, - inhibitors: Set, - inhibitors_present: Set, - products: Set, + available_entities: Set, + context: Set, + t: Set, + reactants: Set, + reactants_absent: Set, + inhibitors: Set, + inhibitors_present: Set, + products: Set, ) -> Self { - Label { - available_entities, - context, - t, - reactants, - reactants_absent, - inhibitors, - inhibitors_present, - products, - } + Label { + available_entities, + context, + t, + reactants, + reactants_absent, + inhibitors, + inhibitors_present, + products, + } } #[allow(clippy::too_many_arguments)] pub fn create( - available_entities: Set, - context: Set, - reactants: Set, - reactants_absent: Set, - inhibitors: Set, - inhibitors_present: Set, - products: Set, + available_entities: Set, + context: Set, + reactants: Set, + reactants_absent: Set, + inhibitors: Set, + inhibitors_present: Set, + products: Set, ) -> Self { - Label { - available_entities: available_entities.clone(), - context: context.clone(), - t: available_entities.union(&context), - reactants, - reactants_absent, - inhibitors, - inhibitors_present, - products, - } + Label { + available_entities: available_entities.clone(), + context: context.clone(), + t: available_entities.union(&context), + reactants, + reactants_absent, + inhibitors, + inhibitors_present, + products, + } } } impl PartialEq for Label { fn eq(&self, other: &Self) -> bool { - self.available_entities == other.available_entities && + self.available_entities == other.available_entities && self.context == other.context && // self.t == other.t && // no need since its the union of the above // // elements @@ -103,23 +100,22 @@ impl PartialEq for Label { impl Hash for Label { fn hash(&self, state: &mut H) { - self.available_entities.hash(state); - self.context.hash(state); - // self.t.hash(state); - self.reactants.hash(state); - self.reactants_absent.hash(state); - self.inhibitors.hash(state); - self.inhibitors_present.hash(state); - self.products.hash(state); + self.available_entities.hash(state); + self.context.hash(state); + // self.t.hash(state); + self.reactants.hash(state); + self.reactants_absent.hash(state); + self.inhibitors.hash(state); + self.inhibitors_present.hash(state); + self.products.hash(state); } } impl PrintableWithTranslator for Label { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "{{available_entities: {}, \ + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!( + f, + "{{available_entities: {}, \ context: {}, \ t: {}, \ reactants: {}, \ @@ -127,15 +123,15 @@ impl PrintableWithTranslator for Label { inihibitors: {}, \ ireactants: {}, \ products: {}}}", - Formatter::from(translator, &self.available_entities), - Formatter::from(translator, &self.context), - Formatter::from(translator, &self.t), - Formatter::from(translator, &self.reactants), - Formatter::from(translator, &self.reactants_absent), - Formatter::from(translator, &self.inhibitors), - Formatter::from(translator, &self.inhibitors_present), - Formatter::from(translator, &self.products), - ) + Formatter::from(translator, &self.available_entities), + Formatter::from(translator, &self.context), + Formatter::from(translator, &self.t), + Formatter::from(translator, &self.reactants), + Formatter::from(translator, &self.reactants_absent), + Formatter::from(translator, &self.inhibitors), + Formatter::from(translator, &self.inhibitors_present), + Formatter::from(translator, &self.products), + ) } } @@ -155,17 +151,13 @@ impl BasicLabel for PositiveLabel { type Set = PositiveSet; fn get_context(&self) -> (&PositiveSet, &PositiveSet, &PositiveSet) { - ( - &self.available_entities, - &self.context, - &self.t, - ) + (&self.available_entities, &self.context, &self.t) } } impl PartialEq for PositiveLabel { fn eq(&self, other: &Self) -> bool { - self.available_entities == other.available_entities && + self.available_entities == other.available_entities && self.context == other.context && // self.t == other.t && // no need since its the union of the above // // elements @@ -177,71 +169,70 @@ impl PartialEq for PositiveLabel { impl Hash for PositiveLabel { fn hash(&self, state: &mut H) { - self.available_entities.hash(state); - self.context.hash(state); - // self.t.hash(state); - self.reactants.hash(state); - self.reactants_absent.hash(state); - self.products.hash(state); + self.available_entities.hash(state); + self.context.hash(state); + // self.t.hash(state); + self.reactants.hash(state); + self.reactants_absent.hash(state); + self.products.hash(state); } } impl PrintableWithTranslator for PositiveLabel { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "{{available_entities: {}, \ + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!( + f, + "{{available_entities: {}, \ context: {}, \ t: {}, \ reactants: {}, \ reactantsi: {}, \ products: {}}}", - Formatter::from(translator, &self.available_entities), - Formatter::from(translator, &self.context), - Formatter::from(translator, &self.t), - Formatter::from(translator, &self.reactants), - Formatter::from(translator, &self.reactants_absent), - Formatter::from(translator, &self.products), - ) + Formatter::from(translator, &self.available_entities), + Formatter::from(translator, &self.context), + Formatter::from(translator, &self.t), + Formatter::from(translator, &self.reactants), + Formatter::from(translator, &self.reactants_absent), + Formatter::from(translator, &self.products), + ) } } impl PositiveLabel { #[allow(clippy::too_many_arguments)] pub fn from( - available_entities: PositiveSet, - context: PositiveSet, - t: PositiveSet, - reactants: PositiveSet, - reactants_absent: PositiveSet, - products: PositiveSet, + available_entities: PositiveSet, + context: PositiveSet, + t: PositiveSet, + reactants: PositiveSet, + reactants_absent: PositiveSet, + products: PositiveSet, ) -> Self { - Self { - available_entities, - context, - t, - reactants, - reactants_absent, - products, - } + Self { + available_entities, + context, + t, + reactants, + reactants_absent, + products, + } } #[allow(clippy::too_many_arguments)] pub fn create( - available_entities: PositiveSet, - context: PositiveSet, - reactants: PositiveSet, - reactants_absent: PositiveSet, - products: PositiveSet, + available_entities: PositiveSet, + context: PositiveSet, + reactants: PositiveSet, + reactants_absent: PositiveSet, + products: PositiveSet, ) -> Self { - Self { - available_entities: available_entities.clone(), - context: context.clone(), - t: available_entities.union(&context), - reactants, - reactants_absent, - products, - } + Self { + available_entities: available_entities.clone(), + context: context.clone(), + t: available_entities.union(&context), + reactants, + reactants_absent, + products, + } } } diff --git a/src/rsprocess/mod.rs b/src/rsprocess/mod.rs index 704aa53..2141fea 100644 --- a/src/rsprocess/mod.rs +++ b/src/rsprocess/mod.rs @@ -1,10 +1,10 @@ //! Crate root -pub mod translator; mod format_helpers; +pub mod translator; -pub mod element; pub mod choices; +pub mod element; pub mod environment; pub mod label; pub mod process; @@ -14,10 +14,10 @@ pub mod system; pub mod assert; pub mod bisimilarity; +pub mod dot; pub mod frequency; pub mod graph; pub mod presets; -pub mod dot; pub mod serialize; pub mod transitions; diff --git a/src/rsprocess/presets.rs b/src/rsprocess/presets.rs index 192bc97..1aca816 100644 --- a/src/rsprocess/presets.rs +++ b/src/rsprocess/presets.rs @@ -5,15 +5,15 @@ use petgraph::Graph; use std::env; use std::fmt::Display; use std::fs; -use std::io::prelude::*; use std::io; +use std::io::prelude::*; use std::rc::Rc; -use super::*; use super::graph::MapEdges; use super::set::Set; -use super::system::{ExtensionsSystem}; +use super::system::ExtensionsSystem; use super::translator::Translator; +use super::*; use super::super::grammar; @@ -62,8 +62,8 @@ pub enum GraphSaveOptions { Dot { node_display: graph::NodeDisplay, edge_display: graph::EdgeDisplay, - node_color: graph::NodeColor, - edge_color: graph::EdgeColor, + node_color: graph::NodeColor, + edge_color: graph::EdgeColor, so: SaveOptions, }, GraphML { @@ -78,17 +78,38 @@ pub enum GraphSaveOptions { /// Describes the computation to apply to the input system or graph. pub enum Instruction { - Stats { so: SaveOptions }, - Target { so: SaveOptions }, - Run { so: SaveOptions }, - Loop { symbol: String, so: SaveOptions }, - Frequency { so: SaveOptions }, - LimitFrequency { experiment: String, so: SaveOptions }, - FastFrequency { experiment: String, so: SaveOptions }, - Digraph { gso: Vec }, - Bisimilarity { system_b: String, - edge_relabeler: Box, - so: SaveOptions } + Stats { + so: SaveOptions, + }, + Target { + so: SaveOptions, + }, + Run { + so: SaveOptions, + }, + Loop { + symbol: String, + so: SaveOptions, + }, + Frequency { + so: SaveOptions, + }, + LimitFrequency { + experiment: String, + so: SaveOptions, + }, + FastFrequency { + experiment: String, + so: SaveOptions, + }, + Digraph { + gso: Vec, + }, + Bisimilarity { + system_b: String, + edge_relabeler: Box, + so: SaveOptions, + }, } /// Describes a system or a graph. @@ -99,11 +120,7 @@ pub enum System { impl System { /// Deserialize the graph if applicable. - pub fn compute( - &self, - translator: Translator - ) -> Result - { + pub fn compute(&self, translator: Translator) -> Result { match self { Self::System { sys } => Ok(EvaluatedSystem::System { sys: sys.to_owned(), @@ -130,14 +147,13 @@ pub enum EvaluatedSystem { impl EvaluatedSystem { pub fn get_translator(&mut self) -> &mut Translator { - match self { - EvaluatedSystem::Graph { graph: _, translator } => { - translator - }, - EvaluatedSystem::System { sys: _, translator } => { - translator - } - } + match self { + EvaluatedSystem::Graph { + graph: _, + translator, + } => translator, + EvaluatedSystem::System { sys: _, translator } => translator, + } } } @@ -151,11 +167,7 @@ pub struct Instructions { // IO Helper Functions // ----------------------------------------------------------------------------- -fn read_file( - translator: &mut Translator, - path_string: String, - parser: F -) -> Result +fn read_file(translator: &mut Translator, path_string: String, parser: F) -> Result where F: Fn(&mut Translator, String) -> Result, { @@ -184,26 +196,19 @@ where Ok(result) } -fn reformat_error( - e: ParseError, - input_str: &str, -) -> Result +fn reformat_error(e: ParseError, input_str: &str) -> Result where T: Display, { match e { - ParseError::ExtraToken { token: (l, t, r) } => { - Err(format!( - "Unexpected token \"{t}\" \ + ParseError::ExtraToken { token: (l, t, r) } => Err(format!( + "Unexpected token \"{t}\" \ between positions {l} and {r}." - )) - }, + )), ParseError::UnrecognizedEof { location: _, expected: _, - } => { - Err("End of file encountered while parsing.".into()) - }, + } => Err("End of file encountered while parsing.".into()), ParseError::InvalidToken { location } => { Err(format!("Invalid token at position {location}.")) } @@ -211,72 +216,67 @@ where token: (l, t, r), expected: _, } => { - use colored::Colorize; + use colored::Colorize; - let mut err = format!( - "Unrecognized token {}{}{} \ + let mut err = format!( + "Unrecognized token {}{}{} \ between positions {l} and {r}.", - "\"".red(), - t.to_string().red(), - "\"".red(), - ); + "\"".red(), + t.to_string().red(), + "\"".red(), + ); - // // Temporary debug. - // err.push_str("Expected: "); - // let mut it = expected.iter().peekable(); - // while let Some(s) = it.next() { - // err.push('('); - // err.push_str(&format!("{}", s.green())); - // err.push(')'); - // if it.peek().is_some() { - // err.push(','); - // err.push(' '); - // } - // } - let right_new_line = - input_str[l..] - .find("\n") - .map(|pos| pos + l) - .unwrap_or(input_str.len()); - let left_new_line = - input_str[..r].rfind("\n") - .map(|pos| pos + 1) - .unwrap_or_default(); + // // Temporary debug. + // err.push_str("Expected: "); + // let mut it = expected.iter().peekable(); + // while let Some(s) = it.next() { + // err.push('('); + // err.push_str(&format!("{}", s.green())); + // err.push(')'); + // if it.peek().is_some() { + // err.push(','); + // err.push(' '); + // } + // } + let right_new_line = input_str[l..] + .find("\n") + .map(|pos| pos + l) + .unwrap_or(input_str.len()); + let left_new_line = input_str[..r] + .rfind("\n") + .map(|pos| pos + 1) + .unwrap_or_default(); - let line_number = - input_str[..l].match_indices('\n').count() + 1; - let pre_no_color = format!("{line_number} |"); - let pre = format!("{}", pre_no_color.blue()); + let line_number = input_str[..l].match_indices('\n').count() + 1; + let pre_no_color = format!("{line_number} |"); + let pre = format!("{}", pre_no_color.blue()); - let line_pos_l = l - left_new_line; - let line_pos_r = r - left_new_line; + let line_pos_l = l - left_new_line; + let line_pos_r = r - left_new_line; - err.push_str( - &format!("\nLine {} position {} to {}:\n{}{}{}{}", - line_number, - line_pos_l, - line_pos_r, - &pre, - &input_str[left_new_line..l].green(), - &input_str[l..r].red(), - &input_str[r..right_new_line], - ) - ); - err.push('\n'); - err.push_str(&" ".repeat(pre_no_color.len()-1)); - err.push_str(&format!("{}", "|".blue())); - err.push_str(&" ".repeat(l - left_new_line)); - err.push_str(&format!("{}", &"↑".red())); - if r - l > 2 { - err.push_str(&" ".repeat(r - l - 2)); - err.push_str(&format!("{}", &"↑".red())); - } + err.push_str(&format!( + "\nLine {} position {} to {}:\n{}{}{}{}", + line_number, + line_pos_l, + line_pos_r, + &pre, + &input_str[left_new_line..l].green(), + &input_str[l..r].red(), + &input_str[r..right_new_line], + )); + err.push('\n'); + err.push_str(&" ".repeat(pre_no_color.len() - 1)); + err.push_str(&format!("{}", "|".blue())); + err.push_str(&" ".repeat(l - left_new_line)); + err.push_str(&format!("{}", &"↑".red())); + if r - l > 2 { + err.push_str(&" ".repeat(r - l - 2)); + err.push_str(&format!("{}", &"↑".red())); + } - Err(err) - }, - ParseError::User { error } => { - Err(error.to_string()) - }, + Err(err) + } + ParseError::User { error } => Err(error.to_string()), } } @@ -310,10 +310,7 @@ fn save_file(contents: &String, path_string: String) -> Result<(), String> { let mut f = match fs::File::create(&path) { Ok(f) => f, - Err(_) => - return Err( - format!("Error creating file {}.", path.to_str().unwrap()) - ), + Err(_) => return Err(format!("Error creating file {}.", path.to_str().unwrap())), }; match write!(f, "{contents}") { Ok(_) => {} @@ -330,8 +327,7 @@ fn save_file(contents: &String, path_string: String) -> Result<(), String> { /// Equivalent main_do(stat) or main_do(stat, MissingE) pub fn stats(system: &EvaluatedSystem) -> Result { match system { - EvaluatedSystem::System { sys, translator } => - Ok(sys.statistics(translator)), + EvaluatedSystem::System { sys, translator } => Ok(sys.statistics(translator)), EvaluatedSystem::Graph { graph, translator } => { let Some(sys) = graph.node_weights().next() else { return Err("No node found in graph.".into()); @@ -346,8 +342,7 @@ pub fn stats(system: &EvaluatedSystem) -> Result { /// Equivalent to main_do(target, E) pub fn target(system: &EvaluatedSystem) -> Result { let (res, translator) = match system { - EvaluatedSystem::System { sys, translator } => - (sys.target()?, translator), + EvaluatedSystem::System { sys, translator } => (sys.target()?, translator), EvaluatedSystem::Graph { graph, translator } => { let Some(sys) = graph.node_weights().next() else { return Err("No node found in graph.".into()); @@ -368,9 +363,7 @@ pub fn target(system: &EvaluatedSystem) -> Result { /// equivalent to main_do(run,Es) pub fn traversed(system: &EvaluatedSystem) -> Result { let (res, translator) = match system { - EvaluatedSystem::System { sys, translator } => { - (sys.run_separated()?, translator) - } + EvaluatedSystem::System { sys, translator } => (sys.run_separated()?, translator), EvaluatedSystem::Graph { graph, translator } => { let Some(sys) = graph.node_weights().next() else { return Err("No node found in graph.".into()); @@ -383,10 +376,7 @@ pub fn traversed(system: &EvaluatedSystem) -> Result { output.push_str("The trace is composed by the set of entities: "); for (e, _c, _t) in res { - output.push_str(&format!( - "{}", - translator::Formatter::from(translator, &e) - )); + output.push_str(&format!("{}", translator::Formatter::from(translator, &e))); } Ok(output) } @@ -394,11 +384,8 @@ pub fn traversed(system: &EvaluatedSystem) -> Result { /// Finds the looping list of states in a reaction system with a perpetual /// context. IMPORTANT: for loops, we assume Delta defines the process constant /// x = Q.x and the context process is x . - /// equivalent to main_do(loop,Es) -pub fn hoop( - system: &EvaluatedSystem, - symbol: String -) -> Result { +/// equivalent to main_do(loop,Es) +pub fn hoop(system: &EvaluatedSystem, symbol: String) -> Result { use system::LoopSystem; let (res, translator) = match system { @@ -425,10 +412,7 @@ pub fn hoop( output.push_str("The loop is composed by the sets: "); for e in res { - output.push_str(&format!( - "{}", - translator::Formatter::from(translator, &e) - )); + output.push_str(&format!("{}", translator::Formatter::from(translator, &e))); } Ok(output) @@ -439,7 +423,7 @@ pub fn hoop( /// equivalent to main_do(freq, PairList) pub fn freq(system: &EvaluatedSystem) -> Result { use frequency::BasicFrequency; - + let (sys, translator) = match system { EvaluatedSystem::System { sys, translator } => (sys, translator), EvaluatedSystem::Graph { graph, translator } => { @@ -461,12 +445,9 @@ pub fn freq(system: &EvaluatedSystem) -> Result { /// Finds the frequency of each entity in the limit loop of a nonterminating /// Reaction System whose context has the form Q1 ... Q1.Q2 ... Q2 ... Qn ... /// equivalent to main_do(limitfreq, PairList) -pub fn limit_freq( - system: &mut EvaluatedSystem, - experiment: String -) -> Result { +pub fn limit_freq(system: &mut EvaluatedSystem, experiment: String) -> Result { use frequency::BasicFrequency; - + let (sys, translator): (&system::System, &mut Translator) = match system { EvaluatedSystem::System { sys, translator } => (sys, translator), EvaluatedSystem::Graph { graph, translator } => { @@ -479,12 +460,11 @@ pub fn limit_freq( let (_, sets) = read_file(translator, experiment, parser_experiment)?; - let res = - match frequency::Frequency::limit_frequency( - &sets, - &sys.reaction_rules, - &sys.available_entities) - { + let res = match frequency::Frequency::limit_frequency( + &sets, + &sys.reaction_rules, + &sys.available_entities, + ) { Some(e) => e, None => { return Err("Error calculating frequency.".into()); @@ -502,10 +482,7 @@ pub fn limit_freq( /// Q1 ... Q1.Q2 ... Q2 ... Qn ... Qn.nil and each Qi is repeated Wi times /// read from a corresponding file. /// equivalent to main_do(fastfreq, PairList) -pub fn fast_freq( - system: &mut EvaluatedSystem, - experiment: String -) -> Result { +pub fn fast_freq(system: &mut EvaluatedSystem, experiment: String) -> Result { use frequency::BasicFrequency; let (sys, translator): (&system::System, &mut Translator) = match system { @@ -520,18 +497,17 @@ pub fn fast_freq( let (weights, sets) = read_file(translator, experiment, parser_experiment)?; - let res = - match frequency::Frequency::fast_frequency( - &sets, - &sys.reaction_rules, - &sys.available_entities, - &weights, - ) { - Some(e) => e, - None => { - return Err("Error calculating frequency.".into()); - } - }; + let res = match frequency::Frequency::fast_frequency( + &sets, + &sys.reaction_rules, + &sys.available_entities, + &weights, + ) { + Some(e) => e, + None => { + return Err("Error calculating frequency.".into()); + } + }; Ok(format!( "Frequency of encountered symbols:\n{}", @@ -543,11 +519,10 @@ pub fn fast_freq( /// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs) pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> { if let EvaluatedSystem::System { sys, translator } = system { - *system = - EvaluatedSystem::Graph { - graph: sys.clone().digraph()?, - translator: translator.to_owned(), - }; + *system = EvaluatedSystem::Graph { + graph: sys.clone().digraph()?, + translator: translator.to_owned(), + }; } Ok(()) } @@ -556,52 +531,60 @@ pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> { pub fn bisimilar( system_a: &mut EvaluatedSystem, edge_relabeler: &super::assert::types::Assert, - system_b: String -) -> Result -{ + system_b: String, +) -> Result { use super::assert::types::AssertReturnValue; - let system_b = read_file(system_a.get_translator(), - system_b.to_string(), - parser_instructions)?; - let mut system_b = - match system_b.system.compute(system_a.get_translator().clone())? { - EvaluatedSystem::System { sys, translator } => - EvaluatedSystem::System { sys, translator }, - EvaluatedSystem::Graph { graph, translator } => { - if translator != *system_a.get_translator() { - return Err("Bisimilarity not implemented for systems with \ + let system_b = read_file( + system_a.get_translator(), + system_b.to_string(), + parser_instructions, + )?; + let mut system_b = match system_b.system.compute(system_a.get_translator().clone())? { + EvaluatedSystem::System { sys, translator } => EvaluatedSystem::System { sys, translator }, + EvaluatedSystem::Graph { graph, translator } => { + if translator != *system_a.get_translator() { + return Err("Bisimilarity not implemented for systems with \ different encodings. Serialize the systems \ - with the same translator.".into()); - } - EvaluatedSystem::Graph { graph, translator } - } - }; + with the same translator." + .into()); + } + EvaluatedSystem::Graph { graph, translator } + } + }; digraph(system_a)?; digraph(&mut system_b)?; // since we ran digraph on both they have to be graphs match (system_a, &mut system_b) { - (EvaluatedSystem::Graph { graph: a, translator: _ }, - EvaluatedSystem::Graph { graph: b, translator: translator_b }) => { - let a: Graph = - a.map_edges(edge_relabeler, translator_b)?; - let b: Graph = - b.map_edges(edge_relabeler, translator_b)?; - Ok(format!( - "{}", - // super::bisimilarity::bisimilarity_kanellakis_smolka::bisimilarity(&&a, &&b) - // super::bisimilarity::bisimilarity_paige_tarjan::bisimilarity_ignore_labels(&&a, &&b) - super::bisimilarity::bisimilarity_paige_tarkan::bisimilarity(&&a, &&b) - )) - }, - _ => { unreachable!() } + ( + EvaluatedSystem::Graph { + graph: a, + translator: _, + }, + EvaluatedSystem::Graph { + graph: b, + translator: translator_b, + }, + ) => { + let a: Graph = + a.map_edges(edge_relabeler, translator_b)?; + let b: Graph = + b.map_edges(edge_relabeler, translator_b)?; + Ok(format!( + "{}", + // super::bisimilarity::bisimilarity_kanellakis_smolka::bisimilarity(&&a, &&b) + // super::bisimilarity::bisimilarity_paige_tarjan::bisimilarity_ignore_labels(&&a, &&b) + super::bisimilarity::bisimilarity_paige_tarkan::bisimilarity(&&a, &&b) + )) + } + _ => { + unreachable!() + } } } - - // ----------------------------------------------------------------------------- // Output Functions // ----------------------------------------------------------------------------- @@ -612,7 +595,7 @@ pub fn dot( node_display: graph::NodeDisplay, edge_display: graph::EdgeDisplay, node_color: graph::NodeColor, - edge_color: graph::EdgeColor + edge_color: graph::EdgeColor, ) -> Result { match system { EvaluatedSystem::System { @@ -629,17 +612,11 @@ pub fn dot( let graph = Rc::new(graph.to_owned()); let node_formatter = - node_color.generate(Rc::clone(&graph), - translator.encode_not_mut("*")); - let edge_formatter = - edge_color.generate(Rc::clone(&graph)); + node_color.generate(Rc::clone(&graph), translator.encode_not_mut("*")); + let edge_formatter = edge_color.generate(Rc::clone(&graph)); - let dot = dot::Dot::with_attr_getters( - &modified_graph, - &[], - &edge_formatter, - &node_formatter, - ); + let dot = + dot::Dot::with_attr_getters(&modified_graph, &[], &edge_formatter, &node_formatter); Ok(format!("{dot}")) } @@ -662,10 +639,8 @@ pub fn graphml( // map each value to the corresponding value we want to display let modified_graph = graph.map( - node_display.generate(Rc::clone(&rc_translator), - graph), - edge_display.generate(rc_translator, - graph), + node_display.generate(Rc::clone(&rc_translator), graph), + edge_display.generate(rc_translator, graph), ); use petgraph_graphml::GraphMl; @@ -695,8 +670,7 @@ pub fn serialize(system: &EvaluatedSystem, path: String) -> Result<(), String> { let f = match fs::File::create(&path) { Ok(f) => f, - Err(_) => return Err(format!("Error creating file {}.", - path.to_str().unwrap())), + Err(_) => return Err(format!("Error creating file {}.", path.to_str().unwrap())), }; match serialize::ser(f, graph, translator) { @@ -710,10 +684,7 @@ pub fn serialize(system: &EvaluatedSystem, path: String) -> Result<(), String> { /// Reads the specified serialized system from a file. /// N.B. graph size in memory might be much larger after serialization and /// deserialization -pub fn deserialize( - input_path: String, -) -> Result<(graph::SystemGraph, Translator), String> -{ +pub fn deserialize(input_path: String) -> Result<(graph::SystemGraph, Translator), String> { // relative path let mut path = match env::current_dir() { Ok(p) => p, @@ -724,8 +695,7 @@ pub fn deserialize( let f = match fs::File::open(&path) { Ok(f) => f, - Err(_) => return Err(format!("Error opening file {}.", - path.to_str().unwrap())), + Err(_) => return Err(format!("Error opening file {}.", path.to_str().unwrap())), }; match serialize::de(f) { @@ -753,10 +723,7 @@ macro_rules! save_options { }; } -fn execute( - instruction: Instruction, - system: &mut EvaluatedSystem -) -> Result<(), String> { +fn execute(instruction: Instruction, system: &mut EvaluatedSystem) -> Result<(), String> { match instruction { Instruction::Stats { so } => { save_options!(stats(system)?, so); @@ -786,8 +753,8 @@ fn execute( GraphSaveOptions::Dot { node_display: nd, edge_display: ed, - node_color: nc, - edge_color: ec, + node_color: nc, + edge_color: ec, so, } => { save_options!(dot(system, nd, ed, nc, ec)?, so); @@ -805,10 +772,14 @@ fn execute( } } } - Instruction::Bisimilarity { system_b, edge_relabeler, so } => { - edge_relabeler.typecheck()?; - save_options!(bisimilar(system, &edge_relabeler, system_b)?, so); - } + Instruction::Bisimilarity { + system_b, + edge_relabeler, + so, + } => { + edge_relabeler.typecheck()?; + save_options!(bisimilar(system, &edge_relabeler, system_b)?, so); + } } Ok(()) } diff --git a/src/rsprocess/process.rs b/src/rsprocess/process.rs index c41fa66..ad8a404 100644 --- a/src/rsprocess/process.rs +++ b/src/rsprocess/process.rs @@ -4,15 +4,16 @@ use std::fmt::Debug; use std::hash::Hash; use std::rc::Rc; +use super::element::{IdState, IdType}; use super::reaction::{PositiveReaction, Reaction}; use super::set::{BasicSet, PositiveSet, Set}; -use super::element::{IdState, IdType}; -use super::translator::{Translator, PrintableWithTranslator, Formatter}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; pub trait BasicProcess -where Self: Clone + Debug + Default + PartialEq + Eq + Hash + Serialize + - PrintableWithTranslator, -for<'a> Self: Deserialize<'a> { +where + Self: Clone + Debug + Default + PartialEq + Eq + Hash + Serialize + PrintableWithTranslator, + for<'a> Self: Deserialize<'a>, +{ type Id; type Set: BasicSet; @@ -27,26 +28,26 @@ for<'a> Self: Deserialize<'a> { pub enum Process { Nill, RecursiveIdentifier { - identifier: IdType, + identifier: IdType, }, EntitySet { - entities: Set, - next_process: Rc, + entities: Set, + next_process: Rc, }, Guarded { - reaction: Reaction, - next_process: Rc, + reaction: Reaction, + next_process: Rc, }, WaitEntity { - repeat: i64, - repeated_process: Rc, - next_process: Rc, + repeat: i64, + repeated_process: Rc, + next_process: Rc, }, Summation { - children: Vec>, + children: Vec>, }, NondeterministicChoice { - children: Vec>, + children: Vec>, }, } @@ -55,172 +56,170 @@ impl BasicProcess for Process { type Set = Set; fn concat(&self, new: &Self) -> Self { - match (self, new) { - ( - Self::NondeterministicChoice { children: c1 }, - Self::NondeterministicChoice { children: c2 }, - ) => Self::NondeterministicChoice { - children: [c1.clone(), c2.clone()].concat(), - }, - (Self::NondeterministicChoice { children }, new) - | (new, Self::NondeterministicChoice { children }) => { - let mut new_children = children.clone(); - new_children.push(Rc::new(new.clone())); - Self::NondeterministicChoice { - children: new_children, - } - } - (_, _) => Self::NondeterministicChoice { - children: vec![Rc::new(self.clone()), Rc::new(new.clone())], - }, - } + match (self, new) { + ( + Self::NondeterministicChoice { children: c1 }, + Self::NondeterministicChoice { children: c2 }, + ) => Self::NondeterministicChoice { + children: [c1.clone(), c2.clone()].concat(), + }, + (Self::NondeterministicChoice { children }, new) + | (new, Self::NondeterministicChoice { children }) => { + let mut new_children = children.clone(); + new_children.push(Rc::new(new.clone())); + Self::NondeterministicChoice { + children: new_children, + } + } + (_, _) => Self::NondeterministicChoice { + children: vec![Rc::new(self.clone()), Rc::new(new.clone())], + }, + } } /// returns all elements used fn all_elements(&self) -> Self::Set { - let mut queue = VecDeque::from([self]); - let mut elements = Self::Set::default(); + let mut queue = VecDeque::from([self]); + let mut elements = Self::Set::default(); - while let Some(el) = queue.pop_front() { - match el { - Self::Nill => {} - Self::RecursiveIdentifier { identifier: _ } => {} - Self::EntitySet { - entities, - next_process, - } => { - elements.push(entities); - queue.push_back(next_process); - } - Self::Guarded { reaction, next_process } => { - elements.push(&reaction.reactants); - elements.push(&reaction.inhibitors); - elements.push(&reaction.products); - queue.push_back(next_process); - } - Self::WaitEntity { - repeat: _, - repeated_process, - next_process, - } => { - queue.push_back(repeated_process); - queue.push_back(next_process); - } - Self::Summation { children } => { - for c in children { - queue.push_back(c); - } - } - Self::NondeterministicChoice { children } => { - for c in children { - queue.push_back(c); - } - } - } - } - elements + while let Some(el) = queue.pop_front() { + match el { + Self::Nill => {} + Self::RecursiveIdentifier { identifier: _ } => {} + Self::EntitySet { + entities, + next_process, + } => { + elements.push(entities); + queue.push_back(next_process); + } + Self::Guarded { + reaction, + next_process, + } => { + elements.push(&reaction.reactants); + elements.push(&reaction.inhibitors); + elements.push(&reaction.products); + queue.push_back(next_process); + } + Self::WaitEntity { + repeat: _, + repeated_process, + next_process, + } => { + queue.push_back(repeated_process); + queue.push_back(next_process); + } + Self::Summation { children } => { + for c in children { + queue.push_back(c); + } + } + Self::NondeterministicChoice { children } => { + for c in children { + queue.push_back(c); + } + } + } + } + elements } /// Finds only the rules X = pre(Q, rec(X)), but not only x = pre(Q, rec(x)) /// to use in filter_map. - fn filter_delta<'a>( - &'a self, - id: &Self::Id - ) -> Option<&'a Self::Set> { - if let Self::EntitySet { entities, next_process } = self - && let Self::RecursiveIdentifier { identifier } = &**next_process - && identifier == id - { - return Some(entities); - } + fn filter_delta<'a>(&'a self, id: &Self::Id) -> Option<&'a Self::Set> { + if let Self::EntitySet { + entities, + next_process, + } = self + && let Self::RecursiveIdentifier { identifier } = &**next_process + && identifier == id + { + return Some(entities); + } - None + None } } impl Default for Process { fn default() -> Self { - Self::Nill + Self::Nill } } impl PrintableWithTranslator for Process { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - match self { - Self::Nill => { - write!(f, "Nill") - }, - Self::RecursiveIdentifier { identifier } => { - write!(f, - "[{}]", - translator - .decode(*identifier) - .unwrap_or("Missing".into())) - }, - Self::EntitySet { entities, next_process, } => { - write!( - f, - "{}.{}", - Formatter::from(translator, entities), - Formatter::from(translator, &**next_process) - ) - }, - Self::Guarded { reaction, next_process } => { - write!(f, - "?{}?.{}", - Formatter::from(translator, reaction), - Formatter::from(translator, &**next_process)) - }, - Self::WaitEntity { repeat, repeated_process, next_process, } => { - write!( - f, - "({})^{repeat}.{}", - Formatter::from(translator, &**repeated_process), - Formatter::from(translator, &**next_process) - ) - } - Self::Summation { children } => { - write!(f, "[")?; - let mut it = children.iter().peekable(); - while let Some(child) = it.next() { - if it.peek().is_none() { - write!( - f, - "{}", - Formatter::from(translator, &**child) - )?; - } else { - write!( - f, - "{} + ", - Formatter::from(translator, &**child) - )?; - } - } - write!(f, "]") - } - Self::NondeterministicChoice { children } => { - write!(f, "[")?; - let mut it = children.iter().peekable(); - while let Some(child) = it.next() { - if it.peek().is_none() { - write!( - f, - "{}", - Formatter::from(translator, &**child) - )?; - } else { - write!( - f, - "{}, ", - Formatter::from(translator, &**child) - )?; - } - } - write!(f, "]") - } - } + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + match self { + Self::Nill => { + write!(f, "Nill") + } + Self::RecursiveIdentifier { identifier } => { + write!( + f, + "[{}]", + translator.decode(*identifier).unwrap_or("Missing".into()) + ) + } + Self::EntitySet { + entities, + next_process, + } => { + write!( + f, + "{}.{}", + Formatter::from(translator, entities), + Formatter::from(translator, &**next_process) + ) + } + Self::Guarded { + reaction, + next_process, + } => { + write!( + f, + "?{}?.{}", + Formatter::from(translator, reaction), + Formatter::from(translator, &**next_process) + ) + } + Self::WaitEntity { + repeat, + repeated_process, + next_process, + } => { + write!( + f, + "({})^{repeat}.{}", + Formatter::from(translator, &**repeated_process), + Formatter::from(translator, &**next_process) + ) + } + Self::Summation { children } => { + write!(f, "[")?; + let mut it = children.iter().peekable(); + while let Some(child) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, &**child))?; + } else { + write!(f, "{} + ", Formatter::from(translator, &**child))?; + } + } + write!(f, "]") + } + Self::NondeterministicChoice { children } => { + write!(f, "[")?; + let mut it = children.iter().peekable(); + while let Some(child) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, &**child))?; + } else { + write!(f, "{}, ", Formatter::from(translator, &**child))?; + } + } + write!(f, "]") + } + } } } @@ -230,26 +229,26 @@ impl PrintableWithTranslator for Process { pub enum PositiveProcess { Nill, RecursiveIdentifier { - identifier: IdType, + identifier: IdType, }, EntitySet { - entities: PositiveSet, - next_process: Rc, + entities: PositiveSet, + next_process: Rc, }, Guarded { - reaction: PositiveReaction, - next_process: Rc, + reaction: PositiveReaction, + next_process: Rc, }, WaitEntity { - repeat: i64, - repeated_process: Rc, - next_process: Rc, + repeat: i64, + repeated_process: Rc, + next_process: Rc, }, Summation { - children: Vec>, + children: Vec>, }, NondeterministicChoice { - children: Vec>, + children: Vec>, }, } @@ -258,211 +257,224 @@ impl BasicProcess for PositiveProcess { type Set = PositiveSet; fn concat(&self, new: &Self) -> Self { - match (self, new) { - ( - Self::NondeterministicChoice { children: c1 }, - Self::NondeterministicChoice { children: c2 }, - ) => Self::NondeterministicChoice { - children: [c1.clone(), c2.clone()].concat(), - }, - (Self::NondeterministicChoice { children }, new) - | (new, Self::NondeterministicChoice { children }) => { - let mut new_children = children.clone(); - new_children.push(Rc::new(new.clone())); - Self::NondeterministicChoice { - children: new_children, - } - } - (_, _) => Self::NondeterministicChoice { - children: vec![Rc::new(self.clone()), Rc::new(new.clone())], - }, - } + match (self, new) { + ( + Self::NondeterministicChoice { children: c1 }, + Self::NondeterministicChoice { children: c2 }, + ) => Self::NondeterministicChoice { + children: [c1.clone(), c2.clone()].concat(), + }, + (Self::NondeterministicChoice { children }, new) + | (new, Self::NondeterministicChoice { children }) => { + let mut new_children = children.clone(); + new_children.push(Rc::new(new.clone())); + Self::NondeterministicChoice { + children: new_children, + } + } + (_, _) => Self::NondeterministicChoice { + children: vec![Rc::new(self.clone()), Rc::new(new.clone())], + }, + } } /// returns all elements used fn all_elements(&self) -> Self::Set { - let mut queue = VecDeque::from([self]); - let mut elements = Self::Set::default(); + let mut queue = VecDeque::from([self]); + let mut elements = Self::Set::default(); - while let Some(el) = queue.pop_front() { - match el { - Self::Nill => {} - Self::RecursiveIdentifier { identifier: _ } => {} - Self::EntitySet { - entities, - next_process, - } => { - elements.push(entities); - queue.push_back(next_process); - } - Self::Guarded { reaction, next_process } => { - elements.push(&reaction.reactants); - elements.push(&reaction.products); - queue.push_back(next_process); - } - Self::WaitEntity { - repeat: _, - repeated_process, - next_process, - } => { - queue.push_back(repeated_process); - queue.push_back(next_process); - } - Self::Summation { children } => { - for c in children { - queue.push_back(c); - } - } - Self::NondeterministicChoice { children } => { - for c in children { - queue.push_back(c); - } - } - } - } - elements + while let Some(el) = queue.pop_front() { + match el { + Self::Nill => {} + Self::RecursiveIdentifier { identifier: _ } => {} + Self::EntitySet { + entities, + next_process, + } => { + elements.push(entities); + queue.push_back(next_process); + } + Self::Guarded { + reaction, + next_process, + } => { + elements.push(&reaction.reactants); + elements.push(&reaction.products); + queue.push_back(next_process); + } + Self::WaitEntity { + repeat: _, + repeated_process, + next_process, + } => { + queue.push_back(repeated_process); + queue.push_back(next_process); + } + Self::Summation { children } => { + for c in children { + queue.push_back(c); + } + } + Self::NondeterministicChoice { children } => { + for c in children { + queue.push_back(c); + } + } + } + } + elements } /// Finds only the rules X = pre(Q, rec(X)), but not only x = pre(Q, rec(x)) /// to use in filter_map. fn filter_delta(&self, id: &Self::Id) -> Option<&Self::Set> { - if let Self::EntitySet { entities, next_process } = self - && let Self::RecursiveIdentifier { identifier } = &**next_process - && identifier == id - { - return Some(entities); - } + if let Self::EntitySet { + entities, + next_process, + } = self + && let Self::RecursiveIdentifier { identifier } = &**next_process + && identifier == id + { + return Some(entities); + } - None + None } } impl Default for PositiveProcess { fn default() -> Self { - Self::Nill + Self::Nill } } impl PrintableWithTranslator for PositiveProcess { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - match self { - Self::Nill => { - write!(f, "Nill") - }, - Self::RecursiveIdentifier { identifier } => { - write!(f, - "[{}]", - translator - .decode(*identifier) - .unwrap_or("Missing".into())) - }, - Self::EntitySet { entities, next_process, } => { - write!( - f, - "{}.{}", - Formatter::from(translator, entities), - Formatter::from(translator, &**next_process) - ) - }, - Self::Guarded { reaction, next_process } => { - write!(f, - "?{}?.{}", - Formatter::from(translator, reaction), - Formatter::from(translator, &**next_process)) - }, - Self::WaitEntity { repeat, repeated_process, next_process, } => { - write!( - f, - "({})^{repeat}.{}", - Formatter::from(translator, &**repeated_process), - Formatter::from(translator, &**next_process) - ) - } - Self::Summation { children } => { - write!(f, "[")?; - let mut it = children.iter().peekable(); - while let Some(child) = it.next() { - if it.peek().is_none() { - write!( - f, - "{}", - Formatter::from(translator, &**child) - )?; - } else { - write!( - f, - "{} + ", - Formatter::from(translator, &**child) - )?; - } - } - write!(f, "]") - } - Self::NondeterministicChoice { children } => { - write!(f, "[")?; - let mut it = children.iter().peekable(); - while let Some(child) = it.next() { - if it.peek().is_none() { - write!( - f, - "{}", - Formatter::from(translator, &**child) - )?; - } else { - write!( - f, - "{}, ", - Formatter::from(translator, &**child) - )?; - } - } - write!(f, "]") - } - } + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + match self { + Self::Nill => { + write!(f, "Nill") + } + Self::RecursiveIdentifier { identifier } => { + write!( + f, + "[{}]", + translator.decode(*identifier).unwrap_or("Missing".into()) + ) + } + Self::EntitySet { + entities, + next_process, + } => { + write!( + f, + "{}.{}", + Formatter::from(translator, entities), + Formatter::from(translator, &**next_process) + ) + } + Self::Guarded { + reaction, + next_process, + } => { + write!( + f, + "?{}?.{}", + Formatter::from(translator, reaction), + Formatter::from(translator, &**next_process) + ) + } + Self::WaitEntity { + repeat, + repeated_process, + next_process, + } => { + write!( + f, + "({})^{repeat}.{}", + Formatter::from(translator, &**repeated_process), + Formatter::from(translator, &**next_process) + ) + } + Self::Summation { children } => { + write!(f, "[")?; + let mut it = children.iter().peekable(); + while let Some(child) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, &**child))?; + } else { + write!(f, "{} + ", Formatter::from(translator, &**child))?; + } + } + write!(f, "]") + } + Self::NondeterministicChoice { children } => { + write!(f, "[")?; + let mut it = children.iter().peekable(); + while let Some(child) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, &**child))?; + } else { + write!(f, "{}, ", Formatter::from(translator, &**child))?; + } + } + write!(f, "]") + } + } } } impl From<&Process> for PositiveProcess { fn from(value: &Process) -> Self { - match value { - Process::Nill => Self::Nill, - Process::EntitySet { entities, next_process } => - Self::EntitySet { - entities: entities.to_positive_set(IdState::Positive), - next_process: Rc::new((&**next_process).into()) }, - Process::RecursiveIdentifier { identifier } => - Self::RecursiveIdentifier { identifier: *identifier }, - Process::Guarded { reaction, next_process } => // TODO: is this right? - Self::Guarded { - reaction: PositiveReaction { - reactants: reaction.reactants - .to_positive_set(IdState::Positive) - .union(&reaction.inhibitors - .to_positive_set(IdState::Negative)), - products: reaction.products - .to_positive_set(IdState::Positive) - }, - next_process: Rc::new((&**next_process).into())}, - Process::WaitEntity { repeat, repeated_process, next_process } => - Self::WaitEntity { - repeat: *repeat, - repeated_process: Rc::new((&**repeated_process).into()), - next_process: Rc::new((&**next_process).into()) }, - Process::Summation { children } => - Self::Summation { - children: children.iter().map(|c| Rc::new((&**c).into())) - .collect() }, - Process::NondeterministicChoice { children } => - Self::NondeterministicChoice { - children: children.iter().map(|c| Rc::new((&**c).into())) - .collect() } - } + match value { + Process::Nill => Self::Nill, + Process::EntitySet { + entities, + next_process, + } => Self::EntitySet { + entities: entities.to_positive_set(IdState::Positive), + next_process: Rc::new((&**next_process).into()), + }, + Process::RecursiveIdentifier { identifier } => Self::RecursiveIdentifier { + identifier: *identifier, + }, + Process::Guarded { + reaction, + next_process, + } => + // TODO: is this right? + { + Self::Guarded { + reaction: PositiveReaction { + reactants: reaction + .reactants + .to_positive_set(IdState::Positive) + .union(&reaction.inhibitors.to_positive_set(IdState::Negative)), + products: reaction.products.to_positive_set(IdState::Positive), + }, + next_process: Rc::new((&**next_process).into()), + } + } + Process::WaitEntity { + repeat, + repeated_process, + next_process, + } => Self::WaitEntity { + repeat: *repeat, + repeated_process: Rc::new((&**repeated_process).into()), + next_process: Rc::new((&**next_process).into()), + }, + Process::Summation { children } => Self::Summation { + children: children.iter().map(|c| Rc::new((&**c).into())).collect(), + }, + Process::NondeterministicChoice { children } => Self::NondeterministicChoice { + children: children.iter().map(|c| Rc::new((&**c).into())).collect(), + }, + } } } -impl Fromfor PositiveProcess { +impl From for PositiveProcess { fn from(value: Process) -> Self { - (&value).into() + (&value).into() } } diff --git a/src/rsprocess/reaction.rs b/src/rsprocess/reaction.rs index 96a3843..b1d2ee3 100644 --- a/src/rsprocess/reaction.rs +++ b/src/rsprocess/reaction.rs @@ -7,12 +7,12 @@ use serde::{Deserialize, Serialize}; use std::hash::Hash; use super::element::{IdState, IdType}; -use super::set::{BasicSet, ExtensionsSet, Set, PositiveSet}; -use super::translator::{Translator, PrintableWithTranslator, Formatter}; +use super::set::{BasicSet, ExtensionsSet, PositiveSet, Set}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; -pub trait BasicReaction: -Clone + Default + Eq + Hash + Serialize + PrintableWithTranslator -where for<'de> Self: Deserialize<'de>, +pub trait BasicReaction: Clone + Default + Eq + Hash + Serialize + PrintableWithTranslator +where + for<'de> Self: Deserialize<'de>, { type Set: BasicSet; fn enabled(&self, state: &Self::Set) -> bool; @@ -25,27 +25,23 @@ pub trait ExtensionReaction: Sized { fn compute_all(reactions: &[Self], state: &Self::Set) -> Self::Set; fn find_loop( - reactions: &[Self], - entities: Self::Set, - q: &Self::Set + reactions: &[Self], + entities: Self::Set, + q: &Self::Set, ) -> (Vec, Vec); - fn find_only_loop( - reactions: &[Self], - entities: &Self::Set, - q: &Self::Set - ) -> Vec; + fn find_only_loop(reactions: &[Self], entities: &Self::Set, q: &Self::Set) -> Vec; fn find_prefix_len_loop( - reactions: &[Self], - entities: Self::Set, - q: &Self::Set + reactions: &[Self], + entities: Self::Set, + q: &Self::Set, ) -> (usize, Vec); fn lollipops_only_loop_decomposed_q( - reactions: &[Self], - entities: &Self::Set, - q: &Self::Set + reactions: &[Self], + entities: &Self::Set, + q: &Self::Set, ) -> Vec; } @@ -56,94 +52,71 @@ impl, Set: BasicSet> ExtensionReaction for T { /// Computes the result of a series of reactions. Returns the union of all /// products. /// see result - fn compute_all( - reactions: &[Self], - state: &Set - ) -> Set - where Self: Sized { - reactions.iter().fold(Set::default(), |mut acc: Set, r| { - acc.extend(r.compute_step(state)); - acc - }) + fn compute_all(reactions: &[Self], state: &Set) -> Set + where + Self: Sized, + { + reactions.iter().fold(Set::default(), |mut acc: Set, r| { + acc.extend(r.compute_step(state)); + acc + }) } /// Finds the loops by simulating the system. - fn find_loop( - reactions: &[Self], - entities: Set, - q: &Set - ) -> (Vec, Vec) { - let mut entities = entities; - let mut trace = vec![]; - loop { - if let Some((prefix, hoop)) = entities.split(&trace) { - return (prefix.to_vec(), hoop.to_vec()); - } else { - let t = entities.union(q); - let products = Self::compute_all(reactions, &t); - trace.push(entities.clone()); - entities = products; - } - } + fn find_loop(reactions: &[Self], entities: Set, q: &Set) -> (Vec, Vec) { + let mut entities = entities; + let mut trace = vec![]; + loop { + if let Some((prefix, hoop)) = entities.split(&trace) { + return (prefix.to_vec(), hoop.to_vec()); + } else { + let t = entities.union(q); + let products = Self::compute_all(reactions, &t); + trace.push(entities.clone()); + entities = products; + } + } } /// Finds the loops by simulating the system. - fn find_only_loop( - reactions: &[Self], - entities: &Set, - q: &Set - ) -> Vec { - let mut entities = entities.clone(); - let mut trace = vec![]; - loop { - if let Some((_prefix, hoop)) = entities.split(&trace) { - return hoop.to_vec(); - } else { - let t = entities.union(q); - let products = Self::compute_all(reactions, &t); - trace.push(entities.clone()); - entities = products; - } - } + fn find_only_loop(reactions: &[Self], entities: &Set, q: &Set) -> Vec { + let mut entities = entities.clone(); + let mut trace = vec![]; + loop { + if let Some((_prefix, hoop)) = entities.split(&trace) { + return hoop.to_vec(); + } else { + let t = entities.union(q); + let products = Self::compute_all(reactions, &t); + trace.push(entities.clone()); + entities = products; + } + } } /// Finds the loops and the length of the prefix by simulating the system. - fn find_prefix_len_loop( - reactions: &[Self], - entities: Set, - q: &Set - ) -> (usize, Vec) { - let mut entities = entities; - let mut trace = vec![]; - loop { - if let Some((prefix, hoop)) = entities.split(&trace) { - return (prefix.len(), hoop.to_vec()); - } else { - let t = entities.union(q); - let products = Self::compute_all(reactions, &t); - trace.push(entities.clone()); - entities = products; - } - } + fn find_prefix_len_loop(reactions: &[Self], entities: Set, q: &Set) -> (usize, Vec) { + let mut entities = entities; + let mut trace = vec![]; + loop { + if let Some((prefix, hoop)) = entities.split(&trace) { + return (prefix.len(), hoop.to_vec()); + } else { + let t = entities.union(q); + let products = Self::compute_all(reactions, &t); + trace.push(entities.clone()); + entities = products; + } + } } /// see loop/5 - fn lollipops_only_loop_decomposed_q( - reactions: &[Self], - entities: &Set, - q: &Set, - ) -> Vec { - let find_loop_fn = - |q| Self::find_only_loop(reactions, - entities, - q); - find_loop_fn(q) + fn lollipops_only_loop_decomposed_q(reactions: &[Self], entities: &Set, q: &Set) -> Vec { + let find_loop_fn = |q| Self::find_only_loop(reactions, entities, q); + find_loop_fn(q) } } - - - // ----------------------------------------------------------------------------- /// Basic structure for a reaction. @@ -160,61 +133,55 @@ impl BasicReaction for Reaction { /// returns true if ```current_state``` enables the reaction /// see enable fn enabled(&self, current_state: &Self::Set) -> bool { - self.reactants.is_subset(current_state) - && self.inhibitors.is_disjoint(current_state) + self.reactants.is_subset(current_state) && self.inhibitors.is_disjoint(current_state) } /// Computes the result of a single reaction (if enabled returns the /// products) otherwise returns None. /// see result fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { - if self.enabled(state) { - Some(&self.products) - } else { - None - } + if self.enabled(state) { + Some(&self.products) + } else { + None + } } } impl PrintableWithTranslator for Reaction { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "(r: {}, i: {}, p: {})", - Formatter::from(translator, &self.reactants), - Formatter::from(translator, &self.inhibitors), - Formatter::from(translator, &self.products) - ) + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!( + f, + "(r: {}, i: {}, p: {})", + Formatter::from(translator, &self.reactants), + Formatter::from(translator, &self.inhibitors), + Formatter::from(translator, &self.products) + ) } } impl Reaction { pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self { - Reaction { reactants, inhibitors, products } + Reaction { + reactants, + inhibitors, + products, + } } pub fn all_products(reactions: &[Self]) -> Set { - reactions.iter().fold( - Set::default(), - |acc, r| - acc.union(&r.products) - ) + reactions + .iter() + .fold(Set::default(), |acc, r| acc.union(&r.products)) } - pub fn all_reactions_with_product<'a>( - reactions: &'a [Self], - el: &IdType - ) -> Vec<&'a Self> { - reactions.iter().fold( - vec![], - |mut acc, r| { - if r.products.contains(el) { - acc.push(r); - } - acc - } - ) + pub fn all_reactions_with_product<'a>(reactions: &'a [Self], el: &IdType) -> Vec<&'a Self> { + reactions.iter().fold(vec![], |mut acc, r| { + if r.products.contains(el) { + acc.push(r); + } + acc + }) } } @@ -223,47 +190,50 @@ impl Reaction { #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct PositiveReaction { pub reactants: PositiveSet, - pub products: PositiveSet + pub products: PositiveSet, } impl BasicReaction for PositiveReaction { type Set = PositiveSet; fn enabled(&self, state: &Self::Set) -> bool { - self.reactants.is_subset(state) + self.reactants.is_subset(state) } fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { - if self.enabled(state) { - Some(&self.products) - } else { - None - } + if self.enabled(state) { + Some(&self.products) + } else { + None + } } } impl PrintableWithTranslator for PositiveReaction { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "(r: {}, p: {})", - Formatter::from(translator, &self.reactants), - Formatter::from(translator, &self.products), - ) + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!( + f, + "(r: {}, p: {})", + Formatter::from(translator, &self.reactants), + Formatter::from(translator, &self.products), + ) } } impl PositiveReaction { pub fn from(reactants: PositiveSet, products: PositiveSet) -> Self { - Self { reactants, products } + Self { + reactants, + products, + } } pub fn create(reactants: Set, inhibitors: Set, products: Set) -> Self { - Self { reactants: - reactants.to_positive_set(IdState::Positive).union( - &inhibitors.to_positive_set(IdState::Negative) - ), - products: products.to_positive_set(IdState::Positive) } + Self { + reactants: reactants + .to_positive_set(IdState::Positive) + .union(&inhibitors.to_positive_set(IdState::Negative)), + products: products.to_positive_set(IdState::Positive), + } } } diff --git a/src/rsprocess/serialize.rs b/src/rsprocess/serialize.rs index f7a21ac..48d4dea 100644 --- a/src/rsprocess/serialize.rs +++ b/src/rsprocess/serialize.rs @@ -5,37 +5,37 @@ use std::io; -use serde::{Deserialize, Serialize}; use super::graph; +use serde::{Deserialize, Serialize}; use super::translator::Translator; #[derive(Serialize, Deserialize)] struct GraphAndTranslator { graph: graph::SystemGraph, - translator: Translator + translator: Translator, } /// Serializer for graph and translator. pub fn ser( writer: W, graph: &graph::SystemGraph, - translator: &Translator + translator: &Translator, ) -> Result<(), serde_cbor_2::Error> where W: io::Write, { - serde_cbor_2::to_writer(writer, - &GraphAndTranslator { - graph: graph.clone(), - translator: translator.clone() - }) + serde_cbor_2::to_writer( + writer, + &GraphAndTranslator { + graph: graph.clone(), + translator: translator.clone(), + }, + ) } /// Deserializer for file that contains graph and translator. -pub fn de( - reader: R -) -> Result<(graph::SystemGraph, Translator), serde_cbor_2::Error> +pub fn de(reader: R) -> Result<(graph::SystemGraph, Translator), serde_cbor_2::Error> where R: io::Read, { diff --git a/src/rsprocess/set.rs b/src/rsprocess/set.rs index 7f08302..6381f5a 100644 --- a/src/rsprocess/set.rs +++ b/src/rsprocess/set.rs @@ -1,18 +1,18 @@ use serde::{Deserialize, Serialize}; -use std::collections::{BTreeSet, BTreeMap}; -use std::hash::Hash; +use std::collections::{BTreeMap, BTreeSet}; use std::fmt; +use std::hash::Hash; -use super::translator::{Formatter, Translator, PrintableWithTranslator}; -use super::element::{IdType, PositiveType, IdState}; +use super::element::{IdState, IdType, PositiveType}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; /// Basic trait for all Set implementations. /// Implement IntoIterator for &Self to have .iter() (not required directly by /// the trait). pub trait BasicSet -where Self: Clone + Eq + Ord + Default + Serialize + IntoIterator - + PrintableWithTranslator, -for<'de> Self: Deserialize<'de> +where + Self: Clone + Eq + Ord + Default + Serialize + IntoIterator + PrintableWithTranslator, + for<'de> Self: Deserialize<'de>, { type Element; @@ -29,36 +29,31 @@ for<'de> Self: Deserialize<'de> } pub trait ExtensionsSet { - fn iter( - &self - ) -> <&Self as IntoIterator>::IntoIter - where for<'b> &'b Self: IntoIterator; + fn iter(&self) -> <&Self as IntoIterator>::IntoIter + where + for<'b> &'b Self: IntoIterator; - fn split<'a>( - &'a self, - trace: &'a [Self] - ) -> Option<(&'a [Self], &'a [Self])> - where Self: Sized; + fn split<'a>(&'a self, trace: &'a [Self]) -> Option<(&'a [Self], &'a [Self])> + where + Self: Sized; } /// Implementations for all sets. impl ExtensionsSet for T { fn iter(&self) -> <&T as IntoIterator>::IntoIter - where for<'b> &'b T: IntoIterator { - self.into_iter() + where + for<'b> &'b T: IntoIterator, + { + self.into_iter() } /// Returns the prefix and the loop from a trace. - fn split<'a>( - &'a self, - trace: &'a [Self] - ) -> Option<(&'a [Self], &'a [Self])> { - let position = trace.iter().rposition(|x| x == self); - position.map(|pos| trace.split_at(pos)) + fn split<'a>(&'a self, trace: &'a [Self]) -> Option<(&'a [Self], &'a [Self])> { + let position = trace.iter().rposition(|x| x == self); + position.map(|pos| trace.split_at(pos)) } } - // ----------------------------------------------------------------------------- /// Basic set of entities. @@ -71,72 +66,76 @@ impl BasicSet for Set { type Element = IdType; fn is_subset(&self, other: &Self) -> bool { - self.identifiers.is_subset(&other.identifiers) + self.identifiers.is_subset(&other.identifiers) } fn is_disjoint(&self, other: &Self) -> bool { - self.identifiers.is_disjoint(&other.identifiers) + self.identifiers.is_disjoint(&other.identifiers) } // returns the new set a \cup b fn union(&self, other: &Self) -> Self { - self.iter().chain(other.iter()).cloned().collect::>().into() + self.iter() + .chain(other.iter()) + .cloned() + .collect::>() + .into() } fn push(&mut self, other: &Self) { - self.identifiers.extend(other.iter()) + self.identifiers.extend(other.iter()) } fn extend(&mut self, other: Option<&Self>) { - if let Some(other) = other { - self.identifiers.extend(other); - } + if let Some(other) = other { + self.identifiers.extend(other); + } } /// returns the new set a \cap b fn intersection(&self, other: &Self) -> Self { - // TODO maybe find more efficient way without copy/clone - let res: BTreeSet<_> = other - .identifiers - .intersection(&self.identifiers) - .copied() - .collect(); - Set { identifiers: res } + // TODO maybe find more efficient way without copy/clone + let res: BTreeSet<_> = other + .identifiers + .intersection(&self.identifiers) + .copied() + .collect(); + Set { identifiers: res } } /// returns the new set a ∖ b fn subtraction(&self, other: &Self) -> Self { - // TODO maybe find more efficient way without copy/clone - let res: BTreeSet<_> = self - .identifiers - .difference(&other.identifiers) - .copied() - .collect(); - Set { identifiers: res } + // TODO maybe find more efficient way without copy/clone + let res: BTreeSet<_> = self + .identifiers + .difference(&other.identifiers) + .copied() + .collect(); + Set { identifiers: res } } fn len(&self) -> usize { - self.identifiers.len() + self.identifiers.len() } fn is_empty(&self) -> bool { - self.identifiers.is_empty() + self.identifiers.is_empty() } fn contains(&self, el: &Self::Element) -> bool { - self.identifiers.contains(el) + self.identifiers.contains(el) } } impl PartialEq for Set { fn eq(&self, other: &Self) -> bool { - self.identifiers.eq(&other.identifiers) + self.identifiers.eq(&other.identifiers) } } impl Hash for Set { fn hash(&self, state: &mut H) { - self.identifiers.hash(state) + self.identifiers.hash(state) } } @@ -145,7 +144,7 @@ impl IntoIterator for Set { type IntoIter = std::collections::btree_set::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.identifiers.into_iter() + self.identifiers.into_iter() } } @@ -154,58 +153,55 @@ impl<'a> IntoIterator for &'a Set { type IntoIter = std::collections::btree_set::Iter<'a, IdType>; fn into_iter(self) -> Self::IntoIter { - self.identifiers.iter() + self.identifiers.iter() } } impl PrintableWithTranslator for Set { - fn print( - &self, - f: &mut fmt::Formatter, - translator: &Translator, - ) -> fmt::Result { - write!(f, "{{")?; - let mut it = self.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!(f, "{}", Formatter::from(translator, el))?; - } else { - write!(f, "{}, ", Formatter::from(translator, el))?; - } - } - write!(f, "}}") + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + write!(f, "{{")?; + let mut it = self.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, el))?; + } else { + write!(f, "{}, ", Formatter::from(translator, el))?; + } + } + write!(f, "}}") } } - impl From<[IdType; N]> for Set { fn from(arr: [IdType; N]) -> Self { - Set { - identifiers: BTreeSet::from(arr), - } + Set { + identifiers: BTreeSet::from(arr), + } } } impl From<&[IdType]> for Set { fn from(arr: &[IdType]) -> Self { - Set { - identifiers: BTreeSet::from_iter(arr.to_vec()), - } + Set { + identifiers: BTreeSet::from_iter(arr.to_vec()), + } } } impl From> for Set { fn from(arr: Vec) -> Self { - Set { - identifiers: BTreeSet::from_iter(arr), - } + Set { + identifiers: BTreeSet::from_iter(arr), + } } } impl Set { /// Converts set to positive set. All elements with the same state. pub fn to_positive_set(&self, state: IdState) -> PositiveSet { - PositiveSet { identifiers: self.iter().map(|x| (*x, state)).collect() } + PositiveSet { + identifiers: self.iter().map(|x| (*x, state)).collect(), + } } /// Computes minimized prohibiting set from reactants and inhibitors. @@ -213,108 +209,155 @@ impl Set { /// and checks for each element of that set if they are also in all other /// unions. Then minimizes the result. pub fn prohibiting_set( - reactants: &[Set], - inhibitors: &[Set], + reactants: &[Set], + inhibitors: &[Set], ) -> Result, String> { - if reactants.len() != inhibitors.len() { - return Err(format!("Different length inputs supplied to create \ + if reactants.len() != inhibitors.len() { + return Err(format!( + "Different length inputs supplied to create \ prohibiting set. reactants: {:?}, \ inhibitors: {:?}", - reactants, inhibitors)) - } - if let Some((r, i)) = - reactants.iter() - .zip(inhibitors.iter()) - .find(|(sr, si)| !sr.intersection(si).is_empty()) - { - return Err(format!("Element in both reactants and inhibitors when \ + reactants, inhibitors + )); + } + if let Some((r, i)) = reactants + .iter() + .zip(inhibitors.iter()) + .find(|(sr, si)| !sr.intersection(si).is_empty()) + { + return Err(format!( + "Element in both reactants and inhibitors when \ creating prohibiting set. reactants: {:?}, \ inhibitors: {:?}", - r, i)) - } + r, i + )); + } - let mut t = { - let union = reactants.iter() - .zip(inhibitors.iter()) - .map(|(sr, si)| { - sr.to_positive_set(IdState::Negative) - .union(&si.to_positive_set(IdState::Positive)) - }) - .collect::>(); - let union_union = union.iter() - .fold(PositiveSet::default(), |acc, s| acc.union(s)); - let mut t = union_union.powerset(); - for set in union.iter() { - t.retain(|el| !el.intersection(set).is_empty()); - } - t - }; + // generate all valid combinations, keeping track of invalid ones (where + // one simbol is both positive and negative) + let mut t = { + let unions = reactants + .iter() + .zip(inhibitors.iter()) + .map(|(sr, si)| { + sr.iter() + .map(|&id| PositiveType { + id, + state: IdState::Negative, + }) + .chain(si.iter().map(|&id| PositiveType { + id, + state: IdState::Positive, + })) + .collect::>() + }) + .collect::>(); - // minimization - // remove sets that contain other sets - { - let mut tmp_t = t.clone().into_iter(); - let mut e = tmp_t.next().unwrap_or_default(); - loop { - let mut modified = false; - t.retain(|set| { - if *set == e { - true - } else if e.is_subset(set) { - modified = true; - false - } else { - true - } - }); - if !modified { - e = { - match tmp_t.next() { - Some(a) => a, - None => break, - } - }; - } - } - } - // replace pair of sets that have a common negative-positive element - // with set without - // cannot happen, caught by error "Element in both ..." above + let mut state = vec![0_usize; unions.len()]; + let mut t = vec![]; - // for e in t.clone() { - // let mut removed_e = false; - // let mut position = 0; - // let mut removed_elements = vec![]; - // t.retain(|set| { - // if set == &e { - // position += 1; - // true - // } else if removed_e { - // true - // } else if let elements = set.opposite_intersection(&e) - // && !elements.is_empty() - // { - // removed_e = true; - // removed_elements.extend(elements); - // false - // } else { - // position += 1; - // true - // } - // }); - // if removed_e { - // let mut set = t.get(position).unwrap().clone(); - // set = set.subtraction(&Set::from(removed_elements.clone()) - // .to_positive_set(IdState::Positive)); - // set = set.subtraction(&Set::from(removed_elements) - // .to_positive_set(IdState::Negative)); - // t.remove(position); - // t.push(set); - // } - // } + loop { + let mut new_combination = + unions.iter().zip(state.iter()) + .map(|(els, pos)| els[*pos]) + .collect::>(); + new_combination.sort_by( + |a, b| + a.id.cmp(&b.id).then(a.state.cmp(&b.state)) + ); - Ok(t) + let mut error = false; + + 'external: for i in 0..new_combination.len()-1 { + let mut j = i + 1; + loop { + if new_combination[i].id != new_combination[j].id { + break; + } else if new_combination[i].id == new_combination[j].id + && new_combination[i].state != new_combination[j].state + { + error = true; + break 'external; + } else { + j += 1; + if j >= new_combination.len() { + break; + } + } + } + } + + if !error { + t.push(PositiveSet::from(new_combination)); + } + + let next = + unions.iter().zip(state.iter()).enumerate() + .rfind( + |(_, (els, pos))| + **pos < els.len() -1 + ); + match next { + None => break, + Some((pos, _)) => { + state[pos] += 1; + state.iter_mut().skip(pos+1).for_each(|el| *el = 0); + } + } + } + t + }; + + // minimization + // remove sets that contain other sets + { + let mut tmp_t = t.clone().into_iter(); + let mut e = tmp_t.next().unwrap_or_default(); + loop { + let mut modified = false; + t.retain(|set| { + if *set == e { + true + } else if e.is_subset(set) { + modified = true; + false + } else { + true + } + }); + if !modified { + e = { + match tmp_t.next() { + Some(a) => a, + None => break, + } + }; + } + } + } + + // replace pair of sets that have a common negative-positive element + // with set without + let mut removed = 0; + + for (pos_set1, set1) in t.clone().iter_mut().enumerate() { + // we find another set that has at least one opposite element in + // common + if let Some((pos_set2, set2)) = t.iter().enumerate().find( + |(_, set2)| + set1.equal_except_negated_elements(set2) + ) { + let intersection = set1.opposite_intersection(set2); + set1.remove_elements(intersection); + + t[pos_set1 - removed] = set1.clone(); + t.remove(pos_set2); + removed += 1; + } + } + + Ok(t) } } @@ -329,133 +372,138 @@ impl BasicSet for PositiveSet { type Element = PositiveType; fn is_subset(&self, other: &Self) -> bool { - for (id, s) in self.iter() { - if let Some(s1) = other.identifiers.get(id) { - if s1 != s { - return false - } - } else { - return false - } - } - true + for (id, s) in self.iter() { + if let Some(s1) = other.identifiers.get(id) { + if s1 != s { + return false; + } + } else { + return false; + } + } + true } fn is_disjoint(&self, other: &Self) -> bool { - for (id, _s) in self.iter() { - if other.identifiers.contains_key(id) { - return false - } - } - true + for (id, _s) in self.iter() { + if other.identifiers.contains_key(id) { + return false; + } + } + true } /// ☞ The operation cannot fail, so we prefer self elements to other, /// but if the reaction system is consistent there wont be any problem. fn union(&self, other: &Self) -> Self { - self.iter().chain(other.iter()).map(|(a, b)| (*a, *b)) - .collect::>().into() + self.iter() + .chain(other.iter()) + .map(|(a, b)| (*a, *b)) + .collect::>() + .into() } fn push(&mut self, other: &Self) { - self.identifiers.extend(other.iter()) + self.identifiers.extend(other.iter()) } fn extend(&mut self, other: Option<&Self>) { - if let Some(other) = other { - self.identifiers.extend(other); - } + if let Some(other) = other { + self.identifiers.extend(other); + } } /// ☞ only returns values that are shared among both, meaning if they have /// different state (positive, negative) they are considered different. fn intersection(&self, other: &Self) -> Self { - let res: BTreeMap<_, _> = other - .identifiers - .iter() - .filter(|(id, s)| { - if let Some(s1) = self.identifiers.get(id) && s1 == *s { - true - } else { - false - } - }) - .map(|(id, s)| (*id, *s)) - .collect(); - PositiveSet { identifiers: res } + let res: BTreeMap<_, _> = other + .identifiers + .iter() + .filter(|(id, s)| { + if let Some(s1) = self.identifiers.get(id) + && s1 == *s + { + true + } else { + false + } + }) + .map(|(id, s)| (*id, *s)) + .collect(); + PositiveSet { identifiers: res } } /// ☞ returns a ∖ b, values that are shared but with different state are /// preserved in the subtraction. fn subtraction(&self, other: &Self) -> Self { - let res: BTreeMap<_, _> = self - .identifiers - .iter() - .filter(|(id, s)| { - if let Some(s1) = other.identifiers.get(id) && s1 == *s { - false - } else { - true - } - }) - .map(|(id, s)| (*id, *s)) - .collect(); - PositiveSet { identifiers: res } + let res: BTreeMap<_, _> = self + .identifiers + .iter() + .filter(|(id, s)| { + if let Some(s1) = other.identifiers.get(id) + && s1 == *s + { + false + } else { + true + } + }) + .map(|(id, s)| (*id, *s)) + .collect(); + PositiveSet { identifiers: res } } fn len(&self) -> usize { - self.identifiers.len() + self.identifiers.len() } fn is_empty(&self) -> bool { - self.identifiers.is_empty() + self.identifiers.is_empty() } fn contains(&self, el: &Self::Element) -> bool { - if let Some(e) = self.identifiers.get(&el.id) && *e == el.state { - true - } else { - false - } + if let Some(e) = self.identifiers.get(&el.id) + && *e == el.state + { + true + } else { + false + } } } impl PrintableWithTranslator for PositiveSet { - fn print( - &self, - f: &mut fmt::Formatter, - translator: &Translator, - ) -> fmt::Result { - write!(f, "{{")?; - let mut it = self.iter().peekable(); - while let Some((id, s)) = it.next() { - if it.peek().is_none() { - write!(f, - "{}", - Formatter::from(translator, - &PositiveType { id: *id, state: *s }) - )?; - } else { - write!(f, - "{}, ", - Formatter::from(translator, - &PositiveType { id: *id, state: *s }) - )?; - } - } - write!(f, "}}") + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result { + write!(f, "{{")?; + let mut it = self.iter().peekable(); + while let Some((id, s)) = it.next() { + if it.peek().is_none() { + write!( + f, + "{}", + Formatter::from(translator, &PositiveType { id: *id, state: *s }) + )?; + } else { + write!( + f, + "{}, ", + Formatter::from(translator, &PositiveType { id: *id, state: *s }) + )?; + } + } + write!(f, "}}") } } impl PartialEq for PositiveSet { fn eq(&self, other: &Self) -> bool { - self.identifiers.eq(&other.identifiers) + self.identifiers.eq(&other.identifiers) } } impl Hash for PositiveSet { fn hash(&self, state: &mut H) { - self.identifiers.hash(state) + self.identifiers.hash(state) } } @@ -464,7 +512,7 @@ impl IntoIterator for PositiveSet { type IntoIter = std::collections::btree_map::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.identifiers.into_iter() + self.identifiers.into_iter() } } @@ -473,63 +521,94 @@ impl<'a> IntoIterator for &'a PositiveSet { type IntoIter = std::collections::btree_map::Iter<'a, IdType, IdState>; fn into_iter(self) -> Self::IntoIter { - self.identifiers.iter() + self.identifiers.iter() } } - impl From<[(IdType, IdState); N]> for PositiveSet { fn from(arr: [(IdType, IdState); N]) -> Self { - PositiveSet { - identifiers: BTreeMap::from(arr), - } + PositiveSet { + identifiers: BTreeMap::from(arr), + } } } impl From<&[(IdType, IdState)]> for PositiveSet { fn from(arr: &[(IdType, IdState)]) -> Self { - PositiveSet { - identifiers: BTreeMap::from_iter(arr.to_vec()), - } + PositiveSet { + identifiers: BTreeMap::from_iter(arr.to_vec()), + } } } impl From> for PositiveSet { fn from(arr: Vec<(IdType, IdState)>) -> Self { - PositiveSet { - identifiers: BTreeMap::from_iter(arr), - } + PositiveSet { + identifiers: BTreeMap::from_iter(arr), + } + } +} + +impl From<[PositiveType; N]> for PositiveSet { + fn from(arr: [PositiveType; N]) -> Self { + arr.into_iter() + .map(|el| (el.id, el.state)) + .collect::>() + .into() + } +} + +impl From<&[PositiveType]> for PositiveSet { + fn from(arr: &[PositiveType]) -> Self { + arr.iter() + .map(|el| (el.id, el.state)) + .collect::>() + .into() + } +} + +impl From> for PositiveSet { + fn from(arr: Vec) -> Self { + arr.into_iter() + .map(|el| (el.id, el.state)) + .collect::>() + .into() } } impl PositiveSet { - pub fn powerset(&self) -> Vec { - self.into_iter().fold({ - let mut asd = Vec::with_capacity(2_usize.pow(self.len() as u32)); - asd.push(vec![]); - asd - }, |mut p, x| { - let i = p.clone().into_iter() - .map(|mut s| { - s.push(x); - s - }); - p.extend(i); - p - }).into_iter() - .map(|x| Self::from(x.into_iter() - .map(|(el, s)| (*el, *s)) - .collect::>())) - .collect::>() + /// Returns the list of elements that are in both set with opposite state. + /// Example: [+1, +2, -3] â©€ [-1, +2, +3] = [1, 3] + pub fn opposite_intersection(&self, other: &Self) -> Vec { + let mut ret = vec![]; + for (el, state) in self { + if let Some(state2) = other.identifiers.get(el) + && *state == !*state2 + { + ret.push(*el); + } + } + ret } - pub fn opposite_intersection(&self, other: &Self) -> Vec { - let mut ret = vec![]; - for (el, state) in self { - if let Some(state2) = other.identifiers.get(el) && *state == !*state2 { - ret.push(*el); - } - } - ret + fn remove_elements(&mut self, other: Vec) { + for element in other { + self.identifiers.remove(&element); + } + } + + fn equal_except_negated_elements(&self, other: &Self) -> bool { + let mut intersection = self.opposite_intersection(other); + intersection.sort(); + let mut self_copy = self.identifiers.clone(); + for el in other { + if intersection.binary_search(el.0).is_err() + || self_copy.get(el.0) != Some(el.1) + { + return false; + } + self_copy.remove(el.0); + } + self_copy.is_empty() } } diff --git a/src/rsprocess/set_test.rs b/src/rsprocess/set_test.rs index 2af1918..3db0dc9 100644 --- a/src/rsprocess/set_test.rs +++ b/src/rsprocess/set_test.rs @@ -1,9 +1,7 @@ #[test] fn prohibiting_set_1() { - use std::collections::BTreeMap; - - use super::set::{Set, PositiveSet}; - use super::element::IdState; + use super::element::IdState::*; + use super::set::{PositiveSet, Set}; let r1r = Set::from(vec![2, 3, 4]); let r1i = Set::from(vec![5, 6, 7]); @@ -11,30 +9,27 @@ fn prohibiting_set_1() { let r2r = Set::from(vec![2, 3, 11]); let r2i = Set::from(vec![5, 6, 7]); - let prohibiting_set = Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + let mut prohibiting_set = + Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + prohibiting_set.sort(); - assert_eq!(prohibiting_set, - vec![PositiveSet { identifiers: - BTreeMap::from([(2, IdState::Negative)]) }, - PositiveSet { identifiers: - BTreeMap::from([(3, IdState::Negative)]) }, - PositiveSet { identifiers: - BTreeMap::from([(5, IdState::Positive)]) }, - PositiveSet { identifiers: - BTreeMap::from([(6, IdState::Positive)]) }, - PositiveSet { identifiers: - BTreeMap::from([(7, IdState::Positive)]) }, - PositiveSet { identifiers: - BTreeMap::from([(4, IdState::Negative), - (11, IdState::Negative)]) }]) + assert_eq!( + prohibiting_set, + vec![ + PositiveSet::from([(2, Negative)]), + PositiveSet::from([(3, Negative)]), + PositiveSet::from([(4, Negative), (11, Negative)]), + PositiveSet::from([(5, Positive)]), + PositiveSet::from([(6, Positive)]), + PositiveSet::from([(7, Positive)]), + ] + ) } #[test] fn prohibiting_set_2() { - use std::collections::BTreeMap; - - use super::set::{Set, PositiveSet}; - use super::element::IdState; + use super::element::IdState::*; + use super::set::{PositiveSet, Set}; let r1r = Set::from(vec![1]); let r1i = Set::from(vec![2]); @@ -42,23 +37,23 @@ fn prohibiting_set_2() { let r2r = Set::from(vec![1]); let r2i = Set::from(vec![3]); - let prohibiting_set = Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + let mut prohibiting_set = + Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + prohibiting_set.sort(); - assert_eq!(prohibiting_set, - vec![PositiveSet { identifiers: - BTreeMap::from([(1, IdState::Negative)]) }, - PositiveSet { identifiers: - BTreeMap::from([(2, IdState::Positive), - (3, IdState::Positive)]) }]) + assert_eq!( + prohibiting_set, + vec![ + PositiveSet::from([(1, Negative)]), + PositiveSet::from([(2, Positive), (3, Positive)]), + ] + ) } - #[test] fn prohibiting_set_3() { - use std::collections::BTreeMap; - - use super::set::{Set, PositiveSet}; - use super::element::IdState; + use super::element::IdState::*; + use super::set::{PositiveSet, Set}; let r1r = Set::from(vec![1]); let r1i = Set::from(vec![2]); @@ -66,13 +61,49 @@ fn prohibiting_set_3() { let r2r = Set::from(vec![3]); let r2i = Set::from(vec![1]); - let prohibiting_set = Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + let mut prohibiting_set = + Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + prohibiting_set.sort(); - assert_eq!(prohibiting_set, - vec![PositiveSet { identifiers: - BTreeMap::from([(1, IdState::Negative), - (3, IdState::Negative)]) }, - PositiveSet { identifiers: - BTreeMap::from([(2, IdState::Positive), - (3, IdState::Negative)]) }]) + assert_eq!( + prohibiting_set, + vec![ + PositiveSet::from([(1, Positive), (2, Positive)]), + PositiveSet::from([(1, Negative), (3, Negative)]), + PositiveSet::from([(2, Positive), (3, Negative)]), + ] + ) +} + +#[test] +fn prohibiting_set_4() { + use super::element::IdState::*; + use super::set::{PositiveSet, Set}; + + let r1r = Set::from(vec![1]); + let r1i = Set::from(vec![2]); + + let r2r = Set::from(vec![3]); + let r2i = Set::from(vec![4]); + + let r3r = Set::from(vec![5]); + let r3i = Set::from(vec![6]); + + let mut prohibiting_set = + Set::prohibiting_set(&[r1r, r2r, r3r], &[r1i, r2i, r3i]).unwrap(); + prohibiting_set.sort(); + + assert_eq!( + prohibiting_set, + vec![ + PositiveSet::from([(1, Negative), (3, Negative), (5, Negative)]), + PositiveSet::from([(1, Negative), (3, Negative), (6, Positive)]), + PositiveSet::from([(1, Negative), (4, Positive), (5, Negative)]), + PositiveSet::from([(1, Negative), (4, Positive), (6, Positive)]), + PositiveSet::from([(2, Positive), (3, Negative), (5, Negative)]), + PositiveSet::from([(2, Positive), (3, Negative), (6, Positive)]), + PositiveSet::from([(2, Positive), (4, Positive), (5, Negative)]), + PositiveSet::from([(2, Positive), (4, Positive), (6, Positive)]), + ] + ) } diff --git a/src/rsprocess/system.rs b/src/rsprocess/system.rs index 72243ad..14ff4a6 100644 --- a/src/rsprocess/system.rs +++ b/src/rsprocess/system.rs @@ -5,29 +5,29 @@ use std::fmt::Debug; use std::hash::Hash; use std::rc::Rc; -use super::environment::{Environment, BasicEnvironment, PositiveEnvironment, - ExtensionsEnvironment, LoopEnvironment}; +use super::element::IdState; +use super::environment::{ + BasicEnvironment, Environment, ExtensionsEnvironment, LoopEnvironment, PositiveEnvironment, +}; use super::label::{BasicLabel, Label, PositiveLabel}; use super::process::{BasicProcess, PositiveProcess, Process}; use super::reaction::{BasicReaction, ExtensionReaction, PositiveReaction, Reaction}; use super::set::{BasicSet, PositiveSet, Set}; -use super::element::IdState; use super::transitions::TransitionsIterator; -use super::translator::{Translator, PrintableWithTranslator, Formatter}; +use super::translator::{Formatter, PrintableWithTranslator, Translator}; pub trait BasicSystem -where Self: Clone + Debug + Serialize + Default + Eq + Hash - + PrintableWithTranslator, -for<'de> Self: Deserialize<'de> { +where + Self: Clone + Debug + Serialize + Default + Eq + Hash + PrintableWithTranslator, + for<'de> Self: Deserialize<'de>, +{ type Set: BasicSet; type Reaction: BasicReaction; type Label: BasicLabel; type Process: BasicProcess; type Environment: BasicEnvironment; - fn to_transitions_iterator( - &self - ) -> Result, String>; + fn to_transitions_iterator(&self) -> Result, String>; fn environment(&self) -> &Self::Environment; fn available_entities(&self) -> &Self::Set; @@ -38,199 +38,164 @@ for<'de> Self: Deserialize<'de> { type Trace = Vec<(Option>, Rc)>; pub trait ExtensionsSystem: BasicSystem { - fn one_transition( - &self - ) -> Result, String>; + fn one_transition(&self) -> Result, String>; - fn nth_transition( - &self, - n: usize, - ) -> Result, String>; + fn nth_transition(&self, n: usize) -> Result, String>; - fn all_transitions( - &self - ) -> Result, String>; + fn all_transitions(&self) -> Result, String>; - fn run( - &self - ) -> Result>, String>; + fn run(&self) -> Result>, String>; fn digraph(self) -> Result, String>; fn target(&self) -> Result<(i64, Self::Set), String>; #[allow(clippy::type_complexity)] - fn run_separated( - &self - ) -> Result, String>; + fn run_separated(&self) -> Result, String>; - fn traces( - self, - n: usize, - ) -> Result>, String>; + fn traces(self, n: usize) -> Result>, String>; } impl ExtensionsSystem for T { /// see oneTransition, transition, smartTransition, smartOneTransition - fn one_transition( - &self - ) -> Result, String> { - let mut tr = self.to_transitions_iterator()?; - Ok(tr.next()) + fn one_transition(&self) -> Result, String> { + let mut tr = self.to_transitions_iterator()?; + Ok(tr.next()) } - fn nth_transition( - &self, - n: usize, - ) -> Result, String> { - let mut tr = self.to_transitions_iterator()?; - Ok(tr.nth(n)) + fn nth_transition(&self, n: usize) -> Result, String> { + let mut tr = self.to_transitions_iterator()?; + Ok(tr.nth(n)) } /// see allTransitions, smartAllTransitions - fn all_transitions( - &self - ) -> Result, String> { - let tr = self.to_transitions_iterator()?; - Ok(tr.collect::>()) + fn all_transitions(&self) -> Result, String> { + let tr = self.to_transitions_iterator()?; + Ok(tr.collect::>()) } /// see oneRun, run, smartOneRunEK, smartRunEK - fn run( - &self - ) -> Result>, String> { - let mut res = vec![Rc::new(self.clone())]; - while let Some((_, next_sys)) = res.last().unwrap().one_transition()? { - res.push(Rc::new(next_sys)); - } - Ok(res) + fn run(&self) -> Result>, String> { + let mut res = vec![Rc::new(self.clone())]; + while let Some((_, next_sys)) = res.last().unwrap().one_transition()? { + res.push(Rc::new(next_sys)); + } + Ok(res) } /// Creates a graph starting from a system as root node. fn digraph(self) -> Result, String> { - use petgraph::Graph; + use petgraph::Graph; - let mut graph = Graph::default(); - let node = graph.add_node(self.clone()); + let mut graph = Graph::default(); + let node = graph.add_node(self.clone()); - let mut association = HashMap::new(); - association.insert(self.clone(), node); + let mut association = HashMap::new(); + association.insert(self.clone(), node); - let mut stack = vec![self]; + let mut stack = vec![self]; - while let Some(current) = stack.pop() { - // depth first - let current_node = *association.get(¤t).unwrap(); + while let Some(current) = stack.pop() { + // depth first + let current_node = *association.get(¤t).unwrap(); - for (label, next) in current.to_transitions_iterator()? { - // if not already visited - let next_node = association.entry(next.clone()).or_insert_with(|| { - stack.push(next.clone()); - graph.add_node(next) - }); - graph.add_edge(current_node, *next_node, label); - } - } - Ok(graph) + for (label, next) in current.to_transitions_iterator()? { + // if not already visited + let next_node = association.entry(next.clone()).or_insert_with(|| { + stack.push(next.clone()); + graph.add_node(next) + }); + graph.add_edge(current_node, *next_node, label); + } + } + Ok(graph) } /// Returns the state in one of the terminal states and the number of steps /// to arrive at the last state. /// see oneTarget, smartOneTarget, target, smartTarget - fn target( - &self - ) -> Result<(i64, Self::Set), String> { - let current = self.one_transition()?; - if current.is_none() { - return Ok((0, self.available_entities().clone())); - } - let mut n = 1; - let mut current = current.unwrap().1; - while let Some((_, next)) = current.one_transition()? { - current = next; - n += 1; - } - Ok((n, current.available_entities().clone())) + fn target(&self) -> Result<(i64, Self::Set), String> { + let current = self.one_transition()?; + if current.is_none() { + return Ok((0, self.available_entities().clone())); + } + let mut n = 1; + let mut current = current.unwrap().1; + while let Some((_, next)) = current.one_transition()? { + current = next; + n += 1; + } + Ok((n, current.available_entities().clone())) } /// see smartOneRunECT, smartRunECT - fn run_separated( - &self - ) -> Result, String> { - let mut res = vec![]; - let current = self.one_transition()?; - if current.is_none() { - return Ok(res); - } - let current = current.unwrap(); - let (available_entities, context, t) = current.0.get_context(); - res.push((available_entities.clone(), context.clone(), t.clone())); - let mut current = current.1; - while let Some((label, next)) = current.one_transition()? { - current = next; - let (available_entities, context, t) = label.get_context(); - res.push((available_entities.clone(), context.clone(), t.clone())); - } - Ok(res) + fn run_separated(&self) -> Result, String> { + let mut res = vec![]; + let current = self.one_transition()?; + if current.is_none() { + return Ok(res); + } + let current = current.unwrap(); + let (available_entities, context, t) = current.0.get_context(); + res.push((available_entities.clone(), context.clone(), t.clone())); + let mut current = current.1; + while let Some((label, next)) = current.one_transition()? { + current = next; + let (available_entities, context, t) = label.get_context(); + res.push((available_entities.clone(), context.clone(), t.clone())); + } + Ok(res) } /// Return the first n traces. Equivalent to visiting the execution tree /// depth first and returning the first n leaf nodes and their path to the /// root. - fn traces( - self, - n: usize, - ) -> Result>, String> { - if n == 0 { - return Ok(vec![]) - } - let mut n = n; - let mut res : Vec> - = vec![]; - let mut current_trace: Trace - = vec![(None, Rc::new(self))]; - let mut branch = vec![0]; - let mut depth = 0; - let mut new_branch = true; + fn traces(self, n: usize) -> Result>, String> { + if n == 0 { + return Ok(vec![]); + } + let mut n = n; + let mut res: Vec> = vec![]; + let mut current_trace: Trace = vec![(None, Rc::new(self))]; + let mut branch = vec![0]; + let mut depth = 0; + let mut new_branch = true; - loop { - let next_sys = - current_trace[depth].1.nth_transition(branch[depth])?; + loop { + let next_sys = current_trace[depth].1.nth_transition(branch[depth])?; - if let Some((current_label, next_sys)) = next_sys { - depth += 1; - if depth >= branch.len() { - branch.push(0); - current_trace.push((Some(Rc::new(current_label)), - Rc::new(next_sys))); - } else { - branch[depth] = 0; - current_trace[depth] = (Some(Rc::new(current_label)), - Rc::new(next_sys)); - } - new_branch = true; - } else { - // at the bottom of a trace, we save to res, then backtrack - // until we find another possible path. - if new_branch { - res.push(current_trace[0..depth].to_vec()); - new_branch = false; - n -= 1; - } - if n == 0 { - break; - } + if let Some((current_label, next_sys)) = next_sys { + depth += 1; + if depth >= branch.len() { + branch.push(0); + current_trace.push((Some(Rc::new(current_label)), Rc::new(next_sys))); + } else { + branch[depth] = 0; + current_trace[depth] = (Some(Rc::new(current_label)), Rc::new(next_sys)); + } + new_branch = true; + } else { + // at the bottom of a trace, we save to res, then backtrack + // until we find another possible path. + if new_branch { + res.push(current_trace[0..depth].to_vec()); + new_branch = false; + n -= 1; + } + if n == 0 { + break; + } - if depth == 0 { - break; - } + if depth == 0 { + break; + } - depth -= 1; - branch[depth] += 1; - } - } + depth -= 1; + branch[depth] += 1; + } + } - Ok(res) + Ok(res) } } @@ -248,22 +213,22 @@ pub trait LoopSystem: BasicSystem { #[allow(clippy::type_complexity)] fn lollipops_named( - &self, - symb: ::Id + &self, + symb: ::Id, ) -> Option<(Vec, Vec)>; fn lollipops_only_loop_named( - &self, - symb: ::Id + &self, + symb: ::Id, ) -> Option>; } -impl, - T: BasicSystem> +impl, T: BasicSystem> LoopSystem for T -where E: BasicEnvironment + ExtensionsEnvironment, -for<'a> &'a E: IntoIterator, - E::Id: Eq, +where + E: BasicEnvironment + ExtensionsEnvironment, + for<'a> &'a E: IntoIterator, + E::Id: Eq, { type Env = E; @@ -276,34 +241,23 @@ for<'a> &'a E: IntoIterator, /// Under these assumptions, the predicate lollipop finds the Prefixes and /// the Loops sequences of entities. /// see lollipop - fn lollipops( - &self - ) -> Vec<(Vec, Vec)> { - self.environment().lollipops_decomposed( - self.reactions(), - self.available_entities(), - ) + fn lollipops(&self) -> Vec<(Vec, Vec)> { + self.environment() + .lollipops_decomposed(self.reactions(), self.available_entities()) } /// Only returns the loop part of the lollipop, returns for all X, where /// X = Q.X /// see loop - fn lollipops_only_loop( - self - ) -> Vec> { - let filtered = - self.environment().iter().filter_map( - |l| - l.1.filter_delta(l.0) - ); + fn lollipops_only_loop(self) -> Vec> { + let filtered = self + .environment() + .iter() + .filter_map(|l| l.1.filter_delta(l.0)); - let find_loop_fn = |q| { - R::find_only_loop(self.reactions(), - self.available_entities(), - q) - }; + let find_loop_fn = |q| R::find_only_loop(self.reactions(), self.available_entities(), q); - filtered.map(find_loop_fn).collect::>() + filtered.map(find_loop_fn).collect::>() } /// A special case of systems is when the context recursively provides @@ -315,48 +269,36 @@ for<'a> &'a E: IntoIterator, /// Under these assumptions, the predicate lollipop finds the Prefixes and /// the Loops sequences of entities. /// see lollipop - fn lollipops_named( - &self, - symb: E::Id - ) -> Option<(Vec, Vec)> { - self.environment().lollipops_decomposed_named( - self.reactions(), - self.available_entities(), - symb, - ) + fn lollipops_named(&self, symb: E::Id) -> Option<(Vec, Vec)> { + self.environment().lollipops_decomposed_named( + self.reactions(), + self.available_entities(), + symb, + ) } /// Only returns the loop part of the lollipop, returns for all X, where /// X = Q.X /// see loop - fn lollipops_only_loop_named( - &self, - symb: E::Id - ) -> Option> { - let filtered = self - .environment() - .iter() - .filter_map( - |l| - if *l.0 == symb { - l.1.filter_delta(&symb) - } else { - None - } - ) - .next(); + fn lollipops_only_loop_named(&self, symb: E::Id) -> Option> { + let filtered = self + .environment() + .iter() + .filter_map(|l| { + if *l.0 == symb { + l.1.filter_delta(&symb) + } else { + None + } + }) + .next(); - let find_loop_fn = |q| { - R::find_only_loop(self.reactions(), - self.available_entities(), - q) - }; + let find_loop_fn = |q| R::find_only_loop(self.reactions(), self.available_entities(), q); - filtered.map(find_loop_fn) + filtered.map(find_loop_fn) } } - // ----------------------------------------------------------------------------- #[derive(Clone, Debug, Deserialize, Serialize)] @@ -374,26 +316,24 @@ impl BasicSystem for System { type Process = Process; type Environment = Environment; - fn to_transitions_iterator( - &self - ) -> Result, String> { - TransitionsIterator::::from(self) + fn to_transitions_iterator(&self) -> Result, String> { + TransitionsIterator::::from(self) } fn environment(&self) -> &Self::Environment { - &self.delta + &self.delta } fn available_entities(&self) -> &Self::Set { - &self.available_entities + &self.available_entities } fn context(&self) -> &Self::Process { - &self.context_process + &self.context_process } fn reactions(&self) -> &Vec { - &self.reaction_rules + &self.reaction_rules } } @@ -402,8 +342,8 @@ impl BasicSystem for System { impl PartialEq for System { // we ignore delta and reaction rules fn eq(&self, other: &System) -> bool { - self.available_entities == other.available_entities && - self.context_process == other.context_process + self.available_entities == other.available_entities + && self.context_process == other.context_process } } @@ -411,67 +351,65 @@ impl PartialEq for System { /// context is compared impl Eq for System {} - /// Hash does not care about delta or reaction rules. Only entities and /// context is hashed impl Hash for System { // ignores delta and reaction rules fn hash(&self, state: &mut H) { - self.available_entities.hash(state); - self.context_process.hash(state); + self.available_entities.hash(state); + self.context_process.hash(state); } } impl Default for System { fn default() -> Self { - Self { delta: Rc::new(Environment::default()), - available_entities: Set::default(), - context_process: Process::Nill, - reaction_rules: Rc::new(Vec::default()) } + Self { + delta: Rc::new(Environment::default()), + available_entities: Set::default(), + context_process: Process::Nill, + reaction_rules: Rc::new(Vec::default()), + } } } impl PrintableWithTranslator for System { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "[delta: {}, available_entities: {}, context_process: {}, \ + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!( + f, + "[delta: {}, available_entities: {}, context_process: {}, \ reaction_rules: [", - Formatter::from(translator, &*self.delta), - Formatter::from(translator, &self.available_entities), - Formatter::from(translator, &self.context_process) - )?; - let mut it = self.reaction_rules.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!(f, "{}", Formatter::from(translator, el))?; - } else { - write!(f, "{}, ", Formatter::from(translator, el))?; - } - } - write!(f, "] ]") + Formatter::from(translator, &*self.delta), + Formatter::from(translator, &self.available_entities), + Formatter::from(translator, &self.context_process) + )?; + let mut it = self.reaction_rules.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, el))?; + } else { + write!(f, "{}, ", Formatter::from(translator, el))?; + } + } + write!(f, "] ]") } } - impl System { pub fn from( - delta: Rc, - available_entities: Set, - context_process: Process, - reaction_rules: Rc>, + delta: Rc, + available_entities: Set, + context_process: Process, + reaction_rules: Rc>, ) -> System { - System { - delta: Rc::clone(&delta), - available_entities, - context_process, - reaction_rules: Rc::clone(&reaction_rules), - } + System { + delta: Rc::clone(&delta), + available_entities, + context_process, + reaction_rules: Rc::clone(&reaction_rules), + } } } - // ----------------------------------------------------------------------------- // Statistics // ----------------------------------------------------------------------------- @@ -480,139 +418,131 @@ impl System { /// Non simulated statistics of a system. /// Returns statistics about the system as a string. /// see main_do(stat,MissingE) - pub fn statistics( - &self, - translator: &Translator, - ) -> String { - use super::translator::Formatter; + pub fn statistics(&self, translator: &Translator) -> String { + use super::translator::Formatter; - let mut result: String = "Statistics:\n".into(); - result.push_str( - "=============================================================\n" - ); - result.push_str(&format!( - "the initial state has {} entities:\n", - self.available_entities.len() - )); - result.push_str(&format!( - "{}\n", - Formatter::from(translator, &self.available_entities) - )); + let mut result: String = "Statistics:\n".into(); + result.push_str("=============================================================\n"); + result.push_str(&format!( + "the initial state has {} entities:\n", + self.available_entities.len() + )); + result.push_str(&format!( + "{}\n", + Formatter::from(translator, &self.available_entities) + )); - let reactants = self - .reaction_rules - .iter() - .fold(Set::default(), |acc, new| acc.union(&new.reactants)); - result.push_str(&format!( - "The reactants are {}:\n{}\n", - reactants.len(), - Formatter::from(translator, &reactants) - )); + let reactants = self + .reaction_rules + .iter() + .fold(Set::default(), |acc, new| acc.union(&new.reactants)); + result.push_str(&format!( + "The reactants are {}:\n{}\n", + reactants.len(), + Formatter::from(translator, &reactants) + )); - let inhibitors = self - .reaction_rules - .iter() - .fold(Set::default(), |acc, new| acc.union(&new.inhibitors)); - result.push_str(&format!( - "The inhibitors are {}:\n{}\n", - inhibitors.len(), - Formatter::from(translator, &inhibitors) - )); + let inhibitors = self + .reaction_rules + .iter() + .fold(Set::default(), |acc, new| acc.union(&new.inhibitors)); + result.push_str(&format!( + "The inhibitors are {}:\n{}\n", + inhibitors.len(), + Formatter::from(translator, &inhibitors) + )); - let products = self - .reaction_rules - .iter() - .fold(Set::default(), |acc, new| acc.union(&new.products)); - result.push_str(&format!( - "The products are {}:\n{}\n", - products.len(), - Formatter::from(translator, &products) - )); + let products = self + .reaction_rules + .iter() + .fold(Set::default(), |acc, new| acc.union(&new.products)); + result.push_str(&format!( + "The products are {}:\n{}\n", + products.len(), + Formatter::from(translator, &products) + )); - let total = reactants.union(&inhibitors.union(&products)); - result.push_str(&format!( - "The reactions involve {} entities:\n{}\n", - total.len(), - Formatter::from(translator, &total) - )); + let total = reactants.union(&inhibitors.union(&products)); + result.push_str(&format!( + "The reactions involve {} entities:\n{}\n", + total.len(), + Formatter::from(translator, &total) + )); - let entities_env = self.delta.all_elements(); - result.push_str(&format!( - "The environment involves {} entities:\n{}\n", - entities_env.len(), - Formatter::from(translator, &entities_env) - )); + let entities_env = self.delta.all_elements(); + result.push_str(&format!( + "The environment involves {} entities:\n{}\n", + entities_env.len(), + Formatter::from(translator, &entities_env) + )); - let entities_context = self.context_process.all_elements(); - result.push_str(&format!( - "The context involves {} entities:\n{}\n", - entities_context.len(), - Formatter::from(translator, &entities_context) - )); + let entities_context = self.context_process.all_elements(); + result.push_str(&format!( + "The context involves {} entities:\n{}\n", + entities_context.len(), + Formatter::from(translator, &entities_context) + )); - let entities_all = total - .union(&entities_env) - .union(&entities_context) - .union(&self.available_entities); + let entities_all = total + .union(&entities_env) + .union(&entities_context) + .union(&self.available_entities); - result.push_str(&format!( - "The whole RS involves {} entities:\n{}\n", - entities_all.len(), - Formatter::from(translator, &entities_all) - )); + result.push_str(&format!( + "The whole RS involves {} entities:\n{}\n", + entities_all.len(), + Formatter::from(translator, &entities_all) + )); - let possible_e = products - .union(&self.available_entities) - .union(&entities_context); - let missing_e = reactants.subtraction(&possible_e); - result.push_str(&format!( - "There are {} reactants that will never be available:\n{}\n", - missing_e.len(), - Formatter::from(translator, &missing_e) - )); + let possible_e = products + .union(&self.available_entities) + .union(&entities_context); + let missing_e = reactants.subtraction(&possible_e); + result.push_str(&format!( + "There are {} reactants that will never be available:\n{}\n", + missing_e.len(), + Formatter::from(translator, &missing_e) + )); - let entities_not_needed = entities_context.subtraction(&total); - result.push_str(&format!( - "The context can provide {} entities that will never be used:\ + let entities_not_needed = entities_context.subtraction(&total); + result.push_str(&format!( + "The context can provide {} entities that will never be used:\ \n{}\n", - entities_not_needed.len(), - Formatter::from(translator, &entities_not_needed) - )); + entities_not_needed.len(), + Formatter::from(translator, &entities_not_needed) + )); - result.push_str(&format!( - "There are {} reactions in total.\n", - self.reaction_rules.len() - )); + result.push_str(&format!( + "There are {} reactions in total.\n", + self.reaction_rules.len() + )); - let mut admissible_reactions = vec![]; - let mut nonadmissible_reactions = vec![]; + let mut admissible_reactions = vec![]; + let mut nonadmissible_reactions = vec![]; - for reaction in self.reaction_rules.iter() { - if reaction.reactants.is_disjoint(&missing_e) { - admissible_reactions.push(reaction); - } else { - nonadmissible_reactions.push(reaction); - } - } + for reaction in self.reaction_rules.iter() { + if reaction.reactants.is_disjoint(&missing_e) { + admissible_reactions.push(reaction); + } else { + nonadmissible_reactions.push(reaction); + } + } - result.push_str(&format!( - "- the applicable reactions are {}.\n", - admissible_reactions.len() - )); + result.push_str(&format!( + "- the applicable reactions are {}.\n", + admissible_reactions.len() + )); - result.push_str(&format!( - "- there are {} reactions that will never be enabled.\n", - nonadmissible_reactions.len() - )); - result.push_str( - "=============================================================" - ); + result.push_str(&format!( + "- there are {} reactions that will never be enabled.\n", + nonadmissible_reactions.len() + )); + result.push_str("============================================================="); - result + result } } - // ----------------------------------------------------------------------------- // Positive System // ----------------------------------------------------------------------------- @@ -632,26 +562,24 @@ impl BasicSystem for PositiveSystem { type Process = PositiveProcess; type Environment = PositiveEnvironment; - fn to_transitions_iterator( - &self - ) -> Result, String> { - TransitionsIterator::::from(self) + fn to_transitions_iterator(&self) -> Result, String> { + TransitionsIterator::::from(self) } fn environment(&self) -> &Self::Environment { - &self.delta + &self.delta } fn available_entities(&self) -> &Self::Set { - &self.available_entities + &self.available_entities } fn context(&self) -> &Self::Process { - &self.context_process + &self.context_process } fn reactions(&self) -> &Vec { - &self.reaction_rules + &self.reaction_rules } } @@ -660,8 +588,8 @@ impl BasicSystem for PositiveSystem { impl PartialEq for PositiveSystem { // we ignore delta and reaction rules fn eq(&self, other: &PositiveSystem) -> bool { - self.available_entities == other.available_entities && - self.context_process == other.context_process + self.available_entities == other.available_entities + && self.context_process == other.context_process } } @@ -674,40 +602,41 @@ impl Eq for PositiveSystem {} impl Hash for PositiveSystem { // ignores delta and reaction rules fn hash(&self, state: &mut H) { - self.available_entities.hash(state); - self.context_process.hash(state); + self.available_entities.hash(state); + self.context_process.hash(state); } } impl Default for PositiveSystem { fn default() -> Self { - Self { delta: Rc::new(PositiveEnvironment::default()), - available_entities: PositiveSet::default(), - context_process: PositiveProcess::default(), - reaction_rules: Rc::new(Vec::default()) } + Self { + delta: Rc::new(PositiveEnvironment::default()), + available_entities: PositiveSet::default(), + context_process: PositiveProcess::default(), + reaction_rules: Rc::new(Vec::default()), + } } } impl PrintableWithTranslator for PositiveSystem { - fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) - -> std::fmt::Result { - write!( - f, - "[delta: {}, available_entities: {}, context_process: {}, \ + fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { + write!( + f, + "[delta: {}, available_entities: {}, context_process: {}, \ reaction_rules: [", - Formatter::from(translator, &*self.delta), - Formatter::from(translator, &self.available_entities), - Formatter::from(translator, &self.context_process) - )?; - let mut it = self.reaction_rules.iter().peekable(); - while let Some(el) = it.next() { - if it.peek().is_none() { - write!(f, "{}", Formatter::from(translator, el))?; - } else { - write!(f, "{}, ", Formatter::from(translator, el))?; - } - } - write!(f, "] ]") + Formatter::from(translator, &*self.delta), + Formatter::from(translator, &self.available_entities), + Formatter::from(translator, &self.context_process) + )?; + let mut it = self.reaction_rules.iter().peekable(); + while let Some(el) = it.next() { + if it.peek().is_none() { + write!(f, "{}", Formatter::from(translator, el))?; + } else { + write!(f, "{}, ", Formatter::from(translator, el))?; + } + } + write!(f, "] ]") } } @@ -718,58 +647,77 @@ impl From for PositiveSystem { /// all reactions that contains el in the products. /// Should never fail. fn from(value: System) -> Self { - let new_env = Rc::new((&*value.delta).into()); - let new_available_entities = - value.available_entities.to_positive_set(IdState::Positive); - let new_context = value.context_process.into(); - let new_reactions = { - let mut res = vec![]; - let old_reactions = &value.reaction_rules; - old_reactions.iter() - .for_each( - |r| res.push(PositiveReaction::create(r.reactants.clone(), - r.inhibitors.clone(), - r.products.clone()))); - let all_products = Reaction::all_products(old_reactions); - for el in all_products { - let p = - Reaction::all_reactions_with_product(old_reactions, &el); - let prohib_set = - Set::prohibiting_set( - &p.iter().map(|p| p.reactants.clone()) - .collect::>(), - &p.iter().map(|p| p.inhibitors.clone()) - .collect::>()) - .unwrap(); - for s in prohib_set { - res.push(PositiveReaction { - reactants: s, - products: PositiveSet::from([(el, IdState::Negative)]) - }) - } - } - Rc::new(res) - }; + let new_env = Rc::new((&*value.delta).into()); + let positive_entities = value.available_entities.to_positive_set(IdState::Positive); - Self { delta: new_env, - available_entities: new_available_entities, - context_process: new_context, - reaction_rules: new_reactions } + let negative_entities = value + .context_process + .all_elements() + .union(&value.environment().all_elements()) + .union( + &value + .reactions() + .iter() + .fold(Set::default(), |acc: Set, el| { + acc.union(&el.inhibitors) + .union(&el.products) + .union(&el.reactants) + }), + ) + .subtraction(&value.available_entities) + .to_positive_set(IdState::Negative); + let new_available_entities = positive_entities.union(&negative_entities); + + let new_context = value.context_process.into(); + let new_reactions = { + let mut res = vec![]; + let old_reactions = &value.reaction_rules; + old_reactions.iter().for_each(|r| { + res.push(PositiveReaction::create( + r.reactants.clone(), + r.inhibitors.clone(), + r.products.clone(), + )) + }); + let all_products = Reaction::all_products(old_reactions); + for el in all_products { + let p = Reaction::all_reactions_with_product(old_reactions, &el); + let prohib_set = Set::prohibiting_set( + &p.iter().map(|p| p.reactants.clone()).collect::>(), + &p.iter().map(|p| p.inhibitors.clone()).collect::>(), + ) + .unwrap(); + for s in prohib_set { + res.push(PositiveReaction { + reactants: s, + products: PositiveSet::from([(el, IdState::Negative)]), + }) + } + } + Rc::new(res) + }; + + Self { + delta: new_env, + available_entities: new_available_entities, + context_process: new_context, + reaction_rules: new_reactions, + } } } impl PositiveSystem { pub fn from( - delta: Rc, - available_entities: PositiveSet, - context_process: PositiveProcess, - reaction_rules: Rc>, + delta: Rc, + available_entities: PositiveSet, + context_process: PositiveProcess, + reaction_rules: Rc>, ) -> Self { - Self { - delta: Rc::clone(&delta), - available_entities, - context_process, - reaction_rules: Rc::clone(&reaction_rules), - } + Self { + delta: Rc::clone(&delta), + available_entities, + context_process, + reaction_rules: Rc::clone(&reaction_rules), + } } } diff --git a/src/rsprocess/system_test.rs b/src/rsprocess/system_test.rs index 9a41fc8..4ad5c97 100644 --- a/src/rsprocess/system_test.rs +++ b/src/rsprocess/system_test.rs @@ -1,173 +1,223 @@ #[test] fn one_transition() { - use super::system::{System, ExtensionsSystem}; - use super::reaction::Reaction; - use super::process::Process; use super::environment::Environment; - use super::set::{Set, BasicSet}; + use super::process::Process; + use super::reaction::Reaction; + use super::set::{BasicSet, Set}; + use super::system::{ExtensionsSystem, System}; use std::rc::Rc; let system = System::from( - Rc::new(Environment::default()), - Set::from([1, 2]), - Process::EntitySet { entities: Set::from([]), - next_process: Rc::new(Process::Nill) }, - Rc::new(vec![Reaction { reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), }, ]) + Rc::new(Environment::default()), + Set::from([1, 2]), + Process::EntitySet { + entities: Set::from([]), + next_process: Rc::new(Process::Nill), + }, + Rc::new(vec![Reaction { + reactants: Set::from([1]), + inhibitors: Set::from([3]), + products: Set::from([3]), + }]), ); match system.one_transition() { - Ok(Some((_, System { available_entities, .. }))) => - assert!(available_entities.len() == 1 && - available_entities.contains(&3)), - _ => panic!() + Ok(Some(( + _, + System { + available_entities, .. + }, + ))) => assert!(available_entities.len() == 1 && available_entities.contains(&3)), + _ => panic!(), } } #[test] fn one_transition_2() { - use super::system::{PositiveSystem, ExtensionsSystem}; - use super::reaction::PositiveReaction; - use super::process::PositiveProcess; - use super::environment::PositiveEnvironment; - use super::set::{PositiveSet, BasicSet}; use super::element::{IdState, PositiveType}; + use super::environment::PositiveEnvironment; + use super::process::PositiveProcess; + use super::reaction::PositiveReaction; + use super::set::{BasicSet, PositiveSet}; + use super::system::{ExtensionsSystem, PositiveSystem}; use std::rc::Rc; let system = PositiveSystem::from( - Rc::new(PositiveEnvironment::default()), - PositiveSet::from([(1, IdState::Positive), - (2, IdState::Positive), - (3, IdState::Negative)]), - PositiveProcess::WaitEntity { repeat: 2, - repeated_process: Rc::new( - PositiveProcess::EntitySet { - entities: PositiveSet::default(), - next_process: Rc::new( - PositiveProcess::Nill) } - ), - next_process: Rc::new(PositiveProcess::Nill) }, - Rc::new(vec![ - PositiveReaction { - reactants: PositiveSet::from([(1, IdState::Positive), - (3, IdState::Negative)]), - products: PositiveSet::from([(3, IdState::Positive)]), }, - PositiveReaction { - reactants: PositiveSet::from([(3, IdState::Positive)]), - products: PositiveSet::from([(3, IdState::Negative)]), }, - PositiveReaction { - reactants: PositiveSet::from([(1, IdState::Negative)]), - products: PositiveSet::from([(3, IdState::Negative)]), }, ]) + Rc::new(PositiveEnvironment::default()), + PositiveSet::from([ + (1, IdState::Positive), + (2, IdState::Positive), + (3, IdState::Negative), + ]), + PositiveProcess::WaitEntity { + repeat: 2, + repeated_process: Rc::new(PositiveProcess::EntitySet { + entities: PositiveSet::default(), + next_process: Rc::new(PositiveProcess::Nill), + }), + next_process: Rc::new(PositiveProcess::Nill), + }, + Rc::new(vec![ + PositiveReaction { + reactants: PositiveSet::from([(1, IdState::Positive), (3, IdState::Negative)]), + products: PositiveSet::from([(3, IdState::Positive)]), + }, + PositiveReaction { + reactants: PositiveSet::from([(3, IdState::Positive)]), + products: PositiveSet::from([(3, IdState::Negative)]), + }, + PositiveReaction { + reactants: PositiveSet::from([(1, IdState::Negative)]), + products: PositiveSet::from([(3, IdState::Negative)]), + }, + ]), ); let system = system.one_transition(); - let system = - match system { - Ok(Some((_, system))) => { - assert!(system.available_entities.len() == 1 && - system.available_entities.contains( - &PositiveType { id: 3, - state: IdState::Positive })); - system - }, - _ => panic!() - }; + let system = match system { + Ok(Some((_, system))) => { + assert!( + system.available_entities.len() == 1 + && system.available_entities.contains(&PositiveType { + id: 3, + state: IdState::Positive + }) + ); + system + } + _ => panic!(), + }; match system.one_transition() { - Ok(Some((_, PositiveSystem { available_entities, .. }))) => - assert!(available_entities.len() == 1 && - available_entities.contains( - &PositiveType { id: 3, - state: IdState::Negative })), - _ => panic!() + Ok(Some(( + _, + PositiveSystem { + available_entities, .. + }, + ))) => assert!( + available_entities.len() == 1 + && available_entities.contains(&PositiveType { + id: 3, + state: IdState::Negative + }) + ), + _ => panic!(), } } #[test] fn convertion() { - use super::system::{System, PositiveSystem}; - use super::reaction::Reaction; - use super::process::Process; use super::environment::Environment; - use super::set::{Set, BasicSet}; + use super::process::Process; + use super::reaction::Reaction; + use super::set::{BasicSet, Set}; + use super::system::{PositiveSystem, System}; use std::rc::Rc; let system = System::from( - Rc::new(Environment::default()), - Set::from([1, 2]), - Process::EntitySet { entities: Set::from([]), - next_process: Rc::new(Process::Nill) }, - Rc::new(vec![Reaction { reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), }, ]) + Rc::new(Environment::default()), + Set::from([1, 2]), + Process::EntitySet { + entities: Set::from([]), + next_process: Rc::new(Process::Nill), + }, + Rc::new(vec![Reaction { + reactants: Set::from([1]), + inhibitors: Set::from([3]), + products: Set::from([3]), + }]), ); let system: PositiveSystem = system.into(); - assert_eq!(system.available_entities.len(), 2); + assert_eq!(system.available_entities.len(), 3); // should be +1, +2, -3 assert_eq!(system.reaction_rules.len(), 3); } #[test] fn traces_1() { - use super::system::{System, ExtensionsSystem}; - use super::reaction::Reaction; - use super::process::Process; use super::environment::Environment; + use super::process::Process; + use super::reaction::Reaction; use super::set::Set; + use super::system::{ExtensionsSystem, System}; use std::rc::Rc; let system = System { - delta: Rc::new(Environment::from([ - (100, Process::WaitEntity { - repeat: 2, - repeated_process: Rc::new(Process::EntitySet { - entities: Set::from([1]), - next_process: Rc::new(Process::Nill) - }), - next_process: Rc::new(Process::Nill) }), - (102, Process::WaitEntity { - repeat: 3, - repeated_process: Rc::new(Process::EntitySet { - entities: Set::from([2]), - next_process: Rc::new(Process::Nill) }), - next_process: Rc::new(Process::Nill) }), - (103, Process::WaitEntity { - repeat: 4, - repeated_process: Rc::new(Process::EntitySet { - entities: Set::from([3]), - next_process: Rc::new(Process::Nill) }), - next_process: Rc::new(Process::Nill) }), - (101, Process::Summation { children: vec![ - Rc::new(Process::EntitySet { - entities: Set::from([10]), - next_process: Rc::new(Process::RecursiveIdentifier { - identifier: 100 }) }), - Rc::new(Process::EntitySet { - entities: Set::from([11]), - next_process: Rc::new(Process::RecursiveIdentifier { - identifier: 102 }) }), - Rc::new(Process::EntitySet { - entities: Set::from([11]), - next_process: Rc::new(Process::RecursiveIdentifier { - identifier: 103 }) }) - ] }), - ])), - available_entities: Set::from([1, 2]), - context_process: Process::RecursiveIdentifier { identifier: 101 }, - reaction_rules: - Rc::new(vec![Reaction { reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), }, - Reaction { reactants: Set::from([3]), - inhibitors: Set::from([1]), - products: Set::from([1]), }, - Reaction { reactants: Set::from([2]), - inhibitors: Set::default(), - products: Set::from([4]), }, - ]) + delta: Rc::new(Environment::from([ + ( + 100, + Process::WaitEntity { + repeat: 2, + repeated_process: Rc::new(Process::EntitySet { + entities: Set::from([1]), + next_process: Rc::new(Process::Nill), + }), + next_process: Rc::new(Process::Nill), + }, + ), + ( + 102, + Process::WaitEntity { + repeat: 3, + repeated_process: Rc::new(Process::EntitySet { + entities: Set::from([2]), + next_process: Rc::new(Process::Nill), + }), + next_process: Rc::new(Process::Nill), + }, + ), + ( + 103, + Process::WaitEntity { + repeat: 4, + repeated_process: Rc::new(Process::EntitySet { + entities: Set::from([3]), + next_process: Rc::new(Process::Nill), + }), + next_process: Rc::new(Process::Nill), + }, + ), + ( + 101, + Process::Summation { + children: vec![ + Rc::new(Process::EntitySet { + entities: Set::from([10]), + next_process: Rc::new(Process::RecursiveIdentifier { identifier: 100 }), + }), + Rc::new(Process::EntitySet { + entities: Set::from([11]), + next_process: Rc::new(Process::RecursiveIdentifier { identifier: 102 }), + }), + Rc::new(Process::EntitySet { + entities: Set::from([11]), + next_process: Rc::new(Process::RecursiveIdentifier { identifier: 103 }), + }), + ], + }, + ), + ])), + available_entities: Set::from([1, 2]), + context_process: Process::RecursiveIdentifier { identifier: 101 }, + reaction_rules: Rc::new(vec![ + Reaction { + reactants: Set::from([1]), + inhibitors: Set::from([3]), + products: Set::from([3]), + }, + Reaction { + reactants: Set::from([3]), + inhibitors: Set::from([1]), + products: Set::from([1]), + }, + Reaction { + reactants: Set::from([2]), + inhibitors: Set::default(), + products: Set::from([4]), + }, + ]), }; let res = system.clone().traces(1).unwrap(); @@ -192,33 +242,41 @@ fn traces_1() { #[test] fn traces_empty_env() { - use super::system::{System, ExtensionsSystem}; - use super::reaction::Reaction; - use super::process::Process; use super::environment::Environment; + use super::process::Process; + use super::reaction::Reaction; use super::set::Set; + use super::system::{ExtensionsSystem, System}; use std::rc::Rc; let system = System { - delta: Rc::new(Environment::from([])), - available_entities: Set::from([1, 2]), - context_process: Process::WaitEntity { - repeat: 10, - repeated_process: Rc::new(Process::EntitySet { - entities: Set::from([1, 2]), - next_process: Rc::new(Process::Nill) }), - next_process: Rc::new(Process::Nill) }, - reaction_rules: - Rc::new(vec![Reaction { reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), }, - Reaction { reactants: Set::from([3]), - inhibitors: Set::from([1]), - products: Set::from([1]), }, - Reaction { reactants: Set::from([2]), - inhibitors: Set::default(), - products: Set::from([4]), }, - ]) + delta: Rc::new(Environment::from([])), + available_entities: Set::from([1, 2]), + context_process: Process::WaitEntity { + repeat: 10, + repeated_process: Rc::new(Process::EntitySet { + entities: Set::from([1, 2]), + next_process: Rc::new(Process::Nill), + }), + next_process: Rc::new(Process::Nill), + }, + reaction_rules: Rc::new(vec![ + Reaction { + reactants: Set::from([1]), + inhibitors: Set::from([3]), + products: Set::from([3]), + }, + Reaction { + reactants: Set::from([3]), + inhibitors: Set::from([1]), + products: Set::from([1]), + }, + Reaction { + reactants: Set::from([2]), + inhibitors: Set::default(), + products: Set::from([4]), + }, + ]), }; let res = system.clone().traces(10).unwrap(); diff --git a/src/rsprocess/transitions.rs b/src/rsprocess/transitions.rs index 35bf3ba..aa6885c 100644 --- a/src/rsprocess/transitions.rs +++ b/src/rsprocess/transitions.rs @@ -2,27 +2,30 @@ use std::rc::Rc; +use super::environment::BasicEnvironment; use super::label::{Label, PositiveLabel}; use super::process::{BasicProcess, PositiveProcess, Process}; +use super::reaction::BasicReaction; use super::set::{BasicSet, PositiveSet, Set}; use super::system::{BasicSystem, PositiveSystem, System}; -use super::reaction::BasicReaction; -use super::environment::BasicEnvironment; #[derive(Clone, Debug)] -pub struct TransitionsIterator<'a, S: BasicSet, - Sys: BasicSystem, - Proc: BasicProcess> { +pub struct TransitionsIterator< + 'a, + S: BasicSet, + Sys: BasicSystem, + Proc: BasicProcess, +> { choices_iterator: std::vec::IntoIter<(Rc, Rc)>, system: &'a Sys, } impl<'a> TransitionsIterator<'a, Set, System, Process> { - pub fn from( - system: &'a System - ) -> Result { - match system.environment().unfold(system.context(), - system.available_entities()) { + pub fn from(system: &'a System) -> Result { + match system + .environment() + .unfold(system.context(), system.available_entities()) + { Ok(o) => Ok(TransitionsIterator { choices_iterator: o.into_iter(), system, @@ -39,13 +42,7 @@ impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> { fn next(&mut self) -> Option<(Label, System)> { let (c, k) = self.choices_iterator.next()?; let t = self.system.available_entities.union(c.as_ref()); - let ( - reactants, - reactants_absent, - inhibitors, - inhibitors_present, - products - ) = + let (reactants, reactants_absent, inhibitors, inhibitors_present, products) = self.system.reaction_rules.iter().fold( ( Set::default(), // reactants @@ -56,13 +53,13 @@ impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> { ), |acc, reaction| { if reaction.enabled(&t) { - ( + ( acc.0.union(&reaction.reactants), acc.1, acc.2.union(&reaction.inhibitors), acc.3, acc.4.union(&reaction.products), - ) + ) } else { ( acc.0, @@ -98,56 +95,50 @@ impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> { // ----------------------------------------------------------------------------- impl<'a> TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess> { - pub fn from( - system: &'a PositiveSystem - ) -> Result { - match system.environment().unfold(system.context(), - system.available_entities()) { + pub fn from(system: &'a PositiveSystem) -> Result { + match system + .environment() + .unfold(system.context(), system.available_entities()) + { Ok(o) => Ok(TransitionsIterator { choices_iterator: o.into_iter(), system, - }), + }), Err(e) => Err(e), } } } -impl<'a> Iterator for - TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess> { +impl<'a> Iterator for TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess> { type Item = (PositiveLabel, PositiveSystem); /// Creates the next arc from the current system. fn next(&mut self) -> Option { - let (c, k) = self.choices_iterator.next()?; + let (c, k) = self.choices_iterator.next()?; let t = self.system.available_entities.union(c.as_ref()); - let ( - reactants, - reactants_absent, - products - ) = - self.system.reaction_rules.iter().fold( - ( - PositiveSet::default(), // reactants - PositiveSet::default(), // reactants_absent - PositiveSet::default(), // products - ), - |acc, reaction| { - if reaction.enabled(&t) { - ( - acc.0.union(&reaction.reactants), - acc.1, - acc.2.union(&reaction.products), - ) - } else { - ( - acc.0, - // TODO is this right? - acc.1.union(&reaction.reactants.intersection(&t)), - acc.2, - ) - } - }, - ); + let (reactants, reactants_absent, products) = self.system.reaction_rules.iter().fold( + ( + PositiveSet::default(), // reactants + PositiveSet::default(), // reactants_absent + PositiveSet::default(), // products + ), + |acc, reaction| { + if reaction.enabled(&t) { + ( + acc.0.union(&reaction.reactants), + acc.1, + acc.2.union(&reaction.products), + ) + } else { + ( + acc.0, + // TODO is this right? + acc.1.union(&reaction.reactants.intersection(&t)), + acc.2, + ) + } + }, + ); let label = PositiveLabel::from( self.system.available_entities.clone(), diff --git a/src/rsprocess/translator.rs b/src/rsprocess/translator.rs index bc51d46..984369a 100644 --- a/src/rsprocess/translator.rs +++ b/src/rsprocess/translator.rs @@ -1,6 +1,6 @@ //! Module for translation and keeping track of strings. -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt; @@ -20,63 +20,59 @@ pub struct Translator { impl Translator { pub fn new() -> Self { - Translator { - strings: HashMap::from([("*".into(), 0)]), - reverse: HashMap::from([(0, "*".into())]), - last_id: 1, - } + Translator { + strings: HashMap::from([("*".into(), 0)]), + reverse: HashMap::from([(0, "*".into())]), + last_id: 1, + } } /// converts a string into an id pub fn encode(&mut self, s: impl Into) -> IdType { - let s = s.into(); - let id = *(self.strings.entry(s.clone()).or_insert({ - self.last_id += 1; - self.last_id - })); - self.reverse.insert(id, s.clone()); - id + let s = s.into(); + let id = *(self.strings.entry(s.clone()).or_insert({ + self.last_id += 1; + self.last_id + })); + self.reverse.insert(id, s.clone()); + id } pub fn encode_not_mut(&self, s: impl Into) -> Option { - self.strings.get(&s.into()).copied() + self.strings.get(&s.into()).copied() } /// converts an id into the corresponding string pub fn decode(&self, el: IdType) -> Option { - self.reverse - .get(&el) - .map(|x| x.to_string()) + self.reverse.get(&el).map(|x| x.to_string()) } } impl Default for Translator { fn default() -> Self { - Translator::new() + Translator::new() } } impl PartialEq for Translator { fn eq(&self, other: &Self) -> bool { - for (s, id) in self.strings.iter() { - match other.strings.get(s) { - None => return false, - Some(id2) if id != id2 => return false, - _ => {} - } - } - true + for (s, id) in self.strings.iter() { + match other.strings.get(s) { + None => return false, + Some(id2) if id != id2 => return false, + _ => {} + } + } + true } } - // ----------------------------------------------------------------------------- // print structures // ----------------------------------------------------------------------------- pub trait PrintableWithTranslator { - fn print(&self, f: &mut fmt::Formatter, translator: &Translator) - -> fmt::Result; + fn print(&self, f: &mut fmt::Formatter, translator: &Translator) -> fmt::Result; } pub struct Formatter<'a, T> { @@ -86,18 +82,15 @@ pub struct Formatter<'a, T> { impl<'a, T> fmt::Display for Formatter<'a, T> where - T: PrintableWithTranslator + T: PrintableWithTranslator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.data.print(f, self.translator) + self.data.print(f, self.translator) } } impl<'a, T> Formatter<'a, T> { - pub fn from( - translator: &'a Translator, - data: &'a T - ) -> Self { - Self { data, translator } + pub fn from(translator: &'a Translator, data: &'a T) -> Self { + Self { data, translator } } }