From 2571148e747512cb6b7f8d0289beee62d5fa1253 Mon Sep 17 00:00:00 2001 From: elvis Date: Mon, 8 Sep 2025 19:04:26 +0200 Subject: [PATCH] Correct hanlding of reactions while converting from System to PositiveSystem --- src/rsprocess/element.rs | 12 +++ src/rsprocess/reaction.rs | 23 +++++ src/rsprocess/set.rs | 3 + src/rsprocess/set_test.rs | 23 +++++ src/rsprocess/system.rs | 46 ++++++--- src/rsprocess/system_test.rs | 178 +++++++++++++++++++++++++++-------- 6 files changed, 232 insertions(+), 53 deletions(-) diff --git a/src/rsprocess/element.rs b/src/rsprocess/element.rs index c3769aa..7abcec0 100644 --- a/src/rsprocess/element.rs +++ b/src/rsprocess/element.rs @@ -67,3 +67,15 @@ impl PrintableWithTranslator for PositiveType { ) } } + +impl From<(IdType, IdState)> for PositiveType { + fn from(value: (IdType, IdState)) -> Self { + Self { id: value.0, state: value.1 } + } +} + +impl From<(&IdType, &IdState)> for PositiveType { + fn from(value: (&IdType, &IdState)) -> Self { + Self { id: *value.0, state: *value.1 } + } +} diff --git a/src/rsprocess/reaction.rs b/src/rsprocess/reaction.rs index b1d2ee3..0cce695 100644 --- a/src/rsprocess/reaction.rs +++ b/src/rsprocess/reaction.rs @@ -236,4 +236,27 @@ impl PositiveReaction { products: products.to_positive_set(IdState::Positive), } } + + /// returns the reactants that are equal + pub fn differ_only_one_element(&self, other: &Self) -> Option { + if self.products != other.products { + return None + } + let mut found = false; + for el in self.reactants.iter() { + match other.reactants.identifiers.get(el.0) { + None => return None, + Some(s) => { + if s != el.1 { + if found { + return None + } else { + found = true + } + } + } + } + } + Some(self.reactants.intersection(&other.reactants)) + } } diff --git a/src/rsprocess/set.rs b/src/rsprocess/set.rs index 6381f5a..b71446f 100644 --- a/src/rsprocess/set.rs +++ b/src/rsprocess/set.rs @@ -349,6 +349,9 @@ impl Set { set1.equal_except_negated_elements(set2) ) { let intersection = set1.opposite_intersection(set2); + if intersection.len() != 1 { + continue + } set1.remove_elements(intersection); t[pos_set1 - removed] = set1.clone(); diff --git a/src/rsprocess/set_test.rs b/src/rsprocess/set_test.rs index 3db0dc9..a919922 100644 --- a/src/rsprocess/set_test.rs +++ b/src/rsprocess/set_test.rs @@ -107,3 +107,26 @@ fn prohibiting_set_4() { ] ) } + +#[test] +fn prohibiting_set_5() { + use super::element::IdState::*; + use super::set::{PositiveSet, Set}; + + let r1r = Set::from(vec![1]); + let r1i = Set::from(vec![2]); + + let r2r = Set::from(vec![1, 2]); + let r2i = Set::from(vec![]); + + let mut prohibiting_set = + Set::prohibiting_set(&[r1r, r2r], &[r1i, r2i]).unwrap(); + prohibiting_set.sort(); + + assert_eq!( + prohibiting_set, + vec![ + PositiveSet::from([(1, Negative)]), + ] + ) +} diff --git a/src/rsprocess/system.rs b/src/rsprocess/system.rs index 14ff4a6..9960f43 100644 --- a/src/rsprocess/system.rs +++ b/src/rsprocess/system.rs @@ -648,7 +648,8 @@ impl From for PositiveSystem { /// Should never fail. fn from(value: System) -> Self { let new_env = Rc::new((&*value.delta).into()); - let positive_entities = value.available_entities.to_positive_set(IdState::Positive); + let positive_entities = + value.available_entities.to_positive_set(IdState::Positive); let negative_entities = value .context_process @@ -666,27 +667,46 @@ impl From for PositiveSystem { ) .subtraction(&value.available_entities) .to_positive_set(IdState::Negative); - let new_available_entities = positive_entities.union(&negative_entities); + let new_available_entities = + positive_entities.union(&negative_entities); let new_context = value.context_process.into(); let new_reactions = { let mut res = vec![]; let old_reactions = &value.reaction_rules; - old_reactions.iter().for_each(|r| { - res.push(PositiveReaction::create( - r.reactants.clone(), - r.inhibitors.clone(), - r.products.clone(), - )) - }); + let all_products = Reaction::all_products(old_reactions); for el in all_products { - let p = Reaction::all_reactions_with_product(old_reactions, &el); + let p = + Reaction::all_reactions_with_product(old_reactions, &el); + let mut tmp = vec![]; + for r in p.iter() { + tmp.push(PositiveReaction::create( + r.reactants.clone(), + r.inhibitors.clone(), + Set::from([el]) + )) + } + tmp.sort_by(|r1, r2| r1.reactants.cmp(&r2.reactants)); + + // remove reactions with only one element of opposite state + // as intersection (same product ```el```) + let mut pos = tmp.len()-1; + while pos > 0 { + if let Some(intersection) + = tmp[pos].differ_only_one_element(&tmp[pos-1]) + { + tmp[pos-1].reactants = intersection; + tmp.remove(pos); + } + pos -= 1; + } + + res.extend(tmp); let prohib_set = Set::prohibiting_set( &p.iter().map(|p| p.reactants.clone()).collect::>(), &p.iter().map(|p| p.inhibitors.clone()).collect::>(), - ) - .unwrap(); + ).unwrap(); // since we have in input a valid system for s in prohib_set { res.push(PositiveReaction { reactants: s, @@ -694,6 +714,8 @@ impl From for PositiveSystem { }) } } + + Rc::new(res) }; diff --git a/src/rsprocess/system_test.rs b/src/rsprocess/system_test.rs index 4ad5c97..6261861 100644 --- a/src/rsprocess/system_test.rs +++ b/src/rsprocess/system_test.rs @@ -1,3 +1,5 @@ +use crate::rsprocess::{set::PositiveSet, system::BasicSystem}; + #[test] fn one_transition() { use super::environment::Environment; @@ -14,11 +16,13 @@ fn one_transition() { entities: Set::from([]), next_process: Rc::new(Process::Nill), }, - Rc::new(vec![Reaction { - reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), - }]), + Rc::new(vec![ + Reaction::from( + Set::from([1]), + Set::from([3]), + Set::from([3]), + ), + ]), ); match system.one_transition() { @@ -59,7 +63,8 @@ fn one_transition_2() { }, Rc::new(vec![ PositiveReaction { - reactants: PositiveSet::from([(1, IdState::Positive), (3, IdState::Negative)]), + reactants: PositiveSet::from([(1, IdState::Positive), + (3, IdState::Negative)]), products: PositiveSet::from([(3, IdState::Positive)]), }, PositiveReaction { @@ -122,11 +127,13 @@ fn convertion() { entities: Set::from([]), next_process: Rc::new(Process::Nill), }, - Rc::new(vec![Reaction { - reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), - }]), + Rc::new(vec![ + Reaction::from( + Set::from([1]), + Set::from([3]), + Set::from([3]), + ), + ]), ); let system: PositiveSystem = system.into(); @@ -202,21 +209,21 @@ fn traces_1() { available_entities: Set::from([1, 2]), context_process: Process::RecursiveIdentifier { identifier: 101 }, reaction_rules: Rc::new(vec![ - Reaction { - reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), - }, - Reaction { - reactants: Set::from([3]), - inhibitors: Set::from([1]), - products: Set::from([1]), - }, - Reaction { - reactants: Set::from([2]), - inhibitors: Set::default(), - products: Set::from([4]), - }, + 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([2]), + Set::default(), + Set::from([4]), + ), ]), }; @@ -261,21 +268,21 @@ fn traces_empty_env() { next_process: Rc::new(Process::Nill), }, reaction_rules: Rc::new(vec![ - Reaction { - reactants: Set::from([1]), - inhibitors: Set::from([3]), - products: Set::from([3]), - }, - Reaction { - reactants: Set::from([3]), - inhibitors: Set::from([1]), - products: Set::from([1]), - }, - Reaction { - reactants: Set::from([2]), - inhibitors: Set::default(), - products: Set::from([4]), - }, + 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([2]), + Set::default(), + Set::from([4]), + ), ]), }; @@ -283,3 +290,92 @@ fn traces_empty_env() { assert_eq!(res.len(), 1); assert_eq!(res[0].len(), 10); } + +#[test] +fn conversion_reactions() { + use std::rc::Rc; + + use super::system::{System, PositiveSystem}; + use super::environment::Environment; + use super::set::Set; + use super::process::Process; + use super::reaction::{Reaction, PositiveReaction}; + use super::element::IdState::*; + + let system = System { + delta: Rc::new(Environment::from([])), + available_entities: Set::from([1, 2]), + context_process: Process::Nill, + reaction_rules: Rc::new(vec![ + Reaction::from( + Set::from([2]), + Set::from([1, 3]), + Set::from([5]), + ), + Reaction::from( + Set::from([1, 2]), + Set::from([3]), + Set::from([5]), + ), + ]), + }; + let converted_system: PositiveSystem = system.into(); + let mut reactions = converted_system.reactions().clone(); + reactions.sort_by(|a, b| a.products.cmp(&b.products) + .then(a.reactants.cmp(&b.reactants))); + + assert_eq!(reactions, + vec![ + PositiveReaction::from( + PositiveSet::from([(2, Positive), (3, Negative)]), + PositiveSet::from([(5, Positive)]), + ), + PositiveReaction::from( + PositiveSet::from([(2, Negative)]), + PositiveSet::from([(5, Negative)]), + ), + PositiveReaction::from( + PositiveSet::from([(3, Positive)]), + PositiveSet::from([(5, Negative)]), + ), + ]); +} + +#[test] +fn conversion_entities() { + use std::rc::Rc; + + use super::system::{System, PositiveSystem}; + use super::environment::Environment; + use super::set::Set; + use super::process::Process; + use super::reaction::Reaction; + use super::element::IdState::*; + + let system = System { + delta: Rc::new(Environment::from([])), + available_entities: Set::from([1, 2]), + context_process: Process::Nill, + reaction_rules: Rc::new(vec![ + Reaction::from( + Set::from([2]), + Set::from([1, 3]), + Set::from([5]), + ), + Reaction::from( + Set::from([1, 2]), + Set::from([3]), + Set::from([5]), + ), + ]), + }; + let converted_system: PositiveSystem = system.into(); + let entities = converted_system.available_entities().clone(); + + assert_eq!(entities, + PositiveSet::from([(1, Positive), + (2, Positive), + (3, Negative), + (5, Negative) + ])); +}