/// <summary>
        /// Converts expression to only use negation, conjunction, and disjunction operators
        /// </summary>
        /// <param name="node"></param>
        /// <param name="steps"></param>
        void ConvertOperators(ref BoolExpr node, IList <ConversionStep> steps)
        {
            if (node == null || node.Op == OperatorType.LEAF)
            {
                return;
            }

            if (Rewrite.Implication(ref node))
            {
                if (node.Parent == null)
                {
                    Root = node;
                }
                steps.Add(new ConversionStep(ToString(), "Implication"));
            }

            if (Rewrite.Equivalence(ref node))
            {
                if (node.Parent == null)
                {
                    Root = node;
                }
                steps.Add(new ConversionStep(ToString(), "Equivalence"));
            }

            if (Rewrite.XOR(ref node))
            {
                if (node.Parent == null)
                {
                    Root = node;
                }
                steps.Add(new ConversionStep(ToString(), "Xor"));
            }

            var right = node.Right;
            var left  = node.Left;

            ConvertOperators(ref left, steps);
            ConvertOperators(ref right, steps);
            node.Right = right;
            node.Left  = left;
        }
        /// <summary>
        /// Applies the distribution rule to an expression
        /// </summary>
        /// <param name="node"></param>
        /// <param name="steps"></param>
        void ApplyDistribution(ref BoolExpr node, IList <ConversionStep> steps)
        {
            if (node == null || node.Op == OperatorType.LEAF)
            {
                return;
            }

            // try to apply distribution
            if (Rewrite.Distribution(ref node))
            {
                if (node.Parent == null)
                {
                    Root = node;
                }
                steps.Add(new ConversionStep(ToString(), "Distribution"));
            }
            var right = node.Right;
            var left  = node.Left;

            ApplyDistribution(ref left, steps);
            ApplyDistribution(ref right, steps);
            node.Right = right;
            node.Left  = left;
        }
        /// <summary>
        /// Converts expression to negation normal form
        /// </summary>
        /// <param name="node"></param>
        /// <param name="steps"></param>
        void ConvertToNNF(ref BoolExpr node, IList <ConversionStep> steps)
        {
            if (node == null || node.Op == OperatorType.LEAF)
            {
                return;
            }

            // try to apply DN as many times as possible
            while (Rewrite.DN(ref node))
            {
                if (node.Parent == null)
                {
                    Root = node;
                }
                steps.Add(new ConversionStep(ToString(), "Double Negation"));
            }

            // try to apply DeM
            if (Rewrite.DeM(ref node))
            {
                if (node.Parent == null)
                {
                    Root = node;
                }
                steps.Add(new ConversionStep(ToString(), "DeMorgan's"));
            }


            var right = node.Right;
            var left  = node.Left;

            ConvertToNNF(ref left, steps);
            ConvertToNNF(ref right, steps);
            node.Right = right;
            node.Left  = left;
        }