// IntersectConstraint.java, created Tue Aug 16 10:29:12 2005 by salcianu // Copyright (C) 2005 Alexandru Salcianu // Licensed under the Modified BSD Licence; see COPYING for details. package jpaul.Constraints.SetConstraints; import java.util.Set; import java.util.LinkedHashSet; import java.util.Collection; import java.util.Arrays; import jpaul.Constraints.ConstraintSystem; import jpaul.Constraints.Constraint; import jpaul.Constraints.SolReader; import jpaul.Constraints.SolAccessor; import jpaul.Constraints.Var; import jpaul.DataStructs.UnionFind; /** IntersectConstraint models a set intersection constraint. Mathematically, such a constraint has the form:
vIn1 /\ vIn2 <= vDest
where /\ stands for set intersection, <= stands for set inclusion, and vIn1, vIn2, vDest are set-valued variables.

NOTE: This is a simplified version of the code, meant to be a Constraint example. * @author Alexandru Salcianu - salcianu@alum.mit.edu * @version $Id: IntersectConstraint.java,v 1.3 2006/01/07 02:33:56 salcianu Exp $ */ public class IntersectConstraint extends Constraint,Set> { /** Creates a IntersectConstraint with the meaning vIn1 /\ vIn2 <= vDest. */ public IntersectConstraint(SVar vIn1, SVar vIn2, SVar vDest) { this.vIn1 = vIn1; this.vIn2 = vIn2; this.vDest = vDest; this.in = Arrays.asList(vIn1, vIn2); this.out = Arrays.asList(vDest); } private final SVar vIn1; private final SVar vIn2; private final SVar vDest; private final Collection> in; private final Collection> out; public Collection> in() { return this.in; } public Collection> out() { return this.out; } /** Returns {@link jpaul.Constraints.Constraint#HIGH_COST HIGH_COST}. */ public int cost() { return Constraint.HIGH_COST; } public void action(SolAccessor,Set> sa) { // Notice the three standard steps of an action method // 1. Read the values of the input variables Set s_in1 = sa.get(vIn1); // null stands for botton, i.e., the empty set. In this case, // the constraint does not generate any new elements into // vDest; hence, we can return immediately. if(s_in1 == null) return; Set s_in2 = sa.get(vIn2); if(s_in2 == null) return; // Just an optimization. if(s_in1.size() < s_in2.size()) { Set temp = s_in1; s_in1 = s_in2; s_in2 = temp; } // 2. Compute the intersection Set intersect = new LinkedHashSet(); for(T elem : s_in1) { if(s_in2.contains(elem)) { intersect.add(elem); } } // 3. Update the destination variable sa.join(vDest, intersect); } // THE REST OF THIS CLASS IS JUST FOR PERFORMANCE REASONS /** We implemented {@link #rewrite}, {@link #equals}, and {@link #hashCode}, such that constraints that are identical after variable unification are not duplicated needlessly. */ public Constraint,Set> rewrite(UnionFind> uf) { SVar vIn1_p = uf.find(vIn1); SVar vIn2_p = uf.find(vIn2); SVar vDest_p = uf.find(vDest); return new IntersectConstraint(vIn1_p, vIn2_p, vDest_p); } public boolean equals(Object o) { if(o == null) return false; if(o == this) return true; if(!(o instanceof IntersectConstraint/**/)) return false; if(this.hashCode() != o.hashCode()) return false; IntersectConstraint ic2 = (IntersectConstraint) o; return this.vIn1.equals(ic2.vIn1) && this.vIn2.equals(ic2.vIn2) && this.vDest.equals(ic2.vDest); } public int hashCode() { if(hashCode == 0) { hashCode = 3 * vIn1.hashCode() + 5 * vIn2.hashCode() + 7 * vDest.hashCode(); } return hashCode; } private int hashCode = 0; // cached hashCode public String toString() { return vIn1 + " /\\ " + vIn2 + " <= " + vDest; } }