Custom chain move implementation in OptaPlanner - optaplanner

For academic purpose, I'm trying to implement a custom chain move in OptaPlanner.
My aim is to purposefully move one link from a chain to another to speed up the resolution of the problem.
Start
1. A -> B -> C
2. D -> E -> F
Move E from D to A
1. A -> E -> B -> C
2. D -> F
Undo move
A -> B -> C
D -> E -> F
I have read both the documentation and several posts on stackoverflow (mainly this, this, this and this) but I keep getting java.lang.IllegalStateException error.
I am surely missing some concept to solve the problem.
What am I doing wrong?
Thanks
The error
2022-08-30 18:18:24,429 (OptaPool-10-MoveThread-2) Move thread (1) exception that will be propagated to the solver thread.: java.lang.IllegalStateException: The entity (eu.gurgolo.domain.Student#1de) has a variable (previousStandStill) with value (eu.gurgolo.domain.Student#1fb) which has a sourceVariableName variable (nextStudent) with a value (eu.gurgolo.domain.Student#1f8) which is not null.
Verify the consistency of your input problem for that sourceVariableName variable.
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.insert(SingletonInverseVariableListener.java:74)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.afterVariableChanged(SingletonInverseVariableListener.java:53)
The code
CustomMoveFactory
public class CustomMoveFactory implements MoveListFactory<MySolution> {
#Override
public List<CustomMove> createMoveList(MySolution solution) {
List<CustomMove> customMoves = new ArrayList<>();
List<Student> students = solution.getStudents();
for(Student s1 : students) {
for(Student s2 : students) {
//Here some logic to add
customMoves.add(new CustomMove(s1, s2));
}
}
return customMoves;
}
}
CustomMove
public class CustomMove extends AbstractMove<MySolution> {
private Student newStandStill;
private Student student;
public CustomMove(Student s1, Student s2) {
this.newStandStill = s1;
this.student = s2;
}
#Override
public boolean isMoveDoable(ScoreDirector<MySolution> scoreDirector) {
return !Objects.equals(newStandStill, student.getPreviousStandStill());
}
#Override
protected AbstractMove<MySolution> createUndoMove(ScoreDirector<MySolution> scoreDirector) {
return new CustomMove(student, newStandStill);
}
#Override
protected void doMoveOnGenuineVariables(ScoreDirector<MySolution> scoreDirector) {
Student nextStudent = student.getNextStudent();
Student nextStandStill = newStandStill.getNextStudent();
// 1. fix the chain where the student will be removed
if(nextStudent != null) {
scoreDirector.beforeVariableChanged(nextStudent, "previousStandStill");
nextStudent.setPreviousStandStill(student.getPreviousStandStill());
scoreDirector.afterVariableChanged(nextStudent, "previousStandStill");
}
// 2. fix the chain where the student will be added
if(nextStandStill != null) {
scoreDirector.beforeVariableChanged(nextStandStill, "previousStandStill");
nextStandStill.setPreviousStandStill(student.getPreviousStandStill());
scoreDirector.afterVariableChanged(nextStandStill, "previousStandStill");
}
// 3. move the student in the chain
scoreDirector.beforeVariableChanged(student, "previousStandStill");
student.setPreviousStandStill(newStandStill);
scoreDirector.afterVariableChanged(student, "previousStandStill");
}
#Override
public CustomMove rebase(ScoreDirector<MySolution> destinationScoreDirector) {
return new CustomMove(destinationScoreDirector.lookUpWorkingObject(newStandStill),
destinationScoreDirector.lookUpWorkingObject(student));
}
#Override
public Collection<? extends Object> getPlanningEntities() {
return Collections.singletonList(newStandStill);
}
#Override
public Collection<? extends Object> getPlanningValues() {
return Collections.singletonList(student);
}
#Override
public String getSimpleMoveTypeDescription() {
return getClass().getSimpleName() + "(" + Student.class.getSimpleName() + ".student)";
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final CustomMove other = (CustomMove) o;
return Objects.equals(newStandStill, other.newStandStill) &&
Objects.equals(student, other.student);
}
#Override
public int hashCode() {
return Objects.hash(newStandStill, student);
}
#Override
public String toString() {
long profId = newStandStill.getProf().getId();
long nextProfId = student.getProf().getId();
return newStandStill.getStudentId() + " {" + profId + " -> " + nextProfId + "}";
}
}

I have evaluated your CustomMove implementation on paper and tried to move E from D to A as proposed in your question.
I think you have a bug in step 2. Your code:
// 2. fix the chain where the student will be added
if(nextStandStill != null) {
scoreDirector.beforeVariableChanged(nextStandStill, "previousStandStill");
nextStandStill.setPreviousStandStill(student.getPreviousStandStill());
scoreDirector.afterVariableChanged(nextStandStill, "previousStandStill");
}
Fixed version of the above:
// 2. fix the chain where the student will be added
if(nextStandStill != null) {
scoreDirector.beforeVariableChanged(nextStandStill, "previousStandStill");
nextStandStill.setPreviousStandStill(student);
scoreDirector.afterVariableChanged(nextStandStill, "previousStandStill");
}
In "move E from D to A", A is newStandstill and so B is nextStandstill. E (the moved student) should become B's new previousStandstill. I hope that illuminates the proposed fix above.

Related

Is there a standard way to package many Restlets into a single Restlet?

I have a situation where the application developers and the framework provider are not the people. As a framework provider, I would like to be able to hand the developers what looks like a single Filter, but is in fact a chain of standard Filters (such as authentication, setting up invocation context, metrics, ++).
I don't seem to find this functionality in the standard library, but maybe there is an extension with it.
Instead of waiting for an answer, I went ahead with my own implementation and sharing here if some needs this.
/**
* Composes an array of Restlet Filters into a single Filter.
*/
public class ComposingFilter extends Filter
{
private final Filter first;
private final Filter last;
public ComposingFilter( Filter... composedOf )
{
Objects.requireNonNull( composedOf );
if( composedOf.length == 0 )
{
throw new IllegalArgumentException( "Filter chain can't be empty." );
}
first = composedOf[ 0 ];
Filter prev = first;
for( int i = 1; i < composedOf.length; i++ )
{
Filter next = composedOf[ i ];
prev.setNext( next );
prev = next;
}
last = composedOf[ composedOf.length - 1 ];
}
#Override
protected int doHandle( Request request, Response response )
{
if( first != null )
{
first.handle( request, response );
Response.setCurrent( response );
if( getContext() != null )
{
Context.setCurrent( getContext() );
}
}
else
{
response.setStatus( Status.SERVER_ERROR_INTERNAL );
getLogger().warning( "The filter " + getName() + " was executed without a next Restlet attached to it." );
}
return CONTINUE;
}
#Override
public synchronized void start()
throws Exception
{
if( isStopped() )
{
first.start();
super.start();
}
}
#Override
public synchronized void stop()
throws Exception
{
if( isStarted() )
{
super.stop();
first.stop();
}
}
#Override
public Restlet getNext()
{
return last.getNext();
}
#Override
public void setNext( Class<? extends ServerResource> targetClass )
{
last.setNext( targetClass );
}
#Override
public void setNext( Restlet next )
{
last.setNext( next );
}
}
NOTE: Not tested yet.

Oracle Coherence index not working with ContainsFilter query

I've added an index to a cache. The index uses a custom extractor that extends AbstractExtractor and overrides only the extract method to return a List of Strings. Then I have a ContainsFilter which uses the same custom extractor that looks for the occurence of a single String in the List of Strings. It does not look like my index is being used based on the time it takes to execute my test. What am I doing wrong? Also, is there some debugging I can switch on to see which indices are used?
public class DependencyIdExtractor extends AbstractExtractor {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Object extract(Object oTarget) {
if (oTarget == null) {
return null;
}
if (oTarget instanceof CacheValue) {
CacheValue cacheValue = (CacheValue)oTarget;
// returns a List of String objects
return cacheValue.getDependencyIds();
}
throw new UnsupportedOperationException();
}
}
Adding the index:
mCache = CacheFactory.getCache(pCacheName);
mCache.addIndex(new DependencyIdExtractor(), false, null);
Performing the ContainsFilter query:
public void invalidateByDependencyId(String pDependencyId) {
ContainsFilter vContainsFilter = new ContainsFilter(new DependencyIdExtractor(), pDependencyId);
#SuppressWarnings("rawtypes")
Set setKeys = mCache.keySet(vContainsFilter);
mCache.keySet().removeAll(setKeys);
}
I solved this by adding a hashCode and equals method implementation to the DependencyIdExtractor class. It is important that you use exactly the same value extractor when adding an index and creating your filter.
public class DependencyIdExtractor extends AbstractExtractor {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Object extract(Object oTarget) {
if (oTarget == null) {
return null;
}
if (oTarget instanceof CacheValue) {
CacheValue cacheValue = (CacheValue)oTarget;
return cacheValue.getDependencyIds();
}
throw new UnsupportedOperationException();
}
#Override
public int hashCode() {
return 1;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof DependencyIdExtractor) {
return true;
}
return false;
}
}
To debug Coherence indices/queries, you can generate an explain plan similar to database query explain plans.
http://www.oracle.com/technetwork/tutorials/tutorial-1841899.html
#SuppressWarnings("unchecked")
public void invalidateByDependencyId(String pDependencyId) {
ContainsFilter vContainsFilter = new ContainsFilter(new DependencyIdExtractor(), pDependencyId);
if (mLog.isTraceEnabled()) {
QueryRecorder agent = new QueryRecorder(RecordType.EXPLAIN);
Object resultsExplain = mCache.aggregate(vContainsFilter, agent);
mLog.trace("resultsExplain = \n" + resultsExplain + "\n");
}
#SuppressWarnings("rawtypes")
Set setKeys = mCache.keySet(vContainsFilter);
mCache.keySet().removeAll(setKeys);
}

How to define point cuts for a sequence of method(s)?

For example if I have 3 classes,
class A {
public void doA() {
/* do something */
}
}
class B {
public void doB() {
A a = new A();
a.doA();
}
}
class MyClass {
public static void main(String args[]) {
B b = new B();
b.doB();
}
}
Now I want to define a point cut for flow doB() -> doA(), like if doB() calls doA() grab parameters from class A and class B and do something in aspect method. Could someone help me out.
Let me slightly extend your sample code in order to make you understand what my solution does and what it cannot do:
class A {
public void doA() {}
}
class B {
public void doB() {
new A().doA();
new C().doC();
}
}
class C {
public void doC() {
new A().doA();
}
}
class MyClass {
public static void main(String args[]) {
new A().doA(); // should not be captured
new B().doB(); // should be captured
}
}
As you can see, there is a new class C now and we have three control flows now:
MyClass.main -> A.doA
MyClass.main -> B.doB -> A.doA
MyClass.main -> B.doB -> C.doC -> A.doA
You want to exclude #1 and capture #2, but what about #3? In this case a.doA is called indirectly from B.doB via C.doC. My solution also captures this indirect case. If this is fine for you or it does not happen in your code base, you can use my solution. Otherwise things would get a little more complicated and you would need to inspect the call stack. Tell me if you need to exclude #2, and I will extend my answer, but the solution will not look as simple as this one, I can promise.
Now here is the aspect:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class ControlFlowInterceptor {
#Before("execution(void A.doA()) && target(a) && cflow(execution(void B.doB()) && target(b))")
public void advice(JoinPoint thisJoinPoint, A a, B b) {
System.out.println(thisJoinPoint);
System.out.println(" " + a);
System.out.println(" " + b);
}
}
The console output looks like this:
execution(void A.doA())
A#7b19f779
B#65c66812
execution(void A.doA())
A#4df2868
B#65c66812
Please note that we have the same B object ID in both outputs, but because C.doC creates an new A object, we have two different A object IDs.

ArrayList partial integrating one List in another

I have a function that creates regular Objects of a same type and I cannot avoid that step.
When I use List.addAll(*) I will get many "Duplications" that are not equal in sense of Objectivity.
I have a very bad coded solution and want to ask if there could be a better or more effective one maybe with Java-Util-functions and defining a Comparator for that single intermezzo?
Here is my bad smell:
private void addPartial(List<SeMo_WikiArticle> allnewWiki, List<SeMo_WikiArticle> newWiki) {
if(allnewWiki.isEmpty())
allnewWiki.addAll(newWiki);
else{
for(SeMo_WikiArticle nn : newWiki){
boolean allreadyIn = false;
for(SeMo_WikiArticle oo : allnewWiki){
if(nn.getID()==oo.getID())
allreadyIn= true;
}
if(!allreadyIn)
allnewWiki.add(nn);
}
}
}
Any Ideas?
Add an override function of equals() into class SeMo_WikiArticle :
class SeMo_WikiArticle {
// assuming this class has two properties below
int id;
String name;
SeMo_WikiArticle(int id, String name) {
this.id = id;
this.name = name;
}
#Override
public boolean equals(Object obj) {
// implement your own comparison policy
// here is an example
if (obj instanceof SeMo_WikiArticle) {
SeMo_WikiArticle sw = (SeMo_WikiArticle)obj;
if (this.id == sw.id && (this.name == sw.name || this.name.equals(sw.name))) {
return true;
}
}
return false;
}
}
After that you can use contains() to judge if the list has already contains the specific object of SeMo_WikiArticle.
Here is the code:
private void addPartial(List<SeMo_WikiArticle> allnewWiki, List<SeMo_WikiArticle> newWiki) {
for (SeMo_WikiArticle sw : newWiki) {
if (!allnewWiki.contains(sw)) {
allnewWiki.add(sw);
}
}
}

How does hive achieve count(distinct ...)?

In the GenericUDAFCount.java:
#Description(name = "count",
value = "_FUNC_(*) - Returns the total number of retrieved rows, including "
+ "rows containing NULL values.\n"
+ "_FUNC_(expr) - Returns the number of rows for which the supplied "
+ "expression is non-NULL.\n"
+ "_FUNC_(DISTINCT expr[, expr...]) - Returns the number of rows for "
+ "which the supplied expression(s) are unique and non-NULL.")
but I don`t see any code to deal with the 'distinct' expression.
public static class GenericUDAFCountEvaluator extends GenericUDAFEvaluator {
private boolean countAllColumns = false;
private LongObjectInspector partialCountAggOI;
private LongWritable result;
#Override
public ObjectInspector init(Mode m, ObjectInspector[] parameters)
throws HiveException {
super.init(m, parameters);
partialCountAggOI =
PrimitiveObjectInspectorFactory.writableLongObjectInspector;
result = new LongWritable(0);
return PrimitiveObjectInspectorFactory.writableLongObjectInspector;
}
private GenericUDAFCountEvaluator setCountAllColumns(boolean countAllCols) {
countAllColumns = countAllCols;
return this;
}
/** class for storing count value. */
static class CountAgg implements AggregationBuffer {
long value;
}
#Override
public AggregationBuffer getNewAggregationBuffer() throws HiveException {
CountAgg buffer = new CountAgg();
reset(buffer);
return buffer;
}
#Override
public void reset(AggregationBuffer agg) throws HiveException {
((CountAgg) agg).value = 0;
}
#Override
public void iterate(AggregationBuffer agg, Object[] parameters)
throws HiveException {
// parameters == null means the input table/split is empty
if (parameters == null) {
return;
}
if (countAllColumns) {
assert parameters.length == 0;
((CountAgg) agg).value++;
} else {
assert parameters.length > 0;
boolean countThisRow = true;
for (Object nextParam : parameters) {
if (nextParam == null) {
countThisRow = false;
break;
}
}
if (countThisRow) {
((CountAgg) agg).value++;
}
}
}
#Override
public void merge(AggregationBuffer agg, Object partial)
throws HiveException {
if (partial != null) {
long p = partialCountAggOI.get(partial);
((CountAgg) agg).value += p;
}
}
#Override
public Object terminate(AggregationBuffer agg) throws HiveException {
result.set(((CountAgg) agg).value);
return result;
}
#Override
public Object terminatePartial(AggregationBuffer agg) throws HiveException {
return terminate(agg);
}
}
How does hive achieve count(distinct ...)? When task runs, it really cost much time.
Where is it in the source code?
As you can just run SELECT DISTINCT column1 FROM table1, DISTINCT expression isn't a flag or option, it's evaluated independently
This page says:
The actual filtering of data bound to parameter types for DISTINCT
implementation is handled by the framework and not the COUNT UDAF
implementation.
If you want drill down to source details, have a look into hive git repository