From f8740b8bd7043b64341be7d40617fcb34005bbee Mon Sep 17 00:00:00 2001 From: elvis Date: Fri, 22 Aug 2025 01:40:15 +0200 Subject: [PATCH] Better tests --- src/rsprocess/assert/tests.rs | 70 +++--- src/rsprocess/transitions.rs | 437 +++++++++++++++++++++------------- 2 files changed, 311 insertions(+), 196 deletions(-) diff --git a/src/rsprocess/assert/tests.rs b/src/rsprocess/assert/tests.rs index 88534f8..ed8f341 100644 --- a/src/rsprocess/assert/tests.rs +++ b/src/rsprocess/assert/tests.rs @@ -9,7 +9,7 @@ use super::rsassert::*; type LocalAssert = RSassert; #[test] -fn assert_tycheck_true() { +fn return_true() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -29,7 +29,7 @@ fn assert_tycheck_true() { } #[test] -fn assert_tycheck_concat_1() { +fn concat_1() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -57,7 +57,7 @@ fn assert_tycheck_concat_1() { } #[test] -fn assert_tycheck_concat_2() { +fn concat_2() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -85,7 +85,7 @@ fn assert_tycheck_concat_2() { } #[test] -fn assert_tycheck_return_1() { +fn return_1() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -110,7 +110,7 @@ fn assert_tycheck_return_1() { } #[test] -fn assert_tycheck_return_incompatible_1() { +fn return_incompatible_1() { let tree = LocalAssert { tree: Tree::Concat( Box::new(Tree::Return(Box::new(Expression::True))), @@ -121,7 +121,7 @@ fn assert_tycheck_return_incompatible_1() { } #[test] -fn assert_tycheck_return_incompatible_2() { +fn return_incompatible_2() { let tree = LocalAssert { tree: Tree::Concat( Box::new(Tree::Return(Box::new(Expression::True))), @@ -141,7 +141,7 @@ fn assert_tycheck_return_incompatible_2() { } #[test] -fn assert_tycheck_return_2() { +fn return_2() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -176,7 +176,7 @@ fn assert_tycheck_return_2() { #[test] -fn assert_tycheck_return_3() { +fn return_3() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -210,7 +210,7 @@ fn assert_tycheck_return_3() { } #[test] -fn assert_tycheck_if_1() { +fn if_1() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -246,7 +246,7 @@ fn assert_tycheck_if_1() { } #[test] -fn assert_tycheck_if_2() { +fn if_2() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -281,7 +281,7 @@ fn assert_tycheck_if_2() { } #[test] -fn assert_tycheck_if_3() { +fn if_3() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -317,7 +317,7 @@ fn assert_tycheck_if_3() { } #[test] -fn assert_tycheck_if_4() { +fn if_4() { let tree = LocalAssert { tree: Tree::Concat( Box::new( @@ -339,7 +339,7 @@ fn assert_tycheck_if_4() { } #[test] -fn assert_tycheck_if_else_1() { +fn if_else_1() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -378,7 +378,7 @@ fn assert_tycheck_if_else_1() { } #[test] -fn assert_tycheck_if_else_2() { +fn if_else_2() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -417,7 +417,7 @@ fn assert_tycheck_if_else_2() { } #[test] -fn assert_tycheck_if_else_3() { +fn if_else_3() { let tree = LocalAssert { tree: Tree::Concat( Box::new( @@ -442,7 +442,7 @@ fn assert_tycheck_if_else_3() { } #[test] -fn assert_tycheck_if_else_4() { +fn if_else_4() { let tree = LocalAssert { tree: Tree::Concat( Box::new( @@ -467,7 +467,7 @@ fn assert_tycheck_if_else_4() { } #[test] -fn assert_tycheck_assignment_1() { +fn assignment_1() { let tree = LocalAssert { tree: Tree::Assignment( Variable::Id("a".into()), @@ -479,7 +479,7 @@ fn assert_tycheck_assignment_1() { } #[test] -fn assert_tycheck_assignment_2() { +fn assignment_2() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -516,7 +516,7 @@ fn assert_tycheck_assignment_2() { } #[test] -fn assert_tycheck_assignment_3() { +fn assignment_3() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -555,7 +555,7 @@ fn assert_tycheck_assignment_3() { } #[test] -fn assert_tycheck_assignment_4() { +fn assignment_4() { let tree = LocalAssert { tree: Tree::Concat( Box::new( @@ -580,7 +580,7 @@ fn assert_tycheck_assignment_4() { } #[test] -fn assert_tycheck_assignment_5() { +fn assignment_5() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -620,7 +620,7 @@ fn assert_tycheck_assignment_5() { } #[test] -fn assert_tycheck_assignment_6() { +fn assignment_6() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -667,7 +667,7 @@ fn assert_tycheck_assignment_6() { } #[test] -fn assert_tycheck_assignment_7() { +fn assignment_7() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -712,7 +712,7 @@ fn assert_tycheck_assignment_7() { } #[test] -fn assert_tycheck_assignment_8() { +fn assignment_8() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -761,7 +761,7 @@ fn assert_tycheck_assignment_8() { } #[test] -fn assert_tycheck_assignment_9() { +fn assignment_9() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -808,7 +808,7 @@ fn assert_tycheck_assignment_9() { } #[test] -fn assert_tycheck_assignment_10() { +fn assignment_10() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -858,7 +858,7 @@ fn assert_tycheck_assignment_10() { #[test] -fn assert_tycheck_for_1() { +fn for_1() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset}; @@ -906,7 +906,7 @@ fn assert_tycheck_for_1() { #[test] -fn assert_tycheck_for_2() { +fn for_2() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset}; @@ -958,7 +958,7 @@ fn assert_tycheck_for_2() { } #[test] -fn assert_tycheck_for_3() { +fn for_3() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset}; @@ -1024,7 +1024,7 @@ fn assert_tycheck_for_3() { } #[test] -fn assert_tycheck_for_4() { +fn for_4() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset}; @@ -1091,7 +1091,7 @@ fn assert_tycheck_for_4() { } #[test] -fn assert_tycheck_for_5() { +fn for_5() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset}; @@ -1171,7 +1171,7 @@ fn assert_tycheck_for_5() { } #[test] -fn assert_tycheck_for_6() { +fn for_6() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset}; @@ -1262,7 +1262,7 @@ fn assert_tycheck_for_6() { } #[test] -fn assert_tycheck_for_7() { +fn for_7() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -1314,7 +1314,7 @@ fn assert_tycheck_for_7() { } #[test] -fn assert_tycheck_for_8() { +fn for_8() { use translator::Translator; use structure::{RSsystem, RSlabel}; @@ -1394,7 +1394,7 @@ fn assert_tycheck_for_8() { } #[test] -fn assert_tycheck_system() { +fn nodes() { use translator::Translator; use structure::{RSsystem, RSlabel, RSset, RSenvironment, RSprocess}; use std::rc::Rc; diff --git a/src/rsprocess/transitions.rs b/src/rsprocess/transitions.rs index 2c1c09e..b6d49c0 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,216 +14,331 @@ 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, + system: &RSsystem, + n: usize, ) -> Result, String> { - let mut tr = TransitionsIterator::from(system)?; - Ok(tr.nth(n)) + let mut tr = TransitionsIterator::from(system)?; + Ok(tr.nth(n)) } type Trace = Vec<(Option>, Rc)>; pub fn traces( - system: RSsystem, - n: usize, + system: RSsystem, + n: usize, ) -> Result, String> { - if n == 0 { - return Ok(vec![]) + 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; } + } - 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) + Ok(res) +} + +#[test] +fn traces_1() { + use super::structure::RSreaction; + + let system = RSsystem { + delta: Rc::new(RSenvironment::from([ + (100, RSprocess::WaitEntity { + repeat: 2, + repeated_process: Rc::new(RSprocess::EntitySet { + entities: RSset::from([1]), + next_process: Rc::new(RSprocess::Nill) + }), + next_process: Rc::new(RSprocess::Nill) }), + (102, RSprocess::WaitEntity { + repeat: 3, + repeated_process: Rc::new(RSprocess::EntitySet { + entities: RSset::from([2]), + next_process: Rc::new(RSprocess::Nill) }), + next_process: Rc::new(RSprocess::Nill) }), + (103, RSprocess::WaitEntity { + repeat: 4, + repeated_process: Rc::new(RSprocess::EntitySet { + entities: RSset::from([3]), + next_process: Rc::new(RSprocess::Nill) }), + next_process: Rc::new(RSprocess::Nill) }), + (101, RSprocess::Summation { children: vec![ + Rc::new(RSprocess::EntitySet { + entities: RSset::from([10]), + next_process: Rc::new(RSprocess::RecursiveIdentifier { + identifier: 100 }) }), + Rc::new(RSprocess::EntitySet { + entities: RSset::from([11]), + next_process: Rc::new(RSprocess::RecursiveIdentifier { + identifier: 102 }) }), + Rc::new(RSprocess::EntitySet { + entities: RSset::from([11]), + next_process: Rc::new(RSprocess::RecursiveIdentifier { + identifier: 103 }) }) + ] }), + ])), + available_entities: RSset::from([1, 2]), + context_process: RSprocess::RecursiveIdentifier { identifier: 101 }, + reaction_rules: + Rc::new(vec![RSreaction { reactants: RSset::from([1]), + inhibitors: RSset::from([3]), + products: RSset::from([3]), }, + RSreaction { reactants: RSset::from([3]), + inhibitors: RSset::from([1]), + products: RSset::from([1]), }, + RSreaction { reactants: RSset::from([2]), + inhibitors: RSset::new(), + products: RSset::from([4]), }, + ]) + }; + + // 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 = traces(system.clone(), 1).unwrap(); + assert_eq!(res.len(), 1); + + let res = traces(system.clone(), 2).unwrap(); + assert_eq!(res.len(), 2); + assert_eq!(res[0].len() + 1, res[1].len()); + + let res = traces(system.clone(), 3).unwrap(); + assert_eq!(res.len(), 3); + + let res = traces(system.clone(), 4).unwrap(); + assert_eq!(res.len(), 3); + + let res = traces(system.clone(), 0).unwrap(); + assert_eq!(res.len(), 0); +} + +#[test] +fn traces_empty_env() { + use super::structure::RSreaction; + + let system = RSsystem { + delta: Rc::new(RSenvironment::from([])), + available_entities: RSset::from([1, 2]), + context_process: RSprocess::WaitEntity { + repeat: 10, + repeated_process: Rc::new(RSprocess::EntitySet { + entities: RSset::from([1, 2]), + next_process: Rc::new(RSprocess::Nill) }), + next_process: Rc::new(RSprocess::Nill) }, + reaction_rules: + Rc::new(vec![RSreaction { reactants: RSset::from([1]), + inhibitors: RSset::from([3]), + products: RSset::from([3]), }, + RSreaction { reactants: RSset::from([3]), + inhibitors: RSset::from([1]), + products: RSset::from([1]), }, + RSreaction { reactants: RSset::from([2]), + inhibitors: RSset::new(), + products: RSset::from([4]), }, + ]) + }; + + let res = traces(system.clone(), 10).unwrap(); + assert_eq!(res.len(), 1); + assert_eq!(res[0].len(), 10); }