Optaplanner的供应被破坏了,因为sourceVariable的实体不能被收回:该实体从未被插入到该值中。

问题描述 投票:0回答:1

我正试图在Java中使用Optaplanner和Spring Boot来解决TSP问题。我想获得通过各种DeliveryLocation的最佳路由,但我得到了以下异常。

Caused by: java.lang.IllegalStateException: The supply (ExternalizedSingletonInverseVariableSupply(previousStandstill)) is corrupted, because the entity (DeliveryLocation{location=location 2}) for sourceVariable (previousStandstill) cannot be retracted: the entity was never inserted for that value (DeliveryLocation{location=location 3}).
    at org.optaplanner.core.impl.domain.variable.inverserelation.ExternalizedSingletonInverseVariableSupply.retract(ExternalizedSingletonInverseVariableSupply.java:116)
    at org.optaplanner.core.impl.domain.variable.inverserelation.ExternalizedSingletonInverseVariableSupply.beforeVariableChanged(ExternalizedSingletonInverseVariableSupply.java:74)
    at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.beforeVariableChanged(VariableListenerSupport.java:173)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:432)
    at org.optaplanner.core.impl.score.director.incremental.IncrementalScoreDirector.beforeVariableChanged(IncrementalScoreDirector.java:158)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.changeVariableFacade(AbstractScoreDirector.java:445)
    at org.optaplanner.core.impl.heuristic.selector.move.generic.chained.ChainedSwapMove.doMoveOnGenuineVariables(ChainedSwapMove.java:86)
    at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:36)
    at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:31)
    at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:190)
    at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.doMove(LocalSearchDecider.java:132)
    at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:116)

DeliveryLocation是这样的。

@PlanningEntity
public class DeliveryLocation implements Standstill {

    private RoadLocation location;

    //Planning variable: changes during planning between score calculation;

    @JsonIgnore
    private Standstill previousStandstill;

    public DeliveryLocation() {

    }

    public DeliveryLocation(RoadLocation location,
                            Standstill previousStandstill) {
        this.location = location;
        this.previousStandstill = previousStandstill;
    }

    @Override
    public RoadLocation getLocation() {
        return location;
    }

    public void setLocation(RoadLocation location) {
        this.location = location;
    }

    @PlanningVariable(valueRangeProviderRefs = {"deliveryLocationRange",
            "sourceRange"}, graphType = PlanningVariableGraphType.CHAINED,
            strengthWeightFactoryClass = SourceDistanceStandstillStrengthWeightFactory.class)
    public Standstill getPreviousStandstill() {
        return previousStandstill;
    }

    public void setPreviousStandstill(Standstill previousStandstill) {
        this.previousStandstill = previousStandstill;
    }

    // ********************************
    // Complex Methods
    // ********************************

    public long getDistanceFromPreviousStandstill() {
        if (previousStandstill == null) {
            return 0L;
        }
        return getDistanceFrom(previousStandstill);
    }

    public long getDistanceFrom(Standstill standstill) {
        return standstill.getLocation().getDistanceTo(location);
    }

    @Override
    public long getDistanceTo(Standstill standstill) {
        if (standstill == null) {
            return 0L;
        }
        return location.getDistanceTo(standstill.getLocation());

    }

    @Override
    public String toString() {
        return "DeliveryLocation{" + "location=" + location.getName() + "}";
    }
}

目前我正在手动加载每个地点到其他地点的距离图。

        String name = "name";
        Source source = new Source(new RoadLocation(23.614895, 46.782025));
        source.getLocation().setName("source");

        String measureUnit = "km";

        List<DeliveryLocation> deliveryLocationList = new ArrayList<>();

        DeliveryLocation location1 = new DeliveryLocation(new RoadLocation(23.615318, 46.788198),
                                                          null);
        location1.setPreviousStandstill(location1);
        location1.getLocation().setName("location 1");
        DeliveryLocation location2 = new DeliveryLocation(new RoadLocation(23.610762, 46.795077),
                                                          null);
        location2.getLocation().setName("location 2");

        DeliveryLocation location3 = new DeliveryLocation(new RoadLocation(23.607437, 46.80074),
                                                          null);
        location3.getLocation().setName("location 3");

        Map<RoadLocation, Double> travelDistanceMap = new HashMap<>();
        // source distance map
        travelDistanceMap.put(source.getLocation(), 0.0);
        travelDistanceMap.put(location1.getLocation(), 943.0);
        travelDistanceMap.put(location2.getLocation(), 2025.0);
        travelDistanceMap.put(location3.getLocation(), 2644.0);
        source.getLocation().setTravelDistanceMap(new HashMap<>(travelDistanceMap));

        travelDistanceMap.clear();
        // location1 distance map
        travelDistanceMap.put(source.getLocation(), 980.0);
        travelDistanceMap.put(location1.getLocation(), 0.0);
        travelDistanceMap.put(location2.getLocation(), 1081.0);
        travelDistanceMap.put(location3.getLocation(), 1700.0);
        location1.getLocation().setTravelDistanceMap(new HashMap<>(travelDistanceMap));

        travelDistanceMap.clear();
        //location2 distance map
        travelDistanceMap.put(source.getLocation(), 2042.0);
        travelDistanceMap.put(location1.getLocation(), 1062.0);
        travelDistanceMap.put(location2.getLocation(), 0.0);
        travelDistanceMap.put(location3.getLocation(), 752.0);
        location2.getLocation().setTravelDistanceMap(new HashMap<>(travelDistanceMap));

        travelDistanceMap.clear();
        //location3 distance map
        travelDistanceMap.put(source.getLocation(), 2687.0);
        travelDistanceMap.put(location1.getLocation(), 1707.0);
        travelDistanceMap.put(location2.getLocation(), 734.0);
        travelDistanceMap.put(location3.getLocation(), 0.0);
        location3.getLocation().setTravelDistanceMap(new HashMap<>(travelDistanceMap));

        List<RoadLocation> locationList = new ArrayList<>();
        locationList.add(location3.getLocation());
        locationList.add(location2.getLocation());
        locationList.add(location1.getLocation());

        deliveryLocationList.add(location1);
        deliveryLocationList.add(location2);
        deliveryLocationList.add(location3);

        BestRoute problem = new BestRoute(measureUnit, name, locationList, source,
                                          deliveryLocationList);
        UUID problemId = UUID.randomUUID();
        BestRoute bestRoute;
        SolverJob<BestRoute, UUID> solverJob = solverManager.solve(problemId, problem);
        try {
            bestRoute = solverJob.getFinalBestSolution();
        } catch (InterruptedException | ExecutionException e) {
            throw new IllegalStateException("Solving failed", e);
        }
        return bestRoute;
    }

这是我的BestRoute类(计划方案)。

@PlanningSolution
public class BestRoute implements Serializable {

    @JsonProperty(value = "unit-of-measurement")
    protected String distanceUnitOfMeasurement;
    private String name;
    @JsonProperty(value = "location-list")
    private List<RoadLocation> locationList;
    private Source source;

    @JsonProperty(value = "delivery-location-list")
    private List<DeliveryLocation> deliveryLocationList;
    private SimpleLongScore score;

    public BestRoute() {

    }

    public BestRoute(String distanceUnitOfMeasurement,
                     String name,
                     List<RoadLocation> locationList,
                     Source source,
                     List<DeliveryLocation> deliveryLocationList) {
        this.distanceUnitOfMeasurement = distanceUnitOfMeasurement;
        this.name = name;
        this.locationList = locationList;
        this.source = source;
        this.deliveryLocationList = deliveryLocationList;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ProblemFactCollectionProperty
    public List<RoadLocation> getLocationList() {
        return locationList;
    }

    public void setLocationList(List<RoadLocation> locationList) {
        this.locationList = locationList;
    }

    @ProblemFactProperty

    public Source getSource() {
        return source;
    }

    public void setSource(Source source) {
        this.source = source;
    }

    @PlanningEntityCollectionProperty
    @ValueRangeProvider(id = "deliveryLocationRange")
    public List<DeliveryLocation> getDeliveryLocationList() {
        return deliveryLocationList;
    }

    public void setDeliveryLocationList(List<DeliveryLocation> deliveryLocationList) {
        this.deliveryLocationList = deliveryLocationList;
    }

    @PlanningScore
    public SimpleLongScore getScore() {
        return score;
    }

    public void setScore(SimpleLongScore score) {
        this.score = score;
    }

    // ************************************************************************
    // Complex methods
    // ************************************************************************

    @ValueRangeProvider(id = "sourceRange")
    public List<Source> getSourceRange() {
        return Collections.singletonList(source);
    }


    public String getDistanceString(NumberFormat numberFormat) {
        if (score == null) {
            return null;
        }

        long distance = -score.getScore();
        if (distanceUnitOfMeasurement == null) {
            return numberFormat.format(((double) distance) / 1000.0);
        }
        switch (distanceUnitOfMeasurement) {
            case "sec": {
                long hours = distance / 3600000;
                long minutes = distance % 3600000 / 60000;
                long seconds = distance % 60000 / 1000;
                long milliseconds = distance % 1000;
                return hours + "h " + minutes + "m " + seconds + "s " + milliseconds + "ms";
            }
            case "km":
            case "meter": {
                long km = distance / 1000;
                long meter = distance % 1000;
                return km + "km " + meter + "m";
            }
            default:
                return numberFormat.format(((double) distance) / 1000.0) + " " +
                       distanceUnitOfMeasurement;
        }

    }

}

如果有必要,请向我索取其他的代码片段.谢谢你的帮助:)

java spring-boot optaplanner
1个回答
0
投票

暂时打开环境模式 FULL_ASSERT 之后关闭)。

我怀疑输入数据被破坏了,FULL_ASSERT可能会检测得更清楚。如果安访问A、B、C,那么如果B.previous=A,那么A.next=B,一定是这样。我怀疑在你的输入数据中,A.next不是B。

© www.soinside.com 2019 - 2024. All rights reserved.