Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public boolean contains(T value) {

@Override
public ValueRange<T> sort(ValueRangeSorter<T> sorter) {
return childValueRange.sort(sorter);
var sortedRange = (CountableValueRange<T>) childValueRange.sort(sorter);
return new NullAllowingCountableValueRange<>(sortedRange);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
import java.util.List;
import java.util.Objects;

import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore;
import ai.timefold.solver.core.api.score.buildin.simple.SimpleScore;
import ai.timefold.solver.core.api.score.calculator.EasyScoreCalculator;
import ai.timefold.solver.core.api.score.stream.Constraint;
import ai.timefold.solver.core.api.score.stream.ConstraintFactory;
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;
import ai.timefold.solver.core.api.solver.SolutionManager;
import ai.timefold.solver.core.config.constructionheuristic.ConstructionHeuristicPhaseConfig;
import ai.timefold.solver.core.config.constructionheuristic.ConstructionHeuristicType;
Expand All @@ -31,6 +35,8 @@
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSorterManner;
import ai.timefold.solver.core.config.solver.SolverConfig;
import ai.timefold.solver.core.config.solver.termination.TerminationConfig;
import ai.timefold.solver.core.testdomain.TestdataEntity;
import ai.timefold.solver.core.testdomain.TestdataSolution;
import ai.timefold.solver.core.testdomain.TestdataValue;
Expand All @@ -53,6 +59,8 @@
import ai.timefold.solver.core.testdomain.list.unassignedvar.TestdataAllowsUnassignedValuesListEntity;
import ai.timefold.solver.core.testdomain.list.unassignedvar.TestdataAllowsUnassignedValuesListSolution;
import ai.timefold.solver.core.testdomain.list.unassignedvar.TestdataAllowsUnassignedValuesListValue;
import ai.timefold.solver.core.testdomain.list.unassignedvar.sort.TestdataAllowsUnassignedListSortableEntity;
import ai.timefold.solver.core.testdomain.list.unassignedvar.sort.TestdataAllowsUnassignedListSortableSolution;
import ai.timefold.solver.core.testdomain.list.valuerange.TestdataListEntityProvidingEntity;
import ai.timefold.solver.core.testdomain.list.valuerange.TestdataListEntityProvidingScoreCalculator;
import ai.timefold.solver.core.testdomain.list.valuerange.TestdataListEntityProvidingSolution;
Expand Down Expand Up @@ -98,6 +106,8 @@
import ai.timefold.solver.core.testdomain.unassignedvar.TestdataAllowsUnassignedEasyScoreCalculator;
import ai.timefold.solver.core.testdomain.unassignedvar.TestdataAllowsUnassignedEntity;
import ai.timefold.solver.core.testdomain.unassignedvar.TestdataAllowsUnassignedSolution;
import ai.timefold.solver.core.testdomain.unassignedvar.sort.TestdataAllowsUnassignedSortableEntity;
import ai.timefold.solver.core.testdomain.unassignedvar.sort.TestdataAllowsUnassignedSortableSolution;
import ai.timefold.solver.core.testdomain.valuerange.entityproviding.unassignedvar.TestdataAllowsUnassignedEntityProvidingEntity;
import ai.timefold.solver.core.testdomain.valuerange.entityproviding.unassignedvar.TestdataAllowsUnassignedEntityProvidingScoreCalculator;
import ai.timefold.solver.core.testdomain.valuerange.entityproviding.unassignedvar.TestdataAllowsUnassignedEntityProvidingSolution;
Expand Down Expand Up @@ -1450,6 +1460,32 @@ void solveValueFactorySorting(ConstructionHeuristicTestConfig phaseConfig) {
}
}

@Test
void penalizeBasicVariable() {
var solverConfig = new SolverConfig()
.withSolutionClass(TestdataAllowsUnassignedSortableSolution.class)
.withEntityClasses(TestdataAllowsUnassignedSortableEntity.class)
.withConstraintProviderClass(PenalizeAssignedConstraintProvider.class)
.withPhases(new ConstructionHeuristicPhaseConfig()
.withTerminationConfig(new TerminationConfig().withStepCountLimit(3)));
var problem = TestdataAllowsUnassignedSortableSolution.generateSolution(1, 1, false);
var solution = PlannerTestUtils.solve(solverConfig, problem);
assertThat(solution.getEntityList().get(0).getValue()).isNull();
}

@Test
void penalizeListVariable() {
var solverConfig = new SolverConfig()
.withSolutionClass(TestdataAllowsUnassignedListSortableSolution.class)
.withEntityClasses(TestdataAllowsUnassignedListSortableEntity.class)
.withConstraintProviderClass(ListPenalizeAssignedConstraintProvider.class)
.withPhases(new ConstructionHeuristicPhaseConfig()
.withTerminationConfig(new TerminationConfig().withStepCountLimit(3)));
var problem = TestdataAllowsUnassignedListSortableSolution.generateSolution(1, 1, false);
var solution = PlannerTestUtils.solve(solverConfig, problem);
assertThat(solution.getEntityList().get(0).getValueList()).isEmpty();
}

@Test
void failConstructionHeuristicEntityRange() {
var solverConfig =
Expand Down Expand Up @@ -1712,6 +1748,35 @@ public static class TestdataSolutionEasyScoreCalculator
}
}

public static class PenalizeAssignedConstraintProvider implements ConstraintProvider {

@Override
public Constraint @NonNull [] defineConstraints(@NonNull ConstraintFactory constraintFactory) {
return new Constraint[] { penalizeAssigned(constraintFactory) };
}

Constraint penalizeAssigned(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(TestdataAllowsUnassignedSortableEntity.class)
Comment thread
zepfred marked this conversation as resolved.
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("penalize assigned");
}
}

public static class ListPenalizeAssignedConstraintProvider implements ConstraintProvider {

@Override
public Constraint @NonNull [] defineConstraints(@NonNull ConstraintFactory constraintFactory) {
return new Constraint[] { penalizeAssigned(constraintFactory) };
}

Constraint penalizeAssigned(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(TestdataAllowsUnassignedListSortableEntity.class)
.filter(entity -> !entity.getValueList().isEmpty())
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("penalize assigned");
}
}

private record ConstructionHeuristicTestConfig(ConstructionHeuristicPhaseConfig config, int[] expected, boolean shuffle) {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,16 @@ void sort() {
new ComparatorFactorySelectionSorter<>(solution -> integerComparator, SelectionSorterOrder.DESCENDING));
assertAllElementsOfIterator(((CountableValueRange<Integer>) new NullAllowingCountableValueRange<>(
(new ListValueRange<>(Arrays.asList(-15, 25, 0, 1, -1)))).sort(ascComparatorSorter)).createOriginalIterator(),
-15, -1, 0, 1, 25);
null, -15, -1, 0, 1, 25);
assertAllElementsOfIterator(((CountableValueRange<Integer>) new NullAllowingCountableValueRange<>(
(new ListValueRange<>(Arrays.asList(-15, 25, 0, 1, -1)))).sort(ascComparatorFactorySorter))
.createOriginalIterator(), -15, -1, 0, 1, 25);
.createOriginalIterator(), null, -15, -1, 0, 1, 25);
assertAllElementsOfIterator(((CountableValueRange<Integer>) new NullAllowingCountableValueRange<>(
(new ListValueRange<>(Arrays.asList(-15, 25, 0, 1, -1)))).sort(descComparatorSorter)).createOriginalIterator(),
25, 1, 0, -1, -15);
null, 25, 1, 0, -1, -15);
assertAllElementsOfIterator(((CountableValueRange<Integer>) new NullAllowingCountableValueRange<>(
(new ListValueRange<>(Arrays.asList(-15, 25, 0, 1, -1)))).sort(descComparatorFactorySorter))
.createOriginalIterator(), 25, 1, 0, -1, -15);
.createOriginalIterator(), null, 25, 1, 0, -1, -15);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ai.timefold.solver.core.testdomain.list.unassignedvar.sort;

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

import ai.timefold.solver.core.api.domain.entity.PlanningEntity;
import ai.timefold.solver.core.api.domain.variable.PlanningListVariable;
import ai.timefold.solver.core.testdomain.TestdataObject;
import ai.timefold.solver.core.testdomain.common.TestSortableComparator;
import ai.timefold.solver.core.testdomain.common.TestdataSortableValue;

@PlanningEntity
public class TestdataAllowsUnassignedListSortableEntity extends TestdataObject {

@PlanningListVariable(allowsUnassignedValues = true, valueRangeProviderRefs = "valueRange",
comparatorClass = TestSortableComparator.class)
private List<TestdataSortableValue> valueList;

public TestdataAllowsUnassignedListSortableEntity() {
}

public TestdataAllowsUnassignedListSortableEntity(String code) {
super(code);
this.valueList = new ArrayList<>();
}

public List<TestdataSortableValue> getValueList() {
return valueList;
}

public void setValueList(List<TestdataSortableValue> valueList) {
this.valueList = valueList;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package ai.timefold.solver.core.testdomain.list.unassignedvar.sort;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty;
import ai.timefold.solver.core.api.domain.solution.PlanningScore;
import ai.timefold.solver.core.api.domain.solution.PlanningSolution;
import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty;
import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider;
import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore;
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
import ai.timefold.solver.core.testdomain.common.TestdataSortableValue;

@PlanningSolution
public class TestdataAllowsUnassignedListSortableSolution {

public static SolutionDescriptor<TestdataAllowsUnassignedListSortableSolution> buildSolutionDescriptor() {
return SolutionDescriptor.buildSolutionDescriptor(
TestdataAllowsUnassignedListSortableSolution.class,
TestdataAllowsUnassignedListSortableEntity.class,
TestdataSortableValue.class);
}

public static TestdataAllowsUnassignedListSortableSolution generateSolution(int valueCount, int entityCount,
boolean shuffle) {
var entityList = new ArrayList<>(IntStream.range(0, entityCount)
.mapToObj(i -> new TestdataAllowsUnassignedListSortableEntity("Generated Entity " + i))
.toList());
var valueList = new ArrayList<>(IntStream.range(0, valueCount)
.mapToObj(i -> new TestdataSortableValue("Generated Value " + i, i))
.toList());
if (shuffle) {
var random = new Random(0);
Collections.shuffle(entityList, random);
Collections.shuffle(valueList, random);
}
TestdataAllowsUnassignedListSortableSolution solution = new TestdataAllowsUnassignedListSortableSolution();
solution.setValueList(valueList);
solution.setEntityList(entityList);
return solution;
}

private List<TestdataSortableValue> valueList;
private List<TestdataAllowsUnassignedListSortableEntity> entityList;
private HardSoftScore score;

@ValueRangeProvider(id = "valueRange")
@ProblemFactCollectionProperty
public List<TestdataSortableValue> getValueList() {
return valueList;
}

public void setValueList(List<TestdataSortableValue> valueList) {
this.valueList = valueList;
}

@PlanningEntityCollectionProperty
public List<TestdataAllowsUnassignedListSortableEntity> getEntityList() {
return entityList;
}

public void setEntityList(List<TestdataAllowsUnassignedListSortableEntity> entityList) {
this.entityList = entityList;
}

@PlanningScore
public HardSoftScore getScore() {
return score;
}

public void setScore(HardSoftScore score) {
this.score = score;
}

public void removeEntity(TestdataAllowsUnassignedListSortableEntity entity) {
this.entityList = entityList.stream()
.filter(e -> e != entity)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ai.timefold.solver.core.testdomain.unassignedvar.sort;

import ai.timefold.solver.core.api.domain.entity.PlanningEntity;
import ai.timefold.solver.core.api.domain.variable.PlanningVariable;
import ai.timefold.solver.core.testdomain.TestdataObject;
import ai.timefold.solver.core.testdomain.common.TestSortableComparator;
import ai.timefold.solver.core.testdomain.common.TestdataSortableValue;

@PlanningEntity
public class TestdataAllowsUnassignedSortableEntity extends TestdataObject {

@PlanningVariable(allowsUnassigned = true, valueRangeProviderRefs = "valueRange",
comparatorClass = TestSortableComparator.class)
private TestdataSortableValue value;

public TestdataAllowsUnassignedSortableEntity() {
}

public TestdataAllowsUnassignedSortableEntity(String code) {
super(code);
}

public TestdataSortableValue getValue() {
return value;
}

public void setValue(TestdataSortableValue value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package ai.timefold.solver.core.testdomain.unassignedvar.sort;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty;
import ai.timefold.solver.core.api.domain.solution.PlanningScore;
import ai.timefold.solver.core.api.domain.solution.PlanningSolution;
import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty;
import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider;
import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore;
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
import ai.timefold.solver.core.testdomain.common.TestdataSortableValue;

@PlanningSolution
public class TestdataAllowsUnassignedSortableSolution {

public static SolutionDescriptor<TestdataAllowsUnassignedSortableSolution> buildSolutionDescriptor() {
return SolutionDescriptor.buildSolutionDescriptor(
TestdataAllowsUnassignedSortableSolution.class,
TestdataAllowsUnassignedSortableEntity.class,
TestdataSortableValue.class);
}

public static TestdataAllowsUnassignedSortableSolution generateSolution(int valueCount, int entityCount,
boolean shuffle) {
var entityList = new ArrayList<>(IntStream.range(0, entityCount)
.mapToObj(i -> new TestdataAllowsUnassignedSortableEntity("Generated Entity " + i))
.toList());
var valueList = new ArrayList<>(IntStream.range(0, valueCount)
.mapToObj(i -> new TestdataSortableValue("Generated Value " + i, i))
.toList());
if (shuffle) {
var random = new Random(0);
Collections.shuffle(entityList, random);
Collections.shuffle(valueList, random);
}
TestdataAllowsUnassignedSortableSolution solution = new TestdataAllowsUnassignedSortableSolution();
solution.setValueList(valueList);
solution.setEntityList(entityList);
return solution;
}

private List<TestdataSortableValue> valueList;
private List<TestdataAllowsUnassignedSortableEntity> entityList;
private HardSoftScore score;

@ValueRangeProvider(id = "valueRange")
@ProblemFactCollectionProperty
public List<TestdataSortableValue> getValueList() {
return valueList;
}

public void setValueList(List<TestdataSortableValue> valueList) {
this.valueList = valueList;
}

@PlanningEntityCollectionProperty
public List<TestdataAllowsUnassignedSortableEntity> getEntityList() {
return entityList;
}

public void setEntityList(List<TestdataAllowsUnassignedSortableEntity> entityList) {
this.entityList = entityList;
}

@PlanningScore
public HardSoftScore getScore() {
return score;
}

public void setScore(HardSoftScore score) {
this.score = score;
}

public void removeEntity(TestdataAllowsUnassignedSortableEntity entity) {
this.entityList = entityList.stream()
.filter(e -> e != entity)
.toList();
}
}
Loading