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