// // IntervalEnvironmentBase.cs // // Authors: // Alexander Chebaturkin (chebaturkin@gmail.com) // // Copyright (C) 2012 Alexander Chebaturkin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.IO; using Mono.CodeContracts.Static.DataStructures; using Mono.CodeContracts.Static.Lattices; namespace Mono.CodeContracts.Static.Analysis.Numerical { abstract class IntervalEnvironmentBase : IIntervalEnvironment, IEnvironmentDomain, TVar, TExpr> where TInterval : IntervalBase where TVar : IEquatable { public abstract IntervalAssumerBase Assumer { get; } public abstract IntervalContextBase Context { get; } public readonly IExpressionDecoder Decoder; readonly EnvironmentDomain vars_to_intervals; public IEnumerable Variables { get { return vars_to_intervals.Keys; } } protected IntervalEnvironmentBase (IExpressionDecoder decoder, EnvironmentDomain varsToInterval) { Decoder = decoder; vars_to_intervals = varsToInterval; } protected IntervalEnvironmentBase (IExpressionDecoder decoder) : this (decoder, EnvironmentDomain.TopValue (null)) { } public TInterval Eval (TExpr expr) { int intValue; if (Decoder.IsConstantInt (expr, out intValue)) return Context.For (intValue); var evaluator = new EvaluateExpressionVisitor, TVar, TExpr, TInterval, TNumeric> (Decoder); var interval = evaluator.Visit (expr, new Counter> (this)); if (evaluator.DuplicatedOccurences.Length () >= 1) { var noDuplicates = true; TInterval result = null; foreach (var var in evaluator.DuplicatedOccurences.AsEnumerable ()) { TInterval intv; if (TryGetValue (var, out intv) && intv.IsFinite && Context.IsGreaterEqualThanZero (intv.LowerBound)) { var extreme = EvalWithExtremes (expr, var, intv); if (noDuplicates) { noDuplicates = false; result = extreme; } else result = result.Join (extreme); } } if (!noDuplicates) interval = result; } return interval; } public TInterval Eval (TVar var) { TInterval intv; if (TryGetValue (var, out intv)) return intv; return Context.TopValue; } /// /// Evaluates expression with variable equal to var's lowerbound or upperbound. /// /// /// /// /// TInterval EvalWithExtremes (TExpr expr, TVar var, TInterval intv) { var evaluator = new EvaluateExpressionVisitor, TVar, TExpr, TInterval, TNumeric> (Decoder); var envLowerBound = With (var, Context.For (intv.LowerBound)); // replace current intv with it's only lowerbound var withLowerBound = evaluator.Visit (expr, new Counter> (envLowerBound)); var envUpperBound = With (var, Context.For (intv.UpperBound)); // replace current intv with it's only upperBound var withUpperBound = evaluator.Visit (expr, new Counter> (envUpperBound)); return withLowerBound.Join (withUpperBound); } public string ToString (TExpr expr) { if (IsBottom) return "_|_"; if (IsTop) return "Top"; var list = new List (); foreach (var variable in Variables) { var intv = vars_to_intervals[variable]; if (!intv.IsTop) { var name = Decoder != null ? Decoder.NameOf (variable) : variable.ToString (); list.Add (name + ": " + intv); } } list.Sort (); return string.Join (", ", list); } public IntervalEnvironmentBase AssumeTrue (TExpr guard) { Assumer.AssumeNotEqualToZero (Decoder.UnderlyingVariable (guard), this); return new IntervalTestVisitor (Decoder).VisitTrue (guard, this); } public IntervalEnvironmentBase AssumeFalse (TExpr guard) { return Assumer.AssumeEqualToZero (Decoder.UnderlyingVariable (guard), this); } public FlatDomain CheckIfHolds (TExpr expr) { return FlatDomain.TopValue; } public bool Contains (TVar v) { return vars_to_intervals.Contains (v); } public bool TryGetValue (TVar v, out TInterval interval) { return vars_to_intervals.TryGetValue (v, out interval); } public IntervalEnvironmentBase With (TVar var, TInterval interval) { return NewInstance (vars_to_intervals.With (var, interval)); } public IntervalEnvironmentBase RefineVariable (TVar var, TInterval interval) { TInterval current; if (TryGetValue (var, out current)) interval = interval.Meet (current); if (interval.IsBottom) return Bottom; return With (var, interval); } #region Implementation of IAbstractDomain public IntervalEnvironmentBase Top { get { return NewInstance (EnvironmentDomain.TopValue (null)); } } public IntervalEnvironmentBase Bottom { get { return NewInstance (EnvironmentDomain.BottomValue ()); } } public bool IsTop { get { return vars_to_intervals.IsTop; } } public bool IsBottom { get { return vars_to_intervals.IsBottom; } } public IntervalEnvironmentBase Join (IntervalEnvironmentBase that) { return NewInstance (vars_to_intervals.Join (that.vars_to_intervals)); } public IntervalEnvironmentBase Join (IntervalEnvironmentBase that, bool widen, out bool weaker) { return NewInstance (vars_to_intervals.Join (that.vars_to_intervals, widen, out weaker)); } public IntervalEnvironmentBase Widen (IntervalEnvironmentBase that) { return NewInstance (vars_to_intervals.Widen (that.vars_to_intervals)); } public IntervalEnvironmentBase Meet (IntervalEnvironmentBase that) { return NewInstance (vars_to_intervals.Meet (that.vars_to_intervals)); } public bool LessEqual (IntervalEnvironmentBase that) { return vars_to_intervals.LessEqual (that.vars_to_intervals); } public IntervalEnvironmentBase ImmutableVersion () { return this; } public IntervalEnvironmentBase Clone () { return this; } public void Dump (TextWriter tw) { vars_to_intervals.Dump (tw); } #endregion protected abstract IntervalEnvironmentBase NewInstance (EnvironmentDomain varsToIntervals); class IntervalTestVisitor { readonly IntervalAssumeTrueVisitor true_visitor; readonly IntervalAssumeFalseVisitor false_visitor; public IntervalTestVisitor (IExpressionDecoder decoder) { true_visitor = new IntervalAssumeTrueVisitor (decoder); false_visitor = new IntervalAssumeFalseVisitor (decoder); true_visitor.FalseVisitor = false_visitor; false_visitor.TrueVisitor = true_visitor; } public IntervalEnvironmentBase VisitTrue (TExpr guard, IntervalEnvironmentBase data) { return true_visitor.Visit (guard, data); } public IntervalEnvironmentBase VisitFalse (TExpr guard, IntervalEnvironmentBase data) { return false_visitor.Visit (guard, data); } } public abstract IntervalEnvironmentBase AssumeVariableIn (TVar var, Interval interval); public IntervalEnvironmentBase AssumeLessEqualThan (TExpr left, TExpr right) { return Assumer.AssumeLessEqualThan (left, right, this); } INumericalEnvironmentDomain IAbstractDomain>.Top { get { return Top; } } INumericalEnvironmentDomain IAbstractDomain>.Bottom { get { return Bottom; } } INumericalEnvironmentDomain IAbstractDomain>.Join (INumericalEnvironmentDomain that) { return Join (that as IntervalEnvironmentBase); } INumericalEnvironmentDomain IAbstractDomain>.Join (INumericalEnvironmentDomain that, bool widen, out bool weaker) { return Join (that as IntervalEnvironmentBase, widen, out weaker); } INumericalEnvironmentDomain IAbstractDomain>.Widen (INumericalEnvironmentDomain that) { return Widen (that as IntervalEnvironmentBase); } INumericalEnvironmentDomain IAbstractDomain>.Meet (INumericalEnvironmentDomain that) { return Meet (that as IntervalEnvironmentBase); } bool IAbstractDomain>.LessEqual (INumericalEnvironmentDomain that) { return LessEqual (that as IntervalEnvironmentBase); } INumericalEnvironmentDomain IAbstractDomain>.ImmutableVersion () { return ImmutableVersion (); } INumericalEnvironmentDomain IAbstractDomain>.Clone () { return Clone (); } INumericalEnvironmentDomain IEnvironmentDomain, TVar, TExpr>.AssumeTrue (TExpr guard) { return AssumeTrue (guard); } INumericalEnvironmentDomain IEnvironmentDomain, TVar, TExpr>.AssumeFalse (TExpr guard) { return AssumeFalse (guard); } INumericalEnvironmentDomain INumericalEnvironmentDomain.AssumeVariableIn (TVar var, Interval interval) { return AssumeVariableIn (var, interval); } INumericalEnvironmentDomain INumericalEnvironmentDomain.AssumeLessEqualThan (TExpr left, TExpr right) { return AssumeLessEqualThan (left, right); } } }