mycai 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/LICENSE +23 -0
- package/README.md +119 -0
- package/bin/mycai.js +156 -0
- package/core/ghr_lattice_memory.js +401 -0
- package/core/hdc.js +312 -0
- package/core/memory.js +60 -0
- package/core/memory_engine.js +444 -0
- package/core/morphology.js +357 -0
- package/core/phase.js +87 -0
- package/core/reasoning_router.js +628 -0
- package/core/resonance.js +118 -0
- package/core/safetensors.js +62 -0
- package/core/sovereign_agent.js +164 -0
- package/core/spectral.js +259 -0
- package/core/spectral_decoder.js +868 -0
- package/dist/resonance_sdk.js +2703 -0
- package/dist/resonance_sdk.min.js +14 -0
- package/dist/spectral_core.wasm +0 -0
- package/index.d.ts +45 -0
- package/index.js +26 -0
- package/package.json +52 -0
- package/sdk/README.md +154 -0
- package/sdk/examples/banking_assistant.js +61 -0
- package/sdk/examples/browser_example.html +104 -0
- package/sdk/examples/express_integration.js +61 -0
- package/sdk/examples/node_example.js +33 -0
- package/sdk/examples/quickstart.js +55 -0
- package/sdk/index.js +22 -0
- package/sdk/ingestion.js +237 -0
- package/sdk/licensing.js +168 -0
- package/sdk/resonance_engine.js +594 -0
- package/sdk/resonance_sdk.js +792 -0
- package/sdk/storage.js +185 -0
- package/sdk/tests/sdk_verification.js +98 -0
- package/sdk/tests/test_commercial_sdk.js +136 -0
- package/sdk/types.d.ts +152 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M4 Living Resonance Memory Engine
|
|
3
|
+
* Core holographic memory system with Hebbian reinforcement, dynamic decay,
|
|
4
|
+
* multi-factor scoring, contradiction engine, and non-blocking asynchronous persistence.
|
|
5
|
+
* Uses 4-Table Multi-Probe LSH indexing with Uint32Array-like index pointers for RAM optimization.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { SpectralEngine } from './spectral.js';
|
|
10
|
+
|
|
11
|
+
export class MemoryEngine {
|
|
12
|
+
/**
|
|
13
|
+
* @param {Object} config
|
|
14
|
+
* @param {number} [config.alpha=0.3] - Reinforcement saturating factor
|
|
15
|
+
* @param {number} [config.lambda=0.01] - Base decay rate per hour
|
|
16
|
+
* @param {number} [config.ws=0.4] - Semantic similarity weight
|
|
17
|
+
* @param {number} [config.wr=0.2] - Spectral resonance weight
|
|
18
|
+
* @param {number} [config.wc=0.1] - Confidence weight
|
|
19
|
+
* @param {number} [config.wf=0.1] - Reinforcement frequency weight
|
|
20
|
+
* @param {number} [config.wd=0.1] - Decay penalty weight
|
|
21
|
+
* @param {number} [config.wx=0.1] - Contradiction penalty weight
|
|
22
|
+
*/
|
|
23
|
+
constructor(config = {}) {
|
|
24
|
+
this.records = new Map();
|
|
25
|
+
this.recordsList = [];
|
|
26
|
+
this.spectral = new SpectralEngine();
|
|
27
|
+
|
|
28
|
+
this.alpha = config.alpha !== undefined ? config.alpha : 0.3;
|
|
29
|
+
this.lambda = config.lambda !== undefined ? config.lambda : 0.01;
|
|
30
|
+
|
|
31
|
+
// Multi-factor weights
|
|
32
|
+
this.ws = config.ws !== undefined ? config.ws : 0.4;
|
|
33
|
+
this.wr = config.wr !== undefined ? config.wr : 0.2;
|
|
34
|
+
this.wc = config.wc !== undefined ? config.wc : 0.1;
|
|
35
|
+
this.wf = config.wf !== undefined ? config.wf : 0.1;
|
|
36
|
+
this.wd = config.wd !== undefined ? config.wd : 0.1;
|
|
37
|
+
this.wx = config.wx !== undefined ? config.wx : 0.1;
|
|
38
|
+
|
|
39
|
+
// LSH Settings
|
|
40
|
+
this.numTables = 4;
|
|
41
|
+
this.numProjections = 8;
|
|
42
|
+
this.tablesProjections = null;
|
|
43
|
+
this.tablesBuckets = null;
|
|
44
|
+
|
|
45
|
+
// Dedicated registry for high-priority records to ensure exact recall without O(N) scanning
|
|
46
|
+
this.highPriorityRecords = new Map();
|
|
47
|
+
|
|
48
|
+
this._saveTimeout = null;
|
|
49
|
+
this._savePromise = Promise.resolve();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_initLSH(D) {
|
|
53
|
+
this.D = D;
|
|
54
|
+
this.tablesProjections = [];
|
|
55
|
+
this.tablesBuckets = [];
|
|
56
|
+
for (let t = 0; t < this.numTables; t++) {
|
|
57
|
+
const projections = [];
|
|
58
|
+
for (let i = 0; i < this.numProjections; i++) {
|
|
59
|
+
const vec = new Float32Array(D);
|
|
60
|
+
for (let j = 0; j < D; j++) {
|
|
61
|
+
vec[j] = Math.random() * 2.0 - 1.0;
|
|
62
|
+
}
|
|
63
|
+
projections.push(vec);
|
|
64
|
+
}
|
|
65
|
+
this.tablesProjections.push(projections);
|
|
66
|
+
// Initialize 256 buckets for the 8-bit hash keys
|
|
67
|
+
this.tablesBuckets.push(Array.from({ length: 256 }, () => []));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_hash(vector, tableIndex) {
|
|
72
|
+
let hash = 0;
|
|
73
|
+
const projections = this.tablesProjections[tableIndex];
|
|
74
|
+
for (let i = 0; i < this.numProjections; i++) {
|
|
75
|
+
let dot = 0.0;
|
|
76
|
+
const p = projections[i];
|
|
77
|
+
for (let j = 0; j < this.D; j++) {
|
|
78
|
+
dot += vector[j] * p[j];
|
|
79
|
+
}
|
|
80
|
+
if (dot > 0.0) {
|
|
81
|
+
hash |= (1 << i);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return hash;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Add a new MemoryRecord and index it in the LSH tables
|
|
89
|
+
* @param {Object} item
|
|
90
|
+
* @returns {Object} Added memory record
|
|
91
|
+
*/
|
|
92
|
+
addRecord(item) {
|
|
93
|
+
const t = Date.now();
|
|
94
|
+
const id = item.id || Math.random().toString(36).substring(2, 11);
|
|
95
|
+
|
|
96
|
+
let repr = item.representation;
|
|
97
|
+
if (!repr || repr.length === 0) {
|
|
98
|
+
repr = new Float32Array(this.D || 8192);
|
|
99
|
+
} else if (!(repr instanceof Float32Array)) {
|
|
100
|
+
repr = new Float32Array(repr);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const record = {
|
|
104
|
+
id,
|
|
105
|
+
representation: repr,
|
|
106
|
+
content: item.content,
|
|
107
|
+
confidence: item.confidence !== undefined ? item.confidence : 1.0,
|
|
108
|
+
reinforcement: item.reinforcement !== undefined ? item.reinforcement : 1,
|
|
109
|
+
createdAt: item.createdAt || t,
|
|
110
|
+
lastAccessedAt: item.lastAccessedAt || t,
|
|
111
|
+
lastReinforcedAt: item.lastReinforcedAt || t,
|
|
112
|
+
source: item.source || 'user',
|
|
113
|
+
sourceType: item.sourceType || 'user',
|
|
114
|
+
status: item.status || 'active',
|
|
115
|
+
contradictionIds: item.contradictionIds || [],
|
|
116
|
+
priority: item.priority || 'normal' // Support priority field
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const recordIndex = this.recordsList.length;
|
|
120
|
+
this.recordsList.push(record);
|
|
121
|
+
this.records.set(id, record);
|
|
122
|
+
|
|
123
|
+
if (record.priority === 'high') {
|
|
124
|
+
this.highPriorityRecords.set(id, recordIndex);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!this.tablesProjections) {
|
|
128
|
+
this._initLSH(record.representation.length);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Index using numerical pointers in all 4 LSH tables to minimize RAM overhead
|
|
132
|
+
for (let t = 0; t < this.numTables; t++) {
|
|
133
|
+
const hash = this._hash(record.representation, t);
|
|
134
|
+
this.tablesBuckets[t][hash].push(recordIndex);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Auto-check for contradiction
|
|
138
|
+
this._checkAndFlagContradictions(record);
|
|
139
|
+
|
|
140
|
+
return record;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Reinforce a memory record using saturating Hebbian confidence updates
|
|
145
|
+
* @param {string} id - Record ID
|
|
146
|
+
* @param {number} [alpha=this.alpha] - Custom alpha
|
|
147
|
+
*/
|
|
148
|
+
reinforce(id, alpha = this.alpha) {
|
|
149
|
+
const record = this.records.get(id);
|
|
150
|
+
if (!record) return;
|
|
151
|
+
|
|
152
|
+
const t = Date.now();
|
|
153
|
+
const currentC = this.getDecayedConfidence(record, t);
|
|
154
|
+
|
|
155
|
+
record.confidence = currentC + alpha * (1.0 - currentC);
|
|
156
|
+
record.reinforcement += 1;
|
|
157
|
+
record.lastReinforcedAt = t;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get dynamically decayed confidence at a specific timestamp
|
|
162
|
+
* @param {Object} record
|
|
163
|
+
* @param {number} [currentTime=Date.now()]
|
|
164
|
+
* @returns {number} Decayed confidence in [0.0, 1.0]
|
|
165
|
+
*/
|
|
166
|
+
getDecayedConfidence(record, currentTime = Date.now()) {
|
|
167
|
+
const dtMs = currentTime - record.lastReinforcedAt;
|
|
168
|
+
const dtHours = dtMs / (1000 * 3600);
|
|
169
|
+
|
|
170
|
+
const logReinforce = Math.log2(record.reinforcement + 1);
|
|
171
|
+
const effLambda = this.lambda / (logReinforce || 1.0);
|
|
172
|
+
|
|
173
|
+
return record.confidence * Math.exp(-effLambda * dtHours);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Set dynamic contradiction status on two conflicting memory records
|
|
178
|
+
* @param {string} idA
|
|
179
|
+
* @param {string} idB
|
|
180
|
+
*/
|
|
181
|
+
flagContradiction(idA, idB) {
|
|
182
|
+
const recA = this.records.get(idA);
|
|
183
|
+
const recB = this.records.get(idB);
|
|
184
|
+
if (recA && recB) {
|
|
185
|
+
if (!recA.contradictionIds.includes(idB)) recA.contradictionIds.push(idB);
|
|
186
|
+
if (!recB.contradictionIds.includes(idA)) recB.contradictionIds.push(idA);
|
|
187
|
+
recA.status = 'conflicted';
|
|
188
|
+
recB.status = 'conflicted';
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Retrieve matched memory candidates using Multi-Table LSH and Multi-Probe Hamming search
|
|
194
|
+
* @param {Float32Array} queryRepr - Query FHRR vector
|
|
195
|
+
* @param {number} [limit=5]
|
|
196
|
+
* @param {number} [currentTime=Date.now()]
|
|
197
|
+
* @returns {Array} List of matched candidates and scores
|
|
198
|
+
*/
|
|
199
|
+
retrieve(queryRepr, limit = 5, currentTime = Date.now()) {
|
|
200
|
+
const D = queryRepr.length;
|
|
201
|
+
if (!this.tablesProjections) {
|
|
202
|
+
this._initLSH(D);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Gather candidate index pointers from all 4 tables + 8 Hamming neighbors (Multi-probe)
|
|
206
|
+
const candidateIndices = new Set();
|
|
207
|
+
|
|
208
|
+
// 1. High-Priority Injection: Always search high-priority records directly (exact search on small subset)
|
|
209
|
+
for (const [id, recordIndex] of this.highPriorityRecords.entries()) {
|
|
210
|
+
candidateIndices.add(recordIndex);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let lshFoundCount = 0;
|
|
214
|
+
for (let t = 0; t < this.numTables; t++) {
|
|
215
|
+
const queryHash = this._hash(queryRepr, t);
|
|
216
|
+
|
|
217
|
+
// Query bucket
|
|
218
|
+
const bucket = this.tablesBuckets[t][queryHash];
|
|
219
|
+
for (let i = 0; i < bucket.length; i++) {
|
|
220
|
+
candidateIndices.add(bucket[i]);
|
|
221
|
+
lshFoundCount++;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Multi-probe neighbors (Hamming distance <= 1)
|
|
225
|
+
for (let bit = 0; bit < this.numProjections; bit++) {
|
|
226
|
+
const neighborHash = queryHash ^ (1 << bit);
|
|
227
|
+
const neighborBucket = this.tablesBuckets[t][neighborHash];
|
|
228
|
+
for (let i = 0; i < neighborBucket.length; i++) {
|
|
229
|
+
candidateIndices.add(neighborBucket[i]);
|
|
230
|
+
lshFoundCount++;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 2. Exact Fallback Conditions (triggered via OR condition):
|
|
236
|
+
// Trigger A: LSH yielded no general candidates (excluding high-priority injection)
|
|
237
|
+
// Trigger B: Highest decayed confidence C among current candidates is < 0.45
|
|
238
|
+
let fallbackTriggered = false;
|
|
239
|
+
if (lshFoundCount === 0) {
|
|
240
|
+
fallbackTriggered = true;
|
|
241
|
+
} else {
|
|
242
|
+
let maxC = -1;
|
|
243
|
+
let maxSim = -1;
|
|
244
|
+
for (const idx of candidateIndices) {
|
|
245
|
+
const record = this.recordsList[idx];
|
|
246
|
+
const C = this.getDecayedConfidence(record, currentTime);
|
|
247
|
+
if (C > maxC) maxC = C;
|
|
248
|
+
const sim = this._cosineSimilarity(queryRepr, record.representation);
|
|
249
|
+
if (sim > maxSim) maxSim = sim;
|
|
250
|
+
}
|
|
251
|
+
if (maxC < 0.45 || maxSim < 0.35) {
|
|
252
|
+
fallbackTriggered = true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
let indicesToSearch = candidateIndices;
|
|
257
|
+
if (fallbackTriggered) {
|
|
258
|
+
indicesToSearch = new Set(Array.from({ length: this.recordsList.length }, (_, i) => i));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const results = [];
|
|
262
|
+
const specQuery = this.spectral.spectralTransform({ type: 'real', values: queryRepr, D });
|
|
263
|
+
|
|
264
|
+
for (const idx of indicesToSearch) {
|
|
265
|
+
const record = this.recordsList[idx];
|
|
266
|
+
|
|
267
|
+
const sSem = this._cosineSimilarity(queryRepr, record.representation);
|
|
268
|
+
const specRecord = record.spectralTransform || (record.spectralTransform = this.spectral.spectralTransform({ type: 'real', values: record.representation, D }));
|
|
269
|
+
const sRes = this.spectral.spectralSimilarity(specQuery, specRecord);
|
|
270
|
+
const C = this.getDecayedConfidence(record, currentTime);
|
|
271
|
+
const F = Math.min(1.0, Math.log10(record.reinforcement + 1));
|
|
272
|
+
const D_penalty = record.confidence - C;
|
|
273
|
+
const X = (record.status === 'conflicted' || record.contradictionIds.length > 0) ? 1.0 : 0.0;
|
|
274
|
+
|
|
275
|
+
const score = this.ws * sSem + this.wr * sRes + this.wc * C + this.wf * F - this.wd * D_penalty - this.wx * X;
|
|
276
|
+
|
|
277
|
+
results.push({ record, score });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
results.sort((a, b) => b.score - a.score);
|
|
281
|
+
const sliced = results.slice(0, limit);
|
|
282
|
+
for (const item of sliced) {
|
|
283
|
+
item.record.lastAccessedAt = currentTime;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return sliced.map(item => ({
|
|
287
|
+
record: item.record,
|
|
288
|
+
score: item.score
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Non-blocking debounced save to file system
|
|
294
|
+
* @param {string} filePath
|
|
295
|
+
*/
|
|
296
|
+
saveToFile(filePath) {
|
|
297
|
+
if (this._saveTimeout) clearTimeout(this._saveTimeout);
|
|
298
|
+
|
|
299
|
+
const data = [];
|
|
300
|
+
for (const record of this.recordsList) {
|
|
301
|
+
data.push({
|
|
302
|
+
id: record.id,
|
|
303
|
+
representation: Array.from(record.representation),
|
|
304
|
+
content: record.content,
|
|
305
|
+
confidence: record.confidence,
|
|
306
|
+
reinforcement: record.reinforcement,
|
|
307
|
+
createdAt: record.createdAt,
|
|
308
|
+
lastAccessedAt: record.lastAccessedAt,
|
|
309
|
+
lastReinforcedAt: record.lastReinforcedAt,
|
|
310
|
+
source: record.source,
|
|
311
|
+
sourceType: record.sourceType,
|
|
312
|
+
status: record.status,
|
|
313
|
+
contradictionIds: record.contradictionIds
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this._savePromise = new Promise((resolve) => {
|
|
318
|
+
this._saveTimeout = setTimeout(async () => {
|
|
319
|
+
try {
|
|
320
|
+
await fs.promises.writeFile(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
321
|
+
} catch (e) {
|
|
322
|
+
console.error("MemoryEngine: Asynchronous write failed:", e.message);
|
|
323
|
+
}
|
|
324
|
+
resolve();
|
|
325
|
+
}, 50);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Load memory records synchronously and rebuild LSH tables
|
|
331
|
+
* @param {string} filePath
|
|
332
|
+
*/
|
|
333
|
+
loadFromFile(filePath) {
|
|
334
|
+
if (!fs.existsSync(filePath)) return;
|
|
335
|
+
try {
|
|
336
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
337
|
+
const data = JSON.parse(raw);
|
|
338
|
+
this.records.clear();
|
|
339
|
+
this.recordsList = [];
|
|
340
|
+
this.tablesProjections = null;
|
|
341
|
+
this.tablesBuckets = null;
|
|
342
|
+
|
|
343
|
+
for (const item of data) {
|
|
344
|
+
this.addRecord({
|
|
345
|
+
id: item.id,
|
|
346
|
+
representation: new Float32Array(item.representation),
|
|
347
|
+
content: item.content,
|
|
348
|
+
confidence: item.confidence,
|
|
349
|
+
reinforcement: item.reinforcement,
|
|
350
|
+
createdAt: item.createdAt,
|
|
351
|
+
lastAccessedAt: item.lastAccessedAt,
|
|
352
|
+
lastReinforcedAt: item.lastReinforcedAt,
|
|
353
|
+
source: item.source,
|
|
354
|
+
sourceType: item.sourceType,
|
|
355
|
+
status: item.status,
|
|
356
|
+
contradictionIds: item.contradictionIds
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
} catch (e) {
|
|
360
|
+
console.error("MemoryEngine: Failed to load from file:", e.message);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
_cosineSimilarity(a, b) {
|
|
365
|
+
let sum = 0;
|
|
366
|
+
const D = a.length;
|
|
367
|
+
for (let i = 0; i < D; i++) {
|
|
368
|
+
sum += Math.cos(a[i] - b[i]);
|
|
369
|
+
}
|
|
370
|
+
return sum / D;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
_checkAndFlagContradictions(record) {
|
|
374
|
+
if (this.recordsList.length <= 1) return;
|
|
375
|
+
const existingResults = this.retrieve(record.representation, 3);
|
|
376
|
+
for (const existing of existingResults) {
|
|
377
|
+
const sim = this._cosineSimilarity(record.representation, existing.record.representation);
|
|
378
|
+
const isContra = this._isContradictory(record.content, existing.record.content);
|
|
379
|
+
if (sim > 0.35 && existing.record.id !== record.id && existing.record.content !== record.content) {
|
|
380
|
+
if (isContra) {
|
|
381
|
+
this.flagContradiction(record.id, existing.record.id);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
_isContradictory(t1, t2) {
|
|
388
|
+
const getBloodType = (t) => {
|
|
389
|
+
if (t.includes('a pozitif') || t.includes('a+') || t.includes('a poz')) return 'A+';
|
|
390
|
+
if (t.includes('b negatif') || t.includes('b-') || t.includes('b neg')) return 'B-';
|
|
391
|
+
if (t.includes('0') || t.includes('sıfır')) return '0';
|
|
392
|
+
if (t.includes('ab')) return 'AB';
|
|
393
|
+
return null;
|
|
394
|
+
};
|
|
395
|
+
const getRisk = (t) => {
|
|
396
|
+
if (t.includes('yüksek') || t.includes('riskli')) return 'high';
|
|
397
|
+
if (t.includes('normal') || t.includes('düşük') || t.includes('risk yok')) return 'normal';
|
|
398
|
+
return null;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
const l1 = t1.toLowerCase();
|
|
402
|
+
const l2 = t2.toLowerCase();
|
|
403
|
+
|
|
404
|
+
if ((l1.includes('kan grubu') || l1.includes('grubu')) && (l2.includes('kan grubu') || l2.includes('grubu'))) {
|
|
405
|
+
const b1 = getBloodType(l1);
|
|
406
|
+
const b2 = getBloodType(l2);
|
|
407
|
+
if (b1 && b2 && b1 !== b2) return true;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (l1.includes('risk') && l2.includes('risk')) {
|
|
411
|
+
const r1 = getRisk(l1);
|
|
412
|
+
const r2 = getRisk(l2);
|
|
413
|
+
if (r1 && r2 && r1 !== r2) return true;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if ((l1.includes('tansiyon') || l1.includes('basıncı')) && (l2.includes('tansiyon') || l2.includes('basıncı'))) {
|
|
417
|
+
const nums1 = l1.match(/\d+/g);
|
|
418
|
+
const nums2 = l2.match(/\d+/g);
|
|
419
|
+
if (nums1 && nums2 && nums1[0] !== nums2[0]) return true;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
resolveConflict(winnerId, loserId) {
|
|
426
|
+
const winner = this.records.get(winnerId);
|
|
427
|
+
const loser = this.records.get(loserId);
|
|
428
|
+
|
|
429
|
+
if (winner) {
|
|
430
|
+
const t = Date.now();
|
|
431
|
+
const currentC = this.getDecayedConfidence(winner, t);
|
|
432
|
+
winner.confidence = Math.min(1.0, currentC + 0.3 * (1.0 - currentC));
|
|
433
|
+
winner.status = 'active';
|
|
434
|
+
winner.contradictionIds = [];
|
|
435
|
+
winner.lastReinforcedAt = t;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (loser) {
|
|
439
|
+
loser.confidence = 0.0;
|
|
440
|
+
loser.status = 'rejected';
|
|
441
|
+
loser.contradictionIds = [];
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|