From 3d6ca9f1b49e6dedada5694d42543320f87c273a Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 4 Dec 2023 16:22:58 -0700 Subject: [PATCH 01/10] fixed wiring bug for expressions and primitives --- skema/skema-rs/skema/src/database.rs | 59 ++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index b3ee80bf521..5213f3510c7 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -1182,7 +1182,15 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec } } FunctionType::Imported => { - create_import( + create_att_primitive( + gromet, // gromet for metadata + &mut nodes, // nodes + &mut edges, + &mut meta_nodes, + &mut start, + c_args.clone(), + ); + /*create_import( gromet, &mut nodes, &mut edges, @@ -1199,11 +1207,19 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec c_args.att_idx, c_args.bf_counter, c_args.parent_node.clone(), - ); + );*/ } FunctionType::ImportedMethod => { + create_att_primitive( + gromet, // gromet for metadata + &mut nodes, // nodes + &mut edges, + &mut meta_nodes, + &mut start, + c_args.clone(), + ); // basically seems like these are just functions to me. - c_args.att_idx = boxf.contents.unwrap() as usize; + /*c_args.att_idx = boxf.contents.unwrap() as usize; c_args.att_box = gromet.modules[0].attributes[c_args.att_idx - 1].clone(); create_function( gromet, // gromet for metadata @@ -1212,7 +1228,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec &mut meta_nodes, &mut start, c_args.clone(), - ); + );*/ } _ => {} } @@ -1611,8 +1627,7 @@ pub fn create_function( } FunctionType::ImportedMethod => { // this is a function call, but for some reason is not called a function - new_c_args.att_idx = att_sub_box.contents.unwrap() as usize; - create_function( + create_att_primitive( gromet, // gromet for metadata nodes, // nodes edges, @@ -1620,9 +1635,26 @@ pub fn create_function( start, new_c_args.clone(), ); + /*new_c_args.att_idx = att_sub_box.contents.unwrap() as usize; + create_function( + gromet, // gromet for metadata + nodes, // nodes + edges, + meta_nodes, + start, + new_c_args.clone(), + );*/ } FunctionType::Imported => { - create_import(gromet, nodes, edges, meta_nodes, start, c_args.clone()); + create_att_primitive( + gromet, // gromet for metadata + nodes, // nodes + edges, + meta_nodes, + start, + new_c_args.clone(), + ); + /*create_import(gromet, nodes, edges, meta_nodes, start, c_args.clone()); *start += 1; // now to implement wiring import_wiring( @@ -1632,7 +1664,7 @@ pub fn create_function( c_args.att_idx, c_args.bf_counter, c_args.parent_node.clone(), - ); + );*/ } _ => { println!( @@ -4146,7 +4178,7 @@ pub fn create_att_abstract( // now make the node with the port information let mut metadata_idx = 0; let n3 = Node { - n_type: String::from("Primitive"), + n_type: String::from("Abstract"), value: None, name: c_args.cur_box.name.clone(), node_id: format!("n{}", start), @@ -5099,7 +5131,7 @@ pub fn wfopo_cross_att_wiring( } } // this will construct connections from the sub function modules opi's to another sub module opo's, tracing data inside the function -// opi(sub)->opo(sub) +// opi(sub)->opo(sub) or pif(current) -> opo(sub) or opi(sub) -> pof(current) #[allow(unused_assignments)] pub fn wff_cross_att_wiring( eboxf: FunctionNet, // This is the current attribute, should be the function if in a function @@ -5232,7 +5264,7 @@ pub fn wff_cross_att_wiring( && (tgt_box as u32) == node.box_counter as u32 { // only opo's - if node.n_type == "Primitive" || node.n_type == "Literal" { + if node.n_type == "Primitive" || node.n_type == "Literal" || node.n_type == "Abstract" { // iterate through port to check for tgt for p in node.out_idx.as_ref().unwrap().iter() { // push the src first, being pif @@ -5269,6 +5301,7 @@ pub fn wff_cross_att_wiring( } } } else { + // This should be pif -> opo let src_nbox = bf_counter; // nbox value of src opi // collect info to identify the opo tgt node let tgt_idx = wire.tgt; // port index @@ -5298,11 +5331,11 @@ pub fn wff_cross_att_wiring( && (src_box as u32) == node.box_counter as u32 { // only opo's - if node.n_type == "Primitive" { + if node.n_type == "Primitive" || node.n_type == "Abstract" { // iterate through port to check for tgt for p in node.in_indx.as_ref().unwrap().iter() { // push the src first, being pif - if (src_opi_idx as u32) == *p { + if (src_idx as u32) == *p { wff_src_tgt.push(node.node_id.clone()); } } From b079f7d9bff87dd5eb1a5e3d8da6f2b7b136b1e2 Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 4 Dec 2023 17:15:11 -0700 Subject: [PATCH 02/10] initial support for infering unpack names when wired directly --- skema/skema-rs/skema/src/database.rs | 195 ++++++++++++++++----------- 1 file changed, 114 insertions(+), 81 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index 5213f3510c7..5ee09b13489 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -68,12 +68,13 @@ pub struct Node { pub box_counter: usize, // this indexes the box call for the node one scope up, matches nbox if higher scope is top level } -#[derive(Debug, Clone, PartialEq, Ord, Eq, PartialOrd)] +#[derive(Debug, Clone, PartialEq, Ord, Eq, PartialOrd, Default)] pub struct Edge { pub src: String, pub tgt: String, pub e_type: String, pub prop: Option, // option because of opo's and opi's + pub refer: Option, } #[derive(Debug, Clone)] @@ -378,7 +379,7 @@ fn create_module(gromet: &ModuleCollection) -> Vec { src: String::from("mod"), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; let edge_query = format!( "{} ({})-[e{}{}:{}]->({})", @@ -453,6 +454,7 @@ fn create_function_net_lib(gromet: &ModuleCollection, mut start: u32) -> Vec Vec Vec Vec Vec Vec Vec tgt: format!("n{}", start), e_type: String::from("Contains"), prop: Some(boxf.contents.unwrap() as usize), + ..Default::default() }; nodes.push(n1.clone()); edges.push(e1); @@ -991,7 +998,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -1012,7 +1019,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -1052,7 +1059,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec src: n1.node_id.clone(), tgt: node.node_id.clone(), e_type: String::from("Contains"), - prop: None, + ..Default::default() }; edges.push(e5); } @@ -1110,7 +1117,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec src: wfopi_src_tgt[0].clone(), tgt: wfopi_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e6); } @@ -1163,7 +1170,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec src: wfopo_src_tgt[0].clone(), tgt: wfopo_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e7); } @@ -1360,6 +1367,10 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec let set_query = format!("set e{}{}.index={}", edge.src, edge.tgt, edge.prop.unwrap()); queries.push(set_query); } + if edge.refer.is_some() { + let set_query = format!("set e{}{}.refer={}", edge.src, edge.tgt, edge.refer.unwrap()); + queries.push(set_query); + } } queries } @@ -1422,7 +1433,7 @@ pub fn create_import( src: c_args.parent_node.node_id, tgt: n3.node_id.clone(), e_type: String::from("Contains"), - prop: None, + ..Default::default() }; edges.push(e4); if eboxf.metadata.is_some() { @@ -1439,7 +1450,7 @@ pub fn create_import( src: n3.node_id, tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -1500,6 +1511,7 @@ pub fn create_function( tgt: n1.node_id.clone(), e_type: String::from("Contains"), prop: Some(c_args.att_idx), + ..Default::default() }; parent_node = n1.clone(); nodes.push(n1.clone()); @@ -1520,7 +1532,7 @@ pub fn create_function( src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -1799,6 +1811,7 @@ pub fn create_conditional( tgt: format!("n{}", start), e_type: String::from("Contains"), prop: Some(cond_counter as usize), + ..Default::default() }; nodes.push(n1.clone()); edges.push(e1); @@ -1832,7 +1845,7 @@ pub fn create_conditional( src: n1.node_id.clone(), tgt: format!("n{}", start), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; nodes.push(n2.clone()); edges.push(e3); @@ -1850,7 +1863,7 @@ pub fn create_conditional( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -1885,7 +1898,7 @@ pub fn create_conditional( src: n1.node_id.clone(), tgt: format!("n{}", start), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; nodes.push(n3.clone()); edges.push(e5); @@ -1903,7 +1916,7 @@ pub fn create_conditional( src: n3.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -2051,7 +2064,7 @@ pub fn create_conditional( src: wfc_src_tgt[0].clone(), tgt: wfc_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -2104,7 +2117,7 @@ pub fn create_conditional( src: cond_src_tgt[0].clone(), tgt: cond_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e9); } @@ -2151,7 +2164,7 @@ pub fn create_conditional( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e10); } @@ -2199,7 +2212,7 @@ pub fn create_conditional( src: else_src_tgt[0].clone(), tgt: else_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e11); } @@ -2251,7 +2264,7 @@ pub fn create_conditional( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e12); } @@ -2299,7 +2312,7 @@ pub fn create_conditional( src: else_src_tgt[0].clone(), tgt: else_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e13); } @@ -2349,7 +2362,7 @@ pub fn create_conditional( src: cond_src_tgt[0].clone(), tgt: cond_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e14); } @@ -2389,6 +2402,7 @@ pub fn create_for_loop( tgt: format!("n{}", start), e_type: String::from("Contains"), prop: Some(cond_counter as usize), + ..Default::default() }; nodes.push(n1.clone()); edges.push(e1); @@ -2412,7 +2426,7 @@ pub fn create_for_loop( src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -2524,7 +2538,7 @@ pub fn create_for_loop( src: n1.node_id.clone(), tgt: format!("n{}", start), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; nodes.push(n2.clone()); edges.push(e3); @@ -2542,7 +2556,7 @@ pub fn create_for_loop( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -2576,7 +2590,7 @@ pub fn create_for_loop( src: n1.node_id.clone(), tgt: format!("n{}", start), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; nodes.push(n3.clone()); edges.push(e5); @@ -2594,7 +2608,7 @@ pub fn create_for_loop( src: n3.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -2668,7 +2682,7 @@ pub fn create_for_loop( src: wfl_src_tgt[0].clone(), tgt: wfl_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -2717,7 +2731,7 @@ pub fn create_for_loop( src: cond_src_tgt[0].clone(), tgt: cond_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e9); } @@ -2764,7 +2778,7 @@ pub fn create_for_loop( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e10); } @@ -2814,7 +2828,7 @@ pub fn create_for_loop( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e12); } @@ -2861,7 +2875,7 @@ pub fn create_for_loop( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e15); } @@ -2911,7 +2925,7 @@ pub fn create_for_loop( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e16); } @@ -2960,7 +2974,7 @@ pub fn create_for_loop( src: cond_src_tgt[0].clone(), tgt: cond_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e14); } @@ -3001,6 +3015,7 @@ pub fn create_while_loop( tgt: format!("n{}", start), e_type: String::from("Contains"), prop: Some(cond_counter as usize), + ..Default::default() }; nodes.push(n1.clone()); edges.push(e1); @@ -3024,7 +3039,7 @@ pub fn create_while_loop( src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3113,7 +3128,7 @@ pub fn create_while_loop( src: n1.node_id.clone(), tgt: format!("n{}", start), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; nodes.push(n2.clone()); edges.push(e3); @@ -3131,7 +3146,7 @@ pub fn create_while_loop( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3165,7 +3180,7 @@ pub fn create_while_loop( src: n1.node_id.clone(), tgt: format!("n{}", start), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; nodes.push(n3.clone()); edges.push(e5); @@ -3183,7 +3198,7 @@ pub fn create_while_loop( src: n3.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3257,7 +3272,7 @@ pub fn create_while_loop( src: wfl_src_tgt[0].clone(), tgt: wfl_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -3306,7 +3321,7 @@ pub fn create_while_loop( src: cond_src_tgt[0].clone(), tgt: cond_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e9); } @@ -3353,7 +3368,7 @@ pub fn create_while_loop( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e10); } @@ -3403,7 +3418,7 @@ pub fn create_while_loop( src: if_src_tgt[0].clone(), tgt: if_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e12); } @@ -3452,7 +3467,7 @@ pub fn create_while_loop( src: cond_src_tgt[0].clone(), tgt: cond_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e14); } @@ -3488,6 +3503,7 @@ pub fn create_att_expression( tgt: format!("n{}", start), e_type: String::from("Contains"), prop: Some(c_args.att_idx), + ..Default::default() }; nodes.push(n1.clone()); edges.push(e1); @@ -3508,7 +3524,7 @@ pub fn create_att_expression( src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3577,7 +3593,7 @@ pub fn create_att_expression( src: n1.node_id.clone(), tgt: n2.node_id.clone(), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; edges.push(e3); if att_box.opo.clone().as_ref().unwrap()[oport as usize] @@ -3601,7 +3617,7 @@ pub fn create_att_expression( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3676,7 +3692,7 @@ pub fn create_att_expression( src: n1.node_id.clone(), tgt: n2.node_id.clone(), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; edges.push(e3); if att_box.opi.clone().as_ref().unwrap()[iport as usize] @@ -3700,7 +3716,7 @@ pub fn create_att_expression( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3791,6 +3807,7 @@ pub fn create_att_predicate( tgt: format!("n{}", start), e_type: String::from("Contains"), prop: Some(c_args.att_idx), + ..Default::default() }; nodes.push(n1.clone()); edges.push(e1); @@ -3811,7 +3828,7 @@ pub fn create_att_predicate( src: n1.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3854,7 +3871,7 @@ pub fn create_att_predicate( src: n1.node_id.clone(), tgt: n2.node_id.clone(), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; edges.push(e3); if att_box.opo.clone().as_ref().unwrap()[oport as usize] @@ -3878,7 +3895,7 @@ pub fn create_att_predicate( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -3915,7 +3932,7 @@ pub fn create_att_predicate( src: n1.node_id.clone(), tgt: n2.node_id.clone(), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; edges.push(e3); if att_box.opi.clone().as_ref().unwrap()[iport as usize] @@ -3939,7 +3956,7 @@ pub fn create_att_predicate( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -4041,7 +4058,7 @@ pub fn create_att_literal( src: c_args.parent_node.node_id, tgt: n3.node_id.clone(), e_type: String::from("Contains"), - prop: None, + ..Default::default() }; edges.push(e4); if lit_box.metadata.is_some() { @@ -4058,7 +4075,7 @@ pub fn create_att_literal( src: n3.node_id, tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -4117,7 +4134,7 @@ pub fn create_att_primitive( src: c_args.parent_node.node_id, tgt: n3.node_id.clone(), e_type: String::from("Contains"), - prop: None, + ..Default::default() }; edges.push(e4); if c_args.cur_box.metadata.is_some() { @@ -4134,7 +4151,7 @@ pub fn create_att_primitive( src: n3.node_id, tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -4155,11 +4172,15 @@ pub fn create_att_abstract( ) { // first find the pof's for box let mut pof: Vec = vec![]; + let mut pof_names: Vec = vec![]; if c_args.att_box.pof.is_some() { let mut po_idx: u32 = 1; for port in c_args.att_box.pof.clone().unwrap().iter() { if port.r#box == c_args.box_counter as u8 { pof.push(po_idx); + if port.name.is_some() { + pof_names.push(port.name.clone().unwrap()); + } } po_idx += 1; } @@ -4175,11 +4196,17 @@ pub fn create_att_abstract( pi_idx += 1; } } + // now to construct an entry of ValueL for abstract port references + let val = ValueL { + value_type: "List".to_string(), + value: format!("{:?}", pof_names.clone()), + gromet_type: Some("Abstract".to_string()), + }; // now make the node with the port information let mut metadata_idx = 0; let n3 = Node { n_type: String::from("Abstract"), - value: None, + value: Some(val), name: c_args.cur_box.name.clone(), node_id: format!("n{}", start), out_idx: Some(pof), @@ -4195,7 +4222,7 @@ pub fn create_att_abstract( src: c_args.parent_node.node_id, tgt: n3.node_id.clone(), e_type: String::from("Contains"), - prop: None, + ..Default::default() }; edges.push(e4); if c_args.cur_box.metadata.is_some() { @@ -4212,7 +4239,7 @@ pub fn create_att_abstract( src: n3.node_id, tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -4267,7 +4294,7 @@ pub fn create_opo( src: c_args.parent_node.node_id.clone(), tgt: n2.node_id.clone(), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; edges.push(e3); @@ -4293,7 +4320,7 @@ pub fn create_opo( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -4352,7 +4379,7 @@ pub fn create_opi( src: c_args.parent_node.node_id.clone(), tgt: n2.node_id.clone(), e_type: String::from("Port_Of"), - prop: None, + ..Default::default() }; edges.push(e3); @@ -4378,7 +4405,7 @@ pub fn create_opi( src: n2.node_id.clone(), tgt: format!("m{}", metadata_idx), e_type: String::from("Metadata"), - prop: None, + ..Default::default() }; edges.push(me1); } @@ -4450,6 +4477,7 @@ pub fn wfopi_wiring( tgt: wfopi_src_tgt[1].clone(), e_type: String::from("Wire"), prop: Some(prop.unwrap() as usize), + ..Default::default() }; edges.push(e6); } @@ -4512,7 +4540,7 @@ pub fn wfopo_wiring( src: wfopo_src_tgt[0].clone(), tgt: wfopo_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e7); } @@ -4532,6 +4560,7 @@ pub fn wff_wiring( for wire in eboxf.wff.unwrap().iter() { let mut wff_src_tgt: Vec = vec![]; let mut prop = None; + let mut refer = None; let src_idx = wire.src; // port index @@ -4565,7 +4594,7 @@ pub fn wff_wiring( // push the tgt if (wire.src as u32) == *p { wff_src_tgt.push(node.node_id.clone()); - prop = Some(i as u32); + prop = Some(i as usize); } } } @@ -4587,10 +4616,13 @@ pub fn wff_wiring( // exclude opo's if node.n_type != "Opo" { // iterate through port to check for tgt - for p in node.out_idx.as_ref().unwrap().iter() { + for (i, p) in node.out_idx.as_ref().unwrap().iter().enumerate() { // push the tgt if (wire.tgt as u32) == *p { wff_src_tgt.push(node.node_id.clone()); + if node.n_type == "Abstract" { + refer = Some(i as usize); + } } } } @@ -4604,7 +4636,8 @@ pub fn wff_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: Some(prop.unwrap() as usize), + prop: Some(prop.unwrap()), + refer: refer, }; edges.push(e8); } @@ -4667,7 +4700,7 @@ pub fn wopio_wiring( src: wopio_src_tgt[0].clone(), tgt: wopio_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e7); } @@ -4817,7 +4850,7 @@ pub fn import_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -4905,7 +4938,7 @@ pub fn import_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -5039,7 +5072,7 @@ pub fn wfopi_cross_att_wiring( src: wfopi_src_tgt[0].clone(), tgt: wfopi_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -5123,7 +5156,7 @@ pub fn wfopo_cross_att_wiring( src: wfopo_src_tgt[0].clone(), tgt: wfopo_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -5227,7 +5260,7 @@ pub fn wff_cross_att_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -5295,7 +5328,7 @@ pub fn wff_cross_att_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -5368,7 +5401,7 @@ pub fn wff_cross_att_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e8); } @@ -5482,7 +5515,7 @@ pub fn external_wiring(gromet: &ModuleCollection, nodes: &mut [Node], edges: &mu src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), - prop: None, + ..Default::default() }; edges.push(e9); } From 3f3b5b100436a0e8b2902308f7f286f4c36d93b6 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 5 Dec 2023 14:03:57 -0700 Subject: [PATCH 03/10] better memgraph nodes for lists --- skema/skema-rs/skema/src/database.rs | 122 ++++++++++++++++++- skema/skema-rs/skema/src/model_extraction.rs | 17 +++ 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index 5ee09b13489..911f3085f40 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -779,7 +779,8 @@ fn create_function_net_lib(gromet: &ModuleCollection, mut start: u32) -> Vec Vec Vec } } // convert every node object into a node query - let create = String::from("CREATE"); + queries.append(&mut construct_memgraph_queries(&mut nodes, &mut edges, &mut meta_nodes, &mut queries.clone())); + /*let create = String::from("CREATE"); for node in nodes.iter() { let mut name = String::from("a"); if node.name.is_none() { @@ -1371,7 +1373,7 @@ fn create_function_net(gromet: &ModuleCollection, mut start: u32) -> Vec let set_query = format!("set e{}{}.refer={}", edge.src, edge.tgt, edge.refer.unwrap()); queries.push(set_query); } - } + }*/ queries } // this method creates an import type function @@ -4197,9 +4199,18 @@ pub fn create_att_abstract( } } // now to construct an entry of ValueL for abstract port references + let mut value_vec = Vec::::new(); + for name in pof_names.iter() { + let val = ValueL { + value_type: "String".to_string(), + value: format!("{:?}", name.clone()), + gromet_type: Some("Name".to_string()), + }; + value_vec.push(val.clone()); + } let val = ValueL { value_type: "List".to_string(), - value: format!("{:?}", pof_names.clone()), + value: format!("{:?}", value_vec.clone()), gromet_type: Some("Abstract".to_string()), }; // now make the node with the port information @@ -5533,3 +5544,104 @@ pub fn parse_gromet_queries(gromet: ModuleCollection) -> Vec { queries } + +// convert every node object into a node query +pub fn construct_memgraph_queries(nodes: &mut Vec, edges: &mut Vec, meta_nodes: &mut Vec, queries: &mut Vec) -> Vec { + // convert every node object into a node query + let create = String::from("CREATE"); + for node in nodes.iter() { + let mut name = String::from("a"); + if node.name.is_none() { + name = node.n_type.clone(); + } else { + name = node.name.as_ref().unwrap().to_string(); + } + // better parsing of values for inference later on. + // handles case of parsing a list as a proper list object, only depth one though + // would need recursive function for aritrary depth. To be done at somepoint. + let value = match &node.value { + Some(val) => if val.value_type == *"List" { + let val_type = val.value_type.clone(); + let val_grom_type = val.gromet_type.as_ref().unwrap(); + let val_len = val.value[..].len(); + let val_val: Vec = val.value[1..val_len].split("}, ").map(|x| x.to_string()).collect(); + + let mut val_vec = Vec::::new(); + for (i, val) in val_val.iter().enumerate() { + if i == val_val.len() - 1 { + let val_string = format!("{}}}", &val[7..(val.len()-2)]); + val_vec.push(val_string.clone()); + } else { + let val_string = format!("{}}}", &val[7..]); + val_vec.push(val_string.clone()); + } + } + let mut final_val_vec = Vec::::new(); + for val_str in val_vec.iter() { + let val_fields: Vec = val_str.split(", ").map(|x| x.to_string()).collect(); + let cor_val: Vec = val_fields[1].split(": ").map(|x| x.to_string()).collect(); + let final_val = cor_val[1].replace("\\\"", ""); + final_val_vec.push(final_val.clone()); + } + format!( + "{{ value_type:{:?}, value:{:?}, gromet_type:{:?} }}", + val_type, + final_val_vec, + val_grom_type + ).replace("\\\"", "") + } else { + format!( + "{{ value_type:{:?}, value:{:?}, gromet_type:{:?} }}", + val.value_type, + val.value, + val.gromet_type.as_ref().unwrap() + ) + }, + None => String::from("\"\""), + }; + + // NOTE: The format of value has changed to represent a literal Cypher map {field:value}. + // We no longer need to format value with the debug :? parameter + let node_query = format!( + "{} ({}:{} {{name:{:?},value:{},order_box:{:?},order_att:{:?}}})", + create, node.node_id, node.n_type, name, value, node.nbox, node.contents + ); + queries.push(node_query); + } + for node in meta_nodes.iter() { + queries.append(&mut create_metadata_node_query(node.clone())); + } + + // convert every edge object into an edge query + let init_edges = edges.len(); + edges.sort(); + edges.dedup(); + let edges_clone = edges.clone(); + // also dedup if edge prop is different + for (i, edge) in edges_clone.iter().enumerate().rev() { + if i != 0 && edge.src == edges_clone[i - 1].src && edge.tgt == edges_clone[i - 1].tgt { + edges.remove(i); + } + } + let fin_edges = edges.len(); + if init_edges != fin_edges { + println!("Duplicated Edges Removed, check for bugs"); + } + for edge in edges.iter() { + let edge_query = format!( + "{} ({})-[e{}{}:{}]->({})", + create, edge.src, edge.src, edge.tgt, edge.e_type, edge.tgt + ); + queries.push(edge_query); + + if edge.prop.is_some() { + let set_query = format!("set e{}{}.index={}", edge.src, edge.tgt, edge.prop.unwrap()); + queries.push(set_query); + } + if edge.refer.is_some() { + let set_query = format!("set e{}{}.refer={}", edge.src, edge.tgt, edge.refer.unwrap()); + queries.push(set_query); + } + } + queries.to_vec() +} diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index 9f50b7336f1..e70e80774e0 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -17,6 +17,23 @@ use neo4rs; use neo4rs::{query, Error}; use std::sync::Arc; +#[derive(Clone, Debug)] +pub struct ModelNode { + id: i64, + label: String, + name: String, + value: Option, +} + +#[derive(Clone, Debug)] +pub struct ModelEdge { + id: i64, + src_id: i64, + tgt_id: i64, + index: Option, + refer: Option, +} + #[allow(non_snake_case)] pub async fn module_id2mathml_MET_ast(module_id: i64, config: Config) -> Vec { let mut core_dynamics_ast = Vec::::new(); From cd4fdbaf6786576b6a3c163ebadbb97e461ab17b Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 5 Dec 2023 16:55:45 -0700 Subject: [PATCH 04/10] moved nodes and edges to clone-able ones --- skema/skema-rs/skema/src/database.rs | 2 +- skema/skema-rs/skema/src/model_extraction.rs | 167 +++++++++---------- 2 files changed, 82 insertions(+), 87 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index 911f3085f40..28d8c79a04e 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -5560,7 +5560,7 @@ pub fn construct_memgraph_queries(nodes: &mut Vec, edges: &mut Vec, // handles case of parsing a list as a proper list object, only depth one though // would need recursive function for aritrary depth. To be done at somepoint. let value = match &node.value { - Some(val) => if val.value_type == *"List" { + Some(val) => if val.value_type == *"List" && &val.value[0..1] == "[" && &val.value[1..2] != "]" { let val_type = val.value_type.clone(); let val_grom_type = val.gromet_type.as_ref().unwrap(); let val_len = val.value[..].len(); diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index e70e80774e0..bedd0ebe616 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -21,7 +21,7 @@ use std::sync::Arc; pub struct ModelNode { id: i64, label: String, - name: String, + name: Option, value: Option, } @@ -73,16 +73,16 @@ pub async fn find_pn_dynamics(module_id: i64, config: Config) -> Vec { // 1. find each function node let mut function_nodes = Vec::::new(); for node in graph.node_indices() { - if graph[node].labels()[0] == *"Function" { + if graph[node].label == *"Function" { function_nodes.push(node); } } // 2. check and make sure only expressions in function // 3. check number of expressions and decide off that - let mut functions = Vec::>::new(); + let mut functions = Vec::>::new(); for i in 0..function_nodes.len() { // grab the subgraph of the given expression - functions.push(subgraph2petgraph(graph[function_nodes[i]].id(), config.clone()).await); + functions.push(subgraph2petgraph(graph[function_nodes[i]].id, config.clone()).await); } // get a sense of the number of expressions in each function let mut func_counter = 0; @@ -91,17 +91,17 @@ pub async fn find_pn_dynamics(module_id: i64, config: Config) -> Vec { let mut expression_counter = 0; let mut primitive_counter = 0; for node in func.node_indices() { - if func[node].labels()[0] == *"Expression" { + if func[node].label == *"Expression" { expression_counter += 1; } - if func[node].labels()[0] == *"Primitive" { - if func[node].get::("name").unwrap() == *"ast.Mult" { + if func[node].label == *"Primitive" { + if *func[node].name.as_ref().unwrap() == "ast.Mult".to_string() { primitive_counter += 1; - } else if func[node].get::("name").unwrap() == *"ast.Add" { + } else if *func[node].name.as_ref().unwrap() == "ast.Add".to_string() { primitive_counter += 1; - } else if func[node].get::("name").unwrap() == *"ast.Sub" { + } else if *func[node].name.as_ref().unwrap() == "ast.Sub".to_string() { primitive_counter += 1; - } else if func[node].get::("name").unwrap() == *"ast.USub" { + } else if *func[node].name.as_ref().unwrap() == "ast.USub".to_string() { primitive_counter += 1; } } @@ -115,8 +115,8 @@ pub async fn find_pn_dynamics(module_id: i64, config: Config) -> Vec { let mut core_id = Vec::::new(); for c_func in core_func.iter() { for node in functions[*c_func].node_indices() { - if functions[*c_func][node].labels()[0] == *"Function" { - core_id.push(functions[*c_func][node].id()); + if functions[*c_func][node].label == *"Function" { + core_id.push(functions[*c_func][node].id); } } } @@ -135,7 +135,7 @@ pub async fn subgrapg2_core_dyn_MET_ast( // find all the expressions let mut expression_nodes = Vec::::new(); for node in graph.node_indices() { - if graph[node].labels()[0] == *"Expression" { + if graph[node].label == *"Expression" { expression_nodes.push(node); } } @@ -145,14 +145,14 @@ pub async fn subgrapg2_core_dyn_MET_ast( // initialize vector to collect all expression wiring graphs for i in 0..expression_nodes.len() { // grab the wiring subgraph of the given expression - let mut sub_w = subgraph_wiring(graph[expression_nodes[i]].id(), config.clone()) + let mut sub_w = subgraph_wiring(graph[expression_nodes[i]].id, config.clone()) .await .unwrap(); if sub_w.node_count() > 3 { - let expr = trim_un_named(&mut sub_w, config.clone()).await; + let expr = trim_un_named(&mut sub_w).await; let mut root_node = Vec::::new(); for node_index in expr.node_indices() { - if expr[node_index].labels()[0].clone() == *"Opo" { + if expr[node_index].label.clone() == *"Opo" { root_node.push(node_index); } } @@ -169,15 +169,15 @@ pub async fn subgrapg2_core_dyn_MET_ast( #[allow(non_snake_case)] fn tree_2_MET_ast( - graph: &mut petgraph::Graph, + graph: &mut petgraph::Graph, root_node: NodeIndex, ) -> Result { let mut fo_eq_vec = Vec::::new(); let _math_vec = Vec::::new(); let mut lhs = Vec::::new(); - if graph[root_node].labels()[0] == *"Opo" { + if graph[root_node].label == *"Opo" { // we first construct the derivative of the first node - let deriv_name: &str = &graph[root_node].get::("name").unwrap(); + let deriv_name: &str = &graph[root_node].name.as_ref().unwrap(); // this will let us know if additional trimming is needed to handle the code implementation of the equations // let mut step_impl = false; this will be used for step implementaion for later // This is very bespoke right now @@ -200,7 +200,7 @@ fn tree_2_MET_ast( lhs.push(deriv); } for node in graph.neighbors_directed(root_node, Outgoing) { - if graph[node].labels()[0].clone() == *"Primitive" { + if graph[node].label.clone() == *"Primitive" { let operate = get_operator_MET(graph, node); // output -> Operator let rhs_arg = get_args_MET(graph, node); // output -> Vec let rhs = MathExpressionTree::Cons(operate, rhs_arg); // MathExpressionTree @@ -223,7 +223,7 @@ fn tree_2_MET_ast( #[allow(non_snake_case)] pub fn get_args_MET( - graph: &petgraph::Graph, + graph: &petgraph::Graph, root_node: NodeIndex, ) -> Vec { let mut args = Vec::::new(); @@ -236,14 +236,14 @@ pub fn get_args_MET( // construct vecs for node in graph.neighbors_directed(root_node, Outgoing) { // first need to check for operator - if graph[node].labels()[0].clone() == *"Primitive" { + if graph[node].label.clone() == *"Primitive" { let operate = get_operator_MET(graph, node); // output -> Operator let rhs_arg = get_args_MET(graph, node); // output -> Vec let rhs = MathExpressionTree::Cons(operate, rhs_arg); // MathExpressionTree args.push(rhs.clone()); } else { // asummption it is atomic - let temp_string = graph[node].get::("name").unwrap().clone(); + let temp_string = graph[node].name.as_ref().unwrap().clone(); let arg2 = MathExpressionTree::Atom(MathExpression::Mi(Mi(temp_string.clone()))); args.push(arg2.clone()); } @@ -252,7 +252,7 @@ pub fn get_args_MET( let x = graph .edge_weight(graph.find_edge(root_node, node).unwrap()) .unwrap() - .get::("index") + .index .unwrap(); arg_order.push(x); } @@ -274,23 +274,23 @@ pub fn get_args_MET( #[allow(non_snake_case)] #[allow(clippy::if_same_then_else)] pub fn get_operator_MET( - graph: &petgraph::Graph, + graph: &petgraph::Graph, root_node: NodeIndex, ) -> Operator { let mut op = Vec::::new(); - if graph[root_node].get::("name").unwrap() == *"ast.Mult" { + if *graph[root_node].name.as_ref().unwrap() == "ast.Mult".to_string() { op.push(Operator::Multiply); - } else if graph[root_node].get::("name").unwrap() == *"ast.Add" { + } else if *graph[root_node].name.as_ref().unwrap() == "ast.Add" { op.push(Operator::Add); - } else if graph[root_node].get::("name").unwrap() == *"ast.Sub" { + } else if *graph[root_node].name.as_ref().unwrap() == "ast.Sub" { op.push(Operator::Subtract); - } else if graph[root_node].get::("name").unwrap() == *"ast.USub" { + } else if *graph[root_node].name.as_ref().unwrap() == "ast.USub" { op.push(Operator::Subtract); - } else if graph[root_node].get::("name").unwrap() == *"ast.Div" { + } else if *graph[root_node].name.as_ref().unwrap() == "ast.Div" { op.push(Operator::Divide); } else { op.push(Operator::Other( - graph[root_node].get::("name").unwrap(), + graph[root_node].name.clone().unwrap(), )); } op[0].clone() @@ -298,16 +298,13 @@ pub fn get_operator_MET( // this currently only works for un-named nodes that are not chained or have multiple incoming/outgoing edges async fn trim_un_named( - graph: &mut petgraph::Graph, - config: Config, -) -> &mut petgraph::Graph { + graph: &mut petgraph::Graph, +) -> &mut petgraph::Graph { // first create a cloned version of the graph we can modify while iterating over it. - let graph_call = Arc::new(config.graphdb_connection().await); - // iterate over the graph and add a new edge to bypass the un-named nodes for node_index in graph.node_indices() { - if graph[node_index].get::("name").unwrap().clone() == *"un-named" { + if graph[node_index].clone().name.unwrap().clone() == *"un-named" { let mut bypass = Vec::::new(); for node1 in graph.neighbors_directed(node_index, Incoming) { bypass.push(node1); @@ -318,21 +315,7 @@ async fn trim_un_named( // one incoming one outgoing if bypass.len() == 2 { // annoyingly have to pull the edge/Relation to insert into graph - let mut edge_list = Vec::::new(); - let query_string = format!( - "MATCH (n)-[r:Wire]->(m) WHERE id(n) = {} AND id(m) = {} RETURN r", - graph[bypass[0]].id(), - graph[node_index].id() - ); - let mut result = graph_call.execute(query(&query_string[..])).await.unwrap(); - while let Ok(Some(row)) = result.next().await { - let edge: neo4rs::Relation = row.get("r").unwrap(); - edge_list.push(edge); - } - // add the bypass edge - for edge in edge_list { - graph.add_edge(bypass[0], bypass[1], edge); - } + graph.add_edge(bypass[0], bypass[1], graph.edge_weight(graph.find_edge(bypass[0], node_index).unwrap()).unwrap().clone()); } else if bypass.len() > 2 { // this operates on the assumption that there maybe multiple references to the port // (incoming arrows) but only one outgoing arrow, this seems to be the case based on @@ -341,21 +324,7 @@ async fn trim_un_named( let end_node_idx = bypass.len() - 1; for (i, _ent) in bypass[0..end_node_idx].iter().enumerate() { // this iterates over all but the last entry in the bypass vec - let mut edge_list = Vec::::new(); - let query_string = format!( - "MATCH (n)-[r:Wire]->(m) WHERE id(n) = {} AND id(m) = {} RETURN r", - graph[bypass[i]].id(), - graph[node_index].id() - ); - let mut result = graph_call.execute(query(&query_string[..])).await.unwrap(); - while let Ok(Some(row)) = result.next().await { - let edge: neo4rs::Relation = row.get("r").unwrap(); - edge_list.push(edge); - } - - for edge in edge_list { - graph.add_edge(bypass[i], bypass[end_node_idx], edge); - } + graph.add_edge(bypass[i], bypass[end_node_idx], graph.edge_weight(graph.find_edge(bypass[i], node_index).unwrap()).unwrap().clone()); } } } @@ -364,8 +333,8 @@ async fn trim_un_named( // now we perform a filter_map to remove the un-named nodes and only the bypass edge will remain to connect the nodes // we also remove the unpack node if it is present here as well for node_index in graph.node_indices().rev() { - if graph[node_index].get::("name").unwrap().clone() == *"un-named" - || graph[node_index].get::("name").unwrap().clone() == *"unpack" + if graph[node_index].name.clone().unwrap() == *"un-named" + || graph[node_index].name.clone().unwrap() == *"unpack" { graph.remove_node(node_index); } @@ -377,9 +346,9 @@ async fn trim_un_named( async fn subgraph_wiring( module_id: i64, config: Config, -) -> Result, Error> { - let mut node_list = Vec::::new(); - let mut edge_list = Vec::::new(); +) -> Result, Error> { + let mut node_list = Vec::::new(); + let mut edge_list = Vec::::new(); // Connect to Memgraph. let graph = Arc::new(config.graphdb_connection().await); @@ -399,7 +368,13 @@ async fn subgraph_wiring( .await?; while let Ok(Some(row)) = result1.next().await { let node: neo4rs::Node = row.get("nodes2").unwrap(); - node_list.push(node); + let modelnode = ModelNode { + id: node.id(), + label: node.labels()[0].clone(), + name: node.get::("name"), + value: node.get::("value") + }; + node_list.push(modelnode); } // edge query let mut result2 = graph @@ -417,10 +392,17 @@ async fn subgraph_wiring( .await?; while let Ok(Some(row)) = result2.next().await { let edge: neo4rs::Relation = row.get("edges2").unwrap(); - edge_list.push(edge); + let modeledge = ModelEdge { + id: edge.id(), + src_id: edge.start_node_id(), + tgt_id: edge.end_node_id(), + index: edge.get::("index"), + refer: edge.get::("refer") + }; + edge_list.push(modeledge); } - let mut graph: petgraph::Graph = Graph::new(); + let mut graph: petgraph::Graph = Graph::new(); // Add nodes to the petgraph graph and collect their indexes let mut nodes = Vec::::new(); @@ -434,10 +416,10 @@ async fn subgraph_wiring( let mut src = Vec::::new(); let mut tgt = Vec::::new(); for node_idx in &nodes { - if graph[*node_idx].id() == edge.start_node_id() { + if graph[*node_idx].id == edge.src_id { src.push(*node_idx); } - if graph[*node_idx].id() == edge.end_node_id() { + if graph[*node_idx].id == edge.tgt_id { tgt.push(*node_idx); } } @@ -451,11 +433,11 @@ async fn subgraph_wiring( async fn subgraph2petgraph( module_id: i64, config: Config, -) -> petgraph::Graph { +) -> petgraph::Graph { let (x, y) = get_subgraph(module_id, config.clone()).await.unwrap(); // Create a petgraph graph - let mut graph: petgraph::Graph = Graph::new(); + let mut graph: petgraph::Graph = Graph::new(); // Add nodes to the petgraph graph and collect their indexes let mut nodes = Vec::::new(); @@ -469,10 +451,10 @@ async fn subgraph2petgraph( let mut src = Vec::::new(); let mut tgt = Vec::::new(); for node_idx in &nodes { - if graph[*node_idx].id() == edge.start_node_id() { + if graph[*node_idx].id == edge.src_id { src.push(*node_idx); } - if graph[*node_idx].id() == edge.end_node_id() { + if graph[*node_idx].id == edge.tgt_id { tgt.push(*node_idx); } } @@ -486,11 +468,11 @@ async fn subgraph2petgraph( pub async fn get_subgraph( module_id: i64, config: Config, -) -> Result<(Vec, Vec), Error> { +) -> Result<(Vec, Vec), Error> { // construct the query that will delete the module with a given unique identifier - let mut node_list = Vec::::new(); - let mut edge_list = Vec::::new(); + let mut node_list = Vec::::new(); + let mut edge_list = Vec::::new(); // Connect to Memgraph. let graph = Arc::new(config.graphdb_connection().await); @@ -509,7 +491,13 @@ pub async fn get_subgraph( .await?; while let Ok(Some(row)) = result1.next().await { let node: neo4rs::Node = row.get("nodes2").unwrap(); - node_list.push(node); + let modelnode = ModelNode { + id: node.id(), + label: node.labels()[0].clone(), + name: node.get::("name"), + value: node.get::("value") + }; + node_list.push(modelnode); } // edge query let mut result2 = graph @@ -526,7 +514,14 @@ pub async fn get_subgraph( .await?; while let Ok(Some(row)) = result2.next().await { let edge: neo4rs::Relation = row.get("edges2").unwrap(); - edge_list.push(edge); + let modeledge = ModelEdge { + id: edge.id(), + src_id: edge.start_node_id(), + tgt_id: edge.end_node_id(), + index: edge.get::("index"), + refer: edge.get::("refer") + }; + edge_list.push(modeledge); } Ok((node_list, edge_list)) From d568becce89068990db7c549cb050eab55c1cab3 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 5 Dec 2023 17:17:50 -0700 Subject: [PATCH 05/10] cargo fmt and cargo clippy --- skema/skema-rs/skema/src/database.rs | 117 ++++++++++++------- skema/skema-rs/skema/src/model_extraction.rs | 40 +++++-- 2 files changed, 101 insertions(+), 56 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index 28d8c79a04e..4a6f3c24bfc 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -779,7 +779,12 @@ fn create_function_net_lib(gromet: &ModuleCollection, mut start: u32) -> Vec Vec } } // convert every node object into a node query - queries.append(&mut construct_memgraph_queries(&mut nodes, &mut edges, &mut meta_nodes, &mut queries.clone())); + queries.append(&mut construct_memgraph_queries( + &mut nodes, + &mut edges, + &mut meta_nodes, + &mut queries.clone(), + )); /*let create = String::from("CREATE"); for node in nodes.iter() { let mut name = String::from("a"); @@ -4605,7 +4615,7 @@ pub fn wff_wiring( // push the tgt if (wire.src as u32) == *p { wff_src_tgt.push(node.node_id.clone()); - prop = Some(i as usize); + prop = Some(i); } } } @@ -4632,7 +4642,7 @@ pub fn wff_wiring( if (wire.tgt as u32) == *p { wff_src_tgt.push(node.node_id.clone()); if node.n_type == "Abstract" { - refer = Some(i as usize); + refer = Some(i); } } } @@ -4648,7 +4658,7 @@ pub fn wff_wiring( tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), prop: Some(prop.unwrap()), - refer: refer, + refer, }; edges.push(e8); } @@ -5308,7 +5318,10 @@ pub fn wff_cross_att_wiring( && (tgt_box as u32) == node.box_counter as u32 { // only opo's - if node.n_type == "Primitive" || node.n_type == "Literal" || node.n_type == "Abstract" { + if node.n_type == "Primitive" + || node.n_type == "Literal" + || node.n_type == "Abstract" + { // iterate through port to check for tgt for p in node.out_idx.as_ref().unwrap().iter() { // push the src first, being pif @@ -5546,7 +5559,12 @@ pub fn parse_gromet_queries(gromet: ModuleCollection) -> Vec { } // convert every node object into a node query -pub fn construct_memgraph_queries(nodes: &mut Vec, edges: &mut Vec, meta_nodes: &mut Vec, queries: &mut Vec) -> Vec { +pub fn construct_memgraph_queries( + nodes: &mut Vec, + edges: &mut Vec, + meta_nodes: &mut Vec, + queries: &mut Vec, +) -> Vec { // convert every node object into a node query let create = String::from("CREATE"); for node in nodes.iter() { @@ -5558,45 +5576,51 @@ pub fn construct_memgraph_queries(nodes: &mut Vec, edges: &mut Vec, } // better parsing of values for inference later on. // handles case of parsing a list as a proper list object, only depth one though - // would need recursive function for aritrary depth. To be done at somepoint. + // would need recursive function for aritrary depth. To be done at somepoint. let value = match &node.value { - Some(val) => if val.value_type == *"List" && &val.value[0..1] == "[" && &val.value[1..2] != "]" { - let val_type = val.value_type.clone(); - let val_grom_type = val.gromet_type.as_ref().unwrap(); - let val_len = val.value[..].len(); - let val_val: Vec = val.value[1..val_len].split("}, ").map(|x| x.to_string()).collect(); - - let mut val_vec = Vec::::new(); - for (i, val) in val_val.iter().enumerate() { - if i == val_val.len() - 1 { - let val_string = format!("{}}}", &val[7..(val.len()-2)]); - val_vec.push(val_string.clone()); - } else { - let val_string = format!("{}}}", &val[7..]); - val_vec.push(val_string.clone()); + Some(val) => { + if val.value_type == *"List" && &val.value[0..1] == "[" && &val.value[1..2] != "]" { + let val_type = val.value_type.clone(); + let val_grom_type = val.gromet_type.as_ref().unwrap(); + let val_len = val.value[..].len(); + let val_val: Vec = val.value[1..val_len] + .split("}, ") + .map(|x| x.to_string()) + .collect(); + + let mut val_vec = Vec::::new(); + for (i, val) in val_val.iter().enumerate() { + if i == val_val.len() - 1 { + let val_string = format!("{}}}", &val[7..(val.len() - 2)]); + val_vec.push(val_string.clone()); + } else { + let val_string = format!("{}}}", &val[7..]); + val_vec.push(val_string.clone()); + } } + let mut final_val_vec = Vec::::new(); + for val_str in val_vec.iter() { + let val_fields: Vec = + val_str.split(", ").map(|x| x.to_string()).collect(); + let cor_val: Vec = + val_fields[1].split(": ").map(|x| x.to_string()).collect(); + let final_val = cor_val[1].replace("\\\"", ""); + final_val_vec.push(final_val.clone()); + } + format!( + "{{ value_type:{:?}, value:{:?}, gromet_type:{:?} }}", + val_type, final_val_vec, val_grom_type + ) + .replace("\\\"", "") + } else { + format!( + "{{ value_type:{:?}, value:{:?}, gromet_type:{:?} }}", + val.value_type, + val.value, + val.gromet_type.as_ref().unwrap() + ) } - let mut final_val_vec = Vec::::new(); - for val_str in val_vec.iter() { - let val_fields: Vec = val_str.split(", ").map(|x| x.to_string()).collect(); - let cor_val: Vec = val_fields[1].split(": ").map(|x| x.to_string()).collect(); - let final_val = cor_val[1].replace("\\\"", ""); - final_val_vec.push(final_val.clone()); - } - format!( - "{{ value_type:{:?}, value:{:?}, gromet_type:{:?} }}", - val_type, - final_val_vec, - val_grom_type - ).replace("\\\"", "") - } else { - format!( - "{{ value_type:{:?}, value:{:?}, gromet_type:{:?} }}", - val.value_type, - val.value, - val.gromet_type.as_ref().unwrap() - ) - }, + } None => String::from("\"\""), }; @@ -5639,7 +5663,12 @@ pub fn construct_memgraph_queries(nodes: &mut Vec, edges: &mut Vec, queries.push(set_query); } if edge.refer.is_some() { - let set_query = format!("set e{}{}.refer={}", edge.src, edge.tgt, edge.refer.unwrap()); + let set_query = format!( + "set e{}{}.refer={}", + edge.src, + edge.tgt, + edge.refer.unwrap() + ); queries.push(set_query); } } diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index bedd0ebe616..c0a5c0f05de 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -17,6 +17,7 @@ use neo4rs; use neo4rs::{query, Error}; use std::sync::Arc; +/// This struct is the node struct for the constructed petgraph #[derive(Clone, Debug)] pub struct ModelNode { id: i64, @@ -25,6 +26,7 @@ pub struct ModelNode { value: Option, } +/// This struct is the edge struct for the constructed petgraph #[derive(Clone, Debug)] pub struct ModelEdge { id: i64, @@ -65,8 +67,7 @@ pub async fn module_id2mathml_MET_ast(module_id: i64, config: Config) -> Vec Vec { let graph = subgraph2petgraph(module_id, config.clone()).await; @@ -177,7 +178,7 @@ fn tree_2_MET_ast( let mut lhs = Vec::::new(); if graph[root_node].label == *"Opo" { // we first construct the derivative of the first node - let deriv_name: &str = &graph[root_node].name.as_ref().unwrap(); + let deriv_name: &str = graph[root_node].name.as_ref().unwrap(); // this will let us know if additional trimming is needed to handle the code implementation of the equations // let mut step_impl = false; this will be used for step implementaion for later // This is very bespoke right now @@ -289,9 +290,7 @@ pub fn get_operator_MET( } else if *graph[root_node].name.as_ref().unwrap() == "ast.Div" { op.push(Operator::Divide); } else { - op.push(Operator::Other( - graph[root_node].name.clone().unwrap(), - )); + op.push(Operator::Other(graph[root_node].name.clone().unwrap())); } op[0].clone() } @@ -315,7 +314,14 @@ async fn trim_un_named( // one incoming one outgoing if bypass.len() == 2 { // annoyingly have to pull the edge/Relation to insert into graph - graph.add_edge(bypass[0], bypass[1], graph.edge_weight(graph.find_edge(bypass[0], node_index).unwrap()).unwrap().clone()); + graph.add_edge( + bypass[0], + bypass[1], + graph + .edge_weight(graph.find_edge(bypass[0], node_index).unwrap()) + .unwrap() + .clone(), + ); } else if bypass.len() > 2 { // this operates on the assumption that there maybe multiple references to the port // (incoming arrows) but only one outgoing arrow, this seems to be the case based on @@ -324,7 +330,14 @@ async fn trim_un_named( let end_node_idx = bypass.len() - 1; for (i, _ent) in bypass[0..end_node_idx].iter().enumerate() { // this iterates over all but the last entry in the bypass vec - graph.add_edge(bypass[i], bypass[end_node_idx], graph.edge_weight(graph.find_edge(bypass[i], node_index).unwrap()).unwrap().clone()); + graph.add_edge( + bypass[i], + bypass[end_node_idx], + graph + .edge_weight(graph.find_edge(bypass[i], node_index).unwrap()) + .unwrap() + .clone(), + ); } } } @@ -343,6 +356,7 @@ async fn trim_un_named( graph } +/// This function takes in a node id and returns a petgraph subgraph of only the wire type edges async fn subgraph_wiring( module_id: i64, config: Config, @@ -372,7 +386,7 @@ async fn subgraph_wiring( id: node.id(), label: node.labels()[0].clone(), name: node.get::("name"), - value: node.get::("value") + value: node.get::("value"), }; node_list.push(modelnode); } @@ -397,7 +411,7 @@ async fn subgraph_wiring( src_id: edge.start_node_id(), tgt_id: edge.end_node_id(), index: edge.get::("index"), - refer: edge.get::("refer") + refer: edge.get::("refer"), }; edge_list.push(modeledge); } @@ -430,6 +444,7 @@ async fn subgraph_wiring( Ok(graph) } +/// This function takes in a node id and returns a petgraph representing the memgraph async fn subgraph2petgraph( module_id: i64, config: Config, @@ -465,6 +480,7 @@ async fn subgraph2petgraph( graph } +/// This function takes in a node id and returns the nodes and edges in it pub async fn get_subgraph( module_id: i64, config: Config, @@ -495,7 +511,7 @@ pub async fn get_subgraph( id: node.id(), label: node.labels()[0].clone(), name: node.get::("name"), - value: node.get::("value") + value: node.get::("value"), }; node_list.push(modelnode); } @@ -519,7 +535,7 @@ pub async fn get_subgraph( src_id: edge.start_node_id(), tgt_id: edge.end_node_id(), index: edge.get::("index"), - refer: edge.get::("refer") + refer: edge.get::("refer"), }; edge_list.push(modeledge); } From 19361a73bbcf9f7ea9aa96597691dcc1a0a430ee Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 6 Dec 2023 11:03:06 -0700 Subject: [PATCH 06/10] added some comments --- skema/skema-rs/skema/src/model_extraction.rs | 62 ++++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index c0a5c0f05de..2821c75e63c 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -36,11 +36,32 @@ pub struct ModelEdge { refer: Option, } +/** + * This is the main function call for model extraction. + * + * Parameters: + * - module_id: i64 -> This is the top level id of the gromet module in memgraph. + * - config: Config -> This is a config struct for connecting to memgraph + * + * Returns: + * - Vector of FirstOrderODE -> This vector of structs is used to construct a PetriNet or RegNet further down the pipeline + * + * Assumptions: + * - As of right now, we can always assume the code has been sliced to only one relevant function which contains the + * core dynamics in it somewhere + * + * Notes: + * - FirstOrderODE is primarily composed of a LHS and a RHS, + * - LHS is just a Mi object of the state being differentiated. There are additional fields for the LHS but only the + * content field is used in downstream inference for now. + * - RHS is where the bulk of the inference happens, it produces an expression tree, hence the MET -> Math Expression Tree. + * Every operator has a vector of arguments. (order matters) + */ #[allow(non_snake_case)] pub async fn module_id2mathml_MET_ast(module_id: i64, config: Config) -> Vec { let mut core_dynamics_ast = Vec::::new(); - let core_id = find_pn_dynamics(module_id, config.clone()).await; // gives back list of function nodes that might contain the dynamics + let core_id = find_pn_dynamics(module_id, config.clone()).await; if core_id.is_empty() { let deriv = Ci { @@ -67,7 +88,15 @@ pub async fn module_id2mathml_MET_ast(module_id: i64, config: Config) -> Vec Vec { let graph = subgraph2petgraph(module_id, config.clone()).await; @@ -125,6 +154,12 @@ pub async fn find_pn_dynamics(module_id: i64, config: Config) -> Vec { core_id } + +/** + * Once the function node has been identified, this function takes it from there to extract the vector of FirstOrderODE's + * + * This is based heavily on the assumption that each equation is in a seperate expression which breaks for the vector case. + */ #[allow(non_snake_case)] pub async fn subgrapg2_core_dyn_MET_ast( root_node_id: i64, @@ -168,6 +203,10 @@ pub async fn subgrapg2_core_dyn_MET_ast( Ok(core_dynamics) } + +/** + * This function is designed to take in a petgraph instance of a wires only expression subgraph and output a FirstOrderODE equations representing it. + */ #[allow(non_snake_case)] fn tree_2_MET_ast( graph: &mut petgraph::Graph, @@ -222,6 +261,7 @@ fn tree_2_MET_ast( Ok(fo_eq_vec[0].clone()) } +/// This is a recursive function that walks along the wired subgraph of an expression to construct the expression tree #[allow(non_snake_case)] pub fn get_args_MET( graph: &petgraph::Graph, @@ -271,7 +311,7 @@ pub fn get_args_MET( ordered_args } -// this gets the operator from the node name +/// This gets the operator from the node name #[allow(non_snake_case)] #[allow(clippy::if_same_then_else)] pub fn get_operator_MET( @@ -295,7 +335,16 @@ pub fn get_operator_MET( op[0].clone() } -// this currently only works for un-named nodes that are not chained or have multiple incoming/outgoing edges +/** + * This function takes in a wiring only petgraph of an expression and trims off the un-named nodes and unpack nodes. + * + * This is done by creating new edges that bypass the un-named nodes and then deleting them from the graph. + * For deleting the unpacks, the assumption is they are always terminal in the subgraph and can be deleted freely. + * + * Concerns: + * - I don't think this will work if there are multiple un-named nodes changed together. I haven't seen this in practice, + * but I think it's possible. So something to keep in mind. + */ async fn trim_un_named( graph: &mut petgraph::Graph, ) -> &mut petgraph::Graph { @@ -356,7 +405,8 @@ async fn trim_un_named( graph } -/// This function takes in a node id and returns a petgraph subgraph of only the wire type edges +/// This function takes in a node id (typically that of an expression subgraph) and returns a +/// petgraph subgraph of only the wire type edges async fn subgraph_wiring( module_id: i64, config: Config, @@ -444,7 +494,7 @@ async fn subgraph_wiring( Ok(graph) } -/// This function takes in a node id and returns a petgraph representing the memgraph +/// This function takes in a node id and returns a petgraph represention of the memgraph graph async fn subgraph2petgraph( module_id: i64, config: Config, From e862aa743f1fe4788b0f5a0fa4d4e4cab9ab4bb0 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 6 Dec 2023 12:01:35 -0700 Subject: [PATCH 07/10] fixed some comments --- skema/skema-rs/skema/src/model_extraction.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index 2821c75e63c..abd9dd674b0 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -392,7 +392,7 @@ async fn trim_un_named( } } - // now we perform a filter_map to remove the un-named nodes and only the bypass edge will remain to connect the nodes + // now we remove the un-named nodes and only the bypass edge will remain to connect the nodes // we also remove the unpack node if it is present here as well for node_index in graph.node_indices().rev() { if graph[node_index].name.clone().unwrap() == *"un-named" @@ -535,7 +535,6 @@ pub async fn get_subgraph( module_id: i64, config: Config, ) -> Result<(Vec, Vec), Error> { - // construct the query that will delete the module with a given unique identifier let mut node_list = Vec::::new(); let mut edge_list = Vec::::new(); From c155343c99d37da88b55fdbc40028591d5f310fb Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 6 Dec 2023 18:12:02 -0700 Subject: [PATCH 08/10] preliminary support for SIDARTHE --- skema/skema-rs/skema/src/database.rs | 23 ++- skema/skema-rs/skema/src/model_extraction.rs | 177 +++++++++++++++---- 2 files changed, 164 insertions(+), 36 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index 4a6f3c24bfc..66ecaac44c1 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -3745,9 +3745,7 @@ pub fn create_att_expression( for att_sub_box in att_box.bf.as_ref().unwrap().iter() { new_c_args.box_counter = box_counter; new_c_args.cur_box = att_sub_box.clone(); - if att_sub_box.contents.is_some() { - new_c_args.att_idx = att_sub_box.contents.unwrap() as usize; - } + new_c_args.att_idx = c_args.att_idx.clone(); match att_sub_box.function_type { FunctionType::Literal => { create_att_literal( @@ -3769,6 +3767,17 @@ pub fn create_att_expression( new_c_args.clone(), ); } + FunctionType::Expression => { + new_c_args.att_idx = att_sub_box.contents.unwrap() as usize; + create_att_expression( + gromet, // gromet for metadata + nodes, // nodes + edges, + meta_nodes, + start, + new_c_args.clone(), + ); + } _ => {} } box_counter += 1; @@ -3784,6 +3793,14 @@ pub fn create_att_expression( c_args.bf_counter, ); + cross_att_wiring( + att_box.clone(), + nodes, + edges, + c_args.att_idx, + c_args.bf_counter, + ); + // Now we also perform wopio wiring in case there is an empty expression if att_box.wopio.is_some() { wopio_wiring(att_box, nodes, edges, c_args.att_idx - 1, c_args.bf_counter); diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index abd9dd674b0..865e6d11099 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -1,7 +1,9 @@ use crate::config::Config; +use crate::database::Node; use mathml::ast::operator::Operator; pub use mathml::mml2pn::{ACSet, Term}; use petgraph::prelude::*; +use petgraph::visit::IntoNeighborsDirected; use std::string::ToString; @@ -38,22 +40,22 @@ pub struct ModelEdge { /** * This is the main function call for model extraction. - * + * * Parameters: - * - module_id: i64 -> This is the top level id of the gromet module in memgraph. + * - module_id: i64 -> This is the top level id of the gromet module in memgraph. * - config: Config -> This is a config struct for connecting to memgraph - * + * * Returns: * - Vector of FirstOrderODE -> This vector of structs is used to construct a PetriNet or RegNet further down the pipeline - * + * * Assumptions: - * - As of right now, we can always assume the code has been sliced to only one relevant function which contains the + * - As of right now, we can always assume the code has been sliced to only one relevant function which contains the * core dynamics in it somewhere - * - * Notes: + * + * Notes: * - FirstOrderODE is primarily composed of a LHS and a RHS, * - LHS is just a Mi object of the state being differentiated. There are additional fields for the LHS but only the - * content field is used in downstream inference for now. + * content field is used in downstream inference for now. * - RHS is where the bulk of the inference happens, it produces an expression tree, hence the MET -> Math Expression Tree. * Every operator has a vector of arguments. (order matters) */ @@ -88,14 +90,14 @@ pub async fn module_id2mathml_MET_ast(module_id: i64, config: Config) -> Vec Vec { @@ -154,11 +156,10 @@ pub async fn find_pn_dynamics(module_id: i64, config: Config) -> Vec { core_id } - /** * Once the function node has been identified, this function takes it from there to extract the vector of FirstOrderODE's - * - * This is based heavily on the assumption that each equation is in a seperate expression which breaks for the vector case. + * + * This is based heavily on the assumption that each equation is in a seperate expression which breaks for the vector case. */ #[allow(non_snake_case)] pub async fn subgrapg2_core_dyn_MET_ast( @@ -184,8 +185,24 @@ pub async fn subgrapg2_core_dyn_MET_ast( let mut sub_w = subgraph_wiring(graph[expression_nodes[i]].id, config.clone()) .await .unwrap(); - if sub_w.node_count() > 3 { - let expr = trim_un_named(&mut sub_w).await; + let mut prim_counter = 0; + let mut has_call = false; + for node_index in sub_w.node_indices() { + if sub_w[node_index].label == "Primitive".to_string() { + prim_counter += 1; + if *sub_w[node_index].name.as_ref().unwrap() == "_call" { + has_call = true; + } + } + } + if sub_w.node_count() > 3 && !(prim_counter == 1 && has_call) && prim_counter != 0 { + println!("expression: {}", graph[expression_nodes[i]].id); + // the call expressions get referenced by multiple top level expressions, so deleting the nodes in it breaks the other graphs. Need to pass clone of expression subgraph so references to original has all the nodes. + if has_call { + sub_w = trim_calls(sub_w.clone()) + } + let expr = trim_un_named(&mut sub_w); + println!("node count post trimming: {:?}", expr.node_count()); let mut root_node = Vec::::new(); for node_index in expr.node_indices() { if expr[node_index].label.clone() == *"Opo" { @@ -203,9 +220,8 @@ pub async fn subgrapg2_core_dyn_MET_ast( Ok(core_dynamics) } - /** - * This function is designed to take in a petgraph instance of a wires only expression subgraph and output a FirstOrderODE equations representing it. + * This function is designed to take in a petgraph instance of a wires only expression subgraph and output a FirstOrderODE equations representing it. */ #[allow(non_snake_case)] fn tree_2_MET_ast( @@ -244,6 +260,7 @@ fn tree_2_MET_ast( let operate = get_operator_MET(graph, node); // output -> Operator let rhs_arg = get_args_MET(graph, node); // output -> Vec let rhs = MathExpressionTree::Cons(operate, rhs_arg); // MathExpressionTree + println!("rhs: {:?}", rhs.clone()); let rhs_flat = flatten_mults(rhs.clone()); let fo_eq = FirstOrderODE { lhs_var: lhs[0].clone(), @@ -336,16 +353,16 @@ pub fn get_operator_MET( } /** - * This function takes in a wiring only petgraph of an expression and trims off the un-named nodes and unpack nodes. - * - * This is done by creating new edges that bypass the un-named nodes and then deleting them from the graph. - * For deleting the unpacks, the assumption is they are always terminal in the subgraph and can be deleted freely. - * - * Concerns: - * - I don't think this will work if there are multiple un-named nodes changed together. I haven't seen this in practice, - * but I think it's possible. So something to keep in mind. + * This function takes in a wiring only petgraph of an expression and trims off the un-named nodes and unpack nodes. + * + * This is done by creating new edges that bypass the un-named nodes and then deleting them from the graph. + * For deleting the unpacks, the assumption is they are always terminal in the subgraph and can be deleted freely. + * + * Concerns: + * - I don't think this will work if there are multiple un-named nodes changed together. I haven't seen this in practice, + * but I think it's possible. So something to keep in mind. */ -async fn trim_un_named( +fn trim_un_named( graph: &mut petgraph::Graph, ) -> &mut petgraph::Graph { // first create a cloned version of the graph we can modify while iterating over it. @@ -363,6 +380,11 @@ async fn trim_un_named( // one incoming one outgoing if bypass.len() == 2 { // annoyingly have to pull the edge/Relation to insert into graph + println!( + "bypass[0]: {:?}, node_index: {:?}", + graph[bypass[0]].clone(), + graph[node_index].clone() + ); graph.add_edge( bypass[0], bypass[1], @@ -376,6 +398,8 @@ async fn trim_un_named( // (incoming arrows) but only one outgoing arrow, this seems to be the case based on // data too. + // SIDARTHE: failing if only an outgoing edge.... + let end_node_idx = bypass.len() - 1; for (i, _ent) in bypass[0..end_node_idx].iter().enumerate() { // this iterates over all but the last entry in the bypass vec @@ -405,7 +429,7 @@ async fn trim_un_named( graph } -/// This function takes in a node id (typically that of an expression subgraph) and returns a +/// This function takes in a node id (typically that of an expression subgraph) and returns a /// petgraph subgraph of only the wire type edges async fn subgraph_wiring( module_id: i64, @@ -535,7 +559,6 @@ pub async fn get_subgraph( module_id: i64, config: Config, ) -> Result<(Vec, Vec), Error> { - let mut node_list = Vec::::new(); let mut edge_list = Vec::::new(); @@ -591,3 +614,91 @@ pub async fn get_subgraph( Ok((node_list, edge_list)) } + +// this does special trimming to handle function calls +pub fn trim_calls( + graph: petgraph::Graph, +) -> petgraph::Graph { + + let mut graph_clone = graph.clone(); + + // find the call nodes + for node_index in graph.node_indices() { + if graph[node_index].clone().name.unwrap().clone() == *"_call" { + // we now trace up the incoming path until we hit a primitive, + // this will be the start node for the new edge. + + // initialize trackers + let mut node_start = node_index; + let mut node_end = node_index; + let mut inner_nodes = Vec::::new(); + + // find end node and track path + for node in graph.neighbors_directed(node_index, Outgoing) { + if graph.edge_weight(graph.find_edge(node_index, node).unwrap()).unwrap().index.unwrap() == 0 { + let mut temp = to_terminal(graph.clone(), node); + node_end = temp.0; + inner_nodes.append(&mut temp.1); + } + } + + // find start primtive node and track path + for node in graph.neighbors_directed(node_index, Incoming) { + let mut temp = to_primitive(graph.clone(), node); + node_start = temp.0; + inner_nodes.append(&mut temp.1); + } + + // add edge from start to end node, with weight from start node a matching outgoing node form it + for node in graph.clone().neighbors_directed(node_start, Outgoing) { + for node_p in inner_nodes.iter() { + if node == *node_p { + graph_clone.add_edge(node_start, node_end, graph.clone().edge_weight(graph.clone().find_edge(node_start, node).unwrap()).unwrap().clone()); + } + } + } + // we keep track all the node indexes we found while tracing the path and delete all + // intermediate nodes. + for node in inner_nodes.iter() { + graph_clone.remove_node(*node); + } + } + } + + graph_clone +} + +// outgoing walker to terminal node +pub fn to_terminal(graph: petgraph::Graph, node_index: NodeIndex) -> (NodeIndex, Vec) { + let mut node_vec = Vec::::new(); + let mut end_node = node_index; + // if there another node deeper + // else pass original input node out and an empty path vector + if graph.neighbors_directed(node_index, Outgoing).count() != 0 { + node_vec.push(node_index); // add current node to path list + for node in graph.neighbors_directed(node_index, Outgoing) { + // pass next node forward + let mut temp = to_terminal(graph.clone(), node); + end_node = temp.0; // make end_node + node_vec.append(&mut temp.1); // append previous path nodes + } + } + (end_node, node_vec) +} + +// incoming walker to first primitive +pub fn to_primitive(graph: petgraph::Graph, node_index: NodeIndex) -> (NodeIndex, Vec) { + let mut node_vec = Vec::::new(); + let mut end_node = node_index; + node_vec.push(node_index); + for node in graph.neighbors_directed(node_index, Outgoing) { + if graph[node].label.clone() != *"Primtive" { + let mut temp = to_primitive(graph.clone(), node); + end_node = temp.0; + node_vec.append(&mut temp.1); + } else { + end_node = node; + } + } + (end_node, node_vec) +} From f3ecbda0c73616c4ef1a167168f17d18c7df2915 Mon Sep 17 00:00:00 2001 From: Free-Quarks Date: Thu, 7 Dec 2023 13:02:03 -0700 Subject: [PATCH 09/10] SIDARTHE prelimenary support --- skema/skema-rs/skema/src/database.rs | 5 +- skema/skema-rs/skema/src/model_extraction.rs | 83 ++++++++++++++------ 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index 66ecaac44c1..eefbb18dc2f 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -5212,6 +5212,7 @@ pub fn wff_cross_att_wiring( bf_counter: u8, // this is the current box ) { for wire in eboxf.wff.as_ref().unwrap().iter() { + let mut prop = None; // collect info to identify the opi src node let src_idx = wire.src; // port index let src_pif = eboxf.pif.as_ref().unwrap()[(src_idx - 1) as usize].clone(); // src port @@ -5407,10 +5408,11 @@ pub fn wff_cross_att_wiring( // only opo's if node.n_type == "Primitive" || node.n_type == "Abstract" { // iterate through port to check for tgt - for p in node.in_indx.as_ref().unwrap().iter() { + for (i, p) in node.in_indx.as_ref().unwrap().iter().enumerate() { // push the src first, being pif if (src_idx as u32) == *p { wff_src_tgt.push(node.node_id.clone()); + prop = Some(i); } } } @@ -5442,6 +5444,7 @@ pub fn wff_cross_att_wiring( src: wff_src_tgt[0].clone(), tgt: wff_src_tgt[1].clone(), e_type: String::from("Wire"), + prop: Some(prop.unwrap()), ..Default::default() }; edges.push(e8); diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index 865e6d11099..18189cdac48 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -2,6 +2,7 @@ use crate::config::Config; use crate::database::Node; use mathml::ast::operator::Operator; pub use mathml::mml2pn::{ACSet, Term}; +use petgraph::matrix_graph::node_index; use petgraph::prelude::*; use petgraph::visit::IntoNeighborsDirected; @@ -199,10 +200,13 @@ pub async fn subgrapg2_core_dyn_MET_ast( println!("expression: {}", graph[expression_nodes[i]].id); // the call expressions get referenced by multiple top level expressions, so deleting the nodes in it breaks the other graphs. Need to pass clone of expression subgraph so references to original has all the nodes. if has_call { + println!("trimmed calls"); + println!("node count pre call trimming: {:?}", sub_w.node_count()); sub_w = trim_calls(sub_w.clone()) } + println!("node count post call trimming: {:?}", sub_w.node_count()); let expr = trim_un_named(&mut sub_w); - println!("node count post trimming: {:?}", expr.node_count()); + println!("node count post un-named trimming: {:?}", expr.node_count()); let mut root_node = Vec::::new(); for node_index in expr.node_indices() { if expr[node_index].label.clone() == *"Opo" { @@ -371,14 +375,15 @@ fn trim_un_named( for node_index in graph.node_indices() { if graph[node_index].clone().name.unwrap().clone() == *"un-named" { let mut bypass = Vec::::new(); + let mut outgoing_bypass = Vec::::new(); for node1 in graph.neighbors_directed(node_index, Incoming) { bypass.push(node1); } for node2 in graph.neighbors_directed(node_index, Outgoing) { - bypass.push(node2); + outgoing_bypass.push(node2); } // one incoming one outgoing - if bypass.len() == 2 { + if bypass.len() == 1 && outgoing_bypass.len() == 1 { // annoyingly have to pull the edge/Relation to insert into graph println!( "bypass[0]: {:?}, node_index: {:?}", @@ -387,25 +392,23 @@ fn trim_un_named( ); graph.add_edge( bypass[0], - bypass[1], + outgoing_bypass[0], graph .edge_weight(graph.find_edge(bypass[0], node_index).unwrap()) .unwrap() .clone(), ); - } else if bypass.len() > 2 { + } else if bypass.len() >= 2 && outgoing_bypass.len() == 1 { // this operates on the assumption that there maybe multiple references to the port // (incoming arrows) but only one outgoing arrow, this seems to be the case based on // data too. - // SIDARTHE: failing if only an outgoing edge.... - let end_node_idx = bypass.len() - 1; - for (i, _ent) in bypass[0..end_node_idx].iter().enumerate() { + for (i, _ent) in bypass.iter().enumerate() { // this iterates over all but the last entry in the bypass vec graph.add_edge( bypass[i], - bypass[end_node_idx], + outgoing_bypass[0], graph .edge_weight(graph.find_edge(bypass[i], node_index).unwrap()) .unwrap() @@ -619,23 +622,29 @@ pub async fn get_subgraph( pub fn trim_calls( graph: petgraph::Graph, ) -> petgraph::Graph { - let mut graph_clone = graph.clone(); + // This will be all the nodes to be deleted + let mut inner_nodes = Vec::::new(); // find the call nodes for node_index in graph.node_indices() { if graph[node_index].clone().name.unwrap().clone() == *"_call" { // we now trace up the incoming path until we hit a primitive, // this will be the start node for the new edge. - + // initialize trackers let mut node_start = node_index; let mut node_end = node_index; - let mut inner_nodes = Vec::::new(); // find end node and track path for node in graph.neighbors_directed(node_index, Outgoing) { - if graph.edge_weight(graph.find_edge(node_index, node).unwrap()).unwrap().index.unwrap() == 0 { + if graph + .edge_weight(graph.find_edge(node_index, node).unwrap()) + .unwrap() + .index + .unwrap() + == 0 + { let mut temp = to_terminal(graph.clone(), node); node_end = temp.0; inner_nodes.append(&mut temp.1); @@ -652,24 +661,41 @@ pub fn trim_calls( // add edge from start to end node, with weight from start node a matching outgoing node form it for node in graph.clone().neighbors_directed(node_start, Outgoing) { for node_p in inner_nodes.iter() { - if node == *node_p { - graph_clone.add_edge(node_start, node_end, graph.clone().edge_weight(graph.clone().find_edge(node_start, node).unwrap()).unwrap().clone()); + if node == *node_p { + graph_clone.add_edge( + node_start, + node_end, + graph + .clone() + .edge_weight(graph.clone().find_edge(node_start, node).unwrap()) + .unwrap() + .clone(), + ); } } } // we keep track all the node indexes we found while tracing the path and delete all - // intermediate nodes. - for node in inner_nodes.iter() { - graph_clone.remove_node(*node); - } + // intermediate nodes. + inner_nodes.push(node_index); } } + inner_nodes.sort(); + for node in inner_nodes.iter().rev() { + println!( + "node_index: {:?}, node name: {:?}", + node, + graph_clone.clone()[*node].name.clone().unwrap() + ); + graph_clone.remove_node(*node); + } graph_clone } -// outgoing walker to terminal node -pub fn to_terminal(graph: petgraph::Graph, node_index: NodeIndex) -> (NodeIndex, Vec) { +pub fn to_terminal( + graph: petgraph::Graph, + node_index: NodeIndex, +) -> (NodeIndex, Vec) { let mut node_vec = Vec::::new(); let mut end_node = node_index; // if there another node deeper @@ -682,17 +708,21 @@ pub fn to_terminal(graph: petgraph::Graph, node_index: Nod end_node = temp.0; // make end_node node_vec.append(&mut temp.1); // append previous path nodes } - } + } + println!("to terminal node_vec step: {:?}", node_vec.clone()); (end_node, node_vec) } -// incoming walker to first primitive -pub fn to_primitive(graph: petgraph::Graph, node_index: NodeIndex) -> (NodeIndex, Vec) { +// incoming walker to first primitive (NOTE: assumes input is not a primitive) +pub fn to_primitive( + graph: petgraph::Graph, + node_index: NodeIndex, +) -> (NodeIndex, Vec) { let mut node_vec = Vec::::new(); let mut end_node = node_index; node_vec.push(node_index); - for node in graph.neighbors_directed(node_index, Outgoing) { - if graph[node].label.clone() != *"Primtive" { + for node in graph.neighbors_directed(node_index, Incoming) { + if graph[node].label.clone() != *"Primitive" { let mut temp = to_primitive(graph.clone(), node); end_node = temp.0; node_vec.append(&mut temp.1); @@ -700,5 +730,6 @@ pub fn to_primitive(graph: petgraph::Graph, node_index: No end_node = node; } } + println!("to primitive node_vec step: {:?}", node_vec.clone()); (end_node, node_vec) } From 380bf25a2dee7f07c696adfe5d40eeca564e02e8 Mon Sep 17 00:00:00 2001 From: Free-Quarks Date: Thu, 7 Dec 2023 13:05:01 -0700 Subject: [PATCH 10/10] cleaned up prints and fmt --- skema/skema-rs/skema/src/database.rs | 2 +- skema/skema-rs/skema/src/model_extraction.rs | 26 +++----------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/skema/skema-rs/skema/src/database.rs b/skema/skema-rs/skema/src/database.rs index eefbb18dc2f..9e3fbdd8746 100644 --- a/skema/skema-rs/skema/src/database.rs +++ b/skema/skema-rs/skema/src/database.rs @@ -3745,7 +3745,7 @@ pub fn create_att_expression( for att_sub_box in att_box.bf.as_ref().unwrap().iter() { new_c_args.box_counter = box_counter; new_c_args.cur_box = att_sub_box.clone(); - new_c_args.att_idx = c_args.att_idx.clone(); + new_c_args.att_idx = c_args.att_idx; match att_sub_box.function_type { FunctionType::Literal => { create_att_literal( diff --git a/skema/skema-rs/skema/src/model_extraction.rs b/skema/skema-rs/skema/src/model_extraction.rs index 18189cdac48..505227309a0 100644 --- a/skema/skema-rs/skema/src/model_extraction.rs +++ b/skema/skema-rs/skema/src/model_extraction.rs @@ -1,8 +1,8 @@ use crate::config::Config; -use crate::database::Node; + use mathml::ast::operator::Operator; pub use mathml::mml2pn::{ACSet, Term}; -use petgraph::matrix_graph::node_index; + use petgraph::prelude::*; use petgraph::visit::IntoNeighborsDirected; @@ -189,7 +189,7 @@ pub async fn subgrapg2_core_dyn_MET_ast( let mut prim_counter = 0; let mut has_call = false; for node_index in sub_w.node_indices() { - if sub_w[node_index].label == "Primitive".to_string() { + if sub_w[node_index].label == *"Primitive" { prim_counter += 1; if *sub_w[node_index].name.as_ref().unwrap() == "_call" { has_call = true; @@ -200,13 +200,9 @@ pub async fn subgrapg2_core_dyn_MET_ast( println!("expression: {}", graph[expression_nodes[i]].id); // the call expressions get referenced by multiple top level expressions, so deleting the nodes in it breaks the other graphs. Need to pass clone of expression subgraph so references to original has all the nodes. if has_call { - println!("trimmed calls"); - println!("node count pre call trimming: {:?}", sub_w.node_count()); sub_w = trim_calls(sub_w.clone()) } - println!("node count post call trimming: {:?}", sub_w.node_count()); let expr = trim_un_named(&mut sub_w); - println!("node count post un-named trimming: {:?}", expr.node_count()); let mut root_node = Vec::::new(); for node_index in expr.node_indices() { if expr[node_index].label.clone() == *"Opo" { @@ -214,7 +210,7 @@ pub async fn subgrapg2_core_dyn_MET_ast( } } if root_node.len() >= 2 { - // println!("More than one Opo! Skipping Expression!"); + println!("More than one Opo! Skipping Expression!"); } else { core_dynamics.push(tree_2_MET_ast(expr, root_node[0]).unwrap()); } @@ -264,7 +260,6 @@ fn tree_2_MET_ast( let operate = get_operator_MET(graph, node); // output -> Operator let rhs_arg = get_args_MET(graph, node); // output -> Vec let rhs = MathExpressionTree::Cons(operate, rhs_arg); // MathExpressionTree - println!("rhs: {:?}", rhs.clone()); let rhs_flat = flatten_mults(rhs.clone()); let fo_eq = FirstOrderODE { lhs_var: lhs[0].clone(), @@ -385,11 +380,6 @@ fn trim_un_named( // one incoming one outgoing if bypass.len() == 1 && outgoing_bypass.len() == 1 { // annoyingly have to pull the edge/Relation to insert into graph - println!( - "bypass[0]: {:?}, node_index: {:?}", - graph[bypass[0]].clone(), - graph[node_index].clone() - ); graph.add_edge( bypass[0], outgoing_bypass[0], @@ -403,7 +393,6 @@ fn trim_un_named( // (incoming arrows) but only one outgoing arrow, this seems to be the case based on // data too. - let end_node_idx = bypass.len() - 1; for (i, _ent) in bypass.iter().enumerate() { // this iterates over all but the last entry in the bypass vec graph.add_edge( @@ -681,11 +670,6 @@ pub fn trim_calls( } inner_nodes.sort(); for node in inner_nodes.iter().rev() { - println!( - "node_index: {:?}, node name: {:?}", - node, - graph_clone.clone()[*node].name.clone().unwrap() - ); graph_clone.remove_node(*node); } @@ -709,7 +693,6 @@ pub fn to_terminal( node_vec.append(&mut temp.1); // append previous path nodes } } - println!("to terminal node_vec step: {:?}", node_vec.clone()); (end_node, node_vec) } @@ -730,6 +713,5 @@ pub fn to_primitive( end_node = node; } } - println!("to primitive node_vec step: {:?}", node_vec.clone()); (end_node, node_vec) }