Reputation: 807
For a solution of the time windowed VRP I edited the solved XML file and set <locked>true</locked>
for all customers.
I added a SelctionFiler class and configured it as proposed. At the end of solved xml data file I added some new unassigned customers.
I expected that only the new unassigned customers would be optimized and would be inserted at the end of the existing chains - which is not the case - the chains are broken.
Question: What exactly is in 6.2 necessary to handle immovable customer appointments?
I thought the jira issue https://issues.jboss.org/browse/PLANNER-239 has only to be solved for 6.0.1.
Geoffrey wrote: In 6.2 a number of improvements have been made for this IIRC, but it's not solved in all cases. What are the improvements for the time windowed VRP?
This questions belongs to my problem: Can optaplanner solve partly pre-assigned planning entities using Drools rules?
Best regards, Milenko
Upvotes: 0
Views: 618
Reputation: 1794
This is the configuration we use with optaplanner 6.2.0. To keep the customers locked in place filters had to be implemented for changeMoveSelector, swapMoveSelector and tailChainSwapMoveSelector in addition to CustomerEntitySelectionFilter.
<localSearch>
<unionMoveSelector>
<changeMoveSelector>
<entitySelector id="entitySelector1"/>
<filterClass>...THIS....CustomerFilterChangeMove</filterClass>
<valueSelector>
<nearbySelection>
<originEntitySelector mimicSelectorRef="entitySelector1"/>
<nearbyDistanceMeterClass>....CustomerNearbyDistanceMeter</nearbyDistanceMeterClass>
<parabolicDistributionSizeMaximum>80</parabolicDistributionSizeMaximum>
</nearbySelection>
</valueSelector>
</changeMoveSelector>
<swapMoveSelector>
<filterClass>...THIS....CustomerFilterSwapMove</filterClass>
</swapMoveSelector>
<tailChainSwapMoveSelector>
<entitySelector id="entitySelector3"/>
<filterClass>...THIS...CustomerFilterTailChainSwapMove</filterClass>
<valueSelector>
<nearbySelection>
<originEntitySelector mimicSelectorRef="entitySelector3"/>
<nearbyDistanceMeterClass>....CustomerNearbyDistanceMeter</nearbyDistanceMeterClass>
<parabolicDistributionSizeMaximum>80</parabolicDistributionSizeMaximum>
</nearbySelection>
</valueSelector>
<!--Disabled, doesn't work with tailChain -->
<!--<selectReversingMoveToo>false</selectReversingMoveToo>-->
</tailChainSwapMoveSelector>
</unionMoveSelector>
<acceptor>
<lateAcceptanceSize>200</lateAcceptanceSize>
</acceptor>
<forager>
<acceptedCountLimit>1</acceptedCountLimit>
</forager>
</localSearch>
The customer chain is checked for locked customers on EntitySelectionFilter and CustomerFilterTailChainSwapMove (both chains).
The classes are:
namespace ...THIS...;
public class CustomerFilterChangeMove implements SelectionFilter<ChangeMove> {
@Override
public boolean accept(ScoreDirector scoreDirector, ChangeMove changeMove) {
Customer customer = (Customer) changeMove.getEntity();
if(customer!=null && customer.isLocked())
return false;
//everything is fine
return true;
}
}
public class CustomerFilterSwapMove implements SelectionFilter<SwapMove>
{
@Override
public boolean accept(ScoreDirector scoreDirector, SwapMove move)
{
Customer leftCustomer = (Customer) move.getLeftEntity();
Customer rightCustomer = (Customer) move.getRightEntity();
if(leftCustomer!=null && leftCustomer.isLocked())
return false;
if(rightCustomer!=null && rightCustomer.isLocked())
return false;
return true;
}
}
public class CustomerFilterTailChainSwapMove implements SelectionFilter<TailChainSwapMove>
{
/**
* Chain starting at left entity will be moved to the right. If there's an entity on the right side, it's chain will be moved to the left
*/
@Override
public boolean accept(ScoreDirector scoreDirector, TailChainSwapMove move)
{
Customer shadow=null;
Customer leftCustomer = (Customer) move.getLeftEntity();
Customer rightCustomer = null;
Vehicle leftVehicle = leftCustomer.getVehicle();
Vehicle rightVehicle=null;
if(move.getRightValue() instanceof Customer)
{
rightCustomer = (Customer) move.getRightValue();
rightVehicle = rightCustomer.getVehicle();
}
else if(move.getRightValue() instanceof Vehicle)
{
rightVehicle = (Vehicle) move.getRightValue();
rightCustomer = rightVehicle.getNextCustomer();
}
shadow=rightCustomer;
while(shadow!=null)
{
if(shadow.isLocked())
return false;
shadow=shadow.getNextCustomer();
}
shadow=leftCustomer;
while(shadow!=null)
{
if(shadow.isLocked())
return false;
shadow=shadow.getNextCustomer();
}
return true;
}
}
public class CustomerEntitySelectionFilter implements SelectionFilter<Customer> {
@Override
public boolean accept(ScoreDirector scoreDirector, Customer customer) {
Customer shadow = customer;
while(shadow!=null)
{
if (shadow.isLocked())
return false;
shadow=shadow.getNextCustomer();
}
return true;
}
}
Upvotes: 2