diff --git a/src/rsprocess/grammar.lalrpop b/src/rsprocess/grammar.lalrpop index 97d9dde..6870546 100644 --- a/src/rsprocess/grammar.lalrpop +++ b/src/rsprocess/grammar.lalrpop @@ -272,11 +272,20 @@ LiteralSeparatorEdge: presets::EdgeDisplay = { }; NodeDisplay: presets::NodeDisplay = { - "Hide" => presets::NodeDisplay::Display(graph::GraphMapNodes::Hide), - "Entities" => presets::NodeDisplay::Display(graph::GraphMapNodes::Entities), + "Hide" => + presets::NodeDisplay::Display(graph::GraphMapNodes::Hide), + "Entities" => + presets::NodeDisplay::Display(graph::GraphMapNodes::Entities), "MaskEntities" => presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{mask}), - "Context" => presets::NodeDisplay::Display(graph::GraphMapNodes::Context) + "Context" => + presets::NodeDisplay::Display(graph::GraphMapNodes::Context), + "UncommonEntities" => + presets::NodeDisplay::UncommonEntities, + "MaskUncommonentities" => + presets::NodeDisplay::MaskUncommonEntities(mask), + "ExcludeEntities" => + presets::NodeDisplay::Display(graph::GraphMapNodes::ExcludeEntities{mask}) } /// Node display formatters separated by arbitrary strings in quotes diff --git a/src/rsprocess/graph.rs b/src/rsprocess/graph.rs index bf51f18..48ce5c6 100644 --- a/src/rsprocess/graph.rs +++ b/src/rsprocess/graph.rs @@ -41,6 +41,20 @@ pub fn digraph( Ok(graph) } + +pub fn common_entities( + graph: &RSgraph +) -> RSset { + graph.node_references().fold( + None, + |acc, node| + match acc { + None => Some(node.1.available_entities.clone()), + Some(acc) => Some(node.1.available_entities.intersection(&acc)) + } + ).unwrap_or(RSset::new()) +} + // ----------------------------------------------------------------------------- // helper functions // ----------------------------------------------------------------------------- @@ -54,6 +68,7 @@ pub enum GraphMapNodes { Hide, Entities, MaskEntities { mask: RSset }, + ExcludeEntities { mask: RSset }, Context, } @@ -108,6 +123,20 @@ impl GraphMapNodesTy { } ) }, + ExcludeEntities { mask } => { + Box::new( + move |_, node: &RSsystem| { + let masked_entities = + node.available_entities + .subtraction(&mask); + format!("{}", + translator::RSsetDisplay::from( + &translator, + &masked_entities) + ) + } + ) + } Context => { Box::new( move |_, node: &RSsystem| diff --git a/src/rsprocess/presets.rs b/src/rsprocess/presets.rs index 7a859ae..70a3542 100644 --- a/src/rsprocess/presets.rs +++ b/src/rsprocess/presets.rs @@ -62,6 +62,8 @@ impl Default for SaveOptions { pub enum NodeDisplay { Separator(String), Display(graph::GraphMapNodes), + UncommonEntities, + MaskUncommonEntities(RSset) } @@ -539,6 +541,7 @@ pub fn bisimilar( #[allow(clippy::type_complexity)] fn generate_node_pringting_fn<'a>( node_display: &'a Vec, + graph: &graph::RSgraph, translator: Rc, ) -> Box String + 'a> { // The type cannot be aliased since rust doesnt like generics. @@ -557,11 +560,43 @@ fn generate_node_pringting_fn<'a>( (accumulator)(i, n) + &graph::GraphMapNodesTy::from(d.clone(), val.clone()).get()(i, n) }) - } + }, NodeDisplay::Separator(s) => { // we have a string so simply add it at the end Box::new(move |i, n| (accumulator)(i, n) + s) - } + }, + // ad hoc since graph information is not available in the graph + // function generation + NodeDisplay::UncommonEntities => { + let common_entities = graph::common_entities(graph); + let val = translator.clone(); + Box::new(move |i, n| { + (accumulator)(i, n) + + &graph::GraphMapNodesTy::from( + graph::GraphMapNodes::ExcludeEntities { + mask: common_entities.clone() + }, + val.clone() + ).get()(i, n) + } + ) + }, + // ad hoc since graph information is not available in the graph + // function generation + NodeDisplay::MaskUncommonEntities(mask) => { + let common_entities = graph::common_entities(graph); + let val = translator.clone(); + Box::new(move |i, n| { + (accumulator)(i, n) + + &graph::GraphMapNodesTy::from( + graph::GraphMapNodes::ExcludeEntities { + mask: common_entities.union(mask) + }, + val.clone() + ).get()(i, n) + } + ) + }, }; } accumulator @@ -666,6 +701,7 @@ pub fn dot( // fine... let modified_graph = graph.map( generate_node_pringting_fn(&node_display, + graph, Rc::clone(&rc_translator)), generate_edge_pringting_fn(&edge_display, Rc::clone(&rc_translator)), @@ -707,6 +743,7 @@ pub fn graphml( // map each value to the corresponding value we want to display let modified_graph = graph.map( generate_node_pringting_fn(&node_display, + graph, Rc::clone(&rc_translator)), generate_edge_pringting_fn(&edge_display, rc_translator), diff --git a/src/rsprocess/structure.rs b/src/rsprocess/structure.rs index d49b18e..b9ace77 100644 --- a/src/rsprocess/structure.rs +++ b/src/rsprocess/structure.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; // ----------------------------------------------------------------------------- /// Basic set of entities. -#[derive(Clone, Debug, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialOrd, Eq, Ord, Serialize, Deserialize)] pub struct RSset { pub identifiers: BTreeSet, } @@ -79,7 +79,7 @@ impl RSset { RSset { identifiers: res } } - /// returns the new set a \ b + /// returns the new set a ∖ b pub fn subtraction(&self, b: &RSset) -> RSset { // TODO maybe find more efficient way without copy/clone let res: BTreeSet<_> = self @@ -123,6 +123,12 @@ impl PartialEq for RSset { } } +impl Hash for RSset { + fn hash(&self, state: &mut H) { + self.identifiers.hash(state) + } +} + impl IntoIterator for RSset { type Item = IdType; type IntoIter = std::collections::btree_set::IntoIter; @@ -564,7 +570,8 @@ impl PartialEq for RSlabel { fn eq(&self, other: &Self) -> bool { self.available_entities == other.available_entities && self.context == other.context && - self.t == other.t && + // self.t == other.t && // no need since its the union of the above + // // elements self.reactants == other.reactants && self.reactants_absent == other.reactants_absent && self.inhibitors == other.inhibitors &&