Support for excluding common entities and excluding custom ones

This commit is contained in:
elvis
2025-07-16 16:20:29 +02:00
parent 0ef51200e5
commit 23ce9c3488
4 changed files with 90 additions and 8 deletions

View File

@ -272,11 +272,20 @@ LiteralSeparatorEdge: presets::EdgeDisplay = {
}; };
NodeDisplay: presets::NodeDisplay = { NodeDisplay: presets::NodeDisplay = {
"Hide" => presets::NodeDisplay::Display(graph::GraphMapNodes::Hide), "Hide" =>
"Entities" => presets::NodeDisplay::Display(graph::GraphMapNodes::Entities), presets::NodeDisplay::Display(graph::GraphMapNodes::Hide),
"Entities" =>
presets::NodeDisplay::Display(graph::GraphMapNodes::Entities),
"MaskEntities" <mask: Set> => "MaskEntities" <mask: Set> =>
presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{mask}), 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" <mask: Set> =>
presets::NodeDisplay::MaskUncommonEntities(mask),
"ExcludeEntities" <mask: Set> =>
presets::NodeDisplay::Display(graph::GraphMapNodes::ExcludeEntities{mask})
} }
/// Node display formatters separated by arbitrary strings in quotes /// Node display formatters separated by arbitrary strings in quotes

View File

@ -41,6 +41,20 @@ pub fn digraph(
Ok(graph) 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 // helper functions
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -54,6 +68,7 @@ pub enum GraphMapNodes {
Hide, Hide,
Entities, Entities,
MaskEntities { mask: RSset }, MaskEntities { mask: RSset },
ExcludeEntities { mask: RSset },
Context, 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 => { Context => {
Box::new( Box::new(
move |_, node: &RSsystem| move |_, node: &RSsystem|

View File

@ -62,6 +62,8 @@ impl Default for SaveOptions {
pub enum NodeDisplay { pub enum NodeDisplay {
Separator(String), Separator(String),
Display(graph::GraphMapNodes), Display(graph::GraphMapNodes),
UncommonEntities,
MaskUncommonEntities(RSset)
} }
@ -539,6 +541,7 @@ pub fn bisimilar(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn generate_node_pringting_fn<'a>( fn generate_node_pringting_fn<'a>(
node_display: &'a Vec<NodeDisplay>, node_display: &'a Vec<NodeDisplay>,
graph: &graph::RSgraph,
translator: Rc<Translator>, translator: Rc<Translator>,
) -> Box<dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> String + 'a> { ) -> Box<dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> String + 'a> {
// The type cannot be aliased since rust doesnt like generics. // The type cannot be aliased since rust doesnt like generics.
@ -557,11 +560,43 @@ fn generate_node_pringting_fn<'a>(
(accumulator)(i, n) (accumulator)(i, n)
+ &graph::GraphMapNodesTy::from(d.clone(), val.clone()).get()(i, n) + &graph::GraphMapNodesTy::from(d.clone(), val.clone()).get()(i, n)
}) })
} },
NodeDisplay::Separator(s) => { NodeDisplay::Separator(s) => {
// we have a string so simply add it at the end // we have a string so simply add it at the end
Box::new(move |i, n| (accumulator)(i, n) + s) 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 accumulator
@ -666,6 +701,7 @@ pub fn dot(
// fine... // fine...
let modified_graph = graph.map( let modified_graph = graph.map(
generate_node_pringting_fn(&node_display, generate_node_pringting_fn(&node_display,
graph,
Rc::clone(&rc_translator)), Rc::clone(&rc_translator)),
generate_edge_pringting_fn(&edge_display, generate_edge_pringting_fn(&edge_display,
Rc::clone(&rc_translator)), Rc::clone(&rc_translator)),
@ -707,6 +743,7 @@ pub fn graphml(
// map each value to the corresponding value we want to display // map each value to the corresponding value we want to display
let modified_graph = graph.map( let modified_graph = graph.map(
generate_node_pringting_fn(&node_display, generate_node_pringting_fn(&node_display,
graph,
Rc::clone(&rc_translator)), Rc::clone(&rc_translator)),
generate_edge_pringting_fn(&edge_display, generate_edge_pringting_fn(&edge_display,
rc_translator), rc_translator),

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/// Basic set of entities. /// 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 struct RSset {
pub identifiers: BTreeSet<IdType>, pub identifiers: BTreeSet<IdType>,
} }
@ -79,7 +79,7 @@ impl RSset {
RSset { identifiers: res } RSset { identifiers: res }
} }
/// returns the new set a \ b /// returns the new set a b
pub fn subtraction(&self, b: &RSset) -> RSset { pub fn subtraction(&self, b: &RSset) -> RSset {
// TODO maybe find more efficient way without copy/clone // TODO maybe find more efficient way without copy/clone
let res: BTreeSet<_> = self let res: BTreeSet<_> = self
@ -123,6 +123,12 @@ impl PartialEq for RSset {
} }
} }
impl Hash for RSset {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.identifiers.hash(state)
}
}
impl IntoIterator for RSset { impl IntoIterator for RSset {
type Item = IdType; type Item = IdType;
type IntoIter = std::collections::btree_set::IntoIter<Self::Item>; type IntoIter = std::collections::btree_set::IntoIter<Self::Item>;
@ -564,7 +570,8 @@ impl PartialEq for RSlabel {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.available_entities == other.available_entities && self.available_entities == other.available_entities &&
self.context == other.context && 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 == other.reactants &&
self.reactants_absent == other.reactants_absent && self.reactants_absent == other.reactants_absent &&
self.inhibitors == other.inhibitors && self.inhibitors == other.inhibitors &&