@nahisaho/musubix-ontology-mcp 1.0.0
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/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/inference/index.d.ts +6 -0
- package/dist/inference/index.d.ts.map +1 -0
- package/dist/inference/index.js +6 -0
- package/dist/inference/index.js.map +1 -0
- package/dist/inference/rule-engine.d.ts +149 -0
- package/dist/inference/rule-engine.d.ts.map +1 -0
- package/dist/inference/rule-engine.js +478 -0
- package/dist/inference/rule-engine.js.map +1 -0
- package/dist/integration/index.d.ts +6 -0
- package/dist/integration/index.d.ts.map +1 -0
- package/dist/integration/index.js +6 -0
- package/dist/integration/index.js.map +1 -0
- package/dist/integration/pattern-bridge.d.ts +146 -0
- package/dist/integration/pattern-bridge.d.ts.map +1 -0
- package/dist/integration/pattern-bridge.js +517 -0
- package/dist/integration/pattern-bridge.js.map +1 -0
- package/dist/privacy/index.d.ts +6 -0
- package/dist/privacy/index.d.ts.map +1 -0
- package/dist/privacy/index.js +6 -0
- package/dist/privacy/index.js.map +1 -0
- package/dist/privacy/privacy-guard.d.ts +43 -0
- package/dist/privacy/privacy-guard.d.ts.map +1 -0
- package/dist/privacy/privacy-guard.js +59 -0
- package/dist/privacy/privacy-guard.js.map +1 -0
- package/dist/store/index.d.ts +7 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +7 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/n3-store.d.ts +115 -0
- package/dist/store/n3-store.d.ts.map +1 -0
- package/dist/store/n3-store.js +344 -0
- package/dist/store/n3-store.js.map +1 -0
- package/dist/store/ontology-store.d.ts +59 -0
- package/dist/store/ontology-store.d.ts.map +1 -0
- package/dist/store/ontology-store.js +135 -0
- package/dist/store/ontology-store.js.map +1 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MUSUBIX Ontology Reasoning MCP
|
|
3
|
+
* @module @nahisaho/musubix-ontology-mcp
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
* @traceability REQ-ONTO-001
|
|
6
|
+
*/
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
export * from './store/index.js';
|
|
9
|
+
export * from './privacy/index.js';
|
|
10
|
+
export * from './inference/index.js';
|
|
11
|
+
export * from './integration/index.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,YAAY,CAAC;AAG3B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MUSUBIX Ontology Reasoning MCP
|
|
3
|
+
* @module @nahisaho/musubix-ontology-mcp
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
* @traceability REQ-ONTO-001
|
|
6
|
+
*/
|
|
7
|
+
// Types
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
// Ontology Store (TSK-ONTO-001)
|
|
10
|
+
export * from './store/index.js';
|
|
11
|
+
// Privacy Protection (TSK-ONTO-008)
|
|
12
|
+
export * from './privacy/index.js';
|
|
13
|
+
// Inference Engine (TSK-ONTO-002)
|
|
14
|
+
export * from './inference/index.js';
|
|
15
|
+
// Pattern Integration (TSK-INT-001)
|
|
16
|
+
export * from './integration/index.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,gCAAgC;AAChC,cAAc,kBAAkB,CAAC;AAEjC,oCAAoC;AACpC,cAAc,oBAAoB,CAAC;AAEnC,kCAAkC;AAClC,cAAc,sBAAsB,CAAC;AAErC,oCAAoC;AACpC,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Inference module exports
|
|
3
|
+
* @traceability TSK-ONTO-002
|
|
4
|
+
*/
|
|
5
|
+
export { RuleEngine, type InferenceRuleDefinition, type RuleCondition, type RuleAction, type Bindings, type RuleMatch, type InferenceStats, } from './rule-engine.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inference/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,UAAU,EACV,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/inference/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,UAAU,GAOX,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Inference Rule Engine for Ontology Store
|
|
3
|
+
* @traceability TSK-ONTO-002, REQ-ONTO-001
|
|
4
|
+
*/
|
|
5
|
+
import type { Triple } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Rule condition types
|
|
8
|
+
*/
|
|
9
|
+
export type RuleCondition = {
|
|
10
|
+
type: 'triple-pattern';
|
|
11
|
+
subject?: string | {
|
|
12
|
+
variable: string;
|
|
13
|
+
};
|
|
14
|
+
predicate?: string | {
|
|
15
|
+
variable: string;
|
|
16
|
+
};
|
|
17
|
+
object?: string | {
|
|
18
|
+
variable: string;
|
|
19
|
+
};
|
|
20
|
+
} | {
|
|
21
|
+
type: 'transitive';
|
|
22
|
+
predicate: string;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'symmetric';
|
|
25
|
+
predicate: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'inverse';
|
|
28
|
+
predicate1: string;
|
|
29
|
+
predicate2: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Rule action types
|
|
33
|
+
*/
|
|
34
|
+
export type RuleAction = {
|
|
35
|
+
type: 'add-triple';
|
|
36
|
+
subject: string | {
|
|
37
|
+
variable: string;
|
|
38
|
+
};
|
|
39
|
+
predicate: string;
|
|
40
|
+
object: string | {
|
|
41
|
+
variable: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Inference rule definition
|
|
46
|
+
*/
|
|
47
|
+
export interface InferenceRuleDefinition {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
priority: number;
|
|
52
|
+
conditions: RuleCondition[];
|
|
53
|
+
actions: RuleAction[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Binding map for variables
|
|
57
|
+
*/
|
|
58
|
+
export type Bindings = Record<string, string>;
|
|
59
|
+
/**
|
|
60
|
+
* Rule match result
|
|
61
|
+
*/
|
|
62
|
+
export interface RuleMatch {
|
|
63
|
+
ruleId: string;
|
|
64
|
+
bindings: Bindings;
|
|
65
|
+
inferredTriples: Triple[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Inference statistics
|
|
69
|
+
*/
|
|
70
|
+
export interface InferenceStats {
|
|
71
|
+
rulesApplied: number;
|
|
72
|
+
triplesInferred: number;
|
|
73
|
+
iterationsUsed: number;
|
|
74
|
+
timeMs: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Rule Engine for applying inference rules
|
|
78
|
+
*/
|
|
79
|
+
export declare class RuleEngine {
|
|
80
|
+
private rules;
|
|
81
|
+
private maxIterations;
|
|
82
|
+
constructor(options?: {
|
|
83
|
+
maxIterations?: number;
|
|
84
|
+
});
|
|
85
|
+
/**
|
|
86
|
+
* Load built-in RDFS/OWL inference rules
|
|
87
|
+
*/
|
|
88
|
+
private loadBuiltinRules;
|
|
89
|
+
/**
|
|
90
|
+
* Add a rule to the engine
|
|
91
|
+
*/
|
|
92
|
+
addRule(rule: InferenceRuleDefinition): void;
|
|
93
|
+
/**
|
|
94
|
+
* Remove a rule
|
|
95
|
+
*/
|
|
96
|
+
removeRule(ruleId: string): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Get all rules
|
|
99
|
+
*/
|
|
100
|
+
getRules(): InferenceRuleDefinition[];
|
|
101
|
+
/**
|
|
102
|
+
* Apply all rules to triples until fixpoint
|
|
103
|
+
*/
|
|
104
|
+
applyRules(triples: Triple[]): {
|
|
105
|
+
triples: Triple[];
|
|
106
|
+
stats: InferenceStats;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Apply transitive closure for a predicate
|
|
110
|
+
*/
|
|
111
|
+
private applyTransitiveClosure;
|
|
112
|
+
/**
|
|
113
|
+
* Apply symmetry for a predicate
|
|
114
|
+
*/
|
|
115
|
+
private applySymmetry;
|
|
116
|
+
/**
|
|
117
|
+
* Apply inverse property rule
|
|
118
|
+
*/
|
|
119
|
+
private applyInverse;
|
|
120
|
+
/**
|
|
121
|
+
* Get symmetric properties from triples
|
|
122
|
+
*/
|
|
123
|
+
private getSymmetricProperties;
|
|
124
|
+
/**
|
|
125
|
+
* Get inverse property pairs from triples
|
|
126
|
+
*/
|
|
127
|
+
private getInverseProperties;
|
|
128
|
+
/**
|
|
129
|
+
* Match a rule against triples
|
|
130
|
+
*/
|
|
131
|
+
private matchRule;
|
|
132
|
+
/**
|
|
133
|
+
* Match a pattern against a triple
|
|
134
|
+
*/
|
|
135
|
+
private matchPattern;
|
|
136
|
+
/**
|
|
137
|
+
* Check if two binding sets are compatible
|
|
138
|
+
*/
|
|
139
|
+
private compatibleBindings;
|
|
140
|
+
/**
|
|
141
|
+
* Apply actions with bindings
|
|
142
|
+
*/
|
|
143
|
+
private applyActions;
|
|
144
|
+
/**
|
|
145
|
+
* Create unique key for triple
|
|
146
|
+
*/
|
|
147
|
+
private tripleKey;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=rule-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-engine.d.ts","sourceRoot":"","sources":["../../src/inference/rule-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Inference Rule Engine for Ontology Store
|
|
3
|
+
* @traceability TSK-ONTO-002, REQ-ONTO-001
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* RDFS namespace constants
|
|
7
|
+
*/
|
|
8
|
+
const RDFS = {
|
|
9
|
+
subClassOf: 'http://www.w3.org/2000/01/rdf-schema#subClassOf',
|
|
10
|
+
subPropertyOf: 'http://www.w3.org/2000/01/rdf-schema#subPropertyOf',
|
|
11
|
+
domain: 'http://www.w3.org/2000/01/rdf-schema#domain',
|
|
12
|
+
range: 'http://www.w3.org/2000/01/rdf-schema#range',
|
|
13
|
+
};
|
|
14
|
+
const RDF = {
|
|
15
|
+
type: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
|
|
16
|
+
};
|
|
17
|
+
const OWL = {
|
|
18
|
+
TransitiveProperty: 'http://www.w3.org/2002/07/owl#TransitiveProperty',
|
|
19
|
+
SymmetricProperty: 'http://www.w3.org/2002/07/owl#SymmetricProperty',
|
|
20
|
+
InverseFunctionalProperty: 'http://www.w3.org/2002/07/owl#InverseFunctionalProperty',
|
|
21
|
+
inverseOf: 'http://www.w3.org/2002/07/owl#inverseOf',
|
|
22
|
+
sameAs: 'http://www.w3.org/2002/07/owl#sameAs',
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Rule Engine for applying inference rules
|
|
26
|
+
*/
|
|
27
|
+
export class RuleEngine {
|
|
28
|
+
rules = new Map();
|
|
29
|
+
maxIterations;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.maxIterations = options?.maxIterations ?? 10;
|
|
32
|
+
this.loadBuiltinRules();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Load built-in RDFS/OWL inference rules
|
|
36
|
+
*/
|
|
37
|
+
loadBuiltinRules() {
|
|
38
|
+
// RDFS9: subClassOf transitivity
|
|
39
|
+
this.addRule({
|
|
40
|
+
id: 'rdfs9',
|
|
41
|
+
name: 'RDFS SubClass Transitivity',
|
|
42
|
+
description: 'If X subClassOf Y and Y subClassOf Z, then X subClassOf Z',
|
|
43
|
+
priority: 100,
|
|
44
|
+
conditions: [
|
|
45
|
+
{ type: 'transitive', predicate: RDFS.subClassOf },
|
|
46
|
+
],
|
|
47
|
+
actions: [],
|
|
48
|
+
});
|
|
49
|
+
// RDFS7: subPropertyOf transitivity
|
|
50
|
+
this.addRule({
|
|
51
|
+
id: 'rdfs7',
|
|
52
|
+
name: 'RDFS SubProperty Transitivity',
|
|
53
|
+
description: 'If P subPropertyOf Q and Q subPropertyOf R, then P subPropertyOf R',
|
|
54
|
+
priority: 100,
|
|
55
|
+
conditions: [
|
|
56
|
+
{ type: 'transitive', predicate: RDFS.subPropertyOf },
|
|
57
|
+
],
|
|
58
|
+
actions: [],
|
|
59
|
+
});
|
|
60
|
+
// RDFS11: type inheritance through subClassOf
|
|
61
|
+
this.addRule({
|
|
62
|
+
id: 'rdfs11',
|
|
63
|
+
name: 'RDFS Type Inheritance',
|
|
64
|
+
description: 'If X type C and C subClassOf D, then X type D',
|
|
65
|
+
priority: 90,
|
|
66
|
+
conditions: [
|
|
67
|
+
{
|
|
68
|
+
type: 'triple-pattern',
|
|
69
|
+
subject: { variable: 'x' },
|
|
70
|
+
predicate: RDF.type,
|
|
71
|
+
object: { variable: 'c' },
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: 'triple-pattern',
|
|
75
|
+
subject: { variable: 'c' },
|
|
76
|
+
predicate: RDFS.subClassOf,
|
|
77
|
+
object: { variable: 'd' },
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
actions: [
|
|
81
|
+
{
|
|
82
|
+
type: 'add-triple',
|
|
83
|
+
subject: { variable: 'x' },
|
|
84
|
+
predicate: RDF.type,
|
|
85
|
+
object: { variable: 'd' },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
// OWL symmetric property
|
|
90
|
+
this.addRule({
|
|
91
|
+
id: 'owl-symmetric',
|
|
92
|
+
name: 'OWL Symmetric Property',
|
|
93
|
+
description: 'If P is symmetric and X P Y, then Y P X',
|
|
94
|
+
priority: 80,
|
|
95
|
+
conditions: [
|
|
96
|
+
{ type: 'symmetric', predicate: '' }, // Placeholder, matched dynamically
|
|
97
|
+
],
|
|
98
|
+
actions: [],
|
|
99
|
+
});
|
|
100
|
+
// OWL inverse property
|
|
101
|
+
this.addRule({
|
|
102
|
+
id: 'owl-inverse',
|
|
103
|
+
name: 'OWL Inverse Property',
|
|
104
|
+
description: 'If P inverseOf Q and X P Y, then Y Q X',
|
|
105
|
+
priority: 80,
|
|
106
|
+
conditions: [
|
|
107
|
+
{ type: 'inverse', predicate1: '', predicate2: '' },
|
|
108
|
+
],
|
|
109
|
+
actions: [],
|
|
110
|
+
});
|
|
111
|
+
// OWL sameAs transitivity
|
|
112
|
+
this.addRule({
|
|
113
|
+
id: 'owl-sameas-trans',
|
|
114
|
+
name: 'OWL SameAs Transitivity',
|
|
115
|
+
description: 'If X sameAs Y and Y sameAs Z, then X sameAs Z',
|
|
116
|
+
priority: 70,
|
|
117
|
+
conditions: [
|
|
118
|
+
{ type: 'transitive', predicate: OWL.sameAs },
|
|
119
|
+
],
|
|
120
|
+
actions: [],
|
|
121
|
+
});
|
|
122
|
+
// OWL sameAs symmetry
|
|
123
|
+
this.addRule({
|
|
124
|
+
id: 'owl-sameas-sym',
|
|
125
|
+
name: 'OWL SameAs Symmetry',
|
|
126
|
+
description: 'If X sameAs Y, then Y sameAs X',
|
|
127
|
+
priority: 70,
|
|
128
|
+
conditions: [
|
|
129
|
+
{ type: 'symmetric', predicate: OWL.sameAs },
|
|
130
|
+
],
|
|
131
|
+
actions: [],
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Add a rule to the engine
|
|
136
|
+
*/
|
|
137
|
+
addRule(rule) {
|
|
138
|
+
this.rules.set(rule.id, rule);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Remove a rule
|
|
142
|
+
*/
|
|
143
|
+
removeRule(ruleId) {
|
|
144
|
+
return this.rules.delete(ruleId);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get all rules
|
|
148
|
+
*/
|
|
149
|
+
getRules() {
|
|
150
|
+
return Array.from(this.rules.values())
|
|
151
|
+
.sort((a, b) => b.priority - a.priority);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Apply all rules to triples until fixpoint
|
|
155
|
+
*/
|
|
156
|
+
applyRules(triples) {
|
|
157
|
+
const startTime = Date.now();
|
|
158
|
+
const tripleSet = new Set(triples.map(t => this.tripleKey(t)));
|
|
159
|
+
const allTriples = [...triples];
|
|
160
|
+
let rulesApplied = 0;
|
|
161
|
+
let triplesInferred = 0;
|
|
162
|
+
// Get symmetric and inverse properties
|
|
163
|
+
const symmetricProps = this.getSymmetricProperties(allTriples);
|
|
164
|
+
const inverseProps = this.getInverseProperties(allTriples);
|
|
165
|
+
for (let iteration = 0; iteration < this.maxIterations; iteration++) {
|
|
166
|
+
const newTriples = [];
|
|
167
|
+
// Apply transitive closure rules
|
|
168
|
+
for (const rule of this.getRules()) {
|
|
169
|
+
for (const condition of rule.conditions) {
|
|
170
|
+
if (condition.type === 'transitive') {
|
|
171
|
+
const inferred = this.applyTransitiveClosure(allTriples, condition.predicate, tripleSet);
|
|
172
|
+
newTriples.push(...inferred);
|
|
173
|
+
if (inferred.length > 0)
|
|
174
|
+
rulesApplied++;
|
|
175
|
+
}
|
|
176
|
+
if (condition.type === 'symmetric') {
|
|
177
|
+
const predicate = condition.predicate || '';
|
|
178
|
+
const predicates = predicate ? [predicate] : symmetricProps;
|
|
179
|
+
for (const p of predicates) {
|
|
180
|
+
const inferred = this.applySymmetry(allTriples, p, tripleSet);
|
|
181
|
+
newTriples.push(...inferred);
|
|
182
|
+
if (inferred.length > 0)
|
|
183
|
+
rulesApplied++;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (condition.type === 'inverse') {
|
|
187
|
+
for (const [p1, p2] of inverseProps) {
|
|
188
|
+
const inferred = this.applyInverse(allTriples, p1, p2, tripleSet);
|
|
189
|
+
newTriples.push(...inferred);
|
|
190
|
+
if (inferred.length > 0)
|
|
191
|
+
rulesApplied++;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Apply pattern-based rules
|
|
197
|
+
for (const rule of this.getRules()) {
|
|
198
|
+
const matches = this.matchRule(rule, allTriples);
|
|
199
|
+
for (const match of matches) {
|
|
200
|
+
for (const triple of match.inferredTriples) {
|
|
201
|
+
const key = this.tripleKey(triple);
|
|
202
|
+
if (!tripleSet.has(key)) {
|
|
203
|
+
tripleSet.add(key);
|
|
204
|
+
newTriples.push(triple);
|
|
205
|
+
rulesApplied++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (newTriples.length === 0) {
|
|
211
|
+
// Fixpoint reached
|
|
212
|
+
return {
|
|
213
|
+
triples: allTriples,
|
|
214
|
+
stats: {
|
|
215
|
+
rulesApplied,
|
|
216
|
+
triplesInferred,
|
|
217
|
+
iterationsUsed: iteration + 1,
|
|
218
|
+
timeMs: Date.now() - startTime,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
triplesInferred += newTriples.length;
|
|
223
|
+
allTriples.push(...newTriples);
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
triples: allTriples,
|
|
227
|
+
stats: {
|
|
228
|
+
rulesApplied,
|
|
229
|
+
triplesInferred,
|
|
230
|
+
iterationsUsed: this.maxIterations,
|
|
231
|
+
timeMs: Date.now() - startTime,
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Apply transitive closure for a predicate
|
|
237
|
+
*/
|
|
238
|
+
applyTransitiveClosure(triples, predicate, existingKeys) {
|
|
239
|
+
const inferred = [];
|
|
240
|
+
const edges = triples.filter(t => t.predicate === predicate);
|
|
241
|
+
// Build adjacency map
|
|
242
|
+
const adjacency = new Map();
|
|
243
|
+
for (const edge of edges) {
|
|
244
|
+
if (!adjacency.has(edge.subject)) {
|
|
245
|
+
adjacency.set(edge.subject, new Set());
|
|
246
|
+
}
|
|
247
|
+
adjacency.get(edge.subject).add(edge.object);
|
|
248
|
+
}
|
|
249
|
+
// Compute transitive closure using Warshall-like algorithm
|
|
250
|
+
for (const [start, directTargets] of adjacency) {
|
|
251
|
+
const visited = new Set();
|
|
252
|
+
const queue = [...directTargets];
|
|
253
|
+
while (queue.length > 0) {
|
|
254
|
+
const current = queue.shift();
|
|
255
|
+
if (visited.has(current))
|
|
256
|
+
continue;
|
|
257
|
+
visited.add(current);
|
|
258
|
+
const nextTargets = adjacency.get(current);
|
|
259
|
+
if (nextTargets) {
|
|
260
|
+
for (const next of nextTargets) {
|
|
261
|
+
if (!visited.has(next)) {
|
|
262
|
+
const newTriple = {
|
|
263
|
+
subject: start,
|
|
264
|
+
predicate,
|
|
265
|
+
object: next,
|
|
266
|
+
};
|
|
267
|
+
const key = this.tripleKey(newTriple);
|
|
268
|
+
if (!existingKeys.has(key)) {
|
|
269
|
+
existingKeys.add(key);
|
|
270
|
+
inferred.push(newTriple);
|
|
271
|
+
}
|
|
272
|
+
queue.push(next);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return inferred;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Apply symmetry for a predicate
|
|
282
|
+
*/
|
|
283
|
+
applySymmetry(triples, predicate, existingKeys) {
|
|
284
|
+
const inferred = [];
|
|
285
|
+
const edges = triples.filter(t => t.predicate === predicate);
|
|
286
|
+
for (const edge of edges) {
|
|
287
|
+
const inverse = {
|
|
288
|
+
subject: edge.object,
|
|
289
|
+
predicate: edge.predicate,
|
|
290
|
+
object: edge.subject,
|
|
291
|
+
};
|
|
292
|
+
const key = this.tripleKey(inverse);
|
|
293
|
+
if (!existingKeys.has(key)) {
|
|
294
|
+
existingKeys.add(key);
|
|
295
|
+
inferred.push(inverse);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return inferred;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Apply inverse property rule
|
|
302
|
+
*/
|
|
303
|
+
applyInverse(triples, predicate1, predicate2, existingKeys) {
|
|
304
|
+
const inferred = [];
|
|
305
|
+
// P1(X, Y) => P2(Y, X)
|
|
306
|
+
for (const t of triples.filter(t => t.predicate === predicate1)) {
|
|
307
|
+
const inverse = {
|
|
308
|
+
subject: t.object,
|
|
309
|
+
predicate: predicate2,
|
|
310
|
+
object: t.subject,
|
|
311
|
+
};
|
|
312
|
+
const key = this.tripleKey(inverse);
|
|
313
|
+
if (!existingKeys.has(key)) {
|
|
314
|
+
existingKeys.add(key);
|
|
315
|
+
inferred.push(inverse);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// P2(X, Y) => P1(Y, X)
|
|
319
|
+
for (const t of triples.filter(t => t.predicate === predicate2)) {
|
|
320
|
+
const inverse = {
|
|
321
|
+
subject: t.object,
|
|
322
|
+
predicate: predicate1,
|
|
323
|
+
object: t.subject,
|
|
324
|
+
};
|
|
325
|
+
const key = this.tripleKey(inverse);
|
|
326
|
+
if (!existingKeys.has(key)) {
|
|
327
|
+
existingKeys.add(key);
|
|
328
|
+
inferred.push(inverse);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return inferred;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get symmetric properties from triples
|
|
335
|
+
*/
|
|
336
|
+
getSymmetricProperties(triples) {
|
|
337
|
+
return triples
|
|
338
|
+
.filter(t => t.predicate === RDF.type &&
|
|
339
|
+
t.object === OWL.SymmetricProperty)
|
|
340
|
+
.map(t => t.subject);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get inverse property pairs from triples
|
|
344
|
+
*/
|
|
345
|
+
getInverseProperties(triples) {
|
|
346
|
+
return triples
|
|
347
|
+
.filter(t => t.predicate === OWL.inverseOf)
|
|
348
|
+
.map(t => [t.subject, t.object]);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Match a rule against triples
|
|
352
|
+
*/
|
|
353
|
+
matchRule(rule, triples) {
|
|
354
|
+
const matches = [];
|
|
355
|
+
// Only handle pattern-based rules here
|
|
356
|
+
const patternConditions = rule.conditions.filter(c => c.type === 'triple-pattern');
|
|
357
|
+
if (patternConditions.length === 0 || rule.actions.length === 0) {
|
|
358
|
+
return matches;
|
|
359
|
+
}
|
|
360
|
+
// For simplicity, handle single and dual pattern rules
|
|
361
|
+
if (patternConditions.length === 1) {
|
|
362
|
+
const pattern = patternConditions[0];
|
|
363
|
+
for (const triple of triples) {
|
|
364
|
+
const bindings = this.matchPattern(pattern, triple);
|
|
365
|
+
if (bindings) {
|
|
366
|
+
const inferredTriples = this.applyActions(rule.actions, bindings);
|
|
367
|
+
if (inferredTriples.length > 0) {
|
|
368
|
+
matches.push({
|
|
369
|
+
ruleId: rule.id,
|
|
370
|
+
bindings,
|
|
371
|
+
inferredTriples,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else if (patternConditions.length === 2) {
|
|
378
|
+
// Join two patterns
|
|
379
|
+
const [pattern1, pattern2] = patternConditions;
|
|
380
|
+
for (const t1 of triples) {
|
|
381
|
+
const bindings1 = this.matchPattern(pattern1, t1);
|
|
382
|
+
if (bindings1) {
|
|
383
|
+
for (const t2 of triples) {
|
|
384
|
+
const bindings2 = this.matchPattern(pattern2, t2);
|
|
385
|
+
if (bindings2 && this.compatibleBindings(bindings1, bindings2)) {
|
|
386
|
+
const merged = { ...bindings1, ...bindings2 };
|
|
387
|
+
const inferredTriples = this.applyActions(rule.actions, merged);
|
|
388
|
+
if (inferredTriples.length > 0) {
|
|
389
|
+
matches.push({
|
|
390
|
+
ruleId: rule.id,
|
|
391
|
+
bindings: merged,
|
|
392
|
+
inferredTriples,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return matches;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Match a pattern against a triple
|
|
404
|
+
*/
|
|
405
|
+
matchPattern(pattern, triple) {
|
|
406
|
+
const bindings = {};
|
|
407
|
+
// Match subject
|
|
408
|
+
if (pattern.subject) {
|
|
409
|
+
if (typeof pattern.subject === 'string') {
|
|
410
|
+
if (pattern.subject !== triple.subject)
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
bindings[pattern.subject.variable] = triple.subject;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// Match predicate
|
|
418
|
+
if (pattern.predicate) {
|
|
419
|
+
if (typeof pattern.predicate === 'string') {
|
|
420
|
+
if (pattern.predicate !== triple.predicate)
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
bindings[pattern.predicate.variable] = triple.predicate;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Match object
|
|
428
|
+
if (pattern.object) {
|
|
429
|
+
if (typeof pattern.object === 'string') {
|
|
430
|
+
if (pattern.object !== triple.object)
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
bindings[pattern.object.variable] = triple.object;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return bindings;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Check if two binding sets are compatible
|
|
441
|
+
*/
|
|
442
|
+
compatibleBindings(b1, b2) {
|
|
443
|
+
for (const key of Object.keys(b1)) {
|
|
444
|
+
if (key in b2 && b1[key] !== b2[key]) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Apply actions with bindings
|
|
452
|
+
*/
|
|
453
|
+
applyActions(actions, bindings) {
|
|
454
|
+
const result = [];
|
|
455
|
+
for (const action of actions) {
|
|
456
|
+
if (action.type === 'add-triple') {
|
|
457
|
+
const subject = typeof action.subject === 'string'
|
|
458
|
+
? action.subject
|
|
459
|
+
: bindings[action.subject.variable];
|
|
460
|
+
const predicate = action.predicate;
|
|
461
|
+
const object = typeof action.object === 'string'
|
|
462
|
+
? action.object
|
|
463
|
+
: bindings[action.object.variable];
|
|
464
|
+
if (subject && predicate && object) {
|
|
465
|
+
result.push({ subject, predicate, object });
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Create unique key for triple
|
|
473
|
+
*/
|
|
474
|
+
tripleKey(triple) {
|
|
475
|
+
return `${triple.subject}|${triple.predicate}|${triple.object}`;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
//# sourceMappingURL=rule-engine.js.map
|