/*
* Copyright (C) 2018 Alexander Nutz (nutz@informatik.uni-freiburg.de)
* Copyright (C) 2018 University of Freiburg
*
* This file is part of the ULTIMATE Util Library.
*
* The ULTIMATE Util Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ULTIMATE Util Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ULTIMATE Util Library. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE Util Library, or any covered work, by linking
* or combining it with Eclipse RCP (or a modified version of Eclipse RCP),
* containing parts covered by the terms of the Eclipse Public License, the
* licensors of the ULTIMATE Util Library grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.util.datastructures.congruenceclosure;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import de.uni_freiburg.informatik.ultimate.util.datastructures.DataStructureUtils;
import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation;
/**
* Handles "literal set" constraints. In addition to equalities and disequalities, A CongruenceClosure may have
* constraints of the form "l in L", where l is a literal and L is a set of literals. These constraints are handled
* through an instance of this class.
*
* @author Alexander Nutz (nutz@informatik.uni-freiburg.de)
*
*/
public class CCLiteralSetConstraints> {
private final CcManager mCcManager;
SetConstraintManager mSetConstraintManager;
private CongruenceClosure mCongruenceClosure;
private Map> mContainsConstraints;
private boolean mIsInconsistent;
public CCLiteralSetConstraints(final CcManager manager, final CongruenceClosure congruenceClosure) {
mCcManager = manager;
mCongruenceClosure = congruenceClosure;
mSetConstraintManager = manager.getSetConstraintManager();
mContainsConstraints = new HashMap<>();
mIsInconsistent = false;
// assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
}
/**
* copy constructor
*
* @param manager
* @param congruenceClosure
* @param containsConstraints
*/
CCLiteralSetConstraints(final CcManager manager, final CongruenceClosure congruenceClosure,
final CCLiteralSetConstraints litSetConstraints) {
assert !litSetConstraints.isInconsistent();
mCcManager = manager;
mCongruenceClosure = congruenceClosure;
mSetConstraintManager = manager.getSetConstraintManager();
mContainsConstraints = new HashMap<>();
// deep copy
for (final Entry> en : litSetConstraints.getConstraints().entrySet()) {
mContainsConstraints.put(en.getKey(), new SetConstraintConjunction<>(this, en.getValue()));
}
mIsInconsistent = false;
// assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
}
public HashRelation reportContains(final ELEM element, final Set> constraintRaw) {
assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
final ELEM elementRep = mCongruenceClosure.getRepresentativeElement(element);
final Set> constraintUpdRep =
mSetConstraintManager.updateOnChangedRepresentative(constraintRaw, mCongruenceClosure);
final Set> oldConstraint = getConstraint(element);
// just for analogy to reportEquality
mContainsConstraints.remove(elementRep);
Set> newConstraint;
if (oldConstraint != null) {
newConstraint = DataStructureUtils.union(oldConstraint, constraintUpdRep);
} else {
newConstraint = constraintUpdRep;
}
HashRelation equalitiesToPropagate = null;
if (newConstraint != null) {
equalitiesToPropagate = updateContainsConstraintApplyPropagations(elementRep, newConstraint);
}
return equalitiesToPropagate;
}
public HashRelation reportContains(final ELEM element, final Collection elements) {
assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
if (isInconsistent()) {
// nothing to do
return null;
}
mCcManager.addElement(mCongruenceClosure, element, true, false);
mCcManager.addAllElements(mCongruenceClosure, elements, null, true);
final ELEM elementRep = mCongruenceClosure.getRepresentativeElement(element);
return reportContains(elementRep, Collections.singleton(mSetConstraintManager.buildSetConstraint(elements)));// additionalConstraint);
}
/**
*
* @param constrainedElemRep
* @param newConstraint
* @return a pair of elements whose equality should be propagated, or null
*/
private HashRelation updateContainsConstraintApplyPropagations(final ELEM constrainedElemRep,
final Set> newConstraint) {
assert !mContainsConstraints.containsKey(constrainedElemRep) : "assuming this has been removed before";
assert mCongruenceClosure.isRepresentative(constrainedElemRep);
assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
final HashRelation result = new HashRelation<>();
final Set> newConstraintFiltered =
mSetConstraintManager.filterWithDisequalities(mCongruenceClosure, constrainedElemRep, newConstraint);
/*
* rule: e in {} --> \bot
*/
if (newConstraintFiltered.stream().anyMatch(SetConstraint::isInconsistent)) {
reportInconsistency();
return result;
}
final Set> newConstraint1 =
mCcManager.normalizeSetConstraintConjunction(this, newConstraintFiltered);
/*
* rule: e in {l} --> e ~ l (containsConstraint is implicit in this case)
*/
for (final ELEM sv : mSetConstraintManager.getSingletonValues(newConstraint1)) {
if (!constrainedElemRep.equals(sv)) {
result.addPair(constrainedElemRep, sv);
}
}
final SetConstraintConjunction newConstraint2 =
mCcManager.buildSetConstraintConjunction(this, constrainedElemRep, newConstraint1);
if (!newConstraint2.isTautological()) {
// not tautological, not a singeton --> save the new constraint
putContainsConstraint(constrainedElemRep, newConstraint2);
}
assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
return result;
}
private void reportInconsistency() {
mIsInconsistent = true;
mContainsConstraints = null;
}
/**
* Call this when an equality is reported in mCongruenceClosure
* updates representatives
* applies the rule "e ~ l --> e in {l}" (if one of the elements is a literal) EDIT: this rule is automatically
* dealt with because we only store representatives here and literals are always the representatives of their
* equivalence class. We leave the containments l in {l} implicit.
*
* EDIT (may18): what was not dealt with before: updating representatives may not be enough, because some
* propagation rules might trigger: e.g., if one of the newly equated elements has a disequality constraint, and one
* has a set constraint, they might interact (example: e1 in {l1, l2}, e2 != l1, e2 != l2 && e1 = e2 --> bottom)
*
* @param elem1OldRep
* @param elem2OldRep
* @param newRep
* @return
*/
public HashRelation reportEquality(final ELEM elem1OldRep, final ELEM elem2OldRep, final ELEM newRep) {
assert mCongruenceClosure.getRepresentativeElement(elem1OldRep) == newRep;
assert mCongruenceClosure.getRepresentativeElement(elem2OldRep) == newRep;
if (isInconsistent()) {
// nothing to do
return null;
}
Set> elem1LiteralSet = getConstraint(elem1OldRep);
Set> elem2LiteralSet = getConstraint(elem2OldRep);
mContainsConstraints.remove(elem1OldRep);
mContainsConstraints.remove(elem2OldRep);
if (elem1LiteralSet != null) {
elem1LiteralSet = mSetConstraintManager.updateOnChangedRepresentative(elem1LiteralSet, elem1OldRep,
elem2OldRep, newRep);
}
if (elem2LiteralSet != null) {
elem2LiteralSet = mSetConstraintManager.updateOnChangedRepresentative(elem2LiteralSet, elem1OldRep,
elem2OldRep, newRep);
}
Set> newConstraint = null;
if (elem1LiteralSet != null && elem2LiteralSet != null) {
newConstraint = mSetConstraintManager.meet(this, elem1LiteralSet, elem2LiteralSet);
} else if (elem1LiteralSet != null) {
newConstraint = elem1LiteralSet;
} else if (elem2LiteralSet != null) {
newConstraint = elem2LiteralSet;
} else {
// no contains-constraints on either element present --> nothing to do
}
// update the other set constraints according to the change in representatives
for (final Entry> en : new HashSet<>(mContainsConstraints.entrySet())) {
final Set> oldSc = en.getValue().getSetConstraints();
final Set> newSc =
mSetConstraintManager.updateOnChangedRepresentative(oldSc, elem1OldRep, elem2OldRep, newRep);
assert newSc == oldSc || mSetConstraintManager.getSingletonValues(newSc).isEmpty();
final SetConstraintConjunction updated =
newSc == oldSc ? en.getValue() : mCcManager.buildSetConstraintConjunction(this, en.getKey(), newSc);
mContainsConstraints.put(en.getKey(), updated);
}
HashRelation eqToProp = null;
if (newConstraint != null) {
eqToProp = updateContainsConstraintApplyPropagations(newRep, newConstraint);
}
assert CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3 || sanityCheck();
return eqToProp;
}
public CCLiteralSetConstraints merge(final CongruenceClosure newCc,
final HashRelation thisSplitInfo, final HashRelation otherSplitInfo,
final CCLiteralSetConstraints other, final BinaryOperator>> literalMergeOperator) {
if (this.isInconsistent()) {
return other;
}
if (other.isInconsistent()) {
return this;
}
/*
* Note that we cannot do shortcut on (this.isTautological() || other.isTautological()) here, because if we join
* x = 1 and x = 2, the literal set constraints by themselves are tautological/empty..
*/
final CCLiteralSetConstraints newSetConstraints = new CCLiteralSetConstraints<>(mCcManager, newCc);
final Map> newContainsConstraints = new HashMap<>();
for (final ELEM constrainedElem : newCc.getAllRepresentatives()) {
final Set> thisConstraint =
this.getConstraintWrtSplit(constrainedElem, newCc, thisSplitInfo);
final Set> otherConstraint =
other.getConstraintWrtSplit(constrainedElem, newCc, otherSplitInfo);
final Set> newConstraints = literalMergeOperator.apply(thisConstraint, otherConstraint);
assert mSetConstraintManager.getSingletonValues(newConstraints).stream()
.filter(sv -> !newCc.getRepresentativeElement(sv).equals(constrainedElem))
.collect(Collectors.toSet()).isEmpty() : "created non-tautological singleton set constraints "
+ "--> report them, befor buildSetConstraintConj.. throws them away!";
final SetConstraintConjunction newConstraint =
mCcManager.buildSetConstraintConjunction(newSetConstraints, constrainedElem, newConstraints);
if (SetConstraintManager.isTautological(newConstraint)) {
// tautological constraint --> nothing to add
} else {
newContainsConstraints.put(constrainedElem, newConstraint);
}
}
newSetConstraints.setContainsConstraints(newContainsConstraints);
return newSetConstraints;
}
private void setContainsConstraints(final Map> newContainsConstraints) {
mContainsConstraints = newContainsConstraints;
}
public boolean isStrongerThan(final CCLiteralSetConstraints other) {
assert CcManager.isPartitionStronger(this.getCongruenceClosure().mElementTVER,
other.getCongruenceClosure().mElementTVER) : "assuming this has been checked already";
final Set constrainedElements = new HashSet<>();
constrainedElements.addAll(mContainsConstraints.keySet());
constrainedElements.addAll(other.mContainsConstraints.keySet());
final HashRelation splitInfo =
CcManager.computeSplitInfo(this.getCongruenceClosure(), other.getCongruenceClosure());
for (final ELEM elem : constrainedElements) {
// [old: the two constraints must be in terms of the same representatives --> adapt the first to the
// second..]
/*
* update the literal constraints wrt the split that the congruenceclosure has between first and second (at
* this point we already know that the Cc of other is weaker or equal than the Cc of this, so the partition
* can only be finer.
*/
final Set> firstConstraint = // this.getConstraint(elem);
// mSetConstraintManager.updateOnChangedRepresentative(this.getConstraint(elem),
// other.getCongruenceClosure());
getConstraintWrtSplit(elem, other.getCongruenceClosure(), splitInfo);
final Set> secondConstraint = other.getConstraint(elem);
if (!mSetConstraintManager.isStrongerThan(firstConstraint, secondConstraint)) {
return false;
}
}
return true;
}
public boolean isInconsistent() {
return mIsInconsistent;
}
boolean sanityCheck() {
if (mIsInconsistent) {
return true;
}
/*
* we only store representatives in our set of constraints, i.e., for each explicitly stored constraint
* "e in L", e must be a representative in mCongruenceClosure. we leave the constraints of the form
* "l in {l}" implicit.
*/
// for (final ELEM el : mContainsConstraints.keySet()) {
for (final Entry> en : mContainsConstraints.entrySet()) {
if (!mCongruenceClosure.isRepresentative(en.getKey())) {
assert false;
return false;
}
if (en.getValue().isTautological()) {
assert false;
return false;
}
// this is not a violation: e.g., 2 in {x, y} is a valid (in the sense of "sane") constraint
// if (en.getKey().isLiteral()) {
// assert false;
// return false;
// }
}
/*
* for any constrain "e in L", all elements of L must be literals
*/
for (final SetConstraintConjunction constraint : mContainsConstraints.values()) {
if (!constraint.sanityCheck()) {
assert false;
return false;
}
if (constraint.mSurroundingCCSetConstraints != this) {
assert false;
return false;
}
// if (literalSet.size() == 1) {
// // we leave constraints of the form l in {l} implicit
// assert false;
// return false;
// }
// if (!literalSet.stream().allMatch(ELEM::isLiteral)) {
// assert false;
// return false;
// }
}
if (mCongruenceClosure.mLiteralSetConstraints != this) {
assert false;
return false;
}
return true;
}
public Map> getConstraints() {
return Collections.unmodifiableMap(mContainsConstraints);
}
/**
* Return the constraint of the form "e in L U N" that the set constraints of mCongruenceClosure puts on elem.
*
* If there is a set constraint, return the set. Otherwise return null (for "unconstrained")
*
* @param elem
* @return
*/
Set> getConstraint(final ELEM elem) {
if (!mCongruenceClosure.hasElement(elem)) {
return null;
}
final Set> result = new HashSet<>();
final ELEM rep = mCongruenceClosure.getRepresentativeElement(elem);
/* an equality x ~ y implies a set constraint x in {y}, which we add to the conjunction. */
// if (!rep.equals(elem)) {
result.add(mSetConstraintManager.buildSetConstraint(Collections.singleton(rep)));
// }
// dont do this: (only talk about representatives..)
// for (final ELEM eqMember : mCongruenceClosure.getEquivalenceClass(elem)) {
// result.add(mSetConstraintManager.buildSetConstraint(Collections.singleton(eqMember)));
// }
{
final SetConstraintConjunction sccRep = mContainsConstraints.get(rep);
if (sccRep != null) {
result.addAll(sccRep.getSetConstraints());
}
/*
* for good measure: also check if there is a constraint stored under elem when elem is not rep (happens
* during CCLiteralSetConstraint.reportEquality
*/
final SetConstraintConjunction sccEl = mContainsConstraints.get(elem);
if (sccEl != null) {
result.addAll(sccEl.getSetConstraints());
}
}
if (result.isEmpty()) {
// could not find any elements for the set constraint
return null;
}
return result;
}
/**
* Get the constraints that this CCLiteralSetConstraints instance puts on constrainedElem, relative to the
* equivalence relation in newCc.
*
* E.g. if this contains a set constraint x in {a , b}, and splitInfo contains a -> {c, d}, then we replace that set
* constraint by x in {c, b} /\ x in {d, b}.
*
*
* [old (wrt. that getConstraint takes into account equalities): (e.g. mCongruenceClosure = {!x, y, z,a}, newCc =
* {x, !y, z}, {!a}, constrainedElem = x, (representatives are marked with "!"), then the result should be "x in {y}
* /\ x in {a}") ]
*
* @param constrainedElem
* @param ccWithFinerPartition
* TODO remove this param?
* @return
*/
private Set> getConstraintWrtSplit(final ELEM constrainedElem,
final CongruenceClosure ccWithFinerPartition, final HashRelation splitInfo) {
if (!mCongruenceClosure.hasElement(constrainedElem)) {
return null;
}
final Set> oldConstraint = getConstraint(constrainedElem);
if (oldConstraint == null) {
return null;
}
// initialize to constraint relative to old Cc
Set> result = new HashSet<>(oldConstraint);
for (final ELEM oldRep : splitInfo.getDomain()) {
assert !mCongruenceClosure.hasElement(oldRep) || mCongruenceClosure.isRepresentative(oldRep);
final Set> newResult = new HashSet<>();
for (final SetConstraint sc : result) {
/*
* add a constraint for each newRep corresponding to oldRep, where oldRep has been replaced with that
* newRep
*/
for (final ELEM newRep : splitInfo.getImage(oldRep)) {
assert ccWithFinerPartition.isRepresentative(newRep);
newResult.add(mSetConstraintManager.transformElements(sc, e -> e.equals(oldRep) ? newRep : e));
}
}
result = newResult;
}
return result;
}
public void setCongruenceClosure(final CongruenceClosure congruenceClosure) {
assert mCongruenceClosure == null : "never re-set the congruence closure!";
mCongruenceClosure = congruenceClosure;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("CCLiteralSetConstraints:\n");
for (final Entry> en : getConstraints().entrySet()) {
sb.append(en.getValue());
sb.append("\n");
}
return sb.toString();
}
public void projectAway(final ELEM elem) {
// EDIT: makes no sense: this is called during removal, when elem may already have been removed from mCc
// if (!mCongruenceClosure.hasElement(elem)) {
// // element not present, do nothing
// return;
// }
// assert mCongruenceClosure.isRepresentative(elem) : "right?..";
// remove constraints of the form "elem in S"
mContainsConstraints.remove(elem);
/*
* remove constraints that have elem on their right hand side (a more precise alternative would be to introduce
* a dummy element, effectively an existentially quantified variable.. but we would have to introduce one for
* every projected element, right?..)
*/
for (final Entry> en : new HashSet<>(mContainsConstraints.entrySet())) {
en.getValue().projectAway(elem);
// clean up constraints that became tautological
if (en.getValue().isTautological()) {
mContainsConstraints.remove(en.getKey());
}
}
}
public void replaceRepresentative(final ELEM oldRep, final ELEM newRep) {
// replace elem in constraints of the form "elem in S"
final SetConstraintConjunction constraints = mContainsConstraints.remove(oldRep);
if (constraints != null && newRep != null) {
putContainsConstraint(newRep, constraints);
}
// replace elem in any right hand side set of a constraint
for (final Entry> en : new HashSet<>(mContainsConstraints.entrySet())) {
final Set> oldSc = en.getValue().getSetConstraints();
final Set> newSc =
mSetConstraintManager.updateOnChangedRepresentative(oldSc, oldRep, newRep);
assert mSetConstraintManager.getSingletonValues(newSc).isEmpty();
final SetConstraintConjunction updated =
newSc == oldSc ? en.getValue() : mCcManager.buildSetConstraintConjunction(this, en.getKey(), newSc);
putContainsConstraint(en.getKey(), updated);
}
}
public SetConstraintConjunction putContainsConstraint(final ELEM newRep,
final SetConstraintConjunction constraints) {
assert constraints.mSurroundingCCSetConstraints == this;
return mContainsConstraints.put(newRep, constraints);
}
public void reportDisequality(final ELEM elem1, final ELEM elem2) {
final ELEM elem1Rep = mCongruenceClosure.getRepresentativeElement(elem1);
final ELEM elem2Rep = mCongruenceClosure.getRepresentativeElement(elem2);
assert !elem1Rep.isLiteral() || !elem2Rep.isLiteral() : "literal disequalities should be implicit and not "
+ "reported";
// rule: e in L /\ e != l --> e in L\{l}
{
final Set> elem2Constraint = getConstraint(elem2Rep);// mContainsConstraints.get(elem2Rep);
if (elem2Constraint != null) {
final Set> elem2ConstraintFiltered =
mSetConstraintManager.filterWithDisequality(elem2Constraint, elem1Rep);
if (elem2ConstraintFiltered != elem2Constraint) {
// made changes
assert mSetConstraintManager.getSingletonValues(elem2ConstraintFiltered).isEmpty();
final SetConstraintConjunction newConstraint =
mCcManager.buildSetConstraintConjunction(this, elem2Rep, elem2ConstraintFiltered);
// rule: e in {} --> \bot
if (newConstraint.isInconsistent()) {
reportInconsistency();
}
putContainsConstraint(elem2Rep, newConstraint);
} else {
// made no changes
}
}
}
// rule: e in L /\ e != l --> e in L\{l}
{
final Set> elem1Constraint = getConstraint(elem1Rep);
if (elem1Constraint != null) {
final Set> elem1ConstraintFiltered =
mSetConstraintManager.filterWithDisequality(elem1Constraint, elem2Rep);
if (elem1ConstraintFiltered != elem1Constraint) {
// made changes
final SetConstraintConjunction newConstraint =
mCcManager.buildSetConstraintConjunction(this, elem1Rep, elem1ConstraintFiltered);
// rule: e in {} --> \bot
if (newConstraint.isInconsistent()) {
reportInconsistency();
}
putContainsConstraint(elem1Rep, newConstraint);
} else {
// made no changes
}
}
}
}
/**
*
* @param constraintsToKeepReps
* @return CCliteralSetconstraints where all constraints constrain an element in the given set. CongrunceClosure
* field is left at null.
*/
public CCLiteralSetConstraints
filterAndKeepOnlyConstraintsThatIntersectWith(final Set constraintsToKeepReps) {
assert !isInconsistent() : "handle this case";
final CCLiteralSetConstraints result = new CCLiteralSetConstraints<>(mCcManager, null);
for (final Entry> en : mContainsConstraints.entrySet()) {
if (constraintsToKeepReps.contains(en.getKey())) {
result.putContainsConstraint(en.getKey(), new SetConstraintConjunction<>(result, en.getValue()));
}
if (DataStructureUtils.haveNonEmptyIntersection(constraintsToKeepReps, en.getValue().getAllRhsElements())) {
result.putContainsConstraint(en.getKey(), new SetConstraintConjunction<>(result, en.getValue()));
}
}
assert !result.isInconsistent();
return result;
}
public void transformElements(final Function elemTransformer) {
final Map> copy = new HashMap<>(mContainsConstraints);
for (final Entry> en : copy.entrySet()) {
mContainsConstraints.remove(en.getKey());
final ELEM keyTransformed = elemTransformer.apply(en.getKey());
final Set> valueTransformedSet =
mSetConstraintManager.transformElements(en.getValue().getSetConstraints(), elemTransformer);
assert mSetConstraintManager.getSingletonValues(valueTransformedSet).isEmpty();
final SetConstraintConjunction valueTransformed =
mCcManager.buildSetConstraintConjunction(this, keyTransformed, valueTransformedSet);
putContainsConstraint(keyTransformed, valueTransformed);
}
}
public CongruenceClosure getCongruenceClosure() {
return mCongruenceClosure;
}
public HashRelation getElemToExpansion() {
final HashRelation result = new HashRelation<>();
for (final Entry> en : mContainsConstraints.entrySet()) {
if (en.getValue().hasOnlyLiterals()) {
result.addAllPairs(en.getKey(), en.getValue().getLiterals());
}
}
return result;
}
/**
*
* @return true iff this is not inconsistent and no literal constraints are stored explicitly (note that if
* mCongruenceClosure has equalities there are non-tautological literal constraints which are not stored
* explicitly)
*/
public boolean isEmpty() {
if (isInconsistent()) {
return false;
}
return mContainsConstraints.isEmpty();
}
public Set getRelatedElements(final ELEM rep) {
assert mCongruenceClosure.isRepresentative(rep);
final Set result = new HashSet<>();
{
final Set> c = getConstraint(rep);
if (c != null) {
c.forEach(sc -> sc.getElementSet().forEach(result::add));
}
}
for (final Entry> en : getConstraints().entrySet()) {
if (en.getKey().equals(rep)) {
en.getValue().getAllRhsElements().forEach(result::add);
} else {
if (en.getValue().getAllRhsElements().contains(rep)) {
en.getValue().getAllRhsElements().forEach(result::add);
result.add(en.getKey());
}
}
}
result.remove(rep);
return result;
}
/**
* method for queries from the outside
*
* @param elem
* @return
*/
// public SetConstraintConjunction getContainsConstraint(final ELEM elem) {
public Set> getContainsConstraint(final ELEM elem) {
return getConstraint(elem);
// final ELEM rep = mCongruenceClosure.getRepresentativeElement(elem);
// return mContainsConstraints.get(rep);
}
public boolean isConstrained(final ELEM elem) {
if (elem != mCongruenceClosure.getRepresentativeElement(elem)) {
throw new AssertionError(
"this is only called when elem is " + "unconstrained on mCongruenceClosure.mElementTVER, right?");
}
return mContainsConstraints.get(elem) != null;
}
public Set getAllElementsMentionedInASetConstraint() {
final Set result = new HashSet<>();
for (final Entry> en : mContainsConstraints.entrySet()) {
result.add(en.getValue().getConstrainedElement());
result.addAll(en.getValue().getAllRhsElements());
}
return result;
}
}