Edge color working

This commit is contained in:
elvis
2025-07-13 19:08:39 +02:00
parent 6fd606d75d
commit 75028fbf38
8 changed files with 232 additions and 51 deletions

View File

@ -440,7 +440,7 @@ NodeColorConditional: (graph::NodeColorConditional, String) = {
ColorNode: graph::NodeColor = { ColorNode: graph::NodeColor = {
<conditionals: Separated_Or<NodeColorConditional, "||">> <conditionals: Separated_Or<NodeColorConditional, "||">>
"!" <base_color: PATH> => "!" <base_color: PATH> =>
graph::NodeColor { conditionals: conditionals, graph::NodeColor { conditionals,
base_color: base_color.to_string() }, base_color: base_color.to_string() },
"!" <base_color: PATH> => "!" <base_color: PATH> =>
@ -448,15 +448,53 @@ ColorNode: graph::NodeColor = {
base_color: base_color.to_string() }, base_color: base_color.to_string() },
} }
EdgeColorConditional: (graph::EdgeColorConditional, String) = {
"Entities" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::Entities(op, set),
color.to_string()),
"Context" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::Context(op, set),
color.to_string()),
"T" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::T(op, set),
color.to_string()),
"Reactants" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::Reactants(op, set),
color.to_string()),
"AbsentReactants" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::ReactantsAbsent(op, set),
color.to_string()),
"Inhibitors" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::Inhibitors(op, set),
color.to_string()),
"PresentInhibitors" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::InhibitorsPresent(op, set),
color.to_string()),
"Products" <op: Operation> <set: Set> "?" <color: PATH> =>
(graph::EdgeColorConditional::Products(op, set),
color.to_string()),
}
ColorEdge: graph::EdgeColor = {
<conditionals: Separated_Or<EdgeColorConditional, "||">>
"!" <base_color: PATH> =>
graph::EdgeColor { conditionals,
base_color: base_color.to_string() },
"!" <base_color: PATH> =>
graph::EdgeColor { conditionals: vec![],
base_color: base_color.to_string() },
}
GraphSaveOptions: presets::GraphSaveOptions = { GraphSaveOptions: presets::GraphSaveOptions = {
"Dot" <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> "|" "Dot" <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> "|"
<c_node: ColorNode> ">" <c_node: ColorNode> "|" <c_edge: ColorEdge> ">"
<so: SaveOptions> => <so: SaveOptions> =>
presets::GraphSaveOptions::Dot { node_display: s_node, presets::GraphSaveOptions::Dot { node_display: s_node,
edge_display: s_edge, edge_display: s_edge,
node_color: c_node, node_color: c_node,
edge_color: c_edge,
so }, so },
"GraphML" <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> ">" "GraphML" <s_node: SeparatorNode> "|" <s_edge: SeparatorEdge> ">"
<so: SaveOptions> => <so: SaveOptions> =>

View File

@ -373,12 +373,6 @@ type RSformatNodeTy =
<&RSdotGraph as IntoNodeReferences>::NodeRef <&RSdotGraph as IntoNodeReferences>::NodeRef
) -> Option<String>; ) -> Option<String>;
type RSformatEdgeTy =
dyn Fn(
&RSdotGraph,
<&RSdotGraph as IntoEdgeReferences>::EdgeRef
) -> String;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum OperationType { pub enum OperationType {
Equals, Equals,
@ -420,7 +414,6 @@ pub enum ContextColorConditional {
WaitEntity WaitEntity
} }
#[derive(Clone)] #[derive(Clone)]
pub enum NodeColorConditional { pub enum NodeColorConditional {
ContextConditional(ContextColorConditional), ContextConditional(ContextColorConditional),
@ -544,16 +537,140 @@ pub fn node_formatter(
} }
} }
type RSformatEdgeTy =
dyn Fn(
&RSdotGraph,
<&RSdotGraph as IntoEdgeReferences>::EdgeRef
) -> Option<String>;
#[derive(Clone)]
pub enum EdgeColorConditional {
Entities(OperationType, RSset),
Context(OperationType, RSset),
T(OperationType, RSset),
Reactants(OperationType, RSset),
ReactantsAbsent(OperationType, RSset),
Inhibitors(OperationType, RSset),
InhibitorsPresent(OperationType, RSset),
Products(OperationType, RSset),
}
#[derive(Clone)]
pub struct EdgeColor {
pub conditionals: Vec<(EdgeColorConditional, String)>,
pub base_color: String
}
pub fn edge_formatter_base_color(
base_color: String
) -> String
{
", fillcolor=".to_string() + &base_color
}
pub fn edge_formatter( pub fn edge_formatter(
original_graph: Rc<RSgraph> original_graph: Rc<RSgraph>,
rule: EdgeColorConditional,
color: String,
) -> Box<RSformatEdgeTy> ) -> Box<RSformatEdgeTy>
{ {
Box::new( match rule {
move |_g, e| String::from( EdgeColorConditional::Entities(ot, set) => {
if original_graph.edge_weight(e.id()).unwrap().products.is_empty() { Box::new(
"color=black, fontcolor=black" move |_, e| {
} else { let rssystem = original_graph.edge_weight(e.id()).unwrap();
"color=blue, fontcolor=blue" if ot.evaluate(&rssystem.available_entities, &set) {
} Some(", fillcolor=".to_string() + &color)
)) } else {
None
}
}
)
},
EdgeColorConditional::Context(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.context, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
EdgeColorConditional::T(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.t, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
EdgeColorConditional::Reactants(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.reactants, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
EdgeColorConditional::ReactantsAbsent(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.reactants_absent, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
EdgeColorConditional::Inhibitors(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.inhibitors, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
EdgeColorConditional::InhibitorsPresent(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.inhibitors_present, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
EdgeColorConditional::Products(ot, set) => {
Box::new(
move |_, e| {
let rssystem = original_graph.edge_weight(e.id()).unwrap();
if ot.evaluate(&rssystem.products, &set) {
Some(", fillcolor=".to_string() + &color)
} else {
None
}
}
)
},
}
} }

View File

@ -76,6 +76,7 @@ pub enum GraphSaveOptions {
node_display: Vec<NodeDisplay>, node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay>, edge_display: Vec<EdgeDisplay>,
node_color: graph::NodeColor, node_color: graph::NodeColor,
edge_color: graph::EdgeColor,
so: SaveOptions, so: SaveOptions,
}, },
GraphML { GraphML {
@ -205,7 +206,7 @@ where
let mut it = expected.iter().peekable(); let mut it = expected.iter().peekable();
while let Some(s) = it.next() { while let Some(s) = it.next() {
err.push('('); err.push('(');
err.push_str(&s); err.push_str(s);
err.push(')'); err.push(')');
if it.peek().is_some() { if it.peek().is_some() {
err.push(','); err.push(',');
@ -575,12 +576,36 @@ fn generate_node_color_fn<'a>(
) )
} }
use petgraph::visit::IntoEdgeReferences;
#[allow(clippy::type_complexity)]
fn generate_edge_color_fn<'a>(
edge_color: &'a graph::EdgeColor,
original_graph: Rc<Graph<RSsystem, RSlabel>>,
) -> Box<dyn Fn(&Graph<String, String>, <&Graph<String, String, petgraph::Directed, u32> as IntoEdgeReferences>::EdgeRef) -> String + 'a> {
Box::new(
move |i, n| {
let cloned_edge_color = edge_color.clone();
for (rule, color) in cloned_edge_color.conditionals {
if let Some(s) = graph::edge_formatter(
original_graph.clone(),
rule,
color
)(i, n) {
return s
}
}
graph::edge_formatter_base_color(edge_color.base_color.to_string())
}
)
}
/// Writes the specified graph to a file in .dot format. /// Writes the specified graph to a file in .dot format.
pub fn dot( pub fn dot(
system: &EvaluatedSystem, system: &EvaluatedSystem,
node_display: Vec<NodeDisplay>, node_display: Vec<NodeDisplay>,
edge_display: Vec<EdgeDisplay>, edge_display: Vec<EdgeDisplay>,
node_color: &graph::NodeColor node_color: &graph::NodeColor,
edge_color: &graph::EdgeColor
) -> Result<String, String> { ) -> Result<String, String> {
match system { match system {
EvaluatedSystem::System { EvaluatedSystem::System {
@ -601,15 +626,15 @@ pub fn dot(
let graph = Rc::new(graph.to_owned()); let graph = Rc::new(graph.to_owned());
// let edge_formatter =
// graph::default_edge_formatter(Rc::clone(&graph));
let node_formatter = let node_formatter =
generate_node_color_fn(node_color, graph, rc_translator); generate_node_color_fn(node_color, Rc::clone(&graph), rc_translator);
let edge_formatter =
generate_edge_color_fn(edge_color, graph);
let dot = rsdot::RSDot::with_attr_getters( let dot = rsdot::RSDot::with_attr_getters(
&modified_graph, &modified_graph,
&[], &[],
&|_, _| String::new(), // &edge_formatter, &edge_formatter,
&node_formatter, &node_formatter,
); );
@ -759,9 +784,10 @@ fn execute(
node_display: nd, node_display: nd,
edge_display: ed, edge_display: ed,
node_color: nc, node_color: nc,
edge_color: ec,
so, so,
} => { } => {
save_options!(dot(system, nd, ed, &nc)?, so); save_options!(dot(system, nd, ed, &nc, &ec)?, so);
} }
GraphSaveOptions::GraphML { GraphSaveOptions::GraphML {
node_display: nd, node_display: nd,

View File

@ -35,7 +35,7 @@ pub fn of_RSsystem<'a>(translator: &'a Translator, system: &'a RSsystem) -> Stri
let inhibitors = system let inhibitors = system
.reaction_rules .reaction_rules
.iter() .iter()
.fold(RSset::new(), |acc, new| acc.union(&new.inihibitors)); .fold(RSset::new(), |acc, new| acc.union(&new.inhibitors));
result.push_str(&format!( result.push_str(&format!(
"The inhibitors are {}:\n{}\n", "The inhibitors are {}:\n{}\n",
inhibitors.len(), inhibitors.len(),

View File

@ -135,7 +135,7 @@ impl IntoIterator for RSset {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RSreaction { pub struct RSreaction {
pub reactants: RSset, pub reactants: RSset,
pub inihibitors: RSset, pub inhibitors: RSset,
pub products: RSset, pub products: RSset,
} }
@ -143,15 +143,15 @@ impl RSreaction {
pub fn new() -> Self { pub fn new() -> Self {
RSreaction { RSreaction {
reactants: RSset::new(), reactants: RSset::new(),
inihibitors: RSset::new(), inhibitors: RSset::new(),
products: RSset::new(), products: RSset::new(),
} }
} }
pub fn from(reactants: RSset, inihibitors: RSset, products: RSset) -> Self { pub fn from(reactants: RSset, inhibitors: RSset, products: RSset) -> Self {
RSreaction { RSreaction {
reactants, reactants,
inihibitors, inhibitors,
products, products,
} }
} }
@ -160,7 +160,7 @@ impl RSreaction {
/// see enable /// see enable
pub fn enabled(&self, current_state: &RSset) -> bool { pub fn enabled(&self, current_state: &RSset) -> bool {
self.reactants.is_subset(current_state) self.reactants.is_subset(current_state)
&& self.inihibitors.is_disjoint(current_state) && self.inhibitors.is_disjoint(current_state)
} }
} }
@ -498,8 +498,8 @@ pub struct RSlabel {
pub t: RSset, pub t: RSset,
pub reactants: RSset, pub reactants: RSset,
pub reactants_absent: RSset, pub reactants_absent: RSset,
pub inihibitors: RSset, pub inhibitors: RSset,
pub inihibitors_present: RSset, pub inhibitors_present: RSset,
pub products: RSset, pub products: RSset,
} }
@ -511,8 +511,8 @@ impl RSlabel {
t: RSset::new(), t: RSset::new(),
reactants: RSset::new(), reactants: RSset::new(),
reactants_absent: RSset::new(), reactants_absent: RSset::new(),
inihibitors: RSset::new(), inhibitors: RSset::new(),
inihibitors_present: RSset::new(), inhibitors_present: RSset::new(),
products: RSset::new(), products: RSset::new(),
} }
} }
@ -524,8 +524,8 @@ impl RSlabel {
t: RSset, t: RSset,
reactants: RSset, reactants: RSset,
reactants_absent: RSset, reactants_absent: RSset,
inihibitors: RSset, inhibitors: RSset,
inihibitors_present: RSset, inhibitors_present: RSset,
products: RSset, products: RSset,
) -> Self { ) -> Self {
RSlabel { RSlabel {
@ -534,8 +534,8 @@ impl RSlabel {
t, t,
reactants, reactants,
reactants_absent, reactants_absent,
inihibitors, inhibitors,
inihibitors_present, inhibitors_present,
products, products,
} }
} }

View File

@ -34,16 +34,16 @@ impl<'a> Iterator for TransitionsIterator<'a> {
let ( let (
reactants, reactants,
reactants_absent, reactants_absent,
inihibitors, inhibitors,
inihibitors_present, inhibitors_present,
products products
) = ) =
self.system.reaction_rules.iter().fold( self.system.reaction_rules.iter().fold(
( (
RSset::new(), // reactants RSset::new(), // reactants
RSset::new(), // reactants_absent RSset::new(), // reactants_absent
RSset::new(), // inihibitors RSset::new(), // inhibitors
RSset::new(), // inihibitors_present RSset::new(), // inhibitors_present
RSset::new(), // products RSset::new(), // products
), ),
|acc, reaction| { |acc, reaction| {
@ -51,14 +51,14 @@ impl<'a> Iterator for TransitionsIterator<'a> {
( (
acc.0.union(&reaction.reactants), acc.0.union(&reaction.reactants),
acc.1, acc.1,
acc.2.union(&reaction.inihibitors), acc.2.union(&reaction.inhibitors),
acc.3, acc.3,
acc.4.union(&reaction.products), acc.4.union(&reaction.products),
) )
} else { } else {
( (
acc.0, acc.0,
acc.1.union(&reaction.inihibitors.intersection(&t)), acc.1.union(&reaction.inhibitors.intersection(&t)),
acc.2, acc.2,
acc.3.union(&reaction.reactants.subtraction(&t)), acc.3.union(&reaction.reactants.subtraction(&t)),
acc.4, acc.4,
@ -73,8 +73,8 @@ impl<'a> Iterator for TransitionsIterator<'a> {
t, t,
reactants, reactants,
reactants_absent, reactants_absent,
inihibitors, inhibitors,
inihibitors_present, inhibitors_present,
products.clone(), products.clone(),
); );
let new_system = RSsystem::from( let new_system = RSsystem::from(

View File

@ -133,7 +133,7 @@ fn print_reaction(
f, f,
"(r: {}, i: {}, p: {})", "(r: {}, i: {}, p: {})",
RSsetDisplay::from(translator, &reaction.reactants), RSsetDisplay::from(translator, &reaction.reactants),
RSsetDisplay::from(translator, &reaction.inihibitors), RSsetDisplay::from(translator, &reaction.inhibitors),
RSsetDisplay::from(translator, &reaction.products) RSsetDisplay::from(translator, &reaction.products)
) )
} }
@ -339,8 +339,8 @@ fn print_label(
RSsetDisplay::from(translator, &label.t), RSsetDisplay::from(translator, &label.t),
RSsetDisplay::from(translator, &label.reactants), RSsetDisplay::from(translator, &label.reactants),
RSsetDisplay::from(translator, &label.reactants_absent), RSsetDisplay::from(translator, &label.reactants_absent),
RSsetDisplay::from(translator, &label.inihibitors), RSsetDisplay::from(translator, &label.inhibitors),
RSsetDisplay::from(translator, &label.inihibitors_present), RSsetDisplay::from(translator, &label.inhibitors_present),
RSsetDisplay::from(translator, &label.products), RSsetDisplay::from(translator, &label.products),
) )
} }

View File

@ -4,4 +4,4 @@ Context: [({a,b}.{a}.{a,c}.x + {a,b}.{a}.{a}.nill)]
Reactions: ([{a,b}, {c}, {b}]) Reactions: ([{a,b}, {c}, {b}])
Digraph > Dot Context | Hide | Context.EntitySet ⊆ {a, c} ? "HERE" || Context.NonDeterministicChoice ? "ASDASDSAD" ! "#123" > Print Digraph > Dot Context | Hide | Context.EntitySet ⊆ {a, c} ? "HERE" || Context.NonDeterministicChoice ? "ASDASDSAD" ! "#123" | ! "#987" > Print