diff --git a/backend/shared/src/binding_box/structs.rs b/backend/shared/src/binding_box/structs.rs index ed578d7..1f0dea0 100644 --- a/backend/shared/src/binding_box/structs.rs +++ b/backend/shared/src/binding_box/structs.rs @@ -161,6 +161,56 @@ pub enum BindingBoxTreeNode { AND(usize, usize), NOT(usize), } +const UNNAMED: &'static str = "UNNAMED - "; +impl BindingBoxTreeNode { + pub fn to_box(self) -> (BindingBox, Vec) { + match self { + BindingBoxTreeNode::Box(b, children) => (b, children), + BindingBoxTreeNode::OR(c1, c2) => ( + BindingBox { + new_event_vars: HashMap::default(), + new_object_vars: HashMap::default(), + filters: Vec::default(), + size_filters: Vec::default(), + constraints: vec![Constraint::OR { + child_names: vec![ + format!("{}{}", UNNAMED, c1), + format!("{}{}", UNNAMED, c2), + ], + }], + }, + vec![c1, c2], + ), + BindingBoxTreeNode::AND(c1, c2) => ( + BindingBox { + new_event_vars: HashMap::default(), + new_object_vars: HashMap::default(), + filters: Vec::default(), + size_filters: Vec::default(), + constraints: vec![Constraint::AND { + child_names: vec![ + format!("{}{}", UNNAMED, c1), + format!("{}{}", UNNAMED, c2), + ], + }], + }, + vec![c1, c2], + ), + BindingBoxTreeNode::NOT(c1) => ( + BindingBox { + new_event_vars: HashMap::default(), + new_object_vars: HashMap::default(), + filters: Vec::default(), + size_filters: Vec::default(), + constraints: vec![Constraint::NOT { + child_names: vec![format!("{}{}", UNNAMED, c1)], + }], + }, + vec![c1], + ), + } + } +} #[derive(TS)] #[ts(export, export_to = "../../../frontend/src/types/generated/")] @@ -192,11 +242,16 @@ impl BindingBoxTreeNode { tree: &BindingBoxTree, ocel: &IndexLinkedOCEL, ) -> (EvaluationResults, Vec<(Binding, Option)>) { - match self { - BindingBoxTreeNode::Box(bbox, children) => { + let (bbox,children) = match self.clone() { + BindingBoxTreeNode::Box(b, cs) => (b,cs), + x => { + x.to_box()} + }; + // match self { + // BindingBoxTreeNode::Box(bbox, children) => { let expanded: Vec = bbox.expand(vec![parent_binding.clone()], ocel); enum BindingResult { - FilteredOutBySizeFilter(Binding,EvaluationResults), + FilteredOutBySizeFilter(Binding, EvaluationResults), Sat(Binding, EvaluationResults), Viol(Binding, ViolationReason, EvaluationResults), } @@ -210,12 +265,12 @@ impl BindingBoxTreeNode { Vec<(Binding, Option)>, > = HashMap::new(); // let mut child_res = Vec::with_capacity(children.len()); - for c in children { + for c in &children { let c_name = tree .edge_names .get(&(own_index, *c)) .cloned() - .unwrap_or(format!("NO NAME PROVIDED - {c}")); + .unwrap_or(format!("{UNNAMED}{c}")); let (c_res, violations) = // Evaluate Child tree.nodes[*c].evaluate(*c, own_index, b.clone(), tree, ocel); @@ -254,7 +309,7 @@ impl BindingBoxTreeNode { } for sf in &bbox.size_filters { if !sf.check(&child_res) { - return BindingResult::FilteredOutBySizeFilter(b.clone(),all_res); + return BindingResult::FilteredOutBySizeFilter(b.clone(), all_res); } } for (constr_index, constr) in bbox.constraints.iter().enumerate() { @@ -288,7 +343,6 @@ impl BindingBoxTreeNode { } } Constraint::NOT { child_names } => { - let violated = !child_names.iter().all(|child_name| { if let Some(c_res) = child_res.get(child_name) { c_res.iter().any(|(_b, v)| v.is_some()) @@ -301,7 +355,7 @@ impl BindingBoxTreeNode { } else { None } - }, + } Constraint::OR { child_names } => { // println!("Child indices: {:?}, Children: {:?}", child_names, children); let any_sat = child_names.iter().any(|child_name| { @@ -318,7 +372,6 @@ impl BindingBoxTreeNode { } } Constraint::AND { child_names } => { - // println!("Child indices: {:?}, Children: {:?}", child_names, children); let any_sat = child_names.iter().all(|child_name| { if let Some(c_res) = child_res.get(child_name) { @@ -332,7 +385,7 @@ impl BindingBoxTreeNode { } else { Some(ViolationReason::ConstraintNotSatisfied(constr_index)) } - }, + } }; if let Some(vr) = viol { all_res.push((own_index, b.clone(), Some(vr))); @@ -344,17 +397,14 @@ impl BindingBoxTreeNode { }) .collect(); - - - re - .into_par_iter() + re.into_par_iter() .fold( || (EvaluationResults::new(), Vec::new()), |(mut a, mut b), x| match x { - BindingResult::FilteredOutBySizeFilter(_binding,r) => { + BindingResult::FilteredOutBySizeFilter(_binding, r) => { a.extend(r); - (a,b) - }, + (a, b) + } BindingResult::Sat(binding, r) => { a.extend(r); b.push((binding, None)); @@ -467,9 +517,9 @@ impl BindingBoxTreeNode { // (ret, Some(ViolationReason::ChildrenOfNOTSatisfied)) // } // } - _ => todo!(), - } - } + // _ => todo!(), + // } + // } } #[derive(TS)] @@ -589,7 +639,9 @@ impl SizeFilter { if let Some(c_res) = child_res.get(child_name) { if min.is_some_and(|min| c_res.len() < min) { false - } else { !max.is_some_and(|max| c_res.len() > max) } + } else { + !max.is_some_and(|max| c_res.len() > max) + } } else { false } @@ -625,9 +677,7 @@ impl SizeFilter { .iter() .map(|(binding, _)| match child_name_with_var_name[0].1 { Variable::Event(e_var) => binding.get_ev_index(&e_var).map(|e| e.0), - Variable::Object(o_var) => { - binding.get_ob_index(&o_var).map(|o| o.0) - } + Variable::Object(o_var) => binding.get_ob_index(&o_var).map(|o| o.0), }) .collect(); for (other_c, var) in child_name_with_var_name.iter().skip(1) { diff --git a/backend/shared/src/discovery/mod.rs b/backend/shared/src/discovery/mod.rs index 78fdb7f..299dde9 100644 --- a/backend/shared/src/discovery/mod.rs +++ b/backend/shared/src/discovery/mod.rs @@ -13,7 +13,9 @@ use serde::{Deserialize, Serialize}; use crate::{ binding_box::{ - structs::{BindingBoxTreeNode, EventVariable, Filter, ObjectVariable}, + structs::{ + BindingBoxTreeNode, Constraint, EventVariable, Filter, ObjectVariable, SizeFilter, + }, BindingBox, BindingBoxTree, }, preprocessing::{ @@ -55,6 +57,7 @@ impl EventuallyFollowsConstraints { } impl From<&EventuallyFollowsConstraints> for BindingBoxTree { fn from(val: &EventuallyFollowsConstraints) -> Self { + let child_name = "A".to_string(); let bbox0 = BindingBoxTreeNode::Box( BindingBox { new_event_vars: vec![( @@ -75,7 +78,13 @@ impl From<&EventuallyFollowsConstraints> for BindingBoxTree { qualifier: None, }], size_filters: vec![], - constraints: vec![], + constraints: vec![Constraint::SizeFilter { + filter: SizeFilter::NumChilds { + child_name: child_name.clone(), + min: Some(1), + max: None, + }, + }], }, vec![1], ); @@ -108,8 +117,7 @@ impl From<&EventuallyFollowsConstraints> for BindingBoxTree { ); BindingBoxTree { nodes: vec![bbox0, bbox1], - edge_names: HashMap::new(), - // size_constraints: vec![((0, 1), (Some(1), None))].into_iter().collect(), + edge_names: vec![((0, 1), child_name)].into_iter().collect(), } } } @@ -387,6 +395,7 @@ impl From<&SimpleDiscoveredCountConstraints> for BindingBoxTree { )], EventOrObject::Object => vec![], }; + let child_name = "A".to_string(); let bbox0 = BindingBoxTreeNode::Box( BindingBox { @@ -394,7 +403,13 @@ impl From<&SimpleDiscoveredCountConstraints> for BindingBoxTree { new_object_vars: new_ob.into_iter().collect(), filters: vec![], size_filters: vec![], - constraints: vec![], + constraints: vec![Constraint::SizeFilter { + filter: SizeFilter::NumChilds { + child_name: child_name.clone(), + min: Some(val.min_count), + max: Some(val.max_count), + }, + }], }, vec![1], ); @@ -450,7 +465,7 @@ impl From<&SimpleDiscoveredCountConstraints> for BindingBoxTree { ); BindingBoxTree { nodes: vec![bbox0, bbox1], - edge_names: HashMap::new(), + edge_names: vec![((0, 1), child_name)].into_iter().collect(), // size_constraints: vec![((0, 1), (Some(val.min_count), Some(val.max_count)))] // .into_iter() // .collect(), @@ -652,6 +667,7 @@ impl From<&AutoDiscoveredORConstraint> for BindingBoxTree { if !val.0.object_types.contains(&object_type) { panic!("!!! No object overlap in OR constraint"); } + let child_name_0 = "A".to_string(); let root_node = BindingBoxTreeNode::Box( BindingBox { new_event_vars: HashMap::default(), @@ -664,12 +680,32 @@ impl From<&AutoDiscoveredORConstraint> for BindingBoxTree { .collect(), filters: Vec::default(), size_filters: vec![], - constraints: vec![], + constraints: vec![Constraint::SAT { + child_names: vec![child_name_0.clone()], + }], }, vec![1], ); - let or_node = BindingBoxTreeNode::OR(2, 3); - let count_node = BindingBoxTreeNode::Box( + let child_name_1 = "B".to_string(); + let child_name_2 = "C".to_string(); + let or_node = BindingBoxTreeNode::OR(2, 4); + let count_node_1 = BindingBoxTreeNode::Box( + BindingBox { + new_event_vars: vec![].into_iter().collect(), + new_object_vars: HashMap::default(), + filters: vec![], + size_filters: vec![], + constraints: vec![Constraint::SizeFilter { + filter: SizeFilter::NumChilds { + child_name: child_name_1.clone(), + min: Some(1), + max: None, + }, + }], + }, + vec![3], + ); + let count_node_2 = BindingBoxTreeNode::Box( BindingBox { new_event_vars: vec![( EventVariable(0), @@ -703,9 +739,15 @@ impl From<&AutoDiscoveredORConstraint> for BindingBoxTree { qualifier: None, }], size_filters: vec![], - constraints: vec![], + constraints: vec![Constraint::SizeFilter { + filter: SizeFilter::NumChilds { + child_name: child_name_2.clone(), + min: Some(val.1.min_count), + max: Some(val.1.max_count), + }, + }], }, - vec![4], + vec![5], ); let ef_node2 = BindingBoxTreeNode::Box( @@ -737,134 +779,22 @@ impl From<&AutoDiscoveredORConstraint> for BindingBoxTree { ); BindingBoxTree { - nodes: vec![root_node, or_node, count_node, ef_node1, ef_node2], - edge_names: HashMap::new(), - // size_constraints: vec![ - // ((1, 2), (Some(val.1.min_count), Some(val.1.max_count))), - // ((3, 4), (Some(1), None)), - // ] - // .into_iter() - // .collect(), + nodes: vec![ + root_node, + or_node, + count_node_1, + count_node_2, + ef_node1, + ef_node2, + ], + edge_names: vec![ + ((0, 1), child_name_0), + ((2, 3), child_name_1), + ((4, 5), child_name_2), + ] + .into_iter() + .collect(), } - // Previous code (might be useful for merging arbitrary trees) - // let (tree1, tree2): (BindingBoxTree, BindingBoxTree) = match val { - // AutoDiscoveredORConstraint::EfOrCount(ef, cc) => { - // let tree1: BindingBoxTree = ef.into(); - // let mut tree2: BindingBoxTree = cc.into(); - // // Remove first node from tree2 & move size constraint to OR -> new first tree2 node - // tree2.nodes = tree2.nodes.into_iter().skip(1).collect(); - // tree2.size_constraints = tree2 - // .size_constraints - // .into_iter() - // .map(|orig_c| { - // let mut c = orig_c; - // c.0 = (0 - tree1.nodes.len() - 1, c.0 .1 - 1); - // c - // }) - // .collect(); - // (tree1, tree2) - // } - // AutoDiscoveredORConstraint::CountOrEf(cc, ef) => { - // let mut tree1: BindingBoxTree = cc.into(); - // let tree2: BindingBoxTree = ef.into(); - // // Remove first node from tree1 & move size constraint to OR -> new first tree1 node - // tree1.nodes = tree1.nodes.into_iter().skip(1).collect(); - // tree1.size_constraints = tree1 - // .size_constraints - // .into_iter() - // .map(|orig_c| { - // let mut c = orig_c; - // c.0 = (c.0 .0 - 1, c.0 .1 - 1); - // c - // }) - // .collect(); - // (tree1, tree2) - // } - // }; - // let root_objs = match tree1.nodes.first().unwrap() { - // BindingBoxTreeNode::Box(bbox, _) => bbox.new_object_vars.clone(), - // BindingBoxTreeNode::OR(_, _) => todo!(), - // BindingBoxTreeNode::AND(_, _) => todo!(), - // BindingBoxTreeNode::NOT(_) => todo!(), - // }; - - // let mut tree = BindingBoxTree { - // nodes: vec![ - // BindingBoxTreeNode::Box( - // BindingBox { - // new_event_vars: vec![].into_iter().collect(), - // new_object_vars: root_objs, - // filter_constraint: vec![], - // }, - // vec![1], - // ), - // BindingBoxTreeNode::OR(2, 2 + tree1.nodes.len()), - // ], - // size_constraints: vec![].into_iter().collect(), - // }; - // let mut prev_nodes = 2; - // let mut prev_ob_vars = 0; - // let mut prev_ev_vars = 0; - - // for tr in &[tree1, tree2] { - // for node in &tr.nodes { - // tree.nodes.push(match node { - // BindingBoxTreeNode::Box(bbox, cs) => BindingBoxTreeNode::Box( - // BindingBox { - // new_event_vars: bbox - // .new_event_vars - // .iter() - // .map(|(a, b)| (EventVariable(a.0 + prev_ev_vars), b.clone())) - // .collect(), - // new_object_vars: HashMap::new(), - // // new_object_vars: bbox - // // .new_object_vars - // // .iter() - // // .map(|(a, b)| (ObjectVariable(a.0 + prev_ob_vars), b.clone())) - // // .collect(), - // filter_constraint: bbox - // .filter_constraint - // .iter() - // .map(|fc| match fc { - // FilterConstraint::ObjectAssociatedWithEvent(ov, ev, q) => { - // FilterConstraint::ObjectAssociatedWithEvent( - // ObjectVariable(ov.0 + prev_ob_vars), - // EventVariable(ev.0 + prev_ev_vars), - // q.clone(), - // ) - // } - // FilterConstraint::ObjectAssociatedWithObject(ov1, ov2, q) => { - // FilterConstraint::ObjectAssociatedWithObject( - // ObjectVariable(ov1.0 + prev_ob_vars), - // ObjectVariable(ov2.0 + prev_ob_vars), - // q.clone(), - // ) - // } - // FilterConstraint::TimeBetweenEvents(ev1, ev2, t) => { - // FilterConstraint::TimeBetweenEvents( - // EventVariable(ev1.0 + prev_ev_vars), - // EventVariable(ev2.0 + prev_ev_vars), - // *t, - // ) - // } - // }) - // .collect(), - // }, - // cs.iter().map(|i| i + prev_nodes).collect_vec(), - // ), - // _ => todo!("Other box tree nodes are not supported for merging!"), - // }) - // } - // for ((n_index1, n_index2), size_constr) in &tr.size_constraints { - // tree.size_constraints - // .insert((n_index1 + prev_nodes, n_index2 + prev_nodes), *size_constr); - // } - // prev_nodes += tr.nodes.len(); - // prev_ev_vars += tr.get_ev_vars().len(); - // prev_ob_vars += 0; //tr.get_ob_vars().len(); - // } - - // tree } } diff --git a/frontend/src/routes/visual-editor/helper/constructNodes.ts b/frontend/src/routes/visual-editor/helper/constructNodes.ts index 0b54135..2af466f 100644 --- a/frontend/src/routes/visual-editor/helper/constructNodes.ts +++ b/frontend/src/routes/visual-editor/helper/constructNodes.ts @@ -328,14 +328,15 @@ export function bindingBoxTreeToNodes( return idPrefix + "-edge-" + fromIndex + "-to-" + toIndex; } - function getEdgeData(fromIndex: number, toIndex: number) { - const edgeData = tree.sizeConstraints.find( + function getEdgeData(fromIndex: number, toIndex: number) : EventTypeLinkData { + const edgeData = tree.edgeNames.find( ([[a, b]]) => a === fromIndex && b === toIndex, ); return { color: "#969696", - minCount: edgeData != null ? edgeData[1][0] : null, - maxCount: edgeData != null ? edgeData[1][1] : null, + minCount: null, + maxCount: null, + name: edgeData != null ? edgeData[1] : undefined }; } const treeNode = tree.nodes[index]; diff --git a/frontend/src/routes/visual-editor/helper/evaluation/evaluate-constraints.tsx b/frontend/src/routes/visual-editor/helper/evaluation/evaluate-constraints.tsx index de6b31a..e89ce32 100644 --- a/frontend/src/routes/visual-editor/helper/evaluation/evaluate-constraints.tsx +++ b/frontend/src/routes/visual-editor/helper/evaluation/evaluate-constraints.tsx @@ -9,6 +9,7 @@ import { Filter } from "@/types/generated/Filter"; import { SizeFilter } from "@/types/generated/SizeFilter"; import { Constraint } from "@/types/generated/Constraint"; import { formatSeconds } from "@/components/TimeDurationInput"; +import { Variable } from "@/types/generated/Variable"; export function getParentNodeID( nodeID: string, @@ -216,62 +217,30 @@ function predicateToLaTeX( return String.raw`${value.min ?? 0} \leq \left|\texttt{${ value.child_name }}\right| \leq ${value.max ?? "\\infty"}`; - // return ( - //
- // {value.min ?? 0} ≤ |{value.child_name}| ≤ {value.max ?? "∞"} - //
- // ); - // case "BindingSetEqual": - // return ( - //
- // {value.child_names.join(" = ") ?? 0} - //
- // ); - // case "BindingSetProjectionEqual": - // return ( - //
- // {value.child_name_with_var_name.map(([n, v], i) => ( - //
- // {n} - // - // {"["} - // {"Event" in v ? ( - // - // ) : ( - // - // )} - // {"]"} - // - // {i < value.child_name_with_var_name.length - 1 ? "=" : ""} - //
- // ))} - //
- // ); + case "AND": + return String.raw`\mathrm{AND}(${value.child_names.map(s => "\\texttt{"+s+"}").join(", ")})` + case "SAT": + return String.raw`\mathrm{SAT}(${value.child_names.map(s => "\\texttt{"+s+"}").join(", ")})` + case "NOT": + return String.raw`\mathrm{NOT}(${value.child_names.map(s => "\\texttt{"+s+"}").join(", ")})` + case "OR": + return String.raw`\mathrm{OR}(${value.child_names.map(s => "\\texttt{"+s+"}").join(", ")})` + case "BindingSetEqual": + return String.raw`${value.child_names.map(s => "\\texttt{"+s+"}").join(" = ")}` + case "BindingSetProjectionEqual": { + function varName(v: Variable){ + if("Event" in v){ + return "e" + (1 + v.Event) + }else{ + return "o" + (1 + v.Object) + } + } + return String.raw`${value.child_name_with_var_name.map(([s,v]) => "\\texttt{"+s+"}["+ varName(v) + "]").join(" = ")}` + } case "Filter": return predicateToLaTeX(value.filter); case "SizeFilter": return predicateToLaTeX(value.filter); - // case "SAT": - // return ( - //
- // SAT({value.child_names.map((i) => i).join(",")}) - //
- // ); - // case "NOT": - // return ( - //
- // NOT({value.child_names.map((i) => i).join(",")}) - //
- // ); - // case "OR": - // return ( - //
- // OR({value.child_names.map((i) => i).join(",")}) - //
- // ); - // case "AND": - // return `AND({value.child_names.map((i) => i).join(",")})` - // ); default: return "TODO"; } @@ -280,8 +249,9 @@ function predicateToLaTeX( function bindingTreeToTikzTree(tree: BindingBoxTree) { let s = String.raw` \begin{tikzpicture} - \graph [tree layout,sibling distance=15mm, level distance=20mm, nodes={align=center}] + \graph[tree layout, sibling distance=15mm, nodes={align=center},level 2/.style={level distance=15mm}] { + root [as={}]; `; const edgeNames = [...tree.edgeNames]; for (let i = 0; i < tree.nodes.length; i++) { @@ -297,6 +267,9 @@ function bindingTreeToTikzTree(tree: BindingBoxTree) { } } let i = 0; + s+= ` + root -> v0, +`; for(const [[from,to],name] of edgeNames){ s += String.raw` v${from} -> ["${name}"${i%2 === 0 ? ",swap" : ""}] v${to},` s += "\n"