UNPKG

chop-logic-core

Version:

Core classes, methods and functions for calculating logical formulas and constructing proofs within the Chop Logic project.

1,586 lines (1,528 loc) 64.7 kB
// src/enums/proof.ts var Step = /* @__PURE__ */ ((Step2) => { Step2["Premise"] = "Premise"; Step2["Assumption"] = "Assumption"; Step2["Shortcut"] = "Shortcut"; Step2["Reiteration"] = "Reiteration"; Step2["Derivation"] = "Derivation"; Step2["Axiom"] = "Axiom"; return Step2; })(Step || {}); var HilbertCalculusSchema = /* @__PURE__ */ ((HilbertCalculusSchema2) => { HilbertCalculusSchema2["II"] = "II"; HilbertCalculusSchema2["ID"] = "ID"; HilbertCalculusSchema2["IR"] = "IR"; return HilbertCalculusSchema2; })(HilbertCalculusSchema || {}); var HilbertCalculusRule = /* @__PURE__ */ ((HilbertCalculusRule2) => { HilbertCalculusRule2["II"] = "II"; HilbertCalculusRule2["ID"] = "ID"; HilbertCalculusRule2["IR"] = "IR"; HilbertCalculusRule2["IE"] = "IE"; return HilbertCalculusRule2; })(HilbertCalculusRule || {}); var NaturalCalculusRule = /* @__PURE__ */ ((NaturalCalculusRule2) => { NaturalCalculusRule2["NI"] = "NI"; NaturalCalculusRule2["CI"] = "CI"; NaturalCalculusRule2["DI"] = "DI"; NaturalCalculusRule2["II"] = "II"; NaturalCalculusRule2["EI"] = "EI"; NaturalCalculusRule2["NE"] = "NE"; NaturalCalculusRule2["CE"] = "CE"; NaturalCalculusRule2["DE"] = "DE"; NaturalCalculusRule2["IE"] = "IE"; NaturalCalculusRule2["EE"] = "EE"; return NaturalCalculusRule2; })(NaturalCalculusRule || {}); var PropFormulaCheck = /* @__PURE__ */ ((PropFormulaCheck2) => { PropFormulaCheck2["areEqual"] = "areEqual"; PropFormulaCheck2["isIE"] = "isIE"; PropFormulaCheck2["isDE"] = "isDE"; PropFormulaCheck2["isCE"] = "isCE"; PropFormulaCheck2["isEE"] = "isEE"; PropFormulaCheck2["isNE"] = "isNE"; PropFormulaCheck2["isDI"] = "isDI"; PropFormulaCheck2["isCI"] = "isCI"; PropFormulaCheck2["isEI"] = "isEI"; PropFormulaCheck2["isNI"] = "isNI"; PropFormulaCheck2["isII"] = "isII"; PropFormulaCheck2["isID"] = "isID"; PropFormulaCheck2["isIR"] = "isIR"; return PropFormulaCheck2; })(PropFormulaCheck || {}); // src/enums/symbols.ts var Glyph = /* @__PURE__ */ ((Glyph2) => { Glyph2["Implication"] = "=>"; Glyph2["ReversedImplication"] = "<="; Glyph2["Conjunction"] = "&"; Glyph2["Disjunction"] = "|"; Glyph2["Negation"] = "~"; Glyph2["Equivalence"] = "<=>"; Glyph2["ExclusiveConjunction"] = "^"; Glyph2["ShefferStroke"] = "!&"; Glyph2["WebbOperation"] = "!|"; Glyph2["AntiImplication"] = "!=>"; Glyph2["ReversedAntiImplication"] = "!<="; Glyph2["Contradiction"] = "#"; Glyph2["Tautology"] = "@"; Glyph2["OpenParenthesis"] = "("; Glyph2["CloseParenthesis"] = ")"; return Glyph2; })(Glyph || {}); var GlyphType = /* @__PURE__ */ ((GlyphType2) => { GlyphType2["Variable"] = "variable"; GlyphType2["Operator"] = "operator"; GlyphType2["Parenthesis"] = "parenthesis"; return GlyphType2; })(GlyphType || {}); var GlyphUnicode = /* @__PURE__ */ ((GlyphUnicode2) => { GlyphUnicode2["Implication"] = "\u2192"; GlyphUnicode2["ReversedImplication"] = "\u2190"; GlyphUnicode2["Conjunction"] = "\u2227"; GlyphUnicode2["Disjunction"] = "\u2228"; GlyphUnicode2["Negation"] = "\xAC"; GlyphUnicode2["Equivalence"] = "\u2261"; GlyphUnicode2["ExclusiveConjunction"] = "\u2295"; GlyphUnicode2["ShefferStroke"] = "\u2191"; GlyphUnicode2["WebbOperation"] = "\u2193"; GlyphUnicode2["AntiImplication"] = "\u219B"; GlyphUnicode2["ReversedAntiImplication"] = "\u219A"; GlyphUnicode2["Contradiction"] = "\u22A5"; GlyphUnicode2["Tautology"] = "\u22A4"; GlyphUnicode2["OpenParenthesis"] = "("; GlyphUnicode2["CloseParenthesis"] = ")"; return GlyphUnicode2; })(GlyphUnicode || {}); var Operator = /* @__PURE__ */ ((Operator2) => { Operator2["Var"] = "VAR"; Operator2["Not"] = "NOT"; Operator2["And"] = "AND"; Operator2["Or"] = "OR"; Operator2["Implies"] = "IMPLIES"; Operator2["ReversedImplies"] = "REVERSED_IMPLIES"; Operator2["Equiv"] = "EQUIV"; Operator2["Xor"] = "XOR"; Operator2["Nand"] = "NAND"; Operator2["Nor"] = "NOR"; Operator2["AntiImplies"] = "ANTI_IMPLIES"; Operator2["ReversedAntiImplies"] = "REVERSED_ANTI_IMPLIES"; Operator2["Contradiction"] = "CONTRADICTION"; Operator2["Tautology"] = "TAUTOLOGY"; return Operator2; })(Operator || {}); // src/propositional/builders/create-operator.ts function createOperator(symbol) { switch (symbol.atom[0]) { case "~" /* Negation */: return "NOT" /* Not */; case "&" /* Conjunction */: return "AND" /* And */; case "|" /* Disjunction */: return "OR" /* Or */; case "=>" /* Implication */: return "IMPLIES" /* Implies */; case "<=" /* ReversedImplication */: return "REVERSED_IMPLIES" /* ReversedImplies */; case "<=>" /* Equivalence */: return "EQUIV" /* Equiv */; case "^" /* ExclusiveConjunction */: return "XOR" /* Xor */; case "!&" /* ShefferStroke */: return "NAND" /* Nand */; case "!|" /* WebbOperation */: return "NOR" /* Nor */; case "!=>" /* AntiImplication */: return "ANTI_IMPLIES" /* AntiImplies */; case "!<=" /* ReversedAntiImplication */: return "REVERSED_ANTI_IMPLIES" /* ReversedAntiImplies */; case "#" /* Contradiction */: return "CONTRADICTION" /* Contradiction */; case "@" /* Tautology */: return "TAUTOLOGY" /* Tautology */; default: if (symbol.type === "variable" /* Variable */) { return "VAR" /* Var */; } throw new Error( `Cannot create an operator from symbol "${symbol.atom[0]}".` ); } } // src/tokenizer/get-glyph-unicode.ts var GlyphsDictionary = { ["=>" /* Implication */]: "\u2192" /* Implication */, ["<=" /* ReversedImplication */]: "\u2190" /* ReversedImplication */, ["&" /* Conjunction */]: "\u2227" /* Conjunction */, ["|" /* Disjunction */]: "\u2228" /* Disjunction */, ["~" /* Negation */]: "\xAC" /* Negation */, ["<=>" /* Equivalence */]: "\u2261" /* Equivalence */, ["^" /* ExclusiveConjunction */]: "\u2295" /* ExclusiveConjunction */, ["!&" /* ShefferStroke */]: "\u2191" /* ShefferStroke */, ["!|" /* WebbOperation */]: "\u2193" /* WebbOperation */, ["!=>" /* AntiImplication */]: "\u219B" /* AntiImplication */, ["!<=" /* ReversedAntiImplication */]: "\u219A" /* ReversedAntiImplication */, ["#" /* Contradiction */]: "\u22A5" /* Contradiction */, ["@" /* Tautology */]: "\u22A4" /* Tautology */, ["(" /* OpenParenthesis */]: "(" /* OpenParenthesis */, [")" /* CloseParenthesis */]: ")" /* CloseParenthesis */ }; function getGlyphUnicode(char) { if (char in GlyphsDictionary) { return GlyphsDictionary[char]; } else { throw new Error(`Cannot get a GlyphUnicode for the character "${char}".`); } } // src/tokenizer/get-operator-glyph.ts function getOperatorGlyph(operator) { switch (operator) { case "NOT" /* Not */: return "~" /* Negation */; case "AND" /* And */: return "&" /* Conjunction */; case "OR" /* Or */: return "|" /* Disjunction */; case "IMPLIES" /* Implies */: return "=>" /* Implication */; case "REVERSED_IMPLIES" /* ReversedImplies */: return "<=" /* ReversedImplication */; case "EQUIV" /* Equiv */: return "<=>" /* Equivalence */; case "XOR" /* Xor */: return "^" /* ExclusiveConjunction */; case "NAND" /* Nand */: return "!&" /* ShefferStroke */; case "NOR" /* Nor */: return "!|" /* WebbOperation */; case "ANTI_IMPLIES" /* AntiImplies */: return "!=>" /* AntiImplication */; case "REVERSED_ANTI_IMPLIES" /* ReversedAntiImplies */: return "!<=" /* ReversedAntiImplication */; case "CONTRADICTION" /* Contradiction */: return "#" /* Contradiction */; case "TAUTOLOGY" /* Tautology */: return "@" /* Tautology */; default: throw new Error(`Cannot convert operator "${operator}" to a glyph.`); } } // src/tokenizer/tokenize-string.ts function tokenizeString(input) { if (!input.length) return []; const glyphs = Object.values(Glyph).sort((a, b) => b.length - a.length); const glyphPattern = glyphs.map((g) => g.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`)).join("|"); const variablePattern = "[a-zA-Z]+"; const tokenizer = new RegExp(`(${glyphPattern})|(${variablePattern})`, "g"); const tokens = []; let match = tokenizer.exec(input); while (match !== null) { tokens.push(match[0]); match = tokenizer.exec(input); } if (!tokens.length || tokens.join("") !== input.replaceAll(/\s+/g, "")) { throw new Error(`Invalid character(s) found in input: "${input}".`); } return tokens; } // src/propositional/builders/create-prop-symbol.ts function createPropSymbol(char, position) { const knownGlyphs = Object.values(Glyph); const onlyLatinLetters = /^[a-zA-Z]+$/; if (char === "(" /* OpenParenthesis */ || char === ")" /* CloseParenthesis */) { return { position, atom: [char], type: "parenthesis" /* Parenthesis */, view: getGlyphUnicode(char) }; } else if (knownGlyphs.includes(char)) { return { position, atom: [char], type: "operator" /* Operator */, view: getGlyphUnicode(char) }; } else if (onlyLatinLetters.test(char)) { const firstLetter = char[0].toLowerCase(); return { position, atom: [char], type: "variable" /* Variable */, view: firstLetter }; } else { throw new Error( `Cannot create a propositional symbol from the character "${char}".` ); } } // src/propositional/builders/create-prop-expression.ts function createPropExpression(input) { const tokens = tokenizeString(input); return tokens.map((token, index) => createPropSymbol(token, index)); } // src/propositional/validators/is-well-formed-formula.ts function isWellFormedFormula(expression) { if (expression.length === 0) return false; let index = 0; function parseWFF() { if (isEndOfExpression()) return false; if (isVariable(expression[index])) { return parseVariable2(); } if (isNegation(expression[index])) { return parseNegation2(); } if (isParenthesizedExpression(expression[index])) { return parseParenthesizedExpression(); } return false; } function parseVariable2() { index++; return true; } function parseNegation2() { index++; return parseWFF(); } function parseParenthesizedExpression() { index++; if (!parseWFF()) return false; if (isEndOfExpression() || !isBinaryOperator(expression[index])) return false; index++; if (!parseWFF()) return false; if (isEndOfExpression() || !isClosingParenthesis(expression[index])) return false; index++; return true; } function isEndOfExpression() { return index >= expression.length; } const result = parseWFF(); return result && index === expression.length; } function isVariable(symbol) { return symbol.type === "variable" /* Variable */; } function isNegation(symbol) { return symbol.atom[0] === "~" /* Negation */; } function isParenthesizedExpression(symbol) { return symbol.atom[0] === "(" /* OpenParenthesis */; } function isBinaryOperator(symbol) { return symbol.type === "operator" /* Operator */ && symbol.atom[0] !== "~" /* Negation */; } function isClosingParenthesis(symbol) { return symbol.atom[0] === ")" /* CloseParenthesis */; } // src/propositional/builders/create-prop-formula.ts function createPropFormula(expression) { if (!isWellFormedFormula(expression)) { throw new Error( "Invalid propositional expression: Not a well-formed formula (WFF)." ); } return parseExpression({ expression, start: 0, end: expression.length - 1 }); } function parseExpression({ expression, start, end }) { if (start > end) { throw new Error( `Unexpected expression boundaries: start=${start}, end=${end}` ); } if (isSingleVariable(expression, start, end)) { return parseVariable(expression[start]); } if (isNegation2(expression, start)) { return parseNegation(expression, start, end); } if (isParenthesized(expression, start, end)) { return parseBinaryExpression(expression, start, end); } throw new Error("Invalid formula structure."); } function isSingleVariable(expression, start, end) { return start === end && expression[start].type === "variable" /* Variable */; } function parseVariable(symbol) { return { operator: "VAR" /* Var */, values: symbol.atom }; } function isNegation2(expression, start) { return expression[start].atom[0] === "~" /* Negation */; } function parseNegation(expression, start, end) { return { operator: "NOT" /* Not */, values: [parseExpression({ expression, start: start + 1, end })] }; } function isParenthesized(expression, start, end) { return expression[start].atom[0] === "(" /* OpenParenthesis */ && expression[end].atom[0] === ")" /* CloseParenthesis */; } function parseBinaryExpression(expression, start, end) { const mainOperatorIndex = findMainOperator(expression, start, end); if (mainOperatorIndex === -1) { throw new Error("Could not determine the main operator."); } return { operator: createOperator(expression[mainOperatorIndex]), values: [ parseExpression({ expression, start: start + 1, end: mainOperatorIndex - 1 }), parseExpression({ expression, start: mainOperatorIndex + 1, end: end - 1 }) ] }; } function findMainOperator(expression, start, end) { let balance = 0; for (let i = start; i <= end; i++) { const symbol = expression[i]; if (symbol.atom[0] === "(" /* OpenParenthesis */) balance++; if (symbol.atom[0] === ")" /* CloseParenthesis */) balance--; if (balance === 1 && symbol.type === "operator" /* Operator */ && symbol.atom[0] !== "~" /* Negation */) { return i; } } return -1; } // src/propositional/converters/convert-prop-formula-to-expression.ts function convertPropFormulaToExpression(formula) { const expression = []; let position = 0; function traverse(node) { const { operator, values } = node; if (operator === "VAR" /* Var */) { expression.push(createPropSymbol(values[0], position++)); return; } expression.push(createPropSymbol("(", position++)); if (operator === "NOT" /* Not */) { expression.push(createPropSymbol(getOperatorGlyph(operator), position++)); traverse(values[0]); } else { const [left, right] = values; traverse(left); expression.push(createPropSymbol(getOperatorGlyph(operator), position++)); traverse(right); } expression.push(createPropSymbol(")", position++)); } traverse(formula); return expression; } // src/propositional/converters/convert-prop-formula-to-string.ts function convertPropFormulaToString(formula) { if (formula.operator === "VAR" /* Var */) { return formula.values[0]; } const glyph = getGlyphUnicode(getOperatorGlyph(formula.operator)); const subFormulas = formula.values; const values = subFormulas.map(convertPropFormulaToString); if (formula.operator === "NOT" /* Not */) { return `${glyph}${values[0]}`; } const glyphSpace = ` ${glyph} `; return `(${values.join(glyphSpace)})`; } // src/propositional/converters/extract-prop-sub-formulas.ts function extractPropSubFormulas(formula) { if (formula.operator === "VAR" /* Var */) return []; const subFormulas = /* @__PURE__ */ new Set(); const result = []; function traverse(subFormula) { if (subFormula.operator === "VAR" /* Var */) { return; } const key = JSON.stringify(subFormula); if (!subFormulas.has(key)) { subFormulas.add(key); result.push(subFormula); } if (Array.isArray(subFormula.values)) { for (const value of subFormula.values) { traverse(value); } } } if (Array.isArray(formula.values)) { for (const value of formula.values) { traverse(value); } } return result; } // src/propositional/converters/extract-prop-variables.ts function extractPropVariables(formula) { const variablesSet = /* @__PURE__ */ new Set(); function traverse(node) { if (node.operator === "VAR" /* Var */) { variablesSet.add(node.values[0]); return; } if (Array.isArray(node.values)) { const subFormulas = node.values; for (const subFormula of subFormulas) { traverse(subFormula); } } } traverse(formula); const sortedVariables = Array.from(variablesSet).sort( (a, b) => a.localeCompare(b) ); return new Map(sortedVariables.map((varName, index) => [index, [varName]])); } // src/propositional/converters/replace-atom-in-formula.ts function replaceAtomInFormula({ formula, atom, substitute }) { function traverse(node) { if (node.operator === "VAR" /* Var */) { const nodeAtom = node.values; if (nodeAtom[0] === atom[0]) { if (Array.isArray(substitute) && substitute.length === 1 && typeof substitute[0] === "string") { return { operator: "VAR" /* Var */, values: substitute }; } else { return substitute; } } return node; } if (Array.isArray(node.values)) { const subFormulas = node.values; const newValues = subFormulas.map((subFormula) => traverse(subFormula)); return { operator: node.operator, values: newValues }; } return node; } return traverse(formula); } // src/propositional/evaluators/get-binary-operation-value.ts function getBinaryOperationValue({ operator, leftOperand, rightOperand }) { switch (operator) { case "AND" /* And */: return leftOperand && rightOperand; case "OR" /* Or */: return leftOperand || rightOperand; case "IMPLIES" /* Implies */: return !leftOperand || rightOperand; case "REVERSED_IMPLIES" /* ReversedImplies */: return !rightOperand || leftOperand; case "EQUIV" /* Equiv */: return leftOperand === rightOperand; case "XOR" /* Xor */: return leftOperand !== rightOperand; case "NAND" /* Nand */: return !(leftOperand && rightOperand); case "NOR" /* Nor */: return !(leftOperand || rightOperand); case "ANTI_IMPLIES" /* AntiImplies */: return leftOperand && !rightOperand; case "REVERSED_ANTI_IMPLIES" /* ReversedAntiImplies */: return rightOperand && !leftOperand; case "CONTRADICTION" /* Contradiction */: return false; case "TAUTOLOGY" /* Tautology */: return true; case "VAR" /* Var */: case "NOT" /* Not */: throw new Error(`Operator "${operator}" is not a binary operator.`); default: throw new Error(`Unknown operator: "${operator}".`); } } // src/propositional/evaluators/get-unary-operation-value.ts function getUnaryOperationValue({ operator, operand }) { switch (operator) { case "VAR" /* Var */: return operand; // A variable simply retains its boolean value. case "NOT" /* Not */: return !operand; // Logical negation. default: throw new Error(`Operator "${operator}" is not a valid unary operator.`); } } // src/propositional/evaluators/calculate-prop-formula.ts function calculatePropFormula({ formula, assignment, variablesMap }) { const variables = variablesMap ?? extractPropVariables(formula); if (variables.size !== assignment.length) { throw new Error( `Mismatch between formula variables (${variables.size}) and assignment length (${assignment.length}).` ); } const variableValues = /* @__PURE__ */ new Map(); variables.forEach((atom, index) => { variableValues.set(atom[0], assignment[index]); }); function evaluate(node) { if (node.operator === "VAR" /* Var */) { return !!variableValues.get(node.values[0]); } if (node.operator === "NOT" /* Not */) { const operand = node.values[0]; return getUnaryOperationValue({ operator: node.operator, operand: evaluate(operand) }); } const [left, right] = node.values; return getBinaryOperationValue({ operator: node.operator, leftOperand: evaluate(left), rightOperand: evaluate(right) }); } return evaluate(formula); } // src/propositional/hilbert-calculus/axioms/implication-distribution.ts function implicationDistributionSchema(formulas) { const [A, B, C] = formulas; return { operator: "IMPLIES" /* Implies */, values: [ { operator: "IMPLIES" /* Implies */, values: [A, { operator: "IMPLIES" /* Implies */, values: [B, C] }] }, { operator: "IMPLIES" /* Implies */, values: [ { operator: "IMPLIES" /* Implies */, values: [A, B] }, { operator: "IMPLIES" /* Implies */, values: [A, C] } ] } ] }; } // src/propositional/hilbert-calculus/axioms/implication-introduction.ts function implicationIntroductionSchema(formulas) { const [A, B] = formulas; return { operator: "IMPLIES" /* Implies */, values: [ A, { operator: "IMPLIES" /* Implies */, values: [B, A] } ] }; } // src/propositional/hilbert-calculus/axioms/implication-reversal.ts function implicationReversalSchema(formulas) { const [A, B] = formulas; return { operator: "IMPLIES" /* Implies */, values: [ { operator: "IMPLIES" /* Implies */, values: [ { operator: "NOT" /* Not */, values: [A] }, { operator: "NOT" /* Not */, values: [B] } ] }, { operator: "IMPLIES" /* Implies */, values: [B, A] } ] }; } // src/propositional/hilbert-calculus/axioms/index.ts var HilbertAxioms = Object.freeze({ II: implicationIntroductionSchema, ID: implicationDistributionSchema, IR: implicationReversalSchema }); // src/propositional/validators/are-prop-formulas-structurally-equal.ts function arePropFormulasStructurallyEqual(formulas) { if (!formulas.length) return false; const strings = formulas.map((formula) => JSON.stringify(formula)); return strings.every((item) => item === strings[0]); } // src/propositional/validators/is-conjunction-elimination-applicable.ts function isConjunctionEliminationApplicable(formulas) { if (formulas.length === 0) { return false; } return formulas.every((formula) => formula.operator === "AND" /* And */); } // src/propositional/validators/is-conjunction-introduction-applicable.ts function isConjunctionIntroductionApplicable(formulas) { return formulas.length === 2; } // src/propositional/validators/is-disjunction-elimination-applicable.ts function isDisjunctionEliminationApplicable(formulas) { if (formulas.length !== 3) return false; const [formula1, formula2, formula3] = formulas; let disjunction = null; let implication1 = null; let implication2 = null; for (const formula of [formula1, formula2, formula3]) { const isValidDisjunction = formula.operator === "OR" /* Or */ && Array.isArray(formula.values) && formula.values.length === 2; const isValidImplication = formula.operator === "IMPLIES" /* Implies */ && Array.isArray(formula.values) && formula.values.length === 2; const isImplication1Missing = !implication1; if (isValidDisjunction) { disjunction = formula; } else if (isValidImplication) { if (isImplication1Missing) { implication1 = formula; } else { implication2 = formula; } } } if (!disjunction || !implication1 || !implication2) { return false; } const [disjunct1, disjunct2] = disjunction.values; const [antecedent1, consequent1] = implication1.values; const [antecedent2, consequent2] = implication2.values; if (!arePropFormulasStructurallyEqual([consequent1, consequent2])) { return false; } return arePropFormulasStructurallyEqual([disjunct1, antecedent1]) && arePropFormulasStructurallyEqual([disjunct2, antecedent2]) || arePropFormulasStructurallyEqual([disjunct1, antecedent2]) && arePropFormulasStructurallyEqual([disjunct2, antecedent1]); } // src/propositional/validators/is-disjunction-introduction-applicable.ts function isDisjunctionIntroductionApplicable(formulas) { return formulas.length === 2; } // src/propositional/validators/is-equivalence-elimination-applicable.ts function isEquivalenceEliminationApplicable(formulas) { if (formulas.length === 0) { return false; } return formulas.every((formula) => formula.operator === "EQUIV" /* Equiv */); } // src/propositional/validators/is-equivalence-introduction-applicable.ts function isEquivalenceIntroductionApplicable(formulas) { if (formulas.length !== 2) { return false; } const [formula1, formula2] = formulas; if (formula1.operator !== "IMPLIES" /* Implies */ || formula2.operator !== "IMPLIES" /* Implies */) { return false; } const [antecedent1, consequent1] = formula1.values; const [antecedent2, consequent2] = formula2.values; return arePropFormulasStructurallyEqual([antecedent1, consequent2]) && arePropFormulasStructurallyEqual([antecedent2, consequent1]); } // src/propositional/validators/is-implication-distribution-applicable.ts function isImplicationDistributionSchema(formula) { if (formula.operator !== "IMPLIES" /* Implies */) { return false; } if (!Array.isArray(formula.values) || formula.values.length !== 2) { return false; } const consequent = formula.values[1]; if (!Array.isArray(consequent.values) || consequent.operator !== "IMPLIES" /* Implies */ || consequent.values.length !== 2) { return false; } return true; } function isImplicationDistributionApplicable(formulas) { if (formulas.length === 0) { return false; } return formulas.every(isImplicationDistributionSchema); } // src/propositional/validators/is-implication-elimination-applicable.ts function isImplicationEliminationApplicable(formulas) { if (formulas.length !== 2) return false; const [formula1, formula2] = formulas; const checkImplication = (implication, antecedent) => implication.operator === "IMPLIES" /* Implies */ && Array.isArray(implication.values) && implication.values.length === 2 && arePropFormulasStructurallyEqual([implication.values[0], antecedent]); return checkImplication(formula1, formula2) || checkImplication(formula2, formula1); } // src/propositional/validators/is-implication-introduction-applicable.ts function isImplicationIntroductionApplicable(formulas) { return formulas.length === 2; } // src/propositional/validators/is-implication-reversal-applicable.ts function isImplicationReversalSchema(formula) { if (formula.operator !== "IMPLIES" /* Implies */) { return false; } if (!Array.isArray(formula.values) || formula.values.length !== 2) { return false; } const antecedent = formula.values[0]; const consequent = formula.values[1]; if (!Array.isArray(antecedent.values) || antecedent.operator !== "NOT" /* Not */ || antecedent.values.length !== 1) { return false; } if (!Array.isArray(consequent.values) || consequent.operator !== "NOT" /* Not */ || consequent.values.length !== 1) { return false; } return true; } function isImplicationReversalApplicable(formulas) { if (formulas.length === 0) { return false; } return formulas.every(isImplicationReversalSchema); } // src/propositional/validators/is-negation-elimination-applicable.ts function isNegationEliminationApplicable(formulas) { if (formulas.length === 0) { return false; } return formulas.every( (formula) => formula.operator === "NOT" /* Not */ && Array.isArray(formula.values) && formula.values.length === 1 && formula.values[0].operator === "NOT" /* Not */ ); } // src/propositional/validators/is-negation-introduction-applicable.ts function isNegationIntroductionApplicable(formulas) { if (formulas.length !== 2) { return false; } const [formula1, formula2] = formulas; if (formula1.operator !== "IMPLIES" /* Implies */ || formula2.operator !== "IMPLIES" /* Implies */) { return false; } const [antecedent1, consequent1] = formula1.values; const [antecedent2, consequent2] = formula2.values; if (!arePropFormulasStructurallyEqual([antecedent1, antecedent2])) { return false; } return consequent1.operator === "NOT" /* Not */ && arePropFormulasStructurallyEqual([ consequent1.values[0], consequent2 ]) || consequent2.operator === "NOT" /* Not */ && arePropFormulasStructurallyEqual([ consequent2.values[0], consequent1 ]); } // src/propositional/validators/validate-prop-formulas.ts var PROP_FORMULA_CHECKS = { ["areEqual" /* areEqual */]: arePropFormulasStructurallyEqual, // Elimination rules ["isIE" /* isIE */]: isImplicationEliminationApplicable, ["isDE" /* isDE */]: isDisjunctionEliminationApplicable, ["isCE" /* isCE */]: isConjunctionEliminationApplicable, ["isEE" /* isEE */]: isEquivalenceEliminationApplicable, ["isNE" /* isNE */]: isNegationEliminationApplicable, // Introduction rules ["isDI" /* isDI */]: isDisjunctionIntroductionApplicable, ["isCI" /* isCI */]: isConjunctionIntroductionApplicable, ["isEI" /* isEI */]: isEquivalenceIntroductionApplicable, ["isNI" /* isNI */]: isNegationIntroductionApplicable, ["isII" /* isII */]: isImplicationIntroductionApplicable, // Other rules ["isID" /* isID */]: isImplicationDistributionApplicable, ["isIR" /* isIR */]: isImplicationReversalApplicable }; function validatePropFormulas(formulas, checks = Object.keys( PropFormulaCheck )) { return checks.reduce((results, checkName) => { const checkFunction = PROP_FORMULA_CHECKS[checkName]; results[checkName] = checkFunction ? checkFunction(formulas) : false; return results; }, {}); } // src/propositional/hilbert-calculus/rules/implication-distribution.ts function implicationDistributionRule(formulas) { if (!isImplicationDistributionApplicable(formulas)) { throw new Error( "Implication distribution requires each formula to have the form F => (G => H)." ); } return formulas.map((formula) => { const F = formula.values[0]; const consequent = formula.values[1]; const G = consequent.values[0]; const H = consequent.values[1]; return { operator: "IMPLIES" /* Implies */, values: [ { operator: "IMPLIES" /* Implies */, values: [F, G] }, { operator: "IMPLIES" /* Implies */, values: [F, H] } ] }; }); } // src/propositional/hilbert-calculus/rules/implication-elimination.ts function implicationEliminationRule(formulas) { if (!isImplicationEliminationApplicable(formulas)) { throw new Error( "Implication elimination is not applicable to the given formulas." ); } const [formula1, formula2] = formulas; let implicationFormula; if (formula1.operator === "IMPLIES" /* Implies */ && Array.isArray(formula1.values) && formula1.values.length === 2 && arePropFormulasStructurallyEqual([formula1.values[0], formula2])) { implicationFormula = formula1; } else if (formula2.operator === "IMPLIES" /* Implies */ && Array.isArray(formula2.values) && formula2.values.length === 2 && arePropFormulasStructurallyEqual([formula2.values[0], formula1])) { implicationFormula = formula2; } return [implicationFormula?.values[1]]; } // src/propositional/hilbert-calculus/rules/implication-introduction.ts function implicationIntroductionRule(formulas) { if (!isImplicationIntroductionApplicable(formulas)) { throw new Error( "Implication introduction requires exactly two formulas: the proven formula and the new antecedent formula." ); } const [provenFormula, newFormula] = formulas; return [ { operator: "IMPLIES" /* Implies */, values: [newFormula, provenFormula] } ]; } // src/propositional/hilbert-calculus/rules/implication-reversal.ts function implicationReversalRule(formulas) { if (!isImplicationReversalApplicable(formulas)) { throw new Error( "Implication reversal requires each formula to have the form \xACF => \xACG." ); } return formulas.map((formula) => { const antecedent = formula.values[0]; const consequent = formula.values[1]; const F = antecedent.values[0]; const G = consequent.values[0]; return { operator: "IMPLIES" /* Implies */, values: [G, F] }; }); } // src/propositional/hilbert-calculus/generators/generate-hilbert-proof-steps.ts function generateHilbertProofSteps(input) { const { index, step } = input; if (step === "Derivation" /* Derivation */) { return buildDerivedSteps(index, input.payload); } if (step === "Axiom" /* Axiom */) { return buildAxiomStep(index, input.payload); } return buildBaseStep(index, step, input.payload); } function buildDerivedSteps(index, payload) { const { formulas, rule, derivedFrom } = payload; const derivedFormulas = getRuleFunction(rule)(formulas); return derivedFormulas.map((formula, derivedIndex) => { return { index: index + derivedIndex, step: "Derivation" /* Derivation */, formula, stringView: convertPropFormulaToString(formula), expression: convertPropFormulaToExpression(formula), comment: `${rule}: ${derivedFrom.join(", ")}`, derivedFrom }; }); } function buildAxiomStep(index, payload) { const { formulas, schema } = payload; const formula = getSchemaFunction(schema)(formulas); return [ { index, step: "Axiom" /* Axiom */, formula, stringView: convertPropFormulaToString(formula), expression: convertPropFormulaToExpression(formula), comment: `${schema}` } ]; } function buildBaseStep(index, step, payload) { return [ { index, step, formula: payload.formula, stringView: convertPropFormulaToString(payload.formula), expression: convertPropFormulaToExpression(payload.formula), comment: `${step}` } ]; } function getSchemaFunction(schema) { switch (schema) { case "II" /* II */: return implicationIntroductionSchema; case "ID" /* ID */: return implicationDistributionSchema; case "IR" /* IR */: return implicationReversalSchema; } } function getRuleFunction(rule) { switch (rule) { case "II" /* II */: return implicationIntroductionRule; case "ID" /* ID */: return implicationDistributionRule; case "IR" /* IR */: return implicationReversalRule; case "IE" /* IE */: return implicationEliminationRule; } } // src/propositional/hilbert-calculus/classes/hilbert-proof.ts var HilbertProof = class { /** * Creates a new Hilbert proof with a goal formula. * @param goal - The target formula to prove */ constructor(goal) { this.steps = []; this.goal = goal; } /** * Gets all proof steps in order. * @returns Array of proof steps */ getSteps() { return Object.freeze([...this.steps]); } /** * Gets the goal formula of this proof. * @returns The target formula */ getGoal() { return this.goal; } /** * Gets the number of steps in the proof. * @returns The current step count */ getStepCount() { return this.steps.length; } /** * Gets a specific step by index (1-based). * @param index - The step number (1-based) * @returns The proof step, or undefined if not found */ getStep(index) { return this.steps[index - 1]; } /** * Adds a premise (given assumption) to the proof. * @param formula - The premise formula * @param comment - Optional explanation for the premise * @returns The added proof step */ addPremise(formula, comment) { const steps = generateHilbertProofSteps({ index: this.steps.length + 1, step: "Premise" /* Premise */, payload: { formula } }); const step = steps[0]; if (comment) { step.comment = comment; } this.steps.push(step); return step; } /** * Adds an axiom step to the proof. * @param payload - The axiom payload containing formulas and schema * @param comment - Optional explanation for the axiom * @returns The added proof step */ addAxiom(payload, comment) { const steps = generateHilbertProofSteps({ index: this.steps.length + 1, step: "Axiom" /* Axiom */, payload }); const step = steps[0]; if (comment) { step.comment = comment; } this.steps.push(step); return step; } /** * Adds a derived step to the proof using a Hilbert calculus rule. * @param payload - The derived step payload containing formulas, schema, and step references * @param comment - Optional explanation for the derivation * @returns The added proof step */ addDerivedStep(payload, comment) { const newSteps = generateHilbertProofSteps({ index: this.steps.length + 1, step: "Derivation" /* Derivation */, payload }); newSteps.forEach((step) => { if (comment) { step.comment = comment; } this.steps.push(step); }); return newSteps; } /** * Checks if the proof is complete (last step matches the goal). * @returns True if the last step's formula matches the goal */ isComplete() { if (this.steps.length === 0) { return false; } if (this.steps.every((step) => step.step === "Premise" /* Premise */)) { return false; } const lastStep = this.getLastStep(); return arePropFormulasStructurallyEqual([lastStep.formula, this.goal]); } /** * Gets the last step in the proof (which should be the goal). * @returns The final proof step, or undefined if no steps exist */ getLastStep() { return this.steps.at(-1); } /** * Reiterates (repeats) a previously proved step. * Allows referring to a formula from an earlier step in the proof. * @param fromIndex - The index of the step to reiterate (1-based) * @param comment - Optional explanation for the reiteration * @returns The added reiteration step * @throws {Error} if the step index is invalid */ reiterateStep(fromIndex, comment) { const sourceStep = this.getStep(fromIndex); if (!sourceStep) { throw new Error(`Cannot reiterate: step ${fromIndex} not found in proof`); } const steps = generateHilbertProofSteps({ index: this.steps.length + 1, step: "Reiteration" /* Reiteration */, payload: { formula: sourceStep.formula } }); const step = steps[0]; if (comment) { step.comment = comment; } else { step.comment = `Reiteration: ${fromIndex}`; } step.derivedFrom = [fromIndex]; this.steps.push(step); return step; } /** * Clears all steps from the proof. */ clear() { this.steps = []; } /** * Replaces all occurrences of an atom with a formula or atom in all proof steps. * The goal formula is not modified. * * @param atom - The atomic proposition to replace * @param substitute - The formula or atom to substitute */ replace(atom, substitute) { this.steps.forEach((step) => { const newFormula = replaceAtomInFormula({ formula: step.formula, atom, substitute }); step.formula = newFormula; step.expression = convertPropFormulaToExpression(newFormula); step.stringView = convertPropFormulaToString(newFormula); }); } }; // src/propositional/hilbert-calculus/classes/hilbert-proof-builder.ts var HilbertProofBuilder = class { /** * Creates a new proof builder with a goal formula. * @param goal - The target formula to prove */ constructor(goal) { this.proof = new HilbertProof(goal); } /** * Adds a premise (given assumption) to the proof. * @param formula - The premise formula * @param comment - Optional explanation for the premise * @returns This builder instance for chaining */ addPremise(formula, comment) { this.proof.addPremise(formula, comment); return this; } /** * Adds an axiom step to the proof. * @param payload - The axiom payload containing formulas and schema * @param comment - Optional explanation for the axiom * @returns This builder instance for chaining */ addAxiom(payload, comment) { this.proof.addAxiom(payload, comment); return this; } /** * Adds a derived step to the proof using a Hilbert calculus rule. * @param payload - The derived step payload containing formulas, schema, and step references * @param comment - Optional explanation for the derivation * @returns This builder instance for chaining */ addDerivedStep(payload, comment) { this.proof.addDerivedStep(payload, comment); return this; } /** * Reiterates (repeats) a previously proved step. * Allows referring to a formula from an earlier step in the proof. * @param fromIndex - The index of the step to reiterate (1-based) * @param comment - Optional explanation for the reiteration * @returns This builder instance for chaining */ reiterateStep(fromIndex, comment) { this.proof.reiterateStep(fromIndex, comment); return this; } /** * Replaces all occurrences of an atom with a formula or atom in all proof steps. * The goal formula is not modified. * * @param atom - The atomic proposition to replace * @param substitute - The formula or atom to substitute * @returns This builder instance for chaining */ replace(atom, substitute) { this.proof.replace(atom, substitute); return this; } /** * Constructs the proof and returns it. * @returns The completed HilbertProof instance */ build() { return this.proof; } /** * Adds multiple steps in sequence using a callback function. * Useful for building complex proofs programmatically. * * @param stepsFn - A callback that receives the current builder and adds steps * @returns This builder instance for chaining * * @example * ```typescript * proof.buildSteps((builder) => { * builder.addPremise(p); * builder.addAxiom(axiom1); * builder.addDerivedStep(derived1); * }); * ``` */ buildSteps(stepsFn) { stepsFn(this); return this; } /** * Gets the current state of the proof without building. * Useful for inspection during construction. * @returns The current HilbertProof instance */ preview() { return this.proof; } }; // src/propositional/hilbert-calculus/generators/build-hilbert-proof.ts function buildHilbertProof(goal) { return new HilbertProofBuilder(goal); } // src/propositional/hilbert-calculus/generators/compose-hilbert-proof.ts function composeHilbertProof(goal, ...stepGenerators) { const builder = buildHilbertProof(goal); for (const generator of stepGenerators) { generator(builder); } return builder.build(); } // src/propositional/hilbert-calculus/rules/index.ts var HilbertRules = Object.freeze({ II: implicationIntroductionRule, ID: implicationDistributionRule, IE: implicationEliminationRule, IR: implicationReversalRule }); // src/propositional/natural-calculus/rules/conjunction-elimination.ts function conjunctionElimination(formulas) { if (!isConjunctionEliminationApplicable(formulas)) { throw new Error( "Conjunction Elimination is not applicable for the given formulas." ); } return formulas.flatMap((formula) => { const conjunct1 = formula.values[0]; const conjunct2 = formula.values[1]; return [conjunct1, conjunct2]; }); } // src/propositional/natural-calculus/rules/conjunction-introduction.ts function conjunctionIntroduction(formulas) { if (!isConjunctionIntroductionApplicable(formulas)) { throw new Error( "Conjunction introduction is not applicable to the given formulas." ); } const conjunct1 = formulas[0]; const conjunct2 = formulas[1]; return [ { operator: "AND" /* And */, values: [conjunct1, conjunct2] }, { operator: "AND" /* And */, values: [conjunct2, conjunct1] } ]; } // src/propositional/natural-calculus/rules/disjunction-elimination.ts function disjunctionElimination(formulas) { if (!isDisjunctionEliminationApplicable(formulas)) { throw new Error( "Disjunction elimination is not applicable to the given formulas." ); } const implication1 = formulas.find( (formula) => formula.operator === "IMPLIES" /* Implies */ ); return [implication1?.values[1]]; } // src/propositional/natural-calculus/rules/disjunction-introduction.ts function disjunctionIntroduction(formulas) { if (!isDisjunctionIntroductionApplicable(formulas)) { throw new Error( "Disjunction introduction is not applicable to the given formulas." ); } const disjunct1 = formulas[0]; const disjunct2 = formulas[1]; return [ { operator: "OR" /* Or */, values: [disjunct1, disjunct2] }, { operator: "OR" /* Or */, values: [disjunct2, disjunct1] } ]; } // src/propositional/natural-calculus/rules/equivalence-elimination.ts function equivalenceElimination(formulas) { if (!isEquivalenceEliminationApplicable(formulas)) { throw new Error( "Equivalence elimination is not applicable. All formulas must be equivalences." ); } return formulas.flatMap((formula) => { const [A, B] = formula.values; return [ { operator: "IMPLIES" /* Implies */, values: [A, B] }, { operator: "IMPLIES" /* Implies */, values: [B, A] } ]; }); } // src/propositional/natural-calculus/rules/equivalence-introduction.ts function equivalenceIntroduction(formulas) { if (!isEquivalenceIntroductionApplicable(formulas)) { throw new Error( "Equivalence introduction is not applicable to the given formulas." ); } const [implication1, implication2] = formulas; const firstAntecedent = implication1.values[0]; const secondAntecedent = implication2.values[0]; return [ { operator: "EQUIV" /* Equiv */, values: [firstAntecedent, secondAntecedent] } ]; } // src/propositional/natural-calculus/rules/implication-elimination.ts function implicationElimination(formulas) { if (!isImplicationEliminationApplicable(formulas)) { throw new Error( "Implication elimination is not applicable to the given formulas." ); } const implicationFormula = formulas.find( (f) => f.operator === "IMPLIES" /* Implies */ ); return [implicationFormula?.values[1]]; } // src/propositional/natural-calculus/rules/implication-introduction.ts function implicationIntroduction(formulas) { if (!isImplicationIntroductionApplicable(formulas)) { throw new Error( "Implication introduction is not applicable to the given formulas." ); } const [premise, conclusion] = formulas; return [{ operator: "IMPLIES" /* Implies */, values: [premise, conclusion] }]; } // src/propositional/natural-calculus/rules/negation-elimination.ts function negationElimination(formulas) { if (!isNegationEliminationApplicable(formulas)) { throw new Error( "Negation elimination is not applicable to the given formulas." ); } const firstNegationFormula = formulas[0]; const secondNegationFormula = firstNegationFormula.values[0]; return [secondNegationFormula.values[0]]; } // src/propositional/natural-calculus/rules/negation-introduction.ts function negationIntroduction(formulas) { if (!isNegationIntroductionApplicable(formulas)) { throw new Error( "Negation introduction is not applicable to the given formulas." ); } const antecedent = formulas[0].values[0]; return [ { operator: "NOT" /* Not */, values: [antecedent] } ]; } // src/propositional/natural-calculus/generators/generate-natural-proof-steps.ts function generateNaturalProofSteps(input) { const { index, level, step, assumptionIndex } = input; if (step === "Derivation" /* Derivation */) { return buildDerivedSteps2({ index, level, assumptionIndex, payload: input.payload }); } return [ buildBaseStep2({ index, level, step, assumptionIndex, payload: input.payload }) ]; } function buildDerivedSteps2({ index, level, payload, assumptionIndex }) { const { formulas, rule, derivedFrom } = payload; const derivedFormulas = getRuleFunction2(rule)(formulas); return derivedFormulas.map((formula, idx) => ({ index: index + idx + 1, level, step: "Derivation" /* Derivation */, formula, assumptionIndex, stringView: convertPropFormulaToString(formula), expression: convertPropFormulaToExpression(formula), comment: `${rule}: ${derivedFrom.join(", ")}`, derivedFrom })); } function buildBaseStep2({ index, level, step, payload, assumptionIndex }) { return { index, level, step, assumptionIndex, formula: payload.formula, stringView: convertPropFormulaToString(payload.formula), expression: convertPropFormulaToExpression(payload.formula), comment: `${step}` }; } function getRuleFunction2(rule) { switch (rule) { // Introduction rules case "CI" /* CI */: return conjunctionIntroduction; case "DI" /* DI */: return disjunctionIntroduction; case "II" /* II */: return implicationIntroduction; case "EI" /* EI */: return equivalenceIntroduction; case "NI" /* NI */: return negationIntroduction; // Elimination rules case "CE" /* CE */: return conjunctionElimination; case "DE" /* DE */: return disjunctionElimination; case "IE" /* IE */: return implicationElimination; case "EE" /* EE */: return equivalenceElimination; case "NE" /* NE */: return negationElimination; } } // src/propositional/natural-calculus/classes/natural-proof.ts var NaturalProof = class { /** * Creates a new Natural Deduction proof with a goal formula. * @param goal - The target formula to prove */