ChainedSwapMove 期望链接额外的计划变量(当它来自 CountableValueRange 时<Long>)



我正在使用Optaplanner 7.38.0.Final

我已经实现了一个相对简单的模型,我遇到了一些问题。

我有一个名为"访问"的计划实体,其计划变量previousStandstill遵循与车辆配送示例几乎相同的模式,锚变量是"摩托车"类,因此基本上优化问题是找到给定摩托车员工的访问链(首次创建解决方案时固定(,最大限度地减少所有员工的所有路线的时间并为所有访问提供服务。

问题是我想不时打破链条以返回仓库,我认为没有必要创建另一个类来进行此中断,并且在需要路由重新启动时包含一个带有纪元秒时间戳的计划变量(时间戳介于相对较小的范围之间,startOfTrip下面的代码(。

Optaplanner 能够使用给定的 xml 配置创建求解器,如果我在分数计算器上创建一个断点,我可以检查变量并看到构造启发式能够创建有效的访问链,甚至设置时间戳变量的值。

但不知何故,几毫秒后,当在第 43 行(在上面给定版本的原始源代码上(调用org.optaplanner.core.impl.heuristic.selector.move.generic.chained.ChainedSwapMove构造函数时,求解器命中NullPointerException

public ChainedSwapMove(List<GenuineVariableDescriptor<Solution_>> variableDescriptorList,
List<SingletonInverseVariableSupply> inverseVariableSupplyList, Object leftEntity, Object rightEntity) {
super(variableDescriptorList, leftEntity, rightEntity);
oldLeftTrailingEntityList = new ArrayList<>(inverseVariableSupplyList.size());
oldRightTrailingEntityList = new ArrayList<>(inverseVariableSupplyList.size());
for (SingletonInverseVariableSupply inverseVariableSupply : inverseVariableSupplyList) {
oldLeftTrailingEntityList.add(inverseVariableSupply.getInverseSingleton(leftEntity));
oldRightTrailingEntityList.add(inverseVariableSupply.getInverseSingleton(rightEntity));
}
}

似乎变量inverseVariableSupplyList包含一个空引用(当它分析包含常规非链式计划变量的变量描述符列表时,它会创建这个空引用(

package X;
import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.variable.AnchorShadowVariable;
import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable;
import org.optaplanner.core.api.domain.variable.PlanningVariable;
import org.optaplanner.core.api.domain.variable.PlanningVariableGraphType;
import javax.persistence.Transient;
import java.io.Serializable;
import java.time.LocalDateTime;
@PlanningEntity
public class OptimizingVisit implements OptimizingStandstill , Serializable {
private static final long serialVersionUID = 9163651541108883957L;
private ContinuousBranchTripSolution solution;
private Order order;
private Long startOfTrip;
private Long start;
private Long arrivalTime;
private Long end;
private Long travelDuration;
private Long travelDistance;
private OptimizingStandstill previousStandstill;
private OptimizingVisit nextStandstill; //shadow variable
private OptimizingDriver optimizingDriver;
public OptimizingVisit() {
}
public OptimizingVisit(Order order, ContinuousBranchTripSolution solution) {
this.order = order;
this.solution = solution;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
@AnchorShadowVariable(sourceVariableName = "previousStandstill")
public OptimizingDriver getOptimizingDriver() {
return optimizingDriver;
}
public void setOptimizingDriver(OptimizingDriver optimizingDriver) {
this.optimizingDriver = optimizingDriver;
}
public Employee getDriver(){
return this.getOptimizingDriver().getDriver();
}
@PlanningVariable( valueRangeProviderRefs = "startTimeCandidates" )
public Long getStartOfTrip() {
return startOfTrip;
}
public void setStartOfTrip(Long startOfTrip) {
this.startOfTrip = startOfTrip;
}
public Long getTravelDuration() {
return travelDuration;
}
public void setTravelDuration(Long travelDuration) {
this.travelDuration = travelDuration;
}
public Long getTravelDistance() {
return travelDistance;
}
public void setTravelDistance(Long travelDistance) {
this.travelDistance = travelDistance;
}
@PlanningVariable( graphType = PlanningVariableGraphType.CHAINED , valueRangeProviderRefs = { "visitsRange" , "driversRange" } )
public OptimizingStandstill getPreviousStandstill() {
return previousStandstill;
}
public void setPreviousStandstill(OptimizingStandstill previousStandstill) {
this.previousStandstill = previousStandstill;
}
@Override
public OptimizingVisit getNextStandstill() {
return nextStandstill;
}
@Override
public void setNextStandstill(OptimizingVisit nextStandstill) {
this.nextStandstill = nextStandstill;
}
@Override
public Hexagon getHexagon() {
return this.getOrder().getShippingAddress().getHexagon();
}
public TimeRange getTimeRange() {
return new TimeRange( this.start , this.end );
}
/*Helper Methods*/
public long getRecursiveStart(){
if( this.getStartOfTrip() != null ) return this.getStartOfTrip() + 5*60;
if( this.start != null ) return this.start;
this.start = this.getPreviousStandstill().getRecursiveEnd();
return this.start;
}
public long getRecursiveArrivalTime(){
if( this.arrivalTime != null ) return this.arrivalTime;
this.arrivalTime = this.getRecursiveStart() + solution.getDistanceBetweenHexagons( this.getPreviousStandstill().getHexagon() , this.getHexagon() ).getDuration();
return this.arrivalTime;
}
@Override
public long getRecursiveEnd(){
if( this.end != null ) return this.end;
this.end = this.getRecursiveArrivalTime() + TripsOptimizer.standByDuration;
return this.end;
}
public boolean isEndOfTrip(){
return this.getNextStandstill() == null || ( ( OptimizingVisit ) this.getNextStandstill()).getStartOfTrip() != null;
}
public long endOfTrip(){
return this.getRecursiveEnd() + TripsOptimizer.standByDuration + solution.getDistanceBetweenHexagons( this.getHexagon() , this.getOptimizingDriver().getHexagon() ).getDuration();
}
@Override
public void cleanTimes() {
this.start = null;
this.arrivalTime = null;
this.end = null;
}
public long overlapWith( OptimizingVisit optimizingVisit ){
if( this.getRecursiveStart() > optimizingVisit.getRecursiveEnd() ) return 0;
if( this.getRecursiveEnd() < optimizingVisit.getRecursiveStart() ) return 0;
OptimizingVisit firstEvent;
OptimizingVisit lastEvent;
if( this.getRecursiveStart() < optimizingVisit.getRecursiveStart() ){
firstEvent = this;
lastEvent = optimizingVisit;
}else{
firstEvent = optimizingVisit;
lastEvent = this;
}
if( lastEvent.getRecursiveEnd() < firstEvent.getRecursiveEnd() ) return lastEvent.getRecursiveEnd() - lastEvent.getRecursiveStart();
return  firstEvent.getRecursiveEnd() - lastEvent.getRecursiveStart();
}
public long getTimePenalization(){
if( this.order == null ) return 0;
long estimatedArrivalTime = this.getRecursiveArrivalTime();
TimeRange orderTimeRange = this.getOrder().getTimeRange();
if( estimatedArrivalTime > orderTimeRange.getEnd() ){
double secondsOfDifference = estimatedArrivalTime - orderTimeRange.getEnd();
return (long) Math.pow( secondsOfDifference , this.getOrder().isExpress() ? 2 : 1.5 );
}
if( estimatedArrivalTime > orderTimeRange.getStart() ) return 0;
return (long) Math.pow( orderTimeRange.getStart() - estimatedArrivalTime , 2 );
}
@Transient
public double getCarryOnCash() {
if( this.order == null ) return 0;
double r = 0;
if( this.order.isOnAdvanceMode() ){
for ( TransactionMatrix tm : this.order.getTransactionMatrix() ) {
if( !PaymentMethodType.CASH.equals( tm.getPaymentMethodType() ) ) continue;
r += tm.getAdvance();
}
}else{
for ( TransactionMatrix tm : this.order.getTransactionMatrix() ) {
if( !PaymentMethodType.CASH.equals( tm.getPaymentMethodType() ) ) continue;
r += tm.getAmount();
}
}
return r;
}
public long getEarlyOrLateSeconds(){
TimeRange orderTimeRange = this.getOrder().getTimeRange();
long arrivalTime = this.getRecursiveArrivalTime();
long r = 0;
if( arrivalTime < orderTimeRange.getStart() ) r += orderTimeRange.getStart() - arrivalTime;
if( arrivalTime > orderTimeRange.getEnd() ) r += arrivalTime - orderTimeRange.getEnd();
return r;
}
public long getContinuousOptimizationScore( ContinuousBranchTripSolution solution ) {
return 0;
/*if( !( this.getPreviousStandstill() instanceof OptimizingTrip ) ){
return this.getTimePenalization();
}
double r = 0;
OptimizingTrip trip = (OptimizingTrip) this.getPreviousStandstill();
for ( DriverShift shift : solution.getDriverShifts() ){
if( this.getOptimizingDriver().getDriver().computedIdHashCode() != shift.getDriver().computedIdHashCode() ) continue;
long seconds = Math.max( 0 , trip.getEnd() - shift.getAvailableUntilAsEpochSeconds() );
r += Math.pow( seconds * 2 , 2 );
}
r += 0.25d * Math.max( this.getCarryOnCash() - this.getOptimizingDriver().getDriver().getTrustLevel() , 0 );
if ( trip.getStart() > solution.getStart() ) {
r -= 0.5d * ( trip.getEnd() - solution.getStart() );
}
r += this.getTimePenalization();
return (long) r;*/
}
@Override
public String toString() {
return String.format("OptimizingVisit{  %s  ,  %s  ,  %s  ,  %s , %s min early , %s min late  }",
this.order.getNumber(),
this.getOrder().getLowerBoundDelivery(),
this.getPreviousStandstill() == null ? "" : LocalDateTime.ofEpochSecond( this.getRecursiveArrivalTime() , 0 , BitemporalModel.ZONE_OFFSET ),
this.getOrder().getUpperBoundDelivery(),
this.getPreviousStandstill() == null ? "" : Math.max( 0 , ( this.getOrder().getTimeRange().getStart() - this.getRecursiveArrivalTime() ) ) / 60,
this.getPreviousStandstill() == null ? "" : Math.max( 0 , ( this.getRecursiveArrivalTime() - this.getOrder().getTimeRange().getEnd() ) ) / 60
);
}
}

我们最近修复了 PLANNER-1961,其症状与您在这里的问题非常相似。请查看OptaPlanner 7.39.0.final(当它出来时(或更高版本,您的问题很可能会消失。

相关内容

  • 没有找到相关文章

最新更新