public static <Solution_> PartitionChangeMove<Solution_> createMove(
      InnerScoreDirector<Solution_> scoreDirector) {
    SolutionDescriptor<Solution_> solutionDescriptor = scoreDirector.getSolutionDescriptor();
    Solution_ workingSolution = scoreDirector.getWorkingSolution();

    int entityCount = solutionDescriptor.getEntityCount(workingSolution);
    Map<GenuineVariableDescriptor<Solution_>, List<Pair<Object, Object>>> changeMap =
        new LinkedHashMap<>(solutionDescriptor.getEntityDescriptors().size() * 3);
    for (EntityDescriptor<Solution_> entityDescriptor : solutionDescriptor.getEntityDescriptors()) {
      for (GenuineVariableDescriptor<Solution_> variableDescriptor :
          entityDescriptor.getDeclaredGenuineVariableDescriptors()) {
        changeMap.put(variableDescriptor, new ArrayList<>(entityCount));
      }
    }
    for (Iterator<Object> it = solutionDescriptor.extractAllEntitiesIterator(workingSolution);
        it.hasNext(); ) {
      Object entity = it.next();
      EntityDescriptor<Solution_> entityDescriptor =
          solutionDescriptor.findEntityDescriptorOrFail(entity.getClass());
      if (entityDescriptor.isMovable(scoreDirector, entity)) {
        for (GenuineVariableDescriptor<Solution_> variableDescriptor :
            entityDescriptor.getGenuineVariableDescriptors()) {
          Object value = variableDescriptor.getValue(entity);
          changeMap.get(variableDescriptor).add(Pair.of(entity, value));
        }
      }
    }
    return new PartitionChangeMove<>(changeMap);
  }
 @Override
 public void phaseStarted(AbstractPhaseScope phaseScope) {
   InnerScoreDirector scoreDirector = phaseScope.getScoreDirector();
   constraintMatchEnabled = scoreDirector.isConstraintMatchEnabled();
   if (!constraintMatchEnabled) {
     logger.warn(
         "The singleStatistic ({}) cannot function properly"
             + " because ConstraintMatches are not supported on the ScoreDirector.",
         singleStatisticType);
   }
 }
 public PartitionChangeMove<Solution_> relocate(
     InnerScoreDirector<Solution_> destinationScoreDirector) {
   Map<GenuineVariableDescriptor<Solution_>, List<Pair<Object, Object>>> destinationChangeMap =
       new LinkedHashMap<>(changeMap.size());
   for (Map.Entry<GenuineVariableDescriptor<Solution_>, List<Pair<Object, Object>>> entry :
       changeMap.entrySet()) {
     GenuineVariableDescriptor<Solution_> variableDescriptor = entry.getKey();
     List<Pair<Object, Object>> originPairList = entry.getValue();
     List<Pair<Object, Object>> destinationPairList = new ArrayList<>(originPairList.size());
     for (Pair<Object, Object> pair : originPairList) {
       Object originEntity = pair.getKey();
       Object destinationEntity = destinationScoreDirector.locateWorkingObject(originEntity);
       if (destinationEntity == null && originEntity != null) {
         throw new IllegalStateException(
             "The destinationEntity ("
                 + destinationEntity
                 + ") cannot be null if the originEntity ("
                 + originEntity
                 + ") is not null.");
       }
       Object originValue = pair.getValue();
       Object destinationValue = destinationScoreDirector.locateWorkingObject(originValue);
       if (destinationValue == null && originValue != null) {
         throw new IllegalStateException(
             "The destinationValue ("
                 + destinationValue
                 + ") cannot be null if the originValue ("
                 + originValue
                 + ") is not null.");
       }
       destinationPairList.add(Pair.of(destinationEntity, destinationValue));
     }
     destinationChangeMap.put(variableDescriptor, destinationPairList);
   }
   return new PartitionChangeMove<>(destinationChangeMap);
 }
 public ScoreDefinition getScoreDefinition() {
   return scoreDirector.getScoreDefinition();
 }
 public void setWorkingSolutionFromBestSolution() {
   // The workingSolution must never be the same instance as the bestSolution.
   scoreDirector.setWorkingSolution(scoreDirector.cloneSolution(bestSolution));
 }
 public SolutionDescriptor getSolutionDescriptor() {
   return scoreDirector.getSolutionDescriptor();
 }
 public void assertScoreFromScratch(Solution solution) {
   scoreDirector.getScoreDirectorFactory().assertScoreFromScratch(solution);
 }
 public long getCalculateCount() {
   return scoreDirector.getCalculateCount();
 }
 public void assertExpectedWorkingScore(Score expectedWorkingScore, Object completedAction) {
   scoreDirector.assertExpectedWorkingScore(expectedWorkingScore, completedAction);
 }
 public void assertWorkingScoreFromScratch(Score workingScore, Object completedAction) {
   scoreDirector.assertWorkingScoreFromScratch(workingScore, completedAction);
 }
 public Score calculateScore() {
   return scoreDirector.calculateScore();
 }
 public int getWorkingValueCount() {
   return scoreDirector.getWorkingValueCount();
 }
 public List<Object> getWorkingEntityList() {
   return scoreDirector.getWorkingEntityList();
 }
 public int getWorkingEntityCount() {
   return scoreDirector.getWorkingEntityCount();
 }
 public Solution getWorkingSolution() {
   return scoreDirector.getWorkingSolution();
 }