@orkestrel/reason 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.cjs +328 -381
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +27 -10
- package/dist/src/core/index.d.ts +27 -10
- package/dist/src/core/index.js +328 -382
- package/dist/src/core/index.js.map +1 -1
- package/package.json +15 -15
package/dist/src/core/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _orkestrel_contract = require("@orkestrel/contract");
|
|
3
3
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
4
|
-
|
|
4
|
+
// src/core/constants.ts
|
|
5
5
|
/**
|
|
6
6
|
* Holds the default `bail` for the `Reason` orchestrator — a reasoner throw is rethrown
|
|
7
7
|
* after the `error` emit. Default: `true`.
|
|
@@ -98,8 +98,7 @@ var DEFINITION_BUILDER_BRAND = Symbol("reasons.definitionBuilder");
|
|
|
98
98
|
* match the other's guard.
|
|
99
99
|
*/
|
|
100
100
|
var SUBJECT_BUILDER_BRAND = Symbol("reasons.subjectBuilder");
|
|
101
|
-
|
|
102
|
-
//#region src/core/errors.ts
|
|
101
|
+
// src/core/errors.ts
|
|
103
102
|
/**
|
|
104
103
|
* Represents an error thrown by the reasons layer.
|
|
105
104
|
*
|
|
@@ -123,6 +122,7 @@ var ReasonError = class extends Error {
|
|
|
123
122
|
context;
|
|
124
123
|
constructor(code, message, context) {
|
|
125
124
|
super(message);
|
|
125
|
+
Object.defineProperty(this, Symbol.for("@orkestrel/reason.ReasonError"), { value: this });
|
|
126
126
|
this.name = "ReasonError";
|
|
127
127
|
this.code = code;
|
|
128
128
|
if (context !== void 0) this.context = context;
|
|
@@ -131,6 +131,13 @@ var ReasonError = class extends Error {
|
|
|
131
131
|
/**
|
|
132
132
|
* Narrows an unknown caught value to a {@link ReasonError}.
|
|
133
133
|
*
|
|
134
|
+
* @remarks
|
|
135
|
+
* Accepts errors from another installed copy and subclasses regardless of `name`.
|
|
136
|
+
* Requires the own self-valued `Symbol.for('@orkestrel/reason.ReasonError')`
|
|
137
|
+
* brand, a non-base global `Error` prototype, and valid declared members.
|
|
138
|
+
* Plain objects, unbranded look-alikes, and transparent proxies are rejected.
|
|
139
|
+
* Hostile reads return false through the contract intrinsics inside `holds`.
|
|
140
|
+
*
|
|
134
141
|
* @param value - The value to test (typically a `catch` binding)
|
|
135
142
|
* @returns True if `value` is a {@link ReasonError}; false otherwise
|
|
136
143
|
*
|
|
@@ -144,10 +151,15 @@ var ReasonError = class extends Error {
|
|
|
144
151
|
* ```
|
|
145
152
|
*/
|
|
146
153
|
function isReasonError(value) {
|
|
147
|
-
return (0, _orkestrel_contract.
|
|
154
|
+
return (0, _orkestrel_contract.holds)(() => {
|
|
155
|
+
if (!(0, _orkestrel_contract.isInstance)(value, Error) || _orkestrel_contract.INTRINSICS.prototype(value) === Error.prototype) return false;
|
|
156
|
+
if (_orkestrel_contract.INTRINSICS.describe(value, Symbol.for("@orkestrel/reason.ReasonError"))?.value !== value) return false;
|
|
157
|
+
const code = _orkestrel_contract.INTRINSICS.reflect.read(value, "code");
|
|
158
|
+
const context = _orkestrel_contract.INTRINSICS.reflect.read(value, "context");
|
|
159
|
+
return (code === "MISSING" || code === "INVALID" || code === "MISMATCH" || code === "DESTROYED" || code === "TARGET" || code === "OPERATOR") && (0, _orkestrel_contract.isString)(_orkestrel_contract.INTRINSICS.reflect.read(value, "message")) && (context === void 0 || (0, _orkestrel_contract.isObject)(context) || (0, _orkestrel_contract.isFunction)(context));
|
|
160
|
+
});
|
|
148
161
|
}
|
|
149
|
-
|
|
150
|
-
//#region src/core/validators.ts
|
|
162
|
+
// src/core/validators.ts
|
|
151
163
|
/**
|
|
152
164
|
* Determines whether a value is a {@link Reasoning} literal.
|
|
153
165
|
*
|
|
@@ -164,20 +176,20 @@ function isReasonError(value) {
|
|
|
164
176
|
*/
|
|
165
177
|
var isReasoning = (0, _orkestrel_contract.literalOf)("quantitative", "logical", "symbolic", "inferential");
|
|
166
178
|
/**
|
|
167
|
-
* Determines whether a value is a {@link
|
|
179
|
+
* Determines whether a value is a {@link ChainStrategy} literal.
|
|
168
180
|
*
|
|
169
181
|
* @param value - The value to test
|
|
170
182
|
* @returns True if `value` is `'forward'` or `'backward'`; false otherwise
|
|
171
183
|
*
|
|
172
184
|
* @example
|
|
173
185
|
* ```ts
|
|
174
|
-
* import {
|
|
186
|
+
* import { isChainStrategy } from '@src/core'
|
|
175
187
|
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
188
|
+
* isChainStrategy('forward') // true
|
|
189
|
+
* isChainStrategy('upward') // false
|
|
178
190
|
* ```
|
|
179
191
|
*/
|
|
180
|
-
var
|
|
192
|
+
var isChainStrategy = (0, _orkestrel_contract.literalOf)("forward", "backward");
|
|
181
193
|
/**
|
|
182
194
|
* Determines whether a value is a {@link MathOperation} literal.
|
|
183
195
|
*
|
|
@@ -700,7 +712,7 @@ function isLogicalDefinition(value) {
|
|
|
700
712
|
name: _orkestrel_contract.isString,
|
|
701
713
|
description: _orkestrel_contract.isString,
|
|
702
714
|
rules: (0, _orkestrel_contract.arrayOf)(isRule),
|
|
703
|
-
strategy:
|
|
715
|
+
strategy: isChainStrategy,
|
|
704
716
|
depth: _orkestrel_contract.isFiniteNumber
|
|
705
717
|
}, ["description", "depth"])(value);
|
|
706
718
|
}
|
|
@@ -751,7 +763,7 @@ function isInferentialDefinition(value) {
|
|
|
751
763
|
description: _orkestrel_contract.isString,
|
|
752
764
|
inferences: (0, _orkestrel_contract.arrayOf)(isInference),
|
|
753
765
|
facts: (0, _orkestrel_contract.arrayOf)(isFact),
|
|
754
|
-
strategy:
|
|
766
|
+
strategy: isChainStrategy,
|
|
755
767
|
depth: _orkestrel_contract.isFiniteNumber
|
|
756
768
|
}, ["description", "depth"])(value);
|
|
757
769
|
}
|
|
@@ -1012,8 +1024,7 @@ function isProofNode(value) {
|
|
|
1012
1024
|
if (!(0, _orkestrel_contract.isArray)(children)) return false;
|
|
1013
1025
|
const entries = (0, _orkestrel_contract.readArrayEntries)(children);
|
|
1014
1026
|
if (!entries.success || !entries.value.dense) return false;
|
|
1015
|
-
for (
|
|
1016
|
-
const child = entries.value.entries[index];
|
|
1027
|
+
for (const child of entries.value.entries.toReversed()) {
|
|
1017
1028
|
if (!(0, _orkestrel_contract.isObject)(child) || (0, _orkestrel_contract.isArray)(child)) return false;
|
|
1018
1029
|
worklist.push([
|
|
1019
1030
|
child,
|
|
@@ -1200,8 +1211,7 @@ function isDefinitionBuilder(value) {
|
|
|
1200
1211
|
function isSubjectBuilder(value) {
|
|
1201
1212
|
return (0, _orkestrel_contract.isObject)(value) && Reflect.get(value, SUBJECT_BUILDER_BRAND) === true;
|
|
1202
1213
|
}
|
|
1203
|
-
|
|
1204
|
-
//#region src/core/helpers.ts
|
|
1214
|
+
// src/core/helpers.ts
|
|
1205
1215
|
/**
|
|
1206
1216
|
* Formats a {@link FieldPath} for display — the single string key itself, or the
|
|
1207
1217
|
* array segments joined with `.`.
|
|
@@ -1223,6 +1233,19 @@ function formatField(field) {
|
|
|
1223
1233
|
return (0, _orkestrel_contract.isString)(field) ? field : field.join(".");
|
|
1224
1234
|
}
|
|
1225
1235
|
/**
|
|
1236
|
+
* Iterates nonnegative indices below a numeric limit without allocating a range.
|
|
1237
|
+
*
|
|
1238
|
+
* @example
|
|
1239
|
+
* ```ts
|
|
1240
|
+
* [...iterateIndices(2.5)] // [0, 1, 2]
|
|
1241
|
+
* ```
|
|
1242
|
+
*/
|
|
1243
|
+
function* iterateIndices(limit) {
|
|
1244
|
+
yield* Array.prototype.keys.call({ length: Math.max(0, Math.ceil(limit)) });
|
|
1245
|
+
if (limit > Number.MAX_SAFE_INTEGER) yield Number.MAX_SAFE_INTEGER;
|
|
1246
|
+
if (limit > Number.MAX_SAFE_INTEGER + 1) for (;;) yield Number.MAX_SAFE_INTEGER + 1;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1226
1249
|
* Clamps a number to inclusive {@link Bounds}.
|
|
1227
1250
|
*
|
|
1228
1251
|
* @remarks
|
|
@@ -1243,10 +1266,8 @@ function formatField(field) {
|
|
|
1243
1266
|
*/
|
|
1244
1267
|
function clamp(value, limit) {
|
|
1245
1268
|
if (!limit) return value;
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
if (limit.maximum !== void 0 && result > limit.maximum) result = limit.maximum;
|
|
1249
|
-
return result;
|
|
1269
|
+
const minimum = limit.minimum !== void 0 && value < limit.minimum ? limit.minimum : value;
|
|
1270
|
+
return limit.maximum !== void 0 && minimum > limit.maximum ? limit.maximum : minimum;
|
|
1250
1271
|
}
|
|
1251
1272
|
/**
|
|
1252
1273
|
* Checks whether a value falls inside an inclusive range expressed as an array.
|
|
@@ -1442,12 +1463,7 @@ function equalValues(left, right) {
|
|
|
1442
1463
|
* ```
|
|
1443
1464
|
*/
|
|
1444
1465
|
function sortByPriority(items) {
|
|
1445
|
-
|
|
1446
|
-
for (const item of items) {
|
|
1447
|
-
if (!(0, _orkestrel_contract.isObject)(item)) continue;
|
|
1448
|
-
usable.push(item);
|
|
1449
|
-
}
|
|
1450
|
-
return usable.sort((left, right) => (left.priority ?? 0) - (right.priority ?? 0));
|
|
1466
|
+
return Iterator.from(items).filter(_orkestrel_contract.isObject).toArray().sort((left, right) => (left.priority ?? 0) - (right.priority ?? 0));
|
|
1451
1467
|
}
|
|
1452
1468
|
/**
|
|
1453
1469
|
* Collects the ids that appear more than once in an id-carrying list — each
|
|
@@ -1470,9 +1486,10 @@ function sortByPriority(items) {
|
|
|
1470
1486
|
* ```
|
|
1471
1487
|
*/
|
|
1472
1488
|
function findDuplicates(items) {
|
|
1473
|
-
const
|
|
1474
|
-
|
|
1475
|
-
|
|
1489
|
+
const indexed = Iterator.from(items).map((item, index) => [item.id, index]).toArray();
|
|
1490
|
+
const first = new Map(indexed.toReversed());
|
|
1491
|
+
const duplicates = new Set(indexed.filter(([id, index]) => first.get(id) !== index).map(([id]) => id));
|
|
1492
|
+
return indexed.filter(([id, index]) => first.get(id) === index && duplicates.has(id)).map(([id]) => id);
|
|
1476
1493
|
}
|
|
1477
1494
|
/**
|
|
1478
1495
|
* Derives a fact's predicate+arity bucket key — length-prefixed so the
|
|
@@ -1528,14 +1545,7 @@ function factToArityKey(fact) {
|
|
|
1528
1545
|
* ```
|
|
1529
1546
|
*/
|
|
1530
1547
|
function indexByArity(facts) {
|
|
1531
|
-
|
|
1532
|
-
for (const entry of facts) {
|
|
1533
|
-
const key = factToArityKey(entry);
|
|
1534
|
-
const bucket = index.get(key);
|
|
1535
|
-
if (bucket) bucket.push(entry);
|
|
1536
|
-
else index.set(key, [entry]);
|
|
1537
|
-
}
|
|
1538
|
-
return index;
|
|
1548
|
+
return Map.groupBy(facts, factToArityKey);
|
|
1539
1549
|
}
|
|
1540
1550
|
/**
|
|
1541
1551
|
* Derives one fact term's contribution to a dedup key — reference identity for
|
|
@@ -1635,21 +1645,20 @@ function factToKey(fact, identities) {
|
|
|
1635
1645
|
function matchFacts(pattern, candidate) {
|
|
1636
1646
|
if (pattern.predicate !== candidate.predicate) return void 0;
|
|
1637
1647
|
if (pattern.terms.length !== candidate.terms.length) return void 0;
|
|
1638
|
-
const bindings =
|
|
1639
|
-
for (
|
|
1640
|
-
const patternTerm = pattern.terms[index];
|
|
1648
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
1649
|
+
for (const [index, patternTerm] of pattern.terms.entries()) {
|
|
1641
1650
|
const factTerm = candidate.terms[index];
|
|
1642
1651
|
if ((0, _orkestrel_contract.isString)(patternTerm) && patternTerm.startsWith("?")) {
|
|
1643
|
-
if (patternTerm
|
|
1644
|
-
if (bindings
|
|
1645
|
-
} else bindings
|
|
1652
|
+
if (bindings.has(patternTerm)) {
|
|
1653
|
+
if (bindings.get(patternTerm) !== factTerm) return void 0;
|
|
1654
|
+
} else bindings.set(patternTerm, factTerm);
|
|
1646
1655
|
} else if ((0, _orkestrel_contract.isString)(factTerm) && factTerm.startsWith("?")) {
|
|
1647
|
-
if (factTerm
|
|
1648
|
-
if (bindings
|
|
1649
|
-
} else bindings
|
|
1656
|
+
if (bindings.has(factTerm)) {
|
|
1657
|
+
if (bindings.get(factTerm) !== patternTerm) return void 0;
|
|
1658
|
+
} else bindings.set(factTerm, patternTerm);
|
|
1650
1659
|
} else if (patternTerm !== factTerm) return;
|
|
1651
1660
|
}
|
|
1652
|
-
return bindings;
|
|
1661
|
+
return Object.fromEntries(bindings);
|
|
1653
1662
|
}
|
|
1654
1663
|
/**
|
|
1655
1664
|
* Substitutes a fact's bound `'?'`-variables with their values — a fresh fact
|
|
@@ -1711,15 +1720,11 @@ function instantiateFact(fact, bindings) {
|
|
|
1711
1720
|
* ```
|
|
1712
1721
|
*/
|
|
1713
1722
|
function computePremiseConfidence(premises, index, bindings) {
|
|
1714
|
-
|
|
1715
|
-
for (const premise of premises) {
|
|
1723
|
+
return Iterator.from(premises).reduce((confidence, premise) => {
|
|
1716
1724
|
const instantiated = instantiateFact(premise, bindings);
|
|
1717
|
-
for (const candidate of index.get(factToArityKey(premise)) ?? []) if (matchFacts(instantiated, candidate))
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
return confidence;
|
|
1725
|
+
for (const candidate of index.get(factToArityKey(premise)) ?? []) if (matchFacts(instantiated, candidate)) return confidence * (candidate.confidence ?? 1);
|
|
1726
|
+
return confidence;
|
|
1727
|
+
}, 1);
|
|
1723
1728
|
}
|
|
1724
1729
|
/**
|
|
1725
1730
|
* Projects a subject's scalar fields into `has(key, value)` base facts — the
|
|
@@ -1743,25 +1748,24 @@ function computePremiseConfidence(premises, index, bindings) {
|
|
|
1743
1748
|
* ```
|
|
1744
1749
|
*/
|
|
1745
1750
|
function subjectToFacts(subject) {
|
|
1746
|
-
const
|
|
1747
|
-
|
|
1748
|
-
for (const key of Object.keys(subject)) {
|
|
1749
|
-
if (key === "id") continue;
|
|
1751
|
+
const rows = Object.keys(subject).flatMap((key) => {
|
|
1752
|
+
if (key === "id") return [];
|
|
1750
1753
|
const value = subject[key];
|
|
1751
|
-
if (value === void 0 || value === null)
|
|
1752
|
-
if ((0, _orkestrel_contract.isObject)(value))
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1754
|
+
if (value === void 0 || value === null) return [];
|
|
1755
|
+
if ((0, _orkestrel_contract.isObject)(value)) return [];
|
|
1756
|
+
return [{
|
|
1757
|
+
fact: {
|
|
1758
|
+
id: `subject:${key}`,
|
|
1759
|
+
predicate: "has",
|
|
1760
|
+
terms: [key, value],
|
|
1761
|
+
confidence: 1
|
|
1762
|
+
},
|
|
1763
|
+
trace: `Subject field "${key}" → has(${key}, ${String(value)})`
|
|
1764
|
+
}];
|
|
1765
|
+
});
|
|
1762
1766
|
return {
|
|
1763
|
-
facts,
|
|
1764
|
-
trace
|
|
1767
|
+
facts: rows.map((row) => row.fact),
|
|
1768
|
+
trace: [...rows.map((row) => row.trace), ...rows.length > 0 ? [`Injected ${rows.length} fact(s) from subject`] : []]
|
|
1765
1769
|
};
|
|
1766
1770
|
}
|
|
1767
1771
|
/**
|
|
@@ -1791,17 +1795,8 @@ function subjectToFacts(subject) {
|
|
|
1791
1795
|
* ```
|
|
1792
1796
|
*/
|
|
1793
1797
|
function findUnboundVariables(inference) {
|
|
1794
|
-
const bound =
|
|
1795
|
-
|
|
1796
|
-
const unbound = [];
|
|
1797
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1798
|
-
for (const term of inference.conclusion.terms) {
|
|
1799
|
-
if (!(0, _orkestrel_contract.isString)(term) || !term.startsWith("?")) continue;
|
|
1800
|
-
if (bound.has(term) || seen.has(term)) continue;
|
|
1801
|
-
seen.add(term);
|
|
1802
|
-
unbound.push(term);
|
|
1803
|
-
}
|
|
1804
|
-
return unbound;
|
|
1798
|
+
const bound = new Set(Iterator.from(inference.premises).flatMap((premise) => Iterator.from(premise.terms).filter((term) => (0, _orkestrel_contract.isString)(term) && term.startsWith("?"))));
|
|
1799
|
+
return [...new Set(Iterator.from(inference.conclusion.terms).filter((term) => (0, _orkestrel_contract.isString)(term) && term.startsWith("?") && !bound.has(term)))];
|
|
1805
1800
|
}
|
|
1806
1801
|
/**
|
|
1807
1802
|
* Determines whether a symbolic expression contains an unbound occurrence of a
|
|
@@ -2018,8 +2013,9 @@ function extractAtoms(expression) {
|
|
|
2018
2013
|
continue;
|
|
2019
2014
|
}
|
|
2020
2015
|
const operands = node.operands;
|
|
2021
|
-
|
|
2022
|
-
|
|
2016
|
+
const length = operands.length;
|
|
2017
|
+
for (const offset of iterateIndices(length)) {
|
|
2018
|
+
const operand = operands[length - 1 - offset];
|
|
2023
2019
|
if (operand !== void 0) stack.push(operand);
|
|
2024
2020
|
}
|
|
2025
2021
|
}
|
|
@@ -2089,21 +2085,9 @@ function extractConclusions(expression) {
|
|
|
2089
2085
|
* ```
|
|
2090
2086
|
*/
|
|
2091
2087
|
function findOverlayMismatches(rules) {
|
|
2092
|
-
const writeKeys = [];
|
|
2093
|
-
const
|
|
2094
|
-
|
|
2095
|
-
if (!(0, _orkestrel_contract.isArray)(atomLeaf.check.field)) continue;
|
|
2096
|
-
const key = formatField(atomLeaf.check.field);
|
|
2097
|
-
if (seenWrites.has(key)) continue;
|
|
2098
|
-
seenWrites.add(key);
|
|
2099
|
-
writeKeys.push(key);
|
|
2100
|
-
}
|
|
2101
|
-
const readKeys = /* @__PURE__ */ new Set();
|
|
2102
|
-
for (const candidate of rules) for (const premise of candidate.premises) for (const atomLeaf of extractAtoms(premise)) {
|
|
2103
|
-
if (!(0, _orkestrel_contract.isArray)(atomLeaf.check.field)) continue;
|
|
2104
|
-
readKeys.add(formatField(atomLeaf.check.field));
|
|
2105
|
-
}
|
|
2106
|
-
return writeKeys.filter((key) => readKeys.has(key));
|
|
2088
|
+
const writeKeys = new Set(Iterator.from(rules).flatMap((candidate) => extractAtoms(candidate.conclusion).flatMap((atom) => (0, _orkestrel_contract.isArray)(atom.check.field) ? [formatField(atom.check.field)] : [])));
|
|
2089
|
+
const readKeys = new Set(Iterator.from(rules).flatMap((candidate) => Iterator.from(candidate.premises).flatMap((premise) => extractAtoms(premise).flatMap((atom) => (0, _orkestrel_contract.isArray)(atom.check.field) ? [formatField(atom.check.field)] : []))));
|
|
2090
|
+
return [...writeKeys].filter((key) => readKeys.has(key));
|
|
2107
2091
|
}
|
|
2108
2092
|
/**
|
|
2109
2093
|
* Builds the empty, type-shaped failure {@link ReasonResult} matching a
|
|
@@ -2371,20 +2355,20 @@ function removeById(items, id) {
|
|
|
2371
2355
|
function mergeById(base, incoming, resolve) {
|
|
2372
2356
|
const baseById = /* @__PURE__ */ new Map();
|
|
2373
2357
|
for (const item of base) if (!baseById.has(item.id)) baseById.set(item.id, item);
|
|
2374
|
-
const
|
|
2375
|
-
const merged = [];
|
|
2358
|
+
const merged = /* @__PURE__ */ new Map();
|
|
2376
2359
|
for (const item of incoming) {
|
|
2377
|
-
|
|
2378
|
-
|
|
2360
|
+
const query = item.id;
|
|
2361
|
+
if (merged.has(query)) continue;
|
|
2362
|
+
const id = item.id;
|
|
2379
2363
|
const existing = baseById.get(item.id);
|
|
2380
|
-
merged.
|
|
2364
|
+
merged.set(id, existing === void 0 ? item : resolve ? resolve(existing, item) : item);
|
|
2381
2365
|
}
|
|
2382
2366
|
for (const item of base) {
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
merged.
|
|
2367
|
+
const query = item.id;
|
|
2368
|
+
if (merged.has(query)) continue;
|
|
2369
|
+
merged.set(item.id, item);
|
|
2386
2370
|
}
|
|
2387
|
-
return merged;
|
|
2371
|
+
return [...merged.values()];
|
|
2388
2372
|
}
|
|
2389
2373
|
/**
|
|
2390
2374
|
* Inserts `group` into a {@link QuantitativeDefinition}'s `groups` — dedup-then-
|
|
@@ -3343,15 +3327,12 @@ function mergeSubjects(base, incoming) {
|
|
|
3343
3327
|
*/
|
|
3344
3328
|
function repeatSubject(subject, count) {
|
|
3345
3329
|
const baseId = subject.id;
|
|
3346
|
-
|
|
3347
|
-
for (let index = 0; index < count; index += 1) clones.push((0, _orkestrel_contract.isString)(baseId) ? {
|
|
3330
|
+
return iterateIndices(count).map((index) => (0, _orkestrel_contract.isString)(baseId) ? {
|
|
3348
3331
|
...subject,
|
|
3349
3332
|
id: `${baseId}-${index}`
|
|
3350
|
-
} : { ...subject });
|
|
3351
|
-
return clones;
|
|
3333
|
+
} : { ...subject }).toArray();
|
|
3352
3334
|
}
|
|
3353
|
-
|
|
3354
|
-
//#region src/core/parsers.ts
|
|
3335
|
+
// src/core/parsers.ts
|
|
3355
3336
|
/**
|
|
3356
3337
|
* Parses a JSON string into a {@link Definition}, failing safe to `undefined`.
|
|
3357
3338
|
*
|
|
@@ -3378,8 +3359,7 @@ function repeatSubject(subject, count) {
|
|
|
3378
3359
|
function parseDefinition(json) {
|
|
3379
3360
|
return (0, _orkestrel_contract.parseJSONAs)(json, isDefinition);
|
|
3380
3361
|
}
|
|
3381
|
-
|
|
3382
|
-
//#region src/core/Reason.ts
|
|
3362
|
+
// src/core/Reason.ts
|
|
3383
3363
|
/**
|
|
3384
3364
|
* Implements the reasoning orchestrator — a thin router over registered
|
|
3385
3365
|
* {@link ReasonerInterface}s.
|
|
@@ -3506,8 +3486,7 @@ var Reason = class {
|
|
|
3506
3486
|
if (this.#destroyed) throw new ReasonError("DESTROYED", "Reason has been destroyed");
|
|
3507
3487
|
}
|
|
3508
3488
|
};
|
|
3509
|
-
|
|
3510
|
-
//#region src/core/operators/Evaluator.ts
|
|
3489
|
+
// src/core/operators/Evaluator.ts
|
|
3511
3490
|
/**
|
|
3512
3491
|
* Evaluates {@link Check}s against subjects — the shared predicate engine of the
|
|
3513
3492
|
* quantitative and logical reasoners.
|
|
@@ -3577,8 +3556,7 @@ var Evaluator = class {
|
|
|
3577
3556
|
}
|
|
3578
3557
|
}
|
|
3579
3558
|
};
|
|
3580
|
-
|
|
3581
|
-
//#region src/core/operators/Transformer.ts
|
|
3559
|
+
// src/core/operators/Transformer.ts
|
|
3582
3560
|
/**
|
|
3583
3561
|
* Applies math {@link Transform}s to numbers — the quantitative reasoner's
|
|
3584
3562
|
* per-factor pipeline stage.
|
|
@@ -3617,8 +3595,7 @@ var Transformer = class {
|
|
|
3617
3595
|
return transforms.reduce((result, transform) => this.apply(result, transform), value);
|
|
3618
3596
|
}
|
|
3619
3597
|
};
|
|
3620
|
-
|
|
3621
|
-
//#region src/core/operators/Aggregator.ts
|
|
3598
|
+
// src/core/operators/Aggregator.ts
|
|
3622
3599
|
/**
|
|
3623
3600
|
* Reduces number lists to one number per {@link Aggregation} — the quantitative
|
|
3624
3601
|
* reasoner's group and definition combiner.
|
|
@@ -3668,8 +3645,7 @@ var Aggregator = class {
|
|
|
3668
3645
|
}
|
|
3669
3646
|
}
|
|
3670
3647
|
};
|
|
3671
|
-
|
|
3672
|
-
//#region src/core/reasoners/QuantitativeReasoner.ts
|
|
3648
|
+
// src/core/reasoners/QuantitativeReasoner.ts
|
|
3673
3649
|
/**
|
|
3674
3650
|
* Performs factor-based numeric scoring.
|
|
3675
3651
|
*
|
|
@@ -3776,24 +3752,19 @@ var QuantitativeReasoner = class {
|
|
|
3776
3752
|
};
|
|
3777
3753
|
const trace = [];
|
|
3778
3754
|
const errors = [];
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
for (const group of definition.groups) {
|
|
3782
|
-
if (!(0, _orkestrel_contract.isObject)(group)) continue;
|
|
3755
|
+
const groupResults = Iterator.from(definition.groups).flatMap((group) => {
|
|
3756
|
+
if (!(0, _orkestrel_contract.isObject)(group)) return [];
|
|
3783
3757
|
if (group.enabled === false) {
|
|
3784
3758
|
trace.push(`Skipped group "${group.id}" (disabled)`);
|
|
3785
|
-
|
|
3759
|
+
return [];
|
|
3786
3760
|
}
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
if (groupResult.applied) count++;
|
|
3790
|
-
}
|
|
3761
|
+
return [this.#evaluateGroup(group, subject, trace, errors)];
|
|
3762
|
+
}).toArray();
|
|
3791
3763
|
const groupValues = groupResults.filter((group) => group.applied).map((group) => group.value);
|
|
3792
3764
|
const base = definition.base ?? 0;
|
|
3793
|
-
|
|
3794
|
-
trace.push(`Aggregated ${groupValues.length} groups with "${definition.aggregation}": base=${base}, raw=${
|
|
3795
|
-
value = clamp(
|
|
3796
|
-
value = roundTo(value, definition.precision ?? 4);
|
|
3765
|
+
const raw = base + this.#aggregator.aggregate(groupValues, definition.aggregation);
|
|
3766
|
+
trace.push(`Aggregated ${groupValues.length} groups with "${definition.aggregation}": base=${base}, raw=${raw}`);
|
|
3767
|
+
const value = roundTo(clamp(raw, definition.bounds), definition.precision ?? 4);
|
|
3797
3768
|
if (!(0, _orkestrel_contract.isFiniteNumber)(value)) {
|
|
3798
3769
|
const description = Number.isNaN(value) ? "NaN" : String(value);
|
|
3799
3770
|
trace.push(`Definition "${definition.id}": produced non-finite value (${description})`);
|
|
@@ -3803,7 +3774,7 @@ var QuantitativeReasoner = class {
|
|
|
3803
3774
|
reasoning: "quantitative",
|
|
3804
3775
|
value,
|
|
3805
3776
|
groups: groupResults,
|
|
3806
|
-
count,
|
|
3777
|
+
count: groupValues.length,
|
|
3807
3778
|
success: errors.length === 0,
|
|
3808
3779
|
trace,
|
|
3809
3780
|
errors
|
|
@@ -3819,14 +3790,13 @@ var QuantitativeReasoner = class {
|
|
|
3819
3790
|
factors: []
|
|
3820
3791
|
};
|
|
3821
3792
|
}
|
|
3822
|
-
const factorResults =
|
|
3823
|
-
for (const factor of sortByPriority(group.factors)) {
|
|
3793
|
+
const factorResults = Iterator.from(sortByPriority(group.factors)).flatMap((factor) => {
|
|
3824
3794
|
if (factor.enabled === false) {
|
|
3825
3795
|
trace.push(`Skipped factor "${factor.id}" (disabled)`);
|
|
3826
|
-
|
|
3796
|
+
return [];
|
|
3827
3797
|
}
|
|
3828
|
-
|
|
3829
|
-
}
|
|
3798
|
+
return [this.#evaluateFactor(factor, subject, trace, errors)];
|
|
3799
|
+
}).toArray();
|
|
3830
3800
|
const appliedFactors = factorResults.filter((factor) => factor.applied);
|
|
3831
3801
|
if (group.strict && appliedFactors.length !== factorResults.length) {
|
|
3832
3802
|
trace.push(`Group "${group.id}" strict mode: not all factors applied`);
|
|
@@ -3844,8 +3814,7 @@ var QuantitativeReasoner = class {
|
|
|
3844
3814
|
if (!weightById.has(original.id)) weightById.set(original.id, original.weight ?? 1);
|
|
3845
3815
|
}
|
|
3846
3816
|
const weights = appliedFactors.map((factor) => weightById.get(factor.id) ?? 1);
|
|
3847
|
-
|
|
3848
|
-
value = clamp(value, group.bounds);
|
|
3817
|
+
const value = clamp((group.base ?? 0) + this.#aggregator.aggregate(factorValues, group.aggregation, weights), group.bounds);
|
|
3849
3818
|
trace.push(`Group "${group.id}": ${appliedFactors.length}/${factorResults.length} factors applied, value=${value}`);
|
|
3850
3819
|
return {
|
|
3851
3820
|
id: group.id,
|
|
@@ -3889,9 +3858,7 @@ var QuantitativeReasoner = class {
|
|
|
3889
3858
|
raw
|
|
3890
3859
|
};
|
|
3891
3860
|
}
|
|
3892
|
-
|
|
3893
|
-
if (factor.transforms && factor.transforms.length > 0) value = this.#transformer.chain(value, factor.transforms);
|
|
3894
|
-
value = clamp(value, factor.bounds);
|
|
3861
|
+
const value = clamp(factor.transforms && factor.transforms.length > 0 ? this.#transformer.chain(raw, factor.transforms) : raw, factor.bounds);
|
|
3895
3862
|
if (!(0, _orkestrel_contract.isFiniteNumber)(value)) {
|
|
3896
3863
|
const description = Number.isNaN(value) ? "NaN" : String(value);
|
|
3897
3864
|
trace.push(`Factor "${factor.id}": produced non-finite value (${description})`);
|
|
@@ -3912,8 +3879,30 @@ var QuantitativeReasoner = class {
|
|
|
3912
3879
|
};
|
|
3913
3880
|
}
|
|
3914
3881
|
};
|
|
3915
|
-
|
|
3916
|
-
|
|
3882
|
+
// src/core/LogicalState.ts
|
|
3883
|
+
/**
|
|
3884
|
+
* Stores the derived fields and rule results of one logical reasoning call.
|
|
3885
|
+
*/
|
|
3886
|
+
var LogicalState = class {
|
|
3887
|
+
#fields = {};
|
|
3888
|
+
#rules = /* @__PURE__ */ new Map();
|
|
3889
|
+
get fields() {
|
|
3890
|
+
return this.#fields;
|
|
3891
|
+
}
|
|
3892
|
+
field(key) {
|
|
3893
|
+
return this.#fields[key];
|
|
3894
|
+
}
|
|
3895
|
+
set(key, value) {
|
|
3896
|
+
this.#fields[key] = value;
|
|
3897
|
+
}
|
|
3898
|
+
rule(id) {
|
|
3899
|
+
return this.#rules.get(id);
|
|
3900
|
+
}
|
|
3901
|
+
record(result) {
|
|
3902
|
+
this.#rules.set(result.id, result);
|
|
3903
|
+
}
|
|
3904
|
+
};
|
|
3905
|
+
// src/core/reasoners/LogicalReasoner.ts
|
|
3917
3906
|
/**
|
|
3918
3907
|
* Deduces booleans from rules with forward or backward chaining.
|
|
3919
3908
|
*
|
|
@@ -4028,58 +4017,59 @@ var LogicalReasoner = class {
|
|
|
4028
4017
|
}
|
|
4029
4018
|
#forward(definition, subject, trace, errors) {
|
|
4030
4019
|
const maxDepth = definition.depth ?? 10;
|
|
4031
|
-
const
|
|
4020
|
+
const state = new LogicalState();
|
|
4032
4021
|
if (definition.rules.length === 0) trace.push("No rules defined");
|
|
4033
4022
|
const sortedRules = sortByPriority(definition.rules);
|
|
4034
|
-
const reportedErrors =
|
|
4035
|
-
|
|
4036
|
-
if (
|
|
4037
|
-
if (rule.enabled === false) continue;
|
|
4023
|
+
const reportedErrors = new Set(sortedRules.flatMap((rule) => {
|
|
4024
|
+
if (!(0, _orkestrel_contract.isObject)(rule)) return [];
|
|
4025
|
+
if (rule.enabled === false) return [];
|
|
4038
4026
|
if (!rule.premises || rule.premises.length === 0) {
|
|
4039
4027
|
errors.push(`Rule "${rule.id}" has no premises — skipped`);
|
|
4040
|
-
|
|
4028
|
+
return [rule.id];
|
|
4041
4029
|
} else if (!rule.conclusion) {
|
|
4042
4030
|
errors.push(`Rule "${rule.id}" has no conclusion — skipped`);
|
|
4043
|
-
|
|
4031
|
+
return [rule.id];
|
|
4044
4032
|
}
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4033
|
+
return [];
|
|
4034
|
+
}));
|
|
4035
|
+
for (const iteration of iterateIndices(maxDepth)) {
|
|
4048
4036
|
const currentSubject = {
|
|
4049
4037
|
...subject,
|
|
4050
|
-
...
|
|
4038
|
+
...state.fields
|
|
4051
4039
|
};
|
|
4052
|
-
|
|
4040
|
+
if (!sortedRules.reduce((previous, rule) => {
|
|
4053
4041
|
if (rule.enabled === false) {
|
|
4054
4042
|
trace.push(`Skipped rule "${rule.id}" (disabled)`);
|
|
4055
|
-
|
|
4043
|
+
return previous;
|
|
4056
4044
|
}
|
|
4057
|
-
if (reportedErrors.has(rule.id))
|
|
4045
|
+
if (reportedErrors.has(rule.id)) return previous;
|
|
4058
4046
|
if (this.#evaluateRule(rule, currentSubject).applied) {
|
|
4059
4047
|
const conclusions = extractConclusions(rule.conclusion);
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4048
|
+
return Object.entries(conclusions).reduce((updated, [key, value]) => {
|
|
4049
|
+
if (!equalValues(state.field(key), value)) {
|
|
4050
|
+
state.set(key, value);
|
|
4051
|
+
trace.push(`Rule "${rule.id}" derived: ${key}=${String(value)} (iteration ${iteration + 1})`);
|
|
4052
|
+
return true;
|
|
4053
|
+
}
|
|
4054
|
+
return updated;
|
|
4055
|
+
}, previous);
|
|
4065
4056
|
}
|
|
4066
|
-
|
|
4067
|
-
|
|
4057
|
+
return previous;
|
|
4058
|
+
}, false)) {
|
|
4068
4059
|
trace.push(`Forward chaining converged at iteration ${iteration + 1}`);
|
|
4069
4060
|
break;
|
|
4070
4061
|
}
|
|
4071
4062
|
}
|
|
4072
4063
|
const finalSubject = {
|
|
4073
4064
|
...subject,
|
|
4074
|
-
...
|
|
4065
|
+
...state.fields
|
|
4075
4066
|
};
|
|
4076
|
-
const finalResults =
|
|
4077
|
-
|
|
4078
|
-
if (
|
|
4079
|
-
if (rule.
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
}
|
|
4067
|
+
const finalResults = Iterator.from(definition.rules).flatMap((rule) => {
|
|
4068
|
+
if (!(0, _orkestrel_contract.isObject)(rule)) return [];
|
|
4069
|
+
if (rule.enabled === false) return [];
|
|
4070
|
+
if (reportedErrors.has(rule.id)) return [];
|
|
4071
|
+
return [this.#evaluateRule(rule, finalSubject)];
|
|
4072
|
+
}).toArray();
|
|
4083
4073
|
return {
|
|
4084
4074
|
conclusion: finalResults.length > 0 ? finalResults[finalResults.length - 1]?.applied ?? false : false,
|
|
4085
4075
|
rules: finalResults
|
|
@@ -4087,8 +4077,7 @@ var LogicalReasoner = class {
|
|
|
4087
4077
|
}
|
|
4088
4078
|
#backward(definition, subject, trace, errors) {
|
|
4089
4079
|
const maxDepth = definition.depth ?? 10;
|
|
4090
|
-
const
|
|
4091
|
-
const ruleResults = /* @__PURE__ */ new Map();
|
|
4080
|
+
const state = new LogicalState();
|
|
4092
4081
|
if (definition.rules.length === 0) trace.push("No rules defined");
|
|
4093
4082
|
const sortedRules = sortByPriority(definition.rules.filter((rule) => {
|
|
4094
4083
|
if (!(0, _orkestrel_contract.isObject)(rule)) return false;
|
|
@@ -4107,52 +4096,45 @@ var LogicalReasoner = class {
|
|
|
4107
4096
|
if (!(0, _orkestrel_contract.isObject)(rule)) continue;
|
|
4108
4097
|
if (rule.enabled === false) trace.push(`Skipped rule "${rule.id}" (disabled)`);
|
|
4109
4098
|
}
|
|
4110
|
-
for (const rule of sortedRules) this.#proveRule(rule, 0, /* @__PURE__ */ new Set(), sortedRules,
|
|
4111
|
-
const finalResults =
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
else finalResults.push(this.#evaluateRule(rule, {
|
|
4116
|
-
...subject,
|
|
4117
|
-
...derived
|
|
4118
|
-
}));
|
|
4119
|
-
}
|
|
4099
|
+
for (const rule of sortedRules) this.#proveRule(rule, 0, /* @__PURE__ */ new Set(), sortedRules, state, subject, trace, maxDepth);
|
|
4100
|
+
const finalResults = sortedRules.map((rule) => state.rule(rule.id) ?? this.#evaluateRule(rule, {
|
|
4101
|
+
...subject,
|
|
4102
|
+
...state.fields
|
|
4103
|
+
}));
|
|
4120
4104
|
return {
|
|
4121
4105
|
conclusion: finalResults.length > 0 ? finalResults[finalResults.length - 1]?.applied ?? false : false,
|
|
4122
4106
|
rules: finalResults
|
|
4123
4107
|
};
|
|
4124
4108
|
}
|
|
4125
|
-
#proveRule(rule, depth, visited, rules,
|
|
4109
|
+
#proveRule(rule, depth, visited, rules, state, subject, trace, maxDepth) {
|
|
4126
4110
|
if (depth > maxDepth) return false;
|
|
4127
4111
|
if (visited.has(rule.id)) return false;
|
|
4128
|
-
const nextVisited = new Set(visited);
|
|
4129
|
-
nextVisited.add(rule.id);
|
|
4112
|
+
const nextVisited = /* @__PURE__ */ new Set([...visited, rule.id]);
|
|
4130
4113
|
const currentSubject = {
|
|
4131
4114
|
...subject,
|
|
4132
|
-
...
|
|
4115
|
+
...state.fields
|
|
4133
4116
|
};
|
|
4134
|
-
const premiseResults =
|
|
4135
|
-
for (const premise of rule.premises) premiseResults.push(this.#establish(premise, currentSubject, rules, depth + 1, nextVisited, derived, subject, trace, ruleResults, maxDepth));
|
|
4117
|
+
const premiseResults = Iterator.from(rule.premises).map((premise) => this.#establish(premise, currentSubject, rules, depth + 1, nextVisited, state, subject, trace, maxDepth)).toArray();
|
|
4136
4118
|
const allMet = premiseResults.every(Boolean);
|
|
4137
|
-
|
|
4119
|
+
state.record({
|
|
4138
4120
|
id: rule.id,
|
|
4139
4121
|
applied: allMet,
|
|
4140
4122
|
premises: premiseResults
|
|
4141
4123
|
});
|
|
4142
4124
|
if (allMet) {
|
|
4143
4125
|
const conclusions = extractConclusions(rule.conclusion);
|
|
4144
|
-
for (const [key, value] of Object.entries(conclusions)) if (!equalValues(
|
|
4145
|
-
|
|
4126
|
+
for (const [key, value] of Object.entries(conclusions)) if (!equalValues(state.field(key), value)) {
|
|
4127
|
+
state.set(key, value);
|
|
4146
4128
|
trace.push(`Rule "${rule.id}" derived: ${key}=${String(value)} (backward, depth ${depth})`);
|
|
4147
4129
|
}
|
|
4148
4130
|
} else trace.push(`Rule "${rule.id}": does not hold (backward, depth ${depth})`);
|
|
4149
4131
|
return allMet;
|
|
4150
4132
|
}
|
|
4151
|
-
#establish(expression, currentSubject, rules, depth, visited,
|
|
4133
|
+
#establish(expression, currentSubject, rules, depth, visited, state, subject, trace, maxDepth) {
|
|
4152
4134
|
if (this.#evaluateExpression(expression, currentSubject)) return true;
|
|
4153
|
-
return this.#proveExpression(expression, rules, depth, visited,
|
|
4135
|
+
return this.#proveExpression(expression, rules, depth, visited, state, subject, trace, maxDepth);
|
|
4154
4136
|
}
|
|
4155
|
-
#proveExpression(expression, rules, depth, visited,
|
|
4137
|
+
#proveExpression(expression, rules, depth, visited, state, subject, trace, maxDepth) {
|
|
4156
4138
|
if (depth > maxDepth) return false;
|
|
4157
4139
|
if (expression.form === "atom") for (const rule of rules) {
|
|
4158
4140
|
if (!(0, _orkestrel_contract.isObject)(rule)) continue;
|
|
@@ -4161,30 +4143,25 @@ var LogicalReasoner = class {
|
|
|
4161
4143
|
const field = formatField(expression.check.field);
|
|
4162
4144
|
const value = expression.check.value;
|
|
4163
4145
|
if (field in conclusionFacts && conclusionFacts[field] === value) {
|
|
4164
|
-
const nextVisited = new Set(visited);
|
|
4165
|
-
nextVisited.add(rule.id);
|
|
4146
|
+
const nextVisited = /* @__PURE__ */ new Set([...visited, rule.id]);
|
|
4166
4147
|
const currentSubject = {
|
|
4167
4148
|
...subject,
|
|
4168
|
-
...
|
|
4149
|
+
...state.fields
|
|
4169
4150
|
};
|
|
4170
4151
|
const premiseResults = [];
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
const met = this.#establish(premise, currentSubject, rules, depth + 1, nextVisited, derived, subject, trace, ruleResults, maxDepth);
|
|
4152
|
+
const allMet = Iterator.from(rule.premises).every((premise) => {
|
|
4153
|
+
const met = this.#establish(premise, currentSubject, rules, depth + 1, nextVisited, state, subject, trace, maxDepth);
|
|
4174
4154
|
premiseResults.push(met);
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
}
|
|
4179
|
-
}
|
|
4180
|
-
ruleResults.set(rule.id, {
|
|
4155
|
+
return met;
|
|
4156
|
+
});
|
|
4157
|
+
state.record({
|
|
4181
4158
|
id: rule.id,
|
|
4182
4159
|
applied: allMet,
|
|
4183
4160
|
premises: premiseResults
|
|
4184
4161
|
});
|
|
4185
4162
|
if (allMet) {
|
|
4186
|
-
for (const [key, entry] of Object.entries(conclusionFacts)) if (!equalValues(
|
|
4187
|
-
|
|
4163
|
+
for (const [key, entry] of Object.entries(conclusionFacts)) if (!equalValues(state.field(key), entry)) {
|
|
4164
|
+
state.set(key, entry);
|
|
4188
4165
|
trace.push(`Rule "${rule.id}" derived: ${key}=${String(entry)} (backward, depth ${depth})`);
|
|
4189
4166
|
}
|
|
4190
4167
|
return true;
|
|
@@ -4194,31 +4171,31 @@ var LogicalReasoner = class {
|
|
|
4194
4171
|
if (expression.form === "compound") {
|
|
4195
4172
|
const currentSubject = {
|
|
4196
4173
|
...subject,
|
|
4197
|
-
...
|
|
4174
|
+
...state.fields
|
|
4198
4175
|
};
|
|
4199
4176
|
switch (expression.operator) {
|
|
4200
|
-
case "and": return expression.operands.every((operand) => this.#establish(operand, currentSubject, rules, depth, visited,
|
|
4201
|
-
case "or": return expression.operands.some((operand) => this.#establish(operand, currentSubject, rules, depth, visited,
|
|
4177
|
+
case "and": return expression.operands.every((operand) => this.#establish(operand, currentSubject, rules, depth, visited, state, subject, trace, maxDepth));
|
|
4178
|
+
case "or": return expression.operands.some((operand) => this.#establish(operand, currentSubject, rules, depth, visited, state, subject, trace, maxDepth));
|
|
4202
4179
|
case "not": {
|
|
4203
4180
|
if (expression.operands.length === 0) return true;
|
|
4204
4181
|
const first = expression.operands[0];
|
|
4205
4182
|
if (!first) return true;
|
|
4206
|
-
return !this.#establish(first, currentSubject, rules, depth, visited,
|
|
4183
|
+
return !this.#establish(first, currentSubject, rules, depth, visited, state, subject, trace, maxDepth);
|
|
4207
4184
|
}
|
|
4208
4185
|
case "implies": {
|
|
4209
4186
|
if (expression.operands.length < 2) return true;
|
|
4210
4187
|
const antecedent = expression.operands[0];
|
|
4211
4188
|
const consequent = expression.operands[1];
|
|
4212
4189
|
if (!antecedent || !consequent) return true;
|
|
4213
|
-
if (!this.#establish(antecedent, currentSubject, rules, depth, visited,
|
|
4214
|
-
return this.#establish(consequent, currentSubject, rules, depth, visited,
|
|
4190
|
+
if (!this.#establish(antecedent, currentSubject, rules, depth, visited, state, subject, trace, maxDepth)) return true;
|
|
4191
|
+
return this.#establish(consequent, currentSubject, rules, depth, visited, state, subject, trace, maxDepth);
|
|
4215
4192
|
}
|
|
4216
4193
|
case "xor": {
|
|
4217
4194
|
if (expression.operands.length < 2) return false;
|
|
4218
4195
|
const left = expression.operands[0];
|
|
4219
4196
|
const right = expression.operands[1];
|
|
4220
4197
|
if (!left || !right) return false;
|
|
4221
|
-
return this.#establish(left, currentSubject, rules, depth, visited,
|
|
4198
|
+
return this.#establish(left, currentSubject, rules, depth, visited, state, subject, trace, maxDepth) !== this.#establish(right, currentSubject, rules, depth, visited, state, subject, trace, maxDepth);
|
|
4222
4199
|
}
|
|
4223
4200
|
default: return false;
|
|
4224
4201
|
}
|
|
@@ -4256,8 +4233,23 @@ var LogicalReasoner = class {
|
|
|
4256
4233
|
}
|
|
4257
4234
|
}
|
|
4258
4235
|
};
|
|
4259
|
-
|
|
4260
|
-
|
|
4236
|
+
// src/core/SymbolicState.ts
|
|
4237
|
+
/**
|
|
4238
|
+
* Stores numeric bindings for one symbolic reasoning call.
|
|
4239
|
+
*/
|
|
4240
|
+
var SymbolicState = class {
|
|
4241
|
+
#values;
|
|
4242
|
+
constructor(values) {
|
|
4243
|
+
this.#values = { ...values };
|
|
4244
|
+
}
|
|
4245
|
+
get values() {
|
|
4246
|
+
return this.#values;
|
|
4247
|
+
}
|
|
4248
|
+
set(name, value) {
|
|
4249
|
+
this.#values[name] = value;
|
|
4250
|
+
}
|
|
4251
|
+
};
|
|
4252
|
+
// src/core/reasoners/SymbolicReasoner.ts
|
|
4261
4253
|
/**
|
|
4262
4254
|
* Solves algebraic equations by variable isolation.
|
|
4263
4255
|
*
|
|
@@ -4351,17 +4343,17 @@ var SymbolicReasoner = class {
|
|
|
4351
4343
|
const trace = [];
|
|
4352
4344
|
const errors = [];
|
|
4353
4345
|
const precision = definition.precision ?? 4;
|
|
4354
|
-
const
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
if (key === "id") continue;
|
|
4346
|
+
const state = new SymbolicState(definition.variables);
|
|
4347
|
+
const bound = Object.keys(subject).reduce((count, key) => {
|
|
4348
|
+
if (key === "id") return count;
|
|
4358
4349
|
const value = (0, _orkestrel_contract.parseNumber)(subject[key]);
|
|
4359
4350
|
if (value !== void 0) {
|
|
4360
|
-
|
|
4351
|
+
state.set(key, value);
|
|
4361
4352
|
trace.push(`Subject field "${key}" bound as ${key} = ${value}`);
|
|
4362
|
-
|
|
4353
|
+
return count + 1;
|
|
4363
4354
|
}
|
|
4364
|
-
|
|
4355
|
+
return count;
|
|
4356
|
+
}, 0);
|
|
4365
4357
|
if (bound > 0) trace.push(`Bound ${bound} variable(s) from subject`);
|
|
4366
4358
|
if (definition.equations.length === 0) {
|
|
4367
4359
|
trace.push("No equations to solve");
|
|
@@ -4376,7 +4368,7 @@ var SymbolicReasoner = class {
|
|
|
4376
4368
|
for (const equation of definition.equations) {
|
|
4377
4369
|
if (!(0, _orkestrel_contract.isObject)(equation)) continue;
|
|
4378
4370
|
try {
|
|
4379
|
-
const value = this.#solve(equation,
|
|
4371
|
+
const value = this.#solve(equation, state.values);
|
|
4380
4372
|
const rounded = roundTo(value, precision);
|
|
4381
4373
|
if (!(0, _orkestrel_contract.isFiniteNumber)(value) || !(0, _orkestrel_contract.isFiniteNumber)(rounded)) {
|
|
4382
4374
|
const offender = (0, _orkestrel_contract.isFiniteNumber)(value) ? rounded : value;
|
|
@@ -4385,7 +4377,7 @@ var SymbolicReasoner = class {
|
|
|
4385
4377
|
trace.push(`Equation "${equation.id}": FAILED — produced non-finite value (${description})`);
|
|
4386
4378
|
continue;
|
|
4387
4379
|
}
|
|
4388
|
-
|
|
4380
|
+
state.set(equation.target, rounded);
|
|
4389
4381
|
trace.push(`Equation "${equation.id}": ${equation.target} = ${rounded}`);
|
|
4390
4382
|
} catch (error) {
|
|
4391
4383
|
const message = (0, _orkestrel_contract.isError)(error) ? error.message : String(error);
|
|
@@ -4393,15 +4385,15 @@ var SymbolicReasoner = class {
|
|
|
4393
4385
|
trace.push(`Equation "${equation.id}": FAILED — ${message}`);
|
|
4394
4386
|
}
|
|
4395
4387
|
}
|
|
4396
|
-
const solutions =
|
|
4388
|
+
const solutions = new SymbolicState();
|
|
4397
4389
|
for (const equation of definition.equations) {
|
|
4398
4390
|
if (!(0, _orkestrel_contract.isObject)(equation)) continue;
|
|
4399
|
-
const value =
|
|
4400
|
-
if (value !== void 0) solutions
|
|
4391
|
+
const value = state.values[equation.target];
|
|
4392
|
+
if (value !== void 0) solutions.set(equation.target, value);
|
|
4401
4393
|
}
|
|
4402
4394
|
return {
|
|
4403
4395
|
reasoning: "symbolic",
|
|
4404
|
-
solutions,
|
|
4396
|
+
solutions: solutions.values,
|
|
4405
4397
|
success: errors.length === 0,
|
|
4406
4398
|
trace,
|
|
4407
4399
|
errors
|
|
@@ -4459,8 +4451,37 @@ var SymbolicReasoner = class {
|
|
|
4459
4451
|
}
|
|
4460
4452
|
}
|
|
4461
4453
|
};
|
|
4462
|
-
|
|
4463
|
-
|
|
4454
|
+
// src/core/InferenceJoin.ts
|
|
4455
|
+
/**
|
|
4456
|
+
* Joins premise bindings against a predicate-and-arity fact index.
|
|
4457
|
+
*/
|
|
4458
|
+
var InferenceJoin = class {
|
|
4459
|
+
#index;
|
|
4460
|
+
#bindings = [{}];
|
|
4461
|
+
constructor(index) {
|
|
4462
|
+
this.#index = index;
|
|
4463
|
+
}
|
|
4464
|
+
resolve(premises) {
|
|
4465
|
+
this.#bindings = [{}];
|
|
4466
|
+
if (premises.length === 0) return this.#bindings;
|
|
4467
|
+
for (const premise of premises) {
|
|
4468
|
+
const candidates = this.#index.get(factToArityKey(premise)) ?? [];
|
|
4469
|
+
this.#bindings = this.#bindings.flatMap((existing) => {
|
|
4470
|
+
const instantiated = instantiateFact(premise, existing);
|
|
4471
|
+
return Iterator.from(candidates).flatMap((fact) => {
|
|
4472
|
+
const match = matchFacts(instantiated, fact);
|
|
4473
|
+
return match ? [{
|
|
4474
|
+
...existing,
|
|
4475
|
+
...match
|
|
4476
|
+
}] : [];
|
|
4477
|
+
}).toArray();
|
|
4478
|
+
});
|
|
4479
|
+
if (this.#bindings.length === 0) break;
|
|
4480
|
+
}
|
|
4481
|
+
return this.#bindings;
|
|
4482
|
+
}
|
|
4483
|
+
};
|
|
4484
|
+
// src/core/reasoners/InferentialReasoner.ts
|
|
4464
4485
|
/**
|
|
4465
4486
|
* Derives facts with unification variables and proof trees.
|
|
4466
4487
|
*
|
|
@@ -4615,35 +4636,31 @@ var InferentialReasoner = class {
|
|
|
4615
4636
|
}
|
|
4616
4637
|
validInferences.push(inference);
|
|
4617
4638
|
}
|
|
4618
|
-
for (
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
const
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
const
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
derived.push(derivedFact);
|
|
4638
|
-
newDerivation = true;
|
|
4639
|
-
trace.push(`Derived ${derivedFact.predicate}(${derivedFact.terms.join(", ")}) through "${inference.id}" [confidence: ${derivedFact.confidence}] (iteration ${iteration + 1})`);
|
|
4640
|
-
}
|
|
4639
|
+
for (const iteration of iterateIndices(maxDepth)) if (!validInferences.reduce((previous, inference) => {
|
|
4640
|
+
return new InferenceJoin(byArity).resolve(inference.premises).reduce((updated, bindings) => {
|
|
4641
|
+
const conclusion = instantiateFact(inference.conclusion, bindings);
|
|
4642
|
+
const finalConfidence = computePremiseConfidence(inference.premises, byArity, bindings) * (inference.confidence ?? 1);
|
|
4643
|
+
const derivedFact = {
|
|
4644
|
+
...conclusion,
|
|
4645
|
+
confidence: roundTo(finalConfidence, 4)
|
|
4646
|
+
};
|
|
4647
|
+
const key = factToKey(derivedFact, identities);
|
|
4648
|
+
if (!seen.has(key)) {
|
|
4649
|
+
knownFacts.push(derivedFact);
|
|
4650
|
+
const arityKey = factToArityKey(derivedFact);
|
|
4651
|
+
const bucket = byArity.get(arityKey);
|
|
4652
|
+
if (bucket) bucket.push(derivedFact);
|
|
4653
|
+
else byArity.set(arityKey, [derivedFact]);
|
|
4654
|
+
seen.add(key);
|
|
4655
|
+
derived.push(derivedFact);
|
|
4656
|
+
trace.push(`Derived ${derivedFact.predicate}(${derivedFact.terms.join(", ")}) through "${inference.id}" [confidence: ${derivedFact.confidence}] (iteration ${iteration + 1})`);
|
|
4657
|
+
return true;
|
|
4641
4658
|
}
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4659
|
+
return updated;
|
|
4660
|
+
}, previous);
|
|
4661
|
+
}, false)) {
|
|
4662
|
+
trace.push(`Forward chaining converged at iteration ${iteration + 1}`);
|
|
4663
|
+
break;
|
|
4647
4664
|
}
|
|
4648
4665
|
return { derived };
|
|
4649
4666
|
}
|
|
@@ -4696,17 +4713,15 @@ var InferentialReasoner = class {
|
|
|
4696
4713
|
const conclusionBindings = matchFacts(goal, inference.conclusion);
|
|
4697
4714
|
if (!conclusionBindings) continue;
|
|
4698
4715
|
const children = [];
|
|
4699
|
-
|
|
4700
|
-
for (const premise of inference.premises) {
|
|
4716
|
+
if (Iterator.from(inference.premises).every((premise) => {
|
|
4701
4717
|
const instantiated = instantiateFact(premise, conclusionBindings);
|
|
4702
4718
|
const child = this.#prove(instantiated, inferences, baseFacts, depth + 1, maxDepth);
|
|
4703
|
-
if (child)
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
break;
|
|
4719
|
+
if (child) {
|
|
4720
|
+
children.push(child);
|
|
4721
|
+
return true;
|
|
4707
4722
|
}
|
|
4708
|
-
|
|
4709
|
-
|
|
4723
|
+
return false;
|
|
4724
|
+
})) return {
|
|
4710
4725
|
fact: goal.id,
|
|
4711
4726
|
inference: inference.id,
|
|
4712
4727
|
children,
|
|
@@ -4714,30 +4729,8 @@ var InferentialReasoner = class {
|
|
|
4714
4729
|
};
|
|
4715
4730
|
}
|
|
4716
4731
|
}
|
|
4717
|
-
#findAllBindings(premises, byArity) {
|
|
4718
|
-
if (premises.length === 0) return [{}];
|
|
4719
|
-
let currentBindings = [{}];
|
|
4720
|
-
for (const premise of premises) {
|
|
4721
|
-
const nextBindings = [];
|
|
4722
|
-
const candidates = byArity.get(factToArityKey(premise)) ?? [];
|
|
4723
|
-
for (const existing of currentBindings) {
|
|
4724
|
-
const instantiated = instantiateFact(premise, existing);
|
|
4725
|
-
for (const fact of candidates) {
|
|
4726
|
-
const match = matchFacts(instantiated, fact);
|
|
4727
|
-
if (match) nextBindings.push({
|
|
4728
|
-
...existing,
|
|
4729
|
-
...match
|
|
4730
|
-
});
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4733
|
-
currentBindings = nextBindings;
|
|
4734
|
-
if (currentBindings.length === 0) break;
|
|
4735
|
-
}
|
|
4736
|
-
return currentBindings;
|
|
4737
|
-
}
|
|
4738
4732
|
};
|
|
4739
|
-
|
|
4740
|
-
//#region src/core/builders/managers/Collection.ts
|
|
4733
|
+
// src/core/builders/managers/Collection.ts
|
|
4741
4734
|
/**
|
|
4742
4735
|
* Holds the id-keyed collection state the `DefinitionBuilder`'s list managers
|
|
4743
4736
|
* share — the array, the placement verbs, the silent re-seat, and the
|
|
@@ -4803,8 +4796,7 @@ var Collection = class {
|
|
|
4803
4796
|
if (this.#destroyed) throw new ReasonError("DESTROYED", `${this.#owner} has been destroyed`);
|
|
4804
4797
|
}
|
|
4805
4798
|
};
|
|
4806
|
-
|
|
4807
|
-
//#region src/core/builders/managers/EquationManager.ts
|
|
4799
|
+
// src/core/builders/managers/EquationManager.ts
|
|
4808
4800
|
/**
|
|
4809
4801
|
* Implements the {@link EquationManagerInterface} — a self-owning,
|
|
4810
4802
|
* kind-free manager over a symbolic definition's `equations`.
|
|
@@ -4875,11 +4867,7 @@ var EquationManager = class {
|
|
|
4875
4867
|
for (const equation of this.#equations.items()) this.#removeOne(equation.id);
|
|
4876
4868
|
return;
|
|
4877
4869
|
}
|
|
4878
|
-
if ((0, _orkestrel_contract.isArray)(idOrIds))
|
|
4879
|
-
let all = true;
|
|
4880
|
-
for (const id of idOrIds) if (!this.#removeOne(id)) all = false;
|
|
4881
|
-
return all;
|
|
4882
|
-
}
|
|
4870
|
+
if ((0, _orkestrel_contract.isArray)(idOrIds)) return Iterator.from(idOrIds).reduce((all, id) => this.#removeOne(id) && all, true);
|
|
4883
4871
|
return this.#removeOne(idOrIds);
|
|
4884
4872
|
}
|
|
4885
4873
|
seat(equations) {
|
|
@@ -4896,8 +4884,7 @@ var EquationManager = class {
|
|
|
4896
4884
|
return true;
|
|
4897
4885
|
}
|
|
4898
4886
|
};
|
|
4899
|
-
|
|
4900
|
-
//#region src/core/builders/managers/FactManager.ts
|
|
4887
|
+
// src/core/builders/managers/FactManager.ts
|
|
4901
4888
|
/**
|
|
4902
4889
|
* Implements the {@link FactManagerInterface} — a self-owning, kind-free
|
|
4903
4890
|
* manager over an inferential definition's `facts`.
|
|
@@ -4963,11 +4950,7 @@ var FactManager = class {
|
|
|
4963
4950
|
for (const fact of this.#facts.items()) this.#removeOne(fact.id);
|
|
4964
4951
|
return;
|
|
4965
4952
|
}
|
|
4966
|
-
if ((0, _orkestrel_contract.isArray)(idOrIds))
|
|
4967
|
-
let all = true;
|
|
4968
|
-
for (const id of idOrIds) if (!this.#removeOne(id)) all = false;
|
|
4969
|
-
return all;
|
|
4970
|
-
}
|
|
4953
|
+
if ((0, _orkestrel_contract.isArray)(idOrIds)) return Iterator.from(idOrIds).reduce((all, id) => this.#removeOne(id) && all, true);
|
|
4971
4954
|
return this.#removeOne(idOrIds);
|
|
4972
4955
|
}
|
|
4973
4956
|
seat(facts) {
|
|
@@ -4984,8 +4967,7 @@ var FactManager = class {
|
|
|
4984
4967
|
return true;
|
|
4985
4968
|
}
|
|
4986
4969
|
};
|
|
4987
|
-
|
|
4988
|
-
//#region src/core/builders/managers/FactorManager.ts
|
|
4970
|
+
// src/core/builders/managers/FactorManager.ts
|
|
4989
4971
|
/**
|
|
4990
4972
|
* Implements the {@link FactorManagerInterface} — the one divergent
|
|
4991
4973
|
* manager: factors nest inside groups, so it holds no collection state of its
|
|
@@ -5069,11 +5051,7 @@ var FactorManager = class {
|
|
|
5069
5051
|
for (const factor of this.#locate(groupId).factors) this.#removeOne(groupId, factor.id);
|
|
5070
5052
|
return;
|
|
5071
5053
|
}
|
|
5072
|
-
if ((0, _orkestrel_contract.isArray)(idOrIds))
|
|
5073
|
-
let all = true;
|
|
5074
|
-
for (const id of idOrIds) if (!this.#removeOne(groupId, id)) all = false;
|
|
5075
|
-
return all;
|
|
5076
|
-
}
|
|
5054
|
+
if ((0, _orkestrel_contract.isArray)(idOrIds)) return Iterator.from(idOrIds).reduce((all, id) => this.#removeOne(groupId, id) && all, true);
|
|
5077
5055
|
return this.#removeOne(groupId, idOrIds);
|
|
5078
5056
|
}
|
|
5079
5057
|
destroy() {
|
|
@@ -5097,8 +5075,7 @@ var FactorManager = class {
|
|
|
5097
5075
|
return group;
|
|
5098
5076
|
}
|
|
5099
5077
|
};
|
|
5100
|
-
|
|
5101
|
-
//#region src/core/builders/managers/GroupManager.ts
|
|
5078
|
+
// src/core/builders/managers/GroupManager.ts
|
|
5102
5079
|
/**
|
|
5103
5080
|
* Implements the {@link GroupManagerInterface} — a self-owning, kind-free
|
|
5104
5081
|
* manager over a quantitative definition's `groups`.
|
|
@@ -5164,11 +5141,7 @@ var GroupManager = class {
|
|
|
5164
5141
|
for (const group of this.#groups.items()) this.#removeOne(group.id);
|
|
5165
5142
|
return;
|
|
5166
5143
|
}
|
|
5167
|
-
if ((0, _orkestrel_contract.isArray)(idOrIds))
|
|
5168
|
-
let all = true;
|
|
5169
|
-
for (const id of idOrIds) if (!this.#removeOne(id)) all = false;
|
|
5170
|
-
return all;
|
|
5171
|
-
}
|
|
5144
|
+
if ((0, _orkestrel_contract.isArray)(idOrIds)) return Iterator.from(idOrIds).reduce((all, id) => this.#removeOne(id) && all, true);
|
|
5172
5145
|
return this.#removeOne(idOrIds);
|
|
5173
5146
|
}
|
|
5174
5147
|
seat(groups) {
|
|
@@ -5185,8 +5158,7 @@ var GroupManager = class {
|
|
|
5185
5158
|
return true;
|
|
5186
5159
|
}
|
|
5187
5160
|
};
|
|
5188
|
-
|
|
5189
|
-
//#region src/core/builders/managers/InferenceManager.ts
|
|
5161
|
+
// src/core/builders/managers/InferenceManager.ts
|
|
5190
5162
|
/**
|
|
5191
5163
|
* Implements the {@link InferenceManagerInterface} — a self-owning,
|
|
5192
5164
|
* kind-free manager over an inferential definition's `inferences`.
|
|
@@ -5262,11 +5234,7 @@ var InferenceManager = class {
|
|
|
5262
5234
|
for (const inference of this.#inferences.items()) this.#removeOne(inference.id);
|
|
5263
5235
|
return;
|
|
5264
5236
|
}
|
|
5265
|
-
if ((0, _orkestrel_contract.isArray)(idOrIds))
|
|
5266
|
-
let all = true;
|
|
5267
|
-
for (const id of idOrIds) if (!this.#removeOne(id)) all = false;
|
|
5268
|
-
return all;
|
|
5269
|
-
}
|
|
5237
|
+
if ((0, _orkestrel_contract.isArray)(idOrIds)) return Iterator.from(idOrIds).reduce((all, id) => this.#removeOne(id) && all, true);
|
|
5270
5238
|
return this.#removeOne(idOrIds);
|
|
5271
5239
|
}
|
|
5272
5240
|
seat(inferences) {
|
|
@@ -5283,8 +5251,7 @@ var InferenceManager = class {
|
|
|
5283
5251
|
return true;
|
|
5284
5252
|
}
|
|
5285
5253
|
};
|
|
5286
|
-
|
|
5287
|
-
//#region src/core/builders/managers/RuleManager.ts
|
|
5254
|
+
// src/core/builders/managers/RuleManager.ts
|
|
5288
5255
|
/**
|
|
5289
5256
|
* Implements the {@link RuleManagerInterface} — a self-owning, kind-free
|
|
5290
5257
|
* manager over a logical definition's `rules`.
|
|
@@ -5353,11 +5320,7 @@ var RuleManager = class {
|
|
|
5353
5320
|
for (const rule of this.#rules.items()) this.#removeOne(rule.id);
|
|
5354
5321
|
return;
|
|
5355
5322
|
}
|
|
5356
|
-
if ((0, _orkestrel_contract.isArray)(idOrIds))
|
|
5357
|
-
let all = true;
|
|
5358
|
-
for (const id of idOrIds) if (!this.#removeOne(id)) all = false;
|
|
5359
|
-
return all;
|
|
5360
|
-
}
|
|
5323
|
+
if ((0, _orkestrel_contract.isArray)(idOrIds)) return Iterator.from(idOrIds).reduce((all, id) => this.#removeOne(id) && all, true);
|
|
5361
5324
|
return this.#removeOne(idOrIds);
|
|
5362
5325
|
}
|
|
5363
5326
|
seat(rules) {
|
|
@@ -5374,8 +5337,7 @@ var RuleManager = class {
|
|
|
5374
5337
|
return true;
|
|
5375
5338
|
}
|
|
5376
5339
|
};
|
|
5377
|
-
|
|
5378
|
-
//#region src/core/builders/managers/VariableManager.ts
|
|
5340
|
+
// src/core/builders/managers/VariableManager.ts
|
|
5379
5341
|
/**
|
|
5380
5342
|
* Implements the {@link VariableManagerInterface} — a self-owning,
|
|
5381
5343
|
* kind-free manager over a symbolic definition's `variables`, a name-keyed
|
|
@@ -5442,11 +5404,7 @@ var VariableManager = class {
|
|
|
5442
5404
|
for (const name of Object.keys(this.#variables)) this.#removeOne(name);
|
|
5443
5405
|
return;
|
|
5444
5406
|
}
|
|
5445
|
-
if ((0, _orkestrel_contract.isArray)(nameOrNames))
|
|
5446
|
-
let all = true;
|
|
5447
|
-
for (const name of nameOrNames) if (!this.#removeOne(name)) all = false;
|
|
5448
|
-
return all;
|
|
5449
|
-
}
|
|
5407
|
+
if ((0, _orkestrel_contract.isArray)(nameOrNames)) return Iterator.from(nameOrNames).reduce((all, name) => this.#removeOne(name) && all, true);
|
|
5450
5408
|
return this.#removeOne(nameOrNames);
|
|
5451
5409
|
}
|
|
5452
5410
|
seat(variables) {
|
|
@@ -5469,8 +5427,7 @@ var VariableManager = class {
|
|
|
5469
5427
|
return true;
|
|
5470
5428
|
}
|
|
5471
5429
|
};
|
|
5472
|
-
|
|
5473
|
-
//#region src/core/builders/DefinitionBuilder.ts
|
|
5430
|
+
// src/core/builders/DefinitionBuilder.ts
|
|
5474
5431
|
/**
|
|
5475
5432
|
* Implements a stateful workspace builder accumulating a {@link Definition}
|
|
5476
5433
|
* through always-present self-owning manager properties: a private scalar
|
|
@@ -5582,28 +5539,13 @@ var DefinitionBuilder = class {
|
|
|
5582
5539
|
definition: this.#id,
|
|
5583
5540
|
reasoning: current.reasoning
|
|
5584
5541
|
});
|
|
5585
|
-
|
|
5586
|
-
if (current.reasoning === "quantitative" && incoming.reasoning === "quantitative") merged = mergeQuantitativeDefinition(current, incoming);
|
|
5587
|
-
else if (current.reasoning === "logical" && incoming.reasoning === "logical") merged = mergeLogicalDefinition(current, incoming);
|
|
5588
|
-
else if (current.reasoning === "symbolic" && incoming.reasoning === "symbolic") merged = mergeSymbolicDefinition(current, incoming);
|
|
5589
|
-
else if (current.reasoning === "inferential" && incoming.reasoning === "inferential") merged = mergeInferentialDefinition(current, incoming);
|
|
5590
|
-
else merged = current;
|
|
5542
|
+
const merged = current.reasoning === "quantitative" && incoming.reasoning === "quantitative" ? mergeQuantitativeDefinition(current, incoming) : current.reasoning === "logical" && incoming.reasoning === "logical" ? mergeLogicalDefinition(current, incoming) : current.reasoning === "symbolic" && incoming.reasoning === "symbolic" ? mergeSymbolicDefinition(current, incoming) : current.reasoning === "inferential" && incoming.reasoning === "inferential" ? mergeInferentialDefinition(current, incoming) : current;
|
|
5591
5543
|
this.#seat(merged);
|
|
5592
5544
|
this.#emitter.emit("merge", merged.reasoning);
|
|
5593
5545
|
}
|
|
5594
5546
|
clear(key) {
|
|
5595
5547
|
this.#ensureAlive();
|
|
5596
|
-
|
|
5597
|
-
let next;
|
|
5598
|
-
if (current.reasoning === "quantitative" && isQuantitativeClearKey(key)) next = clearQuantitativeDefinition(current, key);
|
|
5599
|
-
else if (current.reasoning === "logical" && isLogicalClearKey(key)) next = clearLogicalDefinition(current, key);
|
|
5600
|
-
else if (current.reasoning === "symbolic" && isSymbolicClearKey(key)) next = clearSymbolicDefinition(current, key);
|
|
5601
|
-
else if (current.reasoning === "inferential" && isInferentialClearKey(key)) next = clearInferentialDefinition(current, key);
|
|
5602
|
-
else throw new ReasonError("MISMATCH", `"${key}" is not a clearable field for reasoning "${current.reasoning}"`, {
|
|
5603
|
-
key,
|
|
5604
|
-
reasoning: current.reasoning
|
|
5605
|
-
});
|
|
5606
|
-
this.#envelope = definitionToEnvelope(next);
|
|
5548
|
+
this.#envelope = definitionToEnvelope(this.#clear(key));
|
|
5607
5549
|
this.#emitter.emit("clear", key);
|
|
5608
5550
|
}
|
|
5609
5551
|
destroy() {
|
|
@@ -5618,6 +5560,17 @@ var DefinitionBuilder = class {
|
|
|
5618
5560
|
this.#emitter.emit("destroy");
|
|
5619
5561
|
this.#emitter.destroy();
|
|
5620
5562
|
}
|
|
5563
|
+
#clear(key) {
|
|
5564
|
+
const current = this.#compose();
|
|
5565
|
+
if (current.reasoning === "quantitative" && isQuantitativeClearKey(key)) return clearQuantitativeDefinition(current, key);
|
|
5566
|
+
else if (current.reasoning === "logical" && isLogicalClearKey(key)) return clearLogicalDefinition(current, key);
|
|
5567
|
+
else if (current.reasoning === "symbolic" && isSymbolicClearKey(key)) return clearSymbolicDefinition(current, key);
|
|
5568
|
+
else if (current.reasoning === "inferential" && isInferentialClearKey(key)) return clearInferentialDefinition(current, key);
|
|
5569
|
+
else throw new ReasonError("MISMATCH", `"${key}" is not a clearable field for reasoning "${current.reasoning}"`, {
|
|
5570
|
+
key,
|
|
5571
|
+
reasoning: current.reasoning
|
|
5572
|
+
});
|
|
5573
|
+
}
|
|
5621
5574
|
#compose() {
|
|
5622
5575
|
const envelope = this.#envelope;
|
|
5623
5576
|
switch (envelope.reasoning) {
|
|
@@ -5663,8 +5616,7 @@ var DefinitionBuilder = class {
|
|
|
5663
5616
|
if (this.#destroyed) throw new ReasonError("DESTROYED", "DefinitionBuilder has been destroyed");
|
|
5664
5617
|
}
|
|
5665
5618
|
};
|
|
5666
|
-
|
|
5667
|
-
//#region src/core/builders/SubjectBuilder.ts
|
|
5619
|
+
// src/core/builders/SubjectBuilder.ts
|
|
5668
5620
|
/**
|
|
5669
5621
|
* Implements a stateful workspace builder accumulating a {@link Subject} — one
|
|
5670
5622
|
* flat key-value collection, no managers.
|
|
@@ -5752,11 +5704,7 @@ var SubjectBuilder = class {
|
|
|
5752
5704
|
for (const key of Object.keys(this.#subject)) if (key !== "id") this.#removeOne(key);
|
|
5753
5705
|
return;
|
|
5754
5706
|
}
|
|
5755
|
-
if ((0, _orkestrel_contract.isArray)(keyOrKeys))
|
|
5756
|
-
let all = true;
|
|
5757
|
-
for (const key of keyOrKeys) if (!this.#removeOne(key)) all = false;
|
|
5758
|
-
return all;
|
|
5759
|
-
}
|
|
5707
|
+
if ((0, _orkestrel_contract.isArray)(keyOrKeys)) return Iterator.from(keyOrKeys).reduce((all, key) => this.#removeOne(key) && all, true);
|
|
5760
5708
|
return this.#removeOne(keyOrKeys);
|
|
5761
5709
|
}
|
|
5762
5710
|
merge(incoming) {
|
|
@@ -5800,8 +5748,7 @@ var SubjectBuilder = class {
|
|
|
5800
5748
|
return existed;
|
|
5801
5749
|
}
|
|
5802
5750
|
};
|
|
5803
|
-
|
|
5804
|
-
//#region src/core/factories.ts
|
|
5751
|
+
// src/core/factories.ts
|
|
5805
5752
|
/**
|
|
5806
5753
|
* Creates a check evaluator.
|
|
5807
5754
|
*
|
|
@@ -6873,7 +6820,6 @@ function createInferentialDefinition(id, name, facts, inferences, overrides) {
|
|
|
6873
6820
|
...overrides
|
|
6874
6821
|
};
|
|
6875
6822
|
}
|
|
6876
|
-
//#endregion
|
|
6877
6823
|
exports.AGGREGATOR_ID = AGGREGATOR_ID;
|
|
6878
6824
|
exports.Aggregator = Aggregator;
|
|
6879
6825
|
exports.CONFIDENCE_PRECISION = CONFIDENCE_PRECISION;
|
|
@@ -6988,7 +6934,7 @@ exports.invertLeft = invertLeft;
|
|
|
6988
6934
|
exports.invertRight = invertRight;
|
|
6989
6935
|
exports.isAggregation = isAggregation;
|
|
6990
6936
|
exports.isBounds = isBounds;
|
|
6991
|
-
exports.
|
|
6937
|
+
exports.isChainStrategy = isChainStrategy;
|
|
6992
6938
|
exports.isCheck = isCheck;
|
|
6993
6939
|
exports.isCheckResult = isCheckResult;
|
|
6994
6940
|
exports.isComparison = isComparison;
|
|
@@ -7031,6 +6977,7 @@ exports.isSymbolicDefinition = isSymbolicDefinition;
|
|
|
7031
6977
|
exports.isSymbolicExpression = isSymbolicExpression;
|
|
7032
6978
|
exports.isSymbolicResult = isSymbolicResult;
|
|
7033
6979
|
exports.isTransform = isTransform;
|
|
6980
|
+
exports.iterateIndices = iterateIndices;
|
|
7034
6981
|
exports.matchFacts = matchFacts;
|
|
7035
6982
|
exports.matchesBounds = matchesBounds;
|
|
7036
6983
|
exports.mergeById = mergeById;
|