From 92627cf12eec16a52855b0459a405b55f242bf46 Mon Sep 17 00:00:00 2001 From: elvis Date: Sun, 26 Oct 2025 18:55:35 +0100 Subject: [PATCH] Instructions for positive systems --- reaction_systems_gui/src/app.rs | 219 ++++++++++++++++++++----- reaction_systems_gui/src/app_logic.rs | 223 +++++++++++++++++++++++++- 2 files changed, 404 insertions(+), 38 deletions(-) diff --git a/reaction_systems_gui/src/app.rs b/reaction_systems_gui/src/app.rs index 82f10e9..276ecf7 100644 --- a/reaction_systems_gui/src/app.rs +++ b/reaction_systems_gui/src/app.rs @@ -58,6 +58,7 @@ pub enum BasicDataType { PositiveEnvironment, PositiveContext, PositiveReactions, + PositiveGraph, } /// Should reflect `BasicDataType`'s values, holding the data that will be @@ -96,8 +97,8 @@ pub enum BasicValue { value: (Vec, Vec), }, Graph { - value: - petgraph::Graph, + value: petgraph::Graph, }, GroupingFunction { value: assert::relabel::Assert, @@ -155,6 +156,10 @@ pub enum BasicValue { PositiveReactions { value: Vec, }, + PositiveGraph { + value: petgraph::Graph, + }, } impl Hash for BasicValue { @@ -229,28 +234,39 @@ impl Default for BasicValue { derive(serde::Serialize, serde::Deserialize) )] pub enum NodeInstruction { + // basic instructions String, Path, ReadPath, + SaveString, + + // create basic data types Symbol, + Set, + Environment, + Context, + Reactions, + PositiveSet, + PositiveEnvironment, + PositiveContext, + PositiveReactions, Experiment, GroupFunction, - SaveString, DisplayNode, DisplayEdge, ColorNode, ColorEdge, - Environment, - Set, - Context, - Reactions, - PositiveSet, + + // convert basic data types ToPositiveSet, + ToPositiveContext, + ToPositiveEnvironment, + ToPositiveReactions, // system instructions + System, ComposeSystem, DecomposeSystem, - System, Statistics, Target, Run, @@ -258,14 +274,8 @@ pub enum NodeInstruction { Frequency, LimitFrequency, FastFrequency, - SystemGraph, - - // graph instructions - BisimilarityKanellakisSmolka, - BisimilarityPaigeTarjanNoLabels, - BisimilarityPaigeTarjan, - Dot, - GraphML, + OverwriteContextEntities, + OverwriteReactionEntities, // positive system instructions PositiveSystem, @@ -275,16 +285,35 @@ pub enum NodeInstruction { PositiveFrequency, PositiveLimitFrequency, PositiveFastFrequency, - ComposePositiveSystem, - DecomposePositiveSystem, - // PositiveGraph, + PositiveComposeSystem, + PositiveDecomposeSystem, + PositiveOverwriteContextEntities, + PositiveOverwriteReactionEntities, + + // system graph instructions + SystemGraph, + BisimilarityKanellakisSmolka, + BisimilarityPaigeTarjanNoLabels, + BisimilarityPaigeTarjan, + Dot, + GraphML, + + // positive system graph instructions + PositiveGraph, + // PositiveBisimilarityKanellakisSmolka, + // PositiveBisimilarityPaigeTarjanNoLabels, + // PositiveBisimilarityPaigeTarjan, + PositiveDot, + PositiveGraphML, // trace instructions Trace, - PositiveTrace, SliceTrace, - PositiveSliceTrace, TraceToString, + + // positive trace instructions + PositiveTrace, + PositiveSliceTrace, PositiveTraceToString, } @@ -372,15 +401,29 @@ impl NodeInstruction { | Self::PositiveSet => vec![("string", String)], | Self::ToPositiveSet => vec![("value", Set)], | Self::DecomposeSystem => vec![("system", System)], - | Self::ComposePositiveSystem => vec![ + | Self::PositiveComposeSystem => vec![ ("environment", PositiveEnvironment), ("initial entities", PositiveSet), ("context", PositiveContext), ("reactions", PositiveReactions), ], - | Self::DecomposePositiveSystem => vec![("system", PositiveSystem)], + | Self::PositiveDecomposeSystem => vec![("system", PositiveSystem)], | Self::TraceToString => vec![("trace", Trace)], | Self::PositiveTraceToString => vec![("trace", PositiveTrace)], + | Self::PositiveEnvironment => vec![("value", String)], + | Self::PositiveContext => vec![("value", String)], + | Self::PositiveReactions => vec![("value", String)], + | Self::ToPositiveContext => vec![("value", Context)], + | Self::ToPositiveEnvironment => vec![("value", Environment)], + | Self::ToPositiveReactions => vec![("value", Reactions)], + | Self::OverwriteContextEntities => vec![("system", System), ("elements", Set)], + | Self::OverwriteReactionEntities => vec![("system", System), ("elements", Set)], + | Self::PositiveOverwriteContextEntities => vec![("system", PositiveSystem), ("elements", PositiveSet)], + | Self::PositiveOverwriteReactionEntities => vec![("system", PositiveSystem), ("elements", PositiveSet)], + | Self::PositiveGraph => vec![("sys", PositiveSystem)], + | Self::PositiveDot => vec![("graph", PositiveGraph)], + | Self::PositiveGraphML => vec![("graph", PositiveGraph)], + } .into_iter() .map(|e| (e.0.to_string(), e.1)) @@ -433,14 +476,14 @@ impl NodeInstruction { | Self::PositiveSliceTrace => vec![("out", PositiveTrace)], | Self::PositiveSet => vec![("out", PositiveSet)], | Self::ToPositiveSet => vec![("out", PositiveSet)], - | Self::ComposePositiveSystem => vec![("out", PositiveSystem)], + | Self::PositiveComposeSystem => vec![("out", PositiveSystem)], | Self::DecomposeSystem => vec![ ("environment", Environment), ("initial entities", Set), ("context", Context), ("reactions", Reactions), ], - | Self::DecomposePositiveSystem => vec![ + | Self::PositiveDecomposeSystem => vec![ ("environment", PositiveEnvironment), ("initial entities", PositiveSet), ("context", PositiveContext), @@ -448,6 +491,19 @@ impl NodeInstruction { ], | Self::TraceToString => vec![("out", String)], | Self::PositiveTraceToString => vec![("out", String)], + | Self::PositiveEnvironment => vec![("out", PositiveEnvironment)], + | Self::PositiveContext => vec![("out", PositiveContext)], + | Self::PositiveReactions => vec![("out", PositiveReactions)], + | Self::ToPositiveContext => vec![("out", PositiveContext)], + | Self::ToPositiveEnvironment => vec![("out", PositiveEnvironment)], + | Self::ToPositiveReactions => vec![("out", PositiveReactions)], + | Self::OverwriteContextEntities => vec![("out", System)], + | Self::OverwriteReactionEntities => vec![("out", System)], + | Self::PositiveOverwriteContextEntities => vec![("out", PositiveSystem)], + | Self::PositiveOverwriteReactionEntities => vec![("out", PositiveSystem)], + | Self::PositiveGraph => vec![("out", PositiveGraph)], + | Self::PositiveDot => vec![("out", String)], + | Self::PositiveGraphML => vec![("out", String)], }; res.into_iter().map(|res| (res.0.to_string(), res.1)).collect::<_>() } @@ -533,6 +589,8 @@ impl NodeInstruction { helper!(PositiveContext, rsprocess::process::PositiveProcess::default()), | BasicDataType::PositiveReactions => helper!(PositiveReactions, vec![]), + | BasicDataType::PositiveGraph => + helper!(PositiveGraph, petgraph::Graph::new()) } } @@ -581,6 +639,7 @@ impl NodeInstruction { | BasicDataType::PositiveEnvironment => helper!(PositiveEnvironment), | BasicDataType::PositiveContext => helper!(PositiveContext), | BasicDataType::PositiveReactions => helper!(PositiveReactions), + | BasicDataType::PositiveGraph => helper!(PositiveGraph), } } } @@ -768,6 +827,7 @@ impl DataTypeTrait for BasicDataType { | Self::PositiveEnvironment => egui::Color32::from_rgb(10, 20, 50), | Self::PositiveContext => egui::Color32::from_rgb(20, 10, 50), | Self::PositiveReactions => egui::Color32::from_rgb(50, 10, 20), + | Self::PositiveGraph => egui::Color32::from_rgb(100, 130, 90), } } @@ -798,6 +858,7 @@ impl DataTypeTrait for BasicDataType { | Self::PositiveEnvironment => Cow::Borrowed("positive environment"), | Self::PositiveContext => Cow::Borrowed("positive context"), | Self::PositiveReactions => Cow::Borrowed("positive reactions"), + | Self::PositiveGraph => Cow::Borrowed("positive graph"), } } } @@ -860,11 +921,24 @@ impl NodeTemplateTrait for NodeInstruction { | Self::PositiveSliceTrace => "Positive Slice Trace", | Self::PositiveSet => "Positive Set", | Self::ToPositiveSet => "Convert to Positive Set", - | Self::ComposePositiveSystem => "Compose a positive system", + | Self::PositiveComposeSystem => "Compose a positive system", | Self::DecomposeSystem => "Decompose a system", - | Self::DecomposePositiveSystem => "Decompose a positive system", + | Self::PositiveDecomposeSystem => "Decompose a positive system", | Self::TraceToString => "Trace to string", | Self::PositiveTraceToString => "Positive trace to string", + | Self::PositiveEnvironment => "Positive Environment", + | Self::PositiveContext => "Positive Context", + | Self::PositiveReactions => "Positive Reactions", + | Self::ToPositiveContext => "Convert to Positive Context", + | Self::ToPositiveEnvironment => "Convert to Positive Environment", + | Self::ToPositiveReactions => "Convert to Positive Reactions", + | Self::OverwriteContextEntities => "Overwrite context entities", + | Self::OverwriteReactionEntities => "Overwirite reaction entities", + | Self::PositiveOverwriteContextEntities => "Overwrite context entities of Positive System", + | Self::PositiveOverwriteReactionEntities => "Overwrite reaction entities of Positive System", + | Self::PositiveGraph => "Graph of a Positive System", + | Self::PositiveDot => "Create Dot file of Positive System", + | Self::PositiveGraphML => "Create GraphML file of Positive System", }) } @@ -889,7 +963,9 @@ impl NodeTemplateTrait for NodeInstruction { | Self::Set | Self::Context | Self::Reactions - | Self::DecomposeSystem => vec!["System"], + | Self::DecomposeSystem + | Self::OverwriteContextEntities + | Self::OverwriteReactionEntities => vec!["System"], | Self::Frequency | Self::LimitFrequency | Self::Experiment @@ -914,8 +990,19 @@ impl NodeTemplateTrait for NodeInstruction { | Self::PositiveFastFrequency | Self::PositiveSet | Self::ToPositiveSet - | Self::ComposePositiveSystem - | Self::DecomposePositiveSystem => vec!["Positive System"], + | Self::PositiveComposeSystem + | Self::PositiveDecomposeSystem + | Self::PositiveEnvironment + | Self::PositiveContext + | Self::PositiveReactions + | Self::ToPositiveContext + | Self::ToPositiveEnvironment + | Self::ToPositiveReactions + | Self::PositiveOverwriteContextEntities + | Self::PositiveOverwriteReactionEntities + | Self::PositiveGraph + | Self::PositiveDot + | Self::PositiveGraphML => vec!["Positive System"], | Self::Trace => vec!["Trace", "System"], | Self::PositiveTrace => vec!["Trace", "Positive System"], | Self::SliceTrace @@ -1000,11 +1087,24 @@ impl NodeTemplateIter for AllInstructions { NodeInstruction::PositiveSliceTrace, NodeInstruction::PositiveSet, NodeInstruction::ToPositiveSet, - NodeInstruction::ComposePositiveSystem, + NodeInstruction::PositiveComposeSystem, NodeInstruction::DecomposeSystem, - NodeInstruction::DecomposePositiveSystem, + NodeInstruction::PositiveDecomposeSystem, NodeInstruction::TraceToString, NodeInstruction::PositiveTraceToString, + NodeInstruction::PositiveEnvironment, + NodeInstruction::PositiveContext, + NodeInstruction::PositiveReactions, + NodeInstruction::ToPositiveContext, + NodeInstruction::ToPositiveEnvironment, + NodeInstruction::ToPositiveReactions, + NodeInstruction::OverwriteContextEntities, + NodeInstruction::OverwriteReactionEntities, + NodeInstruction::PositiveOverwriteContextEntities, + NodeInstruction::PositiveOverwriteReactionEntities, + NodeInstruction::PositiveGraph, + NodeInstruction::PositiveDot, + NodeInstruction::PositiveGraphML, ] } } @@ -1129,6 +1229,9 @@ impl WidgetValueTrait for BasicValue { | BasicValue::PositiveReactions { value: _ } => { ui.label(param_name); }, + | BasicValue::PositiveGraph { value: _ } => { + ui.label(param_name); + } } responses @@ -1161,15 +1264,50 @@ impl NodeDataTrait for NodeData { .unwrap_or(false); match (is_active, graph[node_id].user_data.template) { + | (_, ni) if ni.output().len() > 1 => { + // no buttons for nodes with more than one output + } | (_, NodeInstruction::SaveString) => { + // no need to see the output, just write to file if ui.button("Write").clicked() { responses.push(NodeResponse::User( CustomResponse::SaveToFile(node_id), )); } }, - | (_, ni) if ni.output().len() > 1 => { - // no button for nodes with more than one output + | (true, NodeInstruction::ReadPath) => { + // since no filewatcher we simply give the option to reload the + // file + let button = egui::Button::new( + egui::RichText::new("👁 Active").color(egui::Color32::BLACK), + ).fill(egui::Color32::GOLD); + if ui.add(button).clicked() { + responses.push(NodeResponse::User( + CustomResponse::ClearActiveNode, + )); + } + + let button = egui::Button::new(egui::RichText::new("Update file")); + if ui.add(button).clicked() { + responses.push(NodeResponse::User( + CustomResponse::FieldModified(node_id), + )); + } + } + | (false, NodeInstruction::ReadPath) => { + // since no filewatcher we simply give the option to reload the + // file + if ui.button("👁 Set active").clicked() { + responses.push(NodeResponse::User( + CustomResponse::SetActiveNode(node_id), + )); + } + let button = egui::Button::new(egui::RichText::new("Update file")); + if ui.add(button).clicked() { + responses.push(NodeResponse::User( + CustomResponse::FieldModified(node_id), + )); + } } | (true, _) => { let button = egui::Button::new( @@ -1684,7 +1822,16 @@ fn get_layout( } } text.append(")", 0., Default::default()); - } + }, + | BasicValue::PositiveGraph { value } => text.append( + &format!( + "A graph with {} nodes and {} edges.", + value.node_count(), + value.edge_count() + ), + 0., + Default::default(), + ), }, | Err(err) => { text.append(&format!("{err:?}"), 0., TextFormat { diff --git a/reaction_systems_gui/src/app_logic.rs b/reaction_systems_gui/src/app_logic.rs index bd1c7a7..88a8eb2 100644 --- a/reaction_systems_gui/src/app_logic.rs +++ b/reaction_systems_gui/src/app_logic.rs @@ -1502,7 +1502,7 @@ fn process_template( anyhow::bail!("Not a string"); } }, - | NodeInstruction::ComposePositiveSystem => { + | NodeInstruction::PositiveComposeSystem => { let ( input_env, input_initial_etities, @@ -1566,7 +1566,7 @@ fn process_template( anyhow::bail!("Not a system"); } }, - | NodeInstruction::DecomposePositiveSystem => { + | NodeInstruction::PositiveDecomposeSystem => { let s = retrieve_from_cache![1]; let hash_inputs = hash_inputs!(s); @@ -1616,6 +1616,225 @@ fn process_template( anyhow::bail!("Not a positive trace"); } }, + | NodeInstruction::PositiveEnvironment => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::String { value } = s { + let res = grammar_separated::grammar::PositiveEnvironmentParser::new() + .parse(&mut *translator, &value); + let env = match res { + | Ok(s) => s, + | Err(parse_error) => { + return Ok(Some(BasicValue::Error { + value: helper::reformat_error( + parse_error, + &value, + ctx, + ), + })); + }, + }; + let res = BasicValue::PositiveEnvironment { value: *env }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not a string"); + } + }, + | NodeInstruction::PositiveContext => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::String { value } = s { + let res = grammar_separated::grammar::PositiveContextParser::new() + .parse(&mut *translator, &value); + let context = match res { + | Ok(s) => s, + | Err(parse_error) => { + return Ok(Some(BasicValue::Error { + value: helper::reformat_error( + parse_error, + &value, + ctx, + ), + })); + }, + }; + let res = BasicValue::PositiveContext { value: context }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not a string"); + } + }, + | NodeInstruction::PositiveReactions => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::String { value } = s { + let res = grammar_separated::grammar::PositiveReactionsParser::new() + .parse(&mut *translator, &value); + let reactions = match res { + | Ok(s) => s, + | Err(parse_error) => { + return Ok(Some(BasicValue::Error { + value: helper::reformat_error( + parse_error, + &value, + ctx, + ), + })); + }, + }; + let res = BasicValue::PositiveReactions { value: reactions }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not a string"); + } + }, + | NodeInstruction::ToPositiveContext => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::Context { value } = s { + let res = BasicValue::PositiveContext { + value: value.into(), + }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not a context"); + } + }, + | NodeInstruction::ToPositiveEnvironment => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::Environment { value } = s { + let res = BasicValue::PositiveEnvironment { + value: value.into(), + }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not an environment"); + } + }, + | NodeInstruction::ToPositiveReactions => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::Reactions { value } = s { + let res = BasicValue::PositiveReactions { + value: rsprocess::reaction::PositiveReaction::from_reactions(&value), + }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not reactions"); + } + }, + | NodeInstruction::OverwriteContextEntities => { + let (sys, set) = retrieve_from_cache![2]; + let hash_inputs = hash_inputs!(sys, set); + + match (sys, set) { + | ( + BasicValue::System { value: sys }, + BasicValue::Set { value: set }, + ) => { + let mut new_sys = sys.clone(); + new_sys.overwrite_context_elements(set); + let res = BasicValue::System { value: new_sys }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + }, + | (BasicValue::System { value: _ }, _) => + anyhow::bail!("Not a set"), + | (_, BasicValue::Set { value: _ }) => + anyhow::bail!("Not a system"), + | (_, _) => anyhow::bail!("Inputs all wrong"), + } + }, + | NodeInstruction::OverwriteReactionEntities => { + let (sys, set) = retrieve_from_cache![2]; + let hash_inputs = hash_inputs!(sys, set); + + match (sys, set) { + | ( + BasicValue::System { value: sys }, + BasicValue::Set { value: set }, + ) => { + let mut new_sys = sys.clone(); + new_sys.overwrite_product_elements(set); + let res = BasicValue::System { value: new_sys }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + }, + | (BasicValue::System { value: _ }, _) => + anyhow::bail!("Not a set"), + | (_, BasicValue::Set { value: _ }) => + anyhow::bail!("Not a system"), + | (_, _) => anyhow::bail!("Inputs all wrong"), + } + }, + | NodeInstruction::PositiveOverwriteContextEntities => { + let (sys, set) = retrieve_from_cache![2]; + let hash_inputs = hash_inputs!(sys, set); + + match (sys, set) { + | ( + BasicValue::PositiveSystem { value: sys }, + BasicValue::PositiveSet { value: set }, + ) => { + let mut new_sys = sys.clone(); + new_sys.overwrite_context_elements(set); + let res = BasicValue::PositiveSystem { value: new_sys }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + }, + | (BasicValue::PositiveSystem { value: _ }, _) => + anyhow::bail!("Not a set"), + | (_, BasicValue::PositiveSet { value: _ }) => + anyhow::bail!("Not a system"), + | (_, _) => anyhow::bail!("Inputs all wrong"), + } + }, + | NodeInstruction::PositiveOverwriteReactionEntities => { + let (sys, set) = retrieve_from_cache![2]; + let hash_inputs = hash_inputs!(sys, set); + + match (sys, set) { + | ( + BasicValue::PositiveSystem { value: sys }, + BasicValue::PositiveSet { value: set }, + ) => { + let mut new_sys = sys.clone(); + new_sys.overwrite_product_elements(set); + let res = BasicValue::PositiveSystem { value: new_sys }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + }, + | (BasicValue::PositiveSystem { value: _ }, _) => + anyhow::bail!("Not a set"), + | (_, BasicValue::PositiveSet { value: _ }) => + anyhow::bail!("Not a system"), + | (_, _) => anyhow::bail!("Inputs all wrong"), + } + }, + | NodeInstruction::PositiveGraph => { + let s = retrieve_from_cache![1]; + let hash_inputs = hash_inputs!(s); + + if let BasicValue::PositiveSystem { value } = s { + let value = match value.digraph() { + | Ok(g) => g, + | Err(e) => anyhow::bail!(e), + }; + let res = BasicValue::PositiveGraph { value }; + set_cache_output!((output_names.first().unwrap(), res, hash_inputs)); + } else { + anyhow::bail!("Not a system"); + } + }, + | NodeInstruction::PositiveDot => { + todo!() + }, + | NodeInstruction::PositiveGraphML => { + todo!() + }, } Ok(None) }