Skip to content
Open
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
78 changes: 78 additions & 0 deletions benchmark/src/main/resources/benchmark.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,12 @@
<xs:element name="listRuinRecreateMoveSelector" type="tns:listRuinRecreateMoveSelectorConfig"/>


<xs:element name="multistageMoveSelector" type="tns:multistageMoveSelectorConfig"/>


<xs:element name="listMultistageMoveSelector" type="tns:listMultistageMoveSelectorConfig"/>


<xs:element name="subChainChangeMoveSelector" type="tns:subChainChangeMoveSelectorConfig"/>


Expand Down Expand Up @@ -2027,6 +2033,12 @@
<xs:element name="listRuinRecreateMoveSelector" type="tns:listRuinRecreateMoveSelectorConfig"/>


<xs:element name="multistageMoveSelector" type="tns:multistageMoveSelectorConfig"/>


<xs:element name="listMultistageMoveSelector" type="tns:listMultistageMoveSelectorConfig"/>


<xs:element name="subChainChangeMoveSelector" type="tns:subChainChangeMoveSelectorConfig"/>


Expand Down Expand Up @@ -2066,6 +2078,66 @@
</xs:complexType>


<xs:complexType name="multistageMoveSelectorConfig">


<xs:complexContent>


<xs:extension base="tns:moveSelectorConfig">


<xs:sequence>


<xs:element minOccurs="0" name="stageProviderClass" type="xs:string"/>


<xs:element minOccurs="0" name="entityClass" type="xs:string"/>


<xs:element minOccurs="0" name="variableName" type="xs:string"/>


</xs:sequence>


</xs:extension>


</xs:complexContent>


</xs:complexType>


<xs:complexType name="listMultistageMoveSelectorConfig">


<xs:complexContent>


<xs:extension base="tns:moveSelectorConfig">


<xs:sequence>


<xs:element minOccurs="0" name="stageProviderClass" type="xs:string"/>


</xs:sequence>


</xs:extension>


</xs:complexContent>


</xs:complexType>


<xs:complexType name="pooledEntityPlacerConfig">


Expand Down Expand Up @@ -2381,6 +2453,12 @@
<xs:element name="listRuinRecreateMoveSelector" type="tns:listRuinRecreateMoveSelectorConfig"/>


<xs:element name="multistageMoveSelector" type="tns:multistageMoveSelectorConfig"/>


<xs:element name="listMultistageMoveSelector" type="tns:listMultistageMoveSelectorConfig"/>


<xs:element name="subChainChangeMoveSelector" type="tns:subChainChangeMoveSelectorConfig"/>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.factory.MoveIteratorFactoryConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.factory.MoveListFactoryConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.ChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.MultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.RuinRecreateMoveSelectorConfig;
Expand All @@ -20,6 +21,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.SubChainSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.TailChainSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListMultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListRuinRecreateMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListChangeMoveSelectorConfig;
Expand Down Expand Up @@ -54,6 +56,10 @@ public class CartesianProductMoveSelectorConfig extends MoveSelectorConfig<Carte
type = RuinRecreateMoveSelectorConfig.class),
@XmlElement(name = ListRuinRecreateMoveSelectorConfig.XML_ELEMENT_NAME,
type = ListRuinRecreateMoveSelectorConfig.class),
@XmlElement(name = MultistageMoveSelectorConfig.XML_ELEMENT_NAME,
type = MultistageMoveSelectorConfig.class),
@XmlElement(name = ListMultistageMoveSelectorConfig.XML_ELEMENT_NAME,
type = ListMultistageMoveSelectorConfig.class),
@XmlElement(name = SubChainChangeMoveSelectorConfig.XML_ELEMENT_NAME,
type = SubChainChangeMoveSelectorConfig.class),
@XmlElement(name = SubChainSwapMoveSelectorConfig.XML_ELEMENT_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.factory.MoveIteratorFactoryConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.factory.MoveListFactoryConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.ChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.MultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.RuinRecreateMoveSelectorConfig;
Expand All @@ -23,6 +24,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.SubChainSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.TailChainSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListMultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListRuinRecreateMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListChangeMoveSelectorConfig;
Expand Down Expand Up @@ -61,6 +63,10 @@ public class UnionMoveSelectorConfig
type = RuinRecreateMoveSelectorConfig.class),
@XmlElement(name = ListRuinRecreateMoveSelectorConfig.XML_ELEMENT_NAME,
type = ListRuinRecreateMoveSelectorConfig.class),
@XmlElement(name = MultistageMoveSelectorConfig.XML_ELEMENT_NAME,
type = MultistageMoveSelectorConfig.class),
@XmlElement(name = ListMultistageMoveSelectorConfig.XML_ELEMENT_NAME,
type = ListMultistageMoveSelectorConfig.class),
@XmlElement(name = SubChainChangeMoveSelectorConfig.XML_ELEMENT_NAME,
type = SubChainChangeMoveSelectorConfig.class),
@XmlElement(name = SubChainSwapMoveSelectorConfig.XML_ELEMENT_NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package ai.timefold.solver.core.config.heuristic.selector.move.generic;

import java.util.function.Consumer;

import jakarta.xml.bind.annotation.XmlType;

import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;

import org.jspecify.annotations.NonNull;

@XmlType(propOrder = {
"stageProviderClass",
"entityClass",
"variableName"
})
public class MultistageMoveSelectorConfig extends MoveSelectorConfig<MultistageMoveSelectorConfig> {
public static final String XML_ELEMENT_NAME = "multistageMoveSelector";

protected Class<?> stageProviderClass;

protected Class<?> entityClass = null;
protected String variableName = null;

// **************************
// Getters/Setters
// **************************

public Class<?> getStageProviderClass() {
return stageProviderClass;
}

public void setStageProviderClass(
Class<?> stageProviderClass) {
this.stageProviderClass = stageProviderClass;
}

public Class<?> getEntityClass() {
return entityClass;
}

public void setEntityClass(Class<?> entityClass) {
this.entityClass = entityClass;
}

public String getVariableName() {
return variableName;
}

public void setVariableName(String variableName) {
this.variableName = variableName;
}

// **************************
// With methods
// **************************

public @NonNull MultistageMoveSelectorConfig withStageProviderClass(
@NonNull Class<?> stageProviderClass) {
this.setStageProviderClass(stageProviderClass);
return this;
}

public @NonNull MultistageMoveSelectorConfig withEntityClass(@NonNull Class<?> entityClass) {
this.setEntityClass(entityClass);
return this;
}

public @NonNull MultistageMoveSelectorConfig withVariableName(@NonNull String variableName) {
this.setVariableName(variableName);
return this;
}

// **************************
// Interface methods
// **************************

@Override
public boolean hasNearbySelectionConfig() {
return false;
}

@Override
public @NonNull MultistageMoveSelectorConfig copyConfig() {
return new MultistageMoveSelectorConfig().inherit(this);
}

@Override
public void visitReferencedClasses(@NonNull Consumer<Class<?>> classVisitor) {
classVisitor.accept(stageProviderClass);
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The visitReferencedClasses method should check if stageProviderClass is null before passing it to the classVisitor to avoid potential NullPointerException when the consumer doesn't handle null values. Additionally, entityClass should also be visited if it's non-null since it's a referenced class.

Suggested change
classVisitor.accept(stageProviderClass);
if (stageProviderClass != null) {
classVisitor.accept(stageProviderClass);
}
if (entityClass != null) {
classVisitor.accept(entityClass);
}

Copilot uses AI. Check for mistakes.
}

@Override
public @NonNull MultistageMoveSelectorConfig
inherit(@NonNull MultistageMoveSelectorConfig inheritedConfig) {
super.inherit(inheritedConfig);
stageProviderClass =
ConfigUtils.inheritOverwritableProperty(stageProviderClass,
inheritedConfig.getStageProviderClass());
entityClass =
ConfigUtils.inheritOverwritableProperty(entityClass, inheritedConfig.getEntityClass());
variableName =
ConfigUtils.inheritOverwritableProperty(variableName, inheritedConfig.getVariableName());
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package ai.timefold.solver.core.config.heuristic.selector.move.generic.list;

import java.util.function.Consumer;

import jakarta.xml.bind.annotation.XmlType;

import ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig;
import ai.timefold.solver.core.config.util.ConfigUtils;

import org.jspecify.annotations.NonNull;

@XmlType(propOrder = {
"stageProviderClass"
})
public class ListMultistageMoveSelectorConfig extends MoveSelectorConfig<ListMultistageMoveSelectorConfig> {
public static final String XML_ELEMENT_NAME = "listMultistageMoveSelector";

protected Class<?> stageProviderClass;

// **************************
// Getters/Setters
// **************************

public Class<?> getStageProviderClass() {
return stageProviderClass;
}

public void setStageProviderClass(
Class<?> stageProviderClass) {
this.stageProviderClass = stageProviderClass;
}

// **************************
// With methods
// **************************

public @NonNull ListMultistageMoveSelectorConfig withStageProviderClass(
@NonNull Class<?> stageProviderClass) {
this.setStageProviderClass(stageProviderClass);
return this;
}

// **************************
// Interface methods
// **************************

@Override
public boolean hasNearbySelectionConfig() {
return false;
}

@Override
public @NonNull ListMultistageMoveSelectorConfig copyConfig() {
return new ListMultistageMoveSelectorConfig().inherit(this);
}

@Override
public void visitReferencedClasses(@NonNull Consumer<Class<?>> classVisitor) {
classVisitor.accept(stageProviderClass);
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The visitReferencedClasses method should check if stageProviderClass is null before passing it to the classVisitor to avoid potential NullPointerException when the consumer doesn't handle null values.

Suggested change
classVisitor.accept(stageProviderClass);
if (stageProviderClass != null) {
classVisitor.accept(stageProviderClass);
}

Copilot uses AI. Check for mistakes.
}

@Override
public @NonNull ListMultistageMoveSelectorConfig
inherit(@NonNull ListMultistageMoveSelectorConfig inheritedConfig) {
super.inherit(inheritedConfig);
stageProviderClass =
ConfigUtils.inheritOverwritableProperty(stageProviderClass,
inheritedConfig.getStageProviderClass());
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.factory.MoveIteratorFactoryConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.factory.MoveListFactoryConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.ChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.MultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.PillarSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.RuinRecreateMoveSelectorConfig;
Expand All @@ -20,6 +21,7 @@
import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.SubChainSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.chained.TailChainSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListChangeMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListMultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListRuinRecreateMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListSwapMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.SubListChangeMoveSelectorConfig;
Expand Down Expand Up @@ -65,6 +67,10 @@ public class LocalSearchPhaseConfig extends PhaseConfig<LocalSearchPhaseConfig>
type = RuinRecreateMoveSelectorConfig.class),
@XmlElement(name = ListRuinRecreateMoveSelectorConfig.XML_ELEMENT_NAME,
type = ListRuinRecreateMoveSelectorConfig.class),
@XmlElement(name = MultistageMoveSelectorConfig.XML_ELEMENT_NAME,
type = MultistageMoveSelectorConfig.class),
@XmlElement(name = ListMultistageMoveSelectorConfig.XML_ELEMENT_NAME,
type = ListMultistageMoveSelectorConfig.class),
@XmlElement(name = SubChainChangeMoveSelectorConfig.XML_ELEMENT_NAME,
type = SubChainChangeMoveSelectorConfig.class),
@XmlElement(name = SubChainSwapMoveSelectorConfig.XML_ELEMENT_NAME,
Expand Down
Loading
Loading