/// <summary>
        /// Removes all the variables whom value depends on <code>varsToRemove</code>
        /// </summary>
        /// <param name="alreadyVisited">the variables we have already visited</param>
        private void ProjectVariablesTransitively(Expression varToRemove, ISet <Expression> alreadyVisited)
        {
            alreadyVisited.Add(varToRemove);

            ISet <Expression> continuation = new Set <Expression>();

            foreach (Expression v in this.var2exp.Keys)
            {
                FlatAbstractDomainWithComparer <Expression> liftedExp = this.var2exp[v];

                if (liftedExp.IsBottom || liftedExp.IsTop)
                {
                    continue;
                }

                Expression exp = liftedExp.BoxedElement;

                if (this.decoder.VariablesIn(exp).Contains(varToRemove))
                {
                    continuation.Add(v);
                }
            }

            foreach (Expression nextVarToRemove in continuation)
            {
                if (!alreadyVisited.Contains(nextVarToRemove))
                {
                    ProjectVariablesTransitively(nextVarToRemove, alreadyVisited);
                }
            }
        }
        /// <summary>
        /// Renames all the occurrencies of <code>oldName</code> with <code>newName</code>
        /// </summary>
        public void RenameVariable(Expression /*!*/ oldName, Expression /*!*/ newName)
        {
            if (!this.var2exp.ContainsKey(oldName))
            {
                return;
            }

            this.var2exp[newName] = this.var2exp[oldName];

            foreach (Expression var in this.var2exp.Keys)
            {
                if (!var.Equals(oldName))
                {
                    FlatAbstractDomainWithComparer <Expression> element = this.var2exp[var];

                    if (element.IsBottom || element.IsTop)
                    {
                        continue;
                    }

                    this.var2exp[var] = new FlatAbstractDomainWithComparer <Expression>(this.encoder.Substitute(element.BoxedElement, oldName, newName), this.decoder);
                }
            }

            this.var2exp.Remove(oldName);
        }
        public void RemoveVariable(Expression /*!*/ var)
        // ^ requires this.var2exp.ContainsKey(var);
        {
            this.var2exp.Remove(var);

            ISet <Expression> toProject = new Set <Expression>();

            foreach (Expression v in this.var2exp.Keys)
            {
                FlatAbstractDomainWithComparer <Expression> liftedExp = this.var2exp[v];

                if (liftedExp.IsBottom || liftedExp.IsTop)
                {
                    continue;
                }

                Expression exp = liftedExp.BoxedElement;

                if (this.decoder.VariablesIn(exp).Contains(var))
                {
                    toProject.Add(v);
                }
            }

            foreach (Expression v in toProject)
            {
                this.ProjectVariable(v);
            }
        }
        /// <summary>
        /// Initialize the static fields, if they are not already initialized
        /// </summary>
        private void InitStaticFields()
        {
            Debug.Assert(this.encoder != null && this.decoder != null, "At this point I already need a decoder and an encoder");

            // Check if we have already initialized all the maps
            if (cachedTopMap != null && cachedBottomExpression != null && cachedTopExpression != null)
            {
                return;
            }

            Expression dummyForTop = this.encoder.FreshVariable <int>();
            FlatAbstractDomainWithComparer <Expression> topVal = (FlatAbstractDomainWithComparer <Expression>) new FlatAbstractDomainWithComparer <Expression>(dummyForTop, null).Top;

            cachedTopMap = new SimpleFunctional <Expression, FlatAbstractDomainWithComparer <Expression> >();
            cachedTopMap.Add(dummyForTop, topVal);

            cachedBottomExpression = (FlatAbstractDomainWithComparer <Expression>)topVal.Bottom;
            cachedTopExpression    = topVal;
        }