@@ -22,41 +22,43 @@ public class ListChangeMoveProvider<Solution_, Entity_, Value_>
22
22
23
23
private final PlanningListVariableMetaModel <Solution_ , Entity_ , Value_ > variableMetaModel ;
24
24
private final BiDataFilter <Solution_ , Entity_ , Value_ > isValueInListFilter ;
25
- private final BiDataFilter <Solution_ , Value_ , ElementPosition > noChangeDetectionFilter ;
25
+ private final BiDataFilter <Solution_ , Value_ , ElementPosition > validChangeFilter ;
26
26
27
27
public ListChangeMoveProvider (PlanningListVariableMetaModel <Solution_ , Entity_ , Value_ > variableMetaModel ) {
28
28
this .variableMetaModel = Objects .requireNonNull (variableMetaModel );
29
29
this .isValueInListFilter = (solution , entity , value ) -> {
30
- if (entity == null ) {
31
- // Necessary for the null entity to survive until the later stage,
32
- // where we will use it as a marker to unassigned the value.
30
+ if (entity == null || value == null ) {
31
+ // Necessary for the null to survive until the later stage,
32
+ // where we will use it as a marker to unassign the value.
33
33
return true ;
34
34
}
35
35
return solution .isValueInRange (variableMetaModel , entity , value );
36
36
};
37
- this .noChangeDetectionFilter = (solutionView , value , targetPosition ) -> {
38
- var currentPosition = solutionView .getPositionOf (variableMetaModel , Objects .requireNonNull (value ));
39
- if (!(currentPosition instanceof PositionInList currentPositionInList )) {
40
- // The current position is unassigned, which is acceptable if we can assign it to a list.
41
- return targetPosition instanceof PositionInList ;
37
+ this .validChangeFilter = (solutionView , value , targetPosition ) -> {
38
+ var currentPosition = solutionView .getPositionOf (variableMetaModel , value );
39
+ if (currentPosition .equals (targetPosition )) {
40
+ return false ;
42
41
}
43
- if (!(targetPosition instanceof PositionInList targetPositionInList )) {
44
- // The target position is unassigned, which is only acceptable if we can unassign the value.
45
- return true ;
46
- }
47
- if (Objects .equals (currentPositionInList , targetPositionInList )) {
48
- return false ; // No change in position, so no need to create a move.
49
- }
50
- if (currentPositionInList .entity () != targetPositionInList .entity ()) {
51
- return true ; // Different entities, so we can freely change the position.
52
- }
53
- var listLength = solutionView .countValues (variableMetaModel , currentPositionInList .entity ());
54
- if (listLength == 1 ) {
55
- return false ; // No need to change the position, as the value is the only one in this list.
42
+ if (currentPosition instanceof UnassignedElement ) {
43
+ var targetPositionInList = targetPosition .ensureAssigned ();
44
+ return solutionView .isValueInRange (variableMetaModel , targetPositionInList .entity (), value );
45
+ } else {
46
+ if (!(targetPosition instanceof PositionInList targetPositionInList )) { // Unassigning a value.
47
+ return true ;
48
+ }
49
+ var currentPositionInList = currentPosition .ensureAssigned ();
50
+ if (currentPositionInList .entity () == targetPositionInList .entity ()) {
51
+ var valueCount = solutionView .countValues (variableMetaModel , currentPositionInList .entity ());
52
+ if (valueCount == 1 ) {
53
+ return false ; // The value is already in the list, and it is the only one.
54
+ } else {
55
+ return currentPositionInList .index () != targetPositionInList .index ();
56
+ }
57
+ } else {
58
+ // We can move freely between entities.
59
+ return solutionView .isValueInRange (variableMetaModel , targetPositionInList .entity (), value );
60
+ }
56
61
}
57
- // Make sure we're not moving the value past the list end.
58
- // This would happen if the value was already at the end of the list.
59
- return currentPositionInList .index () != listLength - 1 || targetPositionInList .index () != listLength ;
60
62
};
61
63
}
62
64
@@ -69,14 +71,11 @@ public MoveProducer<Solution_> apply(MoveStreamFactory<Solution_> moveStreamFact
69
71
// To assign or reassign a value, we need to create:
70
72
// - A move for every unpinned value in every entity's list variable to assign the value before that position.
71
73
// - A move for every entity to assign it to the last position in the list variable.
72
- var unpinnedValuesToChange = moveStreamFactory .enumerate (variableMetaModel .type (), false );
73
- var unpinnedEntities = moveStreamFactory .enumerate (variableMetaModel .entity (). type (), true );
74
- var unpinnedValues = moveStreamFactory . enumerate ( variableMetaModel . type (), true );
74
+ var unpinnedEntities = moveStreamFactory .enumerate (variableMetaModel . entity () .type (), false );
75
+ var unpinnedValues = moveStreamFactory .enumerate (variableMetaModel .type (), true )
76
+ . filter (( solutionView , value ) -> value == null || solutionView . getPositionOf ( variableMetaModel , value ) instanceof PositionInList );
75
77
var entityValuePairs = unpinnedEntities .join (unpinnedValues , DataJoiners .filtering (isValueInListFilter ))
76
78
.map ((solutionView , entity , value ) -> {
77
- if (entity == null ) { // This will trigger unassignment of the value.
78
- return ElementPosition .unassigned ();
79
- }
80
79
var valueCount = solutionView .countValues (variableMetaModel , entity );
81
80
if (value == null || valueCount == 0 ) { // This will trigger assignment of the value at the end of the list.
82
81
return ElementPosition .of (entity , valueCount );
@@ -85,8 +84,8 @@ public MoveProducer<Solution_> apply(MoveStreamFactory<Solution_> moveStreamFact
85
84
}
86
85
})
87
86
.distinct ();
88
- var dataStream = unpinnedValuesToChange . join ( entityValuePairs ,
89
- DataJoiners .filtering (noChangeDetectionFilter ));
87
+ var dataStream = moveStreamFactory . enumerate ( variableMetaModel . type (), false )
88
+ . join ( entityValuePairs , DataJoiners .filtering (validChangeFilter ));
90
89
return moveStreamFactory .pick (dataStream )
91
90
.asMove ((solutionView , value , targetPosition ) -> {
92
91
var currentPosition = solutionView .getPositionOf (variableMetaModel , Objects .requireNonNull (value ));
0 commit comments