@polintpro/proposit-core 0.8.0 → 0.8.3
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/README.md +30 -3
- package/dist/cli/commands/analysis.d.ts.map +1 -1
- package/dist/cli/commands/analysis.js +148 -42
- package/dist/cli/commands/analysis.js.map +1 -1
- package/dist/cli/commands/arguments.d.ts.map +1 -1
- package/dist/cli/commands/arguments.js +25 -7
- package/dist/cli/commands/arguments.js.map +1 -1
- package/dist/cli/commands/claims.d.ts.map +1 -1
- package/dist/cli/commands/claims.js +16 -16
- package/dist/cli/commands/claims.js.map +1 -1
- package/dist/cli/commands/diff.d.ts.map +1 -1
- package/dist/cli/commands/diff.js +19 -4
- package/dist/cli/commands/diff.js.map +1 -1
- package/dist/cli/commands/expressions.d.ts.map +1 -1
- package/dist/cli/commands/expressions.js +56 -0
- package/dist/cli/commands/expressions.js.map +1 -1
- package/dist/cli/commands/graph.d.ts +13 -0
- package/dist/cli/commands/graph.d.ts.map +1 -0
- package/dist/cli/commands/graph.js +382 -0
- package/dist/cli/commands/graph.js.map +1 -0
- package/dist/cli/commands/parse.d.ts.map +1 -1
- package/dist/cli/commands/parse.js +13 -6
- package/dist/cli/commands/parse.js.map +1 -1
- package/dist/cli/commands/premises.d.ts.map +1 -1
- package/dist/cli/commands/premises.js +21 -17
- package/dist/cli/commands/premises.js.map +1 -1
- package/dist/cli/commands/render.d.ts.map +1 -1
- package/dist/cli/commands/render.js +23 -12
- package/dist/cli/commands/render.js.map +1 -1
- package/dist/cli/commands/repair.d.ts +3 -0
- package/dist/cli/commands/repair.d.ts.map +1 -0
- package/dist/cli/commands/repair.js +53 -0
- package/dist/cli/commands/repair.js.map +1 -0
- package/dist/cli/commands/sources.d.ts.map +1 -1
- package/dist/cli/commands/sources.js +17 -17
- package/dist/cli/commands/sources.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +27 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/commands/variables.d.ts.map +1 -1
- package/dist/cli/commands/variables.js +11 -4
- package/dist/cli/commands/variables.js.map +1 -1
- package/dist/cli/engine.d.ts +6 -19
- package/dist/cli/engine.d.ts.map +1 -1
- package/dist/cli/engine.js +72 -73
- package/dist/cli/engine.js.map +1 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +4 -0
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/storage/analysis.d.ts +2 -1
- package/dist/cli/storage/analysis.d.ts.map +1 -1
- package/dist/cli/storage/analysis.js +40 -2
- package/dist/cli/storage/analysis.js.map +1 -1
- package/dist/cli/storage/libraries.d.ts +3 -0
- package/dist/cli/storage/libraries.d.ts.map +1 -1
- package/dist/cli/storage/libraries.js +19 -0
- package/dist/cli/storage/libraries.js.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/lib/consts.d.ts.map +1 -1
- package/dist/lib/consts.js +4 -7
- package/dist/lib/consts.js.map +1 -1
- package/dist/lib/core/argument-engine.d.ts +12 -1
- package/dist/lib/core/argument-engine.d.ts.map +1 -1
- package/dist/lib/core/argument-engine.js +295 -17
- package/dist/lib/core/argument-engine.js.map +1 -1
- package/dist/lib/core/argument-library.d.ts.map +1 -1
- package/dist/lib/core/argument-library.js +1 -1
- package/dist/lib/core/argument-library.js.map +1 -1
- package/dist/lib/core/evaluation/grading.d.ts +28 -0
- package/dist/lib/core/evaluation/grading.d.ts.map +1 -0
- package/dist/lib/core/evaluation/grading.js +44 -0
- package/dist/lib/core/evaluation/grading.js.map +1 -0
- package/dist/lib/core/expression-manager.d.ts +2 -1
- package/dist/lib/core/expression-manager.d.ts.map +1 -1
- package/dist/lib/core/expression-manager.js +12 -8
- package/dist/lib/core/expression-manager.js.map +1 -1
- package/dist/lib/core/fork.d.ts.map +1 -1
- package/dist/lib/core/fork.js +3 -3
- package/dist/lib/core/fork.js.map +1 -1
- package/dist/lib/core/interfaces/library.interfaces.d.ts +2 -0
- package/dist/lib/core/interfaces/library.interfaces.d.ts.map +1 -1
- package/dist/lib/core/premise-engine.d.ts +3 -2
- package/dist/lib/core/premise-engine.d.ts.map +1 -1
- package/dist/lib/core/premise-engine.js +17 -11
- package/dist/lib/core/premise-engine.js.map +1 -1
- package/dist/lib/core/proposit-core.d.ts +3 -2
- package/dist/lib/core/proposit-core.d.ts.map +1 -1
- package/dist/lib/core/proposit-core.js +19 -11
- package/dist/lib/core/proposit-core.js.map +1 -1
- package/dist/lib/index.d.ts +3 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +2 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/parsing/argument-parser.d.ts.map +1 -1
- package/dist/lib/parsing/argument-parser.js +17 -14
- package/dist/lib/parsing/argument-parser.js.map +1 -1
- package/dist/lib/parsing/clamp-max-lengths.d.ts +11 -0
- package/dist/lib/parsing/clamp-max-lengths.d.ts.map +1 -0
- package/dist/lib/parsing/clamp-max-lengths.js +56 -0
- package/dist/lib/parsing/clamp-max-lengths.js.map +1 -0
- package/dist/lib/parsing/prompt-builder.d.ts.map +1 -1
- package/dist/lib/parsing/prompt-builder.js +14 -1
- package/dist/lib/parsing/prompt-builder.js.map +1 -1
- package/dist/lib/parsing/types.d.ts +2 -0
- package/dist/lib/parsing/types.d.ts.map +1 -1
- package/dist/lib/schemata/analysis.d.ts +1 -1
- package/dist/lib/schemata/analysis.d.ts.map +1 -1
- package/dist/lib/schemata/analysis.js +2 -2
- package/dist/lib/schemata/analysis.js.map +1 -1
- package/dist/lib/types/checksum.d.ts +7 -7
- package/dist/lib/types/checksum.d.ts.map +1 -1
- package/dist/lib/types/evaluation.d.ts +5 -3
- package/dist/lib/types/evaluation.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { Value } from "typebox/value";
|
|
3
2
|
import { CoreArgumentSchema, isClaimBound, isPremiseBound, } from "../schemata/index.js";
|
|
4
3
|
import { DEFAULT_GRAMMAR_CONFIG, PERMISSIVE_GRAMMAR_CONFIG, } from "../types/grammar.js";
|
|
@@ -7,11 +6,13 @@ import { DEFAULT_CHECKSUM_CONFIG, normalizeChecksumConfig, serializeChecksumConf
|
|
|
7
6
|
import { getOrCreate, sortedUnique } from "../utils/collections.js";
|
|
8
7
|
import { ChangeCollector } from "./change-collector.js";
|
|
9
8
|
import { canonicalSerialize, computeHash, entityChecksum } from "./checksum.js";
|
|
10
|
-
import { kleeneAnd, kleeneNot } from "./evaluation/kleene.js";
|
|
9
|
+
import { kleeneAnd, kleeneNot, kleeneOr, kleeneImplies, kleeneIff, } from "./evaluation/kleene.js";
|
|
11
10
|
import { makeErrorIssue, makeValidationResult, } from "./evaluation/validation.js";
|
|
12
11
|
import { InvariantViolationError } from "./invariant-violation-error.js";
|
|
13
12
|
import { PremiseEngine } from "./premise-engine.js";
|
|
14
13
|
import { VariableManager } from "./variable-manager.js";
|
|
14
|
+
/** Default ID generator using the Web Crypto API (Node.js 20+, all modern browsers). */
|
|
15
|
+
export const defaultGenerateId = () => globalThis.crypto.randomUUID();
|
|
15
16
|
/**
|
|
16
17
|
* Manages a propositional logic argument composed of premises, variable
|
|
17
18
|
* assignments, and logical roles (supporting premises and a conclusion).
|
|
@@ -30,6 +31,7 @@ export class ArgumentEngine {
|
|
|
30
31
|
checksumConfig;
|
|
31
32
|
positionConfig;
|
|
32
33
|
grammarConfig;
|
|
34
|
+
generateId;
|
|
33
35
|
restoringFromSnapshot = false;
|
|
34
36
|
checksumDirty = true;
|
|
35
37
|
cachedMetaChecksum;
|
|
@@ -56,9 +58,11 @@ export class ArgumentEngine {
|
|
|
56
58
|
this.checksumConfig = options?.checksumConfig;
|
|
57
59
|
this.positionConfig = options?.positionConfig;
|
|
58
60
|
this.grammarConfig = options?.grammarConfig;
|
|
61
|
+
this.generateId = options?.generateId ?? defaultGenerateId;
|
|
59
62
|
this.variables = new VariableManager({
|
|
60
63
|
checksumConfig: this.checksumConfig,
|
|
61
64
|
positionConfig: this.positionConfig,
|
|
65
|
+
generateId: this.generateId,
|
|
62
66
|
});
|
|
63
67
|
this.expressionIndex = new Map();
|
|
64
68
|
this.conclusionPremiseId = undefined;
|
|
@@ -320,7 +324,7 @@ export class ArgumentEngine {
|
|
|
320
324
|
return lines.join("\n");
|
|
321
325
|
}
|
|
322
326
|
createPremise(extras, symbol) {
|
|
323
|
-
return this.createPremiseWithId(
|
|
327
|
+
return this.createPremiseWithId(this.generateId(), extras, symbol);
|
|
324
328
|
}
|
|
325
329
|
createPremiseWithId(id, extras, symbol) {
|
|
326
330
|
return this.withValidation(() => {
|
|
@@ -341,6 +345,7 @@ export class ArgumentEngine {
|
|
|
341
345
|
checksumConfig: this.checksumConfig,
|
|
342
346
|
positionConfig: this.positionConfig,
|
|
343
347
|
grammarConfig: this.grammarConfig,
|
|
348
|
+
generateId: this.generateId,
|
|
344
349
|
});
|
|
345
350
|
this.premises.set(id, pm);
|
|
346
351
|
this.wireCircularityCheck(pm);
|
|
@@ -363,7 +368,7 @@ export class ArgumentEngine {
|
|
|
363
368
|
if (!this.restoringFromSnapshot) {
|
|
364
369
|
const autoSymbol = symbol ?? this.generateUniqueSymbol();
|
|
365
370
|
const autoVariable = {
|
|
366
|
-
id:
|
|
371
|
+
id: this.generateId(),
|
|
367
372
|
argumentId: this.argument.id,
|
|
368
373
|
argumentVersion: this.argument.version,
|
|
369
374
|
symbol: autoSymbol,
|
|
@@ -800,17 +805,20 @@ export class ArgumentEngine {
|
|
|
800
805
|
};
|
|
801
806
|
}
|
|
802
807
|
/** Creates a new ArgumentEngine from a previously captured snapshot. */
|
|
803
|
-
static fromSnapshot(snapshot, claimLibrary, sourceLibrary, claimSourceLibrary, grammarConfig, checksumVerification) {
|
|
808
|
+
static fromSnapshot(snapshot, claimLibrary, sourceLibrary, claimSourceLibrary, grammarConfig, checksumVerification, generateId) {
|
|
804
809
|
const engine = new ArgumentEngine(snapshot.argument, claimLibrary, sourceLibrary, claimSourceLibrary, snapshot.config
|
|
805
810
|
? {
|
|
806
811
|
...snapshot.config,
|
|
807
812
|
checksumConfig: normalizeChecksumConfig(snapshot.config.checksumConfig),
|
|
813
|
+
generateId: generateId ?? snapshot.config.generateId,
|
|
808
814
|
}
|
|
809
|
-
:
|
|
815
|
+
: generateId
|
|
816
|
+
? { generateId }
|
|
817
|
+
: undefined);
|
|
810
818
|
engine.restoringFromSnapshot = true;
|
|
811
819
|
// Restore premises first (premise-bound variables reference them)
|
|
812
820
|
for (const premiseSnap of snapshot.premises) {
|
|
813
|
-
const pe = PremiseEngine.fromSnapshot(premiseSnap, snapshot.argument, engine.variables, engine.expressionIndex, grammarConfig);
|
|
821
|
+
const pe = PremiseEngine.fromSnapshot(premiseSnap, snapshot.argument, engine.variables, engine.expressionIndex, grammarConfig, generateId);
|
|
814
822
|
engine.premises.set(pe.getId(), pe);
|
|
815
823
|
engine.wireCircularityCheck(pe);
|
|
816
824
|
engine.wireEmptyBoundPremiseCheck(pe);
|
|
@@ -1488,6 +1496,270 @@ export class ArgumentEngine {
|
|
|
1488
1496
|
}
|
|
1489
1497
|
return makeValidationResult(issues);
|
|
1490
1498
|
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Run fixed-point constraint propagation over accepted operators.
|
|
1501
|
+
* Fills unknown (null) variable values based on operator semantics.
|
|
1502
|
+
* Never overwrites user-assigned values (true/false).
|
|
1503
|
+
*/
|
|
1504
|
+
propagateOperatorConstraints(assignment) {
|
|
1505
|
+
const vars = { ...assignment.variables };
|
|
1506
|
+
const opAssignments = assignment.operatorAssignments;
|
|
1507
|
+
// Collect all expressions across all premises, indexed by id
|
|
1508
|
+
const exprById = new Map();
|
|
1509
|
+
// Children lookup: parentId -> sorted children
|
|
1510
|
+
const childrenOf = new Map();
|
|
1511
|
+
for (const pm of this.listPremises()) {
|
|
1512
|
+
for (const expr of pm.getExpressions()) {
|
|
1513
|
+
exprById.set(expr.id, expr);
|
|
1514
|
+
}
|
|
1515
|
+
// Build children map using getChildExpressions for each operator/formula
|
|
1516
|
+
for (const expr of pm.getExpressions()) {
|
|
1517
|
+
if (expr.type === "operator" || expr.type === "formula") {
|
|
1518
|
+
childrenOf.set(expr.id, pm.getChildExpressions(expr.id));
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
/**
|
|
1523
|
+
* Resolve the current Kleene value of an expression subtree
|
|
1524
|
+
* given the current variable assignments. Does not force-accept
|
|
1525
|
+
* nested operators — evaluates them normally via Kleene logic.
|
|
1526
|
+
*/
|
|
1527
|
+
const resolveValue = (exprId) => {
|
|
1528
|
+
const expr = exprById.get(exprId);
|
|
1529
|
+
if (!expr)
|
|
1530
|
+
return null;
|
|
1531
|
+
if (expr.type === "variable") {
|
|
1532
|
+
return (vars[expr
|
|
1533
|
+
.variableId] ?? null);
|
|
1534
|
+
}
|
|
1535
|
+
if (expr.type === "formula") {
|
|
1536
|
+
const children = childrenOf.get(expr.id) ?? [];
|
|
1537
|
+
return children.length > 0 ? resolveValue(children[0].id) : null;
|
|
1538
|
+
}
|
|
1539
|
+
// operator
|
|
1540
|
+
const op = expr
|
|
1541
|
+
.operator;
|
|
1542
|
+
const children = childrenOf.get(expr.id) ?? [];
|
|
1543
|
+
switch (op) {
|
|
1544
|
+
case "not":
|
|
1545
|
+
return kleeneNot(resolveValue(children[0].id));
|
|
1546
|
+
case "and":
|
|
1547
|
+
return children.reduce((acc, child) => kleeneAnd(acc, resolveValue(child.id)), true);
|
|
1548
|
+
case "or":
|
|
1549
|
+
return children.reduce((acc, child) => kleeneOr(acc, resolveValue(child.id)), false);
|
|
1550
|
+
case "implies": {
|
|
1551
|
+
return kleeneImplies(resolveValue(children[0].id), resolveValue(children[1].id));
|
|
1552
|
+
}
|
|
1553
|
+
case "iff": {
|
|
1554
|
+
return kleeneIff(resolveValue(children[0].id), resolveValue(children[1].id));
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
/**
|
|
1559
|
+
* Unwrap formula wrappers to find the leaf variable expression.
|
|
1560
|
+
* Returns the variableId if the leaf is a variable, otherwise null.
|
|
1561
|
+
*/
|
|
1562
|
+
const resolveLeafVariableId = (expr) => {
|
|
1563
|
+
if (expr.type === "variable") {
|
|
1564
|
+
return expr.variableId;
|
|
1565
|
+
}
|
|
1566
|
+
if (expr.type === "formula") {
|
|
1567
|
+
const children = childrenOf.get(expr.id) ?? [];
|
|
1568
|
+
if (children.length > 0) {
|
|
1569
|
+
return resolveLeafVariableId(children[0]);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
return null;
|
|
1573
|
+
};
|
|
1574
|
+
// Track which variable IDs were explicitly set by the user
|
|
1575
|
+
// (true or false). These are never overwritten by propagation.
|
|
1576
|
+
const userAssigned = new Set();
|
|
1577
|
+
for (const [varId, val] of Object.entries(vars)) {
|
|
1578
|
+
if (val !== null && val !== undefined)
|
|
1579
|
+
userAssigned.add(varId);
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Try to set a child expression's variable to a value.
|
|
1583
|
+
* Never overwrites user-assigned values.
|
|
1584
|
+
* False overrides propagated true (rejection wins).
|
|
1585
|
+
* Returns true if a value changed.
|
|
1586
|
+
*/
|
|
1587
|
+
const trySetChild = (child, value) => {
|
|
1588
|
+
const varId = resolveLeafVariableId(child);
|
|
1589
|
+
if (varId == null || userAssigned.has(varId))
|
|
1590
|
+
return false;
|
|
1591
|
+
const current = vars[varId] ?? null;
|
|
1592
|
+
if (current === null) {
|
|
1593
|
+
vars[varId] = value;
|
|
1594
|
+
return true;
|
|
1595
|
+
}
|
|
1596
|
+
// False overrides propagated true
|
|
1597
|
+
if (value === false && current === true) {
|
|
1598
|
+
vars[varId] = false;
|
|
1599
|
+
return true;
|
|
1600
|
+
}
|
|
1601
|
+
return false;
|
|
1602
|
+
};
|
|
1603
|
+
// Two-phase propagation: rejections first (to establish false values),
|
|
1604
|
+
// then acceptances (which only fill remaining unknowns).
|
|
1605
|
+
// This prevents acceptance from deriving values through chains that
|
|
1606
|
+
// are later invalidated by rejection.
|
|
1607
|
+
for (const phase of ["rejected", "accepted"]) {
|
|
1608
|
+
let changed = true;
|
|
1609
|
+
while (changed) {
|
|
1610
|
+
changed = false;
|
|
1611
|
+
for (const [exprId, expr] of exprById) {
|
|
1612
|
+
if (expr.type !== "operator")
|
|
1613
|
+
continue;
|
|
1614
|
+
const state = opAssignments[exprId];
|
|
1615
|
+
if (state !== phase)
|
|
1616
|
+
continue;
|
|
1617
|
+
const op = expr.operator;
|
|
1618
|
+
const children = childrenOf.get(exprId) ?? [];
|
|
1619
|
+
if (state === "accepted") {
|
|
1620
|
+
switch (op) {
|
|
1621
|
+
case "not": {
|
|
1622
|
+
// ¬A accepted (= true) => child must be false
|
|
1623
|
+
if (children.length > 0) {
|
|
1624
|
+
if (trySetChild(children[0], false))
|
|
1625
|
+
changed = true;
|
|
1626
|
+
}
|
|
1627
|
+
break;
|
|
1628
|
+
}
|
|
1629
|
+
case "and": {
|
|
1630
|
+
// A ∧ B accepted => all children must be true
|
|
1631
|
+
for (const child of children) {
|
|
1632
|
+
if (trySetChild(child, true))
|
|
1633
|
+
changed = true;
|
|
1634
|
+
}
|
|
1635
|
+
break;
|
|
1636
|
+
}
|
|
1637
|
+
case "or": {
|
|
1638
|
+
// A ∨ B accepted: if all-but-one are false, remaining must be true
|
|
1639
|
+
const unknownChildren = [];
|
|
1640
|
+
let allOthersAreFalse = true;
|
|
1641
|
+
for (const child of children) {
|
|
1642
|
+
const childValue = resolveValue(child.id);
|
|
1643
|
+
if (childValue === null) {
|
|
1644
|
+
unknownChildren.push(child);
|
|
1645
|
+
}
|
|
1646
|
+
else if (childValue !== false) {
|
|
1647
|
+
allOthersAreFalse = false;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
if (unknownChildren.length === 1 &&
|
|
1651
|
+
allOthersAreFalse) {
|
|
1652
|
+
if (trySetChild(unknownChildren[0], true))
|
|
1653
|
+
changed = true;
|
|
1654
|
+
}
|
|
1655
|
+
break;
|
|
1656
|
+
}
|
|
1657
|
+
case "implies": {
|
|
1658
|
+
// A → B accepted: if A=true => B=true; if B=false => A=false
|
|
1659
|
+
if (children.length >= 2) {
|
|
1660
|
+
const leftValue = resolveValue(children[0].id);
|
|
1661
|
+
const rightValue = resolveValue(children[1].id);
|
|
1662
|
+
if (leftValue === true) {
|
|
1663
|
+
if (trySetChild(children[1], true))
|
|
1664
|
+
changed = true;
|
|
1665
|
+
}
|
|
1666
|
+
if (rightValue === false) {
|
|
1667
|
+
if (trySetChild(children[0], false))
|
|
1668
|
+
changed = true;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
break;
|
|
1672
|
+
}
|
|
1673
|
+
case "iff": {
|
|
1674
|
+
// A ↔ B accepted: if A known => B matches; if B known => A matches
|
|
1675
|
+
if (children.length >= 2) {
|
|
1676
|
+
const leftValue = resolveValue(children[0].id);
|
|
1677
|
+
const rightValue = resolveValue(children[1].id);
|
|
1678
|
+
if (leftValue !== null) {
|
|
1679
|
+
if (trySetChild(children[1], leftValue))
|
|
1680
|
+
changed = true;
|
|
1681
|
+
}
|
|
1682
|
+
if (rightValue !== null) {
|
|
1683
|
+
if (trySetChild(children[0], rightValue))
|
|
1684
|
+
changed = true;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
break;
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
else {
|
|
1692
|
+
// state === "rejected" — expression forced false
|
|
1693
|
+
switch (op) {
|
|
1694
|
+
case "not": {
|
|
1695
|
+
// ¬A rejected (= false) => child must be true
|
|
1696
|
+
if (children.length > 0) {
|
|
1697
|
+
if (trySetChild(children[0], true))
|
|
1698
|
+
changed = true;
|
|
1699
|
+
}
|
|
1700
|
+
break;
|
|
1701
|
+
}
|
|
1702
|
+
case "and": {
|
|
1703
|
+
// A ∧ B rejected (= false): if all-but-one are true, remaining must be false
|
|
1704
|
+
const unknownChildren = [];
|
|
1705
|
+
let allOthersAreTrue = true;
|
|
1706
|
+
for (const child of children) {
|
|
1707
|
+
const childValue = resolveValue(child.id);
|
|
1708
|
+
if (childValue === null) {
|
|
1709
|
+
unknownChildren.push(child);
|
|
1710
|
+
}
|
|
1711
|
+
else if (childValue !== true) {
|
|
1712
|
+
allOthersAreTrue = false;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
if (unknownChildren.length === 1 &&
|
|
1716
|
+
allOthersAreTrue) {
|
|
1717
|
+
if (trySetChild(unknownChildren[0], false))
|
|
1718
|
+
changed = true;
|
|
1719
|
+
}
|
|
1720
|
+
break;
|
|
1721
|
+
}
|
|
1722
|
+
case "or": {
|
|
1723
|
+
// A ∨ B rejected (= false) => all children must be false
|
|
1724
|
+
for (const child of children) {
|
|
1725
|
+
if (trySetChild(child, false))
|
|
1726
|
+
changed = true;
|
|
1727
|
+
}
|
|
1728
|
+
break;
|
|
1729
|
+
}
|
|
1730
|
+
case "implies": {
|
|
1731
|
+
// A → B rejected (= false) => A must be true, B must be false
|
|
1732
|
+
if (children.length >= 2) {
|
|
1733
|
+
if (trySetChild(children[0], true))
|
|
1734
|
+
changed = true;
|
|
1735
|
+
if (trySetChild(children[1], false))
|
|
1736
|
+
changed = true;
|
|
1737
|
+
}
|
|
1738
|
+
break;
|
|
1739
|
+
}
|
|
1740
|
+
case "iff": {
|
|
1741
|
+
// A ↔ B rejected (= false): if A known => B is opposite; if B known => A is opposite
|
|
1742
|
+
if (children.length >= 2) {
|
|
1743
|
+
const leftValue = resolveValue(children[0].id);
|
|
1744
|
+
const rightValue = resolveValue(children[1].id);
|
|
1745
|
+
if (leftValue !== null) {
|
|
1746
|
+
if (trySetChild(children[1], !leftValue))
|
|
1747
|
+
changed = true;
|
|
1748
|
+
}
|
|
1749
|
+
if (rightValue !== null) {
|
|
1750
|
+
if (trySetChild(children[0], !rightValue))
|
|
1751
|
+
changed = true;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
break;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
return vars;
|
|
1762
|
+
}
|
|
1491
1763
|
evaluate(assignment, options) {
|
|
1492
1764
|
const validateFirst = options?.validateFirst ?? true;
|
|
1493
1765
|
if (validateFirst) {
|
|
@@ -1538,6 +1810,12 @@ export class ArgumentEngine {
|
|
|
1538
1810
|
return true;
|
|
1539
1811
|
return false;
|
|
1540
1812
|
});
|
|
1813
|
+
// Run operator constraint propagation
|
|
1814
|
+
const propagatedVars = this.propagateOperatorConstraints(assignment);
|
|
1815
|
+
const propagatedAssignment = {
|
|
1816
|
+
variables: propagatedVars,
|
|
1817
|
+
operatorAssignments: assignment.operatorAssignments,
|
|
1818
|
+
};
|
|
1541
1819
|
try {
|
|
1542
1820
|
// Build a resolver that lazily evaluates premise-bound variables
|
|
1543
1821
|
// by evaluating their bound premise's expression tree under the
|
|
@@ -1552,7 +1830,7 @@ export class ArgumentEngine {
|
|
|
1552
1830
|
!isPremiseBound(variable) ||
|
|
1553
1831
|
variable.boundArgumentId !== this.argument.id) {
|
|
1554
1832
|
// Claim-bound or externally-bound: read from assignment
|
|
1555
|
-
return
|
|
1833
|
+
return propagatedAssignment.variables[variableId] ?? null;
|
|
1556
1834
|
}
|
|
1557
1835
|
// Internal premise-bound: lazy resolution
|
|
1558
1836
|
const boundPremiseId = variable.boundPremiseId;
|
|
@@ -1561,7 +1839,7 @@ export class ArgumentEngine {
|
|
|
1561
1839
|
resolverCache.set(variableId, null);
|
|
1562
1840
|
return null;
|
|
1563
1841
|
}
|
|
1564
|
-
const premiseResult = boundPremise.evaluate(
|
|
1842
|
+
const premiseResult = boundPremise.evaluate(propagatedAssignment, {
|
|
1565
1843
|
resolver,
|
|
1566
1844
|
});
|
|
1567
1845
|
const value = premiseResult?.rootValue ?? null;
|
|
@@ -1572,9 +1850,9 @@ export class ArgumentEngine {
|
|
|
1572
1850
|
strictUnknownKeys: options?.strictUnknownAssignmentKeys ?? false,
|
|
1573
1851
|
resolver,
|
|
1574
1852
|
};
|
|
1575
|
-
const conclusionEvaluation = conclusion.evaluate(
|
|
1576
|
-
const supportingEvaluations = supportingPremises.map((pm) => pm.evaluate(
|
|
1577
|
-
const constraintEvaluations = constraintPremises.map((pm) => pm.evaluate(
|
|
1853
|
+
const conclusionEvaluation = conclusion.evaluate(propagatedAssignment, evalOpts);
|
|
1854
|
+
const supportingEvaluations = supportingPremises.map((pm) => pm.evaluate(propagatedAssignment, evalOpts));
|
|
1855
|
+
const constraintEvaluations = constraintPremises.map((pm) => pm.evaluate(propagatedAssignment, evalOpts));
|
|
1578
1856
|
const isAdmissibleAssignment = constraintEvaluations.reduce((acc, result) => kleeneAnd(acc, result.rootValue ?? null), true);
|
|
1579
1857
|
const allSupportingPremisesTrue = supportingEvaluations.reduce((acc, result) => kleeneAnd(acc, result.rootValue ?? null), true);
|
|
1580
1858
|
const conclusionTrue = conclusionEvaluation.rootValue ?? null;
|
|
@@ -1593,10 +1871,10 @@ export class ArgumentEngine {
|
|
|
1593
1871
|
return {
|
|
1594
1872
|
ok: true,
|
|
1595
1873
|
assignment: {
|
|
1596
|
-
variables: { ...
|
|
1597
|
-
|
|
1598
|
-
...
|
|
1599
|
-
|
|
1874
|
+
variables: { ...propagatedAssignment.variables },
|
|
1875
|
+
operatorAssignments: {
|
|
1876
|
+
...propagatedAssignment.operatorAssignments,
|
|
1877
|
+
},
|
|
1600
1878
|
},
|
|
1601
1879
|
referencedVariableIds,
|
|
1602
1880
|
conclusion: strip(conclusionEvaluation),
|
|
@@ -1699,7 +1977,7 @@ export class ArgumentEngine {
|
|
|
1699
1977
|
}
|
|
1700
1978
|
const assignment = {
|
|
1701
1979
|
variables: {},
|
|
1702
|
-
|
|
1980
|
+
operatorAssignments: {},
|
|
1703
1981
|
};
|
|
1704
1982
|
for (let i = 0; i < checkedVariableIds.length; i++) {
|
|
1705
1983
|
assignment.variables[checkedVariableIds[i]] = Boolean(mask & (1 << i));
|