Introducing traits for sets and reactions

This commit is contained in:
elvis
2025-08-26 16:56:08 +02:00
parent a46ab3833d
commit bf2403cdcf
14 changed files with 376 additions and 311 deletions

View File

@ -1,6 +1,7 @@
use std::collections::HashMap;
use super::super::{translator, graph, set, process, system, label};
use super::super::set::BasicSet;
/// If changing IntegerType in assert.rs, also change from Num to another
/// similar parser with different return type in grammar.lalrpop in

View File

@ -890,12 +890,12 @@ fn for_1() {
Box::new(Tree::Assignment(
Variable::Id("a".into()),
None,
Box::new(Expression::Set(Set::new()))
Box::new(Expression::Set(Set::default()))
)),
Box::new(Tree::Assignment(
Variable::Id("b".into()),
None,
Box::new(Expression::Set(Set::new()))
Box::new(Expression::Set(Set::default()))
)),
)),
Box::new(Tree::For(
@ -945,7 +945,7 @@ fn for_2() {
Box::new(Tree::Assignment(
Variable::Id("b".into()),
None,
Box::new(Expression::Set(Set::new()))
Box::new(Expression::Set(Set::default()))
)),
)),
Box::new(Tree::For(
@ -996,19 +996,19 @@ fn for_3() {
None,
Box::new(Expression::Label(
Box::new(Label::from(Set::from([1, 2]),
Set::new(),
Set::default(),
Set::from([1, 2]),
Set::new(),
Set::new(),
Set::new(),
Set::new(),
Set::new()))
Set::default(),
Set::default(),
Set::default(),
Set::default(),
Set::default()))
))
)),
Box::new(Tree::Assignment(
Variable::Id("b".into()),
None,
Box::new(Expression::Set(Set::new()))
Box::new(Expression::Set(Set::default()))
)),
)),
Box::new(Tree::For(
@ -1066,17 +1066,17 @@ fn for_4() {
Box::new(Label::from(Set::from([1, 2]),
Set::from([3]),
Set::from([1, 2, 3]),
Set::new(),
Set::new(),
Set::new(),
Set::new(),
Set::new()))
Set::default(),
Set::default(),
Set::default(),
Set::default(),
Set::default()))
))
)),
Box::new(Tree::Assignment(
Variable::Id("b".into()),
None,
Box::new(Expression::Set(Set::new()))
Box::new(Expression::Set(Set::default()))
)),
)),
Box::new(Tree::For(
@ -1135,11 +1135,11 @@ fn for_5() {
Box::new(Label::from(Set::from([1, 2]),
Set::from([3]),
Set::from([1, 2, 3]),
Set::new(),
Set::new(),
Set::new(),
Set::new(),
Set::new()))
Set::default(),
Set::default(),
Set::default(),
Set::default(),
Set::default()))
))
)),
Box::new(Tree::Assignment(
@ -1217,11 +1217,11 @@ fn for_6() {
Box::new(Label::from(Set::from([1, 2]),
Set::from([3]),
Set::from([1, 2, 3]),
Set::new(),
Set::new(),
Set::new(),
Set::new(),
Set::new()))
Set::default(),
Set::default(),
Set::default(),
Set::default(),
Set::default()))
))
)),
Box::new(Tree::Concat(

View File

@ -1,7 +1,7 @@
use std::rc::Rc;
use super::process::Process;
use super::set::Set;
use super::set::{BasicSet, Set};
use super::translator::{Translator, PrintableWithTranslator, Formatter};
#[derive(Clone, Debug)]
@ -18,7 +18,7 @@ impl Choices {
pub fn new_not_empty() -> Self {
Choices {
context_moves: vec![(Rc::new(Set::new()),
context_moves: vec![(Rc::new(Set::default()),
Rc::new(Process::Nill))],
}
}

View File

@ -5,8 +5,8 @@ use std::rc::Rc;
use super::choices::Choices;
use super::process::Process;
use super::reaction::Reaction;
use super::set::Set;
use super::reaction::{Reaction, BasicReaction, ExtensionReaction};
use super::set::{BasicSet, Set};
use super::translator::{IdType, Translator, PrintableWithTranslator, Formatter};
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -30,7 +30,7 @@ impl Environment {
}
pub fn all_elements(&self) -> Set {
let mut acc = Set::new();
let mut acc = Set::default();
for (_, process) in self.definitions.iter() {
acc.push(&process.all_elements());
}
@ -110,7 +110,7 @@ impl Environment {
// short-circuits with try_fold.
if children.is_empty() {
Ok(Choices::from(vec![(
Rc::new(Set::new()),
Rc::new(Set::default()),
Rc::new(Process::Nill),
)]))
} else {

View File

@ -1,5 +1,5 @@
pub mod graph_map_nodes_ty_from {
use super::super::set::Set;
use super::super::set::{BasicSet, Set};
use super::super::system::System;
use super::super::translator;
use std::rc::Rc;
@ -74,7 +74,7 @@ pub mod graph_map_nodes_ty_from {
pub mod graph_map_edges_ty_from {
use super::super::set::Set;
use super::super::set::{BasicSet, Set};
use super::super::label::Label;
use super::super::translator;
use std::rc::Rc;

View File

@ -2,8 +2,8 @@
use std::collections::HashMap;
use super::reaction::Reaction;
use super::set::Set;
use super::reaction::{Reaction, ExtensionReaction};
use super::set::{Set, ExtensionsSet};
use super::system::System;
use super::translator::{IdType, Translator, PrintableWithTranslator, PRECISION};

View File

@ -5,7 +5,7 @@ use petgraph::{Graph, Directed};
use std::rc::Rc;
use super::label::Label;
use super::set::Set;
use super::set::{BasicSet, Set};
use super::system::System;
use super::translator::{self, IdType};
@ -19,7 +19,7 @@ fn common_system_entities(graph: &SystemGraph) -> Set {
None => Some(node.1.available_entities.clone()),
Some(acc) => Some(node.1.available_entities.intersection(&acc))
}
).unwrap_or(Set::new())
).unwrap_or(Set::default())
}
macro_rules! common_label {
@ -39,7 +39,7 @@ macro_rules! common_label {
Some($acc_name) => Some($some_expr)
}
}
).unwrap_or(Set::new())
).unwrap_or(Set::default())
}
};
}
@ -218,7 +218,7 @@ impl NodeDisplay {
if self.contains_uncommon() {
Rc::new(common_system_entities(current_graph))
} else {
Rc::new(Set::new())
Rc::new(Set::default())
};
Box::new(

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use std::hash::Hash;
use super::set::Set;
use super::set::{BasicSet, Set};
use super::translator::{Translator, PrintableWithTranslator, Formatter};
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialOrd)]
@ -19,14 +19,14 @@ pub struct Label {
impl Label {
pub fn new() -> Self {
Label {
available_entities: Set::new(),
context: Set::new(),
t: Set::new(),
reactants: Set::new(),
reactants_absent: Set::new(),
inhibitors: Set::new(),
inhibitors_present: Set::new(),
products: Set::new(),
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(),
}
}

View File

@ -4,7 +4,7 @@ use std::hash::Hash;
use std::rc::Rc;
use super::reaction::Reaction;
use super::set::Set;
use super::set::{Set, BasicSet};
use super::translator::{IdType, Translator, PrintableWithTranslator, Formatter};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -61,7 +61,7 @@ impl Process {
/// returns all elements used
pub fn all_elements(&self) -> Set {
let mut queue = VecDeque::from([self]);
let mut elements = Set::new();
let mut elements = Set::default();
while let Some(el) = queue.pop_front() {
match el {

View File

@ -6,75 +6,64 @@
use serde::{Deserialize, Serialize};
use std::hash::Hash;
use super::set::Set;
use super::set::{BasicSet, ExtensionsSet, Set};
use super::translator::{Translator, PrintableWithTranslator, Formatter};
/// Basic structure for a reaction.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Reaction {
pub reactants: Set,
pub inhibitors: Set,
pub products: Set,
pub trait BasicReaction<S: BasicSet>:
Clone + Default + Eq + Hash + Serialize + PrintableWithTranslator
where for<'de> Self: Deserialize<'de>,
{
fn enabled(&self, state: &S) -> bool;
fn compute_step(&self, state: &S) -> Option<&S>;
}
impl Reaction {
pub fn new() -> Self {
Reaction {
reactants: Set::new(),
inhibitors: Set::new(),
products: Set::new(),
}
}
pub trait ExtensionReaction<S: BasicSet> {
fn compute_all(reactions: &[Self], state: &S) -> S
where Self: Sized;
pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self {
Reaction {
reactants,
inhibitors,
products,
}
}
fn find_loop(reactions: &[Self], entities: S, q: &S) -> (Vec<S>, Vec<S>)
where Self: Sized;
/// returns true if ```current_state``` enables the reaction
/// see enable
pub fn enabled(&self, current_state: &Set) -> bool {
self.reactants.is_subset(current_state)
&& self.inhibitors.is_disjoint(current_state)
}
fn find_only_loop(reactions: &[Self], entities: S, q: &S) -> Vec<S>
where Self: Sized;
/// Computes the result of a single reaction (if enabled returns the products)
/// otherwise returns None.
/// see result
pub fn compute_step<'a>(
&'a self,
current_state: &'a Set,
) -> Option<&'a Set> {
if self.enabled(current_state) {
Some(&self.products)
} else {
None
}
}
fn find_prefix_len_loop(
reactions: &[Self],
entities: S,
q: &S
) -> (usize, Vec<S>)
where Self: Sized;
fn lollipops_only_loop_decomposed_q(
reactions: &[Self],
entities: &S,
q: &S
) -> Vec<S>
where Self: Sized;
}
impl<T: BasicReaction<S>, S: BasicSet> ExtensionReaction<S> for T {
/// Computes the result of a series of reactions. Returns the union of all
/// products.
/// see result
pub fn compute_all<'a>(
current_state: &'a Set,
reactions: &'a [Self]
) -> Set {
reactions.iter().fold(Set::new(), |mut acc, r| {
acc.union_option(r.compute_step(current_state));
fn compute_all(
reactions: &[Self],
state: &S
) -> S
where Self: Sized {
reactions.iter().fold(S::default(), |mut acc: S, r| {
acc.extend(r.compute_step(state));
acc
})
}
/// Finds the loops by simulating the system.
pub fn find_loop(
rs: &[Self],
entities: Set,
q: &Set
) -> (Vec<Set>, Vec<Set>) {
fn find_loop(
reactions: &[Self],
entities: S,
q: &S
) -> (Vec<S>, Vec<S>) {
let mut entities = entities;
let mut trace = vec![];
loop {
@ -82,7 +71,7 @@ impl Reaction {
return (prefix.to_vec(), hoop.to_vec());
} else {
let t = entities.union(q);
let products = Self::compute_all(&t, rs);
let products = Self::compute_all(reactions, &t);
trace.push(entities.clone());
entities = products;
}
@ -91,11 +80,11 @@ impl Reaction {
/// Finds the loops by simulating the system.
pub fn find_only_loop(
rs: &[Self],
entities: Set,
q: &Set
) -> Vec<Set> {
fn find_only_loop(
reactions: &[Self],
entities: S,
q: &S
) -> Vec<S> {
let mut entities = entities;
let mut trace = vec![];
loop {
@ -103,7 +92,7 @@ impl Reaction {
return hoop.to_vec();
} else {
let t = entities.union(q);
let products = Self::compute_all(&t, rs);
let products = Self::compute_all(reactions, &t);
trace.push(entities.clone());
entities = products;
}
@ -112,11 +101,11 @@ impl Reaction {
/// Finds the loops and the length of the prefix by simulating the system.
pub fn find_prefix_len_loop(
rs: &[Self],
entities: Set,
q: &Set
) -> (usize, Vec<Set>) {
fn find_prefix_len_loop(
reactions: &[Self],
entities: S,
q: &S
) -> (usize, Vec<S>) {
let mut entities = entities;
let mut trace = vec![];
loop {
@ -124,7 +113,7 @@ impl Reaction {
return (prefix.len(), hoop.to_vec());
} else {
let t = entities.union(q);
let products = Self::compute_all(&t, rs);
let products = Self::compute_all(reactions, &t);
trace.push(entities.clone());
entities = products;
}
@ -133,22 +122,62 @@ impl Reaction {
/// see loop/5
pub fn lollipops_only_loop_decomposed_q(
reaction_rules: &[Self],
q: &Set,
available_entities: &Set,
) -> Vec<Set> {
fn lollipops_only_loop_decomposed_q(
reactions: &[Self],
entities: &S,
q: &S,
) -> Vec<S> {
let find_loop_fn =
|q| Reaction::find_only_loop(reaction_rules,
available_entities.clone(),
|q| Self::find_only_loop(reactions,
entities.clone(),
q);
find_loop_fn(q)
}
}
impl Default for Reaction {
fn default() -> Self {
Reaction::new()
// -----------------------------------------------------------------------------
/// Basic structure for a reaction.
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Reaction {
pub reactants: Set,
pub inhibitors: Set,
pub products: Set,
}
impl BasicReaction<Set> for Reaction {
/// returns true if ```current_state``` enables the reaction
/// see enable
fn enabled(&self, current_state: &Set) -> bool {
self.reactants.is_subset(current_state)
&& self.inhibitors.is_disjoint(current_state)
}
/// 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> {
if self.enabled(state) {
Some(&self.products)
} else {
None
}
}
}
impl Reaction {
pub fn from(reactants: Set, inhibitors: Set, products: Set) -> Self {
Reaction {
reactants,
inhibitors,
products,
}
}
}

View File

@ -5,108 +5,48 @@ use std::fmt;
use super::translator::{IdType, Translator, PrintableWithTranslator};
/// Basic set of entities.
#[derive(Clone, Debug, PartialOrd, Eq, Ord, Serialize, Deserialize)]
pub struct Set {
pub identifiers: BTreeSet<IdType>,
/// Basic trait for all Set implementations.
/// Implement IntoIterator for &Self to have .iter() (not required directly by
/// the trait).
pub trait BasicSet
where Self: Clone + Eq + Ord + Default + Serialize + IntoIterator
+ PrintableWithTranslator,
for<'de> Self: Deserialize<'de>
{
fn is_subset(&self, other: &Self) -> bool;
fn is_disjoint(&self, other: &Self) -> bool;
fn union(&self, other: &Self) -> Self;
fn push(&mut self, other: &Self);
fn extend(&mut self, other: Option<&Self>);
fn intersection(&self, other: &Self) -> Self;
fn subtraction(&self, other: &Self) -> Self;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
}
impl<const N: usize> From<[IdType; N]> for Set {
fn from(arr: [IdType; N]) -> Self {
Set {
identifiers: BTreeSet::from(arr),
}
}
pub trait ExtensionsSet {
fn iter(
&self
) -> <&Self as IntoIterator>::IntoIter
where for<'b> &'b Self: IntoIterator;
fn split<'a>(
&'a self,
trace: &'a [Self]
) -> Option<(&'a [Self], &'a [Self])>
where Self: Sized;
}
impl From<&[IdType]> for Set {
fn from(arr: &[IdType]) -> Self {
Set {
identifiers: BTreeSet::from_iter(arr.to_vec()),
}
}
}
impl From<Vec<IdType>> for Set {
fn from(arr: Vec<IdType>) -> Self {
Set {
identifiers: BTreeSet::from_iter(arr),
}
}
}
impl Set {
pub const fn new() -> Self {
Set {
identifiers: BTreeSet::new(),
}
}
pub fn is_subset(&self, b: &Set) -> bool {
self.identifiers.is_subset(&b.identifiers)
}
pub fn is_disjoint(&self, b: &Set) -> bool {
self.identifiers.is_disjoint(&b.identifiers)
}
// returns the new set a \cup b
pub fn union(&self, b: &Set) -> Set {
let mut ret: Set = b.clone();
ret.identifiers.extend(self.identifiers.iter());
ret
}
pub fn union_option(&mut self, b: Option<&Set>) {
if let Some(b) = b {
self.identifiers.extend(b.iter());
}
}
/// returns the new set a \cap b
pub fn intersection(&self, b: &Set) -> Set {
// TODO maybe find more efficient way without copy/clone
let res: BTreeSet<_> = b
.identifiers
.intersection(&self.identifiers)
.copied()
.collect();
Set { identifiers: res }
}
/// returns the new set a b
pub fn subtraction(&self, b: &Set) -> Set {
// TODO maybe find more efficient way without copy/clone
let res: BTreeSet<_> = self
.identifiers
.difference(&b.identifiers)
.copied()
.collect();
Set { identifiers: res }
}
pub fn iter(&self) -> std::collections::btree_set::Iter<'_, IdType> {
self.identifiers.iter()
}
pub fn len(&self) -> usize {
self.identifiers.len()
}
pub fn insert(&mut self, el: IdType) -> bool {
self.identifiers.insert(el)
}
pub fn push(&mut self, b: &Set) {
self.identifiers.extend(b.iter())
}
pub fn is_empty(&self) -> bool {
self.identifiers.is_empty()
/// Implementations for all sets.
impl<T: BasicSet> ExtensionsSet for T {
fn iter(&self) -> <&T as IntoIterator>::IntoIter
where for<'b> &'b T: IntoIterator {
self.into_iter()
}
/// Returns the prefix and the loop from a trace.
pub fn split<'a>(
fn split<'a>(
&'a self,
trace: &'a [Self]
) -> Option<(&'a [Self], &'a [Self])> {
@ -115,9 +55,69 @@ impl Set {
}
}
impl Default for Set {
fn default() -> Self {
Set::new()
// -----------------------------------------------------------------------------
/// Basic set of entities.
#[derive(Clone, Debug, Default, PartialOrd, Eq, Ord, Serialize, Deserialize)]
pub struct Set {
pub identifiers: BTreeSet<IdType>,
}
impl BasicSet for Set {
fn is_subset(&self, other: &Self) -> bool {
self.identifiers.is_subset(&other.identifiers)
}
fn is_disjoint(&self, other: &Self) -> bool {
self.identifiers.is_disjoint(&other.identifiers)
}
// returns the new set a \cup b
fn union(&self, other: &Self) -> Self {
let mut ret: Set = other.clone();
ret.identifiers.extend(self.identifiers.iter());
ret
}
fn push(&mut self, b: &Self) {
self.identifiers.extend(b.iter())
}
fn extend(&mut self, other: Option<&Self>) {
if let Some(other) = other {
self.identifiers.extend(other);
}
}
/// returns the new set a \cap b
fn intersection(&self, other: &Self) -> Self {
// TODO maybe find more efficient way without copy/clone
let res: BTreeSet<_> = other
.identifiers
.intersection(&self.identifiers)
.copied()
.collect();
Set { identifiers: res }
}
/// returns the new set a b
fn subtraction(&self, other: &Self) -> Self {
// TODO maybe find more efficient way without copy/clone
let res: BTreeSet<_> = self
.identifiers
.difference(&other.identifiers)
.copied()
.collect();
Set { identifiers: res }
}
fn len(&self) -> usize {
self.identifiers.len()
}
fn is_empty(&self) -> bool {
self.identifiers.is_empty()
}
}
@ -142,6 +142,15 @@ impl IntoIterator for Set {
}
}
impl<'a> IntoIterator for &'a Set {
type Item = &'a IdType;
type IntoIter = std::collections::btree_set::Iter<'a, IdType>;
fn into_iter(self) -> Self::IntoIter {
self.identifiers.iter()
}
}
impl PrintableWithTranslator for Set {
fn print(
&self,
@ -164,3 +173,28 @@ impl PrintableWithTranslator for Set {
write!(f, "}}")
}
}
impl<const N: usize> From<[IdType; N]> for Set {
fn from(arr: [IdType; N]) -> Self {
Set {
identifiers: BTreeSet::from(arr),
}
}
}
impl From<&[IdType]> for Set {
fn from(arr: &[IdType]) -> Self {
Set {
identifiers: BTreeSet::from_iter(arr.to_vec()),
}
}
}
impl From<Vec<IdType>> for Set {
fn from(arr: Vec<IdType>) -> Self {
Set {
identifiers: BTreeSet::from_iter(arr),
}
}
}

View File

@ -7,8 +7,8 @@ use super::environment::Environment;
use super::graph::SystemGraph;
use super::label::Label;
use super::process::Process;
use super::reaction::Reaction;
use super::set::Set;
use super::reaction::{Reaction, ExtensionReaction};
use super::set::{BasicSet, Set};
use super::transitions::TransitionsIterator;
use super::translator::{IdType, Translator, PrintableWithTranslator, Formatter};
@ -27,7 +27,7 @@ impl System {
pub fn new() -> System {
System {
delta: Rc::new(Environment::new()),
available_entities: Set::new(),
available_entities: Set::default(),
context_process: Process::Nill,
reaction_rules: Rc::new(vec![]),
}
@ -405,7 +405,7 @@ impl System {
let reactants = self
.reaction_rules
.iter()
.fold(Set::new(), |acc, new| acc.union(&new.reactants));
.fold(Set::default(), |acc, new| acc.union(&new.reactants));
result.push_str(&format!(
"The reactants are {}:\n{}\n",
reactants.len(),
@ -415,7 +415,7 @@ impl System {
let inhibitors = self
.reaction_rules
.iter()
.fold(Set::new(), |acc, new| acc.union(&new.inhibitors));
.fold(Set::default(), |acc, new| acc.union(&new.inhibitors));
result.push_str(&format!(
"The inhibitors are {}:\n{}\n",
inhibitors.len(),
@ -425,7 +425,7 @@ impl System {
let products = self
.reaction_rules
.iter()
.fold(Set::new(), |acc, new| acc.union(&new.products));
.fold(Set::default(), |acc, new| acc.union(&new.products));
result.push_str(&format!(
"The products are {}:\n{}\n",
products.len(),

View File

@ -53,7 +53,7 @@ fn traces_1() {
inhibitors: Set::from([1]),
products: Set::from([1]), },
Reaction { reactants: Set::from([2]),
inhibitors: Set::new(),
inhibitors: Set::default(),
products: Set::from([4]), },
])
};
@ -113,7 +113,7 @@ fn traces_empty_env() {
inhibitors: Set::from([1]),
products: Set::from([1]), },
Reaction { reactants: Set::from([2]),
inhibitors: Set::new(),
inhibitors: Set::default(),
products: Set::from([4]), },
])
};

View File

@ -4,8 +4,9 @@ use std::rc::Rc;
use super::label::Label;
use super::process::Process;
use super::set::Set;
use super::set::{BasicSet, Set};
use super::system::System;
use super::reaction::BasicReaction;
#[derive(Clone, Debug)]
pub struct TransitionsIterator<'a> {
@ -44,11 +45,11 @@ impl<'a> Iterator for TransitionsIterator<'a> {
) =
self.system.reaction_rules.iter().fold(
(
Set::new(), // reactants
Set::new(), // reactants_absent
Set::new(), // inhibitors
Set::new(), // inhibitors_present
Set::new(), // products
Set::default(), // reactants
Set::default(), // reactants_absent
Set::default(), // inhibitors
Set::default(), // inhibitors_present
Set::default(), // products
),
|acc, reaction| {
if reaction.enabled(&t) {