private KOptDescriptor pickKOptMoveRec()

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;
    }