2 // IntervalEnvironmentBase.cs
5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2012 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.Collections
.Generic
;
33 using Mono
.CodeContracts
.Static
.DataStructures
;
34 using Mono
.CodeContracts
.Static
.Lattices
;
36 namespace Mono
.CodeContracts
.Static
.Analysis
.Numerical
{
37 abstract class IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> : IIntervalEnvironment
<TVar
, TExpr
, TInterval
, TNumeric
>,
38 IEnvironmentDomain
<IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>, TVar
, TExpr
>
39 where TInterval
: IntervalBase
<TInterval
, TNumeric
>
40 where TVar
: IEquatable
<TVar
> {
41 public abstract IntervalAssumerBase
<TVar
, TExpr
, TInterval
, TNumeric
> Assumer { get; }
42 public abstract IntervalContextBase
<TInterval
, TNumeric
> Context { get; }
44 public readonly IExpressionDecoder
<TVar
, TExpr
> Decoder
;
45 readonly EnvironmentDomain
<TVar
, TInterval
> vars_to_intervals
;
47 public IEnumerable
<TVar
> Variables { get { return vars_to_intervals.Keys; }
}
49 protected IntervalEnvironmentBase
50 (IExpressionDecoder
<TVar
, TExpr
> decoder
,
51 EnvironmentDomain
<TVar
, TInterval
> varsToInterval
)
54 vars_to_intervals
= varsToInterval
;
57 protected IntervalEnvironmentBase (IExpressionDecoder
<TVar
, TExpr
> decoder
)
58 : this (decoder
, EnvironmentDomain
<TVar
, TInterval
>.TopValue (null))
62 public TInterval
Eval (TExpr expr
)
65 if (Decoder
.IsConstantInt (expr
, out intValue
))
66 return Context
.For (intValue
);
68 var evaluator
= new EvaluateExpressionVisitor
<IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>, TVar
, TExpr
, TInterval
, TNumeric
> (Decoder
);
69 var interval
= evaluator
.Visit (expr
, new Counter
<IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>> (this));
71 if (evaluator
.DuplicatedOccurences
.Length () >= 1) {
72 var noDuplicates
= true;
73 TInterval result
= null;
74 foreach (var var in evaluator
.DuplicatedOccurences
.AsEnumerable ()) {
76 if (TryGetValue (var, out intv
) && intv
.IsFinite
&&
77 Context
.IsGreaterEqualThanZero (intv
.LowerBound
)) {
78 var extreme
= EvalWithExtremes (expr
, var, intv
);
84 result
= result
.Join (extreme
);
95 public TInterval
Eval (TVar
var)
98 if (TryGetValue (var, out intv
))
101 return Context
.TopValue
;
105 /// Evaluates expression with variable equal to var's lowerbound or upperbound.
107 /// <param name="expr"></param>
108 /// <param name="var"></param>
109 /// <param name="intv"></param>
110 /// <returns></returns>
111 TInterval
EvalWithExtremes (TExpr expr
, TVar
var, TInterval intv
)
113 var evaluator
= new EvaluateExpressionVisitor
<IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>, TVar
, TExpr
, TInterval
, TNumeric
> (Decoder
);
115 var envLowerBound
= With (var, Context
.For (intv
.LowerBound
));
116 // replace current intv with it's only lowerbound
117 var withLowerBound
= evaluator
.Visit (expr
, new Counter
<IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>> (envLowerBound
));
119 var envUpperBound
= With (var, Context
.For (intv
.UpperBound
));
120 // replace current intv with it's only upperBound
121 var withUpperBound
= evaluator
.Visit (expr
, new Counter
<IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>> (envUpperBound
));
123 return withLowerBound
.Join (withUpperBound
);
126 public string ToString (TExpr expr
)
133 var list
= new List
<string> ();
134 foreach (var variable
in Variables
) {
135 var intv
= vars_to_intervals
[variable
];
137 var name
= Decoder
!= null
138 ? Decoder
.NameOf (variable
)
139 : variable
.ToString ();
140 list
.Add (name
+ ": " + intv
);
144 return string.Join (", ", list
);
147 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> AssumeTrue (TExpr guard
)
149 Assumer
.AssumeNotEqualToZero (Decoder
.UnderlyingVariable (guard
), this);
150 return new IntervalTestVisitor (Decoder
).VisitTrue (guard
, this);
153 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> AssumeFalse (TExpr guard
)
155 return Assumer
.AssumeEqualToZero (Decoder
.UnderlyingVariable (guard
), this);
158 public FlatDomain
<bool> CheckIfHolds (TExpr expr
)
160 return FlatDomain
<bool>.TopValue
;
163 public bool Contains (TVar v
)
165 return vars_to_intervals
.Contains (v
);
168 public bool TryGetValue (TVar v
, out TInterval interval
)
170 return vars_to_intervals
.TryGetValue (v
, out interval
);
173 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> With (TVar
var, TInterval interval
)
175 return NewInstance (vars_to_intervals
.With (var, interval
));
178 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> RefineVariable (TVar
var, TInterval interval
)
181 if (TryGetValue (var, out current
))
182 interval
= interval
.Meet (current
);
184 if (interval
.IsBottom
)
187 return With (var, interval
);
190 #region Implementation of IAbstractDomain<T>
192 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Top { get { return NewInstance (EnvironmentDomain<TVar, TInterval>.TopValue (null)); }
}
194 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Bottom { get { return NewInstance (EnvironmentDomain<TVar, TInterval>.BottomValue ()); }
}
196 public bool IsTop { get { return vars_to_intervals.IsTop; }
}
198 public bool IsBottom { get { return vars_to_intervals.IsBottom; }
}
200 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Join (IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> that
)
202 return NewInstance (vars_to_intervals
.Join (that
.vars_to_intervals
));
205 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Join (IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> that
, bool widen
, out bool weaker
)
207 return NewInstance (vars_to_intervals
.Join (that
.vars_to_intervals
, widen
, out weaker
));
210 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Widen (IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> that
)
212 return NewInstance (vars_to_intervals
.Widen (that
.vars_to_intervals
));
215 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Meet (IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> that
)
217 return NewInstance (vars_to_intervals
.Meet (that
.vars_to_intervals
));
220 public bool LessEqual (IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> that
)
222 return vars_to_intervals
.LessEqual (that
.vars_to_intervals
);
225 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> ImmutableVersion ()
230 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> Clone ()
235 public void Dump (TextWriter tw
)
237 vars_to_intervals
.Dump (tw
);
242 protected abstract IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> NewInstance (EnvironmentDomain
<TVar
, TInterval
> varsToIntervals
);
244 class IntervalTestVisitor
{
245 readonly IntervalAssumeTrueVisitor
<TVar
, TExpr
, TInterval
, TNumeric
> true_visitor
;
246 readonly IntervalAssumeFalseVisitor
<TVar
, TExpr
, TInterval
, TNumeric
> false_visitor
;
248 public IntervalTestVisitor (IExpressionDecoder
<TVar
, TExpr
> decoder
)
251 new IntervalAssumeTrueVisitor
<TVar
, TExpr
, TInterval
, TNumeric
> (decoder
);
253 new IntervalAssumeFalseVisitor
<TVar
, TExpr
, TInterval
, TNumeric
> (decoder
);
255 true_visitor
.FalseVisitor
= false_visitor
;
256 false_visitor
.TrueVisitor
= true_visitor
;
259 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> VisitTrue (TExpr guard
, IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> data
)
261 return true_visitor
.Visit (guard
, data
);
264 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> VisitFalse (TExpr guard
, IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> data
)
266 return false_visitor
.Visit (guard
, data
);
270 public abstract IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> AssumeVariableIn (TVar
var, Interval interval
);
272 public IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
> AssumeLessEqualThan (TExpr left
, TExpr right
)
274 return Assumer
.AssumeLessEqualThan (left
, right
, this);
277 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Top { get { return Top; }
}
279 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Bottom { get { return Bottom; }
}
281 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Join (INumericalEnvironmentDomain
<TVar
, TExpr
> that
)
283 return Join (that
as IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>);
286 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Join
287 (INumericalEnvironmentDomain
<TVar
, TExpr
> that
, bool widen
, out bool weaker
)
289 return Join (that
as IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>, widen
,
293 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Widen (INumericalEnvironmentDomain
<TVar
, TExpr
> that
)
295 return Widen (that
as IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>);
298 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Meet (INumericalEnvironmentDomain
<TVar
, TExpr
> that
)
300 return Meet (that
as IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>);
303 bool IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.LessEqual (INumericalEnvironmentDomain
<TVar
, TExpr
> that
)
305 return LessEqual (that
as IntervalEnvironmentBase
<TVar
, TExpr
, TInterval
, TNumeric
>);
308 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.ImmutableVersion ()
310 return ImmutableVersion ();
313 INumericalEnvironmentDomain
<TVar
, TExpr
> IAbstractDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>>.Clone ()
318 INumericalEnvironmentDomain
<TVar
, TExpr
> IEnvironmentDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>, TVar
, TExpr
>.AssumeTrue (TExpr guard
)
320 return AssumeTrue (guard
);
323 INumericalEnvironmentDomain
<TVar
, TExpr
> IEnvironmentDomain
<INumericalEnvironmentDomain
<TVar
, TExpr
>, TVar
, TExpr
>.AssumeFalse (TExpr guard
)
325 return AssumeFalse (guard
);
328 INumericalEnvironmentDomain
<TVar
, TExpr
> INumericalEnvironmentDomain
<TVar
, TExpr
>.AssumeVariableIn (TVar
var, Interval interval
)
330 return AssumeVariableIn (var, interval
);
333 INumericalEnvironmentDomain
<TVar
, TExpr
> INumericalEnvironmentDomain
<TVar
, TExpr
>.AssumeLessEqualThan (TExpr left
, TExpr right
)
335 return AssumeLessEqualThan (left
, right
);