UNPKG

tfl-js

Version:

A TypeScript library for parsing and evaluating propositional logic formulas

113 lines 3.72 kB
"use strict"; /** * Core types for formula representation * Inspired by Carnap's PurePropositional implementation */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Compound = exports.Operator = exports.Atom = void 0; /** * Atomic proposition (e.g., p, q, r) */ class Atom { constructor(name) { this.name = name; } evaluate(valuation) { if (!(this.name in valuation)) { throw new Error(`No valuation provided for atomic proposition ${this.name}`); } return valuation[this.name]; } subformulas() { return [this]; } atoms() { return [this.name]; } toString() { return this.name; } } exports.Atom = Atom; /** * Logical operators (¬, ∧, ∨, →, ↔) */ var Operator; (function (Operator) { Operator["NOT"] = "\u00AC"; Operator["AND"] = "\u2227"; Operator["OR"] = "\u2228"; Operator["IF"] = "\u2192"; Operator["IFF"] = "\u2194"; })(Operator || (exports.Operator = Operator = {})); /** * Compound formula with a logical operator */ class Compound { constructor(operator, left, right) { this.operator = operator; this.left = left; this.right = right; // Validate that binary operators have two operands if (operator !== Operator.NOT && !right) { throw new Error(`Binary operator ${operator} requires two operands`); } // Validate that NOT has only one operand if (operator === Operator.NOT && right) { throw new Error(`Unary operator ${operator} cannot have two operands`); } } evaluate(valuation) { switch (this.operator) { case Operator.AND: // For AND, both sides must be true return this.left.evaluate(valuation) && (this.right?.evaluate(valuation) ?? false); case Operator.OR: // For OR, either side must be true return this.left.evaluate(valuation) || (this.right?.evaluate(valuation) ?? false); case Operator.IF: // For implication p → q, if p is true then q must be true const antecedent = this.left.evaluate(valuation); return antecedent ? (this.right?.evaluate(valuation) ?? false) : true; case Operator.IFF: // For biconditional, both sides must have the same value return this.left.evaluate(valuation) === (this.right?.evaluate(valuation) ?? false); case Operator.NOT: // For negation, the operand must be false return !this.left.evaluate(valuation); default: throw new Error(`Unknown operator: ${this.operator}`); } } subformulas() { const subs = new Set(); // Add left subformulas for (const sub of this.left.subformulas()) { subs.add(sub); } // Add right subformulas if present if (this.right) { for (const sub of this.right.subformulas()) { subs.add(sub); } } // Add the formula itself last subs.add(this); return Array.from(subs); } atoms() { const atoms = [...this.left.atoms()]; if (this.right) { atoms.push(...this.right.atoms()); } return [...new Set(atoms)]; } toString() { if (this.operator === Operator.NOT) { return `${this.operator}${this.left.toString()}`; } return `(${this.left.toString()} ${this.operator} ${this.right.toString()})`; } } exports.Compound = Compound; //# sourceMappingURL=formula.js.map