diff options
Diffstat (limited to 'Source/VCExpr/Clustering.cs')
-rw-r--r-- | Source/VCExpr/Clustering.cs | 1042 |
1 files changed, 521 insertions, 521 deletions
diff --git a/Source/VCExpr/Clustering.cs b/Source/VCExpr/Clustering.cs index 1ab10107..a799aaae 100644 --- a/Source/VCExpr/Clustering.cs +++ b/Source/VCExpr/Clustering.cs @@ -1,522 +1,522 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Text;
-using System.IO;
-using System.Linq;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-
-// Code for managing and clusterings sets of terms; this is used to
-// compress the input given to the theorem prover
-
-namespace Microsoft.Boogie.Clustering {
- using Microsoft.Boogie.VCExprAST;
-
-
- public class SubtermCollector : BoundVarTraversingVCExprVisitor<bool, bool> {
-
- private readonly VCExpressionGenerator/*!*/ Gen;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Gen != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(GlobalVariables));
- Contract.Invariant(cce.NonNullDictionaryAndValues(SubtermClusters));
- }
-
-
- public SubtermCollector(VCExpressionGenerator gen) {
- Contract.Requires(gen != null);
- Gen = gen;
- }
-
- // variables that are global and treated like constants
- private readonly IDictionary<VCExprVar/*!*/, VCExprVar/*!*/> GlobalVariables = new Dictionary<VCExprVar/*!*/, VCExprVar/*!*/>();
-
- private readonly IDictionary<VCExprOp/*!*/, TermClustersSameHead/*!*/> SubtermClusters =
- new Dictionary<VCExprOp/*!*/, TermClustersSameHead/*!*/>();
-
- public void UnifyClusters() {
- foreach (KeyValuePair<VCExprOp/*!*/, TermClustersSameHead/*!*/> pair
- in SubtermClusters) {
- Contract.Assert(cce.NonNullElements(pair));
- pair.Value.UnifyClusters();
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- protected override bool StandardResult(VCExpr node, bool arg) {
- //Contract.Requires(node != null);
- return false; // by default, do not collect terms containing node
- }
-
- public override bool Visit(VCExprLiteral node, bool arg) {
- Contract.Requires(node != null);
- return true;
- }
-
- public override bool Visit(VCExprNAry node, bool arg) {
- Contract.Requires(node != null);
- VCExprBoogieFunctionOp op = node.Op as VCExprBoogieFunctionOp;
- if (op == null) {
- base.Visit(node, arg);
- return false;
- }
-
- bool res = true;
- foreach (VCExpr subexpr in node) {
- Contract.Assert(subexpr != null);
- res &= this.Traverse(subexpr, arg);
- }
-
- if (res) {
- TermClustersSameHead clusters;
- if (!SubtermClusters.TryGetValue(op, out clusters)) {
- clusters = new TermClustersSameHead(op, GlobalVariables, Gen);
- SubtermClusters.Add(op, clusters);
- }
- cce.NonNull(clusters).AddExpr(node);
- }
-
- return res;
- }
-
- public override bool Visit(VCExprVar node, bool arg) {
- Contract.Requires(node != null);
- if (!BoundTermVars.Contains(node))
- GlobalVariables[node] = node;
- return true;
- }
-
- [Pure]
- public override string ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- string/*!*/ res = "";
- foreach (KeyValuePair<VCExprOp/*!*/, TermClustersSameHead/*!*/> pair
- in SubtermClusters) {
- Contract.Assert(cce.NonNullElements(pair));
- res = res + pair.Value + "\n";
- }
- return res;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- // Class for managing and clustering a set of terms that all start
- // with the same function symbol
- internal class TermClustersSameHead {
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Op != null);
- Contract.Invariant(Gen != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(GlobalVariables));
- }
- // variables that are global and treated like constants
- private readonly IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ GlobalVariables;
- public readonly VCExprOp/*!*/ Op;
- private readonly VCExpressionGenerator/*!*/ Gen;
-
- public TermClustersSameHead(VCExprOp op, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, VCExpressionGenerator/*!*/ gen) {
- Contract.Requires(cce.NonNullDictionaryAndValues(globalVars));
- Contract.Requires(gen != null);
- Contract.Requires(op != null);
- Op = op;
- GlobalVariables = globalVars;
- Gen = gen;
- }
-
- private readonly List<Cluster>/*!*/ Clusters = new List<Cluster>();
-
- private struct Cluster {
- public readonly VCExprNAry/*!*/ Generator;
- public readonly int Size;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Generator != null);
- }
-
- public Cluster(VCExprNAry generator, int size) {
- Contract.Requires(generator != null);
- Generator = generator;
- Size = size;
- }
- }
-
- private int Distance(Cluster a, Cluster b) {
- AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(Gen);
- visitor.AntiUnify(a.Generator, b.Generator);
-
- int reprSizeA, reprSizeB;
- visitor.RepresentationSize(GlobalVariables, out reprSizeA, out reprSizeB);
- return (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB;
- }
-
- private bool EqualUpToRenaming(Cluster a, Cluster b) {
- AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(Gen);
- visitor.AntiUnify(a.Generator, b.Generator);
- return visitor.RepresentationIsRenaming(GlobalVariables);
- }
-
- private Cluster Merge(Cluster a, Cluster b) {
- AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(Gen);
- VCExpr/*!*/ generator = visitor.AntiUnify(a.Generator, b.Generator);
- Contract.Assert(generator != null);
- VCExprNAry generatorNAry = generator as VCExprNAry;
- Contract.Assert(generatorNAry != null && Op.Equals(generatorNAry.Op));
- return new Cluster(generatorNAry, a.Size + b.Size);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- public void AddExpr(VCExprNAry expr) {
- Contract.Requires(expr != null);
- Contract.Requires(Op.Equals(expr.Op));
-
- Cluster c = new Cluster(expr, 1);
- for (int i = 0; i < Clusters.Count; ++i) {
- Cluster d = Clusters[i];
- if (EqualUpToRenaming(c, d)) {
- Clusters[i] = new Cluster(d.Generator, d.Size + 1);
- return;
- }
- }
-
- Clusters.Add(c);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- private struct ClusteringMatrix {
-
- private readonly VCExpressionGenerator/*!*/ Gen;
- private readonly IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ GlobalVariables;
-
- public readonly List<Cluster>/*!*/ Clusters;
- public readonly bool[]/*!*/ RemainingClusters;
-
- public readonly Distance[,]/*!*/ Distances;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Gen != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(GlobalVariables));
- Contract.Invariant(Clusters != null);
- Contract.Invariant(RemainingClusters != null);
- Contract.Invariant(Distances != null);
- }
-
-
- public struct Distance {
- public readonly int Dist;
- public readonly VCExprNAry/*!*/ Generator;
-
- public Distance(Cluster a, Cluster b, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, VCExpressionGenerator gen) {
- Contract.Requires(gen != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(globalVars));
- AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(gen);
- Generator = (VCExprNAry)visitor.AntiUnify(a.Generator, b.Generator);
-
- int reprSizeA, reprSizeB;
- visitor.RepresentationSize(globalVars, out reprSizeA, out reprSizeB);
- Dist = (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB;
- }
- }
-
- public ClusteringMatrix(List<Cluster> clusters, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, VCExpressionGenerator gen) {
- Contract.Requires(gen != null);
- Contract.Requires(clusters != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(globalVars));
- List<Cluster> c = new List<Cluster>();
- c.AddRange(clusters);
- Clusters = c;
-
- GlobalVariables = globalVars;
- Gen = gen;
-
- bool[] remaining = new bool[clusters.Count];
- RemainingClusters = remaining;
- for (int i = 0; i < remaining.Length; ++i)
- remaining[i] = true;
-
- Distance[,]/*!*/ distances = new Distance[clusters.Count, clusters.Count];
- Distances = distances;
- for (int i = 1; i < clusters.Count; ++i)
- for (int j = 0; j < i; ++j)
- distances[i, j] =
- new Distance(clusters[i], clusters[j], GlobalVariables, Gen);
- }
-
- public void UnifyClusters(int maxDist) {
- while (true) {
- int i, j;
- int minDist = FindMinDistance(out i, out j);
-
- if (minDist > maxDist)
- return;
-
- MergeClusters(i, j);
- }
- }
-
- public void ResultingClusters(List<Cluster> clusters) {
- Contract.Requires(clusters != null);
- clusters.Clear();
- for (int i = 0; i < Clusters.Count; ++i)
- if (RemainingClusters[i])
- clusters.Add(Clusters[i]);
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- private void Update(int i) {
- for (int j = 0; j < i; ++j) {
- if (RemainingClusters[j])
- Distances[i, j] =
- new Distance(Clusters[i], Clusters[j], GlobalVariables, Gen);
- }
- for (int j = i + 1; j < Clusters.Count; ++j) {
- if (RemainingClusters[j])
- Distances[j, i] =
- new Distance(Clusters[j], Clusters[i], GlobalVariables, Gen);
- }
- }
-
- private int FindMinDistance(out int c0, out int c1) {
- int minDist = int.MaxValue;
- c0 = -1;
- c1 = -1;
-
- for (int i = 0; i < Clusters.Count; ++i)
- if (RemainingClusters[i]) {
- for (int j = 0; j < i; ++j)
- if (RemainingClusters[j]) {
- if (Distances[i, j].Dist < minDist) {
- minDist = Distances[i, j].Dist;
- c0 = i;
- c1 = j;
- }
- }
- }
-
- Contract.Assert(c0 == -1 && c1 == -1 || c0 > c1 && c1 >= 0);
- return minDist;
- }
-
- private void MergeClusters(int i, int j) {
- Contract.Requires(j >= 0 && i > j && RemainingClusters[i] && RemainingClusters[j]);
- Clusters[i] = new Cluster(Distances[i, j].Generator,
- Clusters[i].Size + Clusters[j].Size);
- RemainingClusters[j] = false;
- Update(i);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- public void UnifyClusters() {
- ClusteringMatrix matrix =
- new ClusteringMatrix(Clusters, GlobalVariables, Gen);
- matrix.UnifyClusters(50);
- matrix.ResultingClusters(Clusters);
- }
-
- [Pure]
- public override string ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- string/*!*/ res = "";
- foreach (Cluster c in Clusters)
- res = res + c.Generator + "\t" + c.Size + "\n";
- return res;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- internal class AntiUnificationVisitor : TraversingVCExprVisitor<VCExpr/*!*/, VCExpr/*!*/> {
-
- private readonly VCExpressionGenerator/*!*/ Gen;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Gen != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(Representation));
- }
-
-
- public AntiUnificationVisitor(VCExpressionGenerator gen) {
- Contract.Requires(gen != null);
- Gen = gen;
- }
-
- // Sub-expressions in the first and second expression to be
- // anti-unified that are replaced with variables
- private readonly IDictionary<ExprPair, VCExprVar/*!*/>/*!*/ Representation =
- new Dictionary<ExprPair, VCExprVar/*!*/>();
-
-
-
- private struct ExprPair {
- public readonly VCExpr/*!*/ Expr0, Expr1;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Expr0 != null);
- Contract.Invariant(Expr1 != null);
- }
-
- public ExprPair(VCExpr expr0, VCExpr expr1) {
- Contract.Requires(expr1 != null);
- Contract.Requires(expr0 != null);
- Expr0 = expr0;
- Expr1 = expr1;
- }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public override bool Equals(object that) {
- if (that is ExprPair) {
- ExprPair thatPair = (ExprPair)that;
- return this.Expr0.Equals(thatPair.Expr0) &&
- this.Expr1.Equals(thatPair.Expr1);
- }
- return false;
- }
- [Pure]
- public override int GetHashCode() {
- return Expr0.GetHashCode() + Expr1.GetHashCode() * 13;
- }
- }
-
- public void Reset() {
- Representation.Clear();
- }
-
- public bool RepresentationIsRenaming(IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars) {
- Contract.Requires(cce.NonNullDictionaryAndValues(globalVars));
- if (!Representation.Any(pair => pair.Key.Expr0 is VCExprVar && pair.Key.Expr1 is VCExprVar && !globalVars.ContainsKey(cce.NonNull((VCExprVar)pair.Key.Expr0)) && !globalVars.ContainsKey(cce.NonNull((VCExprVar/*!*/)pair.Key.Expr1))))
- return false;
- // check that all substituted variables are distinct
- // TODO: optimise
- return
- Representation.All(pair1 => Representation.All(pair2 => pair1.Value.Equals(pair2.Value) || !pair1.Key.Expr0.Equals(pair2.Key.Expr0) && !pair1.Key.Expr1.Equals(pair2.Key.Expr1)));
- }
-
- public void RepresentationSize(IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, out int expr0Size, out int expr1Size) {
- Contract.Requires(cce.NonNullDictionaryAndValues(globalVars));
- ReprSizeComputingVisitor/*!*/ size0Visitor = new ReprSizeComputingVisitor();
- ReprSizeComputingVisitor/*!*/ size1Visitor = new ReprSizeComputingVisitor();
-
- foreach (KeyValuePair<ExprPair, VCExprVar/*!*/> pair in Representation) {
- Contract.Assert(pair.Value != null);
- size0Visitor.ComputeSize(pair.Key.Expr0, globalVars);
- size1Visitor.ComputeSize(pair.Key.Expr1, globalVars);
- }
-
- expr0Size = size0Visitor.Size;
- expr1Size = size1Visitor.Size;
- }
-
- public VCExpr AntiUnify(VCExpr s, VCExpr t) {
- Contract.Requires(t != null);
- Contract.Requires(s != null);
- Contract.Requires((s.Type.Equals(t.Type)));
-Contract.Ensures(Contract.Result<VCExpr>() != null);
- return Traverse(s, t);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- private VCExprVar AbstractWithVariable(VCExpr s, VCExpr t) {
- Contract.Requires(t != null);
- Contract.Requires(s != null);
- Contract.Requires((s.Type.Equals(t.Type)));
-Contract.Ensures(Contract.Result<VCExprVar>() != null);
-
- ExprPair pair = new ExprPair(s, t);
- VCExprVar repr;
- if (!Representation.TryGetValue(pair, out repr)) {
- repr = Gen.Variable("abs" + Representation.Count, s.Type);
- Representation.Add(pair, repr);
- }
- return cce.NonNull(repr);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- public override VCExpr Visit(VCExprLiteral node, VCExpr that) {
- Contract.Requires(that != null);
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
- if (node.Equals(that))
- return node;
- return AbstractWithVariable(node, that);
- }
-
- public override VCExpr Visit(VCExprNAry node, VCExpr that) {
- Contract.Requires(that != null);
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
- VCExprNAry thatNAry = that as VCExprNAry;
- if (thatNAry != null && node.Op.Equals(thatNAry.Op)) {
- // type parameters should already have been eliminated at this
- // stage
- Contract.Assert(node.TypeParamArity == 0 && thatNAry.TypeParamArity == 0 && node.Arity == thatNAry.Arity);
-
- List<VCExpr/*!*/>/*!*/ unifiedArgs = new List<VCExpr/*!*/>();
- for (int i = 0; i < node.Arity; ++i)
- unifiedArgs.Add(Traverse(node[i], thatNAry[i]));
-
- return Gen.Function(node.Op, unifiedArgs);
- }
- return AbstractWithVariable(node, that);
- }
-
- public override VCExpr Visit(VCExprVar node, VCExpr that) {
- Contract.Requires(that != null);
- Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
- if (node.Equals(that))
- return node;
- return AbstractWithVariable(node, that);
- }
-
- protected override VCExpr StandardResult(VCExpr node, VCExpr that) {
- //Contract.Requires(that != null);
- //Contract.Requires(node != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
- Contract.Assert(false);
- throw new cce.UnreachableException(); // not handled here
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- internal class ReprSizeComputingVisitor
- : TraversingVCExprVisitor<bool,
- // variables considered as global constants
- IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/> {
-
- public int Size = 0;
-
- public void ComputeSize(VCExpr expr, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars) {
- Contract.Requires(expr != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(globalVars));
- Traverse(expr, globalVars);
- }
-
- protected override bool StandardResult(VCExpr node, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars) {
- //Contract.Requires(node != null);
- //Contract.Requires(cce.NonNullElements(globalVars));
- VCExprVar nodeAsVar = node as VCExprVar;
- if (nodeAsVar == null || globalVars.ContainsKey(nodeAsVar))
- Size = Size + 1;
- return true;
- }
- }
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Text; +using System.IO; +using System.Linq; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +// Code for managing and clusterings sets of terms; this is used to +// compress the input given to the theorem prover + +namespace Microsoft.Boogie.Clustering { + using Microsoft.Boogie.VCExprAST; + + + public class SubtermCollector : BoundVarTraversingVCExprVisitor<bool, bool> { + + private readonly VCExpressionGenerator/*!*/ Gen; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Gen != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(GlobalVariables)); + Contract.Invariant(cce.NonNullDictionaryAndValues(SubtermClusters)); + } + + + public SubtermCollector(VCExpressionGenerator gen) { + Contract.Requires(gen != null); + Gen = gen; + } + + // variables that are global and treated like constants + private readonly IDictionary<VCExprVar/*!*/, VCExprVar/*!*/> GlobalVariables = new Dictionary<VCExprVar/*!*/, VCExprVar/*!*/>(); + + private readonly IDictionary<VCExprOp/*!*/, TermClustersSameHead/*!*/> SubtermClusters = + new Dictionary<VCExprOp/*!*/, TermClustersSameHead/*!*/>(); + + public void UnifyClusters() { + foreach (KeyValuePair<VCExprOp/*!*/, TermClustersSameHead/*!*/> pair + in SubtermClusters) { + Contract.Assert(cce.NonNullElements(pair)); + pair.Value.UnifyClusters(); + } + } + + //////////////////////////////////////////////////////////////////////////// + + protected override bool StandardResult(VCExpr node, bool arg) { + //Contract.Requires(node != null); + return false; // by default, do not collect terms containing node + } + + public override bool Visit(VCExprLiteral node, bool arg) { + Contract.Requires(node != null); + return true; + } + + public override bool Visit(VCExprNAry node, bool arg) { + Contract.Requires(node != null); + VCExprBoogieFunctionOp op = node.Op as VCExprBoogieFunctionOp; + if (op == null) { + base.Visit(node, arg); + return false; + } + + bool res = true; + foreach (VCExpr subexpr in node) { + Contract.Assert(subexpr != null); + res &= this.Traverse(subexpr, arg); + } + + if (res) { + TermClustersSameHead clusters; + if (!SubtermClusters.TryGetValue(op, out clusters)) { + clusters = new TermClustersSameHead(op, GlobalVariables, Gen); + SubtermClusters.Add(op, clusters); + } + cce.NonNull(clusters).AddExpr(node); + } + + return res; + } + + public override bool Visit(VCExprVar node, bool arg) { + Contract.Requires(node != null); + if (!BoundTermVars.Contains(node)) + GlobalVariables[node] = node; + return true; + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result<string>() != null); + string/*!*/ res = ""; + foreach (KeyValuePair<VCExprOp/*!*/, TermClustersSameHead/*!*/> pair + in SubtermClusters) { + Contract.Assert(cce.NonNullElements(pair)); + res = res + pair.Value + "\n"; + } + return res; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + // Class for managing and clustering a set of terms that all start + // with the same function symbol + internal class TermClustersSameHead { + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Op != null); + Contract.Invariant(Gen != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(GlobalVariables)); + } + // variables that are global and treated like constants + private readonly IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ GlobalVariables; + public readonly VCExprOp/*!*/ Op; + private readonly VCExpressionGenerator/*!*/ Gen; + + public TermClustersSameHead(VCExprOp op, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, VCExpressionGenerator/*!*/ gen) { + Contract.Requires(cce.NonNullDictionaryAndValues(globalVars)); + Contract.Requires(gen != null); + Contract.Requires(op != null); + Op = op; + GlobalVariables = globalVars; + Gen = gen; + } + + private readonly List<Cluster>/*!*/ Clusters = new List<Cluster>(); + + private struct Cluster { + public readonly VCExprNAry/*!*/ Generator; + public readonly int Size; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Generator != null); + } + + public Cluster(VCExprNAry generator, int size) { + Contract.Requires(generator != null); + Generator = generator; + Size = size; + } + } + + private int Distance(Cluster a, Cluster b) { + AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(Gen); + visitor.AntiUnify(a.Generator, b.Generator); + + int reprSizeA, reprSizeB; + visitor.RepresentationSize(GlobalVariables, out reprSizeA, out reprSizeB); + return (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB; + } + + private bool EqualUpToRenaming(Cluster a, Cluster b) { + AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(Gen); + visitor.AntiUnify(a.Generator, b.Generator); + return visitor.RepresentationIsRenaming(GlobalVariables); + } + + private Cluster Merge(Cluster a, Cluster b) { + AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(Gen); + VCExpr/*!*/ generator = visitor.AntiUnify(a.Generator, b.Generator); + Contract.Assert(generator != null); + VCExprNAry generatorNAry = generator as VCExprNAry; + Contract.Assert(generatorNAry != null && Op.Equals(generatorNAry.Op)); + return new Cluster(generatorNAry, a.Size + b.Size); + } + + //////////////////////////////////////////////////////////////////////////// + + public void AddExpr(VCExprNAry expr) { + Contract.Requires(expr != null); + Contract.Requires(Op.Equals(expr.Op)); + + Cluster c = new Cluster(expr, 1); + for (int i = 0; i < Clusters.Count; ++i) { + Cluster d = Clusters[i]; + if (EqualUpToRenaming(c, d)) { + Clusters[i] = new Cluster(d.Generator, d.Size + 1); + return; + } + } + + Clusters.Add(c); + } + + //////////////////////////////////////////////////////////////////////////// + + private struct ClusteringMatrix { + + private readonly VCExpressionGenerator/*!*/ Gen; + private readonly IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ GlobalVariables; + + public readonly List<Cluster>/*!*/ Clusters; + public readonly bool[]/*!*/ RemainingClusters; + + public readonly Distance[,]/*!*/ Distances; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Gen != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(GlobalVariables)); + Contract.Invariant(Clusters != null); + Contract.Invariant(RemainingClusters != null); + Contract.Invariant(Distances != null); + } + + + public struct Distance { + public readonly int Dist; + public readonly VCExprNAry/*!*/ Generator; + + public Distance(Cluster a, Cluster b, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, VCExpressionGenerator gen) { + Contract.Requires(gen != null); + Contract.Requires(cce.NonNullDictionaryAndValues(globalVars)); + AntiUnificationVisitor/*!*/ visitor = new AntiUnificationVisitor(gen); + Generator = (VCExprNAry)visitor.AntiUnify(a.Generator, b.Generator); + + int reprSizeA, reprSizeB; + visitor.RepresentationSize(globalVars, out reprSizeA, out reprSizeB); + Dist = (a.Size - 1) * reprSizeA + (b.Size - 1) * reprSizeB; + } + } + + public ClusteringMatrix(List<Cluster> clusters, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, VCExpressionGenerator gen) { + Contract.Requires(gen != null); + Contract.Requires(clusters != null); + Contract.Requires(cce.NonNullDictionaryAndValues(globalVars)); + List<Cluster> c = new List<Cluster>(); + c.AddRange(clusters); + Clusters = c; + + GlobalVariables = globalVars; + Gen = gen; + + bool[] remaining = new bool[clusters.Count]; + RemainingClusters = remaining; + for (int i = 0; i < remaining.Length; ++i) + remaining[i] = true; + + Distance[,]/*!*/ distances = new Distance[clusters.Count, clusters.Count]; + Distances = distances; + for (int i = 1; i < clusters.Count; ++i) + for (int j = 0; j < i; ++j) + distances[i, j] = + new Distance(clusters[i], clusters[j], GlobalVariables, Gen); + } + + public void UnifyClusters(int maxDist) { + while (true) { + int i, j; + int minDist = FindMinDistance(out i, out j); + + if (minDist > maxDist) + return; + + MergeClusters(i, j); + } + } + + public void ResultingClusters(List<Cluster> clusters) { + Contract.Requires(clusters != null); + clusters.Clear(); + for (int i = 0; i < Clusters.Count; ++i) + if (RemainingClusters[i]) + clusters.Add(Clusters[i]); + } + + ////////////////////////////////////////////////////////////////////////// + + private void Update(int i) { + for (int j = 0; j < i; ++j) { + if (RemainingClusters[j]) + Distances[i, j] = + new Distance(Clusters[i], Clusters[j], GlobalVariables, Gen); + } + for (int j = i + 1; j < Clusters.Count; ++j) { + if (RemainingClusters[j]) + Distances[j, i] = + new Distance(Clusters[j], Clusters[i], GlobalVariables, Gen); + } + } + + private int FindMinDistance(out int c0, out int c1) { + int minDist = int.MaxValue; + c0 = -1; + c1 = -1; + + for (int i = 0; i < Clusters.Count; ++i) + if (RemainingClusters[i]) { + for (int j = 0; j < i; ++j) + if (RemainingClusters[j]) { + if (Distances[i, j].Dist < minDist) { + minDist = Distances[i, j].Dist; + c0 = i; + c1 = j; + } + } + } + + Contract.Assert(c0 == -1 && c1 == -1 || c0 > c1 && c1 >= 0); + return minDist; + } + + private void MergeClusters(int i, int j) { + Contract.Requires(j >= 0 && i > j && RemainingClusters[i] && RemainingClusters[j]); + Clusters[i] = new Cluster(Distances[i, j].Generator, + Clusters[i].Size + Clusters[j].Size); + RemainingClusters[j] = false; + Update(i); + } + } + + //////////////////////////////////////////////////////////////////////////// + + public void UnifyClusters() { + ClusteringMatrix matrix = + new ClusteringMatrix(Clusters, GlobalVariables, Gen); + matrix.UnifyClusters(50); + matrix.ResultingClusters(Clusters); + } + + [Pure] + public override string ToString() { + Contract.Ensures(Contract.Result<string>() != null); + string/*!*/ res = ""; + foreach (Cluster c in Clusters) + res = res + c.Generator + "\t" + c.Size + "\n"; + return res; + } + } + + ////////////////////////////////////////////////////////////////////////////// + + internal class AntiUnificationVisitor : TraversingVCExprVisitor<VCExpr/*!*/, VCExpr/*!*/> { + + private readonly VCExpressionGenerator/*!*/ Gen; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Gen != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(Representation)); + } + + + public AntiUnificationVisitor(VCExpressionGenerator gen) { + Contract.Requires(gen != null); + Gen = gen; + } + + // Sub-expressions in the first and second expression to be + // anti-unified that are replaced with variables + private readonly IDictionary<ExprPair, VCExprVar/*!*/>/*!*/ Representation = + new Dictionary<ExprPair, VCExprVar/*!*/>(); + + + + private struct ExprPair { + public readonly VCExpr/*!*/ Expr0, Expr1; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Expr0 != null); + Contract.Invariant(Expr1 != null); + } + + public ExprPair(VCExpr expr0, VCExpr expr1) { + Contract.Requires(expr1 != null); + Contract.Requires(expr0 != null); + Expr0 = expr0; + Expr1 = expr1; + } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (that is ExprPair) { + ExprPair thatPair = (ExprPair)that; + return this.Expr0.Equals(thatPair.Expr0) && + this.Expr1.Equals(thatPair.Expr1); + } + return false; + } + [Pure] + public override int GetHashCode() { + return Expr0.GetHashCode() + Expr1.GetHashCode() * 13; + } + } + + public void Reset() { + Representation.Clear(); + } + + public bool RepresentationIsRenaming(IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars) { + Contract.Requires(cce.NonNullDictionaryAndValues(globalVars)); + if (!Representation.Any(pair => pair.Key.Expr0 is VCExprVar && pair.Key.Expr1 is VCExprVar && !globalVars.ContainsKey(cce.NonNull((VCExprVar)pair.Key.Expr0)) && !globalVars.ContainsKey(cce.NonNull((VCExprVar/*!*/)pair.Key.Expr1)))) + return false; + // check that all substituted variables are distinct + // TODO: optimise + return + Representation.All(pair1 => Representation.All(pair2 => pair1.Value.Equals(pair2.Value) || !pair1.Key.Expr0.Equals(pair2.Key.Expr0) && !pair1.Key.Expr1.Equals(pair2.Key.Expr1))); + } + + public void RepresentationSize(IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars, out int expr0Size, out int expr1Size) { + Contract.Requires(cce.NonNullDictionaryAndValues(globalVars)); + ReprSizeComputingVisitor/*!*/ size0Visitor = new ReprSizeComputingVisitor(); + ReprSizeComputingVisitor/*!*/ size1Visitor = new ReprSizeComputingVisitor(); + + foreach (KeyValuePair<ExprPair, VCExprVar/*!*/> pair in Representation) { + Contract.Assert(pair.Value != null); + size0Visitor.ComputeSize(pair.Key.Expr0, globalVars); + size1Visitor.ComputeSize(pair.Key.Expr1, globalVars); + } + + expr0Size = size0Visitor.Size; + expr1Size = size1Visitor.Size; + } + + public VCExpr AntiUnify(VCExpr s, VCExpr t) { + Contract.Requires(t != null); + Contract.Requires(s != null); + Contract.Requires((s.Type.Equals(t.Type))); +Contract.Ensures(Contract.Result<VCExpr>() != null); + return Traverse(s, t); + } + + //////////////////////////////////////////////////////////////////////////// + + private VCExprVar AbstractWithVariable(VCExpr s, VCExpr t) { + Contract.Requires(t != null); + Contract.Requires(s != null); + Contract.Requires((s.Type.Equals(t.Type))); +Contract.Ensures(Contract.Result<VCExprVar>() != null); + + ExprPair pair = new ExprPair(s, t); + VCExprVar repr; + if (!Representation.TryGetValue(pair, out repr)) { + repr = Gen.Variable("abs" + Representation.Count, s.Type); + Representation.Add(pair, repr); + } + return cce.NonNull(repr); + } + + //////////////////////////////////////////////////////////////////////////// + + public override VCExpr Visit(VCExprLiteral node, VCExpr that) { + Contract.Requires(that != null); + Contract.Requires(node != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + if (node.Equals(that)) + return node; + return AbstractWithVariable(node, that); + } + + public override VCExpr Visit(VCExprNAry node, VCExpr that) { + Contract.Requires(that != null); + Contract.Requires(node != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + VCExprNAry thatNAry = that as VCExprNAry; + if (thatNAry != null && node.Op.Equals(thatNAry.Op)) { + // type parameters should already have been eliminated at this + // stage + Contract.Assert(node.TypeParamArity == 0 && thatNAry.TypeParamArity == 0 && node.Arity == thatNAry.Arity); + + List<VCExpr/*!*/>/*!*/ unifiedArgs = new List<VCExpr/*!*/>(); + for (int i = 0; i < node.Arity; ++i) + unifiedArgs.Add(Traverse(node[i], thatNAry[i])); + + return Gen.Function(node.Op, unifiedArgs); + } + return AbstractWithVariable(node, that); + } + + public override VCExpr Visit(VCExprVar node, VCExpr that) { + Contract.Requires(that != null); + Contract.Requires(node != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + if (node.Equals(that)) + return node; + return AbstractWithVariable(node, that); + } + + protected override VCExpr StandardResult(VCExpr node, VCExpr that) { + //Contract.Requires(that != null); + //Contract.Requires(node != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + Contract.Assert(false); + throw new cce.UnreachableException(); // not handled here + } + } + + ////////////////////////////////////////////////////////////////////////////// + + internal class ReprSizeComputingVisitor + : TraversingVCExprVisitor<bool, + // variables considered as global constants + IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/> { + + public int Size = 0; + + public void ComputeSize(VCExpr expr, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars) { + Contract.Requires(expr != null); + Contract.Requires(cce.NonNullDictionaryAndValues(globalVars)); + Traverse(expr, globalVars); + } + + protected override bool StandardResult(VCExpr node, IDictionary<VCExprVar/*!*/, VCExprVar/*!*/>/*!*/ globalVars) { + //Contract.Requires(node != null); + //Contract.Requires(cce.NonNullElements(globalVars)); + VCExprVar nodeAsVar = node as VCExprVar; + if (nodeAsVar == null || globalVars.ContainsKey(nodeAsVar)) + Size = Size + 1; + return true; + } + } }
\ No newline at end of file |