/// <summary> /// Restrict top down wrt the path condition and strengthen the leaf predicates with psi /// </summary> BDG <T, S> Restrict(S path, T psi) { var key = new Tuple <S, T, BDG <T, S> >(path, psi, this); BDG <T, S> val; if (!algebra.restrictCache.TryGetValue(key, out val)) { if (this.IsLeaf) { val = this.algebra.MkLeaf(this.algebra.leafAlgebra.MkAnd(this.LeafCondition, psi), true); } else { #region restrict the children var path_and_not_nodePred = algebra.nodeAlgebra.MkAnd(path, algebra.nodeAlgebra.MkNot(BranchCondition)); if (algebra.nodeAlgebra.IsSatisfiable(path_and_not_nodePred)) { var f = this.FalseCase.Restrict(path_and_not_nodePred, psi); var path_and_nodePred = algebra.nodeAlgebra.MkAnd(path, BranchCondition); if (algebra.nodeAlgebra.IsSatisfiable(path_and_nodePred)) { var t = this.TrueCase.Restrict(path_and_nodePred, psi); if (f == this.FalseCase && t == this.TrueCase) { val = this; //nothing changed } else { val = this.algebra.MkNode(BranchCondition, t, f); } } else //path implies not(nodePred) { val = f; } } else //path implies nodePred { val = TrueCase.Restrict(path, psi); } #endregion } algebra.restrictCache[key] = val; } return(val); }
/// <summary> /// Maintains the node invariant: sat(path & nodePred) and sat(path & ~nodePred) /// </summary> BDG <T, S> MkAnd(S path, BDG <T, S> that) { var key = new Tuple <S, BDG <T, S>, BDG <T, S> >(path, this, that); BDG <T, S> val; if (!algebra.MkAndCache.TryGetValue(key, out val)) { if (this.IsLeaf) { if (path.Equals(algebra.nodeAlgebra.True)) { val = that.RestrictLeaves(this.LeafCondition); } else { val = that.Restrict(path, this.LeafCondition); } } else if (that.IsLeaf) { val = this.RestrictLeaves(that.LeafCondition); //path is not relevant } else { var path_and_thatCond = algebra.nodeAlgebra.MkAnd(path, that.BranchCondition); if (!algebra.nodeAlgebra.IsSatisfiable(path_and_thatCond)) { //path implies ~that.BranchCondition var t = this.TrueCase.MkAnd(algebra.nodeAlgebra.MkAnd(path, this.BranchCondition), that.FalseCase); var f = this.FalseCase.MkAnd(algebra.nodeAlgebra.MkAnd(path, algebra.nodeAlgebra.MkNot(this.BranchCondition)), that.FalseCase); if (t == this.TrueCase && f == this.FalseCase) { val = this; } else { val = this.algebra.MkNode(this.BranchCondition, t, f); } } else { var path_and_not_thatCond = algebra.nodeAlgebra.MkAnd(path, algebra.nodeAlgebra.MkNot(that.BranchCondition)); if (!algebra.nodeAlgebra.IsSatisfiable(path_and_not_thatCond)) { //path implies that.BranchCondition var t = this.TrueCase.MkAnd(algebra.nodeAlgebra.MkAnd(path, this.BranchCondition), that.TrueCase); var f = this.FalseCase.MkAnd(algebra.nodeAlgebra.MkAnd(path, algebra.nodeAlgebra.MkNot(this.BranchCondition)), that.TrueCase); if (t == this.TrueCase && f == this.FalseCase) { val = this; } else { val = this.algebra.MkNode(this.BranchCondition, t, f); } } else { //both cases are possible var t = this.TrueCase.MkAnd(algebra.nodeAlgebra.MkAnd(path, this.BranchCondition), that); var f = this.FalseCase.MkAnd(algebra.nodeAlgebra.MkAnd(path, algebra.nodeAlgebra.MkNot(this.BranchCondition)), that); if (t == this.TrueCase && f == this.FalseCase) { val = this; } else { val = this.algebra.MkNode(this.BranchCondition, t, f); } } } } algebra.MkAndCache[key] = val; } return(val); }