Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
triceo committed Oct 28, 2024
1 parent 7a79b52 commit c163e9d
Show file tree
Hide file tree
Showing 21 changed files with 918 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ai.timefold.solver.core.api.move;

@FunctionalInterface
public non-sealed interface BiMoveConstructor<Solution_, A, B>
extends MoveConstructor<Solution_> {

Move<Solution_> apply(A a, B b);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ai.timefold.solver.core.api.move;

public interface Dataset<Solution_, A> {
}
38 changes: 38 additions & 0 deletions core/src/main/java/ai/timefold/solver/core/api/move/Datasets.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ai.timefold.solver.core.api.move;

import java.util.Collection;

import org.jspecify.annotations.NonNull;

public interface Datasets<Solution_> {

/**
* Create a cached stream of all possible values of a class.
* Read from the planning solution.
*
* @param clz
* @return
* @param <A>
*/
<A> @NonNull Dataset<Solution_, A> enumerate(@NonNull Class<A> clz);

/**
* Create a cached stream of arbitrary values.
* Read from the planning solution.
*
* @param extractor
* @param <A>
* @return
*/
<A> @NonNull Dataset<Solution_, A> enumerate(@NonNull SolutionExtractor<Solution_, A> extractor);

/**
* Create a cached stream of arbitrary values.
*
* @param collection
* @param <A>
* @return
*/
<A> @NonNull Dataset<Solution_, A> enumerate(@NonNull Collection<A> collection);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ai.timefold.solver.core.api.move;

public sealed interface MoveConstructor<Solution_> permits BiMoveConstructor {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ai.timefold.solver.core.api.move;

import java.util.function.BiFunction;

@FunctionalInterface
public interface MoveProvider<Solution_>
extends BiFunction<Datasets<Solution_>, Picker<Solution_>, MoveConstructor<Solution_>> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,77 @@
*/
public interface MutableSolutionView<Solution_> extends SolutionView<Solution_> {

/**
* Puts a given value at a particular index in a given entity's {@link PlanningListVariable planning list variable}.
* Moves all values at or after the index to the right.
*
* @param variableMetaModel Describes the variable to be changed.
* @param value The value to be assigned to a list variable.
* @param destinationEntity The entity whose list variable is to be changed.
* @param destinationIndex The index at which the value is to be assigned.
* @param <Entity_>
* @param <Value_>
*/
<Entity_, Value_> void assignValue(@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel,
@NonNull Value_ value, @NonNull Entity_ destinationEntity, int destinationIndex);

/**
* Removes a given value from the {@link PlanningListVariable planning list variable} that it's part of.
* Shifts any later values to the left.
*
* @param variableMetaModel Describes the variable to be changed.
* @param value The value to be removed from a list variable.
* @param <Entity_>
* @param <Value_>
* @throws IllegalStateException if the value is not assigned to a list variable
*/
default <Entity_, Value_> void unassignValue(
@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel,
@NonNull Value_ value) {
var locationInList = getPositionOf(variableMetaModel, value)
.ensureAssigned(() -> """
The value (%s) is not assigned to a list variable.
This may indicate score corruption or a problem with the move's implementation."""
.formatted(value));
unassignValue(variableMetaModel, value, locationInList.entity(), locationInList.index());
}

/**
* Removes a value from a given entity's {@link PlanningListVariable planning list variable} at a given index.
* Shifts any later values to the left.
*
* @param variableMetaModel Describes the variable to be changed.
* @param entity The entity whose element is to be removed from a list variable.
* @param index >= 0
* @param <Entity_>
* @param <Value_>
* @return the removed value
* @throws IllegalArgumentException if the index is out of bounds
*/
default <Entity_, Value_> @NonNull Value_ unassignValue(
@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel, @NonNull Entity_ entity,
int index) {
var value = getValueAtIndex(variableMetaModel, entity, index);
unassignValue(variableMetaModel, value, entity, index);
return value;
}

/**
* Removes a given value from a given entity's {@link PlanningListVariable planning list variable} at a given index.
* Shifts any later values to the left.
*
* @param variableMetaModel Describes the variable to be changed.
* @param value The value to be unassigned from a list variable.
* @param entity The entity whose value is to be unassigned from a list variable.
* @param index >= 0
* @param <Entity_>
* @param <Value_>
* @throws IllegalArgumentException if the index is out of bounds
* @throws IllegalStateException if the actual value at the given index is not the given value
*/
<Entity_, Value_> void unassignValue(@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel,
@NonNull Value_ value, @NonNull Entity_ entity, int index);

/**
* Reads the value of a @{@link PlanningVariable basic planning variable} of a given entity.
*
Expand All @@ -47,9 +118,10 @@ <Entity_, Value_> void changeVariable(@NonNull PlanningVariableMetaModel<Solutio
* @param sourceIndex >= 0
* @param destinationEntity The second entity whose variable value is to be changed.
* @param destinationIndex >= 0
* @return the value that was moved; null if nothing was moved
* @throws IndexOutOfBoundsException if the index is out of bounds
*/
<Entity_, Value_> void moveValueBetweenLists(
<Entity_, Value_> @Nullable Value_ moveValueBetweenLists(
@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel,
@NonNull Entity_ sourceEntity, int sourceIndex, @NonNull Entity_ destinationEntity, int destinationIndex);

Expand All @@ -60,9 +132,11 @@ <Entity_, Value_> void moveValueBetweenLists(
* @param entity The entity whose variable value is to be changed.
* @param sourceIndex >= 0
* @param destinationIndex >= 0
* @return the value that was moved; null if nothing was moved
* @throws IndexOutOfBoundsException if the index is out of bounds
*/
<Entity_, Value_> void moveValueInList(@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel,
<Entity_, Value_> @Nullable Value_ moveValueInList(
@NonNull PlanningListVariableMetaModel<Solution_, Entity_, Value_> variableMetaModel,
@NonNull Entity_ entity, int sourceIndex, int destinationIndex);

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ai.timefold.solver.core.api.move;

public interface Picker<Solution_> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ai.timefold.solver.core.api.move;

import java.util.Collection;
import java.util.function.BiFunction;

@FunctionalInterface
public interface SolutionExtractor<Solution_, A>
extends BiFunction<SolutionView<Solution_>, Solution_, Collection<A>> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,26 +154,35 @@ public List<Object> getValue(Object entity) {
return (List<Object>) value;
}

public Object removeElement(Object entity, int index) {
return getValue(entity).remove(index);
@SuppressWarnings("unchecked")
public <Value_> Value_ removeElement(Object entity, int index) {
var list = getValue(entity);
if (list.size() <= index) {
throw new IllegalArgumentException(
"The index to remove (%s) must be less than the size (%s) of the planning list variable (%s) of entity (%s)."
.formatted(index, list.size(), this, entity));
}
return (Value_) list.remove(index);
}

public void addElement(Object entity, int index, Object element) {
getValue(entity).add(index, element);
}

public Object getElement(Object entity, int index) {
@SuppressWarnings("unchecked")
public <Value_> Value_ getElement(Object entity, int index) {
var values = getValue(entity);
if (index >= values.size()) {
throw new IndexOutOfBoundsException(
"Impossible state: The index (%s) must be less than the size (%s) of the planning list variable (%s) of entity (%s)."
.formatted(index, values.size(), this, entity));
}
return values.get(index);
return (Value_) values.get(index);
}

public Object setElement(Object entity, int index, Object element) {
return getValue(entity).set(index, element);
@SuppressWarnings("unchecked")
public <Value_> Value_ setElement(Object entity, int index, Value_ element) {
return (Value_) getValue(entity).set(index, element);
}

public int getListSize(Object entity) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ai.timefold.solver.core.impl.move.dataset;

import java.util.List;

import ai.timefold.solver.core.api.move.Dataset;
import ai.timefold.solver.core.api.move.SolutionView;

public interface InnerUniDataset<Solution_, A>
extends Dataset<Solution_, A> {

void resetWorkingSolution(SolutionView<Solution_> solutionView, Solution_ workingSolution);

void add(A value);

void remove(A value);

void update(A value);

void fix();

List<A> values();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ai.timefold.solver.core.impl.move.dataset;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

import ai.timefold.solver.core.api.move.SolutionExtractor;
import ai.timefold.solver.core.api.move.SolutionView;

public final class UniSolutionBasedDatasetImpl<Solution_, A> implements InnerUniDataset<Solution_, A> {

private final SolutionExtractor<Solution_, A> extractor;
private List<A> values = Collections.emptyList();

public UniSolutionBasedDatasetImpl(SolutionExtractor<Solution_, A> extractor) {
this.extractor = Objects.requireNonNull(extractor);
}

@Override
public void resetWorkingSolution(SolutionView<Solution_> solutionView, Solution_ workingSolution) {
this.values = extractor.apply(solutionView, workingSolution)
.stream()
.distinct()
.toList();
}

@Override
public void add(A value) {
// Do nothing.
}

@Override
public void remove(A value) {
// Do nothing.
}

@Override
public void update(A value) {
// Do nothing.
}

@Override
public void fix() {
// Do nothing.
}

@Override
public List<A> values() {
return values;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ai.timefold.solver.core.impl.move.dataset;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

import ai.timefold.solver.core.api.move.SolutionView;

public final class UniStaticDatasetImpl<Solution_, A> implements InnerUniDataset<Solution_, A> {

private final List<A> values;

public UniStaticDatasetImpl(Collection<A> values) {
this.values = Objects.requireNonNull(values)
.stream()
.distinct()
.toList();
}

@Override
public void resetWorkingSolution(SolutionView<Solution_> solutionView, Solution_ workingSolution) {
// Do nothing.
}

@Override
public void add(A value) {
// Do nothing.
}

@Override
public void remove(A value) {
// Do nothing.
}

@Override
public void update(A value) {
// Do nothing.
}

@Override
public void fix() {
// Do nothing.
}

@Override
public List<A> values() {
return values;
}
}
Loading

0 comments on commit c163e9d

Please sign in to comment.