diff --git a/rsprocess/src/format_helpers.rs b/rsprocess/src/format_helpers.rs index 79cd504..6232999 100644 --- a/rsprocess/src/format_helpers.rs +++ b/rsprocess/src/format_helpers.rs @@ -519,3 +519,584 @@ pub mod edge_formatter { }) } } + +// ----------------------------------------------------------------------------- +// Positive +// ----------------------------------------------------------------------------- + +pub mod positive_graph_map_nodes_ty_from { + use std::rc::Rc; + + use super::super::element::IdState; + use super::super::set::{BasicSet, Set}; + use super::super::system::PositiveSystem; + use super::super::translator; + + type PositiveGraphMapNodesFnTy = + dyn Fn(petgraph::prelude::NodeIndex, &PositiveSystem) -> String; + + pub fn format_string(s: String) -> Box { + Box::new(move |_, _| s.clone()) + } + + pub fn format_hide( + _translator: Rc, + ) -> Box { + Box::new(|_, _| String::new()) + } + + pub fn format_entities( + translator: Rc, + ) -> Box { + Box::new(move |_, node: &PositiveSystem| { + format!( + "{}", + translator::Formatter::from( + &translator, + &node.available_entities + ) + ) + }) + } + + pub fn format_mask_entities( + translator: Rc, + mask: Set, + ) -> Box { + Box::new(move |_, node: &PositiveSystem| { + let masked_entities = node + .available_entities + .mask(&mask.to_positive_set(IdState::Positive)); + format!( + "{}", + translator::Formatter::from(&translator, &masked_entities) + ) + }) + } + + pub fn format_exclude_entities( + translator: Rc, + mask: Set, + ) -> Box { + Box::new(move |_, node: &PositiveSystem| { + let masked_entities = node + .available_entities + .subtraction(&mask.to_positive_set(IdState::Negative)) + .subtraction(&mask.to_positive_set(IdState::Negative)); + format!( + "{}", + translator::Formatter::from(&translator, &masked_entities) + ) + }) + } + + pub fn format_context( + translator: Rc, + ) -> Box { + Box::new(move |_, node: &PositiveSystem| { + format!( + "{}", + translator::Formatter::from(&translator, &node.context_process) + ) + }) + } +} + +pub mod positive_graph_map_edges_ty_from { + use std::rc::Rc; + + use super::super::element::IdState; + use super::super::label::PositiveLabel; + use super::super::set::{BasicSet, Set}; + use super::super::translator; + + type PositiveGraphMapEdgesFnTy<'a> = + dyn Fn(petgraph::prelude::EdgeIndex, &'a PositiveLabel) -> String + 'a; + + pub fn format_string<'a>( + _translator: Rc, + s: String, + ) -> Box> { + Box::new(move |_, _| s.clone()) + } + + pub fn format_hide<'a>( + _translator: Rc, + ) -> Box> { + Box::new(|_, _| String::new()) + } + + macro_rules! create_format_edge { + ( $name:ident, + [$edge_name:ident, $mask_name:ident, $common_name:ident], + $mask_common:expr, + $mask:expr, + $common:expr, + $default:expr ) => { + pub fn $name<'a>( + translator: Rc, + $mask_name: Option, + $common_name: Option, + ) -> Box> { + match ($mask_name, $common_name) { + | (Some($mask_name), Some($common_name)) => + Box::new(move |_, $edge_name: &PositiveLabel| { + format!( + "{}", + translator::Formatter::from( + &translator, + $mask_common + ) + ) + }), + | (Some($mask_name), None) => + Box::new(move |_, $edge_name: &PositiveLabel| { + format!( + "{}", + translator::Formatter::from(&translator, $mask) + ) + }), + | (None, Some($common_name)) => + Box::new(move |_, $edge_name: &PositiveLabel| { + format!( + "{}", + translator::Formatter::from( + &translator, + $common + ) + ) + }), + | (None, None) => + Box::new(move |_, $edge_name: &PositiveLabel| { + format!( + "{}", + translator::Formatter::from( + &translator, + $default + ) + ) + }), + } + } + }; + } + + create_format_edge!( + format_products, + [edge, mask, common], + &edge + .products + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.products.mask(&mask.to_positive_set(IdState::Positive)), + &edge + .products + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.products + ); + + create_format_edge!( + format_entities, + [edge, mask, common], + &edge + .available_entities + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge + .available_entities + .mask(&mask.to_positive_set(IdState::Positive)), + &edge + .available_entities + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.available_entities + ); + + create_format_edge!( + format_context, + [edge, mask, common], + &edge + .context + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.context.mask(&mask.to_positive_set(IdState::Positive)), + &edge + .context + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.context + ); + + create_format_edge!( + format_union, + [edge, mask, common], + &edge + .t + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.t.mask(&mask.to_positive_set(IdState::Positive)), + &edge + .t + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.t + ); + + create_format_edge!( + format_difference, + [edge, mask, common], + &edge + .context + .subtraction(&edge.available_entities) + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge + .context + .subtraction(&edge.available_entities) + .mask(&mask.to_positive_set(IdState::Positive)), + &edge + .context + .subtraction(&edge.available_entities) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.context.subtraction(&edge.available_entities) + ); + + create_format_edge!( + format_entities_deleted, + [edge, mask, common], + &edge + .available_entities + .subtraction(&edge.products) + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge + .available_entities + .subtraction(&edge.products) + .mask(&mask.to_positive_set(IdState::Positive)), + &edge + .available_entities + .subtraction(&edge.products) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.available_entities.subtraction(&edge.products) + ); + + create_format_edge!( + format_entities_added, + [edge, mask, common], + &edge + .products + .subtraction(&edge.available_entities) + .mask(&mask.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge + .products + .subtraction(&edge.available_entities) + .mask(&mask.to_positive_set(IdState::Positive)), + &edge + .products + .subtraction(&edge.available_entities) + .subtraction(&common.to_positive_set(IdState::Positive)) + .subtraction(&common.to_positive_set(IdState::Negative)), + &edge.products.subtraction(&edge.available_entities) + ); +} + +pub mod positive_node_formatter { + use std::rc::Rc; + + use petgraph::visit::IntoNodeReferences; + use petgraph::{Directed, Graph}; + + use super::super::element::IdType; + use super::super::graph::{OperationType, PositiveSystemGraph}; + use super::super::process::PositiveProcess; + use super::super::set::Set; + + type RSdotGraph = Graph; + type RSformatNodeTy = dyn Fn( + &RSdotGraph, + <&RSdotGraph as IntoNodeReferences>::NodeRef, + ) -> Option; + + pub fn format_nill( + original_graph: Rc, + color: String, + _star: Option, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if rssystem.context_process == PositiveProcess::Nill { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_recursive_identifier( + original_graph: Rc, + color: String, + star: Option, + s: IdType, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + match (Some(s) == star, &rssystem.context_process) { + | ( + true, + PositiveProcess::RecursiveIdentifier { identifier: _ }, + ) => Some(", fillcolor=".to_string() + &color), + | ( + false, + PositiveProcess::RecursiveIdentifier { identifier: id }, + ) if id == &s => Some(", fillcolor=".to_string() + &color), + | _ => None, + } + }) + } + + pub fn format_entity_set( + original_graph: Rc, + color: String, + _star: Option, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + match &rssystem.context_process { + | PositiveProcess::EntitySet { + entities, + next_process: _, + } if ot.evaluate_positive(entities, &set) => + Some(", fillcolor=".to_string() + &color), + | _ => None, + } + }) + } + + pub fn format_non_deterministic_choice( + original_graph: Rc, + color: String, + _star: Option, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if let PositiveProcess::NondeterministicChoice { children: _ } = + rssystem.context_process + { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_summation( + original_graph: Rc, + color: String, + _star: Option, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if let PositiveProcess::Summation { children: _ } = + rssystem.context_process + { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_wait_entity( + original_graph: Rc, + color: String, + _star: Option, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if let PositiveProcess::WaitEntity { + repeat: _, + repeated_process: _, + next_process: _, + } = &rssystem.context_process + { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_entities_conditional( + original_graph: Rc, + color: String, + _star: Option, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, n| { + let rssystem = original_graph.node_weight(n.0).unwrap(); + if ot.evaluate_positive(&rssystem.available_entities, &set) { + Some(", fillcolor=".to_string() + &color) + } else { + None + } + }) + } +} + +pub mod positive_edge_formatter { + use std::rc::Rc; + + use petgraph::visit::{EdgeRef, IntoEdgeReferences}; + use petgraph::{Directed, Graph}; + + use super::super::graph::{OperationType, PositiveSystemGraph}; + use super::super::set::Set; + + type RSdotGraph = Graph; + type RSformatEdgeTy = dyn Fn( + &RSdotGraph, + <&RSdotGraph as IntoEdgeReferences>::EdgeRef, + ) -> Option; + + pub fn format_entities( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.available_entities, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_context( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.context, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_t( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.t, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_reactants( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.reactants, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_reactants_absent( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.reactants_absent, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_inhibitors( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.inhibitors, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_inhibitors_present( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.inhibitors_present, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } + + pub fn format_products( + original_graph: Rc, + color: String, + ot: OperationType, + set: Set, + ) -> Box { + Box::new(move |_, e| { + let rssystem = original_graph.edge_weight(e.id()).unwrap(); + if ot.evaluate_positive(&rssystem.products, &set) { + Some(", color=".to_string() + &color) + } else { + None + } + }) + } +} diff --git a/rsprocess/src/graph.rs b/rsprocess/src/graph.rs index 8f8571b..76d5c50 100644 --- a/rsprocess/src/graph.rs +++ b/rsprocess/src/graph.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use super::element::IdType; use super::label::{Label, PositiveLabel}; -use super::set::{BasicSet, Set}; +use super::set::{BasicSet, PositiveSet, Set}; use super::system::{PositiveSystem, System}; use super::translator; @@ -17,6 +17,10 @@ pub type SystemGraph = Graph; pub type PositiveSystemGraph = Graph; +// ----------------------------------------------------------------------------- +// Helpers +// ----------------------------------------------------------------------------- + fn common_system_entities(graph: &SystemGraph) -> Set { graph .node_references() @@ -27,6 +31,17 @@ fn common_system_entities(graph: &SystemGraph) -> Set { .unwrap_or(Set::default()) } +fn positive_common_system_entities(graph: &PositiveSystemGraph) -> Set { + graph + .node_references() + .fold(None, |acc, node| match acc { + | None => Some(node.1.available_entities.elements()), + | Some(acc) => + Some(node.1.available_entities.elements().intersection(&acc)), + }) + .unwrap_or(Set::default()) +} + macro_rules! common_label { ( $name:ident, @@ -98,6 +113,86 @@ common_label!( .intersection(&acc) ); +macro_rules! common_positive_label { + ( + $name:ident, + [$edge_name:ident, $acc_name:ident], + $empty_expr:expr, + $some_expr:expr + ) => { + fn $name(graph: &PositiveSystemGraph) -> Set { + graph + .edge_references() + .fold(None, |$acc_name, $edge_name| { + let $edge_name = $edge_name.weight(); + match $acc_name { + | None => Some($empty_expr), + | Some($acc_name) => Some($some_expr), + } + }) + .unwrap_or(Set::default()) + } + }; +} + +common_positive_label!( + common_positive_label_products, + [edge, acc], + edge.products.elements(), + edge.products.elements().intersection(&acc) +); +common_positive_label!( + common_positive_label_entities, + [edge, acc], + edge.available_entities.elements(), + edge.available_entities.elements().intersection(&acc) +); +common_positive_label!( + common_positive_label_context, + [edge, acc], + edge.context.elements(), + edge.context.elements().intersection(&acc) +); +common_positive_label!( + common_positive_label_union, + [edge, acc], + edge.t.elements(), + edge.t.elements().intersection(&acc) +); +common_positive_label!( + common_positive_label_difference, + [edge, acc], + edge.context + .elements() + .subtraction(&edge.available_entities.elements()), + edge.context + .elements() + .subtraction(&edge.available_entities.elements()) + .intersection(&acc) +); +common_positive_label!( + common_positive_label_entities_deleted, + [edge, acc], + edge.available_entities + .elements() + .subtraction(&edge.products.elements()), + edge.available_entities + .elements() + .subtraction(&edge.products.elements()) + .intersection(&acc) +); +common_positive_label!( + common_positive_label_entities_added, + [edge, acc], + edge.products + .elements() + .subtraction(&edge.available_entities.elements()), + edge.products + .elements() + .subtraction(&edge.available_entities.elements()) + .intersection(&acc) +); + // Nodes ----------------------------------------------------------------------- /// Helper structure that specifies what information to display for nodes. @@ -121,30 +216,58 @@ pub struct NodeDisplay { type GraphMapNodesFnTy<'a> = dyn Fn(petgraph::prelude::NodeIndex, &'a System) -> String + 'a; -fn match_node_display<'a>( - base: &NodeDisplayBase, - common_entities: Rc, - translator: Rc, -) -> Box> { - use NodeDisplayBase::*; +type PositiveGraphMapNodesFnTy<'a> = + dyn Fn(petgraph::prelude::NodeIndex, &'a PositiveSystem) -> String + 'a; - use super::format_helpers::graph_map_nodes_ty_from::*; +impl NodeDisplayBase { + fn match_node_display<'a>( + &self, + common_entities: Rc, + translator: Rc, + ) -> Box> { + use super::format_helpers::graph_map_nodes_ty_from::*; - match base { - | String { string } => format_string(string.clone()), - | Hide => format_hide(translator), - | Entities => format_entities(translator), - | MaskEntities { mask } => - format_mask_entities(translator, mask.clone()), - | ExcludeEntities { mask } => - format_exclude_entities(translator, mask.clone()), - | Context => format_context(translator), - | UncommonEntities => - format_exclude_entities(translator, (*common_entities).clone()), - | MaskUncommonEntities { mask } => format_exclude_entities( - translator, - mask.intersection(&common_entities), - ), + match self { + | Self::String { string } => format_string(string.clone()), + | Self::Hide => format_hide(translator), + | Self::Entities => format_entities(translator), + | Self::MaskEntities { mask } => + format_mask_entities(translator, mask.clone()), + | Self::ExcludeEntities { mask } => + format_exclude_entities(translator, mask.clone()), + | Self::Context => format_context(translator), + | Self::UncommonEntities => + format_exclude_entities(translator, (*common_entities).clone()), + | Self::MaskUncommonEntities { mask } => format_exclude_entities( + translator, + mask.intersection(&common_entities), + ), + } + } + + fn positive_match_node_display<'a>( + &self, + common_entities: Rc, + translator: Rc, + ) -> Box> { + use super::format_helpers::positive_graph_map_nodes_ty_from::*; + + match self { + | Self::String { string } => format_string(string.clone()), + | Self::Hide => format_hide(translator), + | Self::Entities => format_entities(translator), + | Self::MaskEntities { mask } => + format_mask_entities(translator, mask.clone()), + | Self::ExcludeEntities { mask } => + format_exclude_entities(translator, mask.clone()), + | Self::Context => format_context(translator), + | Self::UncommonEntities => + format_exclude_entities(translator, (*common_entities).clone()), + | Self::MaskUncommonEntities { mask } => format_exclude_entities( + translator, + mask.intersection(&common_entities), + ), + } } } @@ -173,8 +296,32 @@ impl NodeDisplay { Box::new(move |i, n| { let mut accumulator = String::new(); for b in &self.base { - let f = match_node_display( - b, + let f = b.match_node_display( + Rc::clone(&common_entities), + Rc::clone(&translator), + ); + + accumulator.push_str(&(f)(i, n)); + } + accumulator + }) + } + + pub fn generate_positive<'a>( + self, + translator: Rc, + current_graph: &PositiveSystemGraph, + ) -> Box> { + let common_entities = if self.contains_uncommon() { + Rc::new(positive_common_system_entities(current_graph)) + } else { + Rc::new(Set::default()) + }; + + Box::new(move |i, n| { + let mut accumulator = String::new(); + for b in &self.base { + let f = b.positive_match_node_display( Rc::clone(&common_entities), Rc::clone(&translator), ); @@ -232,6 +379,9 @@ pub struct EdgeDisplay { type GraphMapEdgesFnTy<'a> = dyn Fn(petgraph::prelude::EdgeIndex, &'a Label) -> String + 'a; +type PositiveGraphMapEdgesFnTy<'a> = + dyn Fn(petgraph::prelude::EdgeIndex, &'a PositiveLabel) -> String + 'a; + #[derive(Default, Clone)] struct CommonEntities { common_products: Set, @@ -243,109 +393,215 @@ struct CommonEntities { common_entities_added: Set, } -fn match_edge_display<'a>( - base: &'a EdgeDisplayBase, - translator: Rc, - common: CommonEntities, -) -> Box> { - use EdgeDisplayBase::*; +impl EdgeDisplayBase { + fn match_edge_display<'a>( + &'a self, + translator: Rc, + common: CommonEntities, + ) -> Box> { + use super::format_helpers::graph_map_edges_ty_from::*; - use super::format_helpers::graph_map_edges_ty_from::*; + match self { + | Self::String { string } => + format_string(translator, string.clone()), + | Self::Hide => format_hide(translator), + | Self::Products { + mask, + filter_common, + } => + if *filter_common { + format_products( + translator, + mask.clone(), + Some(common.common_products), + ) + } else { + format_products(translator, mask.clone(), None) + }, + | Self::Entities { + mask, + filter_common, + } => + if *filter_common { + format_entities( + translator, + mask.clone(), + Some(common.common_entities), + ) + } else { + format_entities(translator, mask.clone(), None) + }, + | Self::Context { + mask, + filter_common, + } => + if *filter_common { + format_context( + translator, + mask.clone(), + Some(common.common_context), + ) + } else { + format_context(translator, mask.clone(), None) + }, + | Self::Union { + mask, + filter_common, + } => + if *filter_common { + format_union( + translator, + mask.clone(), + Some(common.common_union), + ) + } else { + format_union(translator, mask.clone(), None) + }, + | Self::Difference { + mask, + filter_common, + } => + if *filter_common { + format_difference( + translator, + mask.clone(), + Some(common.common_difference), + ) + } else { + format_difference(translator, mask.clone(), None) + }, + | Self::EntitiesDeleted { + mask, + filter_common, + } => + if *filter_common { + format_entities_deleted( + translator, + mask.clone(), + Some(common.common_entities_deleted), + ) + } else { + format_entities_deleted(translator, mask.clone(), None) + }, + | Self::EntitiesAdded { + mask, + filter_common, + } => + if *filter_common { + format_entities_added( + translator, + mask.clone(), + Some(common.common_entities_added), + ) + } else { + format_entities_added(translator, mask.clone(), None) + }, + } + } - match base { - | String { string } => format_string(translator, string.clone()), - | Hide => format_hide(translator), - | Products { - mask, - filter_common, - } => - if *filter_common { - format_products( - translator, - mask.clone(), - Some(common.common_products), - ) - } else { - format_products(translator, mask.clone(), None) - }, - | Entities { - mask, - filter_common, - } => - if *filter_common { - format_entities( - translator, - mask.clone(), - Some(common.common_entities), - ) - } else { - format_entities(translator, mask.clone(), None) - }, - | Context { - mask, - filter_common, - } => - if *filter_common { - format_context( - translator, - mask.clone(), - Some(common.common_context), - ) - } else { - format_context(translator, mask.clone(), None) - }, - | Union { - mask, - filter_common, - } => - if *filter_common { - format_union( - translator, - mask.clone(), - Some(common.common_union), - ) - } else { - format_union(translator, mask.clone(), None) - }, - | Difference { - mask, - filter_common, - } => - if *filter_common { - format_difference( - translator, - mask.clone(), - Some(common.common_difference), - ) - } else { - format_difference(translator, mask.clone(), None) - }, - | EntitiesDeleted { - mask, - filter_common, - } => - if *filter_common { - format_entities_deleted( - translator, - mask.clone(), - Some(common.common_entities_deleted), - ) - } else { - format_entities_deleted(translator, mask.clone(), None) - }, - | EntitiesAdded { - mask, - filter_common, - } => - if *filter_common { - format_entities_added( - translator, - mask.clone(), - Some(common.common_entities_added), - ) - } else { - format_entities_added(translator, mask.clone(), None) - }, + fn positive_match_edge_display<'a>( + &'a self, + translator: Rc, + common: CommonEntities, + ) -> Box> { + use super::format_helpers::positive_graph_map_edges_ty_from::*; + + match self { + | Self::String { string } => + format_string(translator, string.clone()), + | Self::Hide => format_hide(translator), + | Self::Products { + mask, + filter_common, + } => + if *filter_common { + format_products( + translator, + mask.clone(), + Some(common.common_products), + ) + } else { + format_products(translator, mask.clone(), None) + }, + | Self::Entities { + mask, + filter_common, + } => + if *filter_common { + format_entities( + translator, + mask.clone(), + Some(common.common_entities), + ) + } else { + format_entities(translator, mask.clone(), None) + }, + | Self::Context { + mask, + filter_common, + } => + if *filter_common { + format_context( + translator, + mask.clone(), + Some(common.common_context), + ) + } else { + format_context(translator, mask.clone(), None) + }, + | Self::Union { + mask, + filter_common, + } => + if *filter_common { + format_union( + translator, + mask.clone(), + Some(common.common_union), + ) + } else { + format_union(translator, mask.clone(), None) + }, + | Self::Difference { + mask, + filter_common, + } => + if *filter_common { + format_difference( + translator, + mask.clone(), + Some(common.common_difference), + ) + } else { + format_difference(translator, mask.clone(), None) + }, + | Self::EntitiesDeleted { + mask, + filter_common, + } => + if *filter_common { + format_entities_deleted( + translator, + mask.clone(), + Some(common.common_entities_deleted), + ) + } else { + format_entities_deleted(translator, mask.clone(), None) + }, + | Self::EntitiesAdded { + mask, + filter_common, + } => + if *filter_common { + format_entities_added( + translator, + mask.clone(), + Some(common.common_entities_added), + ) + } else { + format_entities_added(translator, mask.clone(), None) + }, + } } } @@ -458,8 +714,56 @@ impl EdgeDisplay { Box::new(move |i, n| { let mut accumulator = String::new(); for b in &self.base { - let f = match_edge_display( - b, + let f = b + .match_edge_display(Rc::clone(&translator), common.clone()); + accumulator.push_str(&(f)(i, n)); + } + accumulator + }) + } + + pub fn generate_positive<'a>( + self, + translator: Rc, + current_graph: &PositiveSystemGraph, + ) -> Box> { + // create the structure for common entities if required + let common = { + let mut tmp = CommonEntities::default(); + if self.common_products() { + tmp.common_products = + common_positive_label_products(current_graph); + } + if self.common_entities() { + tmp.common_entities = + common_positive_label_entities(current_graph); + } + if self.common_context() { + tmp.common_context = + common_positive_label_context(current_graph); + } + if self.common_union() { + tmp.common_union = common_positive_label_union(current_graph); + } + if self.common_difference() { + tmp.common_difference = + common_positive_label_difference(current_graph); + } + if self.common_entities_deleted() { + tmp.common_entities_deleted = + common_positive_label_entities_deleted(current_graph); + } + if self.common_entities_added() { + tmp.common_entities_added = + common_positive_label_entities_added(current_graph); + } + tmp + }; + + Box::new(move |i, n| { + let mut accumulator = String::new(); + for b in &self.base { + let f = b.positive_match_edge_display( Rc::clone(&translator), common.clone(), ); @@ -506,6 +810,19 @@ impl OperationType { | Self::SupersetEqual => b.is_subset(a), } } + + pub fn evaluate_positive(&self, a: &PositiveSet, b: &Set) -> bool { + match self { + | Self::Equals => + a.elements().is_subset(b) && b.is_subset(&a.elements()), + | Self::Subset => + a.elements().is_subset(b) && !b.is_subset(&a.elements()), + | Self::SubsetEqual => a.elements().is_subset(b), + | Self::Superset => + b.is_subset(&a.elements()) && !a.elements().is_subset(b), + | Self::SupersetEqual => b.is_subset(&a.elements()), + } + } } #[derive(Clone, Debug, Serialize, Deserialize, Hash)] @@ -535,57 +852,121 @@ fn node_formatter_base_color(base_color: String) -> String { ", fillcolor=".to_string() + &base_color } -#[inline(always)] -fn match_node_color_conditional<'a>( - rule: &'a NodeColorConditional, - color: &'a String, - original_graph: Rc, - star: Option, -) -> Box> { - use super::format_helpers::node_formatter::*; - match rule { - | NodeColorConditional::ContextConditional(ccc) => match ccc { - | ContextColorConditional::Nill => +impl NodeColorConditional { + fn match_node_color_conditional<'a>( + &self, + color: &'a String, + original_graph: Rc, + star: Option, + ) -> Box> { + use super::format_helpers::node_formatter::*; + match self { + | Self::ContextConditional(ContextColorConditional::Nill) => format_nill(Rc::clone(&original_graph), color.to_string(), star), - | ContextColorConditional::RecursiveIdentifier(s) => - format_recursive_identifier( - Rc::clone(&original_graph), - color.to_string(), - star, - *s, - ), - | ContextColorConditional::EntitySet(ot, set) => format_entity_set( + | Self::ContextConditional( + ContextColorConditional::RecursiveIdentifier(s), + ) => format_recursive_identifier( + Rc::clone(&original_graph), + color.to_string(), + star, + *s, + ), + | Self::ContextConditional(ContextColorConditional::EntitySet( + ot, + set, + )) => format_entity_set( Rc::clone(&original_graph), color.to_string(), star, *ot, set.clone(), ), - | ContextColorConditional::NonDeterministicChoice => - format_non_deterministic_choice( + | Self::ContextConditional( + ContextColorConditional::NonDeterministicChoice, + ) => format_non_deterministic_choice( + Rc::clone(&original_graph), + color.to_string(), + star, + ), + | Self::ContextConditional(ContextColorConditional::Summation) => + format_summation( Rc::clone(&original_graph), color.to_string(), star, ), - | ContextColorConditional::Summation => format_summation( + | Self::ContextConditional(ContextColorConditional::WaitEntity) => + format_wait_entity( + Rc::clone(&original_graph), + color.to_string(), + star, + ), + | Self::EntitiesConditional(ot, set) => + format_entities_conditional( + Rc::clone(&original_graph), + color.to_string(), + star, + *ot, + set.clone(), + ), + } + } + + fn match_positive_node_color_conditional<'a>( + &self, + color: &'a String, + original_graph: Rc, + star: Option, + ) -> Box> { + use super::format_helpers::positive_node_formatter::*; + match self { + | Self::ContextConditional(ContextColorConditional::Nill) => + format_nill(Rc::clone(&original_graph), color.to_string(), star), + | Self::ContextConditional( + ContextColorConditional::RecursiveIdentifier(s), + ) => format_recursive_identifier( Rc::clone(&original_graph), color.to_string(), star, + *s, ), - | ContextColorConditional::WaitEntity => format_wait_entity( - Rc::clone(&original_graph), - color.to_string(), - star, - ), - }, - | NodeColorConditional::EntitiesConditional(ot, set) => - format_entities_conditional( + | Self::ContextConditional(ContextColorConditional::EntitySet( + ot, + set, + )) => format_entity_set( Rc::clone(&original_graph), color.to_string(), star, *ot, set.clone(), ), + | Self::ContextConditional( + ContextColorConditional::NonDeterministicChoice, + ) => format_non_deterministic_choice( + Rc::clone(&original_graph), + color.to_string(), + star, + ), + | Self::ContextConditional(ContextColorConditional::Summation) => + format_summation( + Rc::clone(&original_graph), + color.to_string(), + star, + ), + | Self::ContextConditional(ContextColorConditional::WaitEntity) => + format_wait_entity( + Rc::clone(&original_graph), + color.to_string(), + star, + ), + | Self::EntitiesConditional(ot, set) => + format_entities_conditional( + Rc::clone(&original_graph), + color.to_string(), + star, + *ot, + set.clone(), + ), + } } } @@ -597,8 +978,28 @@ impl NodeColor { ) -> Box> { Box::new(move |i, n| { for (rule, color) in &self.conditionals { - let f = match_node_color_conditional( - rule, + let f = rule.match_node_color_conditional( + color, + Rc::clone(&original_graph), + star, + ); + + if let Some(s) = (f)(i, n) { + return s; + } + } + node_formatter_base_color(self.base_color.clone()) + }) + } + + pub fn generate_positive<'a>( + self, + original_graph: Rc, + star: Option, + ) -> Box> { + Box::new(move |i, n| { + for (rule, color) in &self.conditionals { + let f = rule.match_positive_node_color_conditional( color, Rc::clone(&original_graph), star, @@ -648,63 +1049,122 @@ fn edge_formatter_base_color(base_color: String) -> String { ", color=".to_string() + &base_color } -fn match_edge_color_conditional<'a>( - rule: &'a EdgeColorConditional, - color: &'a String, - original_graph: Rc, -) -> Box> { - use super::format_helpers::edge_formatter::*; - match rule { - | EdgeColorConditional::Entities(ot, set) => format_entities( - Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone(), - ), - | EdgeColorConditional::Context(ot, set) => format_context( - Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone(), - ), - | EdgeColorConditional::T(ot, set) => format_t( - Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone(), - ), - | EdgeColorConditional::Reactants(ot, set) => format_reactants( - Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone(), - ), - | EdgeColorConditional::ReactantsAbsent(ot, set) => - format_reactants_absent( +impl EdgeColorConditional { + fn match_edge_color_conditional<'a>( + &'a self, + color: &'a String, + original_graph: Rc, + ) -> Box> { + use super::format_helpers::edge_formatter::*; + match self { + | Self::Entities(ot, set) => format_entities( Rc::clone(&original_graph), color.to_string(), *ot, set.clone(), ), - | EdgeColorConditional::Inhibitors(ot, set) => format_inhibitors( - Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone(), - ), - | EdgeColorConditional::InhibitorsPresent(ot, set) => - format_inhibitors_present( + | Self::Context(ot, set) => format_context( Rc::clone(&original_graph), color.to_string(), *ot, set.clone(), ), - | EdgeColorConditional::Products(ot, set) => format_products( - Rc::clone(&original_graph), - color.to_string(), - *ot, - set.clone(), - ), + | Self::T(ot, set) => format_t( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Reactants(ot, set) => format_reactants( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::ReactantsAbsent(ot, set) => format_reactants_absent( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Inhibitors(ot, set) => format_inhibitors( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::InhibitorsPresent(ot, set) => format_inhibitors_present( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Products(ot, set) => format_products( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + } + } + + fn match_positive_edge_color_conditional<'a>( + &'a self, + color: &'a String, + original_graph: Rc, + ) -> Box> { + use super::format_helpers::positive_edge_formatter::*; + + match self { + | Self::Entities(ot, set) => format_entities( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Context(ot, set) => format_context( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::T(ot, set) => format_t( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Reactants(ot, set) => format_reactants( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::ReactantsAbsent(ot, set) => format_reactants_absent( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Inhibitors(ot, set) => format_inhibitors( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::InhibitorsPresent(ot, set) => format_inhibitors_present( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + | Self::Products(ot, set) => format_products( + Rc::clone(&original_graph), + color.to_string(), + *ot, + set.clone(), + ), + } } } @@ -715,8 +1175,26 @@ impl EdgeColor { ) -> Box> { Box::new(move |i, n| { for (rule, color) in &self.conditionals { - let f = match_edge_color_conditional( - rule, + let f = rule.match_edge_color_conditional( + color, + Rc::clone(&original_graph), + ); + + if let Some(s) = (f)(i, n) { + return s; + } + } + edge_formatter_base_color(self.base_color.clone()) + }) + } + + pub fn generate_positive<'a>( + self, + original_graph: Rc, + ) -> Box> { + Box::new(move |i, n| { + for (rule, color) in &self.conditionals { + let f = rule.match_positive_edge_color_conditional( color, Rc::clone(&original_graph), ); diff --git a/rsprocess/src/set.rs b/rsprocess/src/set.rs index abbd72f..8da86d8 100644 --- a/rsprocess/src/set.rs +++ b/rsprocess/src/set.rs @@ -704,4 +704,8 @@ impl PositiveSet { .collect::() .union(self) } + + pub fn elements(&self) -> Set { + self.iter().map(|el| *el.0).collect::>().into() + } }