package de.uni_freiburg.informatik.ultimate.util.datastructures.congruenceclosure; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Represents a conjunction over single set constraints that all constrain the * same element. * * @author Alexander Nutz (nutz@informatik.uni-freiburg.de) * * @param */ public class SetConstraintConjunction> { private ELEM mConstrainedElement; final CCLiteralSetConstraints mSurroundingCCSetConstraints; private final SetConstraintManager mSetConstraintManager; private Set> mSetConstraints; private final SetConstraint mScWithOnlyLiterals; /** * sufficient but not a necessary condition for inconsistency */ private boolean mIsInconsistent; /** * special constructor for an inconsistent SetCc * * @param isInconsistent */ public SetConstraintConjunction(final boolean isInconsistent) { assert isInconsistent : "use other constructor in this case!!"; mConstrainedElement = null; mIsInconsistent = true; mSetConstraints = null; mSurroundingCCSetConstraints = null; mScWithOnlyLiterals = null; mSetConstraintManager = null; assert sanityCheck(); } public SetConstraintConjunction(final CCLiteralSetConstraints surroundingSetConstraints, final ELEM constrainedElement, final Collection> setConstraintsRaw) { mConstrainedElement = constrainedElement; mSurroundingCCSetConstraints = surroundingSetConstraints; mSetConstraintManager = surroundingSetConstraints.getCongruenceClosure().getManager().getSetConstraintManager(); // final List> onlyLits = // setConstraintsRaw.stream().filter(SetConstraint::hasOnlyLiterals).collect(Collectors.toList()); final List> onlyLits = new ArrayList<>(); for (final SetConstraint sc : setConstraintsRaw) { if (sc.hasOnlyLiterals()) { onlyLits.add(sc); } } assert onlyLits.size() < 2; if (onlyLits.size() == 1) { mScWithOnlyLiterals = onlyLits.iterator().next(); } else { mScWithOnlyLiterals = null; } mSetConstraints = Collections.unmodifiableSet(new HashSet<>(setConstraintsRaw)); assert sanityCheck(); } /** * copy constructor that may change surroundingCC.. * * @param original * @param surroundingCCSetConstraints */ public SetConstraintConjunction(final CCLiteralSetConstraints surroundingCCSetConstraints, final SetConstraintConjunction original) { mSurroundingCCSetConstraints = surroundingCCSetConstraints; mConstrainedElement = original.mConstrainedElement; mSetConstraintManager = original.mSetConstraintManager; mSetConstraints = Collections.unmodifiableSet(new HashSet<>(original.getSetConstraints())); mScWithOnlyLiterals = original.mScWithOnlyLiterals; assert sanityCheck(); } /** * The given element is projected away. Assume it is not mConstrainedElement. * Project it in the sets. * * @param elem */ public void projectAway(final ELEM elem) { // assert mSurroundingCCSetConstraints.getCongruenceClosure().isRepresentative(elem) : "right?.."; assert !elem.equals(mConstrainedElement); /* * 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?..) */ final Set> newSetConstraints = new HashSet<>(); for (final SetConstraint sc : mSetConstraints) { if (!sc.containsElement(elem)) { newSetConstraints.add(sc); } } mSetConstraints = newSetConstraints; } private Set getSingletonValues() { return mSetConstraintManager.getSingletonValues(mSetConstraints); } public boolean isTautological() { if (mIsInconsistent) { return false; } if (mSetConstraints.isEmpty()) { return true; } return false; } public boolean isInconsistent() { assert !mIsInconsistent || mSetConstraints == null; // return mIsInconsistent || mSetConstraints.stream().anyMatch(sc -> sc.isInconsistent()); if (mIsInconsistent) { return true; } for (final SetConstraint sc : mSetConstraints) { if (sc.isInconsistent()) { return true; } } return false; } public CongruenceClosure getCongruenceClosure() { return mSurroundingCCSetConstraints.getCongruenceClosure(); } public ELEM getConstrainedElement() { assert mConstrainedElement != null; return mConstrainedElement; } CcManager getCcManager() { return mSurroundingCCSetConstraints.getCongruenceClosure().getManager(); } public Set getAllRhsElements() { final Set result = new HashSet<>(); for (final SetConstraint sc : mSetConstraints) { result.addAll(sc.getElementSet()); } return Collections.unmodifiableSet(result); } public Set> getElementSets() { final Set> result = new HashSet<>(); for (final SetConstraint sc : mSetConstraints) { result.add(sc.getElementSet()); } return Collections.unmodifiableSet(result); } @Override public String toString() { if (mIsInconsistent) { return "SetCc: False"; } return "SetConstraintConjunction [ConstrainedElement=" + mConstrainedElement + ", mSetConstraints=" + mSetConstraints + "]"; } public boolean hasOnlyLiterals() { return mScWithOnlyLiterals != null; } public static > boolean hasOnlyLiterals( final Collection> setConstraints) { // return setConstraints.stream().anyMatch(sc -> sc.hasOnlyLiterals()); for (final SetConstraint sc : setConstraints) { if (sc.hasOnlyLiterals()) { return true; } } return false; } public Set getLiterals() { assert mScWithOnlyLiterals.getNonLiterals().isEmpty(); return mScWithOnlyLiterals.getLiterals(); } // public static > Set getLiterals( // final Collection> setConstraints) { // assert setConstraints.stream().filter(sc -> sc.hasOnlyLiterals()).collect(Collectors.toSet()).size() == 1; // for (final SetConstraint sc : setConstraints) { // if (sc.hasOnlyLiterals()) { // return sc.getLiterals(); // } // } // throw new IllegalStateException("check for hasOnlyLiterals before calling this"); // } public void expandVariableToLiterals(final CCLiteralSetConstraints surroundingSetConstraints, final ELEM elem, final Set literals) { assert !elem.isLiteral(); assert getCongruenceClosure().isRepresentative(elem); boolean madeChanges = false; for (final SetConstraint sc : mSetConstraints) { madeChanges |= sc.expandVariableToLiterals(elem, literals); } if (madeChanges) { mSetConstraints = mSurroundingCCSetConstraints.getCongruenceClosure().getManager() .normalizeSetConstraintConjunction(surroundingSetConstraints, mSetConstraints); } } public void resetConstrainedElement(final ELEM elementRep) { mConstrainedElement = elementRep; } public Set> getSetConstraints() { return Collections.unmodifiableSet(mSetConstraints); } public boolean sanityCheck() { if (mIsInconsistent) { if (mSurroundingCCSetConstraints == null) { // fine in this case, no further checks needed return true; } // check that inconsistency flag is set correctly if (!CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3) { if (!mSetConstraints.stream().anyMatch(sc -> sc.isInconsistent())) { assert false; return false; } } } else { // EDIT: new convention: mIsInconsistent flag is a sufficient but not a // necessary condition for // inconsistency } /* * singleton values should be propagated as equalities and omitted from any SetConstraintConjunction */ if (!getSingletonValues().isEmpty()) { assert false; return false; } for (final SetConstraint conjunct : mSetConstraints) { if (!conjunct.sanityCheck()) { assert false; return false; } } if (mSurroundingCCSetConstraints.getCongruenceClosure() != null) { for (final SetConstraint conjunct : mSetConstraints) { // all must be representatives for (final ELEM el : conjunct.getElementSet()) { if (!mSurroundingCCSetConstraints.getCongruenceClosure().isRepresentative(el)) { assert false; return false; } } } } // check minimality of conjunction : all must be incomparable! if (!CcSettings.OMIT_SANITYCHECK_FINE_GRAINED_3) { for (final SetConstraint sc1 : mSetConstraints) { for (final SetConstraint sc2 : mSetConstraints) { if (sc1 == sc2) { continue; } if (mSetConstraintManager.isStrongerThan(sc1, sc2)) { assert false; return false; } } } } // check minimality: conjunction may not contain tautological elements for (final SetConstraint sc : mSetConstraints) { if (sc.containsElement(mConstrainedElement)) { assert false : "we have a constraint of the form x in {x, ...}, which is tautological, but " + "SetConstraintConjunction should be normalized"; return false; } } return true; } /** * checks if a set of SetConstraints is fully normalized (and possibly more * checks) * * @param constrainedElement * @param filtered * @return */ public static > boolean sanityCheck(// final ELEM constrainedElement, final Set> filtered) { if (filtered == null) { return true; } if (filtered.isEmpty()) { // tautological --> normalize to null assert false; return false; } return true; } }