Download src/semantic_engine/boolean_engine.py from Snapkitty/semantic-engine: direct link, hf CLI and curl.
- Browser
- Download file 9.05 kB
-
https://huggingface.co/Snapkitty/semantic-engine/resolve/main/src/semantic_engine/boolean_engine.py
- Command line
-
hf download hf://Snapkitty/semantic-engine/src/semantic_engine/boolean_engine.py
-
curl -L -o boolean_engine.py https://huggingface.co/Snapkitty/semantic-engine/resolve/main/src/semantic_engine/boolean_engine.py
9.05 kB
| # This Source Code Form is subject to the terms of the Mozilla Public | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this | |
| # file, You can obtain one at https://mozilla.org/MPL/2.0/. | |
| """Phase 7: Boolean engine β deterministic normalization to CNF/DNF.""" | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| from typing import Optional, Union | |
| import hashlib | |
| from .types import BooleanOperator, FSMState, PipelineError | |
| # ββ Boolean expression tree βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class BooleanLiteral: | |
| value: bool | |
| def __repr__(self) -> str: | |
| return "β€" if self.value else "β₯" | |
| def negate(self) -> BooleanLiteral: | |
| return BooleanLiteral(not self.value) | |
| class BooleanVar: | |
| name: str | |
| negated: bool = False | |
| def __repr__(self) -> str: | |
| return f"Β¬{self.name}" if self.negated else self.name | |
| def negate(self) -> BooleanVar: | |
| return BooleanVar(self.name, not self.negated) | |
| BooleanAtom = Union[BooleanLiteral, BooleanVar] | |
| class BooleanExpression: | |
| operator: BooleanOperator | |
| operands: list[Union[BooleanExpression, BooleanAtom]] = field(default_factory=list) | |
| constraint_refs: list[str] = field(default_factory=list) | |
| def __repr__(self) -> str: | |
| if self.operator == BooleanOperator.TRUE: | |
| return "β€" | |
| if self.operator == BooleanOperator.FALSE: | |
| return "β₯" | |
| if self.operator == BooleanOperator.NOT: | |
| return f"Β¬({self.operands[0]})" | |
| sym = { | |
| BooleanOperator.AND: "β§", | |
| BooleanOperator.OR: "β¨", | |
| BooleanOperator.XOR: "β", | |
| BooleanOperator.IMPLIES: "β", | |
| BooleanOperator.EQUIVALENCE: "β", | |
| }.get(self.operator, str(self.operator)) | |
| inner = f" {sym} ".join(str(o) for o in self.operands) | |
| return f"({inner})" | |
| def hash(self) -> str: | |
| return hashlib.sha256(repr(self).encode()).hexdigest()[:16] | |
| # ββ Constructors ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def var(name: str, negated: bool = False) -> BooleanVar: | |
| return BooleanVar(name, negated) | |
| def lit(value: bool) -> BooleanLiteral: | |
| return BooleanLiteral(value) | |
| def AND(*args) -> BooleanExpression: | |
| return BooleanExpression(BooleanOperator.AND, list(args)) | |
| def OR(*args) -> BooleanExpression: | |
| return BooleanExpression(BooleanOperator.OR, list(args)) | |
| def NOT(x) -> BooleanExpression: | |
| return BooleanExpression(BooleanOperator.NOT, [x]) | |
| def XOR(a, b) -> BooleanExpression: | |
| return BooleanExpression(BooleanOperator.XOR, [a, b]) | |
| def IMPLIES(a, b) -> BooleanExpression: | |
| return BooleanExpression(BooleanOperator.IMPLIES, [a, b]) | |
| def EQUIV(a, b) -> BooleanExpression: | |
| return BooleanExpression(BooleanOperator.EQUIVALENCE, [a, b]) | |
| # ββ Simplification ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| Expr = Union[BooleanExpression, BooleanAtom] | |
| def simplify(expr: Expr) -> Expr: | |
| """Simplify constants and double negations.""" | |
| if isinstance(expr, (BooleanLiteral, BooleanVar)): | |
| return expr | |
| expr = BooleanExpression(expr.operator, [simplify(o) for o in expr.operands], expr.constraint_refs) | |
| op = expr.operator | |
| # Constant folding | |
| if op == BooleanOperator.NOT: | |
| inner = expr.operands[0] | |
| if isinstance(inner, BooleanLiteral): | |
| return BooleanLiteral(not inner.value) | |
| if isinstance(inner, BooleanVar): | |
| return inner.negate() | |
| if isinstance(inner, BooleanExpression) and inner.operator == BooleanOperator.NOT: | |
| return inner.operands[0] # ¬¬A β A | |
| if op == BooleanOperator.AND: | |
| if any(isinstance(o, BooleanLiteral) and not o.value for o in expr.operands): | |
| return BooleanLiteral(False) | |
| expr.operands = [o for o in expr.operands if not (isinstance(o, BooleanLiteral) and o.value)] | |
| if not expr.operands: | |
| return BooleanLiteral(True) | |
| if len(expr.operands) == 1: | |
| return expr.operands[0] | |
| if op == BooleanOperator.OR: | |
| if any(isinstance(o, BooleanLiteral) and o.value for o in expr.operands): | |
| return BooleanLiteral(True) | |
| expr.operands = [o for o in expr.operands if not (isinstance(o, BooleanLiteral) and not o.value)] | |
| if not expr.operands: | |
| return BooleanLiteral(False) | |
| if len(expr.operands) == 1: | |
| return expr.operands[0] | |
| # A β B β‘ Β¬A β¨ B | |
| if op == BooleanOperator.IMPLIES: | |
| a, b = expr.operands[0], expr.operands[1] | |
| return simplify(OR(NOT(a), b)) | |
| # A β B β‘ (A β B) β§ (B β A) | |
| if op == BooleanOperator.EQUIVALENCE: | |
| a, b = expr.operands[0], expr.operands[1] | |
| return simplify(AND(IMPLIES(a, b), IMPLIES(b, a))) | |
| # A β B β‘ (A β¨ B) β§ Β¬(A β§ B) | |
| if op == BooleanOperator.XOR: | |
| a, b = expr.operands[0], expr.operands[1] | |
| return simplify(AND(OR(a, b), NOT(AND(a, b)))) | |
| return expr | |
| def push_not_inward(expr: Expr) -> Expr: | |
| """Apply De Morgan's laws, push negations to leaves.""" | |
| if isinstance(expr, (BooleanLiteral, BooleanVar)): | |
| return expr | |
| if expr.operator == BooleanOperator.NOT: | |
| inner = expr.operands[0] | |
| if isinstance(inner, BooleanLiteral): | |
| return BooleanLiteral(not inner.value) | |
| if isinstance(inner, BooleanVar): | |
| return inner.negate() | |
| if isinstance(inner, BooleanExpression): | |
| if inner.operator == BooleanOperator.NOT: | |
| return push_not_inward(inner.operands[0]) | |
| if inner.operator == BooleanOperator.AND: | |
| return push_not_inward(OR(*[NOT(o) for o in inner.operands])) | |
| if inner.operator == BooleanOperator.OR: | |
| return push_not_inward(AND(*[NOT(o) for o in inner.operands])) | |
| return BooleanExpression( | |
| expr.operator, | |
| [push_not_inward(o) for o in expr.operands], | |
| expr.constraint_refs, | |
| ) | |
| def distribute_or_over_and(expr: Expr) -> Expr: | |
| """Distribute OR over AND to produce CNF.""" | |
| if isinstance(expr, (BooleanLiteral, BooleanVar)): | |
| return expr | |
| expr = BooleanExpression( | |
| expr.operator, | |
| [distribute_or_over_and(o) for o in expr.operands], | |
| expr.constraint_refs, | |
| ) | |
| if expr.operator == BooleanOperator.OR: | |
| # Find any AND among operands | |
| for i, op in enumerate(expr.operands): | |
| if isinstance(op, BooleanExpression) and op.operator == BooleanOperator.AND: | |
| others = expr.operands[:i] + expr.operands[i+1:] | |
| distributed = AND(*[ | |
| distribute_or_over_and(OR(clause, *others)) | |
| for clause in op.operands | |
| ]) | |
| return distribute_or_over_and(distributed) | |
| return expr | |
| def to_cnf(expr: Expr) -> Expr: | |
| """Convert to Conjunctive Normal Form.""" | |
| e = simplify(expr) | |
| e = push_not_inward(e) | |
| e = distribute_or_over_and(e) | |
| e = simplify(e) | |
| return e | |
| def normalize(expr: Expr) -> Expr: | |
| """ | |
| Deterministic normalization. normalize(normalize(x)) == normalize(x). | |
| """ | |
| result = to_cnf(expr) | |
| # Idempotency check | |
| again = to_cnf(result) | |
| if repr(again) != repr(result): | |
| result = again | |
| return result | |
| # ββ Boolean Normal Form container βββββββββββββββββββββββββββββββββββββββββββββ | |
| class BooleanNormalForm: | |
| original: Expr | |
| normalized: Expr | |
| form: str = "CNF" | |
| stable: bool = False | |
| def verify_stability(self) -> bool: | |
| again = normalize(self.normalized) | |
| self.stable = repr(again) == repr(self.normalized) | |
| return self.stable | |
| # ββ Semantic β Boolean ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def semantic_constraints_to_boolean(constraints: list) -> BooleanNormalForm: | |
| """ | |
| Convert a list of Constraint objects into a Boolean expression. | |
| Each constraint becomes a BooleanVar. Constraints are AND-ed together. | |
| """ | |
| if not constraints: | |
| expr: Expr = BooleanLiteral(True) | |
| else: | |
| vars_ = [var(c.predicate if hasattr(c, "predicate") else str(c)) for c in constraints] | |
| expr = vars_[0] if len(vars_) == 1 else AND(*vars_) | |
| norm = normalize(expr) | |
| bnf = BooleanNormalForm(original=expr, normalized=norm) | |
| bnf.verify_stability() | |
| return bnf | |