66 lines
3.0 KiB
TypeScript
66 lines
3.0 KiB
TypeScript
// 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);
|
|
}; |