propositional
Version:
Propositional logic symbolic computation library
163 lines (162 loc) • 6.36 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.simplify = void 0;
const AST = __importStar(require("../syntax/ast"));
const token_1 = require("../syntax/token");
const generate_1 = require("../syntax/generate");
const equivalence_1 = require("../syntax/equivalence");
/**
* Simplify an expression under the following principles:
* - !0 <=> 1
* - !1 <=> 0
*
* - !!a <=> a
*
* - (a & a) <=> a
* - (a | a) <=> a
* - (a ^ a) <=> 0
* - (a => a) <=> 1
* - (a <=> a) <=> 1
*
* - (a & !a) <=> 0
* - (a | !a) <=> 1
* - (a ^ !a) <=> 1
* - (a <=> !a) <=> 0
*
* - (a => !a) <=> !a
* - (!a => a) <=> a
*
* - (0 & a) <=> 0
* - (0 | a) <=> a
* - (0 ^ a) <=> a
* - (0 => a) <=> 1
* - (0 <=> a) <=> !a
*
* - (1 & a) <=> a
* - (1 | a) <=> 1
* - (1 ^ a) <=> !a
* - (1 => a) <=> a
* - (1 <=> a) <=> a
*
* - (a => 0) <=> !a
* - (a => 1) <=> 1
*/
function simplify(expression) {
switch (true) {
case expression instanceof AST.UnaryExpression:
let inner = simplify(expression.inner);
// !0, !1
if (inner instanceof AST.Literal && inner.value.type == token_1.TokenType.CONSTANT) {
if ((0, equivalence_1.syntacticallyEquivalent)(inner, generate_1.FALSE)) {
return generate_1.TRUE;
}
else {
return generate_1.FALSE;
}
}
// !!a <=> a
if (inner instanceof AST.UnaryExpression) {
return simplify(inner.inner);
}
return (0, generate_1.not)(inner);
case expression instanceof AST.Literal:
return expression;
case expression instanceof AST.BinaryExpression:
let left = simplify(expression.left);
let right = simplify(expression.right);
// left == right
if ((0, equivalence_1.syntacticallyEquivalent)(left, right)) {
switch (expression.operator.type) {
case token_1.TokenType.AND:
case token_1.TokenType.OR:
return left;
case token_1.TokenType.XOR:
return generate_1.FALSE;
case token_1.TokenType.IF:
case token_1.TokenType.IFF:
return generate_1.TRUE;
}
}
// !left = right
if ((0, equivalence_1.syntacticallyEquivalent)((0, generate_1.not)(left), right) || (0, equivalence_1.syntacticallyEquivalent)(left, (0, generate_1.not)(right))) {
switch (expression.operator.type) {
case token_1.TokenType.AND:
case token_1.TokenType.IFF:
return generate_1.FALSE;
case token_1.TokenType.OR:
case token_1.TokenType.XOR:
return generate_1.TRUE;
case token_1.TokenType.IF:
return right;
}
}
// Simplify logic for 1s and 0s by swapping right 1s and 0s to the left
if (((0, equivalence_1.syntacticallyEquivalent)(right, generate_1.TRUE) || (0, equivalence_1.syntacticallyEquivalent)(right, generate_1.FALSE))
&& expression.operator.type != token_1.TokenType.IF) {
let temp = left;
left = right;
right = temp;
}
// left == 0
if ((0, equivalence_1.syntacticallyEquivalent)(left, generate_1.FALSE)) {
switch (expression.operator.type) {
case token_1.TokenType.AND:
return generate_1.FALSE;
case token_1.TokenType.OR:
case token_1.TokenType.XOR:
return right;
case token_1.TokenType.IF:
return generate_1.TRUE;
case token_1.TokenType.IFF:
return simplify((0, generate_1.not)(right));
}
}
// left == 1
if ((0, equivalence_1.syntacticallyEquivalent)(left, generate_1.TRUE)) {
switch (expression.operator.type) {
case token_1.TokenType.OR:
return generate_1.TRUE;
case token_1.TokenType.XOR:
return simplify((0, generate_1.not)(right));
case token_1.TokenType.AND:
case token_1.TokenType.IF:
case token_1.TokenType.IFF:
return right;
}
}
// a => 0
if ((0, equivalence_1.syntacticallyEquivalent)(right, generate_1.FALSE)) {
return simplify((0, generate_1.not)(left));
}
// a => 1
if ((0, equivalence_1.syntacticallyEquivalent)(right, generate_1.TRUE)) {
return generate_1.TRUE;
}
// Otherwise, no simplification available
return new AST.BinaryExpression(left, expression.operator, right);
}
}
exports.simplify = simplify;