// This program has been developed by students from the bachelor Computer Science at Utrecht // University within the Software Project course. // © Copyright Utrecht University (Department of Information and Computing Sciences) 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 BeliefGlobalReduce(beliefNode: Node, nodes: Node[]) { switch (beliefNode.type) { case 'basic_belief': return BasicBeliefReduce(beliefNode, nodes); case 'inferred_belief': return InferredBeliefReduce(beliefNode, nodes); } } 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; 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; } /** * 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); };