diff --git a/src/rsprocess/assert/tests.rs b/src/rsprocess/assert/tests.rs index d809749..d95549d 100644 --- a/src/rsprocess/assert/tests.rs +++ b/src/rsprocess/assert/tests.rs @@ -22,9 +22,9 @@ fn return_true() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -51,9 +51,9 @@ fn concat_1() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -80,9 +80,9 @@ fn concat_2() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -106,9 +106,9 @@ fn return_1() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -172,9 +172,9 @@ fn return_2() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -208,9 +208,9 @@ fn return_3() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -245,9 +245,9 @@ fn if_1() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -281,9 +281,9 @@ fn if_2() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -318,9 +318,9 @@ fn if_3() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -380,9 +380,9 @@ fn if_else_1() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -420,9 +420,9 @@ fn if_else_2() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -520,9 +520,9 @@ fn assignment_2() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -560,9 +560,9 @@ fn assignment_3() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -626,9 +626,9 @@ fn assignment_5() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -674,9 +674,9 @@ fn assignment_6() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -720,9 +720,9 @@ fn assignment_7() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -770,9 +770,9 @@ fn assignment_8() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -818,9 +818,9 @@ fn assignment_9() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -868,9 +868,9 @@ fn assignment_10() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -919,9 +919,9 @@ fn for_1() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + let node_2 = graph.add_node(System::default()); + let edge = graph.add_edge(node_1, node_2, Label::default()); assert!(tree.execute(&graph, &edge, &mut tr).is_err()); } @@ -973,9 +973,9 @@ fn for_2() { tr.encode("two"); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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(_)))); @@ -1041,9 +1041,9 @@ fn for_3() { tr.encode("two"); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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(_)))); @@ -1110,9 +1110,9 @@ fn for_4() { tr.encode("three"); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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(_)))); @@ -1192,9 +1192,9 @@ fn for_5() { tr.encode("three"); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -1284,9 +1284,9 @@ fn for_6() { tr.encode("three"); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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), @@ -1337,9 +1337,9 @@ fn for_7() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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), @@ -1406,9 +1406,9 @@ fn for_8() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let node_1 = graph.add_node(System::default()); + 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)))); @@ -1417,11 +1417,11 @@ fn for_8() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); - let node_2 = graph.add_node(System::new()); - let edge = graph.add_edge(node_1, node_2, Label::new()); - let node_3 = graph.add_node(System::new()); - graph.add_edge(node_1, node_3, Label::new()); + let node_1 = graph.add_node(System::default()); + let node_2 = graph.add_node(System::default()); + let edge = graph.add_edge(node_1, node_2, Label::default()); + 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)))); @@ -1476,16 +1476,16 @@ fn nodes() { let mut tr = Translator::new(); let mut graph = petgraph::Graph::new(); - let node_1 = graph.add_node(System::new()); + let node_1 = graph.add_node(System::default()); let node_2 = graph.add_node( System::from( - Rc::new(Environment::new()), + Rc::new(Environment::default()), Set::from([2]), Process::Nill, Rc::new(vec![]) ) ); - let edge = graph.add_edge(node_1, node_2, Label::new()); + let edge = graph.add_edge(node_1, node_2, Label::default()); println!("{:?}", tree.execute(&graph, &edge, &mut tr)); diff --git a/src/rsprocess/choices.rs b/src/rsprocess/choices.rs index f35f8ad..293c50d 100644 --- a/src/rsprocess/choices.rs +++ b/src/rsprocess/choices.rs @@ -1,33 +1,34 @@ +use std::fmt::Debug; use std::rc::Rc; -use super::process::Process; -use super::set::{BasicSet, Set}; +use super::process::{BasicProcess, PositiveProcess, Process}; +use super::set::{BasicSet, PositiveSet, Set}; use super::translator::{Translator, PrintableWithTranslator, Formatter}; -#[derive(Clone, Debug)] +pub trait BasicChoices +where Self: Clone + Debug + Default + IntoIterator + PrintableWithTranslator { + type Process: BasicProcess; + + fn append(&mut self, other: &mut Self); + fn replace(&mut self, other: Rc); + fn shuffle(&mut self, choices: Self); +} + +// ----------------------------------------------------------------------------- + +#[derive(Clone, Debug, Default)] pub struct Choices { context_moves: Vec<(Rc, Rc)>, } -impl Choices { - pub fn new() -> Self { - Choices { - context_moves: vec![], - } - } +impl BasicChoices for Choices { + type Process = Process; - pub fn new_not_empty() -> Self { - Choices { - context_moves: vec![(Rc::new(Set::default()), - Rc::new(Process::Nill))], - } - } - - pub fn append(&mut self, a: &mut Choices) { + fn append(&mut self, a: &mut Self) { self.context_moves.append(&mut a.context_moves); } - pub fn replace(&mut self, a: Rc) { + fn replace(&mut self, a: Rc) { self.context_moves = self .context_moves .iter_mut() @@ -35,7 +36,7 @@ impl Choices { .collect::>(); } - pub fn shuffle(&mut self, choices: Choices) { + fn shuffle(&mut self, choices: Self) { match ( self.context_moves.is_empty(), choices.context_moves.is_empty(), @@ -57,15 +58,11 @@ impl Choices { } } } - - pub fn iter(&self) -> std::slice::Iter<'_, (Rc, Rc)> { - self.context_moves.iter() - } } -impl Default for Choices { - fn default() -> Self { - Self::new() +impl Choices { + fn iter(&self) -> std::slice::Iter<'_, (Rc, Rc)> { + self.context_moves.iter() } } @@ -125,3 +122,109 @@ impl PrintableWithTranslator for Choices { write!(f, "]") } } + +// ----------------------------------------------------------------------------- + +#[derive(Clone, Debug, Default)] +pub struct PositiveChoices { + context_moves: Vec<(Rc, Rc)>, +} + +impl BasicChoices for PositiveChoices { + type Process = PositiveProcess; + + fn append(&mut self, a: &mut Self) { + 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::>(); + } + + 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; + } + } + } +} + +impl IntoIterator for PositiveChoices { + type Item = (Rc, Rc); + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + 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, "]") + } +} + +impl PositiveChoices { + 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() } + } +} + +impl From<&[(Rc, Rc)]> for PositiveChoices { + fn from(arr: &[(Rc, Rc)]) -> Self { + Self { context_moves: arr.to_vec() } + } +} + +impl From, Rc)>> for PositiveChoices { + fn from(arr: Vec<(Rc, Rc)>) -> Self { + Self { context_moves: arr } + } +} diff --git a/src/rsprocess/environment.rs b/src/rsprocess/environment.rs index 4223008..eb9917d 100644 --- a/src/rsprocess/environment.rs +++ b/src/rsprocess/environment.rs @@ -1,36 +1,49 @@ use serde::{Deserialize, Serialize}; use std::cmp; use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; use std::rc::Rc; -use super::choices::Choices; -use super::process::Process; +use super::choices::{BasicChoices, Choices, PositiveChoices}; +use super::process::{BasicProcess, PositiveProcess, Process}; use super::reaction::{Reaction, BasicReaction, ExtensionReaction}; -use super::set::{BasicSet, Set}; +use super::set::{BasicSet, PositiveSet, Set}; use super::element::IdType; use super::translator::{Translator, PrintableWithTranslator, Formatter}; -#[derive(Clone, Debug, Serialize, Deserialize)] +pub trait BasicEnvironment +where Self: Clone + Debug + Default + Serialize + PrintableWithTranslator, +for<'a> Self: Deserialize<'a> { + type Id; + type Set: BasicSet; + type Choices: BasicChoices; + type Process: BasicProcess; + + fn get(&self, k: Self::Id) -> Option<&Self::Process>; + fn all_elements(&self) -> Self::Set; + fn unfold( + &self, + context: &Self::Process, + entities: &Self::Set, + ) -> Result; +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Environment { definitions: HashMap, } -impl Environment { - pub fn new() -> Environment { - Environment { - definitions: HashMap::new(), - } - } +impl BasicEnvironment for Environment { + type Process = Process; + type Set = Set; + type Choices = Choices; + type Id = IdType; - pub fn get(&self, k: IdType) -> Option<&Process> { + fn get(&self, k: IdType) -> Option<&Process> { self.definitions.get(&k) } - pub fn iter(&self) -> std::collections::hash_map::Iter<'_, u32, Process> { - self.definitions.iter() - } - - pub fn all_elements(&self) -> Set { + fn all_elements(&self) -> Set { let mut acc = Set::default(); for (_, process) in self.definitions.iter() { acc.push(&process.all_elements()); @@ -42,14 +55,14 @@ impl Environment { /// definitions environment. choices::Choices is a list of context moves /// mapping a set of entities and the continuation. /// see unfold - pub fn unfold( + fn unfold( &self, context_process: &Process, current_entities: &Set, ) -> Result { match context_process { Process::Nill => { - Ok(Choices::new()) + Ok(Choices::default()) }, Process::RecursiveIdentifier { identifier } => { let newprocess = self.get(*identifier); @@ -70,7 +83,7 @@ impl Environment { Ok(Choices::from([(Rc::new(reaction.products.clone()), Rc::clone(next_process))])) } else { - Ok(Choices::new()) + Ok(Choices::default()) } } Process::WaitEntity { repeat, repeated_process: _, next_process, } @@ -97,7 +110,7 @@ impl Environment { } Process::Summation { children } => { // short-circuits with try_fold. - children.iter().try_fold(Choices::new(), |mut acc, x| { + children.iter().try_fold(Choices::default(), |mut acc, x| { match self.unfold(x, current_entities) { Ok(mut choices) => { acc.append(&mut choices); @@ -115,7 +128,7 @@ impl Environment { Rc::new(Process::Nill), )])) } else { - children.iter().try_fold(Choices::new(), |mut acc, x| { + children.iter().try_fold(Choices::default(), |mut acc, x| { acc.shuffle(self.unfold(x, current_entities)?); Ok(acc) }) @@ -125,36 +138,6 @@ impl Environment { } } -impl Default for Environment { - fn default() -> Self { - Environment::new() - } -} - -impl From<[(IdType, Process); N]> for Environment { - fn from(arr: [(IdType, Process); N]) -> Self { - 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()), - } - } -} - -impl From> for Environment { - fn from(arr: Vec<(IdType, Process)>) -> Self { - Environment { - definitions: HashMap::from_iter(arr), - } - } -} - impl PrintableWithTranslator for Environment { fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { @@ -181,6 +164,36 @@ impl PrintableWithTranslator for Environment { } } +impl Environment { + pub fn iter(&self) -> std::collections::hash_map::Iter<'_, u32, Process> { + self.definitions.iter() + } +} + +impl From<[(IdType, Process); N]> for Environment { + fn from(arr: [(IdType, Process); N]) -> Self { + 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()), + } + } +} + +impl From> for Environment { + fn from(arr: Vec<(IdType, Process)>) -> Self { + Environment { + definitions: HashMap::from_iter(arr), + } + } +} + // ----------------------------------------------------------------------------- // Loops @@ -510,3 +523,167 @@ impl Environment { // TODO: weak confluence } + +// ----------------------------------------------------------------------------- + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct PositiveEnvironment { + definitions: HashMap, +} + +impl BasicEnvironment for PositiveEnvironment { + type Id = IdType; + type Set = PositiveSet; + type Choices = PositiveChoices; + type Process = PositiveProcess; + + fn get(&self, k: Self::Id) -> Option<&Self::Process> { + 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 + } + + fn unfold( + &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) + }) + } + } + } + } +} + +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, + "({} -> {})", + translator.decode(*el.0).unwrap_or("Missing".into()), + Formatter::from(translator, el.1) + )?; + } else { + write!( + f, + "({} -> {}), ", + translator.decode(*el.0).unwrap_or("Missing".into()), + Formatter::from(translator, el.1) + )?; + } + } + write!(f, "}}") + } +} + +impl PositiveEnvironment { + pub fn iter( + &self + ) -> impl std::iter::Iterator { + 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::>() + } + } +} + +impl From for PositiveEnvironment { + fn from(value: Environment) -> Self { + (&value).into() + } +} diff --git a/src/rsprocess/frequency.rs b/src/rsprocess/frequency.rs index b85a9f7..7db8983 100644 --- a/src/rsprocess/frequency.rs +++ b/src/rsprocess/frequency.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use super::reaction::{Reaction, ExtensionReaction}; use super::set::{Set, ExtensionsSet}; -use super::system::System; +use super::system::{System, ExtensionsSystem}; use super::element::IdType; use super::translator::{Translator, PrintableWithTranslator, PRECISION}; diff --git a/src/rsprocess/grammar.lalrpop b/src/rsprocess/grammar.lalrpop index c8fc61a..28d0d0f 100644 --- a/src/rsprocess/grammar.lalrpop +++ b/src/rsprocess/grammar.lalrpop @@ -256,7 +256,7 @@ CTX_process: process::Process = { // ----------------------------------------------------------------------------- pub Environment: Box = { "[" "]" => - Box::new(environment::Environment::new()), + Box::new(environment::Environment::default()), "[" > "]" => Box::new(environment::Environment::from(t)) }; diff --git a/src/rsprocess/label.rs b/src/rsprocess/label.rs index 57b5cdc..53adac4 100644 --- a/src/rsprocess/label.rs +++ b/src/rsprocess/label.rs @@ -1,10 +1,22 @@ use serde::{Deserialize, Serialize}; +use std::fmt::Debug; use std::hash::Hash; -use super::set::{BasicSet, Set}; +use super::set::{BasicSet, PositiveSet, Set}; use super::translator::{Translator, PrintableWithTranslator, Formatter}; -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialOrd)] +pub trait BasicLabel +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); +} + +// ----------------------------------------------------------------------------- + +#[derive(Default, Clone, Debug, Serialize, Deserialize, Eq, PartialOrd, Ord)] pub struct Label { pub available_entities: Set, pub context: Set, @@ -16,20 +28,19 @@ pub struct Label { pub products: Set, } -impl Label { - pub fn new() -> Self { - Label { - available_entities: Set::default(), - context: Set::default(), - t: Set::default(), - reactants: Set::default(), - reactants_absent: Set::default(), - inhibitors: Set::default(), - inhibitors_present: Set::default(), - products: Set::default(), - } - } +impl BasicLabel for Label { + type Set = Set; + fn get_context(&self) -> (&Set, &Set, &Set) { + ( + &self.available_entities, + &self.context, + &self.t, + ) + } +} + +impl Label { #[allow(clippy::too_many_arguments)] pub fn from( available_entities: Set, @@ -74,20 +85,6 @@ impl Label { products, } } - - pub fn get_context(&self) -> (&Set, &Set, &Set) { - ( - &self.available_entities, - &self.context, - &self.t, - ) - } -} - -impl Default for Label { - fn default() -> Self { - Self::new() - } } impl PartialEq for Label { @@ -122,7 +119,14 @@ impl PrintableWithTranslator for Label { -> std::fmt::Result { write!( f, - "{{available_entities: {}, context: {}, t: {}, reactants: {}, reactantsi: {}, inihibitors: {}, ireactants: {}, products: {}}}", + "{{available_entities: {}, \ + context: {}, \ + t: {}, \ + reactants: {}, \ + reactantsi: {}, \ + inihibitors: {}, \ + ireactants: {}, \ + products: {}}}", Formatter::from(translator, &self.available_entities), Formatter::from(translator, &self.context), Formatter::from(translator, &self.t), @@ -134,3 +138,110 @@ impl PrintableWithTranslator for Label { ) } } + +// ----------------------------------------------------------------------------- + +#[derive(Default, Clone, Debug, Serialize, Deserialize, Eq, PartialOrd, Ord)] +pub struct PositiveLabel { + pub available_entities: PositiveSet, + pub context: PositiveSet, + pub t: PositiveSet, + pub reactants: PositiveSet, + pub reactants_absent: PositiveSet, + pub products: PositiveSet, +} + +impl BasicLabel for PositiveLabel { + type Set = PositiveSet; + + fn get_context(&self) -> (&PositiveSet, &PositiveSet, &PositiveSet) { + ( + &self.available_entities, + &self.context, + &self.t, + ) + } +} + +impl PartialEq for PositiveLabel { + fn eq(&self, other: &Self) -> bool { + self.available_entities == other.available_entities && + self.context == other.context && + // self.t == other.t && // no need since its the union of the above + // // elements + self.reactants == other.reactants && + self.reactants_absent == other.reactants_absent && + self.products == other.products + } +} + +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); + } +} + +impl PrintableWithTranslator for PositiveLabel { + 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), + ) + } +} + +impl PositiveLabel { + #[allow(clippy::too_many_arguments)] + pub fn from( + available_entities: PositiveSet, + context: PositiveSet, + t: PositiveSet, + reactants: PositiveSet, + reactants_absent: PositiveSet, + products: PositiveSet, + ) -> Self { + 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, + ) -> Self { + Self { + available_entities: available_entities.clone(), + context: context.clone(), + t: available_entities.union(&context), + reactants, + reactants_absent, + products, + } + } +} diff --git a/src/rsprocess/presets.rs b/src/rsprocess/presets.rs index c49876f..31d256c 100644 --- a/src/rsprocess/presets.rs +++ b/src/rsprocess/presets.rs @@ -12,6 +12,7 @@ use std::rc::Rc; use super::*; use super::graph::MapEdges; use super::set::Set; +use super::system::{ExtensionsSystem}; use super::translator::Translator; use super::super::grammar; diff --git a/src/rsprocess/process.rs b/src/rsprocess/process.rs index f375b05..c41fa66 100644 --- a/src/rsprocess/process.rs +++ b/src/rsprocess/process.rs @@ -1,13 +1,28 @@ use serde::{Deserialize, Serialize}; use std::collections::VecDeque; +use std::fmt::Debug; use std::hash::Hash; use std::rc::Rc; -use super::reaction::Reaction; -use super::set::{Set, BasicSet}; -use super::element::IdType; +use super::reaction::{PositiveReaction, Reaction}; +use super::set::{BasicSet, PositiveSet, Set}; +use super::element::{IdState, IdType}; use super::translator::{Translator, PrintableWithTranslator, Formatter}; +pub trait BasicProcess +where Self: Clone + Debug + Default + PartialEq + Eq + Hash + Serialize + + PrintableWithTranslator, +for<'a> Self: Deserialize<'a> { + type Id; + type Set: BasicSet; + + fn concat(&self, new: &Self) -> Self; + fn all_elements(&self) -> Self::Set; + fn filter_delta(&self, id: &Self::Id) -> Option<&Self::Set>; +} + +// ----------------------------------------------------------------------------- + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Process { Nill, @@ -35,34 +50,36 @@ pub enum Process { }, } -impl Process { - // TODO: remove all the clone() - pub fn concat(&self, new: &Process) -> Process { +impl BasicProcess for Process { + type Id = IdType; + type Set = Set; + + fn concat(&self, new: &Self) -> Self { match (self, new) { ( - Process::NondeterministicChoice { children: c1 }, - Process::NondeterministicChoice { children: c2 }, - ) => Process::NondeterministicChoice { + Self::NondeterministicChoice { children: c1 }, + Self::NondeterministicChoice { children: c2 }, + ) => Self::NondeterministicChoice { children: [c1.clone(), c2.clone()].concat(), }, - (Process::NondeterministicChoice { children }, new) - | (new, Process::NondeterministicChoice { children }) => { + (Self::NondeterministicChoice { children }, new) + | (new, Self::NondeterministicChoice { children }) => { let mut new_children = children.clone(); new_children.push(Rc::new(new.clone())); - Process::NondeterministicChoice { + Self::NondeterministicChoice { children: new_children, } } - (_, _) => Process::NondeterministicChoice { + (_, _) => Self::NondeterministicChoice { children: vec![Rc::new(self.clone()), Rc::new(new.clone())], }, } } /// returns all elements used - pub fn all_elements(&self) -> Set { + fn all_elements(&self) -> Self::Set { let mut queue = VecDeque::from([self]); - let mut elements = Set::default(); + let mut elements = Self::Set::default(); while let Some(el) = queue.pop_front() { match el { @@ -104,13 +121,12 @@ impl Process { elements } - /// Finds only the rules X = pre(Q, rec(X)), but not only x = pre(Q, rec(x)) /// to use in filter_map. - pub fn filter_delta<'a>( + fn filter_delta<'a>( &'a self, - id: &IdType - ) -> Option<&'a Set> { + id: &Self::Id + ) -> Option<&'a Self::Set> { if let Self::EntitySet { entities, next_process } = self && let Self::RecursiveIdentifier { identifier } = &**next_process && identifier == id @@ -122,6 +138,12 @@ impl Process { } } +impl Default for Process { + fn default() -> Self { + Self::Nill + } +} + impl PrintableWithTranslator for Process { fn print(&self, f: &mut std::fmt::Formatter, translator: &Translator) -> std::fmt::Result { @@ -201,3 +223,246 @@ impl PrintableWithTranslator for Process { } } } + +// ----------------------------------------------------------------------------- + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum PositiveProcess { + Nill, + RecursiveIdentifier { + identifier: IdType, + }, + EntitySet { + entities: PositiveSet, + next_process: Rc, + }, + Guarded { + reaction: PositiveReaction, + next_process: Rc, + }, + WaitEntity { + repeat: i64, + repeated_process: Rc, + next_process: Rc, + }, + Summation { + children: Vec>, + }, + NondeterministicChoice { + children: Vec>, + }, +} + +impl BasicProcess for PositiveProcess { + type Id = IdType; + 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())], + }, + } + } + + /// returns all elements used + fn all_elements(&self) -> Self::Set { + 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 + } + + /// 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); + } + + None + } +} + +impl Default for PositiveProcess { + fn default() -> Self { + 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, "]") + } + } + } +} + +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() } + } + } +} + +impl Fromfor PositiveProcess { + fn from(value: Process) -> Self { + (&value).into() + } +} diff --git a/src/rsprocess/reaction.rs b/src/rsprocess/reaction.rs index fc0a8eb..b46cc49 100644 --- a/src/rsprocess/reaction.rs +++ b/src/rsprocess/reaction.rs @@ -6,6 +6,7 @@ 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}; @@ -161,7 +162,7 @@ impl BasicReaction for Reaction { /// returns true if ```current_state``` enables the reaction /// see enable - fn enabled(&self, current_state: &Set) -> bool { + fn enabled(&self, current_state: &Self::Set) -> bool { self.reactants.is_subset(current_state) && self.inhibitors.is_disjoint(current_state) } @@ -169,7 +170,7 @@ impl BasicReaction for Reaction { /// Computes the result of a single reaction (if enabled returns the /// products) otherwise returns None. /// see result - fn compute_step(&self, state: &Set) -> Option<&Set> { + fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { if self.enabled(state) { Some(&self.products) } else { @@ -195,6 +196,29 @@ impl Reaction { pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self { Reaction { reactants, inhibitors, products } } + + pub fn all_products(reactions: &[Self]) -> Set { + 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 + } + ) + } } // ----------------------------------------------------------------------------- @@ -208,11 +232,11 @@ pub struct PositiveReaction { impl BasicReaction for PositiveReaction { type Set = PositiveSet; - fn enabled(&self, state: &PositiveSet) -> bool { + fn enabled(&self, state: &Self::Set) -> bool { self.reactants.is_subset(state) } - fn compute_step(&self, state: &PositiveSet) -> Option<&PositiveSet> { + fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set> { if self.enabled(state) { Some(&self.products) } else { @@ -235,6 +259,14 @@ impl PrintableWithTranslator for PositiveReaction { impl PositiveReaction { pub fn from(reactants: PositiveSet, products: PositiveSet) -> Self { - PositiveReaction { 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) } } } diff --git a/src/rsprocess/set.rs b/src/rsprocess/set.rs index f68e30b..72eea1e 100644 --- a/src/rsprocess/set.rs +++ b/src/rsprocess/set.rs @@ -14,6 +14,8 @@ where Self: Clone + Eq + Ord + Default + Serialize + IntoIterator + PrintableWithTranslator, for<'de> Self: Deserialize<'de> { + type Element; + fn is_subset(&self, other: &Self) -> bool; fn is_disjoint(&self, other: &Self) -> bool; fn union(&self, other: &Self) -> Self; @@ -23,6 +25,7 @@ for<'de> Self: Deserialize<'de> fn subtraction(&self, other: &Self) -> Self; fn len(&self) -> usize; fn is_empty(&self) -> bool; + fn contains(&self, el: &Self::Element) -> bool; } pub trait ExtensionsSet { @@ -65,6 +68,8 @@ pub struct Set { } impl BasicSet for Set { + type Element = IdType; + fn is_subset(&self, other: &Self) -> bool { self.identifiers.is_subset(&other.identifiers) } @@ -119,6 +124,10 @@ impl BasicSet for Set { fn is_empty(&self) -> bool { self.identifiers.is_empty() } + + fn contains(&self, el: &Self::Element) -> bool { + self.identifiers.contains(el) + } } impl PartialEq for Set { @@ -323,6 +332,8 @@ pub struct PositiveSet { } 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) { @@ -406,6 +417,14 @@ impl BasicSet for PositiveSet { fn is_empty(&self) -> bool { 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 + } + } } impl PrintableWithTranslator for PositiveSet { diff --git a/src/rsprocess/system.rs b/src/rsprocess/system.rs index ef240ed..8462eb1 100644 --- a/src/rsprocess/system.rs +++ b/src/rsprocess/system.rs @@ -1,94 +1,147 @@ +use petgraph::graph::DiGraph; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::fmt::Debug; use std::hash::Hash; use std::rc::Rc; -use super::environment::Environment; -use super::graph::SystemGraph; -use super::label::Label; -use super::process::Process; -use super::reaction::{Reaction, ExtensionReaction}; -use super::set::{BasicSet, Set}; -use super::element::IdType; +use super::environment::{Environment, BasicEnvironment, 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, IdType}; use super::transitions::TransitionsIterator; use super::translator::{Translator, PrintableWithTranslator, Formatter}; +pub trait BasicSystem +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; -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct System { - pub delta: Rc, - pub available_entities: Set, - pub context_process: Process, - pub reaction_rules: Rc>, + fn to_transitions_iterator( + &self + ) -> Result, String>; + + fn environment(&self) -> &Self::Environment; + fn available_entities(&self) -> &Self::Set; + fn context(&self) -> &Self::Process; + fn reactions(&self) -> &Vec; } -type Trace = Vec<(Option>, Rc)>; +type Trace = Vec<(Option>, Rc)>; -impl System { - pub fn new() -> System { - System { - delta: Rc::new(Environment::new()), - available_entities: Set::default(), - context_process: Process::Nill, - reaction_rules: Rc::new(vec![]), - } - } - - pub fn from( - 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), - } - } - - pub fn to_transitions_iterator<'a>( - &'a self - ) -> Result, String> { - TransitionsIterator::from(self) - } - - - /// see oneTransition, transition, smartTransition, smartOneTransition - pub fn one_transition( +pub trait ExtensionsSystem: BasicSystem { + fn one_transition( &self - ) -> Result, String> { + ) -> Result, String>; + + fn nth_transition( + &self, + n: usize, + ) -> Result, String>; + + fn all_transitions( + &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 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()) } - - pub fn nth_transition( + fn nth_transition( &self, n: usize, - ) -> Result, String> { + ) -> Result, String> { let mut tr = self.to_transitions_iterator()?; Ok(tr.nth(n)) } - /// see allTransitions, smartAllTransitions - pub fn all_transitions( + fn all_transitions( &self - ) -> Result, String> { + ) -> Result, String> { let tr = self.to_transitions_iterator()?; Ok(tr.collect::>()) } - - /// see oneTarget, smartOneTarget, target, smartTarget - pub fn target( + /// see oneRun, run, smartOneRunEK, smartRunEK + fn run( &self - ) -> Result<(i64, Set), String> { + ) -> 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; + + let mut graph = Graph::default(); + let node = graph.add_node(self.clone()); + + let mut association = HashMap::new(); + association.insert(self.clone(), node); + + let mut stack = vec![self]; + + 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) + } + + /// 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())); + return Ok((0, self.available_entities().clone())); } let mut n = 1; let mut current = current.unwrap().1; @@ -96,25 +149,13 @@ impl System { current = next; n += 1; } - Ok((n, current.available_entities.clone())) + Ok((n, current.available_entities().clone())) } - /// see oneRun, run, smartOneRunEK, smartRunEK - pub fn run( - self - ) -> Result>, String> { - let mut res = vec![Rc::new(self)]; - while let Some((_, next_sys)) = res.last().unwrap().one_transition()? { - res.push(Rc::new(next_sys)); - } - Ok(res) - } - - /// see smartOneRunECT, smartRunECT - pub fn run_separated( + fn run_separated( &self - ) -> Result, String> { + ) -> Result, String> { let mut res = vec![]; let current = self.one_transition()?; if current.is_none() { @@ -132,16 +173,21 @@ impl System { Ok(res) } - pub fn traces( + /// 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> { + ) -> 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 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; @@ -187,6 +233,46 @@ impl System { } } +// ----------------------------------------------------------------------------- + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct System { + pub delta: Rc, + pub available_entities: Set, + pub context_process: Process, + pub reaction_rules: Rc>, +} + +impl BasicSystem for System { + type Set = Set; + type Reaction = Reaction; + type Label = Label; + type Process = Process; + type Environment = Environment; + + fn to_transitions_iterator( + &self + ) -> Result, String> { + TransitionsIterator::::from(self) + } + + fn environment(&self) -> &Self::Environment { + &self.delta + } + + fn available_entities(&self) -> &Self::Set { + &self.available_entities + } + + fn context(&self) -> &Self::Process { + &self.context_process + } + + fn reactions(&self) -> &Vec { + &self.reaction_rules + } +} + /// Equality does not care about delta or reaction rules. Only entities and /// context is compared impl PartialEq for System { @@ -214,7 +300,10 @@ impl Hash for System { impl Default for System { fn default() -> Self { - System::new() + Self { delta: Rc::new(Environment::default()), + available_entities: Set::default(), + context_process: Process::Nill, + reaction_rules: Rc::new(Vec::default()) } } } @@ -242,6 +331,23 @@ impl PrintableWithTranslator for System { } +impl System { + pub fn from( + 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), + } + } +} + + // ----------------------------------------------------------------------------- // Loops // ----------------------------------------------------------------------------- @@ -339,43 +445,6 @@ impl System { } } -// ----------------------------------------------------------------------------- -// Graph -// ----------------------------------------------------------------------------- - -impl System { - /// Creates a graph starting from a system as root node - pub fn digraph( - self - ) -> Result { - use petgraph::Graph; - - let mut graph = Graph::default(); - let node = graph.add_node(self.clone()); - - let mut association = HashMap::new(); - association.insert(self.clone(), node); - - let mut stack = vec![self]; - - while let Some(current) = stack.pop() { - // depth first - let current_node = *association.get(¤t).unwrap(); - - for (label, next) in TransitionsIterator::from(¤t)? { - // 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) - } -} - - // ----------------------------------------------------------------------------- // Statistics // ----------------------------------------------------------------------------- @@ -388,7 +457,7 @@ impl System { &self, translator: &Translator, ) -> String { - use super::translator; + use super::translator::Formatter; let mut result: String = "Statistics:\n".into(); result.push_str( @@ -400,7 +469,7 @@ impl System { )); result.push_str(&format!( "{}\n", - translator::Formatter::from(translator, &self.available_entities) + Formatter::from(translator, &self.available_entities) )); let reactants = self @@ -410,7 +479,7 @@ impl System { result.push_str(&format!( "The reactants are {}:\n{}\n", reactants.len(), - translator::Formatter::from(translator, &reactants) + Formatter::from(translator, &reactants) )); let inhibitors = self @@ -420,7 +489,7 @@ impl System { result.push_str(&format!( "The inhibitors are {}:\n{}\n", inhibitors.len(), - translator::Formatter::from(translator, &inhibitors) + Formatter::from(translator, &inhibitors) )); let products = self @@ -430,28 +499,28 @@ impl System { result.push_str(&format!( "The products are {}:\n{}\n", products.len(), - translator::Formatter::from(translator, &products) + Formatter::from(translator, &products) )); let total = reactants.union(&inhibitors.union(&products)); result.push_str(&format!( "The reactions involve {} entities:\n{}\n", total.len(), - translator::Formatter::from(translator, &total) + Formatter::from(translator, &total) )); let entities_env = self.delta.all_elements(); result.push_str(&format!( "The environment involves {} entities:\n{}\n", entities_env.len(), - translator::Formatter::from(translator, &entities_env) + 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(), - translator::Formatter::from(translator, &entities_context) + Formatter::from(translator, &entities_context) )); let entities_all = total @@ -462,7 +531,7 @@ impl System { result.push_str(&format!( "The whole RS involves {} entities:\n{}\n", entities_all.len(), - translator::Formatter::from(translator, &entities_all) + Formatter::from(translator, &entities_all) )); let possible_e = products @@ -472,7 +541,7 @@ impl System { result.push_str(&format!( "There are {} reactants that will never be available:\n{}\n", missing_e.len(), - translator::Formatter::from(translator, &missing_e) + Formatter::from(translator, &missing_e) )); let entities_not_needed = entities_context.subtraction(&total); @@ -480,7 +549,7 @@ impl System { "The context can provide {} entities that will never be used:\ \n{}\n", entities_not_needed.len(), - translator::Formatter::from(translator, &entities_not_needed) + Formatter::from(translator, &entities_not_needed) )); result.push_str(&format!( @@ -515,3 +584,165 @@ impl System { result } } + + +// ----------------------------------------------------------------------------- +// Positive System +// ----------------------------------------------------------------------------- + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct PositiveSystem { + pub delta: Rc, + pub available_entities: PositiveSet, + pub context_process: PositiveProcess, + pub reaction_rules: Rc>, +} + +impl BasicSystem for PositiveSystem { + type Set = PositiveSet; + type Reaction = PositiveReaction; + type Label = PositiveLabel; + type Process = PositiveProcess; + type Environment = PositiveEnvironment; + + fn to_transitions_iterator( + &self + ) -> Result, String> { + TransitionsIterator::::from(self) + } + + fn environment(&self) -> &Self::Environment { + &self.delta + } + + fn available_entities(&self) -> &Self::Set { + &self.available_entities + } + + fn context(&self) -> &Self::Process { + &self.context_process + } + + fn reactions(&self) -> &Vec { + &self.reaction_rules + } +} + +/// Equality does not care about delta or reaction rules. Only entities and +/// context is compared +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 + } +} + +/// Equality does not care about delta or reaction rules. Only entities and +/// context is compared +impl Eq for PositiveSystem {} + +/// Hash does not care about delta or reaction rules. Only entities and +/// context is hashed +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); + } +} + +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()) } + } +} + +impl PrintableWithTranslator for PositiveSystem { + 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, "] ]") + } +} + +impl From for PositiveSystem { + /// Converts from a normal system to a positive one, replaces every reaction + /// {r, i, p} with a positive reaction {r ∪ ¬i, p} and with {t, el} for each + /// el ∈ p for p in some reaction and t ∈ prohibiting set of a with respect + /// 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) + }; + + 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>, + ) -> Self { + 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 e51439e..9a41fc8 100644 --- a/src/rsprocess/system_test.rs +++ b/src/rsprocess/system_test.rs @@ -1,6 +1,118 @@ +#[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 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]), }, ]) + ); + + match system.one_transition() { + 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 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)]), }, ]) + ); + + 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!() + }; + + match system.one_transition() { + 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 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]), }, ]) + ); + + let system: PositiveSystem = system.into(); + + assert_eq!(system.available_entities.len(), 2); + assert_eq!(system.reaction_rules.len(), 3); +} + #[test] fn traces_1() { - use super::system::System; + use super::system::{System, ExtensionsSystem}; use super::reaction::Reaction; use super::process::Process; use super::environment::Environment; @@ -58,15 +170,6 @@ fn traces_1() { ]) }; - // for (pos, trace) in res.iter().enumerate() { - // println!("trace {}:", pos); - // for (_, sy) in trace { - // let ent = format!("{:?}", sy.available_entities); - // let con = format!("{:?}", sy.context_process); - // println!("\t({}, {})", ent, con); - // } - // } - let res = system.clone().traces(1).unwrap(); assert_eq!(res.len(), 1); @@ -89,7 +192,7 @@ fn traces_1() { #[test] fn traces_empty_env() { - use super::system::System; + use super::system::{System, ExtensionsSystem}; use super::reaction::Reaction; use super::process::Process; use super::environment::Environment; diff --git a/src/rsprocess/transitions.rs b/src/rsprocess/transitions.rs index 15e664d..35bf3ba 100644 --- a/src/rsprocess/transitions.rs +++ b/src/rsprocess/transitions.rs @@ -2,24 +2,27 @@ use std::rc::Rc; -use super::label::Label; -use super::process::Process; -use super::set::{BasicSet, Set}; -use super::system::System; +use super::label::{Label, PositiveLabel}; +use super::process::{BasicProcess, PositiveProcess, Process}; +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> { - choices_iterator: std::vec::IntoIter<(Rc, Rc)>, - system: &'a System, +pub struct TransitionsIterator<'a, S: BasicSet, + Sys: BasicSystem, + Proc: BasicProcess> { + choices_iterator: std::vec::IntoIter<(Rc, Rc)>, + system: &'a Sys, } -impl<'a> TransitionsIterator<'a> { +impl<'a> TransitionsIterator<'a, Set, System, Process> { pub fn from( system: &'a System - ) -> Result, String> { - match system.delta.unfold(&system.context_process, - &system.available_entities) { + ) -> Result { + match system.environment().unfold(system.context(), + system.available_entities()) { Ok(o) => Ok(TransitionsIterator { choices_iterator: o.into_iter(), system, @@ -29,7 +32,7 @@ impl<'a> TransitionsIterator<'a> { } } -impl<'a> Iterator for TransitionsIterator<'a> { +impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> { type Item = (Label, System); /// Creates the next arc from the current system. @@ -91,3 +94,75 @@ impl<'a> Iterator for TransitionsIterator<'a> { Some((label, new_system)) } } + +// ----------------------------------------------------------------------------- + +impl<'a> TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess> { + 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> { + 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 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 label = PositiveLabel::from( + self.system.available_entities.clone(), + (*c).clone(), + t, + reactants, + reactants_absent, + products.clone(), + ); + let new_system = PositiveSystem::from( + Rc::clone(&self.system.delta), + products, + (*k).clone(), + Rc::clone(&self.system.reaction_rules), + ); + Some((label, new_system)) + } +}