Constrained Variables
Variables in inference goals and rules can carry constraints that restrict their possible values. The SDK provides the guard() builder for arithmetic constraints and the allen() builder for temporal interval relations.
The guard() builder
The guard() function creates a constraint as a TermInputDto representing a guard sort with op and right features.
import { guard, psi, constrained } from '@kortexya/reasoninglayer';
// Find employees with salary > 100000const goal = psi('employee', { name: '?Name', salary: constrained('?Salary', guard('gt', 100000)),});
const result = await client.inference.backwardChain({ goal });The guard() call produces this JSON:
{ "sortName": "guard_constraint", "features": { "op": "gt", "right": 100000 }}Guard operators
All six comparison operators are supported via the GuardOp type:
| Operator | Meaning | Example |
|---|---|---|
lt | Less than | guard('lt', 50) |
lte | Less than or equal | guard('lte', 50) |
gt | Greater than | guard('gt', 100) |
gte | Greater than or equal | guard('gte', 18) |
eq | Equal | guard('eq', 42) |
ne | Not equal | guard('ne', 0) |
The right operand can be a number, string, or boolean:
// Numeric constraintsguard('gt', 100); // > 100guard('lte', 1000.50); // <= 1000.50
// String constraintsguard('eq', 'active'); // == "active"guard('ne', 'deleted'); // != "deleted"
// Boolean constraintsguard('eq', true); // == trueConstrained variables
Use constrained() to attach a constraint to a variable. The first argument is the variable name, the second is the constraint as a TermInputDto.
// Variable with a guard constraintconst salary = constrained('?Salary', guard('gt', 50000));
// Variable with a custom constraint sortconst rating = constrained( '?Rating', psi('range_check', { min: 1, max: 5, }),);Unconstrained variables
Use a plain string for variables without constraints:
const name = '?Name'; // matches anythingCombining constraints in a goal
Build complex query goals with multiple constrained variables:
const goal = psi('employee', { name: '?Name', department: 'engineering', salary: constrained('?Salary', guard('gte', 80000)), age: constrained('?Age', guard('lt', 40)), active: true,});
const result = await client.inference.backwardChain({ goal, maxSolutions: 20,});
for (const solution of result.solutions) { for (const binding of solution.substitution.bindings) { console.log(`${binding.variableName} = ${binding.boundToDisplay}`); }}Allen temporal relations
The allen() builder creates temporal interval constraints based on Allen’s interval algebra. This is used for reasoning about time relationships between events.
import { allen } from '@kortexya/reasoninglayer';
const constraint = allen('before', 'event_a_time', 'event-b-term-uuid');This produces:
{ "type": "Allen", "intervalA": "event_a_time", "intervalBTermId": "event-b-term-uuid", "relation": "before"}The 13 Allen relations
| Relation | Meaning | Diagram |
|---|---|---|
before | A ends before B starts | AAA...BBB |
after | A starts after B ends | BBB...AAA |
meets | A ends exactly when B starts | AAABBB |
met_by | A starts exactly when B ends | BBBAAA |
overlaps | A starts before B and ends during B | AABB with overlap |
overlapped_by | B starts before A and ends during A | BBAA with overlap |
during | A is contained within B | B[A]B |
contains | B is contained within A | A[B]A |
starts | A starts at the same time as B, ends earlier | [AB]B |
started_by | B starts at the same time as A, ends earlier | [BA]A |
finishes | A ends at the same time as B, starts later | B[BA] |
finished_by | B ends at the same time as A, starts later | A[AB] |
equals | A and B have the same start and end | [AB] |
Using Allen constraints with backward chaining
Allen constraints are passed in the constraints field of a backward chain request:
const result = await client.inference.backwardChain({ goal: psi('schedule_conflict', { event: '?Event', }), constraints: [ allen('overlaps', 'meeting_time', meetingTermId), allen('during', 'lunch_time', workdayTermId), ],});Practical example: event scheduling
// Find events that must happen before a deadlineconst result = await client.inference.backwardChain({ goal: psi('task', { name: '?TaskName', due: '?Due', }), constraints: [ allen('before', '?Due', deadlineTermId), ], maxSolutions: 50,});Other constraint types
The ConstraintInputDto type also supports equality and disequality constraints, which can be constructed as plain objects:
// Equality constraint: two variables must be the sameconst equality = { type: 'Equality' as const, var1: '?X', var2: '?Y' };
// Disequality constraint: two variables must differconst disequality = { type: 'Disequality' as const, var1: '?A', var2: '?B' };
const result = await client.inference.backwardChain({ goal: psi('pair', { first: '?X', second: '?Y', }), constraints: [disequality],});