1 //---------------------------------------------------------------------
2 // <copyright file="Converter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
13 using System.Diagnostics;
14 using System.Collections.ObjectModel;
15 using System.Globalization;
18 namespace System.Data.Common.Utils.Boolean
22 /// Handles conversion of expressions to different forms (decision diagram, etc)
24 internal sealed class Converter<T_Identifier>
26 private readonly Vertex _vertex;
27 private readonly ConversionContext<T_Identifier> _context;
28 private DnfSentence<T_Identifier> _dnf;
29 private CnfSentence<T_Identifier> _cnf;
31 internal Converter(BoolExpr<T_Identifier> expr, ConversionContext<T_Identifier> context)
33 _context = context ?? IdentifierService<T_Identifier>.Instance.CreateConversionContext();
34 _vertex = ToDecisionDiagramConverter<T_Identifier>.TranslateToRobdd(expr, _context);
37 internal Vertex Vertex
39 get { return _vertex; }
42 internal DnfSentence<T_Identifier> Dnf
46 InitializeNormalForms();
51 internal CnfSentence<T_Identifier> Cnf
55 InitializeNormalForms();
61 /// Converts the decision diagram (Vertex) wrapped by this converter and translates it into DNF
62 /// and CNF forms. I'll first explain the strategy with respect to DNF, and then explain how CNF
63 /// is achieved in parallel. A DNF sentence representing the expression is simply a disjunction
64 /// of every rooted path through the decision diagram ending in one. For instance, given the
65 /// following decision diagram:
73 /// the following paths evaluate to 'One'
78 /// and the corresponding DNF is (!A.!B) + (A.C)
80 /// It is easy to compute CNF from the DNF of the negation, e.g.:
82 /// !((A.B) + (C.D)) iff. (!A+!B) . (!C+!D)
84 /// To compute the CNF form in parallel, we negate the expression (by swapping One and Zero sinks)
85 /// and collect negation of the literals along the path. In the above example, the following paths
86 /// evaluate to 'Zero':
91 /// and the CNF (which takes the negation of all literals in the path) is (!A+B) . (A+!C)
93 private void InitializeNormalForms()
97 // short-circuit if the root is true/false
101 _cnf = new CnfSentence<T_Identifier>(Set<CnfClause<T_Identifier>>.Empty);
103 var emptyClause = new DnfClause<T_Identifier>(Set<Literal<T_Identifier>>.Empty);
104 var emptyClauseSet = new Set<DnfClause<T_Identifier>>();
105 emptyClauseSet.Add(emptyClause);
106 _dnf = new DnfSentence<T_Identifier>(emptyClauseSet.MakeReadOnly());
108 else if (_vertex.IsZero())
110 // And(Or()) -> False
111 var emptyClause = new CnfClause<T_Identifier>(Set<Literal<T_Identifier>>.Empty);
112 var emptyClauseSet = new Set<CnfClause<T_Identifier>>();
113 emptyClauseSet.Add(emptyClause);
114 _cnf = new CnfSentence<T_Identifier>(emptyClauseSet.MakeReadOnly());
116 _dnf = new DnfSentence<T_Identifier>(Set<DnfClause<T_Identifier>>.Empty);
120 // construct clauses by walking the tree and constructing a clause for each sink
121 Set<DnfClause<T_Identifier>> dnfClauses = new Set<DnfClause<T_Identifier>>();
122 Set<CnfClause<T_Identifier>> cnfClauses = new Set<CnfClause<T_Identifier>>();
123 Set<Literal<T_Identifier>> path = new Set<Literal<T_Identifier>>();
125 FindAllPaths(_vertex, cnfClauses, dnfClauses, path);
127 _cnf = new CnfSentence<T_Identifier>(cnfClauses.MakeReadOnly());
128 _dnf = new DnfSentence<T_Identifier>(dnfClauses.MakeReadOnly());
133 private void FindAllPaths(Vertex vertex, Set<CnfClause<T_Identifier>> cnfClauses, Set<DnfClause<T_Identifier>> dnfClauses,
134 Set<Literal<T_Identifier>> path)
139 var clause = new DnfClause<T_Identifier>(path);
140 dnfClauses.Add(clause);
142 else if (vertex.IsZero())
145 var clause = new CnfClause<T_Identifier>(new Set<Literal<T_Identifier>>(path.Select(l => l.MakeNegated())));
146 cnfClauses.Add(clause);
150 // keep on walking...
151 foreach (var successor in _context.GetSuccessors(vertex))
153 path.Add(successor.Literal);
154 FindAllPaths(successor.Vertex, cnfClauses, dnfClauses, path);
155 path.Remove(successor.Literal);