Skip to content

Commit

Permalink
PLANNER-239 FilteringValueSelector
Browse files Browse the repository at this point in the history
  • Loading branch information
ge0ffrey committed Apr 27, 2016
1 parent 7bf7e75 commit b8ae184
Show file tree
Hide file tree
Showing 11 changed files with 513 additions and 47 deletions.
Expand Up @@ -313,7 +313,8 @@ protected boolean determineBaseRandomSelection(EntityDescriptor entityDescriptor
return false;
case RANDOM:
// Predict if caching will occur
return resolvedCacheType.isNotCached() || (isBaseInherentlyCached() && !hasFiltering(entityDescriptor));
return resolvedCacheType.isNotCached()
|| (isBaseInherentlyCached() && !hasFiltering(entityDescriptor));
default:
throw new IllegalStateException("The selectionOrder (" + resolvedSelectionOrder
+ ") is not implemented.");
Expand Down
Expand Up @@ -16,10 +16,13 @@

package org.optaplanner.core.config.heuristic.selector.value;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.config.heuristic.policy.HeuristicConfigPolicy;
import org.optaplanner.core.config.heuristic.selector.SelectorConfig;
Expand All @@ -33,12 +36,15 @@
import org.optaplanner.core.impl.domain.valuerange.descriptor.EntityIndependentValueRangeDescriptor;
import org.optaplanner.core.impl.domain.valuerange.descriptor.ValueRangeDescriptor;
import org.optaplanner.core.impl.domain.variable.descriptor.GenuineVariableDescriptor;
import org.optaplanner.core.impl.domain.variable.descriptor.VariableDescriptor;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.ComparatorSelectionSorter;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionFilter;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionProbabilityWeightFactory;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionSorter;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionSorterWeightFactory;
import org.optaplanner.core.impl.heuristic.selector.common.decorator.WeightFactorySelectionSorter;
import org.optaplanner.core.impl.heuristic.selector.entity.EntitySelector;
import org.optaplanner.core.impl.heuristic.selector.entity.decorator.FilteringEntitySelector;
import org.optaplanner.core.impl.heuristic.selector.value.EntityIndependentValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.FromEntityPropertyValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.FromSolutionPropertyValueSelector;
Expand All @@ -47,6 +53,7 @@
import org.optaplanner.core.impl.heuristic.selector.value.decorator.DowncastingValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.decorator.EntityDependentSortingValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.decorator.EntityIndependentInitializedValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.decorator.FilteringValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.decorator.InitializedValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.decorator.ProbabilityValueSelector;
import org.optaplanner.core.impl.heuristic.selector.value.decorator.ReinitializeVariableValueSelector;
Expand Down Expand Up @@ -74,7 +81,8 @@ public class ValueSelectorConfig extends SelectorConfig<ValueSelectorConfig> {
@XStreamAlias("nearbySelection")
protected NearbySelectionConfig nearbySelectionConfig = null;

// TODO filterClass
@XStreamImplicit(itemFieldName = "filterClass")
protected List<Class<? extends SelectionFilter>> filterClassList = null;

protected ValueSorterManner sorterManner = null;
protected Class<? extends Comparator> sorterComparatorClass = null;
Expand Down Expand Up @@ -155,6 +163,14 @@ public void setNearbySelectionConfig(NearbySelectionConfig nearbySelectionConfig
this.nearbySelectionConfig = nearbySelectionConfig;
}

public List<Class<? extends SelectionFilter>> getFilterClassList() {
return filterClassList;
}

public void setFilterClassList(List<Class<? extends SelectionFilter>> filterClassList) {
this.filterClassList = filterClassList;
}

public ValueSorterManner getSorterManner() {
return sorterManner;
}
Expand Down Expand Up @@ -274,11 +290,11 @@ public ValueSelector buildValueSelector(HeuristicConfigPolicy configPolicy,
determineBaseRandomSelection(variableDescriptor, resolvedCacheType, resolvedSelectionOrder));

if (nearbySelectionConfig != null) {
// TODO Static filtering should affect nearbySelection too
// TODO Static filtering (such as movableEntitySelectionFilter) should affect nearbySelection too
valueSelector = nearbySelectionConfig.applyNearbyValueSelector(configPolicy,
minimumCacheType, resolvedCacheType, resolvedSelectionOrder, valueSelector);
}
// valueSelector = applyFiltering(variableDescriptor, resolvedCacheType, resolvedSelectionOrder, valueSelector);
valueSelector = applyFiltering(resolvedCacheType, resolvedSelectionOrder, valueSelector);
valueSelector = applyInitializedChainedValueFilter(configPolicy, variableDescriptor,
resolvedCacheType, resolvedSelectionOrder, valueSelector);
valueSelector = applySorting(resolvedCacheType, resolvedSelectionOrder, valueSelector);
Expand All @@ -298,6 +314,7 @@ protected ValueSelector buildMimicReplaying(HeuristicConfigPolicy configPolicy)
|| cacheType != null
|| selectionOrder != null
|| nearbySelectionConfig != null
|| filterClassList != null
|| sorterManner != null
|| sorterComparatorClass != null
|| sorterWeightFactoryClass != null
Expand Down Expand Up @@ -352,7 +369,8 @@ protected boolean determineBaseRandomSelection(GenuineVariableDescriptor variabl
return false;
case RANDOM:
// Predict if caching will occur
return resolvedCacheType.isNotCached() || (isBaseInherentlyCached(variableDescriptor) && !hasFiltering());
return resolvedCacheType.isNotCached()
|| (isBaseInherentlyCached(variableDescriptor) && !hasFiltering(variableDescriptor));
default:
throw new IllegalStateException("The selectionOrder (" + resolvedSelectionOrder
+ ") is not implemented.");
Expand Down Expand Up @@ -384,8 +402,30 @@ private ValueSelector buildBaseValueSelector(
}
}

private boolean hasFiltering() {
return false; // NOT yet implemented
private boolean hasFiltering(GenuineVariableDescriptor variableDescriptor) {
// TODO in some chained cases add || entityDescriptor.hasMovableEntitySelectionFilter()
return !ConfigUtils.isEmptyCollection(filterClassList);
}

private ValueSelector applyFiltering(SelectionCacheType resolvedCacheType, SelectionOrder resolvedSelectionOrder,
ValueSelector valueSelector) {
GenuineVariableDescriptor variableDescriptor = valueSelector.getVariableDescriptor();
if (hasFiltering(variableDescriptor)) {
List<SelectionFilter> filterList = new ArrayList<>(
filterClassList == null ? 1 : filterClassList.size() + 1);
if (filterClassList != null) {
for (Class<? extends SelectionFilter> filterClass : filterClassList) {
filterList.add(ConfigUtils.newInstance(this, "filterClass", filterClass));
}
}
// TODO
// // Filter out immovable entities
// if (variableDescriptor.hasMovableEntitySelectionFilter()) {
// filterList.add(variableDescriptor.getMovableEntitySelectionFilter());
// }
valueSelector = FilteringValueSelector.create(valueSelector, filterList);
}
return valueSelector;
}

protected ValueSelector applyInitializedChainedValueFilter(HeuristicConfigPolicy configPolicy,
Expand All @@ -394,11 +434,7 @@ protected ValueSelector applyInitializedChainedValueFilter(HeuristicConfigPolicy
ValueSelector valueSelector) {
if (configPolicy.isInitializedChainedValueFilterEnabled()
&& variableDescriptor.isChained()) {
if (valueSelector instanceof EntityIndependentValueSelector) {
valueSelector = new EntityIndependentInitializedValueSelector((EntityIndependentValueSelector) valueSelector);
} else {
valueSelector = new InitializedValueSelector(valueSelector);
}
valueSelector = InitializedValueSelector.create(valueSelector);
}
return valueSelector;
}
Expand Down
Expand Up @@ -81,17 +81,17 @@ public long getSize() {

@Override
public Iterator<Object> iterator() {
return new JustInTimeFilteringEntityIterator(childEntitySelector.iterator());
return new JustInTimeFilteringEntityIterator(childEntitySelector.iterator(), determineBailOutSize());
}

protected class JustInTimeFilteringEntityIterator extends UpcomingSelectionIterator<Object> {

private final Iterator<Object> childEntityIterator;
private final long bailOutSize;

public JustInTimeFilteringEntityIterator(Iterator<Object> childEntityIterator) {
public JustInTimeFilteringEntityIterator(Iterator<Object> childEntityIterator, long bailOutSize) {
this.childEntityIterator = childEntityIterator;
this.bailOutSize = determineBailOutSize();
this.bailOutSize = bailOutSize;
}

@Override
Expand All @@ -118,13 +118,6 @@ protected Object createUpcomingSelection() {

}

protected long determineBailOutSize() {
if (!bailOutEnabled) {
return -1L;
}
return childEntitySelector.getSize() * 10L;
}

@Override
public ListIterator<Object> listIterator() {
// TODO Not yet implemented
Expand All @@ -139,10 +132,17 @@ public ListIterator<Object> listIterator(int index) {

@Override
public Iterator<Object> endingIterator() {
return new JustInTimeFilteringEntityIterator(childEntitySelector.endingIterator());
return new JustInTimeFilteringEntityIterator(childEntitySelector.endingIterator(), determineBailOutSize());
}

protected long determineBailOutSize() {
if (!bailOutEnabled) {
return -1L;
}
return childEntitySelector.getSize() * 10L;
}

private boolean accept(ScoreDirector scoreDirector, Object entity) {
protected boolean accept(ScoreDirector scoreDirector, Object entity) {
for (SelectionFilter filter : filterList) {
if (!filter.accept(scoreDirector, entity)) {
return false;
Expand Down
Expand Up @@ -75,17 +75,17 @@ public long getSize() {

@Override
public Iterator<Move> iterator() {
return new JustInTimeFilteringMoveIterator(childMoveSelector.iterator());
return new JustInTimeFilteringMoveIterator(childMoveSelector.iterator(), determineBailOutSize());
}

private class JustInTimeFilteringMoveIterator extends UpcomingSelectionIterator<Move> {

private final Iterator<Move> childMoveIterator;
private final long bailOutSize;

public JustInTimeFilteringMoveIterator(Iterator<Move> childMoveIterator) {
public JustInTimeFilteringMoveIterator(Iterator<Move> childMoveIterator, long bailOutSize) {
this.childMoveIterator = childMoveIterator;
this.bailOutSize = determineBailOutSize();
this.bailOutSize = bailOutSize;
}

@Override
Expand Down Expand Up @@ -119,7 +119,7 @@ protected long determineBailOutSize() {
return childMoveSelector.getSize() * 10L;
}

private boolean accept(ScoreDirector scoreDirector, Move move) {
protected boolean accept(ScoreDirector scoreDirector, Move move) {
for (SelectionFilter filter : filterList) {
if (!filter.accept(scoreDirector, move)) {
return false;
Expand Down
@@ -0,0 +1,51 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.optaplanner.core.impl.heuristic.selector.value.decorator;

import java.util.Iterator;
import java.util.List;

import org.optaplanner.core.impl.heuristic.selector.common.decorator.SelectionFilter;
import org.optaplanner.core.impl.heuristic.selector.value.EntityIndependentValueSelector;

public class EntityIndependentFilteringValueSelector extends FilteringValueSelector
implements EntityIndependentValueSelector {

public EntityIndependentFilteringValueSelector(EntityIndependentValueSelector childValueSelector,
List<SelectionFilter> filterList) {
super(childValueSelector, filterList);
}

@Override
public long getSize() {
return ((EntityIndependentValueSelector) childValueSelector).getSize();
}

@Override
public Iterator<Object> iterator() {
return new JustInTimeFilteringValueIterator(((EntityIndependentValueSelector) childValueSelector).iterator(),
determineBailOutSize());
}

protected long determineBailOutSize() {
if (!bailOutEnabled) {
return -1L;
}
return ((EntityIndependentValueSelector) childValueSelector).getSize() * 10L;
}

}

0 comments on commit b8ae184

Please sign in to comment.