diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/BeliefGlobals.ts b/src/pages/VisProgPage/visualProgrammingUI/nodes/BeliefGlobals.ts index 1299052..b92c5b2 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/nodes/BeliefGlobals.ts +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/BeliefGlobals.ts @@ -1,10 +1,10 @@ -import { type Node } from '@xyflow/react'; -import {type HandleRule, ruleResult} from "../HandleRuleLogic.ts"; +import {getOutgoers, type Node} from '@xyflow/react'; +import {type HandleRule, type RuleResult, ruleResult} from "../HandleRuleLogic.ts"; import useFlowStore from "../VisProgStores.tsx"; import {BasicBeliefReduce} from "./BasicBeliefNode.tsx"; import {type InferredBeliefNodeData, InferredBeliefReduce} from "./InferredBeliefNode.tsx"; -export function BeliefGlobals(beliefNode: Node, nodes: Node[]) { +export function BeliefGlobalReduce(beliefNode: Node, nodes: Node[]) { switch (beliefNode.type) { case 'basic_belief': return BasicBeliefReduce(beliefNode, nodes); @@ -17,9 +17,47 @@ export const noMatchingLeftRightBelief : HandleRule = (connection, _)=> { const { nodes } = useFlowStore.getState(); const thisNode = nodes.find(node => node.id === connection.target && node.type === 'inferred_belief'); if (!thisNode) return ruleResult.satisfied; - const iBelief = (thisNode.data as InferredBeliefNodeData).inferredBelief; + const iBelief = (thisNode.data as InferredBeliefNodeData).inferredBelief; return (iBelief.left === connection.source || iBelief.right === connection.source) ? ruleResult.notSatisfied("Connecting one belief to both input handles of an inferred belief node is not allowed") : ruleResult.satisfied; -} \ No newline at end of file +} +/** + * makes it impossible to connect Inferred belief nodes + * if the connection would create a cyclical connection between inferred beliefs + */ +export const noBeliefCycles: HandleRule = (connection, _): RuleResult => { + const {nodes, edges} = useFlowStore.getState(); + const defaultErrorMessage = "Cyclical connection exists between inferred beliefs"; + + /** + * recursively checks for cyclical connections between InferredBelief nodes + * + * to check for a cycle provide the source of an attempted connection as the targetNode for the cycle check, + * the currentNodeId should be initialised with the id of the targetNode of the attempted connection. + * + * @param {string} targetNodeId - the id of the node we are looking for as the endpoint of a cyclical connection + * @param {string} currentNodeId - the id of the node we are checking for outgoing connections to the provided target node + * @returns {RuleResult} + */ + function checkForCycle(targetNodeId: string, currentNodeId: string): RuleResult { + const outgoingBeliefs = getOutgoers({id: currentNodeId}, nodes, edges) + .filter(node => node.type === 'inferred_belief'); + + if (outgoingBeliefs.length === 0) return ruleResult.satisfied; + if (outgoingBeliefs.some(node => node.id === targetNodeId)) return ruleResult + .notSatisfied(defaultErrorMessage); + + const next = outgoingBeliefs.map(node => checkForCycle(targetNodeId, node.id)) + .find(result => !result.isSatisfied); + + return next + ? next + : ruleResult.satisfied; + } + + return connection.source === connection.target + ? ruleResult.notSatisfied(defaultErrorMessage) + : checkForCycle(connection.source, connection.target); +}; \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/InferredBeliefNode.tsx b/src/pages/VisProgPage/visualProgrammingUI/nodes/InferredBeliefNode.tsx index 9e6df6b..3a8563d 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/nodes/InferredBeliefNode.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/InferredBeliefNode.tsx @@ -1,17 +1,11 @@ -import { - type NodeProps, - Position, - type Node, - getConnectedEdges, getOutgoers -} from '@xyflow/react'; +import {getConnectedEdges, type Node, type NodeProps, Position} from '@xyflow/react'; import {useState} from "react"; -import { Toolbar } from '../components/NodeComponents.tsx'; -import {type HandleRule, type RuleResult, ruleResult} from "../HandleRuleLogic.ts"; -import {BeliefGlobals, noMatchingLeftRightBelief} from "./BeliefGlobals.ts"; +import styles from '../../VisProg.module.css'; +import {Toolbar} from '../components/NodeComponents.tsx'; import {MultiConnectionHandle, SingleConnectionHandle} from "../components/RuleBasedHandle.tsx"; import {allowOnlyConnectionsFromType} from "../HandleRules.ts"; import useFlowStore from "../VisProgStores.tsx"; -import styles from '../../VisProg.module.css'; +import {BeliefGlobalReduce, noBeliefCycles, noMatchingLeftRightBelief} from "./BeliefGlobals.ts"; import switchStyles from './InferredBeliefNode.module.css'; @@ -87,45 +81,6 @@ export function InferredBeliefDisconnectionSource(_thisNode: Node, _targetNodeId // no additional connection logic exists yet } -/** - * makes it impossible to connect Inferred belief nodes - * if the connection would create a cyclical connection between inferred beliefs - */ -const noBeliefCycles : HandleRule = (connection, _): RuleResult => { - const { nodes, edges } = useFlowStore.getState(); - const defaultErrorMessage = "Cyclical connection exists between inferred beliefs"; - - /** - * recursively checks for cyclical connections between InferredBelief nodes - * - * to check for a cycle provide the source of an attempted connection as the targetNode for the cycle check, - * the currentNodeId should be initialised with the id of the targetNode of the attempted connection. - * - * @param {string} targetNodeId - the id of the node we are looking for as the endpoint of a cyclical connection - * @param {string} currentNodeId - the id of the node we are checking for outgoing connections to the provided target node - * @returns {RuleResult} - */ - function checkForCycle(targetNodeId: string, currentNodeId: string) : RuleResult { - const outgoingBeliefs = getOutgoers({id: currentNodeId}, nodes, edges) - .filter(node => node.type === 'inferred_belief'); - - if (outgoingBeliefs.length === 0) return ruleResult.satisfied; - if (outgoingBeliefs.some(node => node.id === targetNodeId)) return ruleResult - .notSatisfied(defaultErrorMessage); - - const next = outgoingBeliefs.map(node => checkForCycle(targetNodeId, node.id)) - .find(result => !result.isSatisfied); - - return next - ? next - : ruleResult.satisfied; - } - - return connection.source === connection.target - ? ruleResult.notSatisfied(defaultErrorMessage) - : checkForCycle(connection.source, connection.target); -} - /** @@ -210,9 +165,9 @@ export function InferredBeliefReduce(node: Node, nodes: Node[]) { const result: Record = { id: node.id, - left: BeliefGlobals(leftBelief, nodes), + left: BeliefGlobalReduce(leftBelief, nodes), operator: data.inferredBelief.operator ? "AND" : "OR", - right: BeliefGlobals(rightBelief, nodes), + right: BeliefGlobalReduce(rightBelief, nodes), }; return result diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx b/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx index 380f1ad..e838ab0 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.tsx @@ -9,7 +9,7 @@ import { TextField } from '../../../../components/TextField'; import {MultiConnectionHandle, SingleConnectionHandle} from "../components/RuleBasedHandle.tsx"; import {allowOnlyConnectionsFromHandle, allowOnlyConnectionsFromType} from "../HandleRules.ts"; import useFlowStore from '../VisProgStores'; -import {BeliefGlobals} from "./BeliefGlobals.ts"; +import {BeliefGlobalReduce} from "./BeliefGlobals.ts"; /** * The default data dot a phase node @@ -108,7 +108,7 @@ export function NormReduce(node: Node, nodes: Node[]) { const conditionNode = nodes.find((node) => node.id === data.condition); // In case something went wrong, and our condition doesn't actually exist; if (conditionNode == undefined) return result; - result["condition"] = BeliefGlobals(conditionNode, nodes) + result["condition"] = BeliefGlobalReduce(conditionNode, nodes) } return result } diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx b/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx index 2bdc586..8332050 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx @@ -12,7 +12,7 @@ import {allowOnlyConnectionsFromHandle, allowOnlyConnectionsFromType} from "../H import useFlowStore from '../VisProgStores'; import { PlanReduce, type Plan } from '../components/Plan'; import PlanEditorDialog from '../components/PlanEditor'; -import {BeliefGlobals} from "./BeliefGlobals.ts"; +import {BeliefGlobalReduce} from "./BeliefGlobals.ts"; /** * The default data structure for a Trigger node @@ -92,7 +92,7 @@ export default function TriggerNode(props: NodeProps) { export function TriggerReduce(node: Node, nodes: Node[]) { const data = node.data as TriggerNodeData; const conditionNode = data.condition ? nodes.find((n)=>n.id===data.condition) : undefined - const conditionData = conditionNode ? BeliefGlobals(conditionNode, nodes) : "" + const conditionData = conditionNode ? BeliefGlobalReduce(conditionNode, nodes) : "" return { id: node.id, condition: conditionData, // Make sure we have a condition before reducing, or default to ""