File: BoolExpr.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (491 lines) | stat: -rw-r--r-- 17,769 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
//---------------------------------------------------------------------
// <copyright file="BoolExpr.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;

namespace System.Data.Common.Utils.Boolean
{
    /// <summary>
    /// Base type for Boolean expressions. Boolean expressions are immutable,
    /// and value-comparable using Equals. Services include local simplification
    /// and normalization to Conjunctive and Disjunctive Normal Forms.
    /// </summary>
    /// <remarks>
    /// Comments use the following notation convention:
    /// 
    ///     "A . B" means "A and B"
    ///     "A + B" means "A or B"
    ///     "!A" means "not A"
    /// </remarks>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal abstract partial class BoolExpr<T_Identifier> : IEquatable<BoolExpr<T_Identifier>>
    {
        /// <summary>
        /// Gets an enumeration value indicating the type of the expression node.
        /// </summary>
        internal abstract ExprType ExprType { get; }

        /// <summary>
        /// Standard accept method invoking the appropriate method overload
        /// in the given visitor.
        /// </summary>
        /// <typeparam name="T_Return">T_Return is the return type for the visitor.</typeparam>
        /// <param name="visitor">Visitor implementation.</param>
        /// <returns>Value computed for this node.</returns>
        internal abstract T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor);

        /// <summary>
        /// Invokes the Simplifier visitor on this expression tree.
        /// Simplifications are purely local (see Simplifier class
        /// for details).
        /// </summary>
        internal BoolExpr<T_Identifier> Simplify()
        {
            return IdentifierService<T_Identifier>.Instance.LocalSimplify(this);
        }

        /// <summary>
        /// Expensive simplification that considers various permutations of the
        /// expression (including Decision Diagram, DNF, and CNF translations)
        /// </summary>
        internal BoolExpr<T_Identifier> ExpensiveSimplify(out Converter<T_Identifier> converter)
        {
            var context = IdentifierService<T_Identifier>.Instance.CreateConversionContext();
            converter = new Converter<T_Identifier>(this, context);

            // Check for valid/unsat constraints
            if (converter.Vertex.IsOne())
            {
                return TrueExpr<T_Identifier>.Value;
            }
            if (converter.Vertex.IsZero())
            {
                return FalseExpr<T_Identifier>.Value;
            }

            // Pick solution from the (unmodified) expression, its CNF and its DNF
            return ChooseCandidate(this, converter.Cnf.Expr, converter.Dnf.Expr);
        }

        private static BoolExpr<T_Identifier> ChooseCandidate(params BoolExpr<T_Identifier>[] candidates)
        {
            Debug.Assert(null != candidates && 1 < candidates.Length, "must be at least one to pick");

            int resultUniqueTermCount = default(int);
            int resultTermCount = default(int);
            BoolExpr<T_Identifier> result = null;

            foreach (var candidate in candidates)
            {
                // first do basic simplification
                var simplifiedCandidate = candidate.Simplify();

                // determine "interesting" properties of the expression
                int candidateUniqueTermCount = simplifiedCandidate.GetTerms().Distinct().Count();
                int candidateTermCount = simplifiedCandidate.CountTerms();

                // see if it's better than the current result best result
                if (null == result || // bootstrap
                    candidateUniqueTermCount < resultUniqueTermCount || // check if the candidate improves on # of terms
                    (candidateUniqueTermCount == resultUniqueTermCount && // in case of tie, choose based on total
                     candidateTermCount < resultTermCount))
                {
                    result = simplifiedCandidate;
                    resultUniqueTermCount = candidateUniqueTermCount;
                    resultTermCount = candidateTermCount;
                }
            }

            return result;
        }

        /// <summary>
        /// Returns all term expressions below this node.
        /// </summary>
        internal List<TermExpr<T_Identifier>> GetTerms()
        {
            return LeafVisitor<T_Identifier>.GetTerms(this);
        }

        /// <summary>
        /// Counts terms in this expression.
        /// </summary>
        internal int CountTerms()
        {
            return TermCounter<T_Identifier>.CountTerms(this);
        }

        /// <summary>
        /// Implicit cast from a value of type T to a TermExpr where
        /// TermExpr.Value is set to the given value.
        /// </summary>
        /// <param name="value">Value to wrap in term expression</param>
        /// <returns>Term expression</returns>
        public static implicit operator BoolExpr<T_Identifier>(T_Identifier value)
        {
            return new TermExpr<T_Identifier>(value);
        }

        /// <summary>
        /// Creates the negation of the current element. 
        /// </summary>
        internal virtual BoolExpr<T_Identifier> MakeNegated()
        {
            return new NotExpr<T_Identifier>(this);
        }

        public override string ToString()
        {
            return ExprType.ToString();
        }

        public bool Equals(BoolExpr<T_Identifier> other)
        {
            return null != other && ExprType == other.ExprType &&
                EquivalentTypeEquals(other);
        }

        protected abstract bool EquivalentTypeEquals(BoolExpr<T_Identifier> other);
    }

    /// <summary>
    /// Boolean expression that evaluates to true.
    /// </summary>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal sealed class TrueExpr<T_Identifier> : BoolExpr<T_Identifier>
    {
        private static readonly TrueExpr<T_Identifier> s_value = new TrueExpr<T_Identifier>();

        // private constructor so that we control existence of True instance
        private TrueExpr()
            : base()
        {
        }

        /// <summary>
        /// Gets the one instance of TrueExpr
        /// </summary>
        internal static TrueExpr<T_Identifier> Value { get { return s_value; } }

        internal override ExprType ExprType { get { return ExprType.True; } }

        internal override T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor)
        {
            return visitor.VisitTrue(this);
        }

        internal override BoolExpr<T_Identifier> MakeNegated()
        {
            return FalseExpr<T_Identifier>.Value;
        }

        protected override bool EquivalentTypeEquals(BoolExpr<T_Identifier> other)
        {
            return object.ReferenceEquals(this, other);
        }
    }

    /// <summary>
    /// Boolean expression that evaluates to false.
    /// </summary>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal sealed class FalseExpr<T_Identifier> : BoolExpr<T_Identifier>
    {
        private static readonly FalseExpr<T_Identifier> s_value = new FalseExpr<T_Identifier>();

        // private constructor so that we control existence of False instance
        private FalseExpr()
            : base()
        {
        }

        /// <summary>
        /// Gets the one instance of FalseExpr
        /// </summary>
        internal static FalseExpr<T_Identifier> Value { get { return s_value; } }

        internal override ExprType ExprType { get { return ExprType.False; } }

        internal override T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor)
        {
            return visitor.VisitFalse(this);
        }

        internal override BoolExpr<T_Identifier> MakeNegated()
        {
            return TrueExpr<T_Identifier>.Value;
        }

        protected override bool EquivalentTypeEquals(BoolExpr<T_Identifier> other)
        {
            return object.ReferenceEquals(this, other);
        }
    }

    /// <summary>
    /// A term is a leaf node in a Boolean expression. Its value (T/F) is undefined.
    /// </summary>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal sealed class TermExpr<T_Identifier> : BoolExpr<T_Identifier>, IEquatable<TermExpr<T_Identifier>>
    {
        private readonly T_Identifier _identifier;
        private readonly IEqualityComparer<T_Identifier> _comparer;

        /// <summary>
        /// Construct a term. 
        /// </summary>
        /// <param name="comparer">Value comparer to use when comparing two
        /// term expressions.</param>
        /// <param name="identifier">Identifier/tag for this term.</param>
        internal TermExpr(IEqualityComparer<T_Identifier> comparer, T_Identifier identifier)
            : base()
        {
            Debug.Assert(null != (object)identifier);
            _identifier = identifier;
            if (null == comparer) { _comparer = EqualityComparer<T_Identifier>.Default; }
            else { _comparer = comparer; }
        }
        internal TermExpr(T_Identifier identifier) : this(null, identifier) { }

        /// <summary>
        /// Gets identifier for this term. This value is used to determine whether
        /// two terms as equivalent.
        /// </summary>
        internal T_Identifier Identifier { get { return _identifier; } }

        internal override ExprType ExprType { get { return ExprType.Term; } }
        
        public override bool Equals(object obj)
        {
            Debug.Fail("use only typed equals");
            return this.Equals(obj as TermExpr<T_Identifier>);
        }

        public bool Equals(TermExpr<T_Identifier> other)
        {
            return _comparer.Equals(_identifier, other._identifier);
        }

        protected override bool EquivalentTypeEquals(BoolExpr<T_Identifier> other)
        {
            return _comparer.Equals(_identifier, ((TermExpr<T_Identifier>)other)._identifier);
        }
        
        public override int GetHashCode()
        {
            return _comparer.GetHashCode(_identifier);
        }
        
        public override string ToString()
        {
            return StringUtil.FormatInvariant("{0}", _identifier);
        }

        internal override T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor)
        {
            return visitor.VisitTerm(this);
        }

        internal override BoolExpr<T_Identifier> MakeNegated()
        {
            Literal<T_Identifier> literal = new Literal<T_Identifier>(this, true);
            // leverage normalization code if it exists
            Literal<T_Identifier> negatedLiteral = literal.MakeNegated();
            if (negatedLiteral.IsTermPositive)
            {
                return negatedLiteral.Term;
            }
            else
            {
                return new NotExpr<T_Identifier>(negatedLiteral.Term);
            }
        }
    }

    /// <summary>
    /// Abstract base class for tree expressions (unary as in Not, n-ary
    /// as in And or Or). Duplicate elements are trimmed at construction
    /// time (algorithms applied to these trees rely on the assumption
    /// of uniform children).
    /// </summary>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal abstract class TreeExpr<T_Identifier> : BoolExpr<T_Identifier>
    {
        private readonly Set<BoolExpr<T_Identifier>> _children;
        private readonly int _hashCode;

        /// <summary>
        /// Initialize a new tree expression with the given children.
        /// </summary>
        /// <param name="children">Child expressions</param>
        protected TreeExpr(IEnumerable<BoolExpr<T_Identifier>> children)
            : base()
        {
            Debug.Assert(null != children);
            _children = new Set<BoolExpr<T_Identifier>>(children);
            _children.MakeReadOnly();
            _hashCode = _children.GetElementsHashCode();
        }

        /// <summary>
        /// Gets the children of this expression node.
        /// </summary>
        internal Set<BoolExpr<T_Identifier>> Children { get { return _children; } }
        
        public override bool Equals(object obj)
        {
            Debug.Fail("use only typed Equals");
            return base.Equals(obj as BoolExpr<T_Identifier>);
        }

        public override int GetHashCode()
        {
            return _hashCode;
        }

        public override string ToString()
        {
            return StringUtil.FormatInvariant("{0}({1})", ExprType, _children);
        }

        protected override bool EquivalentTypeEquals(BoolExpr<T_Identifier> other)
        {
            return ((TreeExpr<T_Identifier>)other).Children.SetEquals(Children);
        }
    }

    /// <summary>
    /// A tree expression that evaluates to true iff. none of its children
    /// evaluate to false.
    /// </summary>
    /// <remarks>
    /// An And expression with no children is equivalent to True (this is an
    /// operational convenience because we assume an implicit True is along
    /// for the ride in every And expression)
    /// 
    ///     A . True iff. A
    /// </remarks>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal class AndExpr<T_Identifier> : TreeExpr<T_Identifier>
    {
        /// <summary>
        /// Initialize a new And expression with the given children.
        /// </summary>
        /// <param name="children">Child expressions</param>
        internal AndExpr(params BoolExpr<T_Identifier>[] children)
            : this((IEnumerable<BoolExpr<T_Identifier>>)children)
        {
        }

        /// <summary>
        /// Initialize a new And expression with the given children.
        /// </summary>
        /// <param name="children">Child expressions</param>
        internal AndExpr(IEnumerable<BoolExpr<T_Identifier>> children)
            : base(children)
        {
        }

        internal override ExprType ExprType { get { return ExprType.And; } }

        internal override T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor)
        {
            return visitor.VisitAnd(this);
        }
    }

    /// <summary>
    /// A tree expression that evaluates to true iff. any of its children
    /// evaluates to true.
    /// </summary>
    /// <remarks>
    /// An Or expression with no children is equivalent to False (this is an
    /// operational convenience because we assume an implicit False is along
    /// for the ride in every Or expression)
    /// 
    ///     A + False iff. A
    /// </remarks>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal class OrExpr<T_Identifier> : TreeExpr<T_Identifier>
    {
        /// <summary>
        /// Initialize a new Or expression with the given children.
        /// </summary>
        /// <param name="children">Child expressions</param>
        internal OrExpr(params BoolExpr<T_Identifier>[] children)
            : this((IEnumerable<BoolExpr<T_Identifier>>)children)
        {
        }

        /// <summary>
        /// Initialize a new Or expression with the given children.
        /// </summary>
        /// <param name="children">Child expressions</param>
        internal OrExpr(IEnumerable<BoolExpr<T_Identifier>> children)
            : base(children)
        {
        }

        internal override ExprType ExprType { get { return ExprType.Or; } }

        internal override T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor)
        {
            return visitor.VisitOr(this);
        }
    }

    /// <summary>
    /// A tree expression that evaluates to true iff. its (single) child evaluates to false.
    /// </summary>
    /// <typeparam name="T_Identifier">The type of leaf term identifiers in this expression.</typeparam>
    internal sealed class NotExpr<T_Identifier> : TreeExpr<T_Identifier>
    {
        /// <summary>
        /// Initialize a new Not expression with the given child.
        /// </summary>
        /// <param name="child"></param>
        internal NotExpr(BoolExpr<T_Identifier> child)
            : base(new BoolExpr<T_Identifier>[] { child })
        {
        }

        internal override ExprType ExprType { get { return ExprType.Not; } }

        internal BoolExpr<T_Identifier> Child { get { return Children.First(); } }

        internal override T_Return Accept<T_Return>(Visitor<T_Identifier, T_Return> visitor)
        {
            return visitor.VisitNot(this);
        }

        public override string ToString()
        {
            return String.Format(CultureInfo.InvariantCulture, "!{0}", Child);
        }

        internal override BoolExpr<T_Identifier> MakeNegated()
        {
            return this.Child;
        }
    }

    /// <summary>
    /// Enumeration of Boolean expression node types.
    /// </summary>
    internal enum ExprType
    {
        And, Not, Or, Term, True, False,
    }
}