private void InitializeNormalForms()
 {
     if (this._cnf != null)
     {
         return;
     }
     if (this._vertex.IsOne())
     {
         this._cnf = new CnfSentence <T_Identifier>(Set <CnfClause <T_Identifier> > .Empty);
         this._dnf = new DnfSentence <T_Identifier>(new Set <DnfClause <T_Identifier> >()
         {
             new DnfClause <T_Identifier>(Set <Literal <T_Identifier> > .Empty)
         }.MakeReadOnly());
     }
     else if (this._vertex.IsZero())
     {
         this._cnf = new CnfSentence <T_Identifier>(new Set <CnfClause <T_Identifier> >()
         {
             new CnfClause <T_Identifier>(Set <Literal <T_Identifier> > .Empty)
         }.MakeReadOnly());
         this._dnf = new DnfSentence <T_Identifier>(Set <DnfClause <T_Identifier> > .Empty);
     }
     else
     {
         Set <DnfClause <T_Identifier> > dnfClauses = new Set <DnfClause <T_Identifier> >();
         Set <CnfClause <T_Identifier> > cnfClauses = new Set <CnfClause <T_Identifier> >();
         Set <Literal <T_Identifier> >   path       = new Set <Literal <T_Identifier> >();
         this.FindAllPaths(this._vertex, cnfClauses, dnfClauses, path);
         this._cnf = new CnfSentence <T_Identifier>(cnfClauses.MakeReadOnly());
         this._dnf = new DnfSentence <T_Identifier>(dnfClauses.MakeReadOnly());
     }
 }
        /// <summary>
        ///     Converts the decision diagram (Vertex) wrapped by this converter and translates it into DNF
        ///     and CNF forms. I'll first explain the strategy with respect to DNF, and then explain how CNF
        ///     is achieved in parallel. A DNF sentence representing the expression is simply a disjunction
        ///     of every rooted path through the decision diagram ending in one. For instance, given the
        ///     following decision diagram:
        ///     A
        ///     0/ \1
        ///     B     C
        ///     0/ \1 0/ \1
        ///     One   Zero   One
        ///     the following paths evaluate to 'One'
        ///     !A, !B
        ///     A, C
        ///     and the corresponding DNF is (!A.!B) + (A.C)
        ///     It is easy to compute CNF from the DNF of the negation, e.g.:
        ///     !((A.B) + (C.D)) iff. (!A+!B) . (!C+!D)
        ///     To compute the CNF form in parallel, we negate the expression (by swapping One and Zero sinks)
        ///     and collect negation of the literals along the path. In the above example, the following paths
        ///     evaluate to 'Zero':
        ///     !A, B
        ///     A, !C
        ///     and the CNF (which takes the negation of all literals in the path) is (!A+B) . (A+!C)
        /// </summary>
        private void InitializeNormalForms()
        {
            if (null == _cnf)
            {
                // short-circuit if the root is true/false
                if (_vertex.IsOne())
                {
                    // And() -> True
                    _cnf = new CnfSentence <T_Identifier>(Set <CnfClause <T_Identifier> > .Empty);
                    // Or(And()) -> True
                    var emptyClause    = new DnfClause <T_Identifier>(Set <Literal <T_Identifier> > .Empty);
                    var emptyClauseSet = new Set <DnfClause <T_Identifier> >();
                    emptyClauseSet.Add(emptyClause);
                    _dnf = new DnfSentence <T_Identifier>(emptyClauseSet.MakeReadOnly());
                }
                else if (_vertex.IsZero())
                {
                    // And(Or()) -> False
                    var emptyClause    = new CnfClause <T_Identifier>(Set <Literal <T_Identifier> > .Empty);
                    var emptyClauseSet = new Set <CnfClause <T_Identifier> >();
                    emptyClauseSet.Add(emptyClause);
                    _cnf = new CnfSentence <T_Identifier>(emptyClauseSet.MakeReadOnly());
                    // Or() -> False
                    _dnf = new DnfSentence <T_Identifier>(Set <DnfClause <T_Identifier> > .Empty);
                }
                else
                {
                    // construct clauses by walking the tree and constructing a clause for each sink
                    var dnfClauses = new Set <DnfClause <T_Identifier> >();
                    var cnfClauses = new Set <CnfClause <T_Identifier> >();
                    var path       = new Set <Literal <T_Identifier> >();

                    FindAllPaths(_vertex, cnfClauses, dnfClauses, path);

                    _cnf = new CnfSentence <T_Identifier>(cnfClauses.MakeReadOnly());
                    _dnf = new DnfSentence <T_Identifier>(dnfClauses.MakeReadOnly());
                }
            }
        }