eyeling 1.6.15 → 1.6.16
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/eyeling.js +164 -287
- package/package.json +1 -1
package/eyeling.js
CHANGED
|
@@ -2041,6 +2041,16 @@ function unifyFormulaTriples(xs, ys, subst) {
|
|
|
2041
2041
|
}
|
|
2042
2042
|
|
|
2043
2043
|
function unifyTerm(a, b, subst) {
|
|
2044
|
+
return unifyTermWithOptions(a, b, subst, { boolValueEq: true, intDecimalEq: false });
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
function unifyTermListAppend(a, b, subst) {
|
|
2048
|
+
// Keep list:append behavior: allow integer<->decimal exact equality,
|
|
2049
|
+
// but do NOT add boolean-value equivalence (preserves current semantics).
|
|
2050
|
+
return unifyTermWithOptions(a, b, subst, { boolValueEq: false, intDecimalEq: true });
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
function unifyTermWithOptions(a, b, subst, opts) {
|
|
2044
2054
|
a = applySubstTerm(a, subst);
|
|
2045
2055
|
b = applySubstTerm(b, subst);
|
|
2046
2056
|
|
|
@@ -2054,9 +2064,8 @@ function unifyTerm(a, b, subst) {
|
|
|
2054
2064
|
s2[v] = t;
|
|
2055
2065
|
return s2;
|
|
2056
2066
|
}
|
|
2057
|
-
|
|
2058
2067
|
if (b instanceof Var) {
|
|
2059
|
-
return
|
|
2068
|
+
return unifyTermWithOptions(b, a, subst, opts);
|
|
2060
2069
|
}
|
|
2061
2070
|
|
|
2062
2071
|
// Exact matches
|
|
@@ -2064,109 +2073,25 @@ function unifyTerm(a, b, subst) {
|
|
|
2064
2073
|
if (a instanceof Literal && b instanceof Literal && a.value === b.value) return { ...subst };
|
|
2065
2074
|
if (a instanceof Blank && b instanceof Blank && a.label === b.label) return { ...subst };
|
|
2066
2075
|
|
|
2067
|
-
//
|
|
2076
|
+
// Plain string vs xsd:string equivalence
|
|
2068
2077
|
if (a instanceof Literal && b instanceof Literal) {
|
|
2069
2078
|
if (literalsEquivalentAsXsdString(a.value, b.value)) return { ...subst };
|
|
2070
2079
|
}
|
|
2071
2080
|
|
|
2072
|
-
// Boolean-value
|
|
2073
|
-
if (a instanceof Literal && b instanceof Literal) {
|
|
2081
|
+
// Boolean-value equivalence (ONLY for normal unifyTerm)
|
|
2082
|
+
if (opts.boolValueEq && a instanceof Literal && b instanceof Literal) {
|
|
2074
2083
|
const ai = parseBooleanLiteralInfo(a);
|
|
2075
2084
|
const bi = parseBooleanLiteralInfo(b);
|
|
2076
2085
|
if (ai && bi && ai.value === bi.value) return { ...subst };
|
|
2077
2086
|
}
|
|
2078
2087
|
|
|
2079
|
-
// Numeric-value match
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
const bi = parseNumericLiteralInfo(b);
|
|
2083
|
-
|
|
2084
|
-
if (ai && bi) {
|
|
2085
|
-
// same datatype: keep existing behavior
|
|
2086
|
-
if (ai.dt === bi.dt) {
|
|
2087
|
-
if (ai.kind === 'bigint' && bi.kind === 'bigint') {
|
|
2088
|
-
if (ai.value === bi.value) return { ...subst };
|
|
2089
|
-
} else {
|
|
2090
|
-
const an = ai.kind === 'bigint' ? Number(ai.value) : ai.value;
|
|
2091
|
-
const bn = bi.kind === 'bigint' ? Number(bi.value) : bi.value;
|
|
2092
|
-
if (!Number.isNaN(an) && !Number.isNaN(bn) && an === bn) return { ...subst };
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
|
|
2098
|
-
// Open list vs concrete list
|
|
2099
|
-
if (a instanceof OpenListTerm && b instanceof ListTerm) {
|
|
2100
|
-
return unifyOpenWithList(a.prefix, a.tailVar, b.elems, subst);
|
|
2101
|
-
}
|
|
2102
|
-
if (a instanceof ListTerm && b instanceof OpenListTerm) {
|
|
2103
|
-
return unifyOpenWithList(b.prefix, b.tailVar, a.elems, subst);
|
|
2104
|
-
}
|
|
2105
|
-
|
|
2106
|
-
// Open list vs open list (same tail var)
|
|
2107
|
-
if (a instanceof OpenListTerm && b instanceof OpenListTerm) {
|
|
2108
|
-
if (a.tailVar !== b.tailVar || a.prefix.length !== b.prefix.length) return null;
|
|
2109
|
-
let s2 = { ...subst };
|
|
2110
|
-
for (let i = 0; i < a.prefix.length; i++) {
|
|
2111
|
-
s2 = unifyTerm(a.prefix[i], b.prefix[i], s2);
|
|
2112
|
-
if (s2 === null) return null;
|
|
2113
|
-
}
|
|
2114
|
-
return s2;
|
|
2115
|
-
}
|
|
2116
|
-
|
|
2117
|
-
// List terms
|
|
2118
|
-
if (a instanceof ListTerm && b instanceof ListTerm) {
|
|
2119
|
-
if (a.elems.length !== b.elems.length) return null;
|
|
2120
|
-
let s2 = { ...subst };
|
|
2121
|
-
for (let i = 0; i < a.elems.length; i++) {
|
|
2122
|
-
s2 = unifyTerm(a.elems[i], b.elems[i], s2);
|
|
2123
|
-
if (s2 === null) return null;
|
|
2124
|
-
}
|
|
2125
|
-
return s2;
|
|
2126
|
-
}
|
|
2127
|
-
|
|
2128
|
-
// Formulas:
|
|
2129
|
-
// 1) If they are alpha-equivalent, succeed without leaking internal bindings.
|
|
2130
|
-
// 2) Otherwise fall back to full unification (may bind vars).
|
|
2131
|
-
if (a instanceof FormulaTerm && b instanceof FormulaTerm) {
|
|
2132
|
-
if (alphaEqFormulaTriples(a.triples, b.triples)) return { ...subst };
|
|
2133
|
-
return unifyFormulaTriples(a.triples, b.triples, subst);
|
|
2134
|
-
}
|
|
2135
|
-
return null;
|
|
2136
|
-
}
|
|
2137
|
-
|
|
2138
|
-
function unifyTermListAppend(a, b, subst) {
|
|
2139
|
-
a = applySubstTerm(a, subst);
|
|
2140
|
-
b = applySubstTerm(b, subst);
|
|
2141
|
-
|
|
2142
|
-
// Variable binding (same as unifyTerm)
|
|
2143
|
-
if (a instanceof Var) {
|
|
2144
|
-
const v = a.name;
|
|
2145
|
-
const t = b;
|
|
2146
|
-
if (t instanceof Var && t.name === v) return { ...subst };
|
|
2147
|
-
if (containsVarTerm(t, v)) return null;
|
|
2148
|
-
const s2 = { ...subst };
|
|
2149
|
-
s2[v] = t;
|
|
2150
|
-
return s2;
|
|
2151
|
-
}
|
|
2152
|
-
if (b instanceof Var) return unifyTermListAppend(b, a, subst);
|
|
2153
|
-
|
|
2154
|
-
// Exact matches
|
|
2155
|
-
if (a instanceof Iri && b instanceof Iri && a.value === b.value) return { ...subst };
|
|
2156
|
-
if (a instanceof Literal && b instanceof Literal && a.value === b.value) return { ...subst };
|
|
2157
|
-
if (a instanceof Blank && b instanceof Blank && a.label === b.label) return { ...subst };
|
|
2158
|
-
|
|
2159
|
-
// Plain string vs xsd:string equivalence
|
|
2160
|
-
if (a instanceof Literal && b instanceof Literal) {
|
|
2161
|
-
if (literalsEquivalentAsXsdString(a.value, b.value)) return { ...subst };
|
|
2162
|
-
}
|
|
2163
|
-
|
|
2164
|
-
// Numeric match: same-dt OR integer<->decimal exact equality (for list:append only)
|
|
2088
|
+
// Numeric-value match:
|
|
2089
|
+
// - always allow equality when datatype matches (existing behavior)
|
|
2090
|
+
// - optionally allow integer<->decimal exact equality (list:append only)
|
|
2165
2091
|
if (a instanceof Literal && b instanceof Literal) {
|
|
2166
2092
|
const ai = parseNumericLiteralInfo(a);
|
|
2167
2093
|
const bi = parseNumericLiteralInfo(b);
|
|
2168
2094
|
if (ai && bi) {
|
|
2169
|
-
// same datatype
|
|
2170
2095
|
if (ai.dt === bi.dt) {
|
|
2171
2096
|
if (ai.kind === 'bigint' && bi.kind === 'bigint') {
|
|
2172
2097
|
if (ai.value === bi.value) return { ...subst };
|
|
@@ -2177,16 +2102,17 @@ function unifyTermListAppend(a, b, subst) {
|
|
|
2177
2102
|
}
|
|
2178
2103
|
}
|
|
2179
2104
|
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2105
|
+
if (opts.intDecimalEq) {
|
|
2106
|
+
const intDt = XSD_NS + 'integer';
|
|
2107
|
+
const decDt = XSD_NS + 'decimal';
|
|
2108
|
+
if ((ai.dt === intDt && bi.dt === decDt) || (ai.dt === decDt && bi.dt === intDt)) {
|
|
2109
|
+
const intInfo = ai.dt === intDt ? ai : bi; // bigint
|
|
2110
|
+
const decInfo = ai.dt === decDt ? ai : bi; // number + lexStr
|
|
2111
|
+
const dec = parseXsdDecimalToBigIntScale(decInfo.lexStr);
|
|
2112
|
+
if (dec) {
|
|
2113
|
+
const scaledInt = intInfo.value * pow10n(dec.scale);
|
|
2114
|
+
if (scaledInt === dec.num) return { ...subst };
|
|
2115
|
+
}
|
|
2190
2116
|
}
|
|
2191
2117
|
}
|
|
2192
2118
|
}
|
|
@@ -2205,7 +2131,7 @@ function unifyTermListAppend(a, b, subst) {
|
|
|
2205
2131
|
if (a.tailVar !== b.tailVar || a.prefix.length !== b.prefix.length) return null;
|
|
2206
2132
|
let s2 = { ...subst };
|
|
2207
2133
|
for (let i = 0; i < a.prefix.length; i++) {
|
|
2208
|
-
s2 =
|
|
2134
|
+
s2 = unifyTermWithOptions(a.prefix[i], b.prefix[i], s2, opts);
|
|
2209
2135
|
if (s2 === null) return null;
|
|
2210
2136
|
}
|
|
2211
2137
|
return s2;
|
|
@@ -2216,7 +2142,7 @@ function unifyTermListAppend(a, b, subst) {
|
|
|
2216
2142
|
if (a.elems.length !== b.elems.length) return null;
|
|
2217
2143
|
let s2 = { ...subst };
|
|
2218
2144
|
for (let i = 0; i < a.elems.length; i++) {
|
|
2219
|
-
s2 =
|
|
2145
|
+
s2 = unifyTermWithOptions(a.elems[i], b.elems[i], s2, opts);
|
|
2220
2146
|
if (s2 === null) return null;
|
|
2221
2147
|
}
|
|
2222
2148
|
return s2;
|
|
@@ -2886,14 +2812,7 @@ function parseNumOrDuration(t) {
|
|
|
2886
2812
|
|
|
2887
2813
|
function formatDurationLiteralFromSeconds(secs) {
|
|
2888
2814
|
const neg = secs < 0;
|
|
2889
|
-
const
|
|
2890
|
-
const days = Math.round(absSecs / 86400.0);
|
|
2891
|
-
const lex = neg ? `" -P${days}D"` : `"P${days}D"`;
|
|
2892
|
-
const cleanLex = neg ? `" -P${days}D"` : `"P${days}D"`; // minor detail; we just follow shape
|
|
2893
|
-
const lex2 = neg ? `" -P${days}D"` : `"P${days}D"`;
|
|
2894
|
-
const actualLex = neg ? `" -P${days}D"` : `"P${days}D"`;
|
|
2895
|
-
// keep simpler, no spaces:
|
|
2896
|
-
const finalLex = neg ? `" -P${days}D"` : `"P${days}D"`;
|
|
2815
|
+
const days = Math.round(Math.abs(secs) / 86400.0);
|
|
2897
2816
|
const literalLex = neg ? `"-P${days}D"` : `"P${days}D"`;
|
|
2898
2817
|
return new Literal(`${literalLex}^^<${XSD_NS}duration>`);
|
|
2899
2818
|
}
|
|
@@ -3091,6 +3010,38 @@ function evalUnaryMathRel(g, subst, forwardFn, inverseFn /* may be null */) {
|
|
|
3091
3010
|
return [];
|
|
3092
3011
|
}
|
|
3093
3012
|
|
|
3013
|
+
function evalListFirstLikeBuiltin(sTerm, oTerm, subst) {
|
|
3014
|
+
if (!(sTerm instanceof ListTerm)) return [];
|
|
3015
|
+
if (!sTerm.elems.length) return [];
|
|
3016
|
+
const first = sTerm.elems[0];
|
|
3017
|
+
const s2 = unifyTerm(oTerm, first, subst);
|
|
3018
|
+
return s2 !== null ? [s2] : [];
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
function evalListRestLikeBuiltin(sTerm, oTerm, subst) {
|
|
3022
|
+
// Closed list: (a b c) -> (b c)
|
|
3023
|
+
if (sTerm instanceof ListTerm) {
|
|
3024
|
+
if (!sTerm.elems.length) return [];
|
|
3025
|
+
const rest = new ListTerm(sTerm.elems.slice(1));
|
|
3026
|
+
const s2 = unifyTerm(oTerm, rest, subst);
|
|
3027
|
+
return s2 !== null ? [s2] : [];
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
// Open list: (a b ... ?T) -> (b ... ?T)
|
|
3031
|
+
if (sTerm instanceof OpenListTerm) {
|
|
3032
|
+
if (!sTerm.prefix.length) return [];
|
|
3033
|
+
if (sTerm.prefix.length === 1) {
|
|
3034
|
+
const s2 = unifyTerm(oTerm, new Var(sTerm.tailVar), subst);
|
|
3035
|
+
return s2 !== null ? [s2] : [];
|
|
3036
|
+
}
|
|
3037
|
+
const rest = new OpenListTerm(sTerm.prefix.slice(1), sTerm.tailVar);
|
|
3038
|
+
const s2 = unifyTerm(oTerm, rest, subst);
|
|
3039
|
+
return s2 !== null ? [s2] : [];
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
return [];
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3094
3045
|
// ============================================================================
|
|
3095
3046
|
// Backward proof & builtins mutual recursion — declarations first
|
|
3096
3047
|
// ============================================================================
|
|
@@ -3785,79 +3736,18 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen) {
|
|
|
3785
3736
|
return [];
|
|
3786
3737
|
}
|
|
3787
3738
|
|
|
3788
|
-
// list:first
|
|
3739
|
+
// list:first and rdf:first
|
|
3789
3740
|
// true iff $s is a list and $o is the first member of that list.
|
|
3790
3741
|
// Schema: $s+ list:first $o-
|
|
3791
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS + 'first') {
|
|
3792
|
-
|
|
3793
|
-
if (!g.s.elems.length) return [];
|
|
3794
|
-
const first = g.s.elems[0];
|
|
3795
|
-
const s2 = unifyTerm(g.o, first, subst);
|
|
3796
|
-
return s2 !== null ? [s2] : [];
|
|
3742
|
+
if (g.p instanceof Iri && (g.p.value === LIST_NS + 'first' || g.p.value === RDF_NS + 'first')) {
|
|
3743
|
+
return evalListFirstLikeBuiltin(g.s, g.o, subst);
|
|
3797
3744
|
}
|
|
3798
3745
|
|
|
3799
|
-
// list:rest
|
|
3746
|
+
// list:rest and rdf:rest
|
|
3800
3747
|
// true iff $s is a (non-empty) list and $o is the rest (tail) of that list.
|
|
3801
3748
|
// Schema: $s+ list:rest $o-
|
|
3802
|
-
if (g.p instanceof Iri && g.p.value === LIST_NS + 'rest') {
|
|
3803
|
-
|
|
3804
|
-
if (g.s instanceof ListTerm) {
|
|
3805
|
-
if (!g.s.elems.length) return [];
|
|
3806
|
-
const rest = new ListTerm(g.s.elems.slice(1));
|
|
3807
|
-
const s2 = unifyTerm(g.o, rest, subst);
|
|
3808
|
-
return s2 !== null ? [s2] : [];
|
|
3809
|
-
}
|
|
3810
|
-
|
|
3811
|
-
// Open list: (a b ... ?T) -> (b ... ?T)
|
|
3812
|
-
if (g.s instanceof OpenListTerm) {
|
|
3813
|
-
if (!g.s.prefix.length) return []; // can't compute rest without a known head
|
|
3814
|
-
|
|
3815
|
-
if (g.s.prefix.length === 1) {
|
|
3816
|
-
// (a ... ?T) rest is exactly ?T
|
|
3817
|
-
const s2 = unifyTerm(g.o, new Var(g.s.tailVar), subst);
|
|
3818
|
-
return s2 !== null ? [s2] : [];
|
|
3819
|
-
}
|
|
3820
|
-
|
|
3821
|
-
const rest = new OpenListTerm(g.s.prefix.slice(1), g.s.tailVar);
|
|
3822
|
-
const s2 = unifyTerm(g.o, rest, subst);
|
|
3823
|
-
return s2 !== null ? [s2] : [];
|
|
3824
|
-
}
|
|
3825
|
-
|
|
3826
|
-
return [];
|
|
3827
|
-
}
|
|
3828
|
-
|
|
3829
|
-
// rdf:first (alias of list:first)
|
|
3830
|
-
// Schema: $s+ rdf:first $o-
|
|
3831
|
-
if (g.p instanceof Iri && g.p.value === RDF_NS + 'first') {
|
|
3832
|
-
if (!(g.s instanceof ListTerm)) return [];
|
|
3833
|
-
if (!g.s.elems.length) return [];
|
|
3834
|
-
const first = g.s.elems[0];
|
|
3835
|
-
const s2 = unifyTerm(g.o, first, subst);
|
|
3836
|
-
return s2 !== null ? [s2] : [];
|
|
3837
|
-
}
|
|
3838
|
-
|
|
3839
|
-
// rdf:rest (alias of list:rest)
|
|
3840
|
-
// Schema: $s+ rdf:rest $o-
|
|
3841
|
-
if (g.p instanceof Iri && g.p.value === RDF_NS + 'rest') {
|
|
3842
|
-
// Closed list: (a b c) -> (b c)
|
|
3843
|
-
if (g.s instanceof ListTerm) {
|
|
3844
|
-
if (!g.s.elems.length) return [];
|
|
3845
|
-
const rest = new ListTerm(g.s.elems.slice(1));
|
|
3846
|
-
const s2 = unifyTerm(g.o, rest, subst);
|
|
3847
|
-
return s2 !== null ? [s2] : [];
|
|
3848
|
-
}
|
|
3849
|
-
// Open list: (a b ... ?T) -> (b ... ?T)
|
|
3850
|
-
if (g.s instanceof OpenListTerm) {
|
|
3851
|
-
if (!g.s.prefix.length) return [];
|
|
3852
|
-
if (g.s.prefix.length === 1) {
|
|
3853
|
-
const s2 = unifyTerm(g.o, new Var(g.s.tailVar), subst);
|
|
3854
|
-
return s2 !== null ? [s2] : [];
|
|
3855
|
-
}
|
|
3856
|
-
const rest = new OpenListTerm(g.s.prefix.slice(1), g.s.tailVar);
|
|
3857
|
-
const s2 = unifyTerm(g.o, rest, subst);
|
|
3858
|
-
return s2 !== null ? [s2] : [];
|
|
3859
|
-
}
|
|
3860
|
-
return [];
|
|
3749
|
+
if (g.p instanceof Iri && (g.p.value === LIST_NS + 'rest' || g.p.value === RDF_NS + 'rest')) {
|
|
3750
|
+
return evalListRestLikeBuiltin(g.s, g.o, subst);
|
|
3861
3751
|
}
|
|
3862
3752
|
|
|
3863
3753
|
// list:iterate
|
|
@@ -5065,134 +4955,121 @@ function forwardChain(facts, forwardRules, backRules) {
|
|
|
5065
4955
|
|
|
5066
4956
|
function runFixpoint() {
|
|
5067
4957
|
let anyChange = false;
|
|
4958
|
+
|
|
5068
4959
|
while (true) {
|
|
5069
4960
|
let changed = false;
|
|
5070
4961
|
|
|
5071
|
-
|
|
5072
|
-
|
|
4962
|
+
for (let i = 0; i < forwardRules.length; i++) {
|
|
4963
|
+
const r = forwardRules[i];
|
|
4964
|
+
const empty = {};
|
|
4965
|
+
const visited = [];
|
|
4966
|
+
const sols = proveGoals(r.premise.slice(), empty, facts, backRules, 0, visited, varGen);
|
|
5073
4967
|
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
const sols = proveGoals(r.premise.slice(), empty, facts, backRules, 0, visited, varGen);
|
|
4968
|
+
// Inference fuse
|
|
4969
|
+
if (r.isFuse && sols.length) {
|
|
4970
|
+
console.log('# Inference fuse triggered: a { ... } => false. rule fired.');
|
|
4971
|
+
process.exit(2);
|
|
4972
|
+
}
|
|
5080
4973
|
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
4974
|
+
for (const s of sols) {
|
|
4975
|
+
// IMPORTANT: one skolem map per *rule firing*
|
|
4976
|
+
const skMap = {};
|
|
4977
|
+
const instantiatedPremises = r.premise.map((b) => applySubstTriple(b, s));
|
|
4978
|
+
const fireKey = firingKey(i, instantiatedPremises);
|
|
4979
|
+
|
|
4980
|
+
for (const cpat of r.conclusion) {
|
|
4981
|
+
const instantiated = applySubstTriple(cpat, s);
|
|
4982
|
+
|
|
4983
|
+
const isFwRuleTriple =
|
|
4984
|
+
isLogImplies(instantiated.p) &&
|
|
4985
|
+
((instantiated.s instanceof FormulaTerm && instantiated.o instanceof FormulaTerm) ||
|
|
4986
|
+
(instantiated.s instanceof Literal && instantiated.s.value === 'true' && instantiated.o instanceof FormulaTerm) ||
|
|
4987
|
+
(instantiated.s instanceof FormulaTerm && instantiated.o instanceof Literal && instantiated.o.value === 'true'));
|
|
4988
|
+
|
|
4989
|
+
const isBwRuleTriple =
|
|
4990
|
+
isLogImpliedBy(instantiated.p) &&
|
|
4991
|
+
((instantiated.s instanceof FormulaTerm && instantiated.o instanceof FormulaTerm) ||
|
|
4992
|
+
(instantiated.s instanceof FormulaTerm && instantiated.o instanceof Literal && instantiated.o.value === 'true') ||
|
|
4993
|
+
(instantiated.s instanceof Literal && instantiated.s.value === 'true' && instantiated.o instanceof FormulaTerm));
|
|
4994
|
+
|
|
4995
|
+
if (isFwRuleTriple || isBwRuleTriple) {
|
|
4996
|
+
if (!hasFactIndexed(facts, instantiated)) {
|
|
4997
|
+
factList.push(instantiated);
|
|
4998
|
+
pushFactIndexed(facts, instantiated);
|
|
4999
|
+
derivedForward.push(new DerivedFact(instantiated, r, instantiatedPremises.slice(), { ...s }));
|
|
5000
|
+
changed = true;
|
|
5001
|
+
}
|
|
5086
5002
|
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
const
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
...s,
|
|
5116
|
-
}),
|
|
5003
|
+
// Promote rule-producing triples to live rules, treating literal true as {}.
|
|
5004
|
+
const left =
|
|
5005
|
+
instantiated.s instanceof FormulaTerm
|
|
5006
|
+
? instantiated.s.triples
|
|
5007
|
+
: instantiated.s instanceof Literal && instantiated.s.value === 'true'
|
|
5008
|
+
? []
|
|
5009
|
+
: null;
|
|
5010
|
+
|
|
5011
|
+
const right =
|
|
5012
|
+
instantiated.o instanceof FormulaTerm
|
|
5013
|
+
? instantiated.o.triples
|
|
5014
|
+
: instantiated.o instanceof Literal && instantiated.o.value === 'true'
|
|
5015
|
+
? []
|
|
5016
|
+
: null;
|
|
5017
|
+
|
|
5018
|
+
if (left !== null && right !== null) {
|
|
5019
|
+
if (isFwRuleTriple) {
|
|
5020
|
+
const [premise0, conclusion] = liftBlankRuleVars(left, right);
|
|
5021
|
+
const premise = reorderPremiseForConstraints(premise0);
|
|
5022
|
+
const headBlankLabels = collectBlankLabelsInTriples(conclusion);
|
|
5023
|
+
const newRule = new Rule(premise, conclusion, true, false, headBlankLabels);
|
|
5024
|
+
|
|
5025
|
+
const already = forwardRules.some(
|
|
5026
|
+
(rr) =>
|
|
5027
|
+
rr.isForward === newRule.isForward &&
|
|
5028
|
+
rr.isFuse === newRule.isFuse &&
|
|
5029
|
+
triplesListEqual(rr.premise, newRule.premise) &&
|
|
5030
|
+
triplesListEqual(rr.conclusion, newRule.conclusion),
|
|
5117
5031
|
);
|
|
5118
|
-
|
|
5119
|
-
}
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
: null;
|
|
5135
|
-
|
|
5136
|
-
if (left !== null && right !== null) {
|
|
5137
|
-
if (isFwRuleTriple) {
|
|
5138
|
-
const [premise0, conclusion] = liftBlankRuleVars(left, right);
|
|
5139
|
-
const premise = reorderPremiseForConstraints(premise0);
|
|
5140
|
-
|
|
5141
|
-
const headBlankLabels = collectBlankLabelsInTriples(conclusion);
|
|
5142
|
-
const newRule = new Rule(premise, conclusion, true, false, headBlankLabels);
|
|
5143
|
-
|
|
5144
|
-
const already = forwardRules.some(
|
|
5145
|
-
(rr) =>
|
|
5146
|
-
rr.isForward === newRule.isForward &&
|
|
5147
|
-
rr.isFuse === newRule.isFuse &&
|
|
5148
|
-
triplesListEqual(rr.premise, newRule.premise) &&
|
|
5149
|
-
triplesListEqual(rr.conclusion, newRule.conclusion),
|
|
5150
|
-
);
|
|
5151
|
-
if (!already) forwardRules.push(newRule);
|
|
5152
|
-
} else if (isBwRuleTriple) {
|
|
5153
|
-
const [premise, conclusion] = liftBlankRuleVars(right, left);
|
|
5154
|
-
|
|
5155
|
-
const headBlankLabels = collectBlankLabelsInTriples(conclusion);
|
|
5156
|
-
const newRule = new Rule(premise, conclusion, false, false, headBlankLabels);
|
|
5157
|
-
|
|
5158
|
-
const already = backRules.some(
|
|
5159
|
-
(rr) =>
|
|
5160
|
-
rr.isForward === newRule.isForward &&
|
|
5161
|
-
rr.isFuse === newRule.isFuse &&
|
|
5162
|
-
triplesListEqual(rr.premise, newRule.premise) &&
|
|
5163
|
-
triplesListEqual(rr.conclusion, newRule.conclusion),
|
|
5164
|
-
);
|
|
5165
|
-
if (!already) {
|
|
5166
|
-
backRules.push(newRule);
|
|
5167
|
-
indexBackRule(backRules, newRule);
|
|
5168
|
-
}
|
|
5032
|
+
if (!already) forwardRules.push(newRule);
|
|
5033
|
+
} else if (isBwRuleTriple) {
|
|
5034
|
+
const [premise, conclusion] = liftBlankRuleVars(right, left);
|
|
5035
|
+
const headBlankLabels = collectBlankLabelsInTriples(conclusion);
|
|
5036
|
+
const newRule = new Rule(premise, conclusion, false, false, headBlankLabels);
|
|
5037
|
+
|
|
5038
|
+
const already = backRules.some(
|
|
5039
|
+
(rr) =>
|
|
5040
|
+
rr.isForward === newRule.isForward &&
|
|
5041
|
+
rr.isFuse === newRule.isFuse &&
|
|
5042
|
+
triplesListEqual(rr.premise, newRule.premise) &&
|
|
5043
|
+
triplesListEqual(rr.conclusion, newRule.conclusion),
|
|
5044
|
+
);
|
|
5045
|
+
if (!already) {
|
|
5046
|
+
backRules.push(newRule);
|
|
5047
|
+
indexBackRule(backRules, newRule);
|
|
5169
5048
|
}
|
|
5170
5049
|
}
|
|
5171
|
-
|
|
5172
|
-
continue; // skip normal fact handling
|
|
5173
5050
|
}
|
|
5174
5051
|
|
|
5175
|
-
//
|
|
5176
|
-
|
|
5052
|
+
continue; // skip normal fact handling
|
|
5053
|
+
}
|
|
5177
5054
|
|
|
5178
|
-
|
|
5179
|
-
|
|
5055
|
+
// Only skolemize blank nodes that occur explicitly in the rule head
|
|
5056
|
+
const inst = skolemizeTripleForHeadBlanks(instantiated, r.headBlankLabels, skMap, skCounter, fireKey, headSkolemCache);
|
|
5180
5057
|
|
|
5181
|
-
|
|
5182
|
-
|
|
5058
|
+
if (!isGroundTriple(inst)) continue;
|
|
5059
|
+
if (hasFactIndexed(facts, inst)) continue;
|
|
5183
5060
|
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
}
|
|
5061
|
+
factList.push(inst);
|
|
5062
|
+
pushFactIndexed(facts, inst);
|
|
5063
|
+
derivedForward.push(new DerivedFact(inst, r, instantiatedPremises.slice(), { ...s }));
|
|
5064
|
+
changed = true;
|
|
5187
5065
|
}
|
|
5188
5066
|
}
|
|
5189
|
-
|
|
5190
|
-
if (!changed) break;
|
|
5191
5067
|
}
|
|
5192
5068
|
|
|
5193
|
-
if (changed) anyChange = true;
|
|
5194
5069
|
if (!changed) break;
|
|
5070
|
+
anyChange = true;
|
|
5195
5071
|
}
|
|
5072
|
+
|
|
5196
5073
|
return anyChange;
|
|
5197
5074
|
}
|
|
5198
5075
|
|