feat: added rule to prevent cyclical connections between inferred belief nodes

ref: N25B-433
This commit is contained in:
JGerla
2026-01-13 08:52:50 +01:00
parent b869f7c071
commit f8acdda03c

View File

@@ -2,11 +2,12 @@ import {
type NodeProps,
Position,
type Node,
getConnectedEdges
getConnectedEdges, getOutgoers
} from '@xyflow/react';
import {useState} from "react";
import { Toolbar } from '../components/NodeComponents.tsx';
import styles from '../../VisProg.module.css';
import {type HandleRule, type RuleResult, ruleResult} from "../HandleRuleLogic.ts";
import {BeliefReduce} from "./BeliefReduce.ts";
import switchStyles from './InferredBeliefNode.module.css';
import {MultiConnectionHandle, SingleConnectionHandle} from "../components/RuleBasedHandle.tsx";
@@ -100,6 +101,30 @@ export function InferredBeliefDisconnectionSource(_thisNode: Node, _targetNodeId
// no additional connection logic exists yet
}
/**
* This rule makes it impossible to connect Inferred belief nodes
* if the connection would create a looping connection between inferred beliefs
*/
const noBeliefCycles : HandleRule = (connection, _): RuleResult => {
const { nodes, edges } = useFlowStore.getState();
function checkForCycle(targetNodeId: string, current: string) : RuleResult {
const outgoingBeliefs = getOutgoers({id: current}, 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("Cyclical connection exists between inferred beliefs");
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("Cyclical connection exists between inferred beliefs")
: checkForCycle(connection.source, connection.target);
}
/**
* Defines how a BasicBelief node should be rendered
* @param props - Node properties provided by React Flow, including `id` and `data`.
@@ -144,14 +169,17 @@ export default function InferredBeliefNode(props: NodeProps<InferredBeliefNode>)
{/* outgoing connections */}
<MultiConnectionHandle type="source" position={Position.Right} id="source" rules={[
allowOnlyConnectionsFromType(["norm", "trigger"]),
noBeliefCycles
]}/>
{/* incoming connections */}
<SingleConnectionHandle type="target" position={Position.Left} style={{top: '30%'}} id="beliefLeft" rules={[
allowOnlyConnectionsFromType(["basic_belief", "inferred_belief"]),
noBeliefCycles
]}/>
<SingleConnectionHandle type="target" position={Position.Left} style={{top: '70%'}} id="beliefRight" rules={[
allowOnlyConnectionsFromType(["basic_belief", "inferred_belief"]),
noBeliefCycles
]}/>
</div>
</>