对于时间窗口VRP的解决方案,我编辑了已解决的XML文件,并为所有客户设置了<locked>true</locked>
。
我添加了一个SelctionFiler类并按照建议配置它。 在解决的xml数据文件的最后,我添加了一些新的未分配客户。
我预计只有新的未分配客户才会被优化,并且会在现有链的末尾插入 - 但事实并非如此 - 链断裂了。
问题:处理不可移动的客户约会所需的6.2究竟是什么?
我认为只需要为6.0.1解决jira问题https://issues.jboss.org/browse/PLANNER-239。
Geoffrey写道:在6.2中,对这个IIRC进行了一些改进,但并未在所有情况下都得到解决。 对时间窗口VRP有哪些改进?
这个问题属于我的问题:Can optaplanner solve partly pre-assigned planning entities using Drools rules?
祝你好运, 米伦科
答案 0 :(得分:2)
这是我们与optaplanner 6.2.0一起使用的配置。为了保持客户锁定,除了CustomerEntitySelectionFilter之外,还必须为changeMoveSelector,swapMoveSelector和tailChainSwapMoveSelector实现过滤器。
<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>
在EntitySelectionFilter和CustomerFilterTailChainSwapMove(两个链)上检查客户链是否有锁定客户。
课程是:
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;
}
}