/** * Simple Test Suite for Qualitative Capacity System * * Tests core functionality using Node.js built-in test framework */ import { test, describe } from 'node:test'; import assert from 'node:assert/strict'; import { QualitativeScale, QualitativeCapacity, QualitativeFusion, OWAQualitativeFusion, getOWAQualitativeWeights, DEFAULT_QUALITATIVE_SCALE } from '../../src/qualitative/index.js'; describe('QualitativeScale', () => { test('should create scale with correct properties', () => { const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test'); assert.deepStrictEqual(scale.values, [0, 0.25, 0.5, 0.75, 1]); assert.strictEqual(scale.bottom, 0); assert.strictEqual(scale.top, 1); assert.strictEqual(scale.size, 5); }); test('should create correct negation map', () => { const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test'); assert.strictEqual(scale.negate(0), 1); assert.strictEqual(scale.negate(1), 0); assert.strictEqual(scale.negate(0.25), 0.75); assert.strictEqual(scale.negate(0.5), 0.5); assert.strictEqual(scale.negate(0.75), 0.25); }); test('should perform min/max operations correctly', () => { const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test'); assert.strictEqual(scale.min(0.25, 0.75), 0.25); assert.strictEqual(scale.max(0.25, 0.75), 0.75); assert.strictEqual(scale.minAll([0.25, 0.5, 0.75]), 0.25); assert.strictEqual(scale.maxAll([0.25, 0.5, 0.75]), 0.75); }); test('should compare values correctly', () => { const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test'); assert.strictEqual(scale.compare(0.25, 0.75), -1); assert.strictEqual(scale.compare(0.75, 0.25), 1); assert.strictEqual(scale.compare(0.5, 0.5), 0); }); test('should validate values are in scale', () => { const scale = new QualitativeScale([0, 0.25, 0.5, 0.75, 1], 'test'); assert.strictEqual(scale.contains(0.5), true); assert.strictEqual(scale.contains(0.3), false); }); test('should create common scales correctly', () => { const binary = QualitativeScale.binary(); assert.deepStrictEqual(binary.values, [0, 1]); const ternary = QualitativeScale.ternary(); assert.deepStrictEqual(ternary.values, [0, 0.5, 1]); const fivePoint = QualitativeScale.fivePoint(); assert.deepStrictEqual(fivePoint.values, [0, 0.25, 0.5, 0.75, 1]); }); }); describe('QualitativeCapacity', () => { test('should create capacity with correct properties', () => { const stateSpace = ['s1', 's2', 's3']; const scale = new QualitativeScale([0, 0.5, 1], 'test'); // Create a QMT with some focal sets const qmt = new Map(); qmt.set(new Set(['s1']), 0.5); qmt.set(new Set(['s1', 's2']), 1); qmt.set(new Set(['s1', 's2', 's3']), 1); const capacity = new QualitativeCapacity(stateSpace, scale, qmt); assert.deepStrictEqual(capacity.stateSpace, ['s1', 's2', 's3']); assert.strictEqual(capacity.scale, scale); assert.strictEqual(capacity.getFocalSets().length, 3); }); test('should compute capacity values correctly', () => { const stateSpace = ['s1', 's2', 's3']; const scale = new QualitativeScale([0, 0.5, 1], 'test'); const qmt = new Map(); qmt.set(new Set(['s1']), 0.5); qmt.set(new Set(['s1', 's2']), 1); qmt.set(new Set(['s1', 's2', 's3']), 1); const capacity = new QualitativeCapacity(stateSpace, scale, qmt); assert.strictEqual(capacity.getCapacity(['s1']), 0.5); assert.strictEqual(capacity.getCapacity(['s1', 's2']), 1); assert.strictEqual(capacity.getCapacity(['s2']), 0); // Not a focal set assert.strictEqual(capacity.getCapacity(['s1', 's2', 's3']), 1); }); test('should identify special capacity types', () => { const stateSpace = ['s1', 's2']; const scale = QualitativeScale.binary(); // Test possibility measure (all focal sets are singletons) const possibilityQMT = new Map(); possibilityQMT.set(new Set(['s1']), 1); possibilityQMT.set(new Set(['s2']), 0.5); const possibilityCapacity = new QualitativeCapacity(stateSpace, scale, possibilityQMT); assert.strictEqual(possibilityCapacity.isPossibilityMeasure(), true); assert.strictEqual(possibilityCapacity.isNecessityMeasure(), false); // Test necessity measure (focal sets form a nested chain) const necessityQMT = new Map(); necessityQMT.set(new Set(['s1']), 0.5); necessityQMT.set(new Set(['s1', 's2']), 1); const necessityCapacity = new QualitativeCapacity(stateSpace, scale, necessityQMT); assert.strictEqual(necessityCapacity.isPossibilityMeasure(), false); assert.strictEqual(necessityCapacity.isNecessityMeasure(), true); }); test('should create simple support capacities', () => { const stateSpace = ['s1', 's2', 's3']; const scale = QualitativeScale.binary(); const ssc = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale); assert.strictEqual(ssc.getCapacity(['s1']), 1); assert.strictEqual(ssc.getCapacity(['s1', 's2']), 1); assert.strictEqual(ssc.getCapacity(['s2']), 0); assert.strictEqual(ssc.isNecessityMeasure(), true); }); }); describe('QualitativeFusion', () => { test('should perform normalized conjunctive fusion', () => { const stateSpace = ['s1', 's2']; const scale = QualitativeScale.binary(); const capacity1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale); const capacity2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 1, scale); const fused = QualitativeFusion.normalizedConjunctive([capacity1, capacity2]); assert.deepStrictEqual(fused.stateSpace, stateSpace); assert.strictEqual(fused.scale, scale); assert.strictEqual(fused.getCapacity(['s1', 's2']), 1); // Full set should have top value }); test('should perform disjunctive fusion', () => { const stateSpace = ['s1', 's2']; const scale = QualitativeScale.binary(); const capacity1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale); const capacity2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 1, scale); const result = QualitativeFusion.disjunctive(capacity1, capacity2); assert.deepStrictEqual(result.stateSpace, stateSpace); assert.strictEqual(result.scale, scale); assert.strictEqual(result.getCapacity(['s1', 's2']), 1); // min(1, 1) }); test('should compute Sugeno integral', () => { const stateSpace = ['s1', 's2']; const scale = QualitativeScale.ternary(); const capacity = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale); const decisionFunction = { 's1': 0.5, 's2': 1 }; const sugenoValue = QualitativeFusion.sugenoIntegral(capacity, decisionFunction); // Should be a value in the scale assert.strictEqual(scale.contains(sugenoValue), true); assert.ok(sugenoValue >= 0); assert.ok(sugenoValue <= 1); }); }); describe('OWAQualitativeFusion', () => { test('should perform qualitative OWA fusion', () => { const values = [0, 0.5, 1]; // Use values that are in the ternary scale const weights = [0, 0.5, 1]; // Use weights that are in the ternary scale const scale = QualitativeScale.ternary(); const result = OWAQualitativeFusion.fuseWithMeta(values, weights, weights, 'max', scale); // The result should be a valid value in the scale assert.ok(scale.contains(result.value)); assert.ok(result.meta); }); test('should generate OWA weights correctly', () => { const scale = QualitativeScale.ternary(); const maxWeights = getOWAQualitativeWeights('max', 3, null, scale); const minWeights = getOWAQualitativeWeights('min', 3, null, scale); assert.strictEqual(maxWeights[0], 1); // Top weight on first position assert.strictEqual(maxWeights[1], 0); // Bottom weight on others assert.strictEqual(maxWeights[2], 0); assert.strictEqual(minWeights[0], 0); // Bottom weight on first positions assert.strictEqual(minWeights[1], 0); assert.strictEqual(minWeights[2], 1); // Top weight on last position }); }); describe('Integration Tests', () => { test('should work with default qualitative scale', () => { const stateSpace = ['s1', 's2']; const capacity = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, DEFAULT_QUALITATIVE_SCALE); assert.strictEqual(capacity.scale, DEFAULT_QUALITATIVE_SCALE); assert.strictEqual(capacity.getCapacity(['s1']), 1); }); test('should perform end-to-end fusion workflow', () => { const stateSpace = ['s1', 's2']; const scale = QualitativeScale.binary(); // Create two simple support capacities const capacity1 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale); const capacity2 = QualitativeCapacity.createSimpleSupport(stateSpace, ['s2'], 1, scale); // Fuse them using normalized conjunctive rule const fused = QualitativeFusion.normalizedConjunctive([capacity1, capacity2]); // Verify the result assert.deepStrictEqual(fused.stateSpace, stateSpace); assert.strictEqual(fused.scale, scale); assert.strictEqual(fused.getCapacity(['s1', 's2']), 1); // Full set should have top value }); test('should handle edge cases gracefully', () => { const stateSpace = ['s1']; const scale = QualitativeScale.binary(); // Test with single state const capacity = QualitativeCapacity.createSimpleSupport(stateSpace, ['s1'], 1, scale); assert.strictEqual(capacity.getCapacity(['s1']), 1); // Test with empty subset assert.strictEqual(capacity.getCapacity([]), 0); }); });