Files

350 lines
11 KiB
JavaScript
Raw Permalink Normal View History

/**
* Test Unified Evidence Fusion System
*
* This test demonstrates the new separation of concerns between aggregation
* (OWA) and reconciliation (bilattice/Dempster-Shafer) logic, supporting
* both qualitative and quantitative modes with the same lexicon.
*/
import { test, describe } from 'node:test';
import assert from 'node:assert';
import {
QualitativeScale,
UnifiedEvidenceFusion,
EvidenceAggregation,
EvidenceReconciliation,
NumericBilatticeOrderings
} from '../../src/qualitative/index.js';
describe('Unified Evidence Fusion System', () => {
test('should demonstrate aggregation vs reconciliation separation', () => {
// Test data with conflicting evidence
const collectedValues = [
{
value: 0.8,
possibility: 0.9,
path: ['evidence1'],
source: { type: 'direct', confidence: 0.95 },
metadata: { timestamp: Date.now(), reliability: 0.9 }
},
{
value: 0.3,
possibility: 0.4,
path: ['evidence2'],
source: { type: 'inferred', confidence: 0.6 },
metadata: { timestamp: Date.now(), reliability: 0.7 }
},
{
value: 0.7,
possibility: 0.6,
path: ['evidence3'],
source: { type: 'derived', confidence: 0.8 },
metadata: { timestamp: Date.now(), reliability: 0.8 }
}
];
// Test pure aggregation (no reconciliation)
const aggregationResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
aggregationMethod: 'majority',
useReconciliation: false
});
assert.ok(aggregationResult.hasValue);
assert.strictEqual(aggregationResult.fusionMethod, 'aggregation');
assert.strictEqual(aggregationResult.reconciliationMethod, 'none');
assert.ok(aggregationResult.epistemicAnalysis === null);
// Test reconciliation-based fusion
const reconciliationResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
aggregationMethod: 'max',
reconciliationMethod: 'dempster_shafer',
epistemicMode: 'hybrid',
useReconciliation: true
});
assert.ok(reconciliationResult.hasValue);
assert.strictEqual(reconciliationResult.fusionMethod, 'reconciliation');
assert.strictEqual(reconciliationResult.reconciliationMethod, 'dempster_shafer');
assert.ok(reconciliationResult.epistemicAnalysis !== null);
});
test('should support both qualitative and quantitative modes with same lexicon', () => {
const collectedValues = [
{
value: 0.75, // Valid fivePoint scale value
possibility: 0.75,
path: ['evidence1'],
source: { type: 'direct' },
metadata: { reliability: 0.9 }
},
{
value: 0.5, // Valid fivePoint scale value
possibility: 0.5,
path: ['evidence2'],
source: { type: 'inferred' },
metadata: { reliability: 0.7 }
}
];
const scale = QualitativeScale.fivePoint();
// Test quantitative mode
const quantitativeResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
aggregationMethod: 'average',
useReconciliation: false
});
// Test qualitative mode
const qualitativeResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'qualitative',
aggregationMethod: 'average',
scale: scale,
useReconciliation: false
});
assert.ok(quantitativeResult.hasValue);
assert.ok(qualitativeResult.hasValue);
assert.strictEqual(quantitativeResult.aggregationMethod, 'average');
assert.strictEqual(qualitativeResult.aggregationMethod, 'average');
// Both should use the same aggregation lexicon
assert.ok(quantitativeResult.value > 0);
assert.ok(qualitativeResult.value > 0);
});
test('should demonstrate numeric bilattice orderings', () => {
// Create a simple numeric capacity
const capacity = {
stateSpace: ['evidence1', 'evidence2', 'evidence3'],
getCapacity: (set) => {
// For single elements
if (set.size === 1) {
if (set.has('evidence1')) return 0.8;
if (set.has('evidence2')) return 0.6;
if (set.has('evidence3')) return 0.4;
}
// For complements (multiple elements)
if (set.size === 2) {
return 0.2; // Some belief in complements
}
// For empty set
if (set.size === 0) {
return 0;
}
// For full set
if (set.size === 3) {
return 1.0;
}
return 0;
}
};
const propositions = [['evidence1'], ['evidence2'], ['evidence3']];
// Test information ordering
const mostInformative = NumericBilatticeOrderings.findMostInformative(propositions, capacity);
assert.ok(mostInformative);
assert.strictEqual(mostInformative.rank, 1);
// Test truth ordering
const mostTrue = NumericBilatticeOrderings.findMostTrue(propositions, capacity);
assert.ok(mostTrue);
assert.strictEqual(mostTrue.rank, 1);
// Test Dempster-Shafer measures
const belief = NumericBilatticeOrderings.dempsterShaferBelief(['evidence1'], capacity);
const plausibility = NumericBilatticeOrderings.dempsterShaferPlausibility(['evidence1'], capacity);
const uncertainty = NumericBilatticeOrderings.dempsterShaferUncertainty(['evidence1'], capacity);
assert.strictEqual(belief, 0.8);
// Plausibility should be 1 - capacity of complement
// Complement of ['evidence1'] is ['evidence2', 'evidence3']
// Capacity of ['evidence2', 'evidence3'] is 0.2
// So plausibility = 1 - 0.2 = 0.8
assert.strictEqual(plausibility, 0.8);
assert.strictEqual(uncertainty, 0); // 0.8 - 0.8 = 0
});
test('should demonstrate reconciliation methods comparison', () => {
const collectedValues = [
{
value: 0.8,
possibility: 0.9,
path: ['evidence1'],
source: { type: 'direct' },
metadata: { reliability: 0.9 }
},
{
value: 0.3,
possibility: 0.4,
path: ['evidence2'],
source: { type: 'inferred' },
metadata: { reliability: 0.7 }
}
];
// Test different reconciliation methods
const bilatticeResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
reconciliationMethod: 'bilattice',
epistemicMode: 'hybrid',
useReconciliation: true
});
const dempsterShaferResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
reconciliationMethod: 'dempster_shafer',
epistemicMode: 'hybrid',
useReconciliation: true
});
const subjectiveLogicResult = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
reconciliationMethod: 'subjective_logic',
epistemicMode: 'hybrid',
useReconciliation: true
});
// All should produce valid results
assert.ok(bilatticeResult.hasValue);
assert.ok(dempsterShaferResult.hasValue);
assert.ok(subjectiveLogicResult.hasValue);
// All should have epistemic analysis
assert.ok(bilatticeResult.epistemicAnalysis);
assert.ok(dempsterShaferResult.epistemicAnalysis);
assert.ok(subjectiveLogicResult.epistemicAnalysis);
// Different methods may produce different results
console.log('Bilattice result:', bilatticeResult.value);
console.log('Dempster-Shafer result:', dempsterShaferResult.value);
console.log('Subjective Logic result:', subjectiveLogicResult.value);
});
test('should demonstrate aggregation methods comparison', () => {
const collectedValues = [
{
value: 0.8,
possibility: 0.8,
path: ['evidence1'],
source: { type: 'direct' },
metadata: { reliability: 0.9 }
},
{
value: 0.6,
possibility: 0.6,
path: ['evidence2'],
source: { type: 'inferred' },
metadata: { reliability: 0.7 }
},
{
value: 0.4,
possibility: 0.4,
path: ['evidence3'],
source: { type: 'derived' },
metadata: { reliability: 0.8 }
}
];
const aggregationMethods = ['max', 'min', 'average', 'majority', 'median'];
const results = {};
for (const method of aggregationMethods) {
results[method] = UnifiedEvidenceFusion.fuse(collectedValues, {
mode: 'quantitative',
aggregationMethod: method,
useReconciliation: false
});
}
// All methods should produce valid results
for (const [method, result] of Object.entries(results)) {
assert.ok(result.hasValue, `Method ${method} should produce valid result`);
assert.strictEqual(result.aggregationMethod, method);
assert.ok(result.value >= 0 && result.value <= 1);
}
// Different methods should produce different results
assert.ok(results.max.value >= results.average.value);
assert.ok(results.average.value >= results.min.value);
});
test('should demonstrate method comparison functionality', () => {
const collectedValues = [
{
value: 0.7,
possibility: 0.7,
path: ['evidence1'],
source: { type: 'direct' },
metadata: { reliability: 0.9 }
},
{
value: 0.5,
possibility: 0.5,
path: ['evidence2'],
source: { type: 'inferred' },
metadata: { reliability: 0.7 }
}
];
const comparison = UnifiedEvidenceFusion.compareMethods(collectedValues, {
mode: 'quantitative',
aggregationMethods: ['max', 'average', 'majority'],
reconciliationMethods: ['none', 'dempster_shafer'],
epistemicModes: ['hybrid']
});
assert.ok(comparison.results);
assert.ok(comparison.summary);
assert.ok(comparison.summary.bestMethods.length > 0);
assert.ok(comparison.summary.worstMethods.length > 0);
assert.ok(comparison.summary.valueRange.min <= comparison.summary.valueRange.max);
});
test('should validate fusion options', () => {
const validation = UnifiedEvidenceFusion.validateOptions({
mode: 'quantitative',
aggregationMethod: 'max',
reconciliationMethod: 'bilattice',
epistemicMode: 'hybrid',
capacityType: 'simple_support'
});
assert.ok(validation.valid);
assert.strictEqual(validation.errors.length, 0);
// Test invalid options
const invalidValidation = UnifiedEvidenceFusion.validateOptions({
mode: 'invalid',
aggregationMethod: 'invalid',
reconciliationMethod: 'invalid'
});
assert.ok(!invalidValidation.valid);
assert.ok(invalidValidation.errors.length > 0);
});
test('should get available methods and descriptions', () => {
const availableMethods = UnifiedEvidenceFusion.getAvailableMethods();
assert.ok(availableMethods.aggregation);
assert.ok(availableMethods.reconciliation);
assert.ok(availableMethods.epistemicModes);
assert.ok(availableMethods.capacityTypes);
const descriptions = UnifiedEvidenceFusion.getMethodDescriptions();
assert.ok(descriptions.aggregation);
assert.ok(descriptions.reconciliation);
assert.ok(descriptions.epistemicModes);
assert.ok(descriptions.capacityTypes);
// Test specific descriptions
assert.ok(descriptions.aggregation.max);
assert.ok(descriptions.reconciliation.bilattice);
assert.ok(descriptions.epistemicModes.hybrid);
});
});