private ValueSelector applyCaching(
     SelectionCacheType resolvedCacheType,
     SelectionOrder resolvedSelectionOrder,
     ValueSelector valueSelector) {
   if (resolvedCacheType.isCached()
       && resolvedCacheType.compareTo(valueSelector.getCacheType()) > 0) {
     if (!(valueSelector instanceof EntityIndependentValueSelector)) {
       throw new IllegalArgumentException(
           "The valueSelectorConfig ("
               + this
               + ") with resolvedSelectionOrder ("
               + resolvedSelectionOrder
               + ") needs to be based on a EntityIndependentValueSelector."
               + " Check your @"
               + ValueRange.class.getSimpleName()
               + " annotations.");
     }
     valueSelector =
         new CachingValueSelector(
             (EntityIndependentValueSelector) valueSelector,
             resolvedCacheType,
             resolvedSelectionOrder.toRandomSelectionBoolean());
   }
   return valueSelector;
 }
 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);
   }
 }
  /**
   * @param environmentMode never null
   * @param solutionDescriptor never null
   * @param entityDescriptor never null
   * @param minimumCacheType never null, If caching is used (different from {@link
   *     SelectionCacheType#JUST_IN_TIME}), then it should be at least this {@link
   *     SelectionCacheType} because an ancestor already uses such caching and less would be
   *     pointless.
   * @param inheritedSelectionOrder never null
   * @return never null
   */
  public ValueSelector buildValueSelector(
      EnvironmentMode environmentMode,
      SolutionDescriptor solutionDescriptor,
      PlanningEntityDescriptor entityDescriptor,
      SelectionCacheType minimumCacheType,
      SelectionOrder inheritedSelectionOrder) {
    PlanningVariableDescriptor variableDescriptor =
        deduceVariableDescriptor(entityDescriptor, variableName);
    SelectionCacheType resolvedCacheType = SelectionCacheType.resolve(cacheType, minimumCacheType);
    SelectionOrder resolvedSelectionOrder =
        SelectionOrder.resolve(selectionOrder, inheritedSelectionOrder);

    validateCacheTypeVersusSelectionOrder(resolvedCacheType, resolvedSelectionOrder);
    //        validateSorting(resolvedSelectionOrder);
    validateProbability(resolvedSelectionOrder);

    // baseValueSelector and lower should be SelectionOrder.ORIGINAL if they are going to get cached
    // completely
    ValueSelector valueSelector =
        buildBaseValueSelector(
            environmentMode,
            variableDescriptor,
            SelectionCacheType.max(minimumCacheType, resolvedCacheType),
            determineBaseRandomSelection(
                variableDescriptor, resolvedCacheType, resolvedSelectionOrder));

    //        valueSelector = applyFiltering(variableDescriptor, resolvedCacheType,
    // resolvedSelectionOrder, valueSelector);
    //        valueSelector = applySorting(resolvedCacheType, resolvedSelectionOrder,
    // valueSelector);
    valueSelector = applyProbability(resolvedCacheType, resolvedSelectionOrder, valueSelector);
    valueSelector = applyShuffling(resolvedCacheType, resolvedSelectionOrder, valueSelector);
    valueSelector = applyCaching(resolvedCacheType, resolvedSelectionOrder, valueSelector);
    return valueSelector;
  }
 /**
  * @param configPolicy never null
  * @param minimumCacheType never null, If caching is used (different from {@link
  *     SelectionCacheType#JUST_IN_TIME}), then it should be at least this {@link
  *     SelectionCacheType} because an ancestor already uses such caching and less would be
  *     pointless.
  * @param inheritedSelectionOrder never null
  * @return never null
  */
 public PillarSelector buildPillarSelector(
     HeuristicConfigPolicy configPolicy,
     SelectionCacheType minimumCacheType,
     SelectionOrder inheritedSelectionOrder) {
   if (minimumCacheType.compareTo(SelectionCacheType.STEP) > 0) {
     throw new IllegalArgumentException(
         "The pillarSelectorConfig ("
             + this
             + ")'s minimumCacheType ("
             + minimumCacheType
             + ") must not be higher than "
             + SelectionCacheType.STEP
             + " because the pillars change every step.");
   }
   // EntitySelector uses SelectionOrder.ORIGINAL because a SameValuePillarSelector STEP caches the
   // values
   EntitySelectorConfig entitySelectorConfig_ =
       entitySelectorConfig == null ? new EntitySelectorConfig() : entitySelectorConfig;
   EntitySelector entitySelector =
       entitySelectorConfig_.buildEntitySelector(
           configPolicy, minimumCacheType, SelectionOrder.ORIGINAL);
   Collection<GenuineVariableDescriptor> variableDescriptors =
       entitySelector.getEntityDescriptor().getVariableDescriptors();
   return new SameValuePillarSelector(
       entitySelector, variableDescriptors, inheritedSelectionOrder.toRandomSelectionBoolean());
 }
 public AbstractCachingMoveSelector(MoveSelector childMoveSelector, SelectionCacheType cacheType) {
   this.childMoveSelector = childMoveSelector;
   this.cacheType = cacheType;
   if (childMoveSelector.isNeverEnding()) {
     throw new IllegalStateException(
         "The selector ("
             + this
             + ") has a childMoveSelector ("
             + childMoveSelector
             + ") with neverEnding ("
             + childMoveSelector.isNeverEnding()
             + ").");
   }
   phaseLifecycleSupport.addEventListener(childMoveSelector);
   if (cacheType.isNotCached()) {
     throw new IllegalArgumentException(
         "The selector (" + this + ") does not support the cacheType (" + cacheType + ").");
   }
   phaseLifecycleSupport.addEventListener(new SelectionCacheLifecycleBridge(cacheType, this));
 }
 protected boolean determineBaseRandomSelection(
     PlanningVariableDescriptor variableDescriptor,
     SelectionCacheType resolvedCacheType,
     SelectionOrder resolvedSelectionOrder) {
   switch (resolvedSelectionOrder) {
     case ORIGINAL:
       return false;
     case SORTED:
     case SHUFFLED:
     case PROBABILISTIC:
       // baseValueSelector and lower should be ORIGINAL if they are going to get cached completely
       return false;
     case RANDOM:
       // Predict if caching will occur
       return resolvedCacheType.isNotCached()
           || (isBaseInherentlyCached(variableDescriptor) && !hasFiltering());
     default:
       throw new IllegalStateException(
           "The selectionOrder (" + resolvedSelectionOrder + ") is not implemented.");
   }
 }
 public ProbabilityValueSelector(
     EntityIndependentValueSelector childValueSelector,
     SelectionCacheType cacheType,
     SelectionProbabilityWeightFactory probabilityWeightFactory) {
   this.childValueSelector = childValueSelector;
   this.cacheType = cacheType;
   this.probabilityWeightFactory = probabilityWeightFactory;
   if (childValueSelector.isNeverEnding()) {
     throw new IllegalStateException(
         "The selector ("
             + this
             + ") has a childValueSelector ("
             + childValueSelector
             + ") with neverEnding ("
             + childValueSelector.isNeverEnding()
             + ").");
   }
   phaseLifecycleSupport.addEventListener(childValueSelector);
   if (cacheType.isNotCached()) {
     throw new IllegalArgumentException(
         "The selector (" + this + ") does not support the cacheType (" + cacheType + ").");
   }
   phaseLifecycleSupport.addEventListener(new SelectionCacheLifecycleBridge(cacheType, this));
 }
  public void runCacheType(SelectionCacheType cacheType, int timesCalled) {
    MoveSelector childMoveSelector =
        SelectorTestUtils.mockMoveSelector(
            DummyMove.class,
            new DummyMove("e1"),
            new DummyMove("e2"),
            new DummyMove("e3"),
            new DummyMove("e4"));

    SelectionFilter<DummyMove> filter =
        new SelectionFilter<DummyMove>() {
          public boolean accept(ScoreDirector scoreDirector, DummyMove move) {
            return !move.getCode().equals("e3");
          }
        };
    List<SelectionFilter> filterList = Arrays.<SelectionFilter>asList(filter);
    MoveSelector moveSelector = new FilteringMoveSelector(childMoveSelector, filterList);
    if (cacheType.isCached()) {
      moveSelector = new CachingMoveSelector(moveSelector, cacheType, false);
    }

    DefaultSolverScope solverScope = mock(DefaultSolverScope.class);
    moveSelector.solvingStarted(solverScope);

    AbstractSolverPhaseScope phaseScopeA = mock(AbstractSolverPhaseScope.class);
    when(phaseScopeA.getSolverScope()).thenReturn(solverScope);
    moveSelector.phaseStarted(phaseScopeA);

    AbstractStepScope stepScopeA1 = mock(AbstractStepScope.class);
    when(stepScopeA1.getPhaseScope()).thenReturn(phaseScopeA);
    moveSelector.stepStarted(stepScopeA1);
    assertAllCodesOfMoveSelector(
        moveSelector, (cacheType.isNotCached() ? 4L : 3L), "e1", "e2", "e4");
    moveSelector.stepEnded(stepScopeA1);

    AbstractStepScope stepScopeA2 = mock(AbstractStepScope.class);
    when(stepScopeA2.getPhaseScope()).thenReturn(phaseScopeA);
    moveSelector.stepStarted(stepScopeA2);
    assertAllCodesOfMoveSelector(
        moveSelector, (cacheType.isNotCached() ? 4L : 3L), "e1", "e2", "e4");
    moveSelector.stepEnded(stepScopeA2);

    moveSelector.phaseEnded(phaseScopeA);

    AbstractSolverPhaseScope phaseScopeB = mock(AbstractSolverPhaseScope.class);
    when(phaseScopeB.getSolverScope()).thenReturn(solverScope);
    moveSelector.phaseStarted(phaseScopeB);

    AbstractStepScope stepScopeB1 = mock(AbstractStepScope.class);
    when(stepScopeB1.getPhaseScope()).thenReturn(phaseScopeB);
    moveSelector.stepStarted(stepScopeB1);
    assertAllCodesOfMoveSelector(
        moveSelector, (cacheType.isNotCached() ? 4L : 3L), "e1", "e2", "e4");
    moveSelector.stepEnded(stepScopeB1);

    AbstractStepScope stepScopeB2 = mock(AbstractStepScope.class);
    when(stepScopeB2.getPhaseScope()).thenReturn(phaseScopeB);
    moveSelector.stepStarted(stepScopeB2);
    assertAllCodesOfMoveSelector(
        moveSelector, (cacheType.isNotCached() ? 4L : 3L), "e1", "e2", "e4");
    moveSelector.stepEnded(stepScopeB2);

    AbstractStepScope stepScopeB3 = mock(AbstractStepScope.class);
    when(stepScopeB3.getPhaseScope()).thenReturn(phaseScopeB);
    moveSelector.stepStarted(stepScopeB3);
    assertAllCodesOfMoveSelector(
        moveSelector, (cacheType.isNotCached() ? 4L : 3L), "e1", "e2", "e4");
    moveSelector.stepEnded(stepScopeB3);

    moveSelector.phaseEnded(phaseScopeB);

    moveSelector.solvingEnded(solverScope);

    verifySolverPhaseLifecycle(childMoveSelector, 1, 2, 5);
    verify(childMoveSelector, times(timesCalled)).iterator();
    verify(childMoveSelector, times(timesCalled)).getSize();
  }