@polintpro/proposit-core 0.8.7 → 0.8.8
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/extensions/ieee/formatting.d.ts +2 -14
- package/dist/extensions/ieee/formatting.d.ts.map +1 -1
- package/dist/extensions/ieee/formatting.js +42 -1038
- package/dist/extensions/ieee/formatting.js.map +1 -1
- package/dist/extensions/ieee/index.d.ts +1 -0
- package/dist/extensions/ieee/index.d.ts.map +1 -1
- package/dist/extensions/ieee/index.js +1 -0
- package/dist/extensions/ieee/index.js.map +1 -1
- package/dist/extensions/ieee/segment-builder.d.ts +9 -0
- package/dist/extensions/ieee/segment-builder.d.ts.map +1 -0
- package/dist/extensions/ieee/segment-builder.js +98 -0
- package/dist/extensions/ieee/segment-builder.js.map +1 -0
- package/dist/extensions/ieee/segment-templates.d.ts +58 -0
- package/dist/extensions/ieee/segment-templates.d.ts.map +1 -0
- package/dist/extensions/ieee/segment-templates.js +1618 -0
- package/dist/extensions/ieee/segment-templates.js.map +1 -0
- package/dist/lib/core/argument-engine.d.ts +2 -19
- package/dist/lib/core/argument-engine.d.ts.map +1 -1
- package/dist/lib/core/argument-engine.js +46 -819
- package/dist/lib/core/argument-engine.js.map +1 -1
- package/dist/lib/core/argument-validation.d.ts +74 -0
- package/dist/lib/core/argument-validation.d.ts.map +1 -0
- package/dist/lib/core/argument-validation.js +315 -0
- package/dist/lib/core/argument-validation.js.map +1 -0
- package/dist/lib/core/evaluation/argument-evaluation.d.ts +53 -0
- package/dist/lib/core/evaluation/argument-evaluation.d.ts.map +1 -0
- package/dist/lib/core/evaluation/argument-evaluation.js +535 -0
- package/dist/lib/core/evaluation/argument-evaluation.js.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CoreArgumentSchema, isClaimBound, isPremiseBound, } from "../schemata/index.js";
|
|
1
|
+
import { isClaimBound, isPremiseBound, } from "../schemata/index.js";
|
|
3
2
|
import { DEFAULT_GRAMMAR_CONFIG, PERMISSIVE_GRAMMAR_CONFIG, } from "../types/grammar.js";
|
|
4
|
-
import { ARG_SCHEMA_INVALID, ARG_OWNERSHIP_MISMATCH, ARG_CLAIM_REF_NOT_FOUND, ARG_PREMISE_REF_NOT_FOUND, ARG_CIRCULARITY_DETECTED, ARG_CONCLUSION_NOT_FOUND, ARG_CHECKSUM_MISMATCH, } from "../types/validation.js";
|
|
5
3
|
import { DEFAULT_CHECKSUM_CONFIG, normalizeChecksumConfig, serializeChecksumConfig, } from "../consts.js";
|
|
6
|
-
import { getOrCreate, sortedUnique } from "../utils/collections.js";
|
|
7
4
|
import { ChangeCollector } from "./change-collector.js";
|
|
8
5
|
import { canonicalSerialize, computeHash, entityChecksum } from "./checksum.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
6
|
+
import { evaluateArgument as evaluateArgumentStandalone, checkArgumentValidity as checkArgumentValidityStandalone, } from "./evaluation/argument-evaluation.js";
|
|
7
|
+
import { validateArgument as validateArgumentStandalone, validateArgumentAfterPremiseMutation as validateAfterPremiseMutationStandalone, validateArgumentEvaluability as validateArgumentEvaluabilityStandalone, collectArgumentReferencedVariables as collectArgumentReferencedVariablesStandalone, } from "./argument-validation.js";
|
|
11
8
|
import { InvariantViolationError } from "./invariant-violation-error.js";
|
|
12
9
|
import { PremiseEngine } from "./premise-engine.js";
|
|
13
10
|
import { VariableManager } from "./variable-manager.js";
|
|
@@ -1181,833 +1178,63 @@ export class ArgumentEngine {
|
|
|
1181
1178
|
};
|
|
1182
1179
|
}
|
|
1183
1180
|
collectReferencedVariables() {
|
|
1184
|
-
|
|
1185
|
-
const bySymbolTmp = new Map();
|
|
1186
|
-
for (const premise of this.listPremises()) {
|
|
1187
|
-
const premiseId = premise.getId();
|
|
1188
|
-
const varsById = new Map(premise.getVariables().map((v) => [v.id, v]));
|
|
1189
|
-
for (const expr of premise.getExpressions()) {
|
|
1190
|
-
if (expr.type !== "variable")
|
|
1191
|
-
continue;
|
|
1192
|
-
const variable = varsById.get(expr.variableId);
|
|
1193
|
-
if (!variable)
|
|
1194
|
-
continue;
|
|
1195
|
-
const byIdEntry = getOrCreate(byIdTmp, variable.id, () => ({
|
|
1196
|
-
symbols: new Set(),
|
|
1197
|
-
premiseIds: new Set(),
|
|
1198
|
-
}));
|
|
1199
|
-
byIdEntry.symbols.add(variable.symbol);
|
|
1200
|
-
byIdEntry.premiseIds.add(premiseId);
|
|
1201
|
-
const bySymbolEntry = getOrCreate(bySymbolTmp, variable.symbol, () => ({
|
|
1202
|
-
variableIds: new Set(),
|
|
1203
|
-
premiseIds: new Set(),
|
|
1204
|
-
}));
|
|
1205
|
-
bySymbolEntry.variableIds.add(variable.id);
|
|
1206
|
-
bySymbolEntry.premiseIds.add(premiseId);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
const byId = {};
|
|
1210
|
-
for (const [variableId, entry] of Array.from(byIdTmp.entries()).sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
1211
|
-
byId[variableId] = {
|
|
1212
|
-
symbol: sortedUnique(entry.symbols)[0] ?? "",
|
|
1213
|
-
premiseIds: sortedUnique(entry.premiseIds),
|
|
1214
|
-
};
|
|
1215
|
-
}
|
|
1216
|
-
const bySymbol = {};
|
|
1217
|
-
for (const [symbol, entry] of Array.from(bySymbolTmp.entries()).sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
1218
|
-
bySymbol[symbol] = {
|
|
1219
|
-
variableIds: sortedUnique(entry.variableIds),
|
|
1220
|
-
premiseIds: sortedUnique(entry.premiseIds),
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
return {
|
|
1224
|
-
variableIds: sortedUnique(byIdTmp.keys()),
|
|
1225
|
-
byId,
|
|
1226
|
-
bySymbol,
|
|
1227
|
-
};
|
|
1181
|
+
return collectArgumentReferencedVariablesStandalone(this.asValidationContext());
|
|
1228
1182
|
}
|
|
1229
|
-
/**
|
|
1230
|
-
* Validates after a PremiseEngine mutation. Identical to `validate()` but
|
|
1231
|
-
* clears cached argument-level checksums first so the checksum-stability
|
|
1232
|
-
* check is skipped (checksums are known to be dirty after a premise
|
|
1233
|
-
* mutation).
|
|
1234
|
-
*/
|
|
1235
|
-
/**
|
|
1236
|
-
* Lightweight validation triggered after a PremiseEngine mutation.
|
|
1237
|
-
* Skips per-premise deep validation (which is O(n) over all premises)
|
|
1238
|
-
* and argument-level checksum stability checks (checksums are known to
|
|
1239
|
-
* be dirty). Only checks argument-level cross-references that a
|
|
1240
|
-
* PremiseEngine mutation could affect.
|
|
1241
|
-
*/
|
|
1242
1183
|
validateAfterPremiseMutation() {
|
|
1243
|
-
|
|
1244
|
-
// Variable references: ensure all variable expressions in the
|
|
1245
|
-
// mutated premise still reference known variables (this is the main
|
|
1246
|
-
// cross-cutting invariant a premise mutation can break).
|
|
1247
|
-
for (const v of this.variables.toArray()) {
|
|
1248
|
-
const base = v;
|
|
1249
|
-
if (isPremiseBound(base)) {
|
|
1250
|
-
const pb = base;
|
|
1251
|
-
if (pb.boundArgumentId === this.argument.id) {
|
|
1252
|
-
if (!this.premises.has(pb.boundPremiseId)) {
|
|
1253
|
-
violations.push({
|
|
1254
|
-
code: ARG_PREMISE_REF_NOT_FOUND,
|
|
1255
|
-
message: `Premise-bound variable "${pb.id}" references non-existent premise "${pb.boundPremiseId}".`,
|
|
1256
|
-
entityType: "variable",
|
|
1257
|
-
entityId: pb.id,
|
|
1258
|
-
});
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
// Conclusion premise reference
|
|
1264
|
-
if (this.conclusionPremiseId !== undefined &&
|
|
1265
|
-
!this.premises.has(this.conclusionPremiseId)) {
|
|
1266
|
-
violations.push({
|
|
1267
|
-
code: ARG_CONCLUSION_NOT_FOUND,
|
|
1268
|
-
message: `Conclusion premise "${this.conclusionPremiseId}" does not exist in this argument.`,
|
|
1269
|
-
entityType: "argument",
|
|
1270
|
-
entityId: this.argument.id,
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
return {
|
|
1274
|
-
ok: violations.length === 0,
|
|
1275
|
-
violations,
|
|
1276
|
-
};
|
|
1184
|
+
return validateAfterPremiseMutationStandalone(this.asValidationContext());
|
|
1277
1185
|
}
|
|
1278
1186
|
validate() {
|
|
1279
|
-
|
|
1280
|
-
// 1. Schema check — flush checksums first so fields are populated
|
|
1281
|
-
const savedMeta = this.cachedMetaChecksum;
|
|
1282
|
-
const savedDescendant = this.cachedDescendantChecksum;
|
|
1283
|
-
const savedCombined = this.cachedCombinedChecksum;
|
|
1284
|
-
this.flushChecksums();
|
|
1285
|
-
const arg = this.getArgument();
|
|
1286
|
-
if (!Value.Check(CoreArgumentSchema, arg)) {
|
|
1287
|
-
violations.push({
|
|
1288
|
-
code: ARG_SCHEMA_INVALID,
|
|
1289
|
-
message: `Argument "${arg.id}" does not conform to CoreArgumentSchema.`,
|
|
1290
|
-
entityType: "argument",
|
|
1291
|
-
entityId: arg.id,
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
// 2. Delegate to VariableManager.validate()
|
|
1295
|
-
const varResult = this.variables.validate();
|
|
1296
|
-
violations.push(...varResult.violations);
|
|
1297
|
-
// 3. Delegate to each PremiseEngine.validate()
|
|
1298
|
-
for (const pe of this.listPremises()) {
|
|
1299
|
-
const premiseResult = pe.validate();
|
|
1300
|
-
violations.push(...premiseResult.violations);
|
|
1301
|
-
}
|
|
1302
|
-
// 4. Variable ownership: all variables must belong to this argument
|
|
1303
|
-
for (const v of this.variables.toArray()) {
|
|
1304
|
-
const base = v;
|
|
1305
|
-
if (base.argumentId !== this.argument.id ||
|
|
1306
|
-
base.argumentVersion !== this.argument.version) {
|
|
1307
|
-
violations.push({
|
|
1308
|
-
code: ARG_OWNERSHIP_MISMATCH,
|
|
1309
|
-
message: `Variable "${base.id}" has argumentId/version "${base.argumentId}/${base.argumentVersion}" but engine is "${this.argument.id}/${this.argument.version}".`,
|
|
1310
|
-
entityType: "variable",
|
|
1311
|
-
entityId: base.id,
|
|
1312
|
-
});
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
// 5. Claim-bound variable references
|
|
1316
|
-
for (const v of this.variables.toArray()) {
|
|
1317
|
-
const base = v;
|
|
1318
|
-
if (isClaimBound(base)) {
|
|
1319
|
-
const cb = base;
|
|
1320
|
-
if (!this.claimLibrary.get(cb.claimId, cb.claimVersion)) {
|
|
1321
|
-
violations.push({
|
|
1322
|
-
code: ARG_CLAIM_REF_NOT_FOUND,
|
|
1323
|
-
message: `Variable "${cb.id}" references claim "${cb.claimId}" version ${cb.claimVersion} which does not exist in the claim library.`,
|
|
1324
|
-
entityType: "variable",
|
|
1325
|
-
entityId: cb.id,
|
|
1326
|
-
});
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
// 6. Premise-bound internal variable references
|
|
1331
|
-
for (const v of this.variables.toArray()) {
|
|
1332
|
-
const base = v;
|
|
1333
|
-
if (isPremiseBound(base)) {
|
|
1334
|
-
const pb = base;
|
|
1335
|
-
if (pb.boundArgumentId === this.argument.id) {
|
|
1336
|
-
if (!this.premises.has(pb.boundPremiseId)) {
|
|
1337
|
-
violations.push({
|
|
1338
|
-
code: ARG_PREMISE_REF_NOT_FOUND,
|
|
1339
|
-
message: `Premise-bound variable "${pb.id}" references non-existent premise "${pb.boundPremiseId}".`,
|
|
1340
|
-
entityType: "variable",
|
|
1341
|
-
entityId: pb.id,
|
|
1342
|
-
});
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
// 7. Circularity detection for internal premise-bound variables.
|
|
1348
|
-
// A cycle exists when a premise-bound variable's bound premise
|
|
1349
|
-
// transitively references back to itself through other
|
|
1350
|
-
// premise-bound variables.
|
|
1351
|
-
for (const v of this.variables.toArray()) {
|
|
1352
|
-
const base = v;
|
|
1353
|
-
if (isPremiseBound(base)) {
|
|
1354
|
-
const pb = base;
|
|
1355
|
-
if (pb.boundArgumentId === this.argument.id) {
|
|
1356
|
-
// Trace from the bound premise through expressions'
|
|
1357
|
-
// variable references to see if we reach back to the
|
|
1358
|
-
// same premise.
|
|
1359
|
-
const boundPremise = this.premises.get(pb.boundPremiseId);
|
|
1360
|
-
if (boundPremise) {
|
|
1361
|
-
let hasCycle = false;
|
|
1362
|
-
for (const expr of boundPremise.getExpressions()) {
|
|
1363
|
-
if (expr.type === "variable") {
|
|
1364
|
-
try {
|
|
1365
|
-
if (this.wouldCreateCycle(expr.variableId, pb.boundPremiseId, new Set())) {
|
|
1366
|
-
hasCycle = true;
|
|
1367
|
-
break;
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
catch {
|
|
1371
|
-
hasCycle = true;
|
|
1372
|
-
break;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
if (hasCycle) {
|
|
1377
|
-
violations.push({
|
|
1378
|
-
code: ARG_CIRCULARITY_DETECTED,
|
|
1379
|
-
message: `Premise-bound variable "${pb.id}" creates a circular dependency through premise "${pb.boundPremiseId}".`,
|
|
1380
|
-
entityType: "variable",
|
|
1381
|
-
entityId: pb.id,
|
|
1382
|
-
});
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
// 8. Conclusion premise reference
|
|
1389
|
-
if (this.conclusionPremiseId !== undefined &&
|
|
1390
|
-
!this.premises.has(this.conclusionPremiseId)) {
|
|
1391
|
-
violations.push({
|
|
1392
|
-
code: ARG_CONCLUSION_NOT_FOUND,
|
|
1393
|
-
message: `Conclusion premise "${this.conclusionPremiseId}" does not exist in this argument.`,
|
|
1394
|
-
entityType: "argument",
|
|
1395
|
-
entityId: this.argument.id,
|
|
1396
|
-
});
|
|
1397
|
-
}
|
|
1398
|
-
// 9. Argument-level checksum verification
|
|
1399
|
-
if (savedMeta !== undefined && savedMeta !== this.cachedMetaChecksum) {
|
|
1400
|
-
violations.push({
|
|
1401
|
-
code: ARG_CHECKSUM_MISMATCH,
|
|
1402
|
-
message: `Argument "${this.argument.id}" meta checksum changed after flush: "${savedMeta}" → "${this.cachedMetaChecksum}".`,
|
|
1403
|
-
entityType: "argument",
|
|
1404
|
-
entityId: this.argument.id,
|
|
1405
|
-
});
|
|
1406
|
-
}
|
|
1407
|
-
if (savedDescendant !== undefined &&
|
|
1408
|
-
savedDescendant !== this.cachedDescendantChecksum) {
|
|
1409
|
-
violations.push({
|
|
1410
|
-
code: ARG_CHECKSUM_MISMATCH,
|
|
1411
|
-
message: `Argument "${this.argument.id}" descendant checksum changed after flush: "${String(savedDescendant)}" → "${String(this.cachedDescendantChecksum)}".`,
|
|
1412
|
-
entityType: "argument",
|
|
1413
|
-
entityId: this.argument.id,
|
|
1414
|
-
});
|
|
1415
|
-
}
|
|
1416
|
-
if (savedCombined !== undefined &&
|
|
1417
|
-
savedCombined !== this.cachedCombinedChecksum) {
|
|
1418
|
-
violations.push({
|
|
1419
|
-
code: ARG_CHECKSUM_MISMATCH,
|
|
1420
|
-
message: `Argument "${this.argument.id}" combined checksum changed after flush: "${savedCombined}" → "${this.cachedCombinedChecksum}".`,
|
|
1421
|
-
entityType: "argument",
|
|
1422
|
-
entityId: this.argument.id,
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
return {
|
|
1426
|
-
ok: violations.length === 0,
|
|
1427
|
-
violations,
|
|
1428
|
-
};
|
|
1187
|
+
return validateArgumentStandalone(this.asValidationContext());
|
|
1429
1188
|
}
|
|
1430
1189
|
validateEvaluability() {
|
|
1431
|
-
|
|
1432
|
-
if (this.conclusionPremiseId === undefined) {
|
|
1433
|
-
issues.push(makeErrorIssue({
|
|
1434
|
-
code: "ARGUMENT_NO_CONCLUSION",
|
|
1435
|
-
message: "Argument has no designated conclusion premise.",
|
|
1436
|
-
}));
|
|
1437
|
-
}
|
|
1438
|
-
else if (!this.premises.has(this.conclusionPremiseId)) {
|
|
1439
|
-
issues.push(makeErrorIssue({
|
|
1440
|
-
code: "ARGUMENT_CONCLUSION_NOT_FOUND",
|
|
1441
|
-
message: `Conclusion premise "${this.conclusionPremiseId}" does not exist.`,
|
|
1442
|
-
premiseId: this.conclusionPremiseId,
|
|
1443
|
-
}));
|
|
1444
|
-
}
|
|
1445
|
-
const idToSymbols = new Map();
|
|
1446
|
-
const symbolToIds = new Map();
|
|
1447
|
-
for (const premise of this.listPremises()) {
|
|
1448
|
-
const varById = new Map(premise.getVariables().map((v) => [v.id, v]));
|
|
1449
|
-
for (const expr of premise.getExpressions()) {
|
|
1450
|
-
if (expr.type !== "variable")
|
|
1451
|
-
continue;
|
|
1452
|
-
const variable = varById.get(expr.variableId);
|
|
1453
|
-
if (!variable)
|
|
1454
|
-
continue;
|
|
1455
|
-
getOrCreate(idToSymbols, variable.id, () => new Set()).add(variable.symbol);
|
|
1456
|
-
getOrCreate(symbolToIds, variable.symbol, () => new Set()).add(variable.id);
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
for (const [variableId, symbols] of idToSymbols) {
|
|
1460
|
-
if (symbols.size > 1) {
|
|
1461
|
-
issues.push(makeErrorIssue({
|
|
1462
|
-
code: "ARGUMENT_VARIABLE_ID_SYMBOL_MISMATCH",
|
|
1463
|
-
message: `Variable ID "${variableId}" is used with multiple symbols: ${sortedUnique(symbols).join(", ")}.`,
|
|
1464
|
-
variableId,
|
|
1465
|
-
}));
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
for (const [symbol, ids] of symbolToIds) {
|
|
1469
|
-
if (ids.size > 1) {
|
|
1470
|
-
issues.push(makeErrorIssue({
|
|
1471
|
-
code: "ARGUMENT_VARIABLE_SYMBOL_AMBIGUOUS",
|
|
1472
|
-
message: `Variable symbol "${symbol}" is used with multiple IDs: ${sortedUnique(ids).join(", ")}.`,
|
|
1473
|
-
}));
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
for (const premise of this.listPremises()) {
|
|
1477
|
-
const premiseValidation = premise.validateEvaluability();
|
|
1478
|
-
issues.push(...premiseValidation.issues);
|
|
1479
|
-
}
|
|
1480
|
-
return makeValidationResult(issues);
|
|
1481
|
-
}
|
|
1482
|
-
/**
|
|
1483
|
-
* Run fixed-point constraint propagation over accepted operators.
|
|
1484
|
-
* Fills unknown (null) variable values based on operator semantics.
|
|
1485
|
-
* Never overwrites user-assigned values (true/false).
|
|
1486
|
-
*/
|
|
1487
|
-
propagateOperatorConstraints(assignment) {
|
|
1488
|
-
const vars = { ...assignment.variables };
|
|
1489
|
-
const opAssignments = assignment.operatorAssignments;
|
|
1490
|
-
// Collect all expressions across all premises, indexed by id
|
|
1491
|
-
const exprById = new Map();
|
|
1492
|
-
// Children lookup: parentId -> sorted children
|
|
1493
|
-
const childrenOf = new Map();
|
|
1494
|
-
for (const pm of this.listPremises()) {
|
|
1495
|
-
for (const expr of pm.getExpressions()) {
|
|
1496
|
-
exprById.set(expr.id, expr);
|
|
1497
|
-
}
|
|
1498
|
-
// Build children map using getChildExpressions for each operator/formula
|
|
1499
|
-
for (const expr of pm.getExpressions()) {
|
|
1500
|
-
if (expr.type === "operator" || expr.type === "formula") {
|
|
1501
|
-
childrenOf.set(expr.id, pm.getChildExpressions(expr.id));
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
/**
|
|
1506
|
-
* Resolve the current Kleene value of an expression subtree
|
|
1507
|
-
* given the current variable assignments. Does not force-accept
|
|
1508
|
-
* nested operators — evaluates them normally via Kleene logic.
|
|
1509
|
-
*/
|
|
1510
|
-
const resolveValue = (exprId) => {
|
|
1511
|
-
const expr = exprById.get(exprId);
|
|
1512
|
-
if (!expr)
|
|
1513
|
-
return null;
|
|
1514
|
-
if (expr.type === "variable") {
|
|
1515
|
-
return (vars[expr
|
|
1516
|
-
.variableId] ?? null);
|
|
1517
|
-
}
|
|
1518
|
-
if (expr.type === "formula") {
|
|
1519
|
-
const children = childrenOf.get(expr.id) ?? [];
|
|
1520
|
-
return children.length > 0 ? resolveValue(children[0].id) : null;
|
|
1521
|
-
}
|
|
1522
|
-
// operator
|
|
1523
|
-
const op = expr
|
|
1524
|
-
.operator;
|
|
1525
|
-
const children = childrenOf.get(expr.id) ?? [];
|
|
1526
|
-
switch (op) {
|
|
1527
|
-
case "not":
|
|
1528
|
-
return kleeneNot(resolveValue(children[0].id));
|
|
1529
|
-
case "and":
|
|
1530
|
-
return children.reduce((acc, child) => kleeneAnd(acc, resolveValue(child.id)), true);
|
|
1531
|
-
case "or":
|
|
1532
|
-
return children.reduce((acc, child) => kleeneOr(acc, resolveValue(child.id)), false);
|
|
1533
|
-
case "implies": {
|
|
1534
|
-
return kleeneImplies(resolveValue(children[0].id), resolveValue(children[1].id));
|
|
1535
|
-
}
|
|
1536
|
-
case "iff": {
|
|
1537
|
-
return kleeneIff(resolveValue(children[0].id), resolveValue(children[1].id));
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
};
|
|
1541
|
-
/**
|
|
1542
|
-
* Unwrap formula wrappers to find the leaf variable expression.
|
|
1543
|
-
* Returns the variableId if the leaf is a variable, otherwise null.
|
|
1544
|
-
*/
|
|
1545
|
-
const resolveLeafVariableId = (expr) => {
|
|
1546
|
-
if (expr.type === "variable") {
|
|
1547
|
-
return expr.variableId;
|
|
1548
|
-
}
|
|
1549
|
-
if (expr.type === "formula") {
|
|
1550
|
-
const children = childrenOf.get(expr.id) ?? [];
|
|
1551
|
-
if (children.length > 0) {
|
|
1552
|
-
return resolveLeafVariableId(children[0]);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
return null;
|
|
1556
|
-
};
|
|
1557
|
-
// Track which variable IDs were explicitly set by the user
|
|
1558
|
-
// (true or false). These are never overwritten by propagation.
|
|
1559
|
-
const userAssigned = new Set();
|
|
1560
|
-
for (const [varId, val] of Object.entries(vars)) {
|
|
1561
|
-
if (val !== null && val !== undefined)
|
|
1562
|
-
userAssigned.add(varId);
|
|
1563
|
-
}
|
|
1564
|
-
/**
|
|
1565
|
-
* Try to set a child expression's variable to a value.
|
|
1566
|
-
* Never overwrites user-assigned values.
|
|
1567
|
-
* False overrides propagated true (rejection wins).
|
|
1568
|
-
* Returns true if a value changed.
|
|
1569
|
-
*/
|
|
1570
|
-
const trySetChild = (child, value) => {
|
|
1571
|
-
const varId = resolveLeafVariableId(child);
|
|
1572
|
-
if (varId == null || userAssigned.has(varId))
|
|
1573
|
-
return false;
|
|
1574
|
-
const current = vars[varId] ?? null;
|
|
1575
|
-
if (current === null) {
|
|
1576
|
-
vars[varId] = value;
|
|
1577
|
-
return true;
|
|
1578
|
-
}
|
|
1579
|
-
// False overrides propagated true
|
|
1580
|
-
if (value === false && current === true) {
|
|
1581
|
-
vars[varId] = false;
|
|
1582
|
-
return true;
|
|
1583
|
-
}
|
|
1584
|
-
return false;
|
|
1585
|
-
};
|
|
1586
|
-
// Two-phase propagation: rejections first (to establish false values),
|
|
1587
|
-
// then acceptances (which only fill remaining unknowns).
|
|
1588
|
-
// This prevents acceptance from deriving values through chains that
|
|
1589
|
-
// are later invalidated by rejection.
|
|
1590
|
-
for (const phase of ["rejected", "accepted"]) {
|
|
1591
|
-
let changed = true;
|
|
1592
|
-
while (changed) {
|
|
1593
|
-
changed = false;
|
|
1594
|
-
for (const [exprId, expr] of exprById) {
|
|
1595
|
-
if (expr.type !== "operator")
|
|
1596
|
-
continue;
|
|
1597
|
-
const state = opAssignments[exprId];
|
|
1598
|
-
if (state !== phase)
|
|
1599
|
-
continue;
|
|
1600
|
-
const op = expr.operator;
|
|
1601
|
-
const children = childrenOf.get(exprId) ?? [];
|
|
1602
|
-
if (state === "accepted") {
|
|
1603
|
-
switch (op) {
|
|
1604
|
-
case "not": {
|
|
1605
|
-
// ¬A accepted (= true) => child must be false
|
|
1606
|
-
if (children.length > 0) {
|
|
1607
|
-
if (trySetChild(children[0], false))
|
|
1608
|
-
changed = true;
|
|
1609
|
-
}
|
|
1610
|
-
break;
|
|
1611
|
-
}
|
|
1612
|
-
case "and": {
|
|
1613
|
-
// A ∧ B accepted => all children must be true
|
|
1614
|
-
for (const child of children) {
|
|
1615
|
-
if (trySetChild(child, true))
|
|
1616
|
-
changed = true;
|
|
1617
|
-
}
|
|
1618
|
-
break;
|
|
1619
|
-
}
|
|
1620
|
-
case "or": {
|
|
1621
|
-
// A ∨ B accepted: if all-but-one are false, remaining must be true
|
|
1622
|
-
const unknownChildren = [];
|
|
1623
|
-
let allOthersAreFalse = true;
|
|
1624
|
-
for (const child of children) {
|
|
1625
|
-
const childValue = resolveValue(child.id);
|
|
1626
|
-
if (childValue === null) {
|
|
1627
|
-
unknownChildren.push(child);
|
|
1628
|
-
}
|
|
1629
|
-
else if (childValue !== false) {
|
|
1630
|
-
allOthersAreFalse = false;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
if (unknownChildren.length === 1 &&
|
|
1634
|
-
allOthersAreFalse) {
|
|
1635
|
-
if (trySetChild(unknownChildren[0], true))
|
|
1636
|
-
changed = true;
|
|
1637
|
-
}
|
|
1638
|
-
break;
|
|
1639
|
-
}
|
|
1640
|
-
case "implies": {
|
|
1641
|
-
// A → B accepted: if A=true => B=true; if B=false => A=false
|
|
1642
|
-
if (children.length >= 2) {
|
|
1643
|
-
const leftValue = resolveValue(children[0].id);
|
|
1644
|
-
const rightValue = resolveValue(children[1].id);
|
|
1645
|
-
if (leftValue === true) {
|
|
1646
|
-
if (trySetChild(children[1], true))
|
|
1647
|
-
changed = true;
|
|
1648
|
-
}
|
|
1649
|
-
if (rightValue === false) {
|
|
1650
|
-
if (trySetChild(children[0], false))
|
|
1651
|
-
changed = true;
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
break;
|
|
1655
|
-
}
|
|
1656
|
-
case "iff": {
|
|
1657
|
-
// A ↔ B accepted: if A known => B matches; if B known => A matches
|
|
1658
|
-
if (children.length >= 2) {
|
|
1659
|
-
const leftValue = resolveValue(children[0].id);
|
|
1660
|
-
const rightValue = resolveValue(children[1].id);
|
|
1661
|
-
if (leftValue !== null) {
|
|
1662
|
-
if (trySetChild(children[1], leftValue))
|
|
1663
|
-
changed = true;
|
|
1664
|
-
}
|
|
1665
|
-
if (rightValue !== null) {
|
|
1666
|
-
if (trySetChild(children[0], rightValue))
|
|
1667
|
-
changed = true;
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
break;
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
else {
|
|
1675
|
-
// state === "rejected" — expression forced false
|
|
1676
|
-
switch (op) {
|
|
1677
|
-
case "not": {
|
|
1678
|
-
// ¬A rejected (= false) => child must be true
|
|
1679
|
-
if (children.length > 0) {
|
|
1680
|
-
if (trySetChild(children[0], true))
|
|
1681
|
-
changed = true;
|
|
1682
|
-
}
|
|
1683
|
-
break;
|
|
1684
|
-
}
|
|
1685
|
-
case "and": {
|
|
1686
|
-
// A ∧ B rejected (= false): if all-but-one are true, remaining must be false
|
|
1687
|
-
const unknownChildren = [];
|
|
1688
|
-
let allOthersAreTrue = true;
|
|
1689
|
-
for (const child of children) {
|
|
1690
|
-
const childValue = resolveValue(child.id);
|
|
1691
|
-
if (childValue === null) {
|
|
1692
|
-
unknownChildren.push(child);
|
|
1693
|
-
}
|
|
1694
|
-
else if (childValue !== true) {
|
|
1695
|
-
allOthersAreTrue = false;
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
if (unknownChildren.length === 1 &&
|
|
1699
|
-
allOthersAreTrue) {
|
|
1700
|
-
if (trySetChild(unknownChildren[0], false))
|
|
1701
|
-
changed = true;
|
|
1702
|
-
}
|
|
1703
|
-
break;
|
|
1704
|
-
}
|
|
1705
|
-
case "or": {
|
|
1706
|
-
// A ∨ B rejected (= false) => all children must be false
|
|
1707
|
-
for (const child of children) {
|
|
1708
|
-
if (trySetChild(child, false))
|
|
1709
|
-
changed = true;
|
|
1710
|
-
}
|
|
1711
|
-
break;
|
|
1712
|
-
}
|
|
1713
|
-
case "implies": {
|
|
1714
|
-
// A → B rejected (= false) => A must be true, B must be false
|
|
1715
|
-
if (children.length >= 2) {
|
|
1716
|
-
if (trySetChild(children[0], true))
|
|
1717
|
-
changed = true;
|
|
1718
|
-
if (trySetChild(children[1], false))
|
|
1719
|
-
changed = true;
|
|
1720
|
-
}
|
|
1721
|
-
break;
|
|
1722
|
-
}
|
|
1723
|
-
case "iff": {
|
|
1724
|
-
// A ↔ B rejected (= false): if A known => B is opposite; if B known => A is opposite
|
|
1725
|
-
if (children.length >= 2) {
|
|
1726
|
-
const leftValue = resolveValue(children[0].id);
|
|
1727
|
-
const rightValue = resolveValue(children[1].id);
|
|
1728
|
-
if (leftValue !== null) {
|
|
1729
|
-
if (trySetChild(children[1], !leftValue))
|
|
1730
|
-
changed = true;
|
|
1731
|
-
}
|
|
1732
|
-
if (rightValue !== null) {
|
|
1733
|
-
if (trySetChild(children[0], !rightValue))
|
|
1734
|
-
changed = true;
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
break;
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
return vars;
|
|
1190
|
+
return validateArgumentEvaluabilityStandalone(this.asValidationContext());
|
|
1745
1191
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1192
|
+
asValidationContext() {
|
|
1193
|
+
return {
|
|
1194
|
+
argumentId: this.argument.id,
|
|
1195
|
+
argumentVersion: this.argument.version,
|
|
1196
|
+
conclusionPremiseId: this.conclusionPremiseId,
|
|
1197
|
+
getArgument: () => this.getArgument(),
|
|
1198
|
+
getVariables: () => this.variables.toArray(),
|
|
1199
|
+
listPremises: () => this.listPremises(),
|
|
1200
|
+
hasPremise: (premiseId) => this.premises.has(premiseId),
|
|
1201
|
+
lookupClaim: (claimId, claimVersion) => this.claimLibrary.get(claimId, claimVersion),
|
|
1202
|
+
flushAndGetChecksumDeltas: () => {
|
|
1203
|
+
const savedMeta = this.cachedMetaChecksum;
|
|
1204
|
+
const savedDescendant = this.cachedDescendantChecksum;
|
|
1205
|
+
const savedCombined = this.cachedCombinedChecksum;
|
|
1206
|
+
this.flushChecksums();
|
|
1751
1207
|
return {
|
|
1752
|
-
|
|
1753
|
-
|
|
1208
|
+
savedMeta,
|
|
1209
|
+
savedDescendant,
|
|
1210
|
+
savedCombined,
|
|
1211
|
+
currentMeta: this.cachedMetaChecksum,
|
|
1212
|
+
currentDescendant: this.cachedDescendantChecksum,
|
|
1213
|
+
currentCombined: this.cachedCombinedChecksum,
|
|
1754
1214
|
};
|
|
1755
|
-
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
if (!conclusion) {
|
|
1759
|
-
return {
|
|
1760
|
-
ok: false,
|
|
1761
|
-
validation: makeValidationResult([
|
|
1762
|
-
makeErrorIssue({
|
|
1763
|
-
code: "ARGUMENT_NO_CONCLUSION",
|
|
1764
|
-
message: "Argument has no designated conclusion premise.",
|
|
1765
|
-
}),
|
|
1766
|
-
]),
|
|
1767
|
-
};
|
|
1768
|
-
}
|
|
1769
|
-
const supportingPremises = this.listSupportingPremises();
|
|
1770
|
-
const supportingIds = new Set(supportingPremises.map((pm) => pm.getId()));
|
|
1771
|
-
const constraintPremises = this.listPremises().filter((pm) => pm.getId() !== this.conclusionPremiseId &&
|
|
1772
|
-
!supportingIds.has(pm.getId()));
|
|
1773
|
-
const allRelevantPremises = [
|
|
1774
|
-
conclusion,
|
|
1775
|
-
...supportingPremises,
|
|
1776
|
-
...constraintPremises,
|
|
1777
|
-
];
|
|
1778
|
-
const allVariableIds = [
|
|
1779
|
-
...new Set(allRelevantPremises.flatMap((pm) => pm
|
|
1780
|
-
.getExpressions()
|
|
1781
|
-
.filter((expr) => expr.type === "variable")
|
|
1782
|
-
.map((expr) => expr.variableId))),
|
|
1783
|
-
].sort();
|
|
1784
|
-
// Claim-bound and externally-bound premise variables get truth-table columns;
|
|
1785
|
-
// internally-bound premise variables are resolved lazily.
|
|
1786
|
-
const referencedVariableIds = allVariableIds.filter((vid) => {
|
|
1787
|
-
const v = this.variables.getVariable(vid);
|
|
1788
|
-
if (v == null)
|
|
1789
|
-
return false;
|
|
1790
|
-
if (isClaimBound(v))
|
|
1791
|
-
return true;
|
|
1792
|
-
if (isPremiseBound(v) && v.boundArgumentId !== this.argument.id)
|
|
1793
|
-
return true;
|
|
1794
|
-
return false;
|
|
1795
|
-
});
|
|
1796
|
-
// Run operator constraint propagation
|
|
1797
|
-
const propagatedVars = this.propagateOperatorConstraints(assignment);
|
|
1798
|
-
const propagatedAssignment = {
|
|
1799
|
-
variables: propagatedVars,
|
|
1800
|
-
operatorAssignments: assignment.operatorAssignments,
|
|
1215
|
+
},
|
|
1216
|
+
validateVariables: () => this.variables.validate(),
|
|
1217
|
+
wouldCreateCycle: (variableId, premiseId, visited) => this.wouldCreateCycle(variableId, premiseId, visited),
|
|
1801
1218
|
};
|
|
1802
|
-
try {
|
|
1803
|
-
// Build a resolver that lazily evaluates premise-bound variables
|
|
1804
|
-
// by evaluating their bound premise's expression tree under the
|
|
1805
|
-
// same assignment. Results are cached per-variable per-evaluate call.
|
|
1806
|
-
const resolverCache = new Map();
|
|
1807
|
-
const resolver = (variableId) => {
|
|
1808
|
-
if (resolverCache.has(variableId)) {
|
|
1809
|
-
return resolverCache.get(variableId);
|
|
1810
|
-
}
|
|
1811
|
-
const variable = this.variables.getVariable(variableId);
|
|
1812
|
-
if (!variable ||
|
|
1813
|
-
!isPremiseBound(variable) ||
|
|
1814
|
-
variable.boundArgumentId !== this.argument.id) {
|
|
1815
|
-
// Claim-bound or externally-bound: read from assignment
|
|
1816
|
-
return propagatedAssignment.variables[variableId] ?? null;
|
|
1817
|
-
}
|
|
1818
|
-
// Internal premise-bound: lazy resolution
|
|
1819
|
-
const boundPremiseId = variable.boundPremiseId;
|
|
1820
|
-
const boundPremise = this.premises.get(boundPremiseId);
|
|
1821
|
-
if (!boundPremise) {
|
|
1822
|
-
resolverCache.set(variableId, null);
|
|
1823
|
-
return null;
|
|
1824
|
-
}
|
|
1825
|
-
const premiseResult = boundPremise.evaluate(propagatedAssignment, {
|
|
1826
|
-
resolver,
|
|
1827
|
-
});
|
|
1828
|
-
const value = premiseResult?.rootValue ?? null;
|
|
1829
|
-
resolverCache.set(variableId, value);
|
|
1830
|
-
return value;
|
|
1831
|
-
};
|
|
1832
|
-
const evalOpts = {
|
|
1833
|
-
strictUnknownKeys: options?.strictUnknownAssignmentKeys ?? false,
|
|
1834
|
-
resolver,
|
|
1835
|
-
};
|
|
1836
|
-
const conclusionEvaluation = conclusion.evaluate(propagatedAssignment, evalOpts);
|
|
1837
|
-
const supportingEvaluations = supportingPremises.map((pm) => pm.evaluate(propagatedAssignment, evalOpts));
|
|
1838
|
-
const constraintEvaluations = constraintPremises.map((pm) => pm.evaluate(propagatedAssignment, evalOpts));
|
|
1839
|
-
const isAdmissibleAssignment = constraintEvaluations.reduce((acc, result) => kleeneAnd(acc, result.rootValue ?? null), true);
|
|
1840
|
-
const allSupportingPremisesTrue = supportingEvaluations.reduce((acc, result) => kleeneAnd(acc, result.rootValue ?? null), true);
|
|
1841
|
-
const conclusionTrue = conclusionEvaluation.rootValue ?? null;
|
|
1842
|
-
const isCounterexample = kleeneAnd(isAdmissibleAssignment, kleeneAnd(allSupportingPremisesTrue, kleeneNot(conclusionTrue)));
|
|
1843
|
-
const includeExpressionValues = options?.includeExpressionValues ?? true;
|
|
1844
|
-
const includeDiagnostics = options?.includeDiagnostics ?? true;
|
|
1845
|
-
const strip = (result) => ({
|
|
1846
|
-
...result,
|
|
1847
|
-
expressionValues: includeExpressionValues
|
|
1848
|
-
? result.expressionValues
|
|
1849
|
-
: {},
|
|
1850
|
-
inferenceDiagnostic: includeDiagnostics
|
|
1851
|
-
? result.inferenceDiagnostic
|
|
1852
|
-
: undefined,
|
|
1853
|
-
});
|
|
1854
|
-
return {
|
|
1855
|
-
ok: true,
|
|
1856
|
-
assignment: {
|
|
1857
|
-
variables: { ...propagatedAssignment.variables },
|
|
1858
|
-
operatorAssignments: {
|
|
1859
|
-
...propagatedAssignment.operatorAssignments,
|
|
1860
|
-
},
|
|
1861
|
-
},
|
|
1862
|
-
referencedVariableIds,
|
|
1863
|
-
conclusion: strip(conclusionEvaluation),
|
|
1864
|
-
supportingPremises: supportingEvaluations.map(strip),
|
|
1865
|
-
constraintPremises: constraintEvaluations.map(strip),
|
|
1866
|
-
isAdmissibleAssignment,
|
|
1867
|
-
allSupportingPremisesTrue,
|
|
1868
|
-
conclusionTrue,
|
|
1869
|
-
isCounterexample,
|
|
1870
|
-
preservesTruthUnderAssignment: kleeneNot(isCounterexample),
|
|
1871
|
-
};
|
|
1872
|
-
}
|
|
1873
|
-
catch (error) {
|
|
1874
|
-
return {
|
|
1875
|
-
ok: false,
|
|
1876
|
-
validation: makeValidationResult([
|
|
1877
|
-
makeErrorIssue({
|
|
1878
|
-
code: "ASSIGNMENT_MISSING_VARIABLE",
|
|
1879
|
-
message: error instanceof Error
|
|
1880
|
-
? error.message
|
|
1881
|
-
: "Argument evaluation failed.",
|
|
1882
|
-
}),
|
|
1883
|
-
]),
|
|
1884
|
-
};
|
|
1885
|
-
}
|
|
1886
1219
|
}
|
|
1887
|
-
|
|
1888
|
-
const validateFirst = options?.validateFirst ?? true;
|
|
1889
|
-
if (validateFirst) {
|
|
1890
|
-
const validation = this.validateEvaluability();
|
|
1891
|
-
if (!validation.ok) {
|
|
1892
|
-
return {
|
|
1893
|
-
ok: false,
|
|
1894
|
-
validation,
|
|
1895
|
-
};
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
const conclusion = this.getConclusionPremise();
|
|
1899
|
-
if (!conclusion) {
|
|
1900
|
-
return {
|
|
1901
|
-
ok: false,
|
|
1902
|
-
validation: makeValidationResult([
|
|
1903
|
-
makeErrorIssue({
|
|
1904
|
-
code: "ARGUMENT_NO_CONCLUSION",
|
|
1905
|
-
message: "Argument has no designated conclusion premise.",
|
|
1906
|
-
}),
|
|
1907
|
-
]),
|
|
1908
|
-
};
|
|
1909
|
-
}
|
|
1910
|
-
const supportingPremises = this.listSupportingPremises();
|
|
1911
|
-
const supportingIds = new Set(supportingPremises.map((pm) => pm.getId()));
|
|
1912
|
-
const constraintPremises = this.listPremises().filter((pm) => pm.getId() !== this.conclusionPremiseId &&
|
|
1913
|
-
!supportingIds.has(pm.getId()));
|
|
1914
|
-
const allVariableIdsForCheck = [
|
|
1915
|
-
...new Set([
|
|
1916
|
-
conclusion,
|
|
1917
|
-
...supportingPremises,
|
|
1918
|
-
...constraintPremises,
|
|
1919
|
-
].flatMap((pm) => pm
|
|
1920
|
-
.getExpressions()
|
|
1921
|
-
.filter((expr) => expr.type === "variable")
|
|
1922
|
-
.map((expr) => expr.variableId))),
|
|
1923
|
-
].sort();
|
|
1924
|
-
// Claim-bound and externally-bound premise variables get truth-table columns;
|
|
1925
|
-
// internally-bound premise variables are resolved lazily.
|
|
1926
|
-
const checkedVariableIds = allVariableIdsForCheck.filter((vid) => {
|
|
1927
|
-
const v = this.variables.getVariable(vid);
|
|
1928
|
-
if (v == null)
|
|
1929
|
-
return false;
|
|
1930
|
-
if (isClaimBound(v))
|
|
1931
|
-
return true;
|
|
1932
|
-
if (isPremiseBound(v) && v.boundArgumentId !== this.argument.id)
|
|
1933
|
-
return true;
|
|
1934
|
-
return false;
|
|
1935
|
-
});
|
|
1936
|
-
if (options?.maxVariables !== undefined &&
|
|
1937
|
-
checkedVariableIds.length > options.maxVariables) {
|
|
1938
|
-
return {
|
|
1939
|
-
ok: false,
|
|
1940
|
-
validation: makeValidationResult([
|
|
1941
|
-
makeErrorIssue({
|
|
1942
|
-
code: "ASSIGNMENT_UNKNOWN_VARIABLE",
|
|
1943
|
-
message: `Validity check requires ${checkedVariableIds.length} variables, exceeding limit ${options.maxVariables}.`,
|
|
1944
|
-
}),
|
|
1945
|
-
]),
|
|
1946
|
-
};
|
|
1947
|
-
}
|
|
1948
|
-
const mode = options?.mode ?? "firstCounterexample";
|
|
1949
|
-
const maxAssignmentsChecked = options?.maxAssignmentsChecked;
|
|
1950
|
-
const counterexamples = [];
|
|
1951
|
-
let numAssignmentsChecked = 0;
|
|
1952
|
-
let numAdmissibleAssignments = 0;
|
|
1953
|
-
let truncated = false;
|
|
1954
|
-
const totalAssignments = 2 ** checkedVariableIds.length;
|
|
1955
|
-
for (let mask = 0; mask < totalAssignments; mask++) {
|
|
1956
|
-
if (maxAssignmentsChecked !== undefined &&
|
|
1957
|
-
numAssignmentsChecked >= maxAssignmentsChecked) {
|
|
1958
|
-
truncated = true;
|
|
1959
|
-
break;
|
|
1960
|
-
}
|
|
1961
|
-
const assignment = {
|
|
1962
|
-
variables: {},
|
|
1963
|
-
operatorAssignments: {},
|
|
1964
|
-
};
|
|
1965
|
-
for (let i = 0; i < checkedVariableIds.length; i++) {
|
|
1966
|
-
assignment.variables[checkedVariableIds[i]] = Boolean(mask & (1 << i));
|
|
1967
|
-
}
|
|
1968
|
-
const result = this.evaluate(assignment, {
|
|
1969
|
-
validateFirst: false,
|
|
1970
|
-
includeExpressionValues: options?.includeCounterexampleEvaluations ?? false,
|
|
1971
|
-
includeDiagnostics: options?.includeCounterexampleEvaluations ?? false,
|
|
1972
|
-
});
|
|
1973
|
-
if (!result.ok) {
|
|
1974
|
-
return {
|
|
1975
|
-
ok: false,
|
|
1976
|
-
validation: result.validation,
|
|
1977
|
-
};
|
|
1978
|
-
}
|
|
1979
|
-
numAssignmentsChecked += 1;
|
|
1980
|
-
if (result.isAdmissibleAssignment === true) {
|
|
1981
|
-
numAdmissibleAssignments += 1;
|
|
1982
|
-
}
|
|
1983
|
-
if (result.isCounterexample === true) {
|
|
1984
|
-
counterexamples.push({
|
|
1985
|
-
assignment: result.assignment,
|
|
1986
|
-
result,
|
|
1987
|
-
});
|
|
1988
|
-
if (mode === "firstCounterexample") {
|
|
1989
|
-
break;
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
const foundCounterexample = counterexamples.length > 0;
|
|
1994
|
-
const fullyChecked = !truncated &&
|
|
1995
|
-
(mode === "exhaustive" ||
|
|
1996
|
-
(mode === "firstCounterexample" && !foundCounterexample));
|
|
1220
|
+
asEvaluationContext() {
|
|
1997
1221
|
return {
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
numAdmissibleAssignments,
|
|
2007
|
-
counterexamples,
|
|
2008
|
-
truncated,
|
|
1222
|
+
argumentId: this.argument.id,
|
|
1223
|
+
conclusionPremiseId: this.conclusionPremiseId,
|
|
1224
|
+
getConclusionPremise: () => this.getConclusionPremise(),
|
|
1225
|
+
listSupportingPremises: () => this.listSupportingPremises(),
|
|
1226
|
+
listPremises: () => this.listPremises(),
|
|
1227
|
+
getVariable: (id) => this.variables.getVariable(id),
|
|
1228
|
+
getPremise: (id) => this.premises.get(id),
|
|
1229
|
+
validateEvaluability: () => this.validateEvaluability(),
|
|
2009
1230
|
};
|
|
2010
1231
|
}
|
|
1232
|
+
evaluate(assignment, options) {
|
|
1233
|
+
return evaluateArgumentStandalone(this.asEvaluationContext(), assignment, options);
|
|
1234
|
+
}
|
|
1235
|
+
checkValidity(options) {
|
|
1236
|
+
return checkArgumentValidityStandalone(this.asEvaluationContext(), options);
|
|
1237
|
+
}
|
|
2011
1238
|
// -----------------------------------------------------------------
|
|
2012
1239
|
// Forking
|
|
2013
1240
|
// -----------------------------------------------------------------
|