/// <summary> /// Non recursively remove constants: /// A * 1 = A /// A + 0 = A /// A # 0 = A /// A # 1 = !A /// A * 0 = 0 /// A + 1 = 1 /// </summary> public static OpCode RemoveConstNR(OpCodeMath op, ref int removeConst, ref int removeConstExpr, ref int removeUnary) { // Remove all constants Type opType = op.GetType(); for (int i = 0; i < op.Operands.Count; i++) { // Must leave atleast one operand to know the value if (op.Operands.Count <= 1) { break; } // Skip non-constant values OpCodeConst constTerm = op.Operands[i] as OpCodeConst; if (constTerm == null) { continue; // Skip non-constants } constTerm.Eval(true); // Ensure Negate is not set if (constTerm.State != OpState.Zero && constTerm.State != OpState.One) { continue; // Skip non-boolean states } // Remove constant: // A * 1 = A // A + 0 = A // A # 0 = A // A # 1 = !A if (opType == typeof(OpCodeXor) || opType == typeof(OpCodeAnd) && constTerm.State == OpState.One || opType == typeof(OpCodeOr) && constTerm.State == OpState.Zero) { // Check for (A # 1) = !A if (opType == typeof(OpCodeXor) && constTerm.State == OpState.One) { op.Negate ^= OpState.One; } // Remove constant op.Operands.RemoveAt(i); i--; // Retry this operand removeConst++; continue; // Continue processing all operands } // Remove constant: // A * 0 = 0 // A + 1 = 1 if (opType == typeof(OpCodeAnd) && constTerm.State == OpState.Zero || opType == typeof(OpCodeOr) && constTerm.State == OpState.One) { // Remove entire sub-expression op.Operands.Clear(); op.Operands.Add(constTerm); removeConstExpr++; break; // Done with all processing } } // Check for only one operand if (op.Operands.Count == 1) { // Remove this gate, and return the operand. // AND, OR, XOR = nop. NAND, NOR, XNOR = inverter. removeUnary++; op.Operands[0].Negate ^= op.Negate; return(op.Operands[0]); } return(op); }
/// <summary> /// Recursively remove extraneuous levels of parenthises: /// a+(b+c) = a+b+c Associative /// a*(b*c) = a*b*c /// a#(b#c) = a#b#c /// a#!(b#c) = !(a#b#c) /// a+!(b*c) = a+!b+!c Demorgan's law /// a*!(b+c) = a*!b*!c /// Remove constants /// Remove identity /// Same for # and * /// </summary> public OpCode Flatten(OpCode op) { OpCodeMath math = op as OpCodeMath; if (math == null) { return(op); } Type opType = op.GetType(); if (opType != typeof(OpCodeAnd) && opType != typeof(OpCodeOr) && opType != typeof(OpCodeXor)) { return(op); } // Flatten all sub-trees first for (int i = 0; i < math.Operands.Count; i++) { math.Operands[i] = Flatten(math.Operands[i]); } // Flatten this branch for (int i = 0; i < math.Operands.Count; i++) { OpCodeMath newMath = math.Operands[i] as OpCodeMath; if (newMath == null) { continue; } // Associative: // a+(b+c) = a+b+c // a*(b*c) = a*b*c // a#(b#c) = a#b#c // a#!(b#c) = !(a#b#c) if (newMath.GetType() == opType && // Op codes must be same (newMath.Negate == OpState.Zero || newMath.Negate == OpState.One && newMath is OpCodeXor)) { math.Operands.RemoveAt(i); math.Operands.AddRange(newMath.Operands); math.Negate ^= newMath.Negate; mAssociative++; i--; // Retry this operand continue; } // Demorgan's law: // a+!(b*c) = a+!b+!c Demorgan's law // a*!(b+c) = a*!b*!c Demorgan's law if (newMath.Negate == OpState.One) { if (op is OpCodeOr && newMath is OpCodeAnd || op is OpCodeAnd && newMath is OpCodeOr) { math.Operands.RemoveAt(i); foreach (OpCode newOp in newMath.Operands) { // Perform demorgans law (negate each sub-op code) newOp.Negate ^= OpState.One; math.Operands.Add(newOp); } mDemorgans++; i--; // Retry this operand continue; } } } return(RemoveIdentityNR(RemoveConstNR(math, ref mRemoveConst, ref mRemoveConstExpr, ref mRemoveUnary))); }