public void insertInTrailingEntityMap(
     PlanningVariableDescriptor variableDescriptor, Object entity) {
   if (hasChainedVariables && variableDescriptor.isChained()) {
     Map<Object, Set<Object>> valueToTrailingEntityMap =
         trailingEntitiesMap.get(variableDescriptor);
     if (valueToTrailingEntityMap == null) {
       throw new IllegalStateException(
           "The ScoreDirector ("
               + getClass()
               + ") is bugged,"
               + " because the chained planningVariable ("
               + variableDescriptor.getVariableName()
               + ") was not found in the trailingEntitiesMap.");
     }
     Object value = variableDescriptor.getValue(entity);
     Set<Object> trailingEntities = valueToTrailingEntityMap.get(value);
     if (trailingEntities == null) {
       trailingEntities = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>());
       valueToTrailingEntityMap.put(value, trailingEntities);
     }
     boolean addSucceeded = trailingEntities.add(entity);
     if (!addSucceeded) {
       throw new IllegalStateException(
           "The ScoreDirector ("
               + getClass()
               + ") is corrupted,"
               + " because the entity ("
               + entity
               + ") for chained planningVariable ("
               + variableDescriptor.getVariableName()
               + ") cannot be inserted: it was already inserted.");
     }
   }
 }
 private void retractFromTrailingEntityMap(Object entity) {
   if (hasChainedVariables) {
     for (Map.Entry<PlanningVariableDescriptor, Map<Object, Set<Object>>> entry :
         chainedVariableToTrailingEntitiesMap.entrySet()) {
       PlanningVariableDescriptor variableDescriptor = entry.getKey();
       if (variableDescriptor.getPlanningEntityDescriptor().appliesToPlanningEntity(entity)) {
         Object value = variableDescriptor.getValue(entity);
         Map<Object, Set<Object>> valueToTrailingEntityMap = entry.getValue();
         Set<Object> trailingEntities = valueToTrailingEntityMap.get(value);
         boolean removeSucceeded = trailingEntities != null && trailingEntities.remove(entity);
         if (!removeSucceeded) {
           throw new IllegalStateException(
               "The ScoreDirector ("
                   + getClass()
                   + ") is corrupted,"
                   + " because the entity ("
                   + entity
                   + ") for chained planningVariable ("
                   + variableDescriptor.getVariableName()
                   + ") cannot be retracted: it was never inserted.");
         }
         if (trailingEntities.isEmpty()) {
           valueToTrailingEntityMap.put(value, null);
         }
       }
     }
   }
 }
 public void retractFromTrailingEntityMap(
     PlanningVariableDescriptor variableDescriptor, Object entity) {
   if (hasChainedVariables && variableDescriptor.isChained()) {
     Map<Object, Set<Object>> valueToTrailingEntityMap =
         trailingEntitiesMap.get(variableDescriptor);
     if (valueToTrailingEntityMap == null) {
       throw new IllegalStateException(
           "The ScoreDirector ("
               + getClass()
               + ") is bugged,"
               + " because the chained planningVariable ("
               + variableDescriptor.getVariableName()
               + ") was not found in the trailingEntitiesMap.");
     }
     Object value = variableDescriptor.getValue(entity);
     Set<Object> trailingEntities = valueToTrailingEntityMap.get(value);
     boolean removeSucceeded = trailingEntities != null && trailingEntities.remove(entity);
     if (!removeSucceeded) {
       throw new IllegalStateException(
           "The ScoreDirector ("
               + getClass()
               + ") is corrupted,"
               + " because the entity ("
               + entity
               + ") for chained planningVariable ("
               + variableDescriptor.getVariableName()
               + ") cannot be retracted: it was never inserted.");
     }
     if (trailingEntities.isEmpty()) {
       valueToTrailingEntityMap.put(value, null);
     }
   }
 }
 private void insertInTrailingEntityMap(Object entity) {
   if (hasChainedVariables) {
     for (Map.Entry<PlanningVariableDescriptor, Map<Object, Set<Object>>> entry :
         chainedVariableToTrailingEntitiesMap.entrySet()) {
       PlanningVariableDescriptor variableDescriptor = entry.getKey();
       if (variableDescriptor.getPlanningEntityDescriptor().appliesToPlanningEntity(entity)) {
         Object value = variableDescriptor.getValue(entity);
         Map<Object, Set<Object>> valueToTrailingEntityMap = entry.getValue();
         Set<Object> trailingEntities = valueToTrailingEntityMap.get(value);
         if (trailingEntities == null) {
           trailingEntities = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>());
           valueToTrailingEntityMap.put(value, trailingEntities);
         }
         boolean addSucceeded = trailingEntities.add(entity);
         if (!addSucceeded) {
           throw new IllegalStateException(
               "The ScoreDirector ("
                   + getClass()
                   + ") is corrupted,"
                   + " because the entity ("
                   + entity
                   + ") for chained planningVariable ("
                   + variableDescriptor.getVariableName()
                   + ") cannot be inserted: it was already inserted.");
         }
       }
     }
   }
 }
 private ValueSelector buildBaseValueSelector(
     EnvironmentMode environmentMode,
     PlanningVariableDescriptor variableDescriptor,
     SelectionCacheType minimumCacheType,
     boolean randomSelection) {
   if (variableDescriptor.getValueRangeDescriptor().isEntityDependent()) {
     FromEntityPropertyPlanningValueRangeDescriptor valueRangeDescriptor =
         (FromEntityPropertyPlanningValueRangeDescriptor)
             variableDescriptor.getValueRangeDescriptor();
     // TODO should we ignore the minimumCacheType so it can be cached on changeMoves too?
     return new FromEntityPropertyValueSelector(
         valueRangeDescriptor, minimumCacheType, randomSelection);
   } else {
     // FromSolutionPropertyValueSelector caches by design, so it uses the minimumCacheType
     if (variableDescriptor.isPlanningValuesCacheable()) {
       if (minimumCacheType.compareTo(SelectionCacheType.PHASE) < 0) {
         // TODO we probably want to default this to SelectionCacheType.JUST_IN_TIME
         minimumCacheType = SelectionCacheType.PHASE;
       }
     } else {
       if (minimumCacheType.compareTo(SelectionCacheType.STEP) < 0) {
         // TODO we probably want to default this to SelectionCacheType.JUST_IN_TIME
         minimumCacheType = SelectionCacheType.STEP;
       }
     }
     return new FromSolutionPropertyValueSelector(
         variableDescriptor, minimumCacheType, randomSelection);
   }
 }
 public void insertInTrailingEntityMap(PlanningEntityDescriptor entityDescriptor, Object entity) {
   if (hasChainedVariables) {
     for (PlanningVariableDescriptor variableDescriptor :
         entityDescriptor.getVariableDescriptors()) {
       if (variableDescriptor.isChained()) {
         insertInTrailingEntityMap(variableDescriptor, entity);
       }
     }
   }
 }
  public ConstructionHeuristicMoveScope nominateMove(ConstructionHeuristicStepScope stepScope) {
    Object entity = stepScope.getEntity();
    if (!reinitializeVariableEntityFilter.accept(stepScope.getScoreDirector(), entity)) {
      return null;
    }
    // TODO extract to PlacerForager
    Score maxScore = null;
    ConstructionHeuristicMoveScope nominatedMoveScope = null;

    int moveIndex = 0;
    for (Iterator it = valueSelector.iterator(entity); it.hasNext(); ) {
      Object value = it.next();
      ConstructionHeuristicMoveScope moveScope = new ConstructionHeuristicMoveScope(stepScope);
      moveScope.setMoveIndex(moveIndex);
      Move move;
      if (variableDescriptor.isChained()) {
        move = new ChainedChangeMove(entity, variableDescriptor, value);
      } else {
        move = new ChangeMove(entity, variableDescriptor, value);
      }
      moveScope.setMove(move);
      if (!move.isMoveDoable(stepScope.getScoreDirector())) {
        logger.trace(
            "        Move index ({}) not doable, ignoring move ({}).",
            moveScope.getMoveIndex(),
            move);
      } else {
        doMove(moveScope);
        // TODO extract to PlacerForager
        if (maxScore == null || moveScope.getScore().compareTo(maxScore) > 0) {
          maxScore = moveScope.getScore();
          // TODO for non explicit Best Fit *, default to random picking from a maxMoveScopeList
          nominatedMoveScope = moveScope;
        }
        if (moveIndex >= selectedCountLimit) {
          break;
        }
      }
      moveIndex++;
      if (termination.isPhaseTerminated(stepScope.getPhaseScope())) {
        break;
      }
    }
    return nominatedMoveScope;
  }
 public Object getTrailingEntity(
     PlanningVariableDescriptor chainedVariableDescriptor, Object planningValue) {
   Set<Object> trailingEntities =
       trailingEntitiesMap.get(chainedVariableDescriptor).get(planningValue);
   if (trailingEntities == null) {
     return null;
   }
   // trailingEntities can never be an empty list
   if (trailingEntities.size() > 1) {
     throw new IllegalStateException(
         "The planningValue ("
             + planningValue
             + ") has multiple trailing entities ("
             + trailingEntities
             + ") pointing to it for chained planningVariable ("
             + chainedVariableDescriptor.getVariableName()
             + ").");
   }
   return trailingEntities.iterator().next();
 }
 public ValuePlacer(Termination termination, ValueSelector valueSelector, int selectedCountLimit) {
   this.termination = termination;
   this.valueSelector = valueSelector;
   variableDescriptor = valueSelector.getVariableDescriptor();
   reinitializeVariableEntityFilter = variableDescriptor.getReinitializeVariableEntityFilter();
   this.selectedCountLimit = selectedCountLimit;
   solverPhaseLifecycleSupport.addEventListener(valueSelector);
   // TODO don't use Integer.MAX_VALUE as a magical value
   if (valueSelector.isNeverEnding() && selectedCountLimit == Integer.MAX_VALUE) {
     throw new IllegalStateException(
         "The placer ("
             + this
             + ") with selectedCountLimit ("
             + selectedCountLimit
             + ") has valueSelector ("
             + valueSelector
             + ") with neverEnding ("
             + valueSelector.isNeverEnding()
             + ").");
   }
 }
 protected boolean isBaseInherentlyCached(PlanningVariableDescriptor variableDescriptor) {
   return !variableDescriptor.getValueRangeDescriptor().isEntityDependent();
 }