Normal Forms & Transformations

LogicalOptimizer produces every classic normal form. Outputs shown here are asserted in LogicalOptimizer.Tests/Documentation/DocExamplesTests.cs.

CNF and DNF (from the optimizer)

OptimizationResult carries both an optimized CNF (conjunctive) and DNF (disjunctive) form:

var result = new BooleanExpressionOptimizer().OptimizeExpression("a & b | a & c");
Console.WriteLine(result.CNF);   // a & (b | c)
Console.WriteLine(result.DNF);   // a & b | a & c

On the CLI these are the --cnf and --dnf flags (see CLI usage).

Algebraic Normal Form (Zhegalkin / Reed–Muller)

Transformations.ToAlgebraicNormalForm computes the canonical XOR-of-AND-monomials form via a fast Möbius transform over the truth table (up to TruthTable.MaxVariables):

var f = new FormulaFactory();

Transformations.ToAlgebraicNormalForm(f.Parse("a & !b | !a & b"));  // a XOR b
Transformations.ToAlgebraicNormalForm(f.Parse("a & b"));            // a & b
Transformations.ToAlgebraicNormalForm(f.Parse("a | b"));            // (a XOR b) XOR (a & b)

On the CLI this is the --anf flag.

Subsumption and heuristic DNF minimization

Transformations.SubsumeDnf(f.Parse("a | a & b"));   // a   (absorbed cube removed)
Transformations.SubsumeCnf(f.Parse("a & (a | b)")); // a   (absorbed clause removed)

// Espresso-style EXPAND / IRREDUNDANT / REDUCE on a cube list, sound by construction.
var minimized = Transformations.MinimizeDnfHeuristic(f.Parse("a & b | a & !b | !a & b"));
// equivalent to: a | b   (the 3-cube cover collapses to 2 literals)

MinimizeDnfHeuristic shrinks large DNF covers (40+ variables) where the exact minimizer is out of range; each move is validated by exact cofactor tautology, so it never changes the function.

Equisatisfiable Tseitin CNF

For handing a formula to a SAT solver, distributive CNF can blow up exponentially. BooleanExpressionOptimizer.ToEquisatisfiableCnf returns a linear-size TseitinCnf with auxiliary variables instead:

var cnf = new BooleanExpressionOptimizer().ToEquisatisfiableCnf("(a | b) & (b | c)");

Console.WriteLine(string.Join(",", cnf.InputVariables)); // a,b,c
Console.WriteLine(cnf.TotalVariableCount);               // 6
Console.WriteLine(cnf.AuxiliaryVariableCount);           // 3
Console.WriteLine(cnf.Clauses.Count);                    // 10
Console.WriteLine(cnf.VariableName(1));                  // a
Console.Write(cnf.ToDimacs());                           // p cnf 6 10 ...

// Feed it straight to the built-in solver:
SatSolver.FromCnf(cnf).Solve();                          // Satisfiable

The CLI exposes this as --cnf-mode=tseitin. The polarity-based Plaisted–Greenbaum style (CnfEncodingStyle.PlaistedGreenbaum) cuts clause count up to ~2×.

Truth tables

TruthTable builds an exhaustive table (up to 20 variables) with equivalence checks:

var table = TruthTable.Generate("a & b");
Console.WriteLine(table.GetResultsString());   // 0001
Console.WriteLine(table.IsSatisfiable());      // True
Console.WriteLine(table.IsTautology());        // False

TruthTable.Generate("a | !a").IsTautology();          // True
TruthTable.AreEquivalent("a & b | a & c", "a & (b | c)"); // True

Next steps

  • SAT solving — consume the Tseitin CNF, or build clauses directly.
  • Minimization — exact two-level SOP/POS and multi-output CSV.
  • Exporters — DIMACS / BLIF / Verilog / LaTeX / C#.