in core/optaplanner-core-impl/src/main/java/org/optaplanner/core/impl/heuristic/selector/move/generic/list/kopt/KOptListMoveIterator.java [154:239]
private KOptDescriptor<Node_> pickKOptMoveRec(Iterator<Node_> valueIterator,
EntityOrderInfo entityOrderInfo,
Node_[] pickedValues,
int pickedSoFar,
int k,
boolean canSelectNewEntities) {
Node_ previousRemovedEdgeEndpoint = pickedValues[2 * pickedSoFar - 2];
Node_ nextRemovedEdgePoint, nextRemovedEdgeOppositePoint;
int remainingAttempts = (k - pickedSoFar + 3) * 2;
while (remainingAttempts > 0) {
nextRemovedEdgePoint = valueIterator.next();
EntityOrderInfo newEntityOrderInfo =
entityOrderInfo.withNewNode(nextRemovedEdgePoint, listVariableDescriptor, inverseVariableSupply);
while (nextRemovedEdgePoint == getNodePredecessor(newEntityOrderInfo, previousRemovedEdgeEndpoint) ||
nextRemovedEdgePoint == getNodeSuccessor(newEntityOrderInfo, previousRemovedEdgeEndpoint) ||
isEdgeAlreadyAdded(pickedValues, previousRemovedEdgeEndpoint, nextRemovedEdgePoint, pickedSoFar - 2) ||
(isEdgeAlreadyDeleted(pickedValues, nextRemovedEdgePoint,
getNodePredecessor(newEntityOrderInfo, nextRemovedEdgePoint),
pickedSoFar - 2)
&& isEdgeAlreadyDeleted(pickedValues, nextRemovedEdgePoint,
getNodeSuccessor(newEntityOrderInfo, nextRemovedEdgePoint),
pickedSoFar - 2))) {
if (remainingAttempts == 0) {
return null;
}
nextRemovedEdgePoint = valueIterator.next();
newEntityOrderInfo =
entityOrderInfo.withNewNode(nextRemovedEdgePoint, listVariableDescriptor, inverseVariableSupply);
remainingAttempts--;
}
remainingAttempts--;
pickedValues[2 * pickedSoFar - 1] = nextRemovedEdgePoint;
if (isEdgeAlreadyDeleted(pickedValues, nextRemovedEdgePoint,
getNodePredecessor(newEntityOrderInfo, nextRemovedEdgePoint),
pickedSoFar - 2)) {
nextRemovedEdgeOppositePoint = getNodeSuccessor(newEntityOrderInfo, nextRemovedEdgePoint);
} else if (isEdgeAlreadyDeleted(pickedValues, nextRemovedEdgePoint,
getNodeSuccessor(newEntityOrderInfo, nextRemovedEdgePoint),
pickedSoFar - 2)) {
nextRemovedEdgeOppositePoint = getNodePredecessor(newEntityOrderInfo, nextRemovedEdgePoint);
} else {
nextRemovedEdgeOppositePoint =
workingRandom.nextBoolean() ? getNodeSuccessor(newEntityOrderInfo, nextRemovedEdgePoint)
: getNodePredecessor(newEntityOrderInfo, nextRemovedEdgePoint);
}
pickedValues[2 * pickedSoFar] = nextRemovedEdgeOppositePoint;
if (canSelectNewEntities && isNodeEndpointOfList(nextRemovedEdgePoint)
|| isNodeEndpointOfList(nextRemovedEdgeOppositePoint)) {
valueIterator = getValuesOnSelectedEntitiesIterator(pickedValues);
canSelectNewEntities = false;
}
if (pickedSoFar < k) {
KOptDescriptor<Node_> descriptor = pickKOptMoveRec(valueIterator, newEntityOrderInfo, pickedValues,
pickedSoFar + 1, k, canSelectNewEntities);
if (descriptor != null && descriptor.isFeasible()) {
return descriptor;
}
} else {
KOptDescriptor<Node_> descriptor = new KOptDescriptor<>(pickedValues,
KOptUtils.getMultiEntitySuccessorFunction(pickedValues,
listVariableDescriptor,
inverseVariableSupply,
indexVariableSupply),
KOptUtils.getMultiEntityBetweenPredicate(pickedValues,
listVariableDescriptor,
inverseVariableSupply,
indexVariableSupply));
if (descriptor.isFeasible()) {
return descriptor;
} else {
descriptor = patchCycles(
descriptor,
newEntityOrderInfo, pickedValues,
pickedSoFar);
if (descriptor.isFeasible()) {
return descriptor;
}
}
}
}
return null;
}