Changing filed on chained planning entity

44 views
Skip to first unread message

Gvozden Marinkovic

unread,
Jun 15, 2020, 1:43:36 PM6/15/20
to OptaPlanner development
Is it possible to change filed on chained planning entity. I am developing 3d bin packing, emulating real case scenario. I designed custom moves, for box insertion. Depending on order I am calculating possible positions to reduce problem size. 

What I need is to set rotation and top left corner on planning entity, as a part of move.

Thank you in advance,

Gvozden


Gvozden Marinkovic

unread,
Jun 17, 2020, 12:51:33 PM6/17/20
to OptaPlanner development
 I chaned PlanningEntity classes, so rotation (axis), corner and locked flag are genuine variables now (not shadow).
Construction heuristics works, change move also, but Swap move (which needs to swap unlocked boxes does not work).

java.lang.NullPointerException: null
   at org.optaplanner.core.impl.heuristic.selector.move.generic.chained.ChainedSwapMove.<init>(ChainedSwapMove.java:43) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
 at org.optaplanner.core.impl.heuristic.selector.move.generic.SwapMoveSelector$2.newSwapSelection(SwapMoveSelector.java:151) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
  at org.optaplanner.core.impl.heuristic.selector.move.generic.SwapMoveSelector$2.newSwapSelection(SwapMoveSelector.java:148) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
  at org.optaplanner.core.impl.heuristic.selector.common.iterator.AbstractRandomSwapIterator.createUpcomingSelection(AbstractRandomSwapIterator.java:58) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
       at org.optaplanner.core.impl.heuristic.selector.common.iterator.UpcomingSelectionIterator.hasNext(UpcomingSelectionIterator.java:43) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
 at org.optaplanner.core.impl.heuristic.selector.move.composite.UnionMoveSelector$RandomUnionMoveIterator.refreshMoveIteratorMap(UnionMoveSelector.java:192) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
  at org.optaplanner.core.impl.heuristic.selector.move.composite.UnionMoveSelector$RandomUnionMoveIterator.hasNext(UnionMoveSelector.java:166) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
 at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(LocalSearchDecider.java:108) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
      at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:71) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
      at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
 at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:189) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
      at org.optaplanner.core.impl.solver.DefaultSolverJob.call(DefaultSolverJob.java:101) ~[optaplanner-core-7.38.0.Final.jar:7.38.0.Final]
 at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_201]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_201]
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_201]
     at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]

solver.xml

<localSearch>
    <unionMoveSelector>
        <changeMoveSelector>
            <valueSelector variableName="topLeftCorner"/>
            <filterClass>rs.plusplusnt.mario.planner.filters.CornerFilter</filterClass>
        </changeMoveSelector>
        <changeMoveSelector>
            <valueSelector variableName="axisPosition"/>
            <filterClass>rs.plusplusnt.mario.planner.filters.RotateFilter</filterClass>
        </changeMoveSelector>
        <changeMoveSelector>
            <valueSelector variableName="locked"/>
            <filterClass>rs.plusplusnt.mario.planner.filters.LockFilter</filterClass>
        </changeMoveSelector>
        <swapMoveSelector/>
    </unionMoveSelector>
</localSearch>

@PlanningEntity
public interface Allocation extends Allocation3D {
   Container getContainer();

    Boolean getLocked();
   List<Coordinate> getNextPackagePossibleCornerPositions();

    @InverseRelationShadowVariable(sourceVariableName = "previousAllocation")
   Package getNextPackage();
   void setNextPackage(Package nextPackage);
}

@PlanningEntity(difficultyComparatorClass = BoxDifficultyComparator.class)
public class Package implements Allocation {
   private Box box;
   private List<Coordinate> possibleCornerPositions;

   private Boolean locked = false;
   private AxisPosition axisPosition = AxisPosition.DEFAULT;
   private Coordinate topLeftCorner = Coordinate.center();

   private Allocation previousAllocation;

   /* shadow*/
   private Box allocatedBox;
   private Container container;
   private Package nextPackage;
   private List<Coordinate> nextPackagePossibleCornerPositions = Collections.singletonList(Coordinate.center());

   

   @Override
   @PlanningId
   public Long getId() {
       return box.getId();
   }

   @Override
   @AnchorShadowVariable(sourceVariableName = "previousAllocation")
   public Container getContainer() {
       return container;
   }

   @PlanningVariable(valueRangeProviderRefs = {"containersRange", "packagesRange"},
           graphType = PlanningVariableGraphType.CHAINED)
   public Allocation getPreviousAllocation() {
       return previousAllocation;
   }

   @InverseRelationShadowVariable(sourceVariableName = "previousAllocation")
   public Package getNextPackage() {
       return nextPackage;
   }

   @PlanningVariable(valueRangeProviderRefs = {"axisRange"})
   public AxisPosition getAxisPosition() {
       return axisPosition;
   }

   @PlanningVariable(valueRangeProviderRefs = {"cornerPositionRange"})
   public Coordinate getTopLeftCorner() {
       return topLeftCorner;
   }

   @ValueRangeProvider(id = "cornerPositionRange")
   public List<Coordinate> possibleCornerPositions() {
       if (previousAllocation != null && previousAllocation.getLocked()) {
           return previousAllocation.getNextPackagePossibleCornerPositions();
       }

        return possibleCornerPositions;
   }

   @ValueRangeProvider(id = "axisRange")
   public List<AxisPosition> possibleAxisPositions() {
       return box.getPossibleAxisPositions();
   }

   @CustomShadowVariable(variableListenerClass = PackagePositionChangeListener.class,
           sources = {@PlanningVariableReference(variableName = "topLeftCorner"),
                   @PlanningVariableReference(variableName = "axisPosition")})
   public Box getAllocatedBox() {
       return allocatedBox;
   }

   @PlanningPin
   @PlanningVariable(valueRangeProviderRefs = {"lockedRange"})
   public Boolean getLocked() {
       return locked;
   }

   @CustomShadowVariable(variableListenerClass = PackagePositionChangeListener.class,
            sources = {@PlanningVariableReference(variableName = "locked")})
   public List<Coordinate> getNextPackagePossibleCornerPositions() {
       return nextPackagePossibleCornerPositions;
   }

}


Geoffrey De Smet

unread,
Jun 17, 2020, 6:27:17 PM6/17/20
to optapla...@googlegroups.com

Try filtering the variableNames for the swap move selector

<localSearch>
  <unionMoveSelector>
   <changeMoveSelector/>
   <swapMoveSelector>
     <variableName>...</>
   </>
</>

See docs chapter on move selection

With kind regards,
Geoffrey De Smet

--
You received this message because you are subscribed to the Google Groups "OptaPlanner development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to optaplanner-d...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/optaplanner-dev/2fe1961f-3714-4ac0-9acd-664f36fb7b93o%40googlegroups.com.

Gvozden Marinkovic

unread,
Jun 18, 2020, 4:53:59 AM6/18/20
to optapla...@googlegroups.com
Thank you Geoffrey Swap is working now ... Struggle can begin ...

Reply all
Reply to author
Forward
0 new messages