eyeling 1.25.4 → 1.25.5
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/browser/eyeling.browser.js +174 -7
- package/eyeling.js +174 -7
- package/lib/engine.js +174 -7
- package/package.json +1 -1
- package/test/api.test.js +20 -0
- package/examples/library-and-path.n3 +0 -499
- package/examples/output/library-and-path.n3 +0 -33
|
@@ -5973,6 +5973,158 @@ function __varOccursElsewhereInPremise(premise, name, idx, field) {
|
|
|
5973
5973
|
return false;
|
|
5974
5974
|
}
|
|
5975
5975
|
|
|
5976
|
+
|
|
5977
|
+
function __scopedPriorityForTerm(t) {
|
|
5978
|
+
if (t instanceof GraphTerm) return 0;
|
|
5979
|
+
const p0 = __logNaturalPriorityFromTerm(t);
|
|
5980
|
+
return p0 !== null && p0 >= 1 ? p0 : 1;
|
|
5981
|
+
}
|
|
5982
|
+
|
|
5983
|
+
function __pushScopedQueryTriplesFromGraph(term, out) {
|
|
5984
|
+
if (!(term instanceof GraphTerm)) return;
|
|
5985
|
+
for (const tr of term.triples) out.push(tr);
|
|
5986
|
+
}
|
|
5987
|
+
|
|
5988
|
+
function __analyzeForwardRuleScopedUse(rule) {
|
|
5989
|
+
const out = {
|
|
5990
|
+
needsSnap: false,
|
|
5991
|
+
baseLevel: 0,
|
|
5992
|
+
queryTriples: [],
|
|
5993
|
+
hasScopedAggregate: false,
|
|
5994
|
+
};
|
|
5995
|
+
|
|
5996
|
+
if (!rule || !Array.isArray(rule.premise)) return out;
|
|
5997
|
+
|
|
5998
|
+
for (let i = 0; i < rule.premise.length; i++) {
|
|
5999
|
+
const tr = rule.premise[i];
|
|
6000
|
+
if (!(tr && tr.p instanceof Iri)) continue;
|
|
6001
|
+
const pv = tr.p.value;
|
|
6002
|
+
|
|
6003
|
+
if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
|
|
6004
|
+
// Explicit quoted scopes are local formulas, not snapshots of the global closure.
|
|
6005
|
+
if (tr.s instanceof GraphTerm) continue;
|
|
6006
|
+
|
|
6007
|
+
// A scope variable that is bound by another premise may become an explicit GraphTerm.
|
|
6008
|
+
// Still, if it remains unbound at runtime the builtin treats it as priority 1.
|
|
6009
|
+
// We therefore record the scoped use, but only use quoted object triples for
|
|
6010
|
+
// dependency analysis; variables inside the quoted object do not bind the scope.
|
|
6011
|
+
out.needsSnap = true;
|
|
6012
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.s));
|
|
6013
|
+
__pushScopedQueryTriplesFromGraph(tr.o, out.queryTriples);
|
|
6014
|
+
continue;
|
|
6015
|
+
}
|
|
6016
|
+
|
|
6017
|
+
if (pv === LOG_NS + 'collectAllIn') {
|
|
6018
|
+
if (tr.o instanceof GraphTerm) continue;
|
|
6019
|
+
|
|
6020
|
+
out.needsSnap = true;
|
|
6021
|
+
out.hasScopedAggregate = true;
|
|
6022
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.o));
|
|
6023
|
+
if (tr.s instanceof ListTerm && tr.s.elems.length === 3) {
|
|
6024
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[1], out.queryTriples);
|
|
6025
|
+
}
|
|
6026
|
+
continue;
|
|
6027
|
+
}
|
|
6028
|
+
|
|
6029
|
+
if (pv === LOG_NS + 'forAllIn') {
|
|
6030
|
+
if (tr.o instanceof GraphTerm) continue;
|
|
6031
|
+
|
|
6032
|
+
out.needsSnap = true;
|
|
6033
|
+
out.hasScopedAggregate = true;
|
|
6034
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.o));
|
|
6035
|
+
if (tr.s instanceof ListTerm && tr.s.elems.length === 2) {
|
|
6036
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[0], out.queryTriples);
|
|
6037
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[1], out.queryTriples);
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
|
|
6042
|
+
return out;
|
|
6043
|
+
}
|
|
6044
|
+
|
|
6045
|
+
function __triplePatternsMayOverlap(a, b) {
|
|
6046
|
+
return unifyTriple(a, b, __emptySubst()) !== null || unifyTriple(b, a, __emptySubst()) !== null;
|
|
6047
|
+
}
|
|
6048
|
+
|
|
6049
|
+
function __ruleConclusionsMayFeedScopedQueries(producer, consumerMeta) {
|
|
6050
|
+
if (!consumerMeta || !consumerMeta.queryTriples || consumerMeta.queryTriples.length === 0) return false;
|
|
6051
|
+
|
|
6052
|
+
// Dynamic conclusions are only known after a proof solution. Conservatively
|
|
6053
|
+
// assume they can feed any scoped query if the producing rule is scoped.
|
|
6054
|
+
if (producer && producer.__dynamicConclusionTerm) return true;
|
|
6055
|
+
|
|
6056
|
+
if (!producer || !Array.isArray(producer.conclusion) || producer.conclusion.length === 0) return false;
|
|
6057
|
+
for (const q of consumerMeta.queryTriples) {
|
|
6058
|
+
for (const h of producer.conclusion) {
|
|
6059
|
+
if (__triplePatternsMayOverlap(q, h)) return true;
|
|
6060
|
+
}
|
|
6061
|
+
}
|
|
6062
|
+
return false;
|
|
6063
|
+
}
|
|
6064
|
+
|
|
6065
|
+
function __setForwardRuleScopedStratumInfo(rule, level) {
|
|
6066
|
+
const value =
|
|
6067
|
+
level > 0
|
|
6068
|
+
? { needsSnap: true, requiredLevel: level, exactLevel: true }
|
|
6069
|
+
: { needsSnap: false, requiredLevel: 0, exactLevel: false };
|
|
6070
|
+
|
|
6071
|
+
if (!hasOwn.call(rule, '__scopedStratumInfo')) {
|
|
6072
|
+
Object.defineProperty(rule, '__scopedStratumInfo', {
|
|
6073
|
+
value,
|
|
6074
|
+
enumerable: false,
|
|
6075
|
+
writable: true,
|
|
6076
|
+
configurable: true,
|
|
6077
|
+
});
|
|
6078
|
+
} else {
|
|
6079
|
+
rule.__scopedStratumInfo = value;
|
|
6080
|
+
}
|
|
6081
|
+
}
|
|
6082
|
+
|
|
6083
|
+
function __computeForwardRuleScopedStrata(forwardRules) {
|
|
6084
|
+
if (!Array.isArray(forwardRules) || forwardRules.length === 0) return 0;
|
|
6085
|
+
|
|
6086
|
+
const metas = forwardRules.map((r) => __analyzeForwardRuleScopedUse(r));
|
|
6087
|
+
const levels = metas.map((m) => (m.needsSnap ? Math.max(1, m.baseLevel || 1) : 0));
|
|
6088
|
+
|
|
6089
|
+
let maxLevel = 0;
|
|
6090
|
+
for (const lvl of levels) if (lvl > maxLevel) maxLevel = lvl;
|
|
6091
|
+
|
|
6092
|
+
// Stratify scoped rules by data dependency: if a scoped query can read facts
|
|
6093
|
+
// produced by another scoped rule, the reader must run against a later frozen
|
|
6094
|
+
// snapshot. This prevents non-monotonic scoped builtins such as collectAllIn
|
|
6095
|
+
// from emitting an early result before lower strata have derived their facts.
|
|
6096
|
+
const passLimit = Math.max(1, forwardRules.length) + maxLevel + 1;
|
|
6097
|
+
for (let pass = 0; pass < passLimit; pass++) {
|
|
6098
|
+
let changed = false;
|
|
6099
|
+
for (let ci = 0; ci < forwardRules.length; ci++) {
|
|
6100
|
+
if (!metas[ci].needsSnap || !metas[ci].hasScopedAggregate) continue;
|
|
6101
|
+
let needed = levels[ci];
|
|
6102
|
+
for (let pi = 0; pi < forwardRules.length; pi++) {
|
|
6103
|
+
if (pi === ci) continue;
|
|
6104
|
+
if (levels[pi] <= 0) continue;
|
|
6105
|
+
if (metas[pi].hasScopedAggregate) continue;
|
|
6106
|
+
if (!__ruleConclusionsMayFeedScopedQueries(forwardRules[pi], metas[ci])) continue;
|
|
6107
|
+
needed = Math.max(needed, levels[pi] + 1);
|
|
6108
|
+
}
|
|
6109
|
+
if (needed !== levels[ci]) {
|
|
6110
|
+
levels[ci] = needed;
|
|
6111
|
+
if (needed > maxLevel) maxLevel = needed;
|
|
6112
|
+
changed = true;
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
if (!changed) break;
|
|
6116
|
+
}
|
|
6117
|
+
|
|
6118
|
+
|
|
6119
|
+
maxLevel = 0;
|
|
6120
|
+
for (let i = 0; i < forwardRules.length; i++) {
|
|
6121
|
+
__setForwardRuleScopedStratumInfo(forwardRules[i], levels[i]);
|
|
6122
|
+
if (levels[i] > maxLevel) maxLevel = levels[i];
|
|
6123
|
+
}
|
|
6124
|
+
|
|
6125
|
+
return maxLevel;
|
|
6126
|
+
}
|
|
6127
|
+
|
|
5976
6128
|
function __computeForwardRuleScopedSkipInfo(rule) {
|
|
5977
6129
|
let needsSnap = false;
|
|
5978
6130
|
let requiredLevel = 0;
|
|
@@ -7158,7 +7310,7 @@ function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
|
|
|
7158
7310
|
goalPredTid: goal.p instanceof Iri ? goal.p.__tid : null,
|
|
7159
7311
|
goalSKey,
|
|
7160
7312
|
goalOKey,
|
|
7161
|
-
needsSkipCheck: !!r.__needsForwardSkipCheck,
|
|
7313
|
+
needsSkipCheck: !!(r.__needsForwardSkipCheck || (r.__scopedStratumInfo && r.__scopedStratumInfo.needsSnap)),
|
|
7162
7314
|
fastSubjectVar,
|
|
7163
7315
|
fastObjectVar,
|
|
7164
7316
|
};
|
|
@@ -8606,7 +8758,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8606
8758
|
let scopedClosureLevel = 0;
|
|
8607
8759
|
|
|
8608
8760
|
// Scan known rules for the maximum requested closure priority in scoped log:* goals.
|
|
8609
|
-
let maxScopedClosurePriorityNeeded =
|
|
8761
|
+
let maxScopedClosurePriorityNeeded = Math.max(
|
|
8762
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
8763
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
8764
|
+
);
|
|
8610
8765
|
|
|
8611
8766
|
// Conservative fast-skip for forward rules that cannot possibly succeed
|
|
8612
8767
|
// until a scoped snapshot exists (or a given closure level is reached).
|
|
@@ -8660,12 +8815,16 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8660
8815
|
// until a snapshot exists (and a certain closure level is reached).
|
|
8661
8816
|
// This prevents expensive proofs that will definitely fail in Phase A
|
|
8662
8817
|
// and in early closure levels.
|
|
8663
|
-
const info = r.__scopedSkipInfo;
|
|
8818
|
+
const info = r.__scopedStratumInfo || r.__scopedSkipInfo;
|
|
8664
8819
|
if (info && info.needsSnap) {
|
|
8665
8820
|
const snapHere = facts.__scopedSnapshot || null;
|
|
8666
8821
|
const lvlHere = (facts && typeof facts.__scopedClosureLevel === 'number' && facts.__scopedClosureLevel) || 0;
|
|
8667
8822
|
if (!snapHere) return true;
|
|
8668
|
-
if (
|
|
8823
|
+
if (info.exactLevel) {
|
|
8824
|
+
if (lvlHere !== info.requiredLevel) return true;
|
|
8825
|
+
} else if (lvlHere < info.requiredLevel) {
|
|
8826
|
+
return true;
|
|
8827
|
+
}
|
|
8669
8828
|
}
|
|
8670
8829
|
|
|
8671
8830
|
// Optimization: if the rule head is **structurally ground** (no vars anywhere, even inside
|
|
@@ -8865,6 +9024,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8865
9024
|
|
|
8866
9025
|
const outcome = __emitForwardRuleSolution(r, entry.ruleIndex, s);
|
|
8867
9026
|
if (outcome.rulesChanged) {
|
|
9027
|
+
maxScopedClosurePriorityNeeded = Math.max(
|
|
9028
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9029
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
9030
|
+
);
|
|
8868
9031
|
agendaIndex = makeSinglePremiseAgendaIndex(forwardRules, backRules);
|
|
8869
9032
|
agendaCursor = 0;
|
|
8870
9033
|
}
|
|
@@ -8878,7 +9041,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8878
9041
|
for (let i = 0; i < forwardRules.length; i++) {
|
|
8879
9042
|
const r = forwardRules[i];
|
|
8880
9043
|
if (agendaIndex.indexed.has(r)) continue;
|
|
8881
|
-
if (r.__needsForwardSkipCheck && __skipForwardRuleNow(r)) continue;
|
|
9044
|
+
if ((r.__needsForwardSkipCheck || (r.__scopedStratumInfo && r.__scopedStratumInfo.needsSnap)) && __skipForwardRuleNow(r)) continue;
|
|
8882
9045
|
|
|
8883
9046
|
const headIsStrictGround = r.__headIsStrictGround;
|
|
8884
9047
|
const maxSols = r.isFuse || headIsStrictGround ? 1 : undefined;
|
|
@@ -8899,6 +9062,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8899
9062
|
for (const s of sols) {
|
|
8900
9063
|
const outcome = __emitForwardRuleSolution(r, i, s);
|
|
8901
9064
|
if (outcome.rulesChanged) {
|
|
9065
|
+
maxScopedClosurePriorityNeeded = Math.max(
|
|
9066
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9067
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
9068
|
+
);
|
|
8902
9069
|
agendaIndex = makeSinglePremiseAgendaIndex(forwardRules, backRules);
|
|
8903
9070
|
agendaCursor = 0;
|
|
8904
9071
|
}
|
|
@@ -8926,8 +9093,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8926
9093
|
// Rules may have been added dynamically (rule-producing triples), possibly
|
|
8927
9094
|
// introducing scoped builtins and/or higher closure priorities.
|
|
8928
9095
|
maxScopedClosurePriorityNeeded = Math.max(
|
|
8929
|
-
maxScopedClosurePriorityNeeded,
|
|
8930
9096
|
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9097
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
8931
9098
|
);
|
|
8932
9099
|
|
|
8933
9100
|
// If there are no scoped builtins in the entire program, Phase B is pure
|
|
@@ -8945,8 +9112,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8945
9112
|
|
|
8946
9113
|
// Phase B can also derive rule-producing triples.
|
|
8947
9114
|
maxScopedClosurePriorityNeeded = Math.max(
|
|
8948
|
-
maxScopedClosurePriorityNeeded,
|
|
8949
9115
|
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9116
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
8950
9117
|
);
|
|
8951
9118
|
|
|
8952
9119
|
if (!changedA && !changedB && scopedClosureLevel >= maxScopedClosurePriorityNeeded) break;
|
package/eyeling.js
CHANGED
|
@@ -5973,6 +5973,158 @@ function __varOccursElsewhereInPremise(premise, name, idx, field) {
|
|
|
5973
5973
|
return false;
|
|
5974
5974
|
}
|
|
5975
5975
|
|
|
5976
|
+
|
|
5977
|
+
function __scopedPriorityForTerm(t) {
|
|
5978
|
+
if (t instanceof GraphTerm) return 0;
|
|
5979
|
+
const p0 = __logNaturalPriorityFromTerm(t);
|
|
5980
|
+
return p0 !== null && p0 >= 1 ? p0 : 1;
|
|
5981
|
+
}
|
|
5982
|
+
|
|
5983
|
+
function __pushScopedQueryTriplesFromGraph(term, out) {
|
|
5984
|
+
if (!(term instanceof GraphTerm)) return;
|
|
5985
|
+
for (const tr of term.triples) out.push(tr);
|
|
5986
|
+
}
|
|
5987
|
+
|
|
5988
|
+
function __analyzeForwardRuleScopedUse(rule) {
|
|
5989
|
+
const out = {
|
|
5990
|
+
needsSnap: false,
|
|
5991
|
+
baseLevel: 0,
|
|
5992
|
+
queryTriples: [],
|
|
5993
|
+
hasScopedAggregate: false,
|
|
5994
|
+
};
|
|
5995
|
+
|
|
5996
|
+
if (!rule || !Array.isArray(rule.premise)) return out;
|
|
5997
|
+
|
|
5998
|
+
for (let i = 0; i < rule.premise.length; i++) {
|
|
5999
|
+
const tr = rule.premise[i];
|
|
6000
|
+
if (!(tr && tr.p instanceof Iri)) continue;
|
|
6001
|
+
const pv = tr.p.value;
|
|
6002
|
+
|
|
6003
|
+
if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
|
|
6004
|
+
// Explicit quoted scopes are local formulas, not snapshots of the global closure.
|
|
6005
|
+
if (tr.s instanceof GraphTerm) continue;
|
|
6006
|
+
|
|
6007
|
+
// A scope variable that is bound by another premise may become an explicit GraphTerm.
|
|
6008
|
+
// Still, if it remains unbound at runtime the builtin treats it as priority 1.
|
|
6009
|
+
// We therefore record the scoped use, but only use quoted object triples for
|
|
6010
|
+
// dependency analysis; variables inside the quoted object do not bind the scope.
|
|
6011
|
+
out.needsSnap = true;
|
|
6012
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.s));
|
|
6013
|
+
__pushScopedQueryTriplesFromGraph(tr.o, out.queryTriples);
|
|
6014
|
+
continue;
|
|
6015
|
+
}
|
|
6016
|
+
|
|
6017
|
+
if (pv === LOG_NS + 'collectAllIn') {
|
|
6018
|
+
if (tr.o instanceof GraphTerm) continue;
|
|
6019
|
+
|
|
6020
|
+
out.needsSnap = true;
|
|
6021
|
+
out.hasScopedAggregate = true;
|
|
6022
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.o));
|
|
6023
|
+
if (tr.s instanceof ListTerm && tr.s.elems.length === 3) {
|
|
6024
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[1], out.queryTriples);
|
|
6025
|
+
}
|
|
6026
|
+
continue;
|
|
6027
|
+
}
|
|
6028
|
+
|
|
6029
|
+
if (pv === LOG_NS + 'forAllIn') {
|
|
6030
|
+
if (tr.o instanceof GraphTerm) continue;
|
|
6031
|
+
|
|
6032
|
+
out.needsSnap = true;
|
|
6033
|
+
out.hasScopedAggregate = true;
|
|
6034
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.o));
|
|
6035
|
+
if (tr.s instanceof ListTerm && tr.s.elems.length === 2) {
|
|
6036
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[0], out.queryTriples);
|
|
6037
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[1], out.queryTriples);
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
|
|
6042
|
+
return out;
|
|
6043
|
+
}
|
|
6044
|
+
|
|
6045
|
+
function __triplePatternsMayOverlap(a, b) {
|
|
6046
|
+
return unifyTriple(a, b, __emptySubst()) !== null || unifyTriple(b, a, __emptySubst()) !== null;
|
|
6047
|
+
}
|
|
6048
|
+
|
|
6049
|
+
function __ruleConclusionsMayFeedScopedQueries(producer, consumerMeta) {
|
|
6050
|
+
if (!consumerMeta || !consumerMeta.queryTriples || consumerMeta.queryTriples.length === 0) return false;
|
|
6051
|
+
|
|
6052
|
+
// Dynamic conclusions are only known after a proof solution. Conservatively
|
|
6053
|
+
// assume they can feed any scoped query if the producing rule is scoped.
|
|
6054
|
+
if (producer && producer.__dynamicConclusionTerm) return true;
|
|
6055
|
+
|
|
6056
|
+
if (!producer || !Array.isArray(producer.conclusion) || producer.conclusion.length === 0) return false;
|
|
6057
|
+
for (const q of consumerMeta.queryTriples) {
|
|
6058
|
+
for (const h of producer.conclusion) {
|
|
6059
|
+
if (__triplePatternsMayOverlap(q, h)) return true;
|
|
6060
|
+
}
|
|
6061
|
+
}
|
|
6062
|
+
return false;
|
|
6063
|
+
}
|
|
6064
|
+
|
|
6065
|
+
function __setForwardRuleScopedStratumInfo(rule, level) {
|
|
6066
|
+
const value =
|
|
6067
|
+
level > 0
|
|
6068
|
+
? { needsSnap: true, requiredLevel: level, exactLevel: true }
|
|
6069
|
+
: { needsSnap: false, requiredLevel: 0, exactLevel: false };
|
|
6070
|
+
|
|
6071
|
+
if (!hasOwn.call(rule, '__scopedStratumInfo')) {
|
|
6072
|
+
Object.defineProperty(rule, '__scopedStratumInfo', {
|
|
6073
|
+
value,
|
|
6074
|
+
enumerable: false,
|
|
6075
|
+
writable: true,
|
|
6076
|
+
configurable: true,
|
|
6077
|
+
});
|
|
6078
|
+
} else {
|
|
6079
|
+
rule.__scopedStratumInfo = value;
|
|
6080
|
+
}
|
|
6081
|
+
}
|
|
6082
|
+
|
|
6083
|
+
function __computeForwardRuleScopedStrata(forwardRules) {
|
|
6084
|
+
if (!Array.isArray(forwardRules) || forwardRules.length === 0) return 0;
|
|
6085
|
+
|
|
6086
|
+
const metas = forwardRules.map((r) => __analyzeForwardRuleScopedUse(r));
|
|
6087
|
+
const levels = metas.map((m) => (m.needsSnap ? Math.max(1, m.baseLevel || 1) : 0));
|
|
6088
|
+
|
|
6089
|
+
let maxLevel = 0;
|
|
6090
|
+
for (const lvl of levels) if (lvl > maxLevel) maxLevel = lvl;
|
|
6091
|
+
|
|
6092
|
+
// Stratify scoped rules by data dependency: if a scoped query can read facts
|
|
6093
|
+
// produced by another scoped rule, the reader must run against a later frozen
|
|
6094
|
+
// snapshot. This prevents non-monotonic scoped builtins such as collectAllIn
|
|
6095
|
+
// from emitting an early result before lower strata have derived their facts.
|
|
6096
|
+
const passLimit = Math.max(1, forwardRules.length) + maxLevel + 1;
|
|
6097
|
+
for (let pass = 0; pass < passLimit; pass++) {
|
|
6098
|
+
let changed = false;
|
|
6099
|
+
for (let ci = 0; ci < forwardRules.length; ci++) {
|
|
6100
|
+
if (!metas[ci].needsSnap || !metas[ci].hasScopedAggregate) continue;
|
|
6101
|
+
let needed = levels[ci];
|
|
6102
|
+
for (let pi = 0; pi < forwardRules.length; pi++) {
|
|
6103
|
+
if (pi === ci) continue;
|
|
6104
|
+
if (levels[pi] <= 0) continue;
|
|
6105
|
+
if (metas[pi].hasScopedAggregate) continue;
|
|
6106
|
+
if (!__ruleConclusionsMayFeedScopedQueries(forwardRules[pi], metas[ci])) continue;
|
|
6107
|
+
needed = Math.max(needed, levels[pi] + 1);
|
|
6108
|
+
}
|
|
6109
|
+
if (needed !== levels[ci]) {
|
|
6110
|
+
levels[ci] = needed;
|
|
6111
|
+
if (needed > maxLevel) maxLevel = needed;
|
|
6112
|
+
changed = true;
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
if (!changed) break;
|
|
6116
|
+
}
|
|
6117
|
+
|
|
6118
|
+
|
|
6119
|
+
maxLevel = 0;
|
|
6120
|
+
for (let i = 0; i < forwardRules.length; i++) {
|
|
6121
|
+
__setForwardRuleScopedStratumInfo(forwardRules[i], levels[i]);
|
|
6122
|
+
if (levels[i] > maxLevel) maxLevel = levels[i];
|
|
6123
|
+
}
|
|
6124
|
+
|
|
6125
|
+
return maxLevel;
|
|
6126
|
+
}
|
|
6127
|
+
|
|
5976
6128
|
function __computeForwardRuleScopedSkipInfo(rule) {
|
|
5977
6129
|
let needsSnap = false;
|
|
5978
6130
|
let requiredLevel = 0;
|
|
@@ -7158,7 +7310,7 @@ function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
|
|
|
7158
7310
|
goalPredTid: goal.p instanceof Iri ? goal.p.__tid : null,
|
|
7159
7311
|
goalSKey,
|
|
7160
7312
|
goalOKey,
|
|
7161
|
-
needsSkipCheck: !!r.__needsForwardSkipCheck,
|
|
7313
|
+
needsSkipCheck: !!(r.__needsForwardSkipCheck || (r.__scopedStratumInfo && r.__scopedStratumInfo.needsSnap)),
|
|
7162
7314
|
fastSubjectVar,
|
|
7163
7315
|
fastObjectVar,
|
|
7164
7316
|
};
|
|
@@ -8606,7 +8758,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8606
8758
|
let scopedClosureLevel = 0;
|
|
8607
8759
|
|
|
8608
8760
|
// Scan known rules for the maximum requested closure priority in scoped log:* goals.
|
|
8609
|
-
let maxScopedClosurePriorityNeeded =
|
|
8761
|
+
let maxScopedClosurePriorityNeeded = Math.max(
|
|
8762
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
8763
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
8764
|
+
);
|
|
8610
8765
|
|
|
8611
8766
|
// Conservative fast-skip for forward rules that cannot possibly succeed
|
|
8612
8767
|
// until a scoped snapshot exists (or a given closure level is reached).
|
|
@@ -8660,12 +8815,16 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8660
8815
|
// until a snapshot exists (and a certain closure level is reached).
|
|
8661
8816
|
// This prevents expensive proofs that will definitely fail in Phase A
|
|
8662
8817
|
// and in early closure levels.
|
|
8663
|
-
const info = r.__scopedSkipInfo;
|
|
8818
|
+
const info = r.__scopedStratumInfo || r.__scopedSkipInfo;
|
|
8664
8819
|
if (info && info.needsSnap) {
|
|
8665
8820
|
const snapHere = facts.__scopedSnapshot || null;
|
|
8666
8821
|
const lvlHere = (facts && typeof facts.__scopedClosureLevel === 'number' && facts.__scopedClosureLevel) || 0;
|
|
8667
8822
|
if (!snapHere) return true;
|
|
8668
|
-
if (
|
|
8823
|
+
if (info.exactLevel) {
|
|
8824
|
+
if (lvlHere !== info.requiredLevel) return true;
|
|
8825
|
+
} else if (lvlHere < info.requiredLevel) {
|
|
8826
|
+
return true;
|
|
8827
|
+
}
|
|
8669
8828
|
}
|
|
8670
8829
|
|
|
8671
8830
|
// Optimization: if the rule head is **structurally ground** (no vars anywhere, even inside
|
|
@@ -8865,6 +9024,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8865
9024
|
|
|
8866
9025
|
const outcome = __emitForwardRuleSolution(r, entry.ruleIndex, s);
|
|
8867
9026
|
if (outcome.rulesChanged) {
|
|
9027
|
+
maxScopedClosurePriorityNeeded = Math.max(
|
|
9028
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9029
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
9030
|
+
);
|
|
8868
9031
|
agendaIndex = makeSinglePremiseAgendaIndex(forwardRules, backRules);
|
|
8869
9032
|
agendaCursor = 0;
|
|
8870
9033
|
}
|
|
@@ -8878,7 +9041,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8878
9041
|
for (let i = 0; i < forwardRules.length; i++) {
|
|
8879
9042
|
const r = forwardRules[i];
|
|
8880
9043
|
if (agendaIndex.indexed.has(r)) continue;
|
|
8881
|
-
if (r.__needsForwardSkipCheck && __skipForwardRuleNow(r)) continue;
|
|
9044
|
+
if ((r.__needsForwardSkipCheck || (r.__scopedStratumInfo && r.__scopedStratumInfo.needsSnap)) && __skipForwardRuleNow(r)) continue;
|
|
8882
9045
|
|
|
8883
9046
|
const headIsStrictGround = r.__headIsStrictGround;
|
|
8884
9047
|
const maxSols = r.isFuse || headIsStrictGround ? 1 : undefined;
|
|
@@ -8899,6 +9062,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8899
9062
|
for (const s of sols) {
|
|
8900
9063
|
const outcome = __emitForwardRuleSolution(r, i, s);
|
|
8901
9064
|
if (outcome.rulesChanged) {
|
|
9065
|
+
maxScopedClosurePriorityNeeded = Math.max(
|
|
9066
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9067
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
9068
|
+
);
|
|
8902
9069
|
agendaIndex = makeSinglePremiseAgendaIndex(forwardRules, backRules);
|
|
8903
9070
|
agendaCursor = 0;
|
|
8904
9071
|
}
|
|
@@ -8926,8 +9093,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8926
9093
|
// Rules may have been added dynamically (rule-producing triples), possibly
|
|
8927
9094
|
// introducing scoped builtins and/or higher closure priorities.
|
|
8928
9095
|
maxScopedClosurePriorityNeeded = Math.max(
|
|
8929
|
-
maxScopedClosurePriorityNeeded,
|
|
8930
9096
|
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9097
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
8931
9098
|
);
|
|
8932
9099
|
|
|
8933
9100
|
// If there are no scoped builtins in the entire program, Phase B is pure
|
|
@@ -8945,8 +9112,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8945
9112
|
|
|
8946
9113
|
// Phase B can also derive rule-producing triples.
|
|
8947
9114
|
maxScopedClosurePriorityNeeded = Math.max(
|
|
8948
|
-
maxScopedClosurePriorityNeeded,
|
|
8949
9115
|
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
9116
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
8950
9117
|
);
|
|
8951
9118
|
|
|
8952
9119
|
if (!changedA && !changedB && scopedClosureLevel >= maxScopedClosurePriorityNeeded) break;
|
package/lib/engine.js
CHANGED
|
@@ -484,6 +484,158 @@ function __varOccursElsewhereInPremise(premise, name, idx, field) {
|
|
|
484
484
|
return false;
|
|
485
485
|
}
|
|
486
486
|
|
|
487
|
+
|
|
488
|
+
function __scopedPriorityForTerm(t) {
|
|
489
|
+
if (t instanceof GraphTerm) return 0;
|
|
490
|
+
const p0 = __logNaturalPriorityFromTerm(t);
|
|
491
|
+
return p0 !== null && p0 >= 1 ? p0 : 1;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function __pushScopedQueryTriplesFromGraph(term, out) {
|
|
495
|
+
if (!(term instanceof GraphTerm)) return;
|
|
496
|
+
for (const tr of term.triples) out.push(tr);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function __analyzeForwardRuleScopedUse(rule) {
|
|
500
|
+
const out = {
|
|
501
|
+
needsSnap: false,
|
|
502
|
+
baseLevel: 0,
|
|
503
|
+
queryTriples: [],
|
|
504
|
+
hasScopedAggregate: false,
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
if (!rule || !Array.isArray(rule.premise)) return out;
|
|
508
|
+
|
|
509
|
+
for (let i = 0; i < rule.premise.length; i++) {
|
|
510
|
+
const tr = rule.premise[i];
|
|
511
|
+
if (!(tr && tr.p instanceof Iri)) continue;
|
|
512
|
+
const pv = tr.p.value;
|
|
513
|
+
|
|
514
|
+
if (pv === LOG_NS + 'includes' || pv === LOG_NS + 'notIncludes') {
|
|
515
|
+
// Explicit quoted scopes are local formulas, not snapshots of the global closure.
|
|
516
|
+
if (tr.s instanceof GraphTerm) continue;
|
|
517
|
+
|
|
518
|
+
// A scope variable that is bound by another premise may become an explicit GraphTerm.
|
|
519
|
+
// Still, if it remains unbound at runtime the builtin treats it as priority 1.
|
|
520
|
+
// We therefore record the scoped use, but only use quoted object triples for
|
|
521
|
+
// dependency analysis; variables inside the quoted object do not bind the scope.
|
|
522
|
+
out.needsSnap = true;
|
|
523
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.s));
|
|
524
|
+
__pushScopedQueryTriplesFromGraph(tr.o, out.queryTriples);
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (pv === LOG_NS + 'collectAllIn') {
|
|
529
|
+
if (tr.o instanceof GraphTerm) continue;
|
|
530
|
+
|
|
531
|
+
out.needsSnap = true;
|
|
532
|
+
out.hasScopedAggregate = true;
|
|
533
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.o));
|
|
534
|
+
if (tr.s instanceof ListTerm && tr.s.elems.length === 3) {
|
|
535
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[1], out.queryTriples);
|
|
536
|
+
}
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (pv === LOG_NS + 'forAllIn') {
|
|
541
|
+
if (tr.o instanceof GraphTerm) continue;
|
|
542
|
+
|
|
543
|
+
out.needsSnap = true;
|
|
544
|
+
out.hasScopedAggregate = true;
|
|
545
|
+
out.baseLevel = Math.max(out.baseLevel, __scopedPriorityForTerm(tr.o));
|
|
546
|
+
if (tr.s instanceof ListTerm && tr.s.elems.length === 2) {
|
|
547
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[0], out.queryTriples);
|
|
548
|
+
__pushScopedQueryTriplesFromGraph(tr.s.elems[1], out.queryTriples);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return out;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function __triplePatternsMayOverlap(a, b) {
|
|
557
|
+
return unifyTriple(a, b, __emptySubst()) !== null || unifyTriple(b, a, __emptySubst()) !== null;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function __ruleConclusionsMayFeedScopedQueries(producer, consumerMeta) {
|
|
561
|
+
if (!consumerMeta || !consumerMeta.queryTriples || consumerMeta.queryTriples.length === 0) return false;
|
|
562
|
+
|
|
563
|
+
// Dynamic conclusions are only known after a proof solution. Conservatively
|
|
564
|
+
// assume they can feed any scoped query if the producing rule is scoped.
|
|
565
|
+
if (producer && producer.__dynamicConclusionTerm) return true;
|
|
566
|
+
|
|
567
|
+
if (!producer || !Array.isArray(producer.conclusion) || producer.conclusion.length === 0) return false;
|
|
568
|
+
for (const q of consumerMeta.queryTriples) {
|
|
569
|
+
for (const h of producer.conclusion) {
|
|
570
|
+
if (__triplePatternsMayOverlap(q, h)) return true;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function __setForwardRuleScopedStratumInfo(rule, level) {
|
|
577
|
+
const value =
|
|
578
|
+
level > 0
|
|
579
|
+
? { needsSnap: true, requiredLevel: level, exactLevel: true }
|
|
580
|
+
: { needsSnap: false, requiredLevel: 0, exactLevel: false };
|
|
581
|
+
|
|
582
|
+
if (!hasOwn.call(rule, '__scopedStratumInfo')) {
|
|
583
|
+
Object.defineProperty(rule, '__scopedStratumInfo', {
|
|
584
|
+
value,
|
|
585
|
+
enumerable: false,
|
|
586
|
+
writable: true,
|
|
587
|
+
configurable: true,
|
|
588
|
+
});
|
|
589
|
+
} else {
|
|
590
|
+
rule.__scopedStratumInfo = value;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function __computeForwardRuleScopedStrata(forwardRules) {
|
|
595
|
+
if (!Array.isArray(forwardRules) || forwardRules.length === 0) return 0;
|
|
596
|
+
|
|
597
|
+
const metas = forwardRules.map((r) => __analyzeForwardRuleScopedUse(r));
|
|
598
|
+
const levels = metas.map((m) => (m.needsSnap ? Math.max(1, m.baseLevel || 1) : 0));
|
|
599
|
+
|
|
600
|
+
let maxLevel = 0;
|
|
601
|
+
for (const lvl of levels) if (lvl > maxLevel) maxLevel = lvl;
|
|
602
|
+
|
|
603
|
+
// Stratify scoped rules by data dependency: if a scoped query can read facts
|
|
604
|
+
// produced by another scoped rule, the reader must run against a later frozen
|
|
605
|
+
// snapshot. This prevents non-monotonic scoped builtins such as collectAllIn
|
|
606
|
+
// from emitting an early result before lower strata have derived their facts.
|
|
607
|
+
const passLimit = Math.max(1, forwardRules.length) + maxLevel + 1;
|
|
608
|
+
for (let pass = 0; pass < passLimit; pass++) {
|
|
609
|
+
let changed = false;
|
|
610
|
+
for (let ci = 0; ci < forwardRules.length; ci++) {
|
|
611
|
+
if (!metas[ci].needsSnap || !metas[ci].hasScopedAggregate) continue;
|
|
612
|
+
let needed = levels[ci];
|
|
613
|
+
for (let pi = 0; pi < forwardRules.length; pi++) {
|
|
614
|
+
if (pi === ci) continue;
|
|
615
|
+
if (levels[pi] <= 0) continue;
|
|
616
|
+
if (metas[pi].hasScopedAggregate) continue;
|
|
617
|
+
if (!__ruleConclusionsMayFeedScopedQueries(forwardRules[pi], metas[ci])) continue;
|
|
618
|
+
needed = Math.max(needed, levels[pi] + 1);
|
|
619
|
+
}
|
|
620
|
+
if (needed !== levels[ci]) {
|
|
621
|
+
levels[ci] = needed;
|
|
622
|
+
if (needed > maxLevel) maxLevel = needed;
|
|
623
|
+
changed = true;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (!changed) break;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
maxLevel = 0;
|
|
631
|
+
for (let i = 0; i < forwardRules.length; i++) {
|
|
632
|
+
__setForwardRuleScopedStratumInfo(forwardRules[i], levels[i]);
|
|
633
|
+
if (levels[i] > maxLevel) maxLevel = levels[i];
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return maxLevel;
|
|
637
|
+
}
|
|
638
|
+
|
|
487
639
|
function __computeForwardRuleScopedSkipInfo(rule) {
|
|
488
640
|
let needsSnap = false;
|
|
489
641
|
let requiredLevel = 0;
|
|
@@ -1669,7 +1821,7 @@ function makeSinglePremiseAgendaIndex(forwardRules, backRules) {
|
|
|
1669
1821
|
goalPredTid: goal.p instanceof Iri ? goal.p.__tid : null,
|
|
1670
1822
|
goalSKey,
|
|
1671
1823
|
goalOKey,
|
|
1672
|
-
needsSkipCheck: !!r.__needsForwardSkipCheck,
|
|
1824
|
+
needsSkipCheck: !!(r.__needsForwardSkipCheck || (r.__scopedStratumInfo && r.__scopedStratumInfo.needsSnap)),
|
|
1673
1825
|
fastSubjectVar,
|
|
1674
1826
|
fastObjectVar,
|
|
1675
1827
|
};
|
|
@@ -3117,7 +3269,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3117
3269
|
let scopedClosureLevel = 0;
|
|
3118
3270
|
|
|
3119
3271
|
// Scan known rules for the maximum requested closure priority in scoped log:* goals.
|
|
3120
|
-
let maxScopedClosurePriorityNeeded =
|
|
3272
|
+
let maxScopedClosurePriorityNeeded = Math.max(
|
|
3273
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
3274
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
3275
|
+
);
|
|
3121
3276
|
|
|
3122
3277
|
// Conservative fast-skip for forward rules that cannot possibly succeed
|
|
3123
3278
|
// until a scoped snapshot exists (or a given closure level is reached).
|
|
@@ -3171,12 +3326,16 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3171
3326
|
// until a snapshot exists (and a certain closure level is reached).
|
|
3172
3327
|
// This prevents expensive proofs that will definitely fail in Phase A
|
|
3173
3328
|
// and in early closure levels.
|
|
3174
|
-
const info = r.__scopedSkipInfo;
|
|
3329
|
+
const info = r.__scopedStratumInfo || r.__scopedSkipInfo;
|
|
3175
3330
|
if (info && info.needsSnap) {
|
|
3176
3331
|
const snapHere = facts.__scopedSnapshot || null;
|
|
3177
3332
|
const lvlHere = (facts && typeof facts.__scopedClosureLevel === 'number' && facts.__scopedClosureLevel) || 0;
|
|
3178
3333
|
if (!snapHere) return true;
|
|
3179
|
-
if (
|
|
3334
|
+
if (info.exactLevel) {
|
|
3335
|
+
if (lvlHere !== info.requiredLevel) return true;
|
|
3336
|
+
} else if (lvlHere < info.requiredLevel) {
|
|
3337
|
+
return true;
|
|
3338
|
+
}
|
|
3180
3339
|
}
|
|
3181
3340
|
|
|
3182
3341
|
// Optimization: if the rule head is **structurally ground** (no vars anywhere, even inside
|
|
@@ -3376,6 +3535,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3376
3535
|
|
|
3377
3536
|
const outcome = __emitForwardRuleSolution(r, entry.ruleIndex, s);
|
|
3378
3537
|
if (outcome.rulesChanged) {
|
|
3538
|
+
maxScopedClosurePriorityNeeded = Math.max(
|
|
3539
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
3540
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
3541
|
+
);
|
|
3379
3542
|
agendaIndex = makeSinglePremiseAgendaIndex(forwardRules, backRules);
|
|
3380
3543
|
agendaCursor = 0;
|
|
3381
3544
|
}
|
|
@@ -3389,7 +3552,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3389
3552
|
for (let i = 0; i < forwardRules.length; i++) {
|
|
3390
3553
|
const r = forwardRules[i];
|
|
3391
3554
|
if (agendaIndex.indexed.has(r)) continue;
|
|
3392
|
-
if (r.__needsForwardSkipCheck && __skipForwardRuleNow(r)) continue;
|
|
3555
|
+
if ((r.__needsForwardSkipCheck || (r.__scopedStratumInfo && r.__scopedStratumInfo.needsSnap)) && __skipForwardRuleNow(r)) continue;
|
|
3393
3556
|
|
|
3394
3557
|
const headIsStrictGround = r.__headIsStrictGround;
|
|
3395
3558
|
const maxSols = r.isFuse || headIsStrictGround ? 1 : undefined;
|
|
@@ -3410,6 +3573,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3410
3573
|
for (const s of sols) {
|
|
3411
3574
|
const outcome = __emitForwardRuleSolution(r, i, s);
|
|
3412
3575
|
if (outcome.rulesChanged) {
|
|
3576
|
+
maxScopedClosurePriorityNeeded = Math.max(
|
|
3577
|
+
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
3578
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
3579
|
+
);
|
|
3413
3580
|
agendaIndex = makeSinglePremiseAgendaIndex(forwardRules, backRules);
|
|
3414
3581
|
agendaCursor = 0;
|
|
3415
3582
|
}
|
|
@@ -3437,8 +3604,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3437
3604
|
// Rules may have been added dynamically (rule-producing triples), possibly
|
|
3438
3605
|
// introducing scoped builtins and/or higher closure priorities.
|
|
3439
3606
|
maxScopedClosurePriorityNeeded = Math.max(
|
|
3440
|
-
maxScopedClosurePriorityNeeded,
|
|
3441
3607
|
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
3608
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
3442
3609
|
);
|
|
3443
3610
|
|
|
3444
3611
|
// If there are no scoped builtins in the entire program, Phase B is pure
|
|
@@ -3456,8 +3623,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
3456
3623
|
|
|
3457
3624
|
// Phase B can also derive rule-producing triples.
|
|
3458
3625
|
maxScopedClosurePriorityNeeded = Math.max(
|
|
3459
|
-
maxScopedClosurePriorityNeeded,
|
|
3460
3626
|
__computeMaxScopedClosurePriorityNeeded(forwardRules, backRules),
|
|
3627
|
+
__computeForwardRuleScopedStrata(forwardRules),
|
|
3461
3628
|
);
|
|
3462
3629
|
|
|
3463
3630
|
if (!changedA && !changedB && scopedClosureLevel >= maxScopedClosurePriorityNeeded) break;
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -2496,6 +2496,26 @@ _:b a ex:Person ; ex:name "B" .
|
|
|
2496
2496
|
],
|
|
2497
2497
|
notExpect: [/:result\s+:sumX\s+"329"\^\^xsd:decimal\s*\./, /:result\s+:meanX\s+"47"\^\^xsd:decimal\s*\./],
|
|
2498
2498
|
},
|
|
2499
|
+
{
|
|
2500
|
+
name: '244 regression: scoped collectAllIn is stratified after scoped notIncludes',
|
|
2501
|
+
opt: { proofComments: false },
|
|
2502
|
+
input: `@prefix : <http://example.org/> .
|
|
2503
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
2504
|
+
|
|
2505
|
+
:a :x 1 .
|
|
2506
|
+
:b :x 1 .
|
|
2507
|
+
|
|
2508
|
+
{ ?s :x 1 . ?X log:notIncludes { ?s :marked ?X } } => { ?s :marked true } .
|
|
2509
|
+
{ ( ?s { ?s :marked true } ?all ) log:collectAllIn ?scope } => { :result :marked ?all } .
|
|
2510
|
+
`,
|
|
2511
|
+
expect: [
|
|
2512
|
+
/^:a\s+:marked\s+true\s*\./m,
|
|
2513
|
+
/^:b\s+:marked\s+true\s*\./m,
|
|
2514
|
+
/^:result\s+:marked\s+\(:a\s+:b\)\s*\./m,
|
|
2515
|
+
],
|
|
2516
|
+
notExpect: [/^:result\s+:marked\s+\(\)\s*\./m],
|
|
2517
|
+
},
|
|
2518
|
+
|
|
2499
2519
|
{
|
|
2500
2520
|
name: '244 regression: log:dtlit recognizes shorthand numeric and boolean literals',
|
|
2501
2521
|
opt: { proofComments: false },
|
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
# ==========================================================================
|
|
2
|
-
# The Library and the Path
|
|
3
|
-
#
|
|
4
|
-
# Source essay:
|
|
5
|
-
# https://josd.github.io/the-library-and-the-path/
|
|
6
|
-
#
|
|
7
|
-
# What this file is trying to do
|
|
8
|
-
# ------------------------------
|
|
9
|
-
# The essay uses a philosophical image:
|
|
10
|
-
#
|
|
11
|
-
# • The "Library" is the space of many possible, internally coherent ways
|
|
12
|
-
# things could be.
|
|
13
|
-
# • The "Path" is the one realized history we actually inhabit.
|
|
14
|
-
# • "Observership" is not a godlike view from outside the world. It is a
|
|
15
|
-
# process inside the Path: systems make observations, leave records, and
|
|
16
|
-
# those records constrain which earlier histories still make sense.
|
|
17
|
-
#
|
|
18
|
-
# This file translates that idea into semantic data and lightweight rules.
|
|
19
|
-
# It is not a physics engine and not a proof of the essay. It is a readable,
|
|
20
|
-
# machine-processable toy model inspired by the essay.
|
|
21
|
-
#
|
|
22
|
-
# Design choices
|
|
23
|
-
# --------------
|
|
24
|
-
# 1. The model uses five layers, echoing the essay's stacked descriptions:
|
|
25
|
-
# quantum, thermodynamic, biological, cognitive, social
|
|
26
|
-
# 2. The Library contains multiple possible states and branches.
|
|
27
|
-
# 3. The realized Path selects one sequence of states.
|
|
28
|
-
# 4. Observations create records.
|
|
29
|
-
# 5. Records act as constraints on candidate histories.
|
|
30
|
-
# ==========================================================================
|
|
31
|
-
|
|
32
|
-
@prefix ex: <https://example.org/library-path#> .
|
|
33
|
-
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
34
|
-
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
35
|
-
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
|
|
36
|
-
|
|
37
|
-
# ----------
|
|
38
|
-
# Vocabulary
|
|
39
|
-
# ----------
|
|
40
|
-
|
|
41
|
-
# These are the main kinds of things in the model.
|
|
42
|
-
ex:Library a rdfs:Class ; rdfs:label "Library" .
|
|
43
|
-
ex:Layer a rdfs:Class ; rdfs:label "Layer of description" .
|
|
44
|
-
ex:State a rdfs:Class ; rdfs:label "State" .
|
|
45
|
-
ex:PossibleState a rdfs:Class ; rdfs:subClassOf ex:State ; rdfs:label "Possible state" .
|
|
46
|
-
ex:RealizedState a rdfs:Class ; rdfs:subClassOf ex:State ; rdfs:label "Realized state" .
|
|
47
|
-
ex:Path a rdfs:Class ; rdfs:label "Path" .
|
|
48
|
-
ex:Transition a rdfs:Class ; rdfs:label "Transition" .
|
|
49
|
-
ex:Observer a rdfs:Class ; rdfs:label "Observer" .
|
|
50
|
-
ex:Observation a rdfs:Class ; rdfs:label "Observation" .
|
|
51
|
-
ex:Record a rdfs:Class ; rdfs:label "Record" .
|
|
52
|
-
ex:Constraint a rdfs:Class ; rdfs:label "Constraint" .
|
|
53
|
-
ex:History a rdfs:Class ; rdfs:label "Candidate history" .
|
|
54
|
-
ex:Theme a rdfs:Class ; rdfs:label "Theme" .
|
|
55
|
-
ex:InterpretiveNote a rdfs:Class ; rdfs:label "Interpretive note" .
|
|
56
|
-
|
|
57
|
-
# Properties. Their names are chosen to read like plain English.
|
|
58
|
-
ex:containsLayer a rdf:Property .
|
|
59
|
-
ex:containsState a rdf:Property .
|
|
60
|
-
ex:containsHistory a rdf:Property .
|
|
61
|
-
ex:throughLibrary a rdf:Property .
|
|
62
|
-
ex:hasState a rdf:Property .
|
|
63
|
-
ex:startsAt a rdf:Property .
|
|
64
|
-
ex:endsAt a rdf:Property .
|
|
65
|
-
ex:nextState a rdf:Property .
|
|
66
|
-
ex:branchesTo a rdf:Property .
|
|
67
|
-
ex:atLayer a rdf:Property .
|
|
68
|
-
ex:timeIndex a rdf:Property .
|
|
69
|
-
ex:describedByTheme a rdf:Property .
|
|
70
|
-
ex:hasTransition a rdf:Property .
|
|
71
|
-
ex:fromState a rdf:Property .
|
|
72
|
-
ex:toState a rdf:Property .
|
|
73
|
-
ex:transitionType a rdf:Property .
|
|
74
|
-
ex:observedBy a rdf:Property .
|
|
75
|
-
ex:makesObservation a rdf:Property .
|
|
76
|
-
ex:atState a rdf:Property .
|
|
77
|
-
ex:writesRecord a rdf:Property .
|
|
78
|
-
ex:aboutState a rdf:Property .
|
|
79
|
-
ex:hasRecord a rdf:Property .
|
|
80
|
-
ex:hasConstraint a rdf:Property .
|
|
81
|
-
ex:matchesRecord a rdf:Property .
|
|
82
|
-
ex:supportsConstraint a rdf:Property .
|
|
83
|
-
ex:compatibleWith a rdf:Property .
|
|
84
|
-
ex:incompatibleWith a rdf:Property .
|
|
85
|
-
ex:memberState a rdf:Property .
|
|
86
|
-
ex:realizes a rdf:Property .
|
|
87
|
-
ex:selectsFrom a rdf:Property .
|
|
88
|
-
ex:plainEnglish a rdf:Property .
|
|
89
|
-
ex:description a rdf:Property .
|
|
90
|
-
ex:glosses a rdf:Property .
|
|
91
|
-
ex:notes a rdf:Property .
|
|
92
|
-
ex:focusesOn a rdf:Property .
|
|
93
|
-
|
|
94
|
-
# -------------------
|
|
95
|
-
# High-level concepts
|
|
96
|
-
# -------------------
|
|
97
|
-
|
|
98
|
-
ex:theLibrary a ex:Library ;
|
|
99
|
-
rdfs:label "The Library" ;
|
|
100
|
-
ex:description "The timeless space of structured possibilities." ;
|
|
101
|
-
ex:plainEnglish "Think of this as the set of coherent ways the world could be, not yet reduced to one lived history." ;
|
|
102
|
-
ex:containsLayer ex:quantum, ex:thermodynamic, ex:biological, ex:cognitive, ex:social .
|
|
103
|
-
|
|
104
|
-
ex:realizedPath a ex:Path ;
|
|
105
|
-
rdfs:label "The realized Path" ;
|
|
106
|
-
ex:throughLibrary ex:theLibrary ;
|
|
107
|
-
ex:selectsFrom ex:theLibrary ;
|
|
108
|
-
ex:description "One actual history through the Library." ;
|
|
109
|
-
ex:plainEnglish "Out of many possibilities, this is the single unfolding sequence that becomes lived reality." .
|
|
110
|
-
|
|
111
|
-
ex:observer a ex:Observer ;
|
|
112
|
-
rdfs:label "Observership" ;
|
|
113
|
-
ex:description "Perspective from within the Path that creates records." ;
|
|
114
|
-
ex:plainEnglish "The observer is not outside the universe. Observation happens inside the realized history and leaves traces behind." .
|
|
115
|
-
|
|
116
|
-
# -----------------
|
|
117
|
-
# Layers and themes
|
|
118
|
-
# -----------------
|
|
119
|
-
|
|
120
|
-
# Each layer is a way of describing the same broad reality at a different scale
|
|
121
|
-
# or level of organization.
|
|
122
|
-
ex:quantum a ex:Layer ;
|
|
123
|
-
rdfs:label "Quantum" ;
|
|
124
|
-
ex:plainEnglish "Microscopic possibilities and amplitudes." ;
|
|
125
|
-
ex:describedByTheme ex:themePossibility .
|
|
126
|
-
|
|
127
|
-
ex:thermodynamic a ex:Layer ;
|
|
128
|
-
rdfs:label "Thermodynamic" ;
|
|
129
|
-
ex:plainEnglish "Flows, gradients, dissipation, and the arrow of time." ;
|
|
130
|
-
ex:describedByTheme ex:themeIrreversibility .
|
|
131
|
-
|
|
132
|
-
ex:biological a ex:Layer ;
|
|
133
|
-
rdfs:label "Biological" ;
|
|
134
|
-
ex:plainEnglish "Living systems that preserve structure and memory across generations." ;
|
|
135
|
-
ex:describedByTheme ex:themePersistence .
|
|
136
|
-
|
|
137
|
-
ex:cognitive a ex:Layer ;
|
|
138
|
-
rdfs:label "Cognitive" ;
|
|
139
|
-
ex:plainEnglish "Internal models, recall, anticipation, and interpretation." ;
|
|
140
|
-
ex:describedByTheme ex:themeModeling .
|
|
141
|
-
|
|
142
|
-
ex:social a ex:Layer ;
|
|
143
|
-
rdfs:label "Social" ;
|
|
144
|
-
ex:plainEnglish "Language, institutions, archives, and public memory." ;
|
|
145
|
-
ex:describedByTheme ex:themeSharedRecord .
|
|
146
|
-
|
|
147
|
-
ex:themePossibility a ex:Theme ;
|
|
148
|
-
rdfs:label "Possibility" ;
|
|
149
|
-
ex:glosses "Many coherent alternatives can exist in description before one history is lived." .
|
|
150
|
-
|
|
151
|
-
ex:themeIrreversibility a ex:Theme ;
|
|
152
|
-
rdfs:label "Irreversibility" ;
|
|
153
|
-
ex:glosses "Records and gradients make the past different from the future." .
|
|
154
|
-
|
|
155
|
-
ex:themePersistence a ex:Theme ;
|
|
156
|
-
rdfs:label "Persistence" ;
|
|
157
|
-
ex:glosses "Some structures endure and transmit form." .
|
|
158
|
-
|
|
159
|
-
ex:themeModeling a ex:Theme ;
|
|
160
|
-
rdfs:label "Modeling" ;
|
|
161
|
-
ex:glosses "Minds encode and use internal representations." .
|
|
162
|
-
|
|
163
|
-
ex:themeSharedRecord a ex:Theme ;
|
|
164
|
-
rdfs:label "Shared record" ;
|
|
165
|
-
ex:glosses "Groups stabilize memory in symbols, texts, norms, and institutions." .
|
|
166
|
-
|
|
167
|
-
# ---------------------
|
|
168
|
-
# States in the Library
|
|
169
|
-
# ---------------------
|
|
170
|
-
|
|
171
|
-
# A state is not meant to be a complete physical description of everything.
|
|
172
|
-
# It is a compact marker for a stage in a possible history.
|
|
173
|
-
|
|
174
|
-
# ---- Realized states ----
|
|
175
|
-
ex:s0 a ex:PossibleState, ex:RealizedState ;
|
|
176
|
-
rdfs:label "s0" ;
|
|
177
|
-
ex:timeIndex 0 ;
|
|
178
|
-
ex:atLayer ex:quantum ;
|
|
179
|
-
ex:description "Initial low-information possibility." ;
|
|
180
|
-
ex:plainEnglish "A starting point containing many open possibilities." .
|
|
181
|
-
|
|
182
|
-
ex:s1 a ex:PossibleState, ex:RealizedState ;
|
|
183
|
-
rdfs:label "s1" ;
|
|
184
|
-
ex:timeIndex 1 ;
|
|
185
|
-
ex:atLayer ex:thermodynamic ;
|
|
186
|
-
ex:description "Entropy gradient becomes a usable arrow." ;
|
|
187
|
-
ex:plainEnglish "A directionality appears: some traces can now accumulate rather than instantly disappear." .
|
|
188
|
-
|
|
189
|
-
ex:s2 a ex:PossibleState, ex:RealizedState ;
|
|
190
|
-
rdfs:label "s2" ;
|
|
191
|
-
ex:timeIndex 2 ;
|
|
192
|
-
ex:atLayer ex:biological ;
|
|
193
|
-
ex:description "A living lineage persists and stores traces." ;
|
|
194
|
-
ex:plainEnglish "Something like heredity or durable adaptation now carries information forward." .
|
|
195
|
-
|
|
196
|
-
ex:s3 a ex:PossibleState, ex:RealizedState ;
|
|
197
|
-
rdfs:label "s3" ;
|
|
198
|
-
ex:timeIndex 3 ;
|
|
199
|
-
ex:atLayer ex:cognitive ;
|
|
200
|
-
ex:description "A mind models the world and remembers." ;
|
|
201
|
-
ex:plainEnglish "Memory becomes explicit enough to support interpretation and anticipation." .
|
|
202
|
-
|
|
203
|
-
ex:s4 a ex:PossibleState, ex:RealizedState ;
|
|
204
|
-
rdfs:label "s4" ;
|
|
205
|
-
ex:timeIndex 4 ;
|
|
206
|
-
ex:atLayer ex:social ;
|
|
207
|
-
ex:description "Shared language stabilizes public records." ;
|
|
208
|
-
ex:plainEnglish "Memory is no longer only private. It becomes collective and institutional." .
|
|
209
|
-
|
|
210
|
-
# ---- Alternative states not taken on the realized Path ----
|
|
211
|
-
ex:s1a a ex:PossibleState ;
|
|
212
|
-
rdfs:label "s1a" ;
|
|
213
|
-
ex:timeIndex 1 ;
|
|
214
|
-
ex:atLayer ex:thermodynamic ;
|
|
215
|
-
ex:description "Thermal structure dissipates too quickly." ;
|
|
216
|
-
ex:plainEnglish "The world remains too fleeting to support durable traces." .
|
|
217
|
-
|
|
218
|
-
ex:s2a a ex:PossibleState ;
|
|
219
|
-
rdfs:label "s2a" ;
|
|
220
|
-
ex:timeIndex 2 ;
|
|
221
|
-
ex:atLayer ex:biological ;
|
|
222
|
-
ex:description "No robust biological memory emerges." ;
|
|
223
|
-
ex:plainEnglish "There are local structures, but nothing that preserves adaptive information well." .
|
|
224
|
-
|
|
225
|
-
ex:s3a a ex:PossibleState ;
|
|
226
|
-
rdfs:label "s3a" ;
|
|
227
|
-
ex:timeIndex 3 ;
|
|
228
|
-
ex:atLayer ex:cognitive ;
|
|
229
|
-
ex:description "Local cognition forms, but no durable self-model." ;
|
|
230
|
-
ex:plainEnglish "Some processing happens, but not enough stable reflective memory to anchor a long narrative." .
|
|
231
|
-
|
|
232
|
-
ex:s4a a ex:PossibleState ;
|
|
233
|
-
rdfs:label "s4a" ;
|
|
234
|
-
ex:timeIndex 4 ;
|
|
235
|
-
ex:atLayer ex:social ;
|
|
236
|
-
ex:description "Agents fail to coordinate stable communal archives." ;
|
|
237
|
-
ex:plainEnglish "There may be minds, but no lasting shared record of them." .
|
|
238
|
-
|
|
239
|
-
ex:theLibrary
|
|
240
|
-
ex:containsState ex:s0, ex:s1, ex:s2, ex:s3, ex:s4,
|
|
241
|
-
ex:s1a, ex:s2a, ex:s3a, ex:s4a .
|
|
242
|
-
|
|
243
|
-
# -------------------
|
|
244
|
-
# Branching structure
|
|
245
|
-
# -------------------
|
|
246
|
-
|
|
247
|
-
# The Library contains branches. The Path selects one branch.
|
|
248
|
-
ex:s0 ex:branchesTo ex:s1, ex:s1a .
|
|
249
|
-
ex:s1 ex:branchesTo ex:s2, ex:s2a .
|
|
250
|
-
ex:s1a ex:branchesTo ex:s2a .
|
|
251
|
-
ex:s2 ex:branchesTo ex:s3, ex:s3a .
|
|
252
|
-
ex:s2a ex:branchesTo ex:s3a .
|
|
253
|
-
ex:s3 ex:branchesTo ex:s4, ex:s4a .
|
|
254
|
-
ex:s3a ex:branchesTo ex:s4a .
|
|
255
|
-
|
|
256
|
-
# The single realized history.
|
|
257
|
-
|
|
258
|
-
ex:realizedPath
|
|
259
|
-
ex:hasState ex:s0, ex:s1, ex:s2, ex:s3, ex:s4 ;
|
|
260
|
-
ex:startsAt ex:s0 ;
|
|
261
|
-
ex:endsAt ex:s4 ;
|
|
262
|
-
ex:notes "This is the one branch counted as lived reality in the model." .
|
|
263
|
-
|
|
264
|
-
ex:s0 ex:nextState ex:s1 .
|
|
265
|
-
ex:s1 ex:nextState ex:s2 .
|
|
266
|
-
ex:s2 ex:nextState ex:s3 .
|
|
267
|
-
ex:s3 ex:nextState ex:s4 .
|
|
268
|
-
|
|
269
|
-
# -----------
|
|
270
|
-
# Transitions
|
|
271
|
-
# -----------
|
|
272
|
-
|
|
273
|
-
# Transitions make the path easier to read for humans.
|
|
274
|
-
ex:t01 a ex:Transition ;
|
|
275
|
-
ex:fromState ex:s0 ;
|
|
276
|
-
ex:toState ex:s1 ;
|
|
277
|
-
ex:transitionType "selection into durable asymmetry" ;
|
|
278
|
-
ex:description "A world with usable directional structure emerges." .
|
|
279
|
-
|
|
280
|
-
ex:t12 a ex:Transition ;
|
|
281
|
-
ex:fromState ex:s1 ;
|
|
282
|
-
ex:toState ex:s2 ;
|
|
283
|
-
ex:transitionType "persistence into adaptation" ;
|
|
284
|
-
ex:description "Energy gradients support living systems that keep information." .
|
|
285
|
-
|
|
286
|
-
ex:t23 a ex:Transition ;
|
|
287
|
-
ex:fromState ex:s2 ;
|
|
288
|
-
ex:toState ex:s3 ;
|
|
289
|
-
ex:transitionType "adaptation into modeling" ;
|
|
290
|
-
ex:description "Biological persistence develops into explicit internal world-models." .
|
|
291
|
-
|
|
292
|
-
ex:t34 a ex:Transition ;
|
|
293
|
-
ex:fromState ex:s3 ;
|
|
294
|
-
ex:toState ex:s4 ;
|
|
295
|
-
ex:transitionType "private memory into public memory" ;
|
|
296
|
-
ex:description "Symbols and institutions stabilize records beyond individual minds." .
|
|
297
|
-
|
|
298
|
-
ex:realizedPath ex:hasTransition ex:t01, ex:t12, ex:t23, ex:t34 .
|
|
299
|
-
|
|
300
|
-
# ------------------------
|
|
301
|
-
# Observations and records
|
|
302
|
-
# ------------------------
|
|
303
|
-
|
|
304
|
-
# In this model, observations produce records. Records are important because
|
|
305
|
-
# they constrain which histories remain plausible from the current standpoint.
|
|
306
|
-
ex:obs1 a ex:Observation ;
|
|
307
|
-
rdfs:label "Observation 1" ;
|
|
308
|
-
ex:atState ex:s1 ;
|
|
309
|
-
ex:writesRecord ex:rec1 ;
|
|
310
|
-
ex:description "A trace of an irreversible thermodynamic arrow is registered." .
|
|
311
|
-
|
|
312
|
-
ex:obs2 a ex:Observation ;
|
|
313
|
-
rdfs:label "Observation 2" ;
|
|
314
|
-
ex:atState ex:s2 ;
|
|
315
|
-
ex:writesRecord ex:rec2 ;
|
|
316
|
-
ex:description "A lineage preserves information across generations." .
|
|
317
|
-
|
|
318
|
-
ex:obs3 a ex:Observation ;
|
|
319
|
-
rdfs:label "Observation 3" ;
|
|
320
|
-
ex:atState ex:s3 ;
|
|
321
|
-
ex:writesRecord ex:rec3 ;
|
|
322
|
-
ex:description "A system forms a recall-capable internal model." .
|
|
323
|
-
|
|
324
|
-
ex:obs4 a ex:Observation ;
|
|
325
|
-
rdfs:label "Observation 4" ;
|
|
326
|
-
ex:atState ex:s4 ;
|
|
327
|
-
ex:writesRecord ex:rec4 ;
|
|
328
|
-
ex:description "A social archive stores memory in a shared symbolic form." .
|
|
329
|
-
|
|
330
|
-
ex:observer ex:makesObservation ex:obs1, ex:obs2, ex:obs3, ex:obs4 .
|
|
331
|
-
|
|
332
|
-
# The records themselves are also constraints.
|
|
333
|
-
ex:rec1 a ex:Record, ex:Constraint ;
|
|
334
|
-
rdfs:label "Record of thermodynamic arrow" ;
|
|
335
|
-
ex:aboutState ex:s1 ;
|
|
336
|
-
ex:description "There exists a stable thermodynamic arrow." ;
|
|
337
|
-
ex:plainEnglish "The present contains traces that imply irreversible structure in the past." .
|
|
338
|
-
|
|
339
|
-
ex:rec2 a ex:Record, ex:Constraint ;
|
|
340
|
-
rdfs:label "Record of biological memory" ;
|
|
341
|
-
ex:aboutState ex:s2 ;
|
|
342
|
-
ex:description "There exists heritable biological memory." ;
|
|
343
|
-
ex:plainEnglish "Current life carries evidence of prior successful information storage." .
|
|
344
|
-
|
|
345
|
-
ex:rec3 a ex:Record, ex:Constraint ;
|
|
346
|
-
rdfs:label "Record of cognitive memory" ;
|
|
347
|
-
ex:aboutState ex:s3 ;
|
|
348
|
-
ex:description "There exists an internal model with recall." ;
|
|
349
|
-
ex:plainEnglish "A remembering mind implies a history rich enough to support its memory traces." .
|
|
350
|
-
|
|
351
|
-
ex:rec4 a ex:Record, ex:Constraint ;
|
|
352
|
-
rdfs:label "Record of social memory" ;
|
|
353
|
-
ex:aboutState ex:s4 ;
|
|
354
|
-
ex:description "There exists shared symbolic culture." ;
|
|
355
|
-
ex:plainEnglish "Texts, rituals, institutions, and archives act as public memory." .
|
|
356
|
-
|
|
357
|
-
# The realized path is constrained by the records visible from within it.
|
|
358
|
-
ex:realizedPath ex:hasConstraint ex:rec1, ex:rec2, ex:rec3, ex:rec4 .
|
|
359
|
-
|
|
360
|
-
# -------------------
|
|
361
|
-
# Candidate histories
|
|
362
|
-
# -------------------
|
|
363
|
-
|
|
364
|
-
# These are simplified rival histories the present might consider.
|
|
365
|
-
# The key idea is that not all candidate pasts fit the records we now have.
|
|
366
|
-
ex:historyAlpha a ex:History ;
|
|
367
|
-
rdfs:label "Alpha — realized history" ;
|
|
368
|
-
ex:memberState ex:s0, ex:s1, ex:s2, ex:s3, ex:s4 ;
|
|
369
|
-
ex:description "The full branch that supports all records in the model." ;
|
|
370
|
-
ex:matchesRecord ex:rec1, ex:rec2, ex:rec3, ex:rec4 .
|
|
371
|
-
|
|
372
|
-
ex:historyBeta a ex:History ;
|
|
373
|
-
rdfs:label "Beta — dissipative branch" ;
|
|
374
|
-
ex:memberState ex:s0, ex:s1a, ex:s2a, ex:s3a, ex:s4a ;
|
|
375
|
-
ex:description "A branch where structure dissipates before rich memory can stabilize." ;
|
|
376
|
-
ex:matchesRecord ex:rec1 .
|
|
377
|
-
|
|
378
|
-
ex:historyGamma a ex:History ;
|
|
379
|
-
rdfs:label "Gamma — biology without durable public memory" ;
|
|
380
|
-
ex:memberState ex:s0, ex:s1, ex:s2, ex:s3a, ex:s4a ;
|
|
381
|
-
ex:description "A branch with persistence and some adaptation, but no robust reflective or social archive." ;
|
|
382
|
-
ex:matchesRecord ex:rec1, ex:rec2 .
|
|
383
|
-
|
|
384
|
-
ex:historyDelta a ex:History ;
|
|
385
|
-
rdfs:label "Delta — private minds without stable institutions" ;
|
|
386
|
-
ex:memberState ex:s0, ex:s1, ex:s2, ex:s3, ex:s4a ;
|
|
387
|
-
ex:description "A branch where memory reaches minds but does not stabilize socially." ;
|
|
388
|
-
ex:matchesRecord ex:rec1, ex:rec2, ex:rec3 .
|
|
389
|
-
|
|
390
|
-
ex:theLibrary ex:containsHistory ex:historyAlpha, ex:historyBeta, ex:historyGamma, ex:historyDelta .
|
|
391
|
-
|
|
392
|
-
# ------------------
|
|
393
|
-
# Interpretive notes
|
|
394
|
-
# ------------------
|
|
395
|
-
|
|
396
|
-
# These are not required for reasoning, but they make the file more readable.
|
|
397
|
-
ex:note1 a ex:InterpretiveNote ;
|
|
398
|
-
ex:focusesOn ex:theLibrary ;
|
|
399
|
-
ex:plainEnglish "The Library is not 'before time' in a literal physical sense here; it is a conceptual space of possibilities." .
|
|
400
|
-
|
|
401
|
-
ex:note2 a ex:InterpretiveNote ;
|
|
402
|
-
ex:focusesOn ex:realizedPath ;
|
|
403
|
-
ex:plainEnglish "The Path is the one sequence that becomes concrete from the inside." .
|
|
404
|
-
|
|
405
|
-
ex:note3 a ex:InterpretiveNote ;
|
|
406
|
-
ex:focusesOn ex:observer ;
|
|
407
|
-
ex:plainEnglish "Observership is modeled as record production, not as magical outside access to all possibilities." .
|
|
408
|
-
|
|
409
|
-
ex:note4 a ex:InterpretiveNote ;
|
|
410
|
-
ex:focusesOn ex:rec1 ;
|
|
411
|
-
ex:plainEnglish "A record is evidence now that narrows what could reasonably count as the past." .
|
|
412
|
-
|
|
413
|
-
# -----
|
|
414
|
-
# Rules
|
|
415
|
-
# -----
|
|
416
|
-
|
|
417
|
-
# These rules are intentionally simple and didactic.
|
|
418
|
-
|
|
419
|
-
# Rule 1
|
|
420
|
-
# If an observation is at a state and writes a record,
|
|
421
|
-
# then that state has that record.
|
|
422
|
-
{ ?obs a ex:Observation ;
|
|
423
|
-
ex:atState ?s ;
|
|
424
|
-
ex:writesRecord ?r . }
|
|
425
|
-
=>
|
|
426
|
-
{ ?s ex:hasRecord ?r .
|
|
427
|
-
?r a ex:Record . } .
|
|
428
|
-
|
|
429
|
-
# Rule 2
|
|
430
|
-
# If the observer makes an observation at a state that lies on the realized path,
|
|
431
|
-
# then that state is observed by that observer.
|
|
432
|
-
{ ?who ex:makesObservation ?obs .
|
|
433
|
-
?obs ex:atState ?s .
|
|
434
|
-
ex:realizedPath ex:hasState ?s . }
|
|
435
|
-
=>
|
|
436
|
-
{ ?s ex:observedBy ?who . } .
|
|
437
|
-
|
|
438
|
-
# Rule 3
|
|
439
|
-
# If a history matches a record that is one of the realized path's constraints,
|
|
440
|
-
# then the history supports that constraint.
|
|
441
|
-
{ ex:realizedPath ex:hasConstraint ?r .
|
|
442
|
-
?h a ex:History ;
|
|
443
|
-
ex:matchesRecord ?r . }
|
|
444
|
-
=>
|
|
445
|
-
{ ?h ex:supportsConstraint ?r . } .
|
|
446
|
-
|
|
447
|
-
# Rule 4
|
|
448
|
-
# Second-stage compatibility check.
|
|
449
|
-
# Inspect closure gate 2, where record-level incompatibilities have already
|
|
450
|
-
# been derived. A history is path-compatible only if no incompatibility is present.
|
|
451
|
-
{
|
|
452
|
-
?h a ex:History .
|
|
453
|
-
2 log:notIncludes { ?h ex:incompatibleWith ?any } .
|
|
454
|
-
}
|
|
455
|
-
=>
|
|
456
|
-
{ ?h ex:compatibleWith ex:realizedPath . } .
|
|
457
|
-
|
|
458
|
-
# Rule 5
|
|
459
|
-
# First-stage record failure check.
|
|
460
|
-
# Inspect closure gate 1 to see whether a history supports a realized-path
|
|
461
|
-
# constraint. If it does not, derive incompatibility with that record.
|
|
462
|
-
{
|
|
463
|
-
ex:realizedPath ex:hasConstraint ?r .
|
|
464
|
-
?h a ex:History .
|
|
465
|
-
1 log:notIncludes { ?h ex:supportsConstraint ?r } .
|
|
466
|
-
}
|
|
467
|
-
=>
|
|
468
|
-
{ ?h ex:incompatibleWith ?r . } .
|
|
469
|
-
|
|
470
|
-
# Rule 6
|
|
471
|
-
# If a state has a record and belongs to the realized path,
|
|
472
|
-
# then the realized path realizes that record-bearing state.
|
|
473
|
-
{ ex:realizedPath ex:hasState ?s .
|
|
474
|
-
?s ex:hasRecord ?r . }
|
|
475
|
-
=>
|
|
476
|
-
{ ex:realizedPath ex:realizes ?s . } .
|
|
477
|
-
|
|
478
|
-
# ----------------------------
|
|
479
|
-
# Human-readable summary nodes
|
|
480
|
-
# ----------------------------
|
|
481
|
-
|
|
482
|
-
ex:summary a rdfs:Resource ;
|
|
483
|
-
rdfs:label "Plain-language summary" ;
|
|
484
|
-
ex:description "The Library contains many coherent alternatives. The Path is one realized sequence through them. Observation happens within the Path and leaves records. Those records narrow which candidate histories remain compatible with what is now observed." .
|
|
485
|
-
|
|
486
|
-
ex:readingGuide a rdfs:Resource ;
|
|
487
|
-
rdfs:label "Where to look first" ;
|
|
488
|
-
ex:description "Start with ex:theLibrary, ex:realizedPath, ex:observer, then read the states s0..s4, then the records rec1..rec4, then the candidate histories." .
|
|
489
|
-
|
|
490
|
-
{
|
|
491
|
-
3 log:includes {
|
|
492
|
-
?s a rdfs:Resource ;
|
|
493
|
-
rdfs:label ?l ;
|
|
494
|
-
ex:description ?d .
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
=>
|
|
498
|
-
{ ?l ex:is ?d . } .
|
|
499
|
-
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
@prefix ex: <https://example.org/library-path#> .
|
|
2
|
-
|
|
3
|
-
ex:s1 ex:hasRecord ex:rec1 .
|
|
4
|
-
ex:s2 ex:hasRecord ex:rec2 .
|
|
5
|
-
ex:s3 ex:hasRecord ex:rec3 .
|
|
6
|
-
ex:s4 ex:hasRecord ex:rec4 .
|
|
7
|
-
ex:s1 ex:observedBy ex:observer .
|
|
8
|
-
ex:s2 ex:observedBy ex:observer .
|
|
9
|
-
ex:s3 ex:observedBy ex:observer .
|
|
10
|
-
ex:s4 ex:observedBy ex:observer .
|
|
11
|
-
ex:historyAlpha ex:supportsConstraint ex:rec1 .
|
|
12
|
-
ex:historyBeta ex:supportsConstraint ex:rec1 .
|
|
13
|
-
ex:historyGamma ex:supportsConstraint ex:rec1 .
|
|
14
|
-
ex:historyDelta ex:supportsConstraint ex:rec1 .
|
|
15
|
-
ex:historyAlpha ex:supportsConstraint ex:rec2 .
|
|
16
|
-
ex:historyGamma ex:supportsConstraint ex:rec2 .
|
|
17
|
-
ex:historyDelta ex:supportsConstraint ex:rec2 .
|
|
18
|
-
ex:historyAlpha ex:supportsConstraint ex:rec3 .
|
|
19
|
-
ex:historyDelta ex:supportsConstraint ex:rec3 .
|
|
20
|
-
ex:historyAlpha ex:supportsConstraint ex:rec4 .
|
|
21
|
-
ex:realizedPath ex:realizes ex:s1 .
|
|
22
|
-
ex:realizedPath ex:realizes ex:s2 .
|
|
23
|
-
ex:realizedPath ex:realizes ex:s3 .
|
|
24
|
-
ex:realizedPath ex:realizes ex:s4 .
|
|
25
|
-
ex:historyBeta ex:incompatibleWith ex:rec2 .
|
|
26
|
-
ex:historyBeta ex:incompatibleWith ex:rec3 .
|
|
27
|
-
ex:historyGamma ex:incompatibleWith ex:rec3 .
|
|
28
|
-
ex:historyBeta ex:incompatibleWith ex:rec4 .
|
|
29
|
-
ex:historyGamma ex:incompatibleWith ex:rec4 .
|
|
30
|
-
ex:historyDelta ex:incompatibleWith ex:rec4 .
|
|
31
|
-
ex:historyAlpha ex:compatibleWith ex:realizedPath .
|
|
32
|
-
"Plain-language summary" ex:is "The Library contains many coherent alternatives. The Path is one realized sequence through them. Observation happens within the Path and leaves records. Those records narrow which candidate histories remain compatible with what is now observed." .
|
|
33
|
-
"Where to look first" ex:is "Start with ex:theLibrary, ex:realizedPath, ex:observer, then read the states s0..s4, then the records rec1..rec4, then the candidate histories." .
|