diff --git a/src/rsprocess/structure.rs b/src/rsprocess/structure.rs index 18d3902..81a6d0d 100644 --- a/src/rsprocess/structure.rs +++ b/src/rsprocess/structure.rs @@ -41,7 +41,7 @@ impl From> for RSset { } impl RSset { - pub fn new() -> Self { + pub const fn new() -> Self { RSset { identifiers: BTreeSet::new(), } diff --git a/src/rsprocess/transitions.rs b/src/rsprocess/transitions.rs index a2569e4..2c1c09e 100644 --- a/src/rsprocess/transitions.rs +++ b/src/rsprocess/transitions.rs @@ -1,11 +1,11 @@ //! Definitions for simple simulation steps. use super::structure::{RSchoices, - RSenvironment, - RSlabel, - RSprocess, - RSset, - RSsystem}; + RSenvironment, + RSlabel, + RSprocess, + RSset, + RSsystem}; use super::support_structures::TransitionsIterator; use std::rc::Rc; @@ -14,149 +14,216 @@ use std::rc::Rc; /// of entities and the continuation. /// see unfold pub fn unfold( - environment: &RSenvironment, - context_process: &RSprocess, - current_entities: &RSset, + environment: &RSenvironment, + context_process: &RSprocess, + current_entities: &RSset, ) -> Result { - match context_process { - RSprocess::Nill => { - Ok(RSchoices::new()) + match context_process { + RSprocess::Nill => { + Ok(RSchoices::new()) }, - RSprocess::RecursiveIdentifier { identifier } => { - let newprocess = environment.get(*identifier); - if let Some(newprocess) = newprocess { - unfold(environment, newprocess, current_entities) - } else { - Err(format!("Missing symbol in context: {identifier}")) - } - } - RSprocess::EntitySet { entities, next_process, } => { - Ok(RSchoices::from([( + RSprocess::RecursiveIdentifier { identifier } => { + let newprocess = environment.get(*identifier); + if let Some(newprocess) = newprocess { + unfold(environment, newprocess, current_entities) + } else { + Err(format!("Missing symbol in context: {identifier}")) + } + } + RSprocess::EntitySet { entities, next_process, } => { + Ok(RSchoices::from([( Rc::new(entities.clone()), Rc::clone(next_process), - )])) + )])) }, RSprocess::Guarded { reaction, next_process } => { - if reaction.enabled(current_entities) { + if reaction.enabled(current_entities) { Ok(RSchoices::from([(Rc::new(reaction.products.clone()), - Rc::clone(next_process))])) - } else { + Rc::clone(next_process))])) + } else { Ok(RSchoices::new()) - } + } } - RSprocess::WaitEntity { repeat, repeated_process: _, next_process, } + RSprocess::WaitEntity { repeat, repeated_process: _, next_process, } if *repeat <= 0 => { - unfold(environment, next_process, current_entities) + unfold(environment, next_process, current_entities) }, - RSprocess::WaitEntity { repeat, repeated_process, next_process, } + RSprocess::WaitEntity { repeat, repeated_process, next_process, } if *repeat == 1 => { - let mut choices1 = unfold(environment, repeated_process, current_entities)?; - choices1.replace(Rc::clone(next_process)); - Ok(choices1) - } - RSprocess::WaitEntity { repeat, repeated_process, next_process, } => { - let mut choices1 = unfold(environment, repeated_process, current_entities)?; - choices1.replace(Rc::new(RSprocess::WaitEntity { - repeat: (*repeat - 1), - repeated_process: Rc::clone(repeated_process), - next_process: Rc::clone(next_process), - })); - Ok(choices1) - } - RSprocess::Summation { children } => { - // short-circuits with try_fold. - children.iter().try_fold(RSchoices::new(), |mut acc, x| { - match unfold(environment, x, current_entities) { - Ok(mut choices) => { - acc.append(&mut choices); - Ok(acc) - } - Err(e) => Err(e), - } - }) - } - RSprocess::NondeterministicChoice { children } => { - // short-circuits with try_fold. - if children.is_empty() { - Ok(RSchoices::from(vec![( - Rc::new(RSset::new()), - Rc::new(RSprocess::Nill), - )])) - } else { - children.iter().try_fold(RSchoices::new(), |mut acc, x| { - acc.shuffle(unfold(environment, x, current_entities)?); - Ok(acc) - }) - } - } - } + let mut choices1 = unfold(environment, repeated_process, current_entities)?; + choices1.replace(Rc::clone(next_process)); + Ok(choices1) + } + RSprocess::WaitEntity { repeat, repeated_process, next_process, } => { + let mut choices1 = unfold(environment, repeated_process, current_entities)?; + choices1.replace(Rc::new(RSprocess::WaitEntity { + repeat: (*repeat - 1), + repeated_process: Rc::clone(repeated_process), + next_process: Rc::clone(next_process), + })); + Ok(choices1) + } + RSprocess::Summation { children } => { + // short-circuits with try_fold. + children.iter().try_fold(RSchoices::new(), |mut acc, x| { + match unfold(environment, x, current_entities) { + Ok(mut choices) => { + acc.append(&mut choices); + Ok(acc) + } + Err(e) => Err(e), + } + }) + } + RSprocess::NondeterministicChoice { children } => { + // short-circuits with try_fold. + if children.is_empty() { + Ok(RSchoices::from(vec![( + Rc::new(RSset::new()), + Rc::new(RSprocess::Nill), + )])) + } else { + children.iter().try_fold(RSchoices::new(), |mut acc, x| { + acc.shuffle(unfold(environment, x, current_entities)?); + Ok(acc) + }) + } + } + } } pub fn iterator_transitions<'a>( - system: &'a RSsystem + system: &'a RSsystem ) -> Result, String> { - TransitionsIterator::from(system) + TransitionsIterator::from(system) } /// see oneTransition, transition, smartTransition, smartOneTransition pub fn one_transition( - system: &RSsystem + system: &RSsystem ) -> Result, String> { - let mut tr = TransitionsIterator::from(system)?; - Ok(tr.next()) + let mut tr = TransitionsIterator::from(system)?; + Ok(tr.next()) } /// see allTransitions, smartAllTransitions pub fn all_transitions( - system: &RSsystem + system: &RSsystem ) -> Result, String> { - let tr = TransitionsIterator::from(system)?; - Ok(tr.collect::>()) + let tr = TransitionsIterator::from(system)?; + Ok(tr.collect::>()) } /// see oneTarget, smartOneTarget, target, smartTarget pub fn target( - system: &RSsystem + system: &RSsystem ) -> Result<(i64, RSset), String> { - let current = one_transition(system)?; - if current.is_none() { - return Ok((0, system.available_entities.clone())); - } - let mut n = 1; - let mut current = current.unwrap().1; - while let Some((_, next)) = one_transition(¤t)? { - current = next; - n += 1; - } - Ok((n, current.available_entities.clone())) + let current = one_transition(system)?; + if current.is_none() { + return Ok((0, system.available_entities.clone())); + } + let mut n = 1; + let mut current = current.unwrap().1; + while let Some((_, next)) = one_transition(¤t)? { + current = next; + n += 1; + } + Ok((n, current.available_entities.clone())) } /// see oneRun, run, smartOneRunEK, smartRunEK pub fn run(system: RSsystem) -> Result>, String> { - let mut res = vec![Rc::new(system)]; - while let Some((_, next_sys)) = one_transition(res.last().unwrap())? { - res.push(Rc::new(next_sys)); - } - Ok(res) + let mut res = vec![Rc::new(system)]; + while let Some((_, next_sys)) = one_transition(res.last().unwrap())? { + res.push(Rc::new(next_sys)); + } + Ok(res) } /// see smartOneRunECT, smartRunECT pub fn run_separated( - system: &RSsystem + system: &RSsystem ) -> Result, String> { - let mut res = vec![]; - let current = one_transition(system)?; - 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)) = one_transition(¤t)? { - current = next; + let mut res = vec![]; + let current = one_transition(system)?; + 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)) = one_transition(¤t)? { + current = next; let (available_entities, context, t) = label.get_context(); - res.push((available_entities.clone(), context.clone(), t.clone())); - } - Ok(res) + res.push((available_entities.clone(), context.clone(), t.clone())); + } + Ok(res) +} + + + +fn nth_transition( + system: &RSsystem, + n: usize, +) -> Result, String> { + let mut tr = TransitionsIterator::from(system)?; + Ok(tr.nth(n)) +} + +type Trace = Vec<(Option>, Rc)>; + +pub fn traces( + system: RSsystem, + 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(system))]; + let mut branch = vec![0]; + let mut depth = 0; + let mut new_branch = true; + + loop { + let next_sys = nth_transition(¤t_trace[depth].1, + 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 depth == 0 { + break; + } + + depth -= 1; + branch[depth] += 1; + } + } + + Ok(res) }