title: OptaPlanner Constraint Streams: Count Distinct Values in Planning Entity Set
body: <p>I'm looking for some help with OptaPlanner's constraint streams.  The problem is a variant on job-shop scheduling, and my planning entities (CandidateAssignment) are wrapping around two decision variables: choice of robot and assigned time grain. Each CandidateAssignment also has a field (a Set) denoting which physical containers in a warehouse will be filled by assigning that task.</p>
  <p>The constraint I'm trying to enforce is to minimize the total number of containers used by all CandidateAssignments in a solution (the goal being to guide OptaPlanner towards grouping tasks by container... there are domain-specific benefits to this in the warehouse).  If each CandidateAssignment could only service a single container, this would be easy:</p>
  <pre><code>  protected Constraint maximizeContainerCompleteness(ConstraintFactory constraintFactory) {
      return constraintFactory.forEach(CandidateAssignment.class)
          .filter(CandidateAssignment::isAssigned)
          .groupBy(CandidateAssignment::getContainerId, countDistinct())
          .penalizeConfigurable(&quot;Group by container&quot;);
    }
  </code></pre>
  <p>Moving from a single ID to a collection seems less straightforward to me (i.e., if CandidateAssignment:getContainerIds returns a set of integers).  Any help would be much appreciated.</p>
  <p>EDIT: Thanks Christopher and Lukáš for the responses.  Christopher's constraint matches my use case (minimize the number of containers serviced by a solution).  However, this ends up being a pretty poor way to guide OptaPlanner towards (more) optimal solutions since it's operating via iterated local search.  Given a candidate solution, the majority of neighbors in that solution's neighborhood will have equal value for that constraint (# unique containers used), so it doesn't have much power of discernment.</p>
  <p>The approach I've tested with reasonable results is as follows:</p>
  <pre><code>  protected Constraint maximizeContainerCompleteness(ConstraintFactory constraintFactory) {
      return constraintFactory.forEach(CandidateAssignment.class)
          .filter(CandidateAssignment::isAssigned)
          .join(Container.class, Joiners.filtering(
              (candidate, container) -&gt; candidate.getContainerIds().contains(container.getContainerId())))
          .rewardConfigurable(&quot;Group by container&quot;, (candidate, container) -&gt; container.getPercentFilledSquared());
    }
  </code></pre>
  <p>This is a modified version of Lukáš' answer.  It works by prioritizing containers which are &quot;mostly full.&quot;  In the real-world use case (which I think I explained pretty poorly above), we'd like to minimize the number of containers used in a solution because it allows the warehouse to replace those containers with new ones which are &quot;easier&quot; to fulfill (the search space is less constrained).  We're planning in a receding time horizon, and having many partially filled bins means that each planning horizon becomes increasingly more difficult to schedule.  &quot;Closing&quot; containers by fulfilling all associated tasks means we can replace that container with a new one and start fresh.</p>
  <p>Anyways, just a bit of context.  This is a very particular use case, but if anyone else reads this and wants to know how to work with this type of constraint, hopefully that helps.</p>