UNPKG

fregejs

Version:

A propositional logic library written in Typescript

480 lines (415 loc) 16.3 kB
import { describe, it } from 'node:test'; import assert from 'node:assert'; import { Calculator } from '../Calculator'; import { Implication, Conjunction, Disjunction, Biconditional, Negation, } from 'types'; describe('calculator', () => { it('should be defined', () => { assert.ok(Calculator, 'calculator class is defined.'); }); describe('evaluate', () => { it('should be defined', () => { assert.ok(Calculator.evaluate, 'evaluate method is defined'); }); it('should evaluate correctly an implication', () => { const operation: Implication = { operation: 'Implication', left: 'A', right: 'B', }; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, true); assert.equal(case3, false); assert.equal(case4, true); }); it('should evaluate correctly a conjunction', () => { const operation: Conjunction = { operation: 'Conjunction', left: 'A', right: 'B', }; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, false); assert.equal(case3, false); assert.equal(case4, false); }); it('should evaluate correctly a disjunction', () => { const operation: Disjunction = { operation: 'Disjunction', left: 'A', right: 'B', }; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, true); assert.equal(case3, true); assert.equal(case4, false); }); it('should evaluate correctly a biconditional', () => { const operation: Biconditional = { operation: 'Biconditional', left: 'A', right: 'B', }; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, false); assert.equal(case3, false); assert.equal(case4, true); }); it('should evaluate correctly a negation', () => { const operation: Negation = { operation: 'Negation', value: 'A' }; const case1 = Calculator.evaluate(operation, { A: true }); const case2 = Calculator.evaluate(operation, { A: false }); assert.equal(case1, false); assert.equal(case2, true); }); it('should evaluate A->(B->A)', () => { const operation = 'A->(B->A)'; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, true); assert.equal(case3, true); assert.equal(case4, true); }); it('should evaluate ¬(¬(A ∧ ¬B) ∧ ¬(A ∧ ¬B))', () => { const operation = '¬A ∨ (¬B ∨ A)'; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, true); assert.equal(case3, true); assert.equal(case4, true); }); it('should evaluate ¬(¬ A ∧ ¬(B->A))', () => { const operation = '¬(A ∧ ¬¬(B ∧ ¬A))'; const case1 = Calculator.evaluate(operation, { A: true, B: true }); const case2 = Calculator.evaluate(operation, { A: false, B: true }); const case3 = Calculator.evaluate(operation, { A: true, B: false }); const case4 = Calculator.evaluate(operation, { A: false, B: false }); assert.equal(case1, true); assert.equal(case2, true); assert.equal(case3, true); assert.equal(case4, true); }); }); describe('generateTruthTable', () => { it('should generate a truth table for ¬P', () => { const output = Calculator.generateTruthTable('¬P'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['P', '¬P']); assert.deepStrictEqual(truthCombinations, [[false], [true]]); assert.deepStrictEqual(truthValues, [true, false]); }); it('should generate a truth table for P -> Q', () => { const output = Calculator.generateTruthTable('P -> Q'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['P', 'Q', 'P -> Q']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [true, true, false, true]); }); it('should generate a truth table for P <-> Q', () => { const output = Calculator.generateTruthTable('P <-> Q'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['P', 'Q', 'P <-> Q']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [true, false, false, true]); }); it('should generate a truth table for P ∧ Q', () => { const output = Calculator.generateTruthTable('P ∧ Q'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['P', 'Q', 'P ∧ Q']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [false, false, false, true]); }); it('should generate a truth table for P ∨ Q', () => { const output = Calculator.generateTruthTable('P ∨ Q'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['P', 'Q', 'P ∨ Q']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [false, true, true, true]); }); it('should generate a truth table for (A ∨ B) -> ¬(¬C ∧ D)', () => { const output = Calculator.generateTruthTable('(A ∨ B) -> ¬(¬C ∧ D)'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, [ 'A', 'B', 'C', 'D', '(A ∨ B) -> ¬(¬C ∧ D)', ]); assert.deepStrictEqual(truthCombinations, [ [false, false, false, false], [false, false, false, true], [false, false, true, false], [false, false, true, true], [false, true, false, false], [false, true, false, true], [false, true, true, false], [false, true, true, true], [true, false, false, false], [true, false, false, true], [true, false, true, false], [true, false, true, true], [true, true, false, false], [true, true, false, true], [true, true, true, false], [true, true, true, true], ]); assert.deepStrictEqual(truthValues, [ true, true, true, true, true, false, true, true, true, false, true, true, true, false, true, true, ]); }); it('should generate a truth table for ¬(A ∧ B)', () => { const output = Calculator.generateTruthTable('¬(A ∧ B)'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['A', 'B', '¬(A ∧ B)']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [true, true, true, false]); }); it('should generate a truth table for (A -> B) ∧ (B -> A)', () => { const output = Calculator.generateTruthTable('(A -> B) ∧ (B -> A)'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['A', 'B', '(A -> B) ∧ (B -> A)']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [true, false, false, true]); }); it('should generate a truth table for (A ∨ B) -> (B -> A)', () => { const output = Calculator.generateTruthTable('(A ∨ B) -> (B -> A)'); const {headers, truthCombinations, truthValues} = output; assert.deepStrictEqual(headers, ['A', 'B', '(A ∨ B) -> (B -> A)']); assert.deepStrictEqual(truthCombinations, [ [false, false], [false, true], [true, false], [true, true], ]); assert.deepStrictEqual(truthValues, [true, false, true, true]); }); }); describe('isSemanticConsequence', () => { describe('Inference Rules', () => { it('should validate an application of Modus Ponens', () => { const output = Calculator.isSemanticConsequence(['P->Q', 'P'], 'Q'); assert.ok(output); }); it('should validate an application of Modus Tollens', () => { const output = Calculator.isSemanticConsequence(['P->Q', '¬Q'], '¬P'); assert.ok(output); }); it('should validate an application of Hypothetical Syllogism', () => { const output = Calculator.isSemanticConsequence( ['P->Q', 'Q->R'], 'P->R' ); assert.ok(output); }); it('should validate an application of Disjunctive Syllogism', () => { const output = Calculator.isSemanticConsequence(['P ∨ Q', '¬P'], 'Q'); assert.ok(output); }); it('should validate an application of Constructive Dilemma', () => { const output = Calculator.isSemanticConsequence( ['P -> Q', 'R -> S', 'P ∨ R'], 'Q ∨ S' ); assert.ok(output); }); it('should validate an application of Reductio ad Absurdum', () => { const output = Calculator.isSemanticConsequence( ['P->(Q ∨ R)', 'R -> (P ∧ ¬P)', 'P', '¬Q'], '¬P' ); assert.ok(output); }); it('should validate an application of Conditional Proof', () => { const output = Calculator.isSemanticConsequence( ['A->B', 'B->C', 'A'], 'A->C' ); assert.ok(output); }); it('should validate an application of Contraposition', () => { const output = Calculator.isSemanticConsequence( ['(P ∧ ¬Q) -> (¬Q ∧ X)'], '¬(¬Q ∧ X) -> ¬(P ∧ ¬Q)' ); assert.ok(output); }); it('should validate an application of Negation of Conditional', () => { const output = Calculator.isSemanticConsequence(['¬(P->Q)'], 'P ∧ ¬Q'); assert.ok(output); }); it('should validate an application of Associativity (Biconditional)', () => { const output = Calculator.isSemanticConsequence( ['(P<->Q)<->R'], 'P<->(Q<->R)' ); assert.ok(output); }); it('should validate an application of Associativity (Conjunction)', () => { const output = Calculator.isSemanticConsequence( ['(P ∧ Q) ∧ R'], 'P ∧ (Q ∧ R)' ); assert.ok(output); }); it('should validate an application of Associativity (Disjunction)', () => { const output = Calculator.isSemanticConsequence( ['(P ∨ Q) ∨ R'], 'P ∨ (Q ∨ R)' ); assert.ok(output); }); it('should validate an application of Commutativity (Biconditional)', () => { const output = Calculator.isSemanticConsequence(['(P<->Q)'], 'Q<->P'); assert.ok(output); }); it('should validate an application of Commutativity (Conjunction)', () => { const output = Calculator.isSemanticConsequence(['(P ∧ Q)'], 'Q ∧ P'); assert.ok(output); }); it('should validate an application of Commutativity (Disjunction)', () => { const output = Calculator.isSemanticConsequence(['(P ∨ Q)'], 'Q ∨ P'); assert.ok(output); }); it('should validate an application of Distribution', () => { const output = Calculator.isSemanticConsequence( ['(P ∨ Q) ∧ R'], '(P ∧ R) ∨ (Q ∧ R)' ); assert.ok(output); }); it('should validate an application of De Morgan (Conjunction)', () => { const output = Calculator.isSemanticConsequence( ['¬(P ∧ Q)'], '¬P ∨ ¬Q' ); assert.ok(output); }); it('should validate an application of De Morgan (Disjunction)', () => { const output = Calculator.isSemanticConsequence( ['¬(P ∨ Q)'], '¬P ∧ ¬Q' ); assert.ok(output); }); it('should validate an application of Implication Introduction', () => { const output = Calculator.isSemanticConsequence(['P'], 'Q->P'); assert.ok(output); }); it('should validate an application of Biconditional Introduction', () => { const output = Calculator.isSemanticConsequence( ['P->Q', 'Q->P'], 'P <-> Q' ); assert.ok(output); }); it('should validate an application of Conjunction Introduction', () => { const output = Calculator.isSemanticConsequence(['P', 'Q'], 'P ∧ Q'); assert.ok(output); }); it('should validate an application of Disjunction Introduction', () => { const output = Calculator.isSemanticConsequence(['P'], 'P ∨ R'); assert.ok(output); }); it('should validate an application of Biconditional Simplification', () => { const output = Calculator.isSemanticConsequence( ['P <-> Q'], '(P->Q) ∧ (Q->P)' ); assert.ok(output); }); it('should validate an application of Conjunction Simplification', () => { const output = Calculator.isSemanticConsequence(['P ∧ Q'], 'P'); const output2 = Calculator.isSemanticConsequence(['P ∧ Q'], 'Q'); assert.ok(output); assert.ok(output2); }); it('should validate an application of Negation Simplification', () => { const output = Calculator.isSemanticConsequence(['¬¬¬¬P'], 'P'); assert.ok(output); }); }); describe('Fallacies', () => { it('should invalidate a fallacy of asserting the consequent', () => { const output = Calculator.isSemanticConsequence(['P->Q', 'Q'], 'P'); assert.ok(!output); }); it('should invalidate a fallacy of asserting the disjunct', () => { const output = Calculator.isSemanticConsequence(['P ∨ Q', 'P'], '¬Q'); assert.ok(!output); }); }); }); });