Slicing for traces, both normal and positive

This commit is contained in:
elvis
2025-09-24 18:25:56 +02:00
parent eee0439f6e
commit fac85a10d5
10 changed files with 1028 additions and 61 deletions

View File

@ -14,5 +14,10 @@ fn main() {
| Err(e) => println!("{e}"), | Err(e) => println!("{e}"),
} }
println!("{} milliseconds elapsed", now.elapsed().as_millis()); let now = now.elapsed();
println!(
"{}.{:0>3} milliseconds elapsed",
now.as_millis(),
now.as_micros() - now.as_millis() * 1000
);
} }

View File

@ -630,8 +630,7 @@ where
/// Computes the LTS. /// Computes the LTS.
/// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs) /// equivalent to main_do(digraph, Arcs) or to main_do(advdigraph, Arcs)
pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> { pub fn digraph(system: &mut EvaluatedSystem) -> Result<(), String> {
if let (Some(sys), true) = (&system.sys, system.graph.is_none()) if let (Some(sys), true) = (&system.sys, system.graph.is_none()) {
{
let graph = sys.digraph()?; let graph = sys.digraph()?;
system.graph = Some(graph); system.graph = Some(graph);
} else if let (Some(positive), true) = } else if let (Some(positive), true) =

View File

@ -11,6 +11,7 @@ pub mod process;
pub mod reaction; pub mod reaction;
pub mod set; pub mod set;
pub mod system; pub mod system;
pub mod trace;
pub mod dot; pub mod dot;
pub mod frequency; pub mod frequency;
@ -23,3 +24,6 @@ mod system_test;
#[cfg(test)] #[cfg(test)]
mod set_test; mod set_test;
#[cfg(test)]
mod trace_test;

View File

@ -19,6 +19,9 @@ where
type Set: BasicSet; type Set: BasicSet;
fn enabled(&self, state: &Self::Set) -> bool; fn enabled(&self, state: &Self::Set) -> bool;
fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set>; fn compute_step(&self, state: &Self::Set) -> Option<&Self::Set>;
fn reactants(&self) -> &Self::Set;
fn products(&self) -> &Self::Set;
} }
pub trait ExtensionReaction: Sized { pub trait ExtensionReaction: Sized {
@ -167,6 +170,14 @@ impl BasicReaction for Reaction {
None None
} }
} }
fn reactants(&self) -> &Self::Set {
&self.reactants
}
fn products(&self) -> &Self::Set {
&self.products
}
} }
impl PrintableWithTranslator for Reaction { impl PrintableWithTranslator for Reaction {
@ -237,6 +248,14 @@ impl BasicReaction for PositiveReaction {
None None
} }
} }
fn reactants(&self) -> &Self::Set {
&self.reactants
}
fn products(&self) -> &Self::Set {
&self.products
}
} }
impl PrintableWithTranslator for PositiveReaction { impl PrintableWithTranslator for PositiveReaction {

View File

@ -636,6 +636,13 @@ impl PositiveSet {
ret ret
} }
/// Returns all elements that are present in self and are positive in other.
pub fn mask(&self, other: &Self) -> Self {
Self::from_iter(self.iter().filter(|el| {
other.contains(&PositiveType::from((*el.0, IdState::Positive)))
}).map(|el| (*el.0, *el.1)))
}
fn remove_elements(&mut self, other: Vec<IdType>) { fn remove_elements(&mut self, other: Vec<IdType>) {
for element in other { for element in other {
self.identifiers.remove(&element); self.identifiers.remove(&element);

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::collections::{HashMap, VecDeque};
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::rc::Rc; use std::rc::Rc;
@ -18,6 +18,7 @@ use super::reaction::{
BasicReaction, ExtensionReaction, PositiveReaction, Reaction, BasicReaction, ExtensionReaction, PositiveReaction, Reaction,
}; };
use super::set::{BasicSet, PositiveSet, Set}; use super::set::{BasicSet, PositiveSet, Set};
use super::trace::Trace;
use super::transitions::TransitionsIterator; use super::transitions::TransitionsIterator;
use super::translator::{Formatter, PrintableWithTranslator, Translator}; use super::translator::{Formatter, PrintableWithTranslator, Translator};
@ -51,9 +52,10 @@ where
fn available_entities(&self) -> &Self::Set; fn available_entities(&self) -> &Self::Set;
fn context(&self) -> &Self::Process; fn context(&self) -> &Self::Process;
fn reactions(&self) -> &Vec<Self::Reaction>; fn reactions(&self) -> &Vec<Self::Reaction>;
}
type Trace<L, S> = Vec<(Option<Rc<L>>, Rc<S>)>; fn context_elements(&self) -> &Self::Set;
fn products_elements(&self) -> &Self::Set;
}
pub trait ExtensionsSystem: BasicSystem { pub trait ExtensionsSystem: BasicSystem {
fn unfold(&self) -> Result<Self::Choices, String>; fn unfold(&self) -> Result<Self::Choices, String>;
@ -134,9 +136,10 @@ impl<T: BasicSystem> ExtensionsSystem for T {
let mut association = HashMap::new(); let mut association = HashMap::new();
association.insert(self.clone(), node); association.insert(self.clone(), node);
let mut stack = vec![self.clone()]; let mut stack = VecDeque::new();
stack.push_back(self.clone());
while let Some(current) = stack.pop() { while let Some(current) = stack.pop_front() {
// depth first // depth first
let current_node = *association.get(&current).unwrap(); let current_node = *association.get(&current).unwrap();
@ -144,7 +147,7 @@ impl<T: BasicSystem> ExtensionsSystem for T {
// if not already visited // if not already visited
let next_node = let next_node =
association.entry(next.clone()).or_insert_with(|| { association.entry(next.clone()).or_insert_with(|| {
stack.push(next.clone()); stack.push_back(next.clone());
graph.add_node(next) graph.add_node(next)
}); });
graph.add_edge(current_node, *next_node, label); graph.add_edge(current_node, *next_node, label);
@ -244,8 +247,8 @@ impl<T: BasicSystem> ExtensionsSystem for T {
} }
let mut n = n; let mut n = n;
let mut res: Vec<Trace<Self::Label, Self>> = vec![]; let mut res: Vec<Trace<Self::Label, Self>> = vec![];
let mut current_trace: Trace<Self::Label, Self> = let mut current_trace: Trace<Self::Label, Self> = Trace::default();
vec![(None, Rc::new(self))]; current_trace.push((None, Rc::new(self)));
let mut branch = vec![0]; let mut branch = vec![0];
let mut depth = 0; let mut depth = 0;
let mut new_branch = true; let mut new_branch = true;
@ -272,18 +275,16 @@ impl<T: BasicSystem> ExtensionsSystem for T {
// at the bottom of a trace, we save to res, then backtrack // at the bottom of a trace, we save to res, then backtrack
// until we find another possible path. // until we find another possible path.
if new_branch { if new_branch {
res.push(current_trace[0..depth].to_vec()); res.push(Trace::from(current_trace[0..depth].to_vec()));
new_branch = false; new_branch = false;
n -= 1; n -= 1;
} }
if n == 0 { if n == 0 {
break; break;
} }
if depth == 0 { if depth == 0 {
break; break;
} }
depth -= 1; depth -= 1;
branch[depth] += 1; branch[depth] += 1;
} }
@ -412,6 +413,9 @@ pub struct System {
pub available_entities: Set, pub available_entities: Set,
pub context_process: Process, pub context_process: Process,
pub reaction_rules: Rc<Vec<Reaction>>, pub reaction_rules: Rc<Vec<Reaction>>,
context_elements: Rc<Set>,
products_elements: Rc<Set>,
} }
impl BasicSystem for System { impl BasicSystem for System {
@ -425,7 +429,7 @@ impl BasicSystem for System {
fn to_transitions_iterator( fn to_transitions_iterator(
&self, &self,
) -> Result<impl Iterator<Item = (Self::Label, Self)>, String> { ) -> Result<impl Iterator<Item = (Self::Label, Self)>, String> {
TransitionsIterator::<Self::Set, Self, Self::Process>::from(self) TransitionsIterator::<Self::Set, Self, Self::Process>::try_from(self)
} }
fn environment(&self) -> &Self::Environment { fn environment(&self) -> &Self::Environment {
@ -443,6 +447,14 @@ impl BasicSystem for System {
fn reactions(&self) -> &Vec<Self::Reaction> { fn reactions(&self) -> &Vec<Self::Reaction> {
&self.reaction_rules &self.reaction_rules
} }
fn context_elements(&self) -> &Self::Set {
&self.context_elements
}
fn products_elements(&self) -> &Self::Set {
&self.products_elements
}
} }
/// Equality does not care about delta or reaction rules. Only entities and /// Equality does not care about delta or reaction rules. Only entities and
@ -476,6 +488,9 @@ impl Default for System {
available_entities: Set::default(), available_entities: Set::default(),
context_process: Process::Nill, context_process: Process::Nill,
reaction_rules: Rc::new(Vec::default()), reaction_rules: Rc::new(Vec::default()),
context_elements: Rc::new(Set::default()),
products_elements: Rc::new(Set::default()),
} }
} }
} }
@ -489,7 +504,7 @@ impl PrintableWithTranslator for System {
write!( write!(
f, f,
"[delta: {}, available_entities: {}, context_process: {}, \ "[delta: {}, available_entities: {}, context_process: {}, \
reaction_rules: [", reaction_rules: [",
Formatter::from(translator, &*self.delta), Formatter::from(translator, &*self.delta),
Formatter::from(translator, &self.available_entities), Formatter::from(translator, &self.available_entities),
Formatter::from(translator, &self.context_process) Formatter::from(translator, &self.context_process)
@ -513,11 +528,22 @@ impl System {
context_process: Process, context_process: Process,
reaction_rules: Rc<Vec<Reaction>>, reaction_rules: Rc<Vec<Reaction>>,
) -> System { ) -> System {
let products_elements = reaction_rules
.iter()
.fold(Set::default(), |acc: Set, r| acc.union(&r.products));
let all_elements_context = delta
.all_elements()
.union(&context_process.all_elements())
.subtraction(&products_elements);
System { System {
delta: Rc::clone(&delta), delta: Rc::clone(&delta),
available_entities, available_entities,
context_process, context_process,
reaction_rules: Rc::clone(&reaction_rules), reaction_rules: Rc::clone(&reaction_rules),
context_elements: Rc::new(all_elements_context),
products_elements: Rc::new(products_elements),
} }
} }
} }
@ -621,7 +647,7 @@ impl System {
let entities_not_needed = entities_context.subtraction(&total); let entities_not_needed = entities_context.subtraction(&total);
result.push_str(&format!( result.push_str(&format!(
"The context can provide {} entities that will never be used:\ "The context can provide {} entities that will never be used:\
\n{}\n", \n{}\n",
entities_not_needed.len(), entities_not_needed.len(),
Formatter::from(translator, &entities_not_needed) Formatter::from(translator, &entities_not_needed)
)); ));
@ -669,6 +695,9 @@ pub struct PositiveSystem {
pub available_entities: PositiveSet, pub available_entities: PositiveSet,
pub context_process: PositiveProcess, pub context_process: PositiveProcess,
pub reaction_rules: Rc<Vec<PositiveReaction>>, pub reaction_rules: Rc<Vec<PositiveReaction>>,
context_elements: Rc<PositiveSet>,
products_elements: Rc<PositiveSet>,
} }
impl BasicSystem for PositiveSystem { impl BasicSystem for PositiveSystem {
@ -682,7 +711,7 @@ impl BasicSystem for PositiveSystem {
fn to_transitions_iterator( fn to_transitions_iterator(
&self, &self,
) -> Result<impl Iterator<Item = (Self::Label, Self)>, String> { ) -> Result<impl Iterator<Item = (Self::Label, Self)>, String> {
TransitionsIterator::<Self::Set, Self, Self::Process>::from(self) TransitionsIterator::<Self::Set, Self, Self::Process>::try_from(self)
} }
fn environment(&self) -> &Self::Environment { fn environment(&self) -> &Self::Environment {
@ -700,6 +729,14 @@ impl BasicSystem for PositiveSystem {
fn reactions(&self) -> &Vec<Self::Reaction> { fn reactions(&self) -> &Vec<Self::Reaction> {
&self.reaction_rules &self.reaction_rules
} }
fn context_elements(&self) -> &Self::Set {
&self.context_elements
}
fn products_elements(&self) -> &Self::Set {
&self.products_elements
}
} }
/// Equality does not care about delta or reaction rules. Only entities and /// Equality does not care about delta or reaction rules. Only entities and
@ -733,6 +770,9 @@ impl Default for PositiveSystem {
available_entities: PositiveSet::default(), available_entities: PositiveSet::default(),
context_process: PositiveProcess::default(), context_process: PositiveProcess::default(),
reaction_rules: Rc::new(Vec::default()), reaction_rules: Rc::new(Vec::default()),
context_elements: Rc::new(PositiveSet::default()),
products_elements: Rc::new(PositiveSet::default()),
} }
} }
} }
@ -746,7 +786,7 @@ impl PrintableWithTranslator for PositiveSystem {
write!( write!(
f, f,
"[delta: {}, available_entities: {}, context_process: {}, \ "[delta: {}, available_entities: {}, context_process: {}, \
reaction_rules: [", reaction_rules: [",
Formatter::from(translator, &*self.delta), Formatter::from(translator, &*self.delta),
Formatter::from(translator, &self.available_entities), Formatter::from(translator, &self.available_entities),
Formatter::from(translator, &self.context_process) Formatter::from(translator, &self.context_process)
@ -840,12 +880,7 @@ impl From<System> for PositiveSystem {
Rc::new(res) Rc::new(res)
}; };
Self { Self::from(new_env, new_available_entities, new_context, new_reactions)
delta: new_env,
available_entities: new_available_entities,
context_process: new_context,
reaction_rules: new_reactions,
}
} }
} }
@ -856,11 +891,24 @@ impl PositiveSystem {
context_process: PositiveProcess, context_process: PositiveProcess,
reaction_rules: Rc<Vec<PositiveReaction>>, reaction_rules: Rc<Vec<PositiveReaction>>,
) -> Self { ) -> Self {
let products_elements = reaction_rules
.iter()
.fold(PositiveSet::default(), |acc: PositiveSet, r| {
acc.union(&r.products)
});
let all_elements_context = delta
.all_elements()
.union(&context_process.all_elements())
.subtraction(&products_elements);
Self { Self {
delta: Rc::clone(&delta), delta: Rc::clone(&delta),
available_entities, available_entities,
context_process, context_process,
reaction_rules: Rc::clone(&reaction_rules), reaction_rules: Rc::clone(&reaction_rules),
context_elements: Rc::new(all_elements_context),
products_elements: Rc::new(products_elements),
} }
} }
} }

View File

@ -156,8 +156,8 @@ fn traces_1() {
use super::set::Set; use super::set::Set;
use super::system::{ExtensionsSystem, System}; use super::system::{ExtensionsSystem, System};
let system = System { let system = System::from(
delta: Rc::new(Environment::from([ Rc::new(Environment::from([
(100, Process::WaitEntity { (100, Process::WaitEntity {
repeat: 2, repeat: 2,
repeated_process: Rc::new(Process::EntitySet { repeated_process: Rc::new(Process::EntitySet {
@ -205,14 +205,14 @@ fn traces_1() {
], ],
}), }),
])), ])),
available_entities: Set::from([1, 2]), Set::from([1, 2]),
context_process: Process::RecursiveIdentifier { identifier: 101 }, Process::RecursiveIdentifier { identifier: 101 },
reaction_rules: Rc::new(vec![ Rc::new(vec![
Reaction::from(Set::from([1]), Set::from([3]), Set::from([3])), Reaction::from(Set::from([1]), Set::from([3]), Set::from([3])),
Reaction::from(Set::from([3]), Set::from([1]), Set::from([1])), Reaction::from(Set::from([3]), Set::from([1]), Set::from([1])),
Reaction::from(Set::from([2]), Set::default(), Set::from([4])), Reaction::from(Set::from([2]), Set::default(), Set::from([4])),
]), ]),
}; );
let res = system.clone().traces(1).unwrap(); let res = system.clone().traces(1).unwrap();
assert_eq!(res.len(), 1); assert_eq!(res.len(), 1);
@ -244,10 +244,10 @@ fn traces_empty_env() {
use super::set::Set; use super::set::Set;
use super::system::{ExtensionsSystem, System}; use super::system::{ExtensionsSystem, System};
let system = System { let system = System::from(
delta: Rc::new(Environment::from([])), Rc::new(Environment::from([])),
available_entities: Set::from([1, 2]), Set::from([1, 2]),
context_process: Process::WaitEntity { Process::WaitEntity {
repeat: 10, repeat: 10,
repeated_process: Rc::new(Process::EntitySet { repeated_process: Rc::new(Process::EntitySet {
entities: Set::from([1, 2]), entities: Set::from([1, 2]),
@ -255,12 +255,12 @@ fn traces_empty_env() {
}), }),
next_process: Rc::new(Process::Nill), next_process: Rc::new(Process::Nill),
}, },
reaction_rules: Rc::new(vec![ Rc::new(vec![
Reaction::from(Set::from([1]), Set::from([3]), Set::from([3])), Reaction::from(Set::from([1]), Set::from([3]), Set::from([3])),
Reaction::from(Set::from([3]), Set::from([1]), Set::from([1])), Reaction::from(Set::from([3]), Set::from([1]), Set::from([1])),
Reaction::from(Set::from([2]), Set::default(), Set::from([4])), Reaction::from(Set::from([2]), Set::default(), Set::from([4])),
]), ]),
}; );
let res = system.clone().traces(10).unwrap(); let res = system.clone().traces(10).unwrap();
assert_eq!(res.len(), 1); assert_eq!(res.len(), 1);
@ -278,15 +278,15 @@ fn conversion_reactions() {
use super::set::Set; use super::set::Set;
use super::system::{PositiveSystem, System}; use super::system::{PositiveSystem, System};
let system = System { let system = System::from(
delta: Rc::new(Environment::from([])), Rc::new(Environment::from([])),
available_entities: Set::from([1, 2]), Set::from([1, 2]),
context_process: Process::Nill, Process::Nill,
reaction_rules: Rc::new(vec![ Rc::new(vec![
Reaction::from(Set::from([2]), Set::from([1, 3]), Set::from([5])), Reaction::from(Set::from([2]), Set::from([1, 3]), Set::from([5])),
Reaction::from(Set::from([1, 2]), Set::from([3]), Set::from([5])), Reaction::from(Set::from([1, 2]), Set::from([3]), Set::from([5])),
]), ]),
}; );
let converted_system: PositiveSystem = system.into(); let converted_system: PositiveSystem = system.into();
let mut reactions = converted_system.reactions().clone(); let mut reactions = converted_system.reactions().clone();
reactions.sort_by(|a, b| { reactions.sort_by(|a, b| {
@ -322,15 +322,15 @@ fn conversion_entities() {
use super::set::Set; use super::set::Set;
use super::system::{PositiveSystem, System}; use super::system::{PositiveSystem, System};
let system = System { let system = System::from(
delta: Rc::new(Environment::from([])), Rc::new(Environment::from([])),
available_entities: Set::from([1, 2]), Set::from([1, 2]),
context_process: Process::Nill, Process::Nill,
reaction_rules: Rc::new(vec![ Rc::new(vec![
Reaction::from(Set::from([2]), Set::from([1, 3]), Set::from([5])), Reaction::from(Set::from([2]), Set::from([1, 3]), Set::from([5])),
Reaction::from(Set::from([1, 2]), Set::from([3]), Set::from([5])), Reaction::from(Set::from([1, 2]), Set::from([3]), Set::from([5])),
]), ]),
}; );
let converted_system: PositiveSystem = system.into(); let converted_system: PositiveSystem = system.into();
let entities = converted_system.available_entities().clone(); let entities = converted_system.available_entities().clone();

415
rsprocess/src/trace.rs Normal file
View File

@ -0,0 +1,415 @@
use std::fmt::Debug;
use std::ops::{Index, IndexMut};
use std::rc::Rc;
use std::slice::SliceIndex;
use crate::reaction::{BasicReaction, PositiveReaction, Reaction};
use crate::set::{BasicSet, PositiveSet, Set};
use crate::system::{BasicSystem, PositiveSystem, System};
use crate::translator::{Formatter, PrintableWithTranslator};
type TraceElement<L, Sys> = (Option<Rc<L>>, Rc<Sys>);
#[derive(Clone, Default)]
pub struct Trace<L, Sys> {
pub values: Vec<TraceElement<L, Sys>>,
}
impl<L, Sys> Trace<L, Sys> {
pub fn push(&mut self, val: TraceElement<L, Sys>) {
self.values.push(val)
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
impl<L, Sys> From<&[TraceElement<L, Sys>]> for Trace<L, Sys> {
fn from(value: &[TraceElement<L, Sys>]) -> Self {
Self {
values: value.to_vec(),
}
}
}
impl<L, Sys, const N: usize> From<&[TraceElement<L, Sys>; N]>
for Trace<L, Sys>
{
fn from(value: &[TraceElement<L, Sys>; N]) -> Self {
Self {
values: value.to_vec(),
}
}
}
impl<'a, L, Sys> From<&'a Vec<TraceElement<L, Sys>>> for Trace<L, Sys> {
fn from(value: &'a Vec<TraceElement<L, Sys>>) -> Self {
Self {
values: value.to_vec(),
}
}
}
impl<L, Sys> From<Vec<TraceElement<L, Sys>>> for Trace<L, Sys> {
fn from(value: Vec<TraceElement<L, Sys>>) -> Self {
Self { values: value }
}
}
impl<L, Sys, I: SliceIndex<[TraceElement<L, Sys>]>> Index<I> for Trace<L, Sys> {
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
&self.values[index]
}
}
impl<L, Sys, I: SliceIndex<[TraceElement<L, Sys>]>> IndexMut<I>
for Trace<L, Sys>
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.values[index]
}
}
// -----------------------------------------------------------------------------
// Slicing Trace
// -----------------------------------------------------------------------------
#[derive(Clone, Default)]
pub struct SlicingElement<S> {
pub context: S,
pub reaction_products: S,
}
impl<S> Debug for SlicingElement<S>
where
S: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{{context: {:?} - reaction_products: {:?}}}",
self.context, self.reaction_products
)
}
}
impl<S> PrintableWithTranslator for SlicingElement<S>
where
S: PrintableWithTranslator,
{
fn print(
&self,
f: &mut std::fmt::Formatter,
translator: &crate::translator::Translator,
) -> std::fmt::Result {
write!(
f,
"{{context: {}, ",
Formatter::from(translator, &self.context)
)?;
write!(
f,
"reaction products: {}}}",
Formatter::from(translator, &self.reaction_products)
)
}
}
#[derive(Clone, Default, Debug)]
pub struct EnabledReactions {
pub data: Vec<usize>,
}
impl PrintableWithTranslator for EnabledReactions {
fn print(
&self,
f: &mut std::fmt::Formatter,
_translator: &crate::translator::Translator,
) -> std::fmt::Result {
let mut elements = self.data.iter().peekable();
while let Some(e) = elements.next() {
if elements.peek().is_some() {
write!(f, "{e}, ")?;
} else {
write!(f, "{e}")?;
}
}
Ok(())
}
}
impl<'a> IntoIterator for &'a EnabledReactions {
type Item = &'a usize;
type IntoIter = std::slice::Iter<'a, usize>;
fn into_iter(self) -> Self::IntoIter {
self.data.iter()
}
}
impl EnabledReactions {
pub fn iter(&self) -> std::slice::Iter<'_, usize> {
self.into_iter()
}
}
#[derive(Clone)]
pub struct SlicingTrace<S: BasicSet,
R: BasicReaction<Set = S>,
Sys: BasicSystem<Set = S, Reaction = R>>
{
pub elements: Vec<SlicingElement<S>>,
pub enabled_reactions: Vec<EnabledReactions>,
pub reactions: Rc<Vec<R>>,
pub systems: Vec<Rc<Sys>>,
pub context_elements: Rc<S>,
pub products_elements: Rc<S>,
}
impl<S: BasicSet,
R: BasicReaction<Set = S>,
Sys: BasicSystem<Set = S, Reaction = R>>
Default for SlicingTrace<S, R, Sys>
{
fn default() -> Self {
Self {
elements: Vec::default(),
enabled_reactions: Vec::default(),
reactions: Rc::new(Vec::default()),
systems: Vec::default(),
context_elements: Rc::new(S::default()),
products_elements: Rc::new(S::default()),
}
}
}
impl<S: BasicSet + Debug,
R: BasicReaction<Set = S>,
Sys: BasicSystem<Set = S, Reaction = R>>
SlicingTrace<S, R, Sys>
{
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
pub fn len(&self) -> usize {
self.elements.len()
}
}
impl SlicingTrace<Set, Reaction, System> {
pub fn slice(&self, marking: Set) -> Result<Self, String> {
let mut reversed_elements = Vec::with_capacity(self.elements.len());
reversed_elements.push(SlicingElement {
context: self
.elements
.last()
.ok_or("Trace with length zero.")?
.context
.clone(),
reaction_products: marking,
});
let mut reversed_enabled_reactions: Vec<EnabledReactions> =
Vec::with_capacity(self.enabled_reactions.len());
for i in (1..(self.len())).rev() {
let reverse_i: usize = self.len() - i;
let i = i - 1;
if reversed_elements.len() <= reverse_i {
reversed_elements.push(SlicingElement::default());
}
if reversed_enabled_reactions.len() <= reverse_i {
reversed_enabled_reactions.push(EnabledReactions::default());
}
for r in self.enabled_reactions[i].iter() {
if !reversed_elements[reverse_i - 1]
.reaction_products
.is_disjoint(self.reactions[*r].products())
{
reversed_enabled_reactions[reverse_i - 1].data.push(*r);
reversed_elements[reverse_i].context.push(
&self.reactions[*r]
.reactants()
.intersection(&self.context_elements),
);
reversed_elements[reverse_i].reaction_products.push(
&self.reactions[*r]
.reactants()
.intersection(&self.products_elements),
)
}
}
}
reversed_elements.reverse();
reversed_enabled_reactions.reverse();
let new_trace = Self {
elements: reversed_elements,
enabled_reactions: reversed_enabled_reactions,
reactions: Rc::clone(&self.reactions),
systems: self.systems.to_vec(),
context_elements: Rc::clone(&self.context_elements),
products_elements: Rc::clone(&self.products_elements),
};
Ok(new_trace)
}
}
impl SlicingTrace<PositiveSet, PositiveReaction, PositiveSystem> {
pub fn slice(&self, marking: PositiveSet) -> Result<Self, String> {
let mut reversed_elements = Vec::with_capacity(self.elements.len());
reversed_elements.push(SlicingElement {
context: self
.elements
.last()
.ok_or("Trace with length zero.")?
.context
.clone(),
reaction_products: marking,
});
let mut reversed_enabled_reactions: Vec<EnabledReactions> =
Vec::with_capacity(self.enabled_reactions.len());
for i in (1..(self.len())).rev() {
let reverse_i: usize = self.len() - i;
let i = i - 1;
if reversed_elements.len() <= reverse_i {
reversed_elements.push(SlicingElement::default());
}
if reversed_enabled_reactions.len() <= reverse_i {
reversed_enabled_reactions.push(EnabledReactions::default());
}
for r in self.enabled_reactions[i].iter() {
if !reversed_elements[reverse_i - 1]
.reaction_products
.intersection(self.reactions[*r].products()).is_empty()
{
reversed_enabled_reactions[reverse_i - 1].data.push(*r);
reversed_elements[reverse_i].context.push(
&self.reactions[*r]
.reactants()
.mask(&self.context_elements),
);
reversed_elements[reverse_i].reaction_products.push(
&self.reactions[*r]
.reactants()
.mask(&self.products_elements),
)
}
}
}
reversed_elements.reverse();
reversed_enabled_reactions.reverse();
let new_trace = Self {
elements: reversed_elements,
enabled_reactions: reversed_enabled_reactions,
reactions: Rc::clone(&self.reactions),
systems: self.systems.to_vec(),
context_elements: Rc::clone(&self.context_elements),
products_elements: Rc::clone(&self.products_elements),
};
Ok(new_trace)
}
}
impl<S: BasicSet,
R: BasicReaction<Set = S>,
Sys: BasicSystem<Set = S, Reaction = R>,>
PrintableWithTranslator for SlicingTrace<S, R, Sys>
{
fn print(
&self,
f: &mut std::fmt::Formatter,
translator: &crate::translator::Translator,
) -> std::fmt::Result {
// let mut systems = self.systems.iter().peekable();
// writeln!(f, "Systems:")?;
// while let Some(system) = systems.next() {
// if systems.peek().is_some() {
// write!(f, "{} --> ", Formatter::from(translator,
// &**system))?; } else {
// writeln!(f, "{}", Formatter::from(translator, &**system))?;
// }
// }
let mut reactions = self.reactions.iter().enumerate().peekable();
writeln!(f, "Reactions:")?;
while let Some((pos, reaction)) = reactions.next() {
if reactions.peek().is_some() {
writeln!(
f,
"\t({pos}) {},",
Formatter::from(translator, reaction)
)?;
} else {
writeln!(
f,
"\t({pos}) {}.",
Formatter::from(translator, reaction)
)?;
}
}
writeln!(
f,
"Context Elements: {}",
Formatter::from(translator, &*self.context_elements)
)?;
writeln!(
f,
"Product Elements: {}",
Formatter::from(translator, &*self.products_elements)
)?;
let mut elements = self.elements.iter().peekable();
let mut enabled_reactions = self.enabled_reactions.iter();
writeln!(f, "Trace:")?;
while let Some(el) = elements.next() {
if let Some(r) = enabled_reactions.next() {
if elements.peek().is_some() {
writeln!(
f,
"{}\n\t|\n{: ^17}\n\t|\n\t",
Formatter::from(translator, el),
format!("({})", Formatter::from(translator, r)),
)?;
} else {
writeln!(
f,
"{}\n\t|\n{: ^17}\n\t|\n\t?",
Formatter::from(translator, el),
format!("({})", Formatter::from(translator, r)),
)?;
}
} else if elements.peek().is_some() {
writeln!(
f,
"{}\n\t|\n\t|\n\t|\n\t",
Formatter::from(translator, el)
)?;
} else {
writeln!(f, "{}", Formatter::from(translator, el))?;
}
}
Ok(())
}
}

382
rsprocess/src/trace_test.rs Normal file
View File

@ -0,0 +1,382 @@
use std::rc::Rc;
use crate::element::IdState;
use crate::reaction::{BasicReaction, PositiveReaction, Reaction};
use crate::set::{ExtensionsSet, PositiveSet, Set, BasicSet};
use crate::system::{PositiveSystem, System};
use crate::trace::*;
use crate::translator::Translator;
#[test]
fn slice_atoi() {
let mut translator = Translator::new();
let reactions = vec![
(
vec!["tgfbr", "stat3", "il6r"],
vec!["tbet", "gata3", "foxp3"],
vec!["rorgt"],
),
(
vec!["tgfbr", "stat3", "il21r"],
vec!["tbet", "gata3", "foxp3"],
vec!["rorgt"],
),
(vec!["il23r"], vec![], vec!["stat3"]),
(vec!["il21"], vec![], vec!["il21r"]),
(vec!["il6"], vec![], vec!["il6r"]),
(vec!["tcr"], vec!["foxp3"], vec!["nfat"]),
(vec!["il27", "nfat"], vec![], vec!["stat1"]),
(vec!["stat1"], vec!["rorgt", "foxp3"], vec!["tbet"]),
]
.iter()
.map(|r| {
Reaction::from(
r.0.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
r.1.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
r.2.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
)
})
.collect::<Vec<_>>();
let elements = [
(vec!["il23r", "il21"], vec!["tcr"]),
(vec!["il21r", "stat3", "nfat"], vec!["il27"]),
(vec!["stat1"], vec![]),
(vec!["tbet"], vec![]),
]
.iter()
.map(|elements| SlicingElement {
context: elements
.1
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
reaction_products: elements
.0
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
})
.collect::<Vec<_>>();
let enabled_reactions = vec![vec![3, 4, 6], vec![7], vec![8]]
.into_iter()
.map(|r| EnabledReactions {
data: r.iter().map(|i| i - 1).collect::<Vec<_>>(),
})
.collect::<Vec<_>>();
let context_elements = ["tgfb", "il6", "tcr", "il27"]
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into();
let products_elements =
["rorgt", "stat3", "il21r", "il6r", "nfat", "stat1", "tbet", "il21",
"il23r"]
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into();
let trace: SlicingTrace<Set, Reaction, System> = SlicingTrace {
elements,
enabled_reactions,
reactions: Rc::new(reactions),
systems: vec![],
context_elements: Rc::new(context_elements),
products_elements: Rc::new(products_elements),
};
let marking = ["tbet"]
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into();
let sliced = trace.slice(marking).unwrap();
let mut reaction_products = sliced
.elements
.iter()
.map(|elements| {
elements
.reaction_products
.iter()
.map(|el| translator.decode(*el).unwrap())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
reaction_products.iter_mut().for_each(|x| x.sort());
let mut correct_reaction_products =
vec![vec![], vec!["nfat"], vec!["stat1"], vec!["tbet"]];
correct_reaction_products.iter_mut().for_each(|x| x.sort());
assert_eq!(reaction_products, correct_reaction_products);
let mut context = sliced
.elements
.iter()
.map(|elements| {
elements
.context
.iter()
.map(|el| translator.decode(*el).unwrap())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
context.iter_mut().for_each(|x| x.sort());
let mut correct_context = vec![vec!["tcr"], vec!["il27"], vec![], vec![]];
correct_context.iter_mut().for_each(|x| x.sort());
assert_eq!(context, correct_context);
let mut enabled_reactions = sliced
.enabled_reactions
.iter()
.map(|elements| elements.data.clone())
.collect::<Vec<_>>();
enabled_reactions.iter_mut().for_each(|x| x.sort());
let mut correct_enabled_reactions = vec![vec![5], vec![6], vec![7]];
correct_enabled_reactions.iter_mut().for_each(|x| x.sort());
assert_eq!(enabled_reactions, correct_enabled_reactions);
}
#[test]
fn slice_positive_atoi() {
let mut translator = Translator::new();
let reactions = {
let reactions = vec![
(
vec!["tgfbr", "stat3", "il6r"],
vec!["tbet", "gata3", "foxp3"],
vec!["rorgt"],
),
(
vec!["tgfbr", "stat3", "il21r"],
vec!["tbet", "gata3", "foxp3"],
vec!["rorgt"],
),
(vec!["il23r"], vec![], vec!["stat3"]),
(vec!["il21"], vec![], vec!["il21r"]),
(vec!["il6"], vec![], vec!["il6r"]),
(vec!["tcr"], vec!["foxp3"], vec!["nfat"]),
(vec!["il27", "nfat"], vec![], vec!["stat1"]),
(vec!["stat1"], vec!["rorgt", "foxp3"], vec!["tbet"]),
]
.iter()
.map(|r| {
Reaction::from(
r.0.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
r.1.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
r.2.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
.into(),
)
})
.collect::<Vec<_>>();
let system = System::from(
Rc::new(crate::environment::Environment::from([])),
Set::from([]),
crate::process::Process::Nill,
Rc::new(reactions),
);
let converted_system: PositiveSystem = system.into();
let mut reactions = Rc::try_unwrap(converted_system.reaction_rules).unwrap();
reactions.sort_by(|a, b| a.reactants.cmp(&b.reactants)
.then(a.products.cmp(&b.products)));
println!("Computed Reactions:");
for (pos, r) in reactions.iter().enumerate() {
println!("\t({pos}) {},", crate::translator::Formatter::from(&translator, r));
}
reactions
};
let elements = [
(vec![("il23r", IdState::Positive), ("il21", IdState::Positive),
("rorgt", IdState::Negative), ("stat3", IdState::Negative),
("il21r", IdState::Negative), ("il6r", IdState::Negative),
("nfat", IdState::Negative), ("stat1", IdState::Negative),
("tbet", IdState::Negative), ("tgfbr", IdState::Negative),
("foxp3", IdState::Negative)],
vec![("tcr", IdState::Positive), ("tgfb", IdState::Negative),
("il6", IdState::Negative), ("il27", IdState::Negative)]),
(vec![("il21r", IdState::Positive), ("stat3", IdState::Positive),
("nfat", IdState::Positive), ("rorgt", IdState::Negative),
("il6r", IdState::Negative), ("stat1", IdState::Negative),
("tbet", IdState::Negative), ("il21", IdState::Negative),
("il23r", IdState::Negative), ("tgfbr", IdState::Negative),
("foxp3", IdState::Negative)],
vec![("il27", IdState::Positive), ("tgfb", IdState::Negative),
("il6", IdState::Negative), ("tcr", IdState::Negative)]),
(vec![("stat1", IdState::Positive), ("rorgt", IdState::Negative),
("stat3", IdState::Negative), ("il21r", IdState::Negative),
("il6r", IdState::Negative), ("nfat", IdState::Negative),
("tbet", IdState::Negative), ("il21", IdState::Negative),
("il23r", IdState::Negative), ("tgfbr", IdState::Negative),
("foxp3", IdState::Negative)],
vec![("il27", IdState::Negative), ("tgfb", IdState::Negative),
("il6", IdState::Negative), ("tcr", IdState::Negative)]),
(vec![("tbet", IdState::Positive), ("rorgt", IdState::Negative),
("stat3", IdState::Negative), ("il21r", IdState::Negative),
("il6r", IdState::Negative), ("nfat", IdState::Negative),
("stat1", IdState::Negative), ("il21", IdState::Negative),
("il23r", IdState::Negative), ("tgfbr", IdState::Negative),
("foxp3", IdState::Negative)],
vec![]),
]
.iter()
.map(|elements| SlicingElement {
context: Into::<PositiveSet>::into(
elements
.1
.iter()
.map(|el| (translator.encode(el.0), el.1))
.collect::<Vec<_>>()),
reaction_products: Into::<PositiveSet>::into(
elements
.0
.iter()
.map(|el| (translator.encode(el.0), el.1))
.collect::<Vec<_>>()),
})
.collect::<Vec<_>>();
let enabled_reactions = {
let mut enabled_reactions = vec![];
for slice_el in elements.iter().rev().skip(1).rev() {
let available_enteties = slice_el.context.union(&slice_el.reaction_products);
enabled_reactions.push(vec![]);
for (pos, r) in reactions.iter().enumerate() {
if r.enabled(&available_enteties) {
enabled_reactions.last_mut().unwrap().push(pos);
}
}
}
enabled_reactions.into_iter()
.map(|r| EnabledReactions {
data: r,
})
.collect::<Vec<_>>()
};
let context_elements =
Into::<Set>::into(
["tgfb", "il6", "tcr", "il27"]
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
).to_positive_set(IdState::Positive);
let products_elements =
Into::<Set>::into(
["rorgt", "stat3", "il21r", "il6r", "nfat", "stat1", "tbet", "il21",
"il23r", "tgfbr", "foxp3"]
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
).to_positive_set(IdState::Positive);
let trace: SlicingTrace<PositiveSet, PositiveReaction, PositiveSystem> =
SlicingTrace {
elements,
enabled_reactions,
reactions: Rc::new(reactions),
systems: vec![],
context_elements: Rc::new(context_elements),
products_elements: Rc::new(products_elements),
};
let marking =
Into::<Set>::into(
["tbet"]
.iter()
.map(|el| translator.encode(*el))
.collect::<Vec<_>>()
).to_positive_set(IdState::Positive);
let sliced = trace.slice(marking).unwrap();
let mut reaction_products = sliced
.elements
.iter()
.map(|elements| {
elements
.reaction_products
.iter()
.map(|el| (translator.decode(*el.0).unwrap(), *el.1))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
reaction_products.iter_mut().for_each(|x| x.sort());
let mut correct_reaction_products: Vec<Vec<(String, IdState)>> =
[vec![("foxp3", IdState::Negative)],
vec![("nfat", IdState::Positive), ("tgfbr", IdState::Negative)],
vec![("stat1", IdState::Positive), ("foxp3", IdState::Negative),
("rorgt", IdState::Negative)],
vec![("tbet", IdState::Positive)]]
.iter().map(|x| x.iter().map(|y| (y.0.to_string(), y.1))
.collect::<Vec<_>>()).collect::<Vec<_>>();
correct_reaction_products.iter_mut().for_each(|x| x.sort());
assert_eq!(reaction_products, correct_reaction_products);
let mut context = sliced
.elements
.iter()
.map(|elements| {
elements
.context
.iter()
.map(|el| (translator.decode(*el.0).unwrap(), *el.1))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
context.iter_mut().for_each(|x| x.sort());
let mut correct_context =
[vec![("tcr", IdState::Positive)],
vec![("il27", IdState::Positive)],
vec![],
vec![]]
.iter().map(|x| x.iter().map(|y| (y.0.to_string(), y.1))
.collect::<Vec<_>>()).collect::<Vec<_>>();
correct_context.iter_mut().for_each(|x| x.sort());
assert_eq!(context, correct_context);
let mut enabled_reactions = sliced
.enabled_reactions
.iter()
.map(|elements| elements.data.clone())
.collect::<Vec<_>>();
enabled_reactions.iter_mut().for_each(|x| x.sort());
let mut correct_enabled_reactions = vec![vec![11], vec![2, 20], vec![10]];
correct_enabled_reactions.iter_mut().for_each(|x| x.sort());
assert_eq!(enabled_reactions, correct_enabled_reactions);
}

View File

@ -1,5 +1,6 @@
//! Module for helper structure for simulation //! Module for helper structure for simulation
use std::fmt::Debug;
use std::rc::Rc; use std::rc::Rc;
use super::label::{Label, PositiveLabel}; use super::label::{Label, PositiveLabel};
@ -8,6 +9,12 @@ use super::reaction::BasicReaction;
use super::set::{BasicSet, PositiveSet, Set}; use super::set::{BasicSet, PositiveSet, Set};
use super::system::{BasicSystem, ExtensionsSystem, PositiveSystem, System}; use super::system::{BasicSystem, ExtensionsSystem, PositiveSystem, System};
pub trait BasicTransition
where
Self: Clone + Debug + Iterator,
{
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TransitionsIterator< pub struct TransitionsIterator<
'a, 'a,
@ -19,12 +26,16 @@ pub struct TransitionsIterator<
system: &'a Sys, system: &'a Sys,
} }
impl<'a> TransitionsIterator<'a, Set, System, Process> { impl<'a> BasicTransition for TransitionsIterator<'a, Set, System, Process> {}
pub fn from(system: &'a System) -> Result<Self, String> {
match system.unfold() { impl<'a> TryFrom<&'a System> for TransitionsIterator<'a, Set, System, Process> {
| Ok(o) => Ok(TransitionsIterator { type Error = String;
fn try_from(value: &'a System) -> Result<Self, Self::Error> {
match value.unfold() {
| Ok(o) => Ok(Self {
choices_iterator: o.into_iter(), choices_iterator: o.into_iter(),
system, system: value,
}), }),
| Err(e) => Err(e), | Err(e) => Err(e),
} }
@ -35,7 +46,7 @@ impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> {
type Item = (Label, System); type Item = (Label, System);
/// Creates the next arc from the current system. /// Creates the next arc from the current system.
fn next(&mut self) -> Option<(Label, System)> { fn next(&mut self) -> Option<Self::Item> {
let (c, k) = self.choices_iterator.next()?; let (c, k) = self.choices_iterator.next()?;
let t = self.system.available_entities.union(c.as_ref()); let t = self.system.available_entities.union(c.as_ref());
let ( let (
@ -44,7 +55,7 @@ impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> {
inhibitors, inhibitors,
inhibitors_present, inhibitors_present,
products, products,
) = self.system.reaction_rules.iter().fold( ) = self.system.reactions().iter().fold(
( (
Set::default(), // reactants Set::default(), // reactants
Set::default(), // reactants_absent Set::default(), // reactants_absent
@ -95,12 +106,21 @@ impl<'a> Iterator for TransitionsIterator<'a, Set, System, Process> {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
impl<'a> TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess> { impl<'a> BasicTransition
pub fn from(system: &'a PositiveSystem) -> Result<Self, String> { for TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess>
match system.unfold() { {
| Ok(o) => Ok(TransitionsIterator { }
impl<'a> TryFrom<&'a PositiveSystem>
for TransitionsIterator<'a, PositiveSet, PositiveSystem, PositiveProcess>
{
type Error = String;
fn try_from(value: &'a PositiveSystem) -> Result<Self, Self::Error> {
match value.unfold() {
| Ok(o) => Ok(Self {
choices_iterator: o.into_iter(), choices_iterator: o.into_iter(),
system, system: value,
}), }),
| Err(e) => Err(e), | Err(e) => Err(e),
} }
@ -174,3 +194,71 @@ impl<'a> Iterator
Some((label, new_system)) Some((label, new_system))
} }
} }
// -----------------------------------------------------------------------------
pub struct TraceIterator<
'a,
S: BasicSet,
Sys: BasicSystem<Set = S, Process = Proc>,
Proc: BasicProcess<Set = S>,
> {
choices_iterator:
<<Sys as BasicSystem>::Choices as std::iter::IntoIterator>::IntoIter,
system: &'a Sys,
}
impl<'a> TryFrom<&'a PositiveSystem>
for TraceIterator<'a, PositiveSet, PositiveSystem, PositiveProcess>
{
type Error = String;
fn try_from(value: &'a PositiveSystem) -> Result<Self, Self::Error> {
match value.unfold() {
| Ok(o) => Ok(Self {
choices_iterator: o.into_iter(),
system: value,
}),
| Err(e) => Err(e),
}
}
}
impl<'a> Iterator
for TraceIterator<'a, PositiveSet, PositiveSystem, PositiveProcess>
{
type Item = (PositiveSet, PositiveSet, Vec<usize>, PositiveSystem);
fn next(&mut self) -> Option<Self::Item> {
let (context, k) = self.choices_iterator.next()?;
let total_entities =
self.system.available_entities().union(context.as_ref());
let (enabled_reaction_positions, all_products) =
self.system.reactions().iter().enumerate().fold(
(vec![], PositiveSet::default()),
|mut acc, (pos, reaction)| {
if reaction.enabled(&total_entities) {
acc.0.push(pos);
(acc.0, acc.1.union(&reaction.products))
} else {
acc
}
},
);
let new_system = PositiveSystem::from(
Rc::clone(&self.system.delta),
all_products,
(*k).clone(),
Rc::clone(&self.system.reaction_rules),
);
Some((
context.as_ref().clone(),
self.system.available_entities().clone(),
enabled_reaction_positions,
new_system,
))
}
}