QuickSelect.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.numbers.arrays;

  18. /**
  19.  * Partition array data.
  20.  *
  21.  * <p>Note: Requires that the floating-point data contains no NaN values; sorting does not
  22.  * respect the order of signed zeros imposed by {@link Double#compare(double, double)};
  23.  * mixed signed zeros may be destroyed (the mixture updated during partitioning). The
  24.  * caller is responsible for counting a mixture of signed zeros and restoring them if
  25.  * required.
  26.  *
  27.  * @see Selection
  28.  * @since 1.2
  29.  */
  30. final class QuickSelect {
  31.     // Implementation Notes
  32.     //
  33.     // Selection is performed using a quickselect variant to recursively divide the range
  34.     // to select the target index, or indices. Partition sizes or recursion are monitored
  35.     // will fall-backs on poor convergence of a linearselect (single index) or heapselect.
  36.     //
  37.     // Many implementations were tested, each with strengths and weaknesses on different
  38.     // input data containing random elements, repeat elements, elements with repeat
  39.     // patterns, and constant elements. The final implementation performs well across data
  40.     // types for single and multiple indices with no obvious weakness.
  41.     // See: o.a.c.numbers.examples.jmh.arrays for benchmarking implementations.
  42.     //
  43.     // Single indices are selected using a quickselect adaptive method based on Alexandrescu.
  44.     // The algorithm is a quickselect around a pivot identified using a
  45.     // sample-of-sample-of-samples created from the entire range data. This pivot will
  46.     // have known lower and upper margins and ensures elimination of a minimum fraction of
  47.     // data at each step. To increase speed the pivot can be identified using less of the data
  48.     // but without margin guarantees (sampling mode). The algorithm monitors partition sizes
  49.     // against the known margins. If the reduction in the partition size is not large enough
  50.     // then the algorithm can disable sampling mode and ensure linear performance by removing
  51.     // a set fraction of the data each iteration.
  52.     //
  53.     // Modifications from Alexandrescu are:
  54.     // 1. Initialise sampling mode using the Floyd-Rivest (FR) SELECT algorithm.
  55.     // 2. Adaption is adjusted to force use of the lower margin in the far-step method when
  56.     //    sampling is disabled.
  57.     // 3. Change the far-step method to a min-of-4 then median-of-3 into the 2nd 12th-tile.
  58.     //    The original method uses a lower-median-of-4, min-of-3 into the 4th 12th-tile.
  59.     // 4. Position the sample around the target k when in sampling mode for the non-far-step
  60.     //    methods.
  61.     //
  62.     // The far step method is used when target k is within 1/12 of the end of the data A.
  63.     // The differences in the far-step method are:
  64.     // - The upper margin when not sampling is 8/24 vs. 9/24; the lower margin remains at 1/12.
  65.     // - The position of the sample is closer to the expected location of k < |A|/12.
  66.     // - Sampling mode uses a median-of-3 with adaptive k, matching the other step methods.
  67.     //   Note the original min-of-3 sample is more likely to create a pivot too small if used
  68.     //   with adaption leaving k in the larger partition and a wasted iteration.
  69.     //
  70.     // The Floyd-Rivest (FR) SELECT algorithm is preferred for sampling over using quickselect
  71.     // adaptive sampling. It uses a smaller sample and has improved heuristics to place the sample
  72.     // pivot. However the FR sample is a small range of the data and pivot selection can be poor
  73.     // if the sample is not representative. This can be mitigated by creating a random sample
  74.     // of the entire range for the pivot selection. This implementation does not use random
  75.     // sampling for the FR mode. Performance is identical on random data (randomisation is a
  76.     // negligible overhead) and faster on sorted data. Any data not suitable for the FR algorithm
  77.     // are immediately switched to the quickselect adaptive algorithm with sampling. Performance
  78.     // across a range of data shows this strategy is approximately mid-way in performance between
  79.     // FR with random sampling, and quickselect adaptive in sampling mode. The benefit is that
  80.     // sorted or partially partitioned data are not intentionally unordered as the method will
  81.     // only move elements known to be incorrectly placed in the array.
  82.     //
  83.     // Multiple indices are selected using a dual-pivot partition method by
  84.     // Yaroslavskiy to divide the interval containing the indices. Recursion is performed for
  85.     // regions containing target indices. The method is thus a partial quicksort into regions of
  86.     // interest. Excess recursion triggers use of a heapselect. When indices are effectively
  87.     // a single index the method can switch to the single index selection to use the FR algorithm.
  88.     //
  89.     // Alternative schemes to partition multiple indices are to repeat call single index select
  90.     // with cached pivots, or without cached pivots if processing indices in order as the previous
  91.     // index brackets the range for the next search. Caching pivots is the most effective
  92.     // alternative. It requires storing all pivots during select, and using the cache to look-up
  93.     // the search bounds (sub-range) for each target index. This requires 2n searches for n indices.
  94.     // All pivots must be stored to avoid destroying previously partitioned data on repeat entry
  95.     // to the array. The current scheme inverts this by requiring at most n-1 divides of the
  96.     // indices during recursion and has the advantage of tracking recursion depth during selection
  97.     // for each sub-range. Division of indices is a small overhead for the common case where
  98.     // the number of indices is far smaller than the size of the data.
  99.     //
  100.     // Dual-pivot partitioning adapted from Yaroslavskiy
  101.     // http://codeblab.com/wp-content/uploads/2009/09/DualPivotQuicksort.pdf
  102.     //
  103.     // Modified to allow partial sorting (partitioning):
  104.     // - Ignore insertion sort for tiny array (handled by calling code).
  105.     // - Ignore recursive calls for a full sort (handled by calling code).
  106.     // - Change to fast-forward over initial ascending / descending runs.
  107.     // - Change to fast-forward great when v > v2 and either break the sorting
  108.     //   loop, or move a[great] direct to the correct location.
  109.     // - Change to use the 2nd and 4th of 5 elements for the pivots.
  110.     // - Identify a large central region using ~5/8 of the length to trigger search for
  111.     //   equal values.
  112.     //
  113.     // For some indices and data a full sort of the data will be faster; this is impossible to
  114.     // predict on unknown data input and attempts to analyse the indices and data impact
  115.     // performance for the majority of use cases where sorting is not a suitable choice.
  116.     // Use of the sortselect finisher allows the current multiple indices method to degrade
  117.     // to a (non-optimised) dual-pivot quicksort (see below).
  118.     //
  119.     // heapselect vs sortselect
  120.     //
  121.     // Quickselect can switch to an alternative when: the range is very small
  122.     // (e.g. insertion sort); or the target index is close to the end (e.g. heapselect).
  123.     // Small ranges and a target index close to the end are handled using a hybrid of insertion
  124.     // sort and selection (sortselect). This is faster than heapselect for small distance from
  125.     // the edge (m) for a single index and has the advantage of sorting all upstream values from
  126.     // the target index (heapselect requires push-down of each successive value to sort). This
  127.     // allows the dual-pivot quickselect on multiple indices that saturate the range to degrade
  128.     // to a (non-optimised) dual-pivot quicksort. However sortselect is worst case Order(m * (r-l))
  129.     // for range [l, r] so cannot be used when quickselect fails to converge as m may be very large.
  130.     // Thus heapselect is used as the stopper algorithm when quickselect progress is slow on
  131.     // multiple indices. If heapselect is used for small range handling the performance on
  132.     // saturated indices is significantly slower. Hence the presence of two final selection
  133.     // methods for different purposes.

  134.     /** Sampling mode using Floyd-Rivest sampling. */
  135.     static final int MODE_FR_SAMPLING = -1;
  136.     /** Sampling mode. */
  137.     static final int MODE_SAMPLING = 0;
  138.     /** No sampling but use adaption of the target k. */
  139.     static final int MODE_ADAPTION = 1;
  140.     /** No sampling and no adaption of target k (strict margins). */
  141.     static final int MODE_STRICT = 2;

  142.     /** Minimum size for sortselect.
  143.      * Below this perform a sort rather than selection. This is used to avoid
  144.      * sort select on tiny data. */
  145.     private static final int MIN_SORTSELECT_SIZE = 4;
  146.     /** Single-pivot sortselect size for quickselect adaptive. Note that quickselect adaptive
  147.      * recursively calls quickselect so very small lengths are included with an initial medium
  148.      * length. Using lengths of 1023-5 and 2043-53 indicate optimum performance around 20-30.
  149.      * Note: The expand partition function assumes a sample of at least length 2 as each end
  150.      * of the sample is used as a sentinel; this imposes a minimum length of 24 on the range
  151.      * to ensure it contains a 12-th tile of length 2. Thus the absolute minimum for the
  152.      * distance from the edge is 12. */
  153.     private static final int LINEAR_SORTSELECT_SIZE = 24;
  154.     /** Dual-pivot sortselect size for the distance of a single k from the edge of the
  155.      * range length n. Benchmarking in range [81+81, 243+243] suggests a value of ~20 (or
  156.      * higher on some hardware). Ranges are chosen based on third interval spacing between
  157.      * powers of 3.
  158.      *
  159.      * <p>Sortselect is faster at this small size than heapselect. A second advantage is
  160.      * that all indices closer to the edge than the target index are also sorted. This
  161.      * allows selection of multiple close indices to be performed with effectively the
  162.      * same speed. High density indices will result in recursion to very short fragments
  163.      * which also trigger use of sort select. The threshold for sorting short lengths is
  164.      * configured in {@link #dualPivotSortSelectSize(int, int)}. */
  165.     private static final int DP_SORTSELECT_SIZE = 20;
  166.     /** Threshold to use Floyd-Rivest sub-sampling. This partitions a sample of the data to
  167.      * identify a pivot so that the target element is in the smaller set after partitioning.
  168.      * The original FR paper used 600 otherwise reverted to the target index as the pivot.
  169.      * This implementation reverts to quickselect adaptive which increases robustness
  170.      * at small size on a variety of data and allows raising the original FR threshold. */
  171.     private static final int FR_SAMPLING_SIZE = 1200;

  172.     /** Increment used for the recursion counter. The counter will overflow to negative when
  173.      * recursion has exceeded the maximum level. The counter is maintained in the upper bits
  174.      * of the dual-pivot control flags. */
  175.     private static final int RECURSION_INCREMENT = 1 << 20;
  176.     /** Mask to extract the sort select size from the dual-pivot control flags. Currently
  177.      * the bits below those used for the recursion counter are only used for the sort select size
  178.      * so this can use a mask with all bits below the increment. */
  179.     private static final int SORTSELECT_MASK = RECURSION_INCREMENT - 1;

  180.     /** Threshold to use repeated step left: 7 / 16. */
  181.     private static final double STEP_LEFT = 0.4375;
  182.     /** Threshold to use repeated step right: 9 / 16. */
  183.     private static final double STEP_RIGHT = 0.5625;
  184.     /** Threshold to use repeated step far-left: 1 / 12. */
  185.     private static final double STEP_FAR_LEFT = 0.08333333333333333;
  186.     /** Threshold to use repeated step far-right: 11 / 12. */
  187.     private static final double STEP_FAR_RIGHT = 0.9166666666666666;

  188.     /** No instances. */
  189.     private QuickSelect() {}

  190.     /**
  191.      * Partition the elements between {@code ka} and {@code kb} using a heap select
  192.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  193.      *
  194.      * @param a Data array to use to find out the K<sup>th</sup> value.
  195.      * @param left Lower bound (inclusive).
  196.      * @param right Upper bound (inclusive).
  197.      * @param ka Lower index to select.
  198.      * @param kb Upper index to select.
  199.      */
  200.     static void heapSelect(double[] a, int left, int right, int ka, int kb) {
  201.         if (right <= left) {
  202.             return;
  203.         }
  204.         // Use the smallest heap
  205.         if (kb - left < right - ka) {
  206.             heapSelectLeft(a, left, right, ka, kb);
  207.         } else {
  208.             heapSelectRight(a, left, right, ka, kb);
  209.         }
  210.     }

  211.     /**
  212.      * Partition the elements between {@code ka} and {@code kb} using a heap select
  213.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  214.      *
  215.      * <p>For best performance this should be called with {@code k} in the lower
  216.      * half of the range.
  217.      *
  218.      * @param a Data array to use to find out the K<sup>th</sup> value.
  219.      * @param left Lower bound (inclusive).
  220.      * @param right Upper bound (inclusive).
  221.      * @param ka Lower index to select.
  222.      * @param kb Upper index to select.
  223.      */
  224.     static void heapSelectLeft(double[] a, int left, int right, int ka, int kb) {
  225.         // Create a max heap in-place in [left, k], rooted at a[left] = max
  226.         // |l|-max-heap-|k|--------------|
  227.         // Build the heap using Floyd's heap-construction algorithm for heap size n.
  228.         // Start at parent of the last element in the heap (k),
  229.         // i.e. start = parent(n-1) : parent(c) = floor((c - 1) / 2) : c = k - left
  230.         int end = kb + 1;
  231.         for (int p = left + ((kb - left - 1) >> 1); p >= left; p--) {
  232.             maxHeapSiftDown(a, a[p], p, left, end);
  233.         }
  234.         // Scan the remaining data and insert
  235.         // Mitigate worst case performance on descending data by backward sweep
  236.         double max = a[left];
  237.         for (int i = right + 1; --i > kb;) {
  238.             final double v = a[i];
  239.             if (v < max) {
  240.                 a[i] = max;
  241.                 maxHeapSiftDown(a, v, left, left, end);
  242.                 max = a[left];
  243.             }
  244.         }
  245.         // Partition [ka, kb]
  246.         // |l|-max-heap-|k|--------------|
  247.         //  |  <-swap->  |   then sift down reduced size heap
  248.         // Avoid sifting heap of size 1
  249.         final int last = Math.max(left, ka - 1);
  250.         while (--end > last) {
  251.             maxHeapSiftDown(a, a[end], left, left, end);
  252.             a[end] = max;
  253.             max = a[left];
  254.         }
  255.     }

  256.     /**
  257.      * Sift the element down the max heap.
  258.      *
  259.      * <p>Assumes {@code root <= p < end}, i.e. the max heap is above root.
  260.      *
  261.      * @param a Heap data.
  262.      * @param v Value to sift.
  263.      * @param p Start position.
  264.      * @param root Root of the heap.
  265.      * @param end End of the heap (exclusive).
  266.      */
  267.     private static void maxHeapSiftDown(double[] a, double v, int p, int root, int end) {
  268.         // child2 = root + 2 * (parent - root) + 2
  269.         //        = 2 * parent - root + 2
  270.         while (true) {
  271.             // Right child
  272.             int c = (p << 1) - root + 2;
  273.             if (c > end) {
  274.                 // No left child
  275.                 break;
  276.             }
  277.             // Use the left child if right doesn't exist, or it is greater
  278.             if (c == end || a[c] < a[c - 1]) {
  279.                 --c;
  280.             }
  281.             if (v >= a[c]) {
  282.                 // Parent greater than largest child - done
  283.                 break;
  284.             }
  285.             // Swap and descend
  286.             a[p] = a[c];
  287.             p = c;
  288.         }
  289.         a[p] = v;
  290.     }

  291.     /**
  292.      * Partition the elements between {@code ka} and {@code kb} using a heap select
  293.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  294.      *
  295.      * <p>For best performance this should be called with {@code k} in the upper
  296.      * half of the range.
  297.      *
  298.      * @param a Data array to use to find out the K<sup>th</sup> value.
  299.      * @param left Lower bound (inclusive).
  300.      * @param right Upper bound (inclusive).
  301.      * @param ka Lower index to select.
  302.      * @param kb Upper index to select.
  303.      */
  304.     static void heapSelectRight(double[] a, int left, int right, int ka, int kb) {
  305.         // Create a min heap in-place in [k, right], rooted at a[right] = min
  306.         // |--------------|k|-min-heap-|r|
  307.         // Build the heap using Floyd's heap-construction algorithm for heap size n.
  308.         // Start at parent of the last element in the heap (k),
  309.         // i.e. start = parent(n-1) : parent(c) = floor((c - 1) / 2) : c = right - k
  310.         int end = ka - 1;
  311.         for (int p = right - ((right - ka - 1) >> 1); p <= right; p++) {
  312.             minHeapSiftDown(a, a[p], p, right, end);
  313.         }
  314.         // Scan the remaining data and insert
  315.         // Mitigate worst case performance on descending data by backward sweep
  316.         double min = a[right];
  317.         for (int i = left - 1; ++i < ka;) {
  318.             final double v = a[i];
  319.             if (v > min) {
  320.                 a[i] = min;
  321.                 minHeapSiftDown(a, v, right, right, end);
  322.                 min = a[right];
  323.             }
  324.         }
  325.         // Partition [ka, kb]
  326.         // |--------------|k|-min-heap-|r|
  327.         //                 |  <-swap->  |   then sift down reduced size heap
  328.         // Avoid sifting heap of size 1
  329.         final int last = Math.min(right, kb + 1);
  330.         while (++end < last) {
  331.             minHeapSiftDown(a, a[end], right, right, end);
  332.             a[end] = min;
  333.             min = a[right];
  334.         }
  335.     }

  336.     /**
  337.      * Sift the element down the min heap.
  338.      *
  339.      * <p>Assumes {@code root >= p > end}, i.e. the max heap is below root.
  340.      *
  341.      * @param a Heap data.
  342.      * @param v Value to sift.
  343.      * @param p Start position.
  344.      * @param root Root of the heap.
  345.      * @param end End of the heap (exclusive).
  346.      */
  347.     private static void minHeapSiftDown(double[] a, double v, int p, int root, int end) {
  348.         // child2 = root - 2 * (root - parent) - 2
  349.         //        = 2 * parent - root - 2
  350.         while (true) {
  351.             // Right child
  352.             int c = (p << 1) - root - 2;
  353.             if (c < end) {
  354.                 // No left child
  355.                 break;
  356.             }
  357.             // Use the left child if right doesn't exist, or it is less
  358.             if (c == end || a[c] > a[c + 1]) {
  359.                 ++c;
  360.             }
  361.             if (v <= a[c]) {
  362.                 // Parent less than smallest child - done
  363.                 break;
  364.             }
  365.             // Swap and descend
  366.             a[p] = a[c];
  367.             p = c;
  368.         }
  369.         a[p] = v;
  370.     }

  371.     /**
  372.      * Partition the elements between {@code ka} and {@code kb} using a sort select
  373.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  374.      *
  375.      * @param a Data array to use to find out the K<sup>th</sup> value.
  376.      * @param left Lower bound (inclusive).
  377.      * @param right Upper bound (inclusive).
  378.      * @param ka Lower index to select.
  379.      * @param kb Upper index to select.
  380.      */
  381.     static void sortSelect(double[] a, int left, int right, int ka, int kb) {
  382.         // Combine the test for right <= left with
  383.         // avoiding the overhead of sort select on tiny data.
  384.         if (right - left <= MIN_SORTSELECT_SIZE) {
  385.             Sorting.sort(a, left, right);
  386.             return;
  387.         }
  388.         // Sort the smallest side
  389.         if (kb - left < right - ka) {
  390.             sortSelectLeft(a, left, right, kb);
  391.         } else {
  392.             sortSelectRight(a, left, right, ka);
  393.         }
  394.     }

  395.     /**
  396.      * Partition the minimum {@code n} elements below {@code k} where
  397.      * {@code n = k - left + 1}. Uses an insertion sort algorithm.
  398.      *
  399.      * <p>Works with any {@code k} in the range {@code left <= k <= right}
  400.      * and performs a full sort of the range below {@code k}.
  401.      *
  402.      * <p>For best performance this should be called with
  403.      * {@code k - left < right - k}, i.e.
  404.      * to partition a value in the lower half of the range.
  405.      *
  406.      * @param a Data array to use to find out the K<sup>th</sup> value.
  407.      * @param left Lower bound (inclusive).
  408.      * @param right Upper bound (inclusive).
  409.      * @param k Index to select.
  410.      */
  411.     static void sortSelectLeft(double[] a, int left, int right, int k) {
  412.         // Sort
  413.         for (int i = left; ++i <= k;) {
  414.             final double v = a[i];
  415.             // Move preceding higher elements above (if required)
  416.             if (v < a[i - 1]) {
  417.                 int j = i;
  418.                 while (--j >= left && v < a[j]) {
  419.                     a[j + 1] = a[j];
  420.                 }
  421.                 a[j + 1] = v;
  422.             }
  423.         }
  424.         // Scan the remaining data and insert
  425.         // Mitigate worst case performance on descending data by backward sweep
  426.         double m = a[k];
  427.         for (int i = right + 1; --i > k;) {
  428.             final double v = a[i];
  429.             if (v < m) {
  430.                 a[i] = m;
  431.                 int j = k;
  432.                 while (--j >= left && v < a[j]) {
  433.                     a[j + 1] = a[j];
  434.                 }
  435.                 a[j + 1] = v;
  436.                 m = a[k];
  437.             }
  438.         }
  439.     }

  440.     /**
  441.      * Partition the maximum {@code n} elements above {@code k} where
  442.      * {@code n = right - k + 1}. Uses an insertion sort algorithm.
  443.      *
  444.      * <p>Works with any {@code k} in the range {@code left <= k <= right}
  445.      * and can be used to perform a full sort of the range above {@code k}.
  446.      *
  447.      * <p>For best performance this should be called with
  448.      * {@code k - left > right - k}, i.e.
  449.      * to partition a value in the upper half of the range.
  450.      *
  451.      * @param a Data array to use to find out the K<sup>th</sup> value.
  452.      * @param left Lower bound (inclusive).
  453.      * @param right Upper bound (inclusive).
  454.      * @param k Index to select.
  455.      */
  456.     static void sortSelectRight(double[] a, int left, int right, int k) {
  457.         // Sort
  458.         for (int i = right; --i >= k;) {
  459.             final double v = a[i];
  460.             // Move succeeding lower elements below (if required)
  461.             if (v > a[i + 1]) {
  462.                 int j = i;
  463.                 while (++j <= right && v > a[j]) {
  464.                     a[j - 1] = a[j];
  465.                 }
  466.                 a[j - 1] = v;
  467.             }
  468.         }
  469.         // Scan the remaining data and insert
  470.         // Mitigate worst case performance on descending data by backward sweep
  471.         double m = a[k];
  472.         for (int i = left - 1; ++i < k;) {
  473.             final double v = a[i];
  474.             if (v > m) {
  475.                 a[i] = m;
  476.                 int j = k;
  477.                 while (++j <= right && v > a[j]) {
  478.                     a[j - 1] = a[j];
  479.                 }
  480.                 a[j - 1] = v;
  481.                 m = a[k];
  482.             }
  483.         }
  484.     }

  485.     /**
  486.      * Partition the array such that index {@code k} corresponds to its correctly
  487.      * sorted value in the equivalent fully sorted array.
  488.      *
  489.      * <p>Assumes {@code k} is a valid index into [left, right].
  490.      *
  491.      * @param a Values.
  492.      * @param left Lower bound of data (inclusive).
  493.      * @param right Upper bound of data (inclusive).
  494.      * @param k Index.
  495.      */
  496.     static void select(double[] a, int left, int right, int k) {
  497.         quickSelectAdaptive(a, left, right, k, k, new int[1], MODE_FR_SAMPLING);
  498.     }

  499.     /**
  500.      * Partition the array such that indices {@code k} correspond to their correctly
  501.      * sorted value in the equivalent fully sorted array.
  502.      *
  503.      * <p>The count of the number of used indices is returned. If the keys are sorted in-place,
  504.      * the count is returned as a negative.
  505.      *
  506.      * @param a Values.
  507.      * @param left Lower bound of data (inclusive).
  508.      * @param right Upper bound of data (inclusive).
  509.      * @param k Indices (may be destructively modified).
  510.      * @param n Count of indices.
  511.      * @return the count of used indices
  512.      * @throws IndexOutOfBoundsException if any index {@code k} is not within the
  513.      * sub-range {@code [left, right]}
  514.      */
  515.     static int select(double[] a, int left, int right, int[] k, int n) {
  516.         if (n < 1) {
  517.             return 0;
  518.         }
  519.         if (n == 1) {
  520.             quickSelectAdaptive(a, left, right, k[0], k[0], new int[1], MODE_FR_SAMPLING);
  521.             return -1;
  522.         }

  523.         // Interval creation validates the indices are in [left, right]
  524.         final UpdatingInterval keys = IndexSupport.createUpdatingInterval(left, right, k, n);

  525.         // Save number of used indices
  526.         final int count = IndexSupport.countIndices(keys, n);

  527.         // Note: If the keys are not separated then they are effectively a single key.
  528.         // Any split of keys separated by the sort select size
  529.         // will be finished on the next iteration.
  530.         final int k1 = keys.left();
  531.         final int kn = keys.right();
  532.         if (kn - k1 < DP_SORTSELECT_SIZE) {
  533.             quickSelectAdaptive(a, left, right, k1, kn, new int[1], MODE_FR_SAMPLING);
  534.         } else {
  535.             // Dual-pivot mode with small range sort length configured using index density
  536.             dualPivotQuickSelect(a, left, right, keys, dualPivotFlags(left, right, k1, kn));
  537.         }
  538.         return count;
  539.     }

  540.     /**
  541.      * Partition the array such that indices {@code k} correspond to their
  542.      * correctly sorted value in the equivalent fully sorted array.
  543.      *
  544.      * <p>For all indices {@code [ka, kb]} and any index {@code i}:
  545.      *
  546.      * <pre>{@code
  547.      * data[i < ka] <= data[ka] <= data[kb] <= data[kb < i]
  548.      * }</pre>
  549.      *
  550.      * <p>This function accepts indices {@code [ka, kb]} that define the
  551.      * range of indices to partition. It is expected that the range is small.
  552.      *
  553.      * <p>The {@code flags} are used to control the sampling mode and adaption of
  554.      * the index within the sample.
  555.      *
  556.      * <p>Returns the bounds containing {@code [ka, kb]}. These may be lower/higher
  557.      * than the keys if equal values are present in the data.
  558.      *
  559.      * @param a Values.
  560.      * @param left Lower bound of data (inclusive, assumed to be strictly positive).
  561.      * @param right Upper bound of data (inclusive, assumed to be strictly positive).
  562.      * @param ka First key of interest.
  563.      * @param kb Last key of interest.
  564.      * @param bounds Upper bound of the range containing {@code [ka, kb]} (inclusive).
  565.      * @param flags Adaption flags.
  566.      * @return Lower bound of the range containing {@code [ka, kb]} (inclusive).
  567.      */
  568.     static int quickSelectAdaptive(double[] a, int left, int right, int ka, int kb,
  569.             int[] bounds, int flags) {
  570.         int l = left;
  571.         int r = right;
  572.         int m = flags;
  573.         while (true) {
  574.             // Select when ka and kb are close to the same end
  575.             // |l|-----|ka|kkkkkkkk|kb|------|r|
  576.             if (Math.min(kb - l, r - ka) < LINEAR_SORTSELECT_SIZE) {
  577.                 sortSelect(a, l, r, ka, kb);
  578.                 bounds[0] = kb;
  579.                 return ka;
  580.             }

  581.             // Only target ka; kb is assumed to be close
  582.             int p0;
  583.             final int n = r - l;
  584.             // f in [0, 1]
  585.             final double f = (double) (ka - l) / n;
  586.             // Record the larger margin (start at 1/4) to create the estimated size.
  587.             // step        L     R
  588.             // far left    1/12  1/3   (use 1/4 + 1/32 + 1/64 ~ 0.328)
  589.             // left        1/6   1/4
  590.             // middle      2/9   2/9   (use 1/4 - 1/32 ~ 0.219)
  591.             int margin = n >> 2;
  592.             if (m < MODE_SAMPLING && r - l > FR_SAMPLING_SIZE) {
  593.                 // Floyd-Rivest sample step uses the same margins
  594.                 p0 = sampleStep(a, l, r, ka, bounds);
  595.                 if (f <= STEP_FAR_LEFT || f >= STEP_FAR_RIGHT) {
  596.                     margin += (n >> 5) + (n >> 6);
  597.                 } else if (f > STEP_LEFT && f < STEP_RIGHT) {
  598.                     margin -= n >> 5;
  599.                 }
  600.             } else if (f <= STEP_LEFT) {
  601.                 if (f <= STEP_FAR_LEFT) {
  602.                     margin += (n >> 5) + (n >> 6);
  603.                     p0 = repeatedStepFarLeft(a, l, r, ka, bounds, m);
  604.                 } else {
  605.                     p0 = repeatedStepLeft(a, l, r, ka, bounds, m);
  606.                 }
  607.             } else if (f >= STEP_RIGHT) {
  608.                 if (f >= STEP_FAR_RIGHT) {
  609.                     margin += (n >> 5) + (n >> 6);
  610.                     p0 = repeatedStepFarRight(a, l, r, ka, bounds, m);
  611.                 } else {
  612.                     p0 = repeatedStepRight(a, l, r, ka, bounds, m);
  613.                 }
  614.             } else {
  615.                 margin -= n >> 5;
  616.                 p0 = repeatedStep(a, l, r, ka, bounds, m);
  617.             }

  618.             // Note: Here we expect [ka, kb] to be small and splitting is unlikely.
  619.             //                   p0 p1
  620.             // |l|--|ka|kkkk|kb|--|P|-------------------|r|
  621.             // |l|----------------|P|--|ka|kkk|kb|------|r|
  622.             // |l|-----------|ka|k|P|k|kb|--------------|r|
  623.             final int p1 = bounds[0];
  624.             if (kb < p0) {
  625.                 // Entirely on left side
  626.                 r = p0 - 1;
  627.             } else if (ka > p1) {
  628.                 // Entirely on right side
  629.                 l = p1 + 1;
  630.             } else {
  631.                 // Pivot splits [ka, kb]. Expect ends to be close to the pivot and finish.
  632.                 // Here we set the bounds for use after median-of-medians pivot selection.
  633.                 // In the event there are many equal values this allows collecting those
  634.                 // known to be equal together when moving around the medians sample.
  635.                 if (kb > p1) {
  636.                     sortSelectLeft(a, p1 + 1, r, kb);
  637.                     bounds[0] = kb;
  638.                 }
  639.                 if (ka < p0) {
  640.                     sortSelectRight(a, l, p0 - 1, ka);
  641.                     p0 = ka;
  642.                 }
  643.                 return p0;
  644.             }
  645.             // Update mode based on target partition size
  646.             if (r - l > n - margin) {
  647.                 m++;
  648.             }
  649.         }
  650.     }

  651.     /**
  652.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  653.      * that all elements smaller than pivot are before it and all elements larger than
  654.      * pivot are after it.
  655.      *
  656.      * <p>Partitions a Floyd-Rivest sample around a pivot offset so that the input {@code k} will
  657.      * fall in the smaller partition when the entire range is partitioned.
  658.      *
  659.      * <p>Assumes the range {@code r - l} is large.
  660.      *
  661.      * @param a Data array.
  662.      * @param l Lower bound (inclusive).
  663.      * @param r Upper bound (inclusive).
  664.      * @param k Target index.
  665.      * @param upper Upper bound (inclusive) of the pivot range.
  666.      * @return Lower bound (inclusive) of the pivot range.
  667.      */
  668.     private static int sampleStep(double[] a, int l, int r, int k, int[] upper) {
  669.         // Floyd-Rivest: use SELECT recursively on a sample of size S to get an estimate
  670.         // for the (k-l+1)-th smallest element into a[k], biased slightly so that the
  671.         // (k-l+1)-th element is expected to lie in the smaller set after partitioning.
  672.         final int n = r - l + 1;
  673.         final int ith = k - l + 1;
  674.         final double z = Math.log(n);
  675.         // sample size = 0.5 * n^(2/3)
  676.         final double s = 0.5 * Math.exp(0.6666666666666666 * z);
  677.         final double sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * Integer.signum(ith - (n >> 1));
  678.         final int ll = Math.max(l, (int) (k - ith * s / n + sd));
  679.         final int rr = Math.min(r, (int) (k + (n - ith) * s / n + sd));
  680.         // Sample recursion restarts from [ll, rr]
  681.         final int p = quickSelectAdaptive(a, ll, rr, k, k, upper, MODE_FR_SAMPLING);
  682.         return expandPartition(a, l, r, ll, rr, p, upper[0], upper);
  683.     }

  684.     /**
  685.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  686.      * that all elements smaller than pivot are before it and all elements larger than
  687.      * pivot are after it.
  688.      *
  689.      * <p>Assumes the range {@code r - l >= 8}; the caller is responsible for selection on a smaller
  690.      * range. If using a 12th-tile for sampling then assumes {@code r - l >= 11}.
  691.      *
  692.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  693.      * with the median of 3 then median of 3; the final sample is placed in the
  694.      * 5th 9th-tile; the pivot chosen from the sample is adaptive using the input {@code k}.
  695.      *
  696.      * <p>Given a pivot in the middle of the sample this has margins of 2/9 and 2/9.
  697.      *
  698.      * @param a Data array.
  699.      * @param l Lower bound (inclusive).
  700.      * @param r Upper bound (inclusive).
  701.      * @param k Target index.
  702.      * @param upper Upper bound (inclusive) of the pivot range.
  703.      * @param flags Control flags.
  704.      * @return Lower bound (inclusive) of the pivot range.
  705.      */
  706.     private static int repeatedStep(double[] a, int l, int r, int k, int[] upper, int flags) {
  707.         // Adapted from Alexandrescu (2016), algorithm 8.
  708.         final int fp;
  709.         final int s;
  710.         int p;
  711.         if (flags <= MODE_SAMPLING) {
  712.             // Median into a 12th-tile
  713.             fp = (r - l + 1) / 12;
  714.             // Position the sample around the target k
  715.             s = k - mapDistance(k - l, l, r, fp);
  716.             p = k;
  717.         } else {
  718.             // i in tertile [3f':6f')
  719.             fp = (r - l + 1) / 9;
  720.             final int f3 = 3 * fp;
  721.             final int end = l + (f3 << 1);
  722.             for (int i = l + f3; i < end; i++) {
  723.                 Sorting.sort3(a, i - f3, i, i + f3);
  724.             }
  725.             // 5th 9th-tile: [4f':5f')
  726.             s = l + (fp << 2);
  727.             // No adaption uses the middle to enforce strict margins
  728.             p = s + (flags == MODE_ADAPTION ? mapDistance(k - l, l, r, fp) : (fp >>> 1));
  729.         }
  730.         final int e = s + fp - 1;
  731.         for (int i = s; i <= e; i++) {
  732.             Sorting.sort3(a, i - fp, i, i + fp);
  733.         }
  734.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  735.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  736.     }

  737.     /**
  738.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  739.      * that all elements smaller than pivot are before it and all elements larger than
  740.      * pivot are after it.
  741.      *
  742.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  743.      * range.
  744.      *
  745.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  746.      * with the lower median of 4 then either median of 3 with the final sample placed in the
  747.      * 5th 12th-tile, or min of 3 with the final sample in the 4th 12th-tile;
  748.      * the pivot chosen from the sample is adaptive using the input {@code k}.
  749.      *
  750.      * <p>Given a pivot in the middle of the sample this has margins of 1/6 and 1/4.
  751.      *
  752.      * @param a Data array.
  753.      * @param l Lower bound (inclusive).
  754.      * @param r Upper bound (inclusive).
  755.      * @param k Target index.
  756.      * @param upper Upper bound (inclusive) of the pivot range.
  757.      * @param flags Control flags.
  758.      * @return Lower bound (inclusive) of the pivot range.
  759.      */
  760.     private static int repeatedStepLeft(double[] a, int l, int r, int k, int[] upper, int flags) {
  761.         // Adapted from Alexandrescu (2016), algorithm 9.
  762.         final int fp;
  763.         final int s;
  764.         int p;
  765.         if (flags <= MODE_SAMPLING) {
  766.             // Median into a 12th-tile
  767.             fp = (r - l + 1) / 12;
  768.             // Position the sample around the target k
  769.             // Avoid bounds error due to rounding as (k-l)/(r-l) -> 1/12
  770.             s = Math.max(k - mapDistance(k - l, l, r, fp), l + fp);
  771.             p = k;
  772.         } else {
  773.             // i in 2nd quartile
  774.             final int f = (r - l + 1) >> 2;
  775.             final int f2 = f + f;
  776.             final int end = l + f2;
  777.             for (int i = l + f; i < end; i++) {
  778.                 Sorting.lowerMedian4(a, i - f, i, i + f, i + f2);
  779.             }
  780.             // i in 5th 12th-tile
  781.             fp = f / 3;
  782.             s = l + f + fp;
  783.             // No adaption uses the middle to enforce strict margins
  784.             p = s + (flags == MODE_ADAPTION ? mapDistance(k - l, l, r, fp) : (fp >>> 1));
  785.         }
  786.         final int e = s + fp - 1;
  787.         for (int i = s; i <= e; i++) {
  788.             Sorting.sort3(a, i - fp, i, i + fp);
  789.         }
  790.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  791.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  792.     }

  793.     /**
  794.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  795.      * that all elements smaller than pivot are before it and all elements larger than
  796.      * pivot are after it.
  797.      *
  798.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  799.      * range.
  800.      *
  801.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  802.      * with the upper median of 4 then either median of 3 with the final sample placed in the
  803.      * 8th 12th-tile, or max of 3 with the final sample in the 9th 12th-tile;
  804.      * the pivot chosen from the sample is adaptive using the input {@code k}.
  805.      *
  806.      * <p>Given a pivot in the middle of the sample this has margins of 1/4 and 1/6.
  807.      *
  808.      * @param a Data array.
  809.      * @param l Lower bound (inclusive).
  810.      * @param r Upper bound (inclusive).
  811.      * @param k Target index.
  812.      * @param upper Upper bound (inclusive) of the pivot range.
  813.      * @param flags Control flags.
  814.      * @return Lower bound (inclusive) of the pivot range.
  815.      */
  816.     private static int repeatedStepRight(double[] a, int l, int r, int k, int[] upper, int flags) {
  817.         // Mirror image repeatedStepLeft using upper median into 3rd quartile
  818.         final int fp;
  819.         final int e;
  820.         int p;
  821.         if (flags <= MODE_SAMPLING) {
  822.             // Median into a 12th-tile
  823.             fp = (r - l + 1) / 12;
  824.             // Position the sample around the target k
  825.             // Avoid bounds error due to rounding as (r-k)/(r-l) -> 11/12
  826.             e = Math.min(k + mapDistance(r - k, l, r, fp), r - fp);
  827.             p = k;
  828.         } else {
  829.             // i in 3rd quartile
  830.             final int f = (r - l + 1) >> 2;
  831.             final int f2 = f + f;
  832.             final int end = r - f2;
  833.             for (int i = r - f; i > end; i--) {
  834.                 Sorting.upperMedian4(a, i - f2, i - f, i, i + f);
  835.             }
  836.             // i in 8th 12th-tile
  837.             fp = f / 3;
  838.             e = r - f - fp;
  839.             // No adaption uses the middle to enforce strict margins
  840.             p = e - (flags == MODE_ADAPTION ? mapDistance(r - k, l, r, fp) : (fp >>> 1));
  841.         }
  842.         final int s = e - fp + 1;
  843.         for (int i = s; i <= e; i++) {
  844.             Sorting.sort3(a, i - fp, i, i + fp);
  845.         }
  846.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  847.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  848.     }

  849.     /**
  850.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  851.      * that all elements smaller than pivot are before it and all elements larger than
  852.      * pivot are after it.
  853.      *
  854.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  855.      * range.
  856.      *
  857.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  858.      * with the minimum of 4 then median of 3; the final sample is placed in the
  859.      * 2nd 12th-tile; the pivot chosen from the sample is adaptive using the input {@code k}.
  860.      *
  861.      * <p>Given a pivot in the middle of the sample this has margins of 1/12 and 1/3.
  862.      *
  863.      * @param a Data array.
  864.      * @param l Lower bound (inclusive).
  865.      * @param r Upper bound (inclusive).
  866.      * @param k Target index.
  867.      * @param upper Upper bound (inclusive) of the pivot range.
  868.      * @param flags Control flags.
  869.      * @return Lower bound (inclusive) of the pivot range.
  870.      */
  871.     private static int repeatedStepFarLeft(double[] a, int l, int r, int k, int[] upper, int flags) {
  872.         // Far step has been changed from the Alexandrescu (2016) step of lower-median-of-4, min-of-3
  873.         // into the 4th 12th-tile to a min-of-4, median-of-3 into the 2nd 12th-tile.
  874.         // The differences are:
  875.         // - The upper margin when not sampling is 8/24 vs. 9/24; the lower margin remains at 1/12.
  876.         // - The position of the sample is closer to the expected location of k < |A| / 12.
  877.         // - Sampling mode uses a median-of-3 with adaptive k, matching the other step methods.
  878.         //   A min-of-3 sample can create a pivot too small if used with adaption of k leaving
  879.         //   k in the larger parition and a wasted iteration.
  880.         // - Adaption is adjusted to force use of the lower margin when not sampling.
  881.         final int fp;
  882.         final int s;
  883.         int p;
  884.         if (flags <= MODE_SAMPLING) {
  885.             // 2nd 12th-tile
  886.             fp = (r - l + 1) / 12;
  887.             s = l + fp;
  888.             // Use adaption
  889.             p = s + mapDistance(k - l, l, r, fp);
  890.         } else {
  891.             // i in 2nd quartile; min into i-f (1st quartile)
  892.             final int f = (r - l + 1) >> 2;
  893.             final int f2 = f + f;
  894.             final int end = l + f2;
  895.             for (int i = l + f; i < end; i++) {
  896.                 if (a[i + f] < a[i - f]) {
  897.                     final double u = a[i + f];
  898.                     a[i + f] = a[i - f];
  899.                     a[i - f] = u;
  900.                 }
  901.                 if (a[i + f2] < a[i]) {
  902.                     final double v = a[i + f2];
  903.                     a[i + f2] = a[i];
  904.                     a[i] = v;
  905.                 }
  906.                 if (a[i] < a[i - f]) {
  907.                     final double u = a[i];
  908.                     a[i] = a[i - f];
  909.                     a[i - f] = u;
  910.                 }
  911.             }
  912.             // 2nd 12th-tile
  913.             fp = f / 3;
  914.             s = l + fp;
  915.             // Lower margin has 2(d+1) elements; d == (position in sample) - s
  916.             // Force k into the lower margin
  917.             p = s + ((k - l) >>> 1);
  918.         }
  919.         final int e = s + fp - 1;
  920.         for (int i = s; i <= e; i++) {
  921.             Sorting.sort3(a, i - fp, i, i + fp);
  922.         }
  923.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  924.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  925.     }

  926.     /**
  927.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  928.      * that all elements smaller than pivot are before it and all elements larger than
  929.      * pivot are after it.
  930.      *
  931.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  932.      * range.
  933.      *
  934.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  935.      * with the maximum of 4 then median of 3; the final sample is placed in the
  936.      * 11th 12th-tile; the pivot chosen from the sample is adaptive using the input {@code k}.
  937.      *
  938.      * <p>Given a pivot in the middle of the sample this has margins of 1/3 and 1/12.
  939.      *
  940.      * @param a Data array.
  941.      * @param l Lower bound (inclusive).
  942.      * @param r Upper bound (inclusive).
  943.      * @param k Target index.
  944.      * @param upper Upper bound (inclusive) of the pivot range.
  945.      * @param flags Control flags.
  946.      * @return Lower bound (inclusive) of the pivot range.
  947.      */
  948.     private static int repeatedStepFarRight(double[] a, int l, int r, int k, int[] upper, int flags) {
  949.         // Mirror image repeatedStepFarLeft
  950.         final int fp;
  951.         final int e;
  952.         int p;
  953.         if (flags <= MODE_SAMPLING) {
  954.             // 11th 12th-tile
  955.             fp = (r - l + 1) / 12;
  956.             e = r - fp;
  957.             // Use adaption
  958.             p = e - mapDistance(r - k, l, r, fp);
  959.         } else {
  960.             // i in 3rd quartile; max into i+f (4th quartile)
  961.             final int f = (r - l + 1) >> 2;
  962.             final int f2 = f + f;
  963.             final int end = r - f2;
  964.             for (int i = r - f; i > end; i--) {
  965.                 if (a[i - f] > a[i + f]) {
  966.                     final double u = a[i - f];
  967.                     a[i - f] = a[i + f];
  968.                     a[i + f] = u;
  969.                 }
  970.                 if (a[i - f2] > a[i]) {
  971.                     final double v = a[i - f2];
  972.                     a[i - f2] = a[i];
  973.                     a[i] = v;
  974.                 }
  975.                 if (a[i] > a[i + f]) {
  976.                     final double u = a[i];
  977.                     a[i] = a[i + f];
  978.                     a[i + f] = u;
  979.                 }
  980.             }
  981.             // 11th 12th-tile
  982.             fp = f / 3;
  983.             e = r - fp;
  984.             // Upper margin has 2(d+1) elements; d == e - (position in sample)
  985.             // Force k into the upper margin
  986.             p = e - ((r - k) >>> 1);
  987.         }
  988.         final int s = e - fp + 1;
  989.         for (int i = s; i <= e; i++) {
  990.             Sorting.sort3(a, i - fp, i, i + fp);
  991.         }
  992.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  993.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  994.     }

  995.     /**
  996.      * Expand a partition around a single pivot. Partitioning exchanges array
  997.      * elements such that all elements smaller than pivot are before it and all
  998.      * elements larger than pivot are after it. The central region is already
  999.      * partitioned.
  1000.      *
  1001.      * <pre>{@code
  1002.      * |l             |s   |p0 p1|   e|                r|
  1003.      * |    ???       | <P | ==P | >P |        ???      |
  1004.      * }</pre>
  1005.      *
  1006.      * <p>This requires that {@code start != end}. However it handles
  1007.      * {@code left == start} and/or {@code end == right}.
  1008.      *
  1009.      * @param a Data array.
  1010.      * @param left Lower bound (inclusive).
  1011.      * @param right Upper bound (inclusive).
  1012.      * @param start Start of the partition range (inclusive).
  1013.      * @param end End of the partitioned range (inclusive).
  1014.      * @param pivot0 Lower pivot location (inclusive).
  1015.      * @param pivot1 Upper pivot location (inclusive).
  1016.      * @param upper Upper bound (inclusive) of the pivot range [k1].
  1017.      * @return Lower bound (inclusive) of the pivot range [k0].
  1018.      */
  1019.     // package-private for testing
  1020.     static int expandPartition(double[] a, int left, int right, int start, int end,
  1021.         int pivot0, int pivot1, int[] upper) {
  1022.         // 3-way partition of the data using a pivot value into
  1023.         // less-than, equal or greater-than.
  1024.         // Based on Sedgewick's Bentley-McIroy partitioning: always swap i<->j then
  1025.         // check for equal to the pivot and move again.
  1026.         //
  1027.         // Move sentinels from start and end to left and right. Scan towards the
  1028.         // sentinels until >=,<=. Swap then move == to the pivot region.
  1029.         //           <-i                           j->
  1030.         // |l |        |            |p0  p1|       |             | r|
  1031.         // |>=|   ???  |     <      |  ==  |   >   |     ???     |<=|
  1032.         //
  1033.         // When either i or j reach the edge perform finishing loop.
  1034.         // Finish loop for a[j] <= v replaces j with p1+1, optionally moves value
  1035.         // to p0 for < and updates the pivot range p1 (and optionally p0):
  1036.         //                                             j->
  1037.         // |l                       |p0  p1|           |         | r|
  1038.         // |         <              |  ==  |       >   |   ???   |<=|

  1039.         final double v = a[pivot0];
  1040.         // Use start/end as sentinels (requires start != end)
  1041.         double vi = a[start];
  1042.         double vj = a[end];
  1043.         a[start] = a[left];
  1044.         a[end] = a[right];
  1045.         a[left] = vj;
  1046.         a[right] = vi;

  1047.         int i = start + 1;
  1048.         int j = end - 1;

  1049.         // Positioned for pre-in/decrement to write to pivot region
  1050.         int p0 = pivot0 == start ? i : pivot0;
  1051.         int p1 = pivot1 == end ? j : pivot1;

  1052.         while (true) {
  1053.             do {
  1054.                 --i;
  1055.             } while (a[i] < v);
  1056.             do {
  1057.                 ++j;
  1058.             } while (a[j] > v);
  1059.             vj = a[i];
  1060.             vi = a[j];
  1061.             a[i] = vi;
  1062.             a[j] = vj;
  1063.             // Move the equal values to pivot region
  1064.             if (vi == v) {
  1065.                 a[i] = a[--p0];
  1066.                 a[p0] = v;
  1067.             }
  1068.             if (vj == v) {
  1069.                 a[j] = a[++p1];
  1070.                 a[p1] = v;
  1071.             }
  1072.             // Termination check and finishing loops.
  1073.             // Note: This works even if pivot region is zero length (p1 == p0-1 due to
  1074.             // length 1 pivot region at either start/end) because we pre-inc/decrement
  1075.             // one side and post-inc/decrement the other side.
  1076.             if (i == left) {
  1077.                 while (j < right) {
  1078.                     do {
  1079.                         ++j;
  1080.                     } while (a[j] > v);
  1081.                     final double w = a[j];
  1082.                     // Move upper bound of pivot region
  1083.                     a[j] = a[++p1];
  1084.                     a[p1] = v;
  1085.                     // Move lower bound of pivot region
  1086.                     if (w != v) {
  1087.                         a[p0] = w;
  1088.                         p0++;
  1089.                     }
  1090.                 }
  1091.                 break;
  1092.             }
  1093.             if (j == right) {
  1094.                 while (i > left) {
  1095.                     do {
  1096.                         --i;
  1097.                     } while (a[i] < v);
  1098.                     final double w = a[i];
  1099.                     // Move lower bound of pivot region
  1100.                     a[i] = a[--p0];
  1101.                     a[p0] = v;
  1102.                     // Move upper bound of pivot region
  1103.                     if (w != v) {
  1104.                         a[p1] = w;
  1105.                         p1--;
  1106.                     }
  1107.                 }
  1108.                 break;
  1109.             }
  1110.         }

  1111.         upper[0] = p1;
  1112.         return p0;
  1113.     }

  1114.     /**
  1115.      * Partition the array such that indices {@code k} correspond to their
  1116.      * correctly sorted value in the equivalent fully sorted array.
  1117.      *
  1118.      * <p>For all indices {@code k} and any index {@code i}:
  1119.      *
  1120.      * <pre>{@code
  1121.      * data[i < k] <= data[k] <= data[k < i]
  1122.      * }</pre>
  1123.      *
  1124.      * <p>This function accepts a {@link UpdatingInterval} of indices {@code k} that define the
  1125.      * range of indices to partition. The {@link UpdatingInterval} can be narrowed or split as
  1126.      * partitioning divides the range.
  1127.      *
  1128.      * <p>Uses an introselect variant. The quickselect is a dual-pivot quicksort
  1129.      * partition method by Vladimir Yaroslavskiy; the fall-back on poor convergence of
  1130.      * the quickselect is a heapselect.
  1131.      *
  1132.      * <p>The {@code flags} contain the the current recursion count and the configured
  1133.      * length threshold for {@code r - l} to perform sort select. The count is in the upper
  1134.      * bits and the threshold is in the lower bits.
  1135.      *
  1136.      * @param a Values.
  1137.      * @param left Lower bound of data (inclusive, assumed to be strictly positive).
  1138.      * @param right Upper bound of data (inclusive, assumed to be strictly positive).
  1139.      * @param k Interval of indices to partition (ordered).
  1140.      * @param flags Control flags.
  1141.      */
  1142.     // package-private for testing
  1143.     static void dualPivotQuickSelect(double[] a, int left, int right, UpdatingInterval k, int flags) {
  1144.         // If partitioning splits the interval then recursion is used for the left-most side(s)
  1145.         // and the right-most side remains within this function. If partitioning does
  1146.         // not split the interval then it remains within this function.
  1147.         int l = left;
  1148.         int r = right;
  1149.         int f = flags;
  1150.         int ka = k.left();
  1151.         int kb = k.right();
  1152.         final int[] upper = {0, 0, 0};
  1153.         while (true) {
  1154.             // Select when ka and kb are close to the same end,
  1155.             // or the entire range is small
  1156.             // |l|-----|ka|--------|kb|------|r|
  1157.             final int n = r - l;
  1158.             if (Math.min(kb - l, r - ka) < DP_SORTSELECT_SIZE ||
  1159.                 n < (f & SORTSELECT_MASK)) {
  1160.                 sortSelect(a, l, r, ka, kb);
  1161.                 return;
  1162.             }
  1163.             if (kb - ka < DP_SORTSELECT_SIZE) {
  1164.                 // Switch to single-pivot mode with Floyd-Rivest sub-sampling
  1165.                 quickSelectAdaptive(a, l, r, ka, kb, upper, MODE_FR_SAMPLING);
  1166.                 return;
  1167.             }
  1168.             if (f < 0) {
  1169.                 // Excess recursion, switch to heap select
  1170.                 heapSelect(a, l, r, ka, kb);
  1171.                 return;
  1172.             }

  1173.             // Dual-pivot partitioning
  1174.             final int p0 = partition(a, l, r, upper);
  1175.             final int p1 = upper[0];

  1176.             // Recursion to max depth
  1177.             // Note: Here we possibly branch left, middle and right with multiple keys.
  1178.             // It is possible that the partition has split the keys
  1179.             // and the recursion proceeds with a reduced set in each region.
  1180.             //                   p0 p1               p2 p3
  1181.             // |l|--|ka|--k----k--|P|------k--|kb|----|P|----|r|
  1182.             //                 kb  |      ka
  1183.             f += RECURSION_INCREMENT;
  1184.             // Recurse left side if required
  1185.             if (ka < p0) {
  1186.                 if (kb <= p1) {
  1187.                     // Entirely on left side
  1188.                     r = p0 - 1;
  1189.                     if (r < kb) {
  1190.                         kb = k.updateRight(r);
  1191.                     }
  1192.                     continue;
  1193.                 }
  1194.                 dualPivotQuickSelect(a, l, p0 - 1, k.splitLeft(p0, p1), f);
  1195.                 // Here we must process middle and/or right
  1196.                 ka = k.left();
  1197.             } else if (kb <= p1) {
  1198.                 // No middle/right side
  1199.                 return;
  1200.             } else if (ka <= p1) {
  1201.                 // Advance lower bound
  1202.                 ka = k.updateLeft(p1 + 1);
  1203.             }
  1204.             // Recurse middle if required
  1205.             final int p2 = upper[1];
  1206.             final int p3 = upper[2];
  1207.             if (ka < p2) {
  1208.                 l = p1 + 1;
  1209.                 if (kb <= p3) {
  1210.                     // Entirely in middle
  1211.                     r = p2 - 1;
  1212.                     if (r < kb) {
  1213.                         kb = k.updateRight(r);
  1214.                     }
  1215.                     continue;
  1216.                 }
  1217.                 dualPivotQuickSelect(a, l, p2 - 1, k.splitLeft(p2, p3), f);
  1218.                 ka = k.left();
  1219.             } else if (kb <= p3) {
  1220.                 // No right side
  1221.                 return;
  1222.             } else if (ka <= p3) {
  1223.                 ka = k.updateLeft(p3 + 1);
  1224.             }
  1225.             // Continue right
  1226.             l = p3 + 1;
  1227.         }
  1228.     }

  1229.     /**
  1230.      * Partition an array slice around 2 pivots. Partitioning exchanges array elements
  1231.      * such that all elements smaller than pivot are before it and all elements larger
  1232.      * than pivot are after it.
  1233.      *
  1234.      * <p>This method returns 4 points describing the pivot ranges of equal values.
  1235.      *
  1236.      * <pre>{@code
  1237.      *         |k0  k1|                |k2  k3|
  1238.      * |   <P  | ==P1 |  <P1 && <P2    | ==P2 |   >P   |
  1239.      * }</pre>
  1240.      *
  1241.      * <ul>
  1242.      * <li>k0: lower pivot1 point
  1243.      * <li>k1: upper pivot1 point (inclusive)
  1244.      * <li>k2: lower pivot2 point
  1245.      * <li>k3: upper pivot2 point (inclusive)
  1246.      * </ul>
  1247.      *
  1248.      * <p>Bounds are set so {@code i < k0}, {@code i > k3} and {@code k1 < i < k2} are
  1249.      * unsorted. When the range {@code [k0, k3]} contains fully sorted elements the result
  1250.      * is set to {@code k1 = k3; k2 == k0}. This can occur if
  1251.      * {@code P1 == P2} or there are zero or one value between the pivots
  1252.      * {@code P1 < v < P2}. Any sort/partition of ranges [left, k0-1], [k1+1, k2-1] and
  1253.      * [k3+1, right] must check the length is {@code > 1}.
  1254.      *
  1255.      * @param a Data array.
  1256.      * @param left Lower bound (inclusive).
  1257.      * @param right Upper bound (inclusive).
  1258.      * @param bounds Points [k1, k2, k3].
  1259.      * @return Lower bound (inclusive) of the pivot range [k0].
  1260.      */
  1261.     private static int partition(double[] a, int left, int right, int[] bounds) {
  1262.         // Pick 2 pivots from 5 approximately uniform through the range.
  1263.         // Spacing is ~ 1/7 made using shifts. Other strategies are equal or much
  1264.         // worse. 1/7 = 5/35 ~ 1/8 + 1/64 : 0.1429 ~ 0.1406
  1265.         // Ensure the value is above zero to choose different points!
  1266.         final int n = right - left;
  1267.         final int step = 1 + (n >>> 3) + (n >>> 6);
  1268.         final int i3 = left + (n >>> 1);
  1269.         final int i2 = i3 - step;
  1270.         final int i1 = i2 - step;
  1271.         final int i4 = i3 + step;
  1272.         final int i5 = i4 + step;
  1273.         Sorting.sort5(a, i1, i2, i3, i4, i5);

  1274.         // Partition data using pivots P1 and P2 into less-than, greater-than or between.
  1275.         // Pivot values P1 & P2 are placed at the end. If P1 < P2, P2 acts as a sentinel.
  1276.         // k traverses the unknown region ??? and values moved if less-than or
  1277.         // greater-than:
  1278.         //
  1279.         // left        less              k       great         right
  1280.         // |P1|  <P1   |   P1 <= & <= P2 |    ???    |    >P2   |P2|
  1281.         //
  1282.         // <P1            (left, lt)
  1283.         // P1 <= & <= P2  [lt, k)
  1284.         // >P2            (gt, right)
  1285.         //
  1286.         // At the end pivots are swapped back to behind the less and great pointers.
  1287.         //
  1288.         // |  <P1        |P1|     P1<= & <= P2    |P2|      >P2    |

  1289.         // Swap ends to the pivot locations.
  1290.         final double v1 = a[i2];
  1291.         a[i2] = a[left];
  1292.         a[left] = v1;
  1293.         final double v2 = a[i4];
  1294.         a[i4] = a[right];
  1295.         a[right] = v2;

  1296.         // pointers
  1297.         int less = left;
  1298.         int great = right;

  1299.         // Fast-forward ascending / descending runs to reduce swaps.
  1300.         // Cannot overrun as end pivots (v1 <= v2) act as sentinels.
  1301.         do {
  1302.             ++less;
  1303.         } while (a[less] < v1);
  1304.         do {
  1305.             --great;
  1306.         } while (a[great] > v2);

  1307.         // a[less - 1] < P1 : a[great + 1] > P2
  1308.         // unvisited in [less, great]
  1309.         SORTING:
  1310.         for (int k = less - 1; ++k <= great;) {
  1311.             final double v = a[k];
  1312.             if (v < v1) {
  1313.                 // swap(a, k, less++)
  1314.                 a[k] = a[less];
  1315.                 a[less] = v;
  1316.                 less++;
  1317.             } else if (v > v2) {
  1318.                 // while k < great and a[great] > v2:
  1319.                 //   great--
  1320.                 while (a[great] > v2) {
  1321.                     if (great-- == k) {
  1322.                         // Done
  1323.                         break SORTING;
  1324.                     }
  1325.                 }
  1326.                 // swap(a, k, great--)
  1327.                 // if a[k] < v1:
  1328.                 //   swap(a, k, less++)
  1329.                 final double w = a[great];
  1330.                 a[great] = v;
  1331.                 great--;
  1332.                 // delay a[k] = w
  1333.                 if (w < v1) {
  1334.                     a[k] = a[less];
  1335.                     a[less] = w;
  1336.                     less++;
  1337.                 } else {
  1338.                     a[k] = w;
  1339.                 }
  1340.             }
  1341.         }

  1342.         // Change to inclusive ends : a[less] < P1 : a[great] > P2
  1343.         less--;
  1344.         great++;
  1345.         // Move the pivots to correct locations
  1346.         a[left] = a[less];
  1347.         a[less] = v1;
  1348.         a[right] = a[great];
  1349.         a[great] = v2;

  1350.         // Record the pivot locations
  1351.         final int lower = less;
  1352.         bounds[2] = great;

  1353.         // equal elements
  1354.         // Original paper: If middle partition is bigger than a threshold
  1355.         // then check for equal elements.

  1356.         // Note: This is extra work. When performing partitioning the region of interest
  1357.         // may be entirely above or below the central region and this can be skipped.

  1358.         // Here we look for equal elements if the centre is more than 5/8 the length.
  1359.         // 5/8 = 1/2 + 1/8. Pivots must be different.
  1360.         if ((great - less) > (n >>> 1) + (n >>> 3) && v1 != v2) {

  1361.             // Fast-forward to reduce swaps. Changes inclusive ends to exclusive ends.
  1362.             // Since v1 != v2 these act as sentinels to prevent overrun.
  1363.             do {
  1364.                 ++less;
  1365.             } while (a[less] == v1);
  1366.             do {
  1367.                 --great;
  1368.             } while (a[great] == v2);

  1369.             // This copies the logic in the sorting loop using == comparisons
  1370.             EQUAL:
  1371.             for (int k = less - 1; ++k <= great;) {
  1372.                 final double v = a[k];
  1373.                 if (v == v1) {
  1374.                     a[k] = a[less];
  1375.                     a[less] = v;
  1376.                     less++;
  1377.                 } else if (v == v2) {
  1378.                     while (a[great] == v2) {
  1379.                         if (great-- == k) {
  1380.                             // Done
  1381.                             break EQUAL;
  1382.                         }
  1383.                     }
  1384.                     final double w = a[great];
  1385.                     a[great] = v;
  1386.                     great--;
  1387.                     if (w == v1) {
  1388.                         a[k] = a[less];
  1389.                         a[less] = w;
  1390.                         less++;
  1391.                     } else {
  1392.                         a[k] = w;
  1393.                     }
  1394.                 }
  1395.             }

  1396.             // Change to inclusive ends
  1397.             less--;
  1398.             great++;
  1399.         }

  1400.         // Between pivots in (less, great)
  1401.         if (v1 != v2 && less < great - 1) {
  1402.             // Record the pivot end points
  1403.             bounds[0] = less;
  1404.             bounds[1] = great;
  1405.         } else {
  1406.             // No unsorted internal region (set k1 = k3; k2 = k0)
  1407.             bounds[0] = bounds[2];
  1408.             bounds[1] = lower;
  1409.         }

  1410.         return lower;
  1411.     }

  1412.     /**
  1413.      * Partition the elements between {@code ka} and {@code kb} using a heap select
  1414.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  1415.      *
  1416.      * @param a Data array to use to find out the K<sup>th</sup> value.
  1417.      * @param left Lower bound (inclusive).
  1418.      * @param right Upper bound (inclusive).
  1419.      * @param ka Lower index to select.
  1420.      * @param kb Upper index to select.
  1421.      */
  1422.     static void heapSelect(int[] a, int left, int right, int ka, int kb) {
  1423.         if (right <= left) {
  1424.             return;
  1425.         }
  1426.         // Use the smallest heap
  1427.         if (kb - left < right - ka) {
  1428.             heapSelectLeft(a, left, right, ka, kb);
  1429.         } else {
  1430.             heapSelectRight(a, left, right, ka, kb);
  1431.         }
  1432.     }

  1433.     /**
  1434.      * Partition the elements between {@code ka} and {@code kb} using a heap select
  1435.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  1436.      *
  1437.      * <p>For best performance this should be called with {@code k} in the lower
  1438.      * half of the range.
  1439.      *
  1440.      * @param a Data array to use to find out the K<sup>th</sup> value.
  1441.      * @param left Lower bound (inclusive).
  1442.      * @param right Upper bound (inclusive).
  1443.      * @param ka Lower index to select.
  1444.      * @param kb Upper index to select.
  1445.      */
  1446.     static void heapSelectLeft(int[] a, int left, int right, int ka, int kb) {
  1447.         // Create a max heap in-place in [left, k], rooted at a[left] = max
  1448.         // |l|-max-heap-|k|--------------|
  1449.         // Build the heap using Floyd's heap-construction algorithm for heap size n.
  1450.         // Start at parent of the last element in the heap (k),
  1451.         // i.e. start = parent(n-1) : parent(c) = floor((c - 1) / 2) : c = k - left
  1452.         int end = kb + 1;
  1453.         for (int p = left + ((kb - left - 1) >> 1); p >= left; p--) {
  1454.             maxHeapSiftDown(a, a[p], p, left, end);
  1455.         }
  1456.         // Scan the remaining data and insert
  1457.         // Mitigate worst case performance on descending data by backward sweep
  1458.         int max = a[left];
  1459.         for (int i = right + 1; --i > kb;) {
  1460.             final int v = a[i];
  1461.             if (v < max) {
  1462.                 a[i] = max;
  1463.                 maxHeapSiftDown(a, v, left, left, end);
  1464.                 max = a[left];
  1465.             }
  1466.         }
  1467.         // Partition [ka, kb]
  1468.         // |l|-max-heap-|k|--------------|
  1469.         //  |  <-swap->  |   then sift down reduced size heap
  1470.         // Avoid sifting heap of size 1
  1471.         final int last = Math.max(left, ka - 1);
  1472.         while (--end > last) {
  1473.             maxHeapSiftDown(a, a[end], left, left, end);
  1474.             a[end] = max;
  1475.             max = a[left];
  1476.         }
  1477.     }

  1478.     /**
  1479.      * Sift the element down the max heap.
  1480.      *
  1481.      * <p>Assumes {@code root <= p < end}, i.e. the max heap is above root.
  1482.      *
  1483.      * @param a Heap data.
  1484.      * @param v Value to sift.
  1485.      * @param p Start position.
  1486.      * @param root Root of the heap.
  1487.      * @param end End of the heap (exclusive).
  1488.      */
  1489.     private static void maxHeapSiftDown(int[] a, int v, int p, int root, int end) {
  1490.         // child2 = root + 2 * (parent - root) + 2
  1491.         //        = 2 * parent - root + 2
  1492.         while (true) {
  1493.             // Right child
  1494.             int c = (p << 1) - root + 2;
  1495.             if (c > end) {
  1496.                 // No left child
  1497.                 break;
  1498.             }
  1499.             // Use the left child if right doesn't exist, or it is greater
  1500.             if (c == end || a[c] < a[c - 1]) {
  1501.                 --c;
  1502.             }
  1503.             if (v >= a[c]) {
  1504.                 // Parent greater than largest child - done
  1505.                 break;
  1506.             }
  1507.             // Swap and descend
  1508.             a[p] = a[c];
  1509.             p = c;
  1510.         }
  1511.         a[p] = v;
  1512.     }

  1513.     /**
  1514.      * Partition the elements between {@code ka} and {@code kb} using a heap select
  1515.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  1516.      *
  1517.      * <p>For best performance this should be called with {@code k} in the upper
  1518.      * half of the range.
  1519.      *
  1520.      * @param a Data array to use to find out the K<sup>th</sup> value.
  1521.      * @param left Lower bound (inclusive).
  1522.      * @param right Upper bound (inclusive).
  1523.      * @param ka Lower index to select.
  1524.      * @param kb Upper index to select.
  1525.      */
  1526.     static void heapSelectRight(int[] a, int left, int right, int ka, int kb) {
  1527.         // Create a min heap in-place in [k, right], rooted at a[right] = min
  1528.         // |--------------|k|-min-heap-|r|
  1529.         // Build the heap using Floyd's heap-construction algorithm for heap size n.
  1530.         // Start at parent of the last element in the heap (k),
  1531.         // i.e. start = parent(n-1) : parent(c) = floor((c - 1) / 2) : c = right - k
  1532.         int end = ka - 1;
  1533.         for (int p = right - ((right - ka - 1) >> 1); p <= right; p++) {
  1534.             minHeapSiftDown(a, a[p], p, right, end);
  1535.         }
  1536.         // Scan the remaining data and insert
  1537.         // Mitigate worst case performance on descending data by backward sweep
  1538.         int min = a[right];
  1539.         for (int i = left - 1; ++i < ka;) {
  1540.             final int v = a[i];
  1541.             if (v > min) {
  1542.                 a[i] = min;
  1543.                 minHeapSiftDown(a, v, right, right, end);
  1544.                 min = a[right];
  1545.             }
  1546.         }
  1547.         // Partition [ka, kb]
  1548.         // |--------------|k|-min-heap-|r|
  1549.         //                 |  <-swap->  |   then sift down reduced size heap
  1550.         // Avoid sifting heap of size 1
  1551.         final int last = Math.min(right, kb + 1);
  1552.         while (++end < last) {
  1553.             minHeapSiftDown(a, a[end], right, right, end);
  1554.             a[end] = min;
  1555.             min = a[right];
  1556.         }
  1557.     }

  1558.     /**
  1559.      * Sift the element down the min heap.
  1560.      *
  1561.      * <p>Assumes {@code root >= p > end}, i.e. the max heap is below root.
  1562.      *
  1563.      * @param a Heap data.
  1564.      * @param v Value to sift.
  1565.      * @param p Start position.
  1566.      * @param root Root of the heap.
  1567.      * @param end End of the heap (exclusive).
  1568.      */
  1569.     private static void minHeapSiftDown(int[] a, int v, int p, int root, int end) {
  1570.         // child2 = root - 2 * (root - parent) - 2
  1571.         //        = 2 * parent - root - 2
  1572.         while (true) {
  1573.             // Right child
  1574.             int c = (p << 1) - root - 2;
  1575.             if (c < end) {
  1576.                 // No left child
  1577.                 break;
  1578.             }
  1579.             // Use the left child if right doesn't exist, or it is less
  1580.             if (c == end || a[c] > a[c + 1]) {
  1581.                 ++c;
  1582.             }
  1583.             if (v <= a[c]) {
  1584.                 // Parent less than smallest child - done
  1585.                 break;
  1586.             }
  1587.             // Swap and descend
  1588.             a[p] = a[c];
  1589.             p = c;
  1590.         }
  1591.         a[p] = v;
  1592.     }

  1593.     /**
  1594.      * Partition the elements between {@code ka} and {@code kb} using a sort select
  1595.      * algorithm. It is assumed {@code left <= ka <= kb <= right}.
  1596.      *
  1597.      * @param a Data array to use to find out the K<sup>th</sup> value.
  1598.      * @param left Lower bound (inclusive).
  1599.      * @param right Upper bound (inclusive).
  1600.      * @param ka Lower index to select.
  1601.      * @param kb Upper index to select.
  1602.      */
  1603.     static void sortSelect(int[] a, int left, int right, int ka, int kb) {
  1604.         // Combine the test for right <= left with
  1605.         // avoiding the overhead of sort select on tiny data.
  1606.         if (right - left <= MIN_SORTSELECT_SIZE) {
  1607.             Sorting.sort(a, left, right);
  1608.             return;
  1609.         }
  1610.         // Sort the smallest side
  1611.         if (kb - left < right - ka) {
  1612.             sortSelectLeft(a, left, right, kb);
  1613.         } else {
  1614.             sortSelectRight(a, left, right, ka);
  1615.         }
  1616.     }

  1617.     /**
  1618.      * Partition the minimum {@code n} elements below {@code k} where
  1619.      * {@code n = k - left + 1}. Uses an insertion sort algorithm.
  1620.      *
  1621.      * <p>Works with any {@code k} in the range {@code left <= k <= right}
  1622.      * and performs a full sort of the range below {@code k}.
  1623.      *
  1624.      * <p>For best performance this should be called with
  1625.      * {@code k - left < right - k}, i.e.
  1626.      * to partition a value in the lower half of the range.
  1627.      *
  1628.      * @param a Data array to use to find out the K<sup>th</sup> value.
  1629.      * @param left Lower bound (inclusive).
  1630.      * @param right Upper bound (inclusive).
  1631.      * @param k Index to select.
  1632.      */
  1633.     static void sortSelectLeft(int[] a, int left, int right, int k) {
  1634.         // Sort
  1635.         for (int i = left; ++i <= k;) {
  1636.             final int v = a[i];
  1637.             // Move preceding higher elements above (if required)
  1638.             if (v < a[i - 1]) {
  1639.                 int j = i;
  1640.                 while (--j >= left && v < a[j]) {
  1641.                     a[j + 1] = a[j];
  1642.                 }
  1643.                 a[j + 1] = v;
  1644.             }
  1645.         }
  1646.         // Scan the remaining data and insert
  1647.         // Mitigate worst case performance on descending data by backward sweep
  1648.         int m = a[k];
  1649.         for (int i = right + 1; --i > k;) {
  1650.             final int v = a[i];
  1651.             if (v < m) {
  1652.                 a[i] = m;
  1653.                 int j = k;
  1654.                 while (--j >= left && v < a[j]) {
  1655.                     a[j + 1] = a[j];
  1656.                 }
  1657.                 a[j + 1] = v;
  1658.                 m = a[k];
  1659.             }
  1660.         }
  1661.     }

  1662.     /**
  1663.      * Partition the maximum {@code n} elements above {@code k} where
  1664.      * {@code n = right - k + 1}. Uses an insertion sort algorithm.
  1665.      *
  1666.      * <p>Works with any {@code k} in the range {@code left <= k <= right}
  1667.      * and can be used to perform a full sort of the range above {@code k}.
  1668.      *
  1669.      * <p>For best performance this should be called with
  1670.      * {@code k - left > right - k}, i.e.
  1671.      * to partition a value in the upper half of the range.
  1672.      *
  1673.      * @param a Data array to use to find out the K<sup>th</sup> value.
  1674.      * @param left Lower bound (inclusive).
  1675.      * @param right Upper bound (inclusive).
  1676.      * @param k Index to select.
  1677.      */
  1678.     static void sortSelectRight(int[] a, int left, int right, int k) {
  1679.         // Sort
  1680.         for (int i = right; --i >= k;) {
  1681.             final int v = a[i];
  1682.             // Move succeeding lower elements below (if required)
  1683.             if (v > a[i + 1]) {
  1684.                 int j = i;
  1685.                 while (++j <= right && v > a[j]) {
  1686.                     a[j - 1] = a[j];
  1687.                 }
  1688.                 a[j - 1] = v;
  1689.             }
  1690.         }
  1691.         // Scan the remaining data and insert
  1692.         // Mitigate worst case performance on descending data by backward sweep
  1693.         int m = a[k];
  1694.         for (int i = left - 1; ++i < k;) {
  1695.             final int v = a[i];
  1696.             if (v > m) {
  1697.                 a[i] = m;
  1698.                 int j = k;
  1699.                 while (++j <= right && v > a[j]) {
  1700.                     a[j - 1] = a[j];
  1701.                 }
  1702.                 a[j - 1] = v;
  1703.                 m = a[k];
  1704.             }
  1705.         }
  1706.     }

  1707.     /**
  1708.      * Partition the array such that index {@code k} corresponds to its correctly
  1709.      * sorted value in the equivalent fully sorted array.
  1710.      *
  1711.      * <p>Assumes {@code k} is a valid index into [left, right].
  1712.      *
  1713.      * @param a Values.
  1714.      * @param left Lower bound of data (inclusive).
  1715.      * @param right Upper bound of data (inclusive).
  1716.      * @param k Index.
  1717.      */
  1718.     static void select(int[] a, int left, int right, int k) {
  1719.         quickSelectAdaptive(a, left, right, k, k, new int[1], MODE_FR_SAMPLING);
  1720.     }

  1721.     /**
  1722.      * Partition the array such that indices {@code k} correspond to their correctly
  1723.      * sorted value in the equivalent fully sorted array.
  1724.      *
  1725.      * <p>The count of the number of used indices is returned. If the keys are sorted in-place,
  1726.      * the count is returned as a negative.
  1727.      *
  1728.      * @param a Values.
  1729.      * @param left Lower bound of data (inclusive).
  1730.      * @param right Upper bound of data (inclusive).
  1731.      * @param k Indices (may be destructively modified).
  1732.      * @param n Count of indices.
  1733.      * @throws IndexOutOfBoundsException if any index {@code k} is not within the
  1734.      * sub-range {@code [left, right]}
  1735.      */
  1736.     static void select(int[] a, int left, int right, int[] k, int n) {
  1737.         if (n == 1) {
  1738.             quickSelectAdaptive(a, left, right, k[0], k[0], new int[1], MODE_FR_SAMPLING);
  1739.             return;
  1740.         }

  1741.         // Interval creation validates the indices are in [left, right]
  1742.         final UpdatingInterval keys = IndexSupport.createUpdatingInterval(left, right, k, n);

  1743.         // Note: If the keys are not separated then they are effectively a single key.
  1744.         // Any split of keys separated by the sort select size
  1745.         // will be finished on the next iteration.
  1746.         final int k1 = keys.left();
  1747.         final int kn = keys.right();
  1748.         if (kn - k1 < DP_SORTSELECT_SIZE) {
  1749.             quickSelectAdaptive(a, left, right, k1, kn, new int[1], MODE_FR_SAMPLING);
  1750.         } else {
  1751.             // Dual-pivot mode with small range sort length configured using index density
  1752.             dualPivotQuickSelect(a, left, right, keys, dualPivotFlags(left, right, k1, kn));
  1753.         }
  1754.     }

  1755.     /**
  1756.      * Partition the array such that indices {@code k} correspond to their
  1757.      * correctly sorted value in the equivalent fully sorted array.
  1758.      *
  1759.      * <p>For all indices {@code [ka, kb]} and any index {@code i}:
  1760.      *
  1761.      * <pre>{@code
  1762.      * data[i < ka] <= data[ka] <= data[kb] <= data[kb < i]
  1763.      * }</pre>
  1764.      *
  1765.      * <p>This function accepts indices {@code [ka, kb]} that define the
  1766.      * range of indices to partition. It is expected that the range is small.
  1767.      *
  1768.      * <p>The {@code flags} are used to control the sampling mode and adaption of
  1769.      * the index within the sample.
  1770.      *
  1771.      * <p>Returns the bounds containing {@code [ka, kb]}. These may be lower/higher
  1772.      * than the keys if equal values are present in the data.
  1773.      *
  1774.      * @param a Values.
  1775.      * @param left Lower bound of data (inclusive, assumed to be strictly positive).
  1776.      * @param right Upper bound of data (inclusive, assumed to be strictly positive).
  1777.      * @param ka First key of interest.
  1778.      * @param kb Last key of interest.
  1779.      * @param bounds Upper bound of the range containing {@code [ka, kb]} (inclusive).
  1780.      * @param flags Adaption flags.
  1781.      * @return Lower bound of the range containing {@code [ka, kb]} (inclusive).
  1782.      */
  1783.     static int quickSelectAdaptive(int[] a, int left, int right, int ka, int kb,
  1784.             int[] bounds, int flags) {
  1785.         int l = left;
  1786.         int r = right;
  1787.         int m = flags;
  1788.         while (true) {
  1789.             // Select when ka and kb are close to the same end
  1790.             // |l|-----|ka|kkkkkkkk|kb|------|r|
  1791.             if (Math.min(kb - l, r - ka) < LINEAR_SORTSELECT_SIZE) {
  1792.                 sortSelect(a, l, r, ka, kb);
  1793.                 bounds[0] = kb;
  1794.                 return ka;
  1795.             }

  1796.             // Only target ka; kb is assumed to be close
  1797.             int p0;
  1798.             final int n = r - l;
  1799.             // f in [0, 1]
  1800.             final double f = (double) (ka - l) / n;
  1801.             // Record the larger margin (start at 1/4) to create the estimated size.
  1802.             // step        L     R
  1803.             // far left    1/12  1/3   (use 1/4 + 1/32 + 1/64 ~ 0.328)
  1804.             // left        1/6   1/4
  1805.             // middle      2/9   2/9   (use 1/4 - 1/32 ~ 0.219)
  1806.             int margin = n >> 2;
  1807.             if (m < MODE_SAMPLING && r - l > FR_SAMPLING_SIZE) {
  1808.                 // Floyd-Rivest sample step uses the same margins
  1809.                 p0 = sampleStep(a, l, r, ka, bounds);
  1810.                 if (f <= STEP_FAR_LEFT || f >= STEP_FAR_RIGHT) {
  1811.                     margin += (n >> 5) + (n >> 6);
  1812.                 } else if (f > STEP_LEFT && f < STEP_RIGHT) {
  1813.                     margin -= n >> 5;
  1814.                 }
  1815.             } else if (f <= STEP_LEFT) {
  1816.                 if (f <= STEP_FAR_LEFT) {
  1817.                     margin += (n >> 5) + (n >> 6);
  1818.                     p0 = repeatedStepFarLeft(a, l, r, ka, bounds, m);
  1819.                 } else {
  1820.                     p0 = repeatedStepLeft(a, l, r, ka, bounds, m);
  1821.                 }
  1822.             } else if (f >= STEP_RIGHT) {
  1823.                 if (f >= STEP_FAR_RIGHT) {
  1824.                     margin += (n >> 5) + (n >> 6);
  1825.                     p0 = repeatedStepFarRight(a, l, r, ka, bounds, m);
  1826.                 } else {
  1827.                     p0 = repeatedStepRight(a, l, r, ka, bounds, m);
  1828.                 }
  1829.             } else {
  1830.                 margin -= n >> 5;
  1831.                 p0 = repeatedStep(a, l, r, ka, bounds, m);
  1832.             }

  1833.             // Note: Here we expect [ka, kb] to be small and splitting is unlikely.
  1834.             //                   p0 p1
  1835.             // |l|--|ka|kkkk|kb|--|P|-------------------|r|
  1836.             // |l|----------------|P|--|ka|kkk|kb|------|r|
  1837.             // |l|-----------|ka|k|P|k|kb|--------------|r|
  1838.             final int p1 = bounds[0];
  1839.             if (kb < p0) {
  1840.                 // Entirely on left side
  1841.                 r = p0 - 1;
  1842.             } else if (ka > p1) {
  1843.                 // Entirely on right side
  1844.                 l = p1 + 1;
  1845.             } else {
  1846.                 // Pivot splits [ka, kb]. Expect ends to be close to the pivot and finish.
  1847.                 // Here we set the bounds for use after median-of-medians pivot selection.
  1848.                 // In the event there are many equal values this allows collecting those
  1849.                 // known to be equal together when moving around the medians sample.
  1850.                 if (kb > p1) {
  1851.                     sortSelectLeft(a, p1 + 1, r, kb);
  1852.                     bounds[0] = kb;
  1853.                 }
  1854.                 if (ka < p0) {
  1855.                     sortSelectRight(a, l, p0 - 1, ka);
  1856.                     p0 = ka;
  1857.                 }
  1858.                 return p0;
  1859.             }
  1860.             // Update mode based on target partition size
  1861.             if (r - l > n - margin) {
  1862.                 m++;
  1863.             }
  1864.         }
  1865.     }

  1866.     /**
  1867.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  1868.      * that all elements smaller than pivot are before it and all elements larger than
  1869.      * pivot are after it.
  1870.      *
  1871.      * <p>Partitions a Floyd-Rivest sample around a pivot offset so that the input {@code k} will
  1872.      * fall in the smaller partition when the entire range is partitioned.
  1873.      *
  1874.      * <p>Assumes the range {@code r - l} is large.
  1875.      *
  1876.      * @param a Data array.
  1877.      * @param l Lower bound (inclusive).
  1878.      * @param r Upper bound (inclusive).
  1879.      * @param k Target index.
  1880.      * @param upper Upper bound (inclusive) of the pivot range.
  1881.      * @return Lower bound (inclusive) of the pivot range.
  1882.      */
  1883.     private static int sampleStep(int[] a, int l, int r, int k, int[] upper) {
  1884.         // Floyd-Rivest: use SELECT recursively on a sample of size S to get an estimate
  1885.         // for the (k-l+1)-th smallest element into a[k], biased slightly so that the
  1886.         // (k-l+1)-th element is expected to lie in the smaller set after partitioning.
  1887.         final int n = r - l + 1;
  1888.         final int ith = k - l + 1;
  1889.         final double z = Math.log(n);
  1890.         // sample size = 0.5 * n^(2/3)
  1891.         final double s = 0.5 * Math.exp(0.6666666666666666 * z);
  1892.         final double sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * Integer.signum(ith - (n >> 1));
  1893.         final int ll = Math.max(l, (int) (k - ith * s / n + sd));
  1894.         final int rr = Math.min(r, (int) (k + (n - ith) * s / n + sd));
  1895.         // Sample recursion restarts from [ll, rr]
  1896.         final int p = quickSelectAdaptive(a, ll, rr, k, k, upper, MODE_FR_SAMPLING);
  1897.         return expandPartition(a, l, r, ll, rr, p, upper[0], upper);
  1898.     }

  1899.     /**
  1900.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  1901.      * that all elements smaller than pivot are before it and all elements larger than
  1902.      * pivot are after it.
  1903.      *
  1904.      * <p>Assumes the range {@code r - l >= 8}; the caller is responsible for selection on a smaller
  1905.      * range. If using a 12th-tile for sampling then assumes {@code r - l >= 11}.
  1906.      *
  1907.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  1908.      * with the median of 3 then median of 3; the final sample is placed in the
  1909.      * 5th 9th-tile; the pivot chosen from the sample is adaptive using the input {@code k}.
  1910.      *
  1911.      * <p>Given a pivot in the middle of the sample this has margins of 2/9 and 2/9.
  1912.      *
  1913.      * @param a Data array.
  1914.      * @param l Lower bound (inclusive).
  1915.      * @param r Upper bound (inclusive).
  1916.      * @param k Target index.
  1917.      * @param upper Upper bound (inclusive) of the pivot range.
  1918.      * @param flags Control flags.
  1919.      * @return Lower bound (inclusive) of the pivot range.
  1920.      */
  1921.     private static int repeatedStep(int[] a, int l, int r, int k, int[] upper, int flags) {
  1922.         // Adapted from Alexandrescu (2016), algorithm 8.
  1923.         final int fp;
  1924.         final int s;
  1925.         int p;
  1926.         if (flags <= MODE_SAMPLING) {
  1927.             // Median into a 12th-tile
  1928.             fp = (r - l + 1) / 12;
  1929.             // Position the sample around the target k
  1930.             s = k - mapDistance(k - l, l, r, fp);
  1931.             p = k;
  1932.         } else {
  1933.             // i in tertile [3f':6f')
  1934.             fp = (r - l + 1) / 9;
  1935.             final int f3 = 3 * fp;
  1936.             final int end = l + (f3 << 1);
  1937.             for (int i = l + f3; i < end; i++) {
  1938.                 Sorting.sort3(a, i - f3, i, i + f3);
  1939.             }
  1940.             // 5th 9th-tile: [4f':5f')
  1941.             s = l + (fp << 2);
  1942.             // No adaption uses the middle to enforce strict margins
  1943.             p = s + (flags == MODE_ADAPTION ? mapDistance(k - l, l, r, fp) : (fp >>> 1));
  1944.         }
  1945.         final int e = s + fp - 1;
  1946.         for (int i = s; i <= e; i++) {
  1947.             Sorting.sort3(a, i - fp, i, i + fp);
  1948.         }
  1949.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  1950.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  1951.     }

  1952.     /**
  1953.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  1954.      * that all elements smaller than pivot are before it and all elements larger than
  1955.      * pivot are after it.
  1956.      *
  1957.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  1958.      * range.
  1959.      *
  1960.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  1961.      * with the lower median of 4 then either median of 3 with the final sample placed in the
  1962.      * 5th 12th-tile, or min of 3 with the final sample in the 4th 12th-tile;
  1963.      * the pivot chosen from the sample is adaptive using the input {@code k}.
  1964.      *
  1965.      * <p>Given a pivot in the middle of the sample this has margins of 1/6 and 1/4.
  1966.      *
  1967.      * @param a Data array.
  1968.      * @param l Lower bound (inclusive).
  1969.      * @param r Upper bound (inclusive).
  1970.      * @param k Target index.
  1971.      * @param upper Upper bound (inclusive) of the pivot range.
  1972.      * @param flags Control flags.
  1973.      * @return Lower bound (inclusive) of the pivot range.
  1974.      */
  1975.     private static int repeatedStepLeft(int[] a, int l, int r, int k, int[] upper, int flags) {
  1976.         // Adapted from Alexandrescu (2016), algorithm 9.
  1977.         final int fp;
  1978.         final int s;
  1979.         int p;
  1980.         if (flags <= MODE_SAMPLING) {
  1981.             // Median into a 12th-tile
  1982.             fp = (r - l + 1) / 12;
  1983.             // Position the sample around the target k
  1984.             // Avoid bounds error due to rounding as (k-l)/(r-l) -> 1/12
  1985.             s = Math.max(k - mapDistance(k - l, l, r, fp), l + fp);
  1986.             p = k;
  1987.         } else {
  1988.             // i in 2nd quartile
  1989.             final int f = (r - l + 1) >> 2;
  1990.             final int f2 = f + f;
  1991.             final int end = l + f2;
  1992.             for (int i = l + f; i < end; i++) {
  1993.                 Sorting.lowerMedian4(a, i - f, i, i + f, i + f2);
  1994.             }
  1995.             // i in 5th 12th-tile
  1996.             fp = f / 3;
  1997.             s = l + f + fp;
  1998.             // No adaption uses the middle to enforce strict margins
  1999.             p = s + (flags == MODE_ADAPTION ? mapDistance(k - l, l, r, fp) : (fp >>> 1));
  2000.         }
  2001.         final int e = s + fp - 1;
  2002.         for (int i = s; i <= e; i++) {
  2003.             Sorting.sort3(a, i - fp, i, i + fp);
  2004.         }
  2005.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  2006.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  2007.     }

  2008.     /**
  2009.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  2010.      * that all elements smaller than pivot are before it and all elements larger than
  2011.      * pivot are after it.
  2012.      *
  2013.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  2014.      * range.
  2015.      *
  2016.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  2017.      * with the upper median of 4 then either median of 3 with the final sample placed in the
  2018.      * 8th 12th-tile, or max of 3 with the final sample in the 9th 12th-tile;
  2019.      * the pivot chosen from the sample is adaptive using the input {@code k}.
  2020.      *
  2021.      * <p>Given a pivot in the middle of the sample this has margins of 1/4 and 1/6.
  2022.      *
  2023.      * @param a Data array.
  2024.      * @param l Lower bound (inclusive).
  2025.      * @param r Upper bound (inclusive).
  2026.      * @param k Target index.
  2027.      * @param upper Upper bound (inclusive) of the pivot range.
  2028.      * @param flags Control flags.
  2029.      * @return Lower bound (inclusive) of the pivot range.
  2030.      */
  2031.     private static int repeatedStepRight(int[] a, int l, int r, int k, int[] upper, int flags) {
  2032.         // Mirror image repeatedStepLeft using upper median into 3rd quartile
  2033.         final int fp;
  2034.         final int e;
  2035.         int p;
  2036.         if (flags <= MODE_SAMPLING) {
  2037.             // Median into a 12th-tile
  2038.             fp = (r - l + 1) / 12;
  2039.             // Position the sample around the target k
  2040.             // Avoid bounds error due to rounding as (r-k)/(r-l) -> 11/12
  2041.             e = Math.min(k + mapDistance(r - k, l, r, fp), r - fp);
  2042.             p = k;
  2043.         } else {
  2044.             // i in 3rd quartile
  2045.             final int f = (r - l + 1) >> 2;
  2046.             final int f2 = f + f;
  2047.             final int end = r - f2;
  2048.             for (int i = r - f; i > end; i--) {
  2049.                 Sorting.upperMedian4(a, i - f2, i - f, i, i + f);
  2050.             }
  2051.             // i in 8th 12th-tile
  2052.             fp = f / 3;
  2053.             e = r - f - fp;
  2054.             // No adaption uses the middle to enforce strict margins
  2055.             p = e - (flags == MODE_ADAPTION ? mapDistance(r - k, l, r, fp) : (fp >>> 1));
  2056.         }
  2057.         final int s = e - fp + 1;
  2058.         for (int i = s; i <= e; i++) {
  2059.             Sorting.sort3(a, i - fp, i, i + fp);
  2060.         }
  2061.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  2062.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  2063.     }

  2064.     /**
  2065.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  2066.      * that all elements smaller than pivot are before it and all elements larger than
  2067.      * pivot are after it.
  2068.      *
  2069.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  2070.      * range.
  2071.      *
  2072.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  2073.      * with the minimum of 4 then median of 3; the final sample is placed in the
  2074.      * 2nd 12th-tile; the pivot chosen from the sample is adaptive using the input {@code k}.
  2075.      *
  2076.      * <p>Given a pivot in the middle of the sample this has margins of 1/12 and 1/3.
  2077.      *
  2078.      * @param a Data array.
  2079.      * @param l Lower bound (inclusive).
  2080.      * @param r Upper bound (inclusive).
  2081.      * @param k Target index.
  2082.      * @param upper Upper bound (inclusive) of the pivot range.
  2083.      * @param flags Control flags.
  2084.      * @return Lower bound (inclusive) of the pivot range.
  2085.      */
  2086.     private static int repeatedStepFarLeft(int[] a, int l, int r, int k, int[] upper, int flags) {
  2087.         // Far step has been changed from the Alexandrescu (2016) step of lower-median-of-4, min-of-3
  2088.         // into the 4th 12th-tile to a min-of-4, median-of-3 into the 2nd 12th-tile.
  2089.         // The differences are:
  2090.         // - The upper margin when not sampling is 8/24 vs. 9/24; the lower margin remains at 1/12.
  2091.         // - The position of the sample is closer to the expected location of k < |A| / 12.
  2092.         // - Sampling mode uses a median-of-3 with adaptive k, matching the other step methods.
  2093.         //   A min-of-3 sample can create a pivot too small if used with adaption of k leaving
  2094.         //   k in the larger parition and a wasted iteration.
  2095.         // - Adaption is adjusted to force use of the lower margin when not sampling.
  2096.         final int fp;
  2097.         final int s;
  2098.         int p;
  2099.         if (flags <= MODE_SAMPLING) {
  2100.             // 2nd 12th-tile
  2101.             fp = (r - l + 1) / 12;
  2102.             s = l + fp;
  2103.             // Use adaption
  2104.             p = s + mapDistance(k - l, l, r, fp);
  2105.         } else {
  2106.             // i in 2nd quartile; min into i-f (1st quartile)
  2107.             final int f = (r - l + 1) >> 2;
  2108.             final int f2 = f + f;
  2109.             final int end = l + f2;
  2110.             for (int i = l + f; i < end; i++) {
  2111.                 if (a[i + f] < a[i - f]) {
  2112.                     final int u = a[i + f];
  2113.                     a[i + f] = a[i - f];
  2114.                     a[i - f] = u;
  2115.                 }
  2116.                 if (a[i + f2] < a[i]) {
  2117.                     final int v = a[i + f2];
  2118.                     a[i + f2] = a[i];
  2119.                     a[i] = v;
  2120.                 }
  2121.                 if (a[i] < a[i - f]) {
  2122.                     final int u = a[i];
  2123.                     a[i] = a[i - f];
  2124.                     a[i - f] = u;
  2125.                 }
  2126.             }
  2127.             // 2nd 12th-tile
  2128.             fp = f / 3;
  2129.             s = l + fp;
  2130.             // Lower margin has 2(d+1) elements; d == (position in sample) - s
  2131.             // Force k into the lower margin
  2132.             p = s + ((k - l) >>> 1);
  2133.         }
  2134.         final int e = s + fp - 1;
  2135.         for (int i = s; i <= e; i++) {
  2136.             Sorting.sort3(a, i - fp, i, i + fp);
  2137.         }
  2138.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  2139.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  2140.     }

  2141.     /**
  2142.      * Partition an array slice around a pivot. Partitioning exchanges array elements such
  2143.      * that all elements smaller than pivot are before it and all elements larger than
  2144.      * pivot are after it.
  2145.      *
  2146.      * <p>Assumes the range {@code r - l >= 11}; the caller is responsible for selection on a smaller
  2147.      * range.
  2148.      *
  2149.      * <p>Uses the Chen and Dumitrescu repeated step median-of-medians-of-medians algorithm
  2150.      * with the maximum of 4 then median of 3; the final sample is placed in the
  2151.      * 11th 12th-tile; the pivot chosen from the sample is adaptive using the input {@code k}.
  2152.      *
  2153.      * <p>Given a pivot in the middle of the sample this has margins of 1/3 and 1/12.
  2154.      *
  2155.      * @param a Data array.
  2156.      * @param l Lower bound (inclusive).
  2157.      * @param r Upper bound (inclusive).
  2158.      * @param k Target index.
  2159.      * @param upper Upper bound (inclusive) of the pivot range.
  2160.      * @param flags Control flags.
  2161.      * @return Lower bound (inclusive) of the pivot range.
  2162.      */
  2163.     private static int repeatedStepFarRight(int[] a, int l, int r, int k, int[] upper, int flags) {
  2164.         // Mirror image repeatedStepFarLeft
  2165.         final int fp;
  2166.         final int e;
  2167.         int p;
  2168.         if (flags <= MODE_SAMPLING) {
  2169.             // 11th 12th-tile
  2170.             fp = (r - l + 1) / 12;
  2171.             e = r - fp;
  2172.             // Use adaption
  2173.             p = e - mapDistance(r - k, l, r, fp);
  2174.         } else {
  2175.             // i in 3rd quartile; max into i+f (4th quartile)
  2176.             final int f = (r - l + 1) >> 2;
  2177.             final int f2 = f + f;
  2178.             final int end = r - f2;
  2179.             for (int i = r - f; i > end; i--) {
  2180.                 if (a[i - f] > a[i + f]) {
  2181.                     final int u = a[i - f];
  2182.                     a[i - f] = a[i + f];
  2183.                     a[i + f] = u;
  2184.                 }
  2185.                 if (a[i - f2] > a[i]) {
  2186.                     final int v = a[i - f2];
  2187.                     a[i - f2] = a[i];
  2188.                     a[i] = v;
  2189.                 }
  2190.                 if (a[i] > a[i + f]) {
  2191.                     final int u = a[i];
  2192.                     a[i] = a[i + f];
  2193.                     a[i + f] = u;
  2194.                 }
  2195.             }
  2196.             // 11th 12th-tile
  2197.             fp = f / 3;
  2198.             e = r - fp;
  2199.             // Upper margin has 2(d+1) elements; d == e - (position in sample)
  2200.             // Force k into the upper margin
  2201.             p = e - ((r - k) >>> 1);
  2202.         }
  2203.         final int s = e - fp + 1;
  2204.         for (int i = s; i <= e; i++) {
  2205.             Sorting.sort3(a, i - fp, i, i + fp);
  2206.         }
  2207.         p = quickSelectAdaptive(a, s, e, p, p, upper, MODE_FR_SAMPLING);
  2208.         return expandPartition(a, l, r, s, e, p, upper[0], upper);
  2209.     }

  2210.     /**
  2211.      * Expand a partition around a single pivot. Partitioning exchanges array
  2212.      * elements such that all elements smaller than pivot are before it and all
  2213.      * elements larger than pivot are after it. The central region is already
  2214.      * partitioned.
  2215.      *
  2216.      * <pre>{@code
  2217.      * |l             |s   |p0 p1|   e|                r|
  2218.      * |    ???       | <P | ==P | >P |        ???      |
  2219.      * }</pre>
  2220.      *
  2221.      * <p>This requires that {@code start != end}. However it handles
  2222.      * {@code left == start} and/or {@code end == right}.
  2223.      *
  2224.      * @param a Data array.
  2225.      * @param left Lower bound (inclusive).
  2226.      * @param right Upper bound (inclusive).
  2227.      * @param start Start of the partition range (inclusive).
  2228.      * @param end End of the partitioned range (inclusive).
  2229.      * @param pivot0 Lower pivot location (inclusive).
  2230.      * @param pivot1 Upper pivot location (inclusive).
  2231.      * @param upper Upper bound (inclusive) of the pivot range [k1].
  2232.      * @return Lower bound (inclusive) of the pivot range [k0].
  2233.      */
  2234.     // package-private for testing
  2235.     static int expandPartition(int[] a, int left, int right, int start, int end,
  2236.         int pivot0, int pivot1, int[] upper) {
  2237.         // 3-way partition of the data using a pivot value into
  2238.         // less-than, equal or greater-than.
  2239.         // Based on Sedgewick's Bentley-McIroy partitioning: always swap i<->j then
  2240.         // check for equal to the pivot and move again.
  2241.         //
  2242.         // Move sentinels from start and end to left and right. Scan towards the
  2243.         // sentinels until >=,<=. Swap then move == to the pivot region.
  2244.         //           <-i                           j->
  2245.         // |l |        |            |p0  p1|       |             | r|
  2246.         // |>=|   ???  |     <      |  ==  |   >   |     ???     |<=|
  2247.         //
  2248.         // When either i or j reach the edge perform finishing loop.
  2249.         // Finish loop for a[j] <= v replaces j with p1+1, optionally moves value
  2250.         // to p0 for < and updates the pivot range p1 (and optionally p0):
  2251.         //                                             j->
  2252.         // |l                       |p0  p1|           |         | r|
  2253.         // |         <              |  ==  |       >   |   ???   |<=|

  2254.         final int v = a[pivot0];
  2255.         // Use start/end as sentinels (requires start != end)
  2256.         int vi = a[start];
  2257.         int vj = a[end];
  2258.         a[start] = a[left];
  2259.         a[end] = a[right];
  2260.         a[left] = vj;
  2261.         a[right] = vi;

  2262.         int i = start + 1;
  2263.         int j = end - 1;

  2264.         // Positioned for pre-in/decrement to write to pivot region
  2265.         int p0 = pivot0 == start ? i : pivot0;
  2266.         int p1 = pivot1 == end ? j : pivot1;

  2267.         while (true) {
  2268.             do {
  2269.                 --i;
  2270.             } while (a[i] < v);
  2271.             do {
  2272.                 ++j;
  2273.             } while (a[j] > v);
  2274.             vj = a[i];
  2275.             vi = a[j];
  2276.             a[i] = vi;
  2277.             a[j] = vj;
  2278.             // Move the equal values to pivot region
  2279.             if (vi == v) {
  2280.                 a[i] = a[--p0];
  2281.                 a[p0] = v;
  2282.             }
  2283.             if (vj == v) {
  2284.                 a[j] = a[++p1];
  2285.                 a[p1] = v;
  2286.             }
  2287.             // Termination check and finishing loops.
  2288.             // Note: This works even if pivot region is zero length (p1 == p0-1 due to
  2289.             // length 1 pivot region at either start/end) because we pre-inc/decrement
  2290.             // one side and post-inc/decrement the other side.
  2291.             if (i == left) {
  2292.                 while (j < right) {
  2293.                     do {
  2294.                         ++j;
  2295.                     } while (a[j] > v);
  2296.                     final int w = a[j];
  2297.                     // Move upper bound of pivot region
  2298.                     a[j] = a[++p1];
  2299.                     a[p1] = v;
  2300.                     // Move lower bound of pivot region
  2301.                     if (w != v) {
  2302.                         a[p0] = w;
  2303.                         p0++;
  2304.                     }
  2305.                 }
  2306.                 break;
  2307.             }
  2308.             if (j == right) {
  2309.                 while (i > left) {
  2310.                     do {
  2311.                         --i;
  2312.                     } while (a[i] < v);
  2313.                     final int w = a[i];
  2314.                     // Move lower bound of pivot region
  2315.                     a[i] = a[--p0];
  2316.                     a[p0] = v;
  2317.                     // Move upper bound of pivot region
  2318.                     if (w != v) {
  2319.                         a[p1] = w;
  2320.                         p1--;
  2321.                     }
  2322.                 }
  2323.                 break;
  2324.             }
  2325.         }

  2326.         upper[0] = p1;
  2327.         return p0;
  2328.     }

  2329.     /**
  2330.      * Partition the array such that indices {@code k} correspond to their
  2331.      * correctly sorted value in the equivalent fully sorted array.
  2332.      *
  2333.      * <p>For all indices {@code k} and any index {@code i}:
  2334.      *
  2335.      * <pre>{@code
  2336.      * data[i < k] <= data[k] <= data[k < i]
  2337.      * }</pre>
  2338.      *
  2339.      * <p>This function accepts a {@link UpdatingInterval} of indices {@code k} that define the
  2340.      * range of indices to partition. The {@link UpdatingInterval} can be narrowed or split as
  2341.      * partitioning divides the range.
  2342.      *
  2343.      * <p>Uses an introselect variant. The quickselect is a dual-pivot quicksort
  2344.      * partition method by Vladimir Yaroslavskiy; the fall-back on poor convergence of
  2345.      * the quickselect is a heapselect.
  2346.      *
  2347.      * <p>The {@code flags} contain the the current recursion count and the configured
  2348.      * length threshold for {@code r - l} to perform sort select. The count is in the upper
  2349.      * bits and the threshold is in the lower bits.
  2350.      *
  2351.      * @param a Values.
  2352.      * @param left Lower bound of data (inclusive, assumed to be strictly positive).
  2353.      * @param right Upper bound of data (inclusive, assumed to be strictly positive).
  2354.      * @param k Interval of indices to partition (ordered).
  2355.      * @param flags Control flags.
  2356.      */
  2357.     // package-private for testing
  2358.     static void dualPivotQuickSelect(int[] a, int left, int right, UpdatingInterval k, int flags) {
  2359.         // If partitioning splits the interval then recursion is used for the left-most side(s)
  2360.         // and the right-most side remains within this function. If partitioning does
  2361.         // not split the interval then it remains within this function.
  2362.         int l = left;
  2363.         int r = right;
  2364.         int f = flags;
  2365.         int ka = k.left();
  2366.         int kb = k.right();
  2367.         final int[] upper = {0, 0, 0};
  2368.         while (true) {
  2369.             // Select when ka and kb are close to the same end,
  2370.             // or the entire range is small
  2371.             // |l|-----|ka|--------|kb|------|r|
  2372.             final int n = r - l;
  2373.             if (Math.min(kb - l, r - ka) < DP_SORTSELECT_SIZE ||
  2374.                 n < (f & SORTSELECT_MASK)) {
  2375.                 sortSelect(a, l, r, ka, kb);
  2376.                 return;
  2377.             }
  2378.             if (kb - ka < DP_SORTSELECT_SIZE) {
  2379.                 // Switch to single-pivot mode with Floyd-Rivest sub-sampling
  2380.                 quickSelectAdaptive(a, l, r, ka, kb, upper, MODE_FR_SAMPLING);
  2381.                 return;
  2382.             }
  2383.             if (f < 0) {
  2384.                 // Excess recursion, switch to heap select
  2385.                 heapSelect(a, l, r, ka, kb);
  2386.                 return;
  2387.             }

  2388.             // Dual-pivot partitioning
  2389.             final int p0 = partition(a, l, r, upper);
  2390.             final int p1 = upper[0];

  2391.             // Recursion to max depth
  2392.             // Note: Here we possibly branch left, middle and right with multiple keys.
  2393.             // It is possible that the partition has split the keys
  2394.             // and the recursion proceeds with a reduced set in each region.
  2395.             //                   p0 p1               p2 p3
  2396.             // |l|--|ka|--k----k--|P|------k--|kb|----|P|----|r|
  2397.             //                 kb  |      ka
  2398.             f += RECURSION_INCREMENT;
  2399.             // Recurse left side if required
  2400.             if (ka < p0) {
  2401.                 if (kb <= p1) {
  2402.                     // Entirely on left side
  2403.                     r = p0 - 1;
  2404.                     if (r < kb) {
  2405.                         kb = k.updateRight(r);
  2406.                     }
  2407.                     continue;
  2408.                 }
  2409.                 dualPivotQuickSelect(a, l, p0 - 1, k.splitLeft(p0, p1), f);
  2410.                 // Here we must process middle and/or right
  2411.                 ka = k.left();
  2412.             } else if (kb <= p1) {
  2413.                 // No middle/right side
  2414.                 return;
  2415.             } else if (ka <= p1) {
  2416.                 // Advance lower bound
  2417.                 ka = k.updateLeft(p1 + 1);
  2418.             }
  2419.             // Recurse middle if required
  2420.             final int p2 = upper[1];
  2421.             final int p3 = upper[2];
  2422.             if (ka < p2) {
  2423.                 l = p1 + 1;
  2424.                 if (kb <= p3) {
  2425.                     // Entirely in middle
  2426.                     r = p2 - 1;
  2427.                     if (r < kb) {
  2428.                         kb = k.updateRight(r);
  2429.                     }
  2430.                     continue;
  2431.                 }
  2432.                 dualPivotQuickSelect(a, l, p2 - 1, k.splitLeft(p2, p3), f);
  2433.                 ka = k.left();
  2434.             } else if (kb <= p3) {
  2435.                 // No right side
  2436.                 return;
  2437.             } else if (ka <= p3) {
  2438.                 ka = k.updateLeft(p3 + 1);
  2439.             }
  2440.             // Continue right
  2441.             l = p3 + 1;
  2442.         }
  2443.     }

  2444.     /**
  2445.      * Partition an array slice around 2 pivots. Partitioning exchanges array elements
  2446.      * such that all elements smaller than pivot are before it and all elements larger
  2447.      * than pivot are after it.
  2448.      *
  2449.      * <p>This method returns 4 points describing the pivot ranges of equal values.
  2450.      *
  2451.      * <pre>{@code
  2452.      *         |k0  k1|                |k2  k3|
  2453.      * |   <P  | ==P1 |  <P1 && <P2    | ==P2 |   >P   |
  2454.      * }</pre>
  2455.      *
  2456.      * <ul>
  2457.      * <li>k0: lower pivot1 point
  2458.      * <li>k1: upper pivot1 point (inclusive)
  2459.      * <li>k2: lower pivot2 point
  2460.      * <li>k3: upper pivot2 point (inclusive)
  2461.      * </ul>
  2462.      *
  2463.      * <p>Bounds are set so {@code i < k0}, {@code i > k3} and {@code k1 < i < k2} are
  2464.      * unsorted. When the range {@code [k0, k3]} contains fully sorted elements the result
  2465.      * is set to {@code k1 = k3; k2 == k0}. This can occur if
  2466.      * {@code P1 == P2} or there are zero or one value between the pivots
  2467.      * {@code P1 < v < P2}. Any sort/partition of ranges [left, k0-1], [k1+1, k2-1] and
  2468.      * [k3+1, right] must check the length is {@code > 1}.
  2469.      *
  2470.      * @param a Data array.
  2471.      * @param left Lower bound (inclusive).
  2472.      * @param right Upper bound (inclusive).
  2473.      * @param bounds Points [k1, k2, k3].
  2474.      * @return Lower bound (inclusive) of the pivot range [k0].
  2475.      */
  2476.     private static int partition(int[] a, int left, int right, int[] bounds) {
  2477.         // Pick 2 pivots from 5 approximately uniform through the range.
  2478.         // Spacing is ~ 1/7 made using shifts. Other strategies are equal or much
  2479.         // worse. 1/7 = 5/35 ~ 1/8 + 1/64 : 0.1429 ~ 0.1406
  2480.         // Ensure the value is above zero to choose different points!
  2481.         final int n = right - left;
  2482.         final int step = 1 + (n >>> 3) + (n >>> 6);
  2483.         final int i3 = left + (n >>> 1);
  2484.         final int i2 = i3 - step;
  2485.         final int i1 = i2 - step;
  2486.         final int i4 = i3 + step;
  2487.         final int i5 = i4 + step;
  2488.         Sorting.sort5(a, i1, i2, i3, i4, i5);

  2489.         // Partition data using pivots P1 and P2 into less-than, greater-than or between.
  2490.         // Pivot values P1 & P2 are placed at the end. If P1 < P2, P2 acts as a sentinel.
  2491.         // k traverses the unknown region ??? and values moved if less-than or
  2492.         // greater-than:
  2493.         //
  2494.         // left        less              k       great         right
  2495.         // |P1|  <P1   |   P1 <= & <= P2 |    ???    |    >P2   |P2|
  2496.         //
  2497.         // <P1            (left, lt)
  2498.         // P1 <= & <= P2  [lt, k)
  2499.         // >P2            (gt, right)
  2500.         //
  2501.         // At the end pivots are swapped back to behind the less and great pointers.
  2502.         //
  2503.         // |  <P1        |P1|     P1<= & <= P2    |P2|      >P2    |

  2504.         // Swap ends to the pivot locations.
  2505.         final int v1 = a[i2];
  2506.         a[i2] = a[left];
  2507.         a[left] = v1;
  2508.         final int v2 = a[i4];
  2509.         a[i4] = a[right];
  2510.         a[right] = v2;

  2511.         // pointers
  2512.         int less = left;
  2513.         int great = right;

  2514.         // Fast-forward ascending / descending runs to reduce swaps.
  2515.         // Cannot overrun as end pivots (v1 <= v2) act as sentinels.
  2516.         do {
  2517.             ++less;
  2518.         } while (a[less] < v1);
  2519.         do {
  2520.             --great;
  2521.         } while (a[great] > v2);

  2522.         // a[less - 1] < P1 : a[great + 1] > P2
  2523.         // unvisited in [less, great]
  2524.         SORTING:
  2525.         for (int k = less - 1; ++k <= great;) {
  2526.             final int v = a[k];
  2527.             if (v < v1) {
  2528.                 // swap(a, k, less++)
  2529.                 a[k] = a[less];
  2530.                 a[less] = v;
  2531.                 less++;
  2532.             } else if (v > v2) {
  2533.                 // while k < great and a[great] > v2:
  2534.                 //   great--
  2535.                 while (a[great] > v2) {
  2536.                     if (great-- == k) {
  2537.                         // Done
  2538.                         break SORTING;
  2539.                     }
  2540.                 }
  2541.                 // swap(a, k, great--)
  2542.                 // if a[k] < v1:
  2543.                 //   swap(a, k, less++)
  2544.                 final int w = a[great];
  2545.                 a[great] = v;
  2546.                 great--;
  2547.                 // delay a[k] = w
  2548.                 if (w < v1) {
  2549.                     a[k] = a[less];
  2550.                     a[less] = w;
  2551.                     less++;
  2552.                 } else {
  2553.                     a[k] = w;
  2554.                 }
  2555.             }
  2556.         }

  2557.         // Change to inclusive ends : a[less] < P1 : a[great] > P2
  2558.         less--;
  2559.         great++;
  2560.         // Move the pivots to correct locations
  2561.         a[left] = a[less];
  2562.         a[less] = v1;
  2563.         a[right] = a[great];
  2564.         a[great] = v2;

  2565.         // Record the pivot locations
  2566.         final int lower = less;
  2567.         bounds[2] = great;

  2568.         // equal elements
  2569.         // Original paper: If middle partition is bigger than a threshold
  2570.         // then check for equal elements.

  2571.         // Note: This is extra work. When performing partitioning the region of interest
  2572.         // may be entirely above or below the central region and this can be skipped.

  2573.         // Here we look for equal elements if the centre is more than 5/8 the length.
  2574.         // 5/8 = 1/2 + 1/8. Pivots must be different.
  2575.         if ((great - less) > (n >>> 1) + (n >>> 3) && v1 != v2) {

  2576.             // Fast-forward to reduce swaps. Changes inclusive ends to exclusive ends.
  2577.             // Since v1 != v2 these act as sentinels to prevent overrun.
  2578.             do {
  2579.                 ++less;
  2580.             } while (a[less] == v1);
  2581.             do {
  2582.                 --great;
  2583.             } while (a[great] == v2);

  2584.             // This copies the logic in the sorting loop using == comparisons
  2585.             EQUAL:
  2586.             for (int k = less - 1; ++k <= great;) {
  2587.                 final int v = a[k];
  2588.                 if (v == v1) {
  2589.                     a[k] = a[less];
  2590.                     a[less] = v;
  2591.                     less++;
  2592.                 } else if (v == v2) {
  2593.                     while (a[great] == v2) {
  2594.                         if (great-- == k) {
  2595.                             // Done
  2596.                             break EQUAL;
  2597.                         }
  2598.                     }
  2599.                     final int w = a[great];
  2600.                     a[great] = v;
  2601.                     great--;
  2602.                     if (w == v1) {
  2603.                         a[k] = a[less];
  2604.                         a[less] = w;
  2605.                         less++;
  2606.                     } else {
  2607.                         a[k] = w;
  2608.                     }
  2609.                 }
  2610.             }

  2611.             // Change to inclusive ends
  2612.             less--;
  2613.             great++;
  2614.         }

  2615.         // Between pivots in (less, great)
  2616.         if (v1 != v2 && less < great - 1) {
  2617.             // Record the pivot end points
  2618.             bounds[0] = less;
  2619.             bounds[1] = great;
  2620.         } else {
  2621.             // No unsorted internal region (set k1 = k3; k2 = k0)
  2622.             bounds[0] = bounds[2];
  2623.             bounds[1] = lower;
  2624.         }

  2625.         return lower;
  2626.     }

  2627.     /**
  2628.      * Map the distance from the edge of {@code [l, r]} to a new distance in {@code [0, n)}.
  2629.      *
  2630.      * <p>The provides the adaption {@code kf'/|A|} from Alexandrescu (2016) where
  2631.      * {@code k == d}, {@code f' == n} and {@code |A| == r-l+1}.
  2632.      *
  2633.      * <p>For convenience this accepts the input range {@code [l, r]}.
  2634.      *
  2635.      * @param d Distance from the edge in {@code [0, r - l]}.
  2636.      * @param l Lower bound (inclusive).
  2637.      * @param r Upper bound (inclusive).
  2638.      * @param n Size of the new range.
  2639.      * @return the mapped distance in [0, n)
  2640.      */
  2641.     private static int mapDistance(int d, int l, int r, int n) {
  2642.         return (int) (d * (n - 1.0) / (r - l));
  2643.     }

  2644.     /**
  2645.      * Configure the dual-pivot control flags. This packs the maximum recursion depth and
  2646.      * sort select size into a single integer.
  2647.      *
  2648.      * @param left Lower bound (inclusive).
  2649.      * @param right Upper bound (inclusive).
  2650.      * @param k1 First key of interest.
  2651.      * @param kn Last key of interest.
  2652.      * @return the flags
  2653.      */
  2654.     private static int dualPivotFlags(int left, int right, int k1, int kn) {
  2655.         final int maxDepth = dualPivotMaxDepth(right - left);
  2656.         final int ss = dualPivotSortSelectSize(k1, kn);
  2657.         return dualPivotFlags(maxDepth, ss);
  2658.     }

  2659.     /**
  2660.      * Configure the dual-pivot control flags. This packs the maximum recursion depth and
  2661.      * sort select size into a single integer.
  2662.      *
  2663.      * @param maxDepth Maximum recursion depth.
  2664.      * @param ss Sort select size.
  2665.      * @return the flags
  2666.      */
  2667.     static int dualPivotFlags(int maxDepth, int ss) {
  2668.         // The flags are packed using the upper bits to count back from -1 in
  2669.         // step sizes. The lower bits pack the sort select size.
  2670.         int flags = Integer.MIN_VALUE - maxDepth * RECURSION_INCREMENT;
  2671.         flags &= ~SORTSELECT_MASK;
  2672.         return flags | ss;
  2673.     }

  2674.     /**
  2675.      * Compute the maximum recursion depth for dual pivot recursion.
  2676.      * This is an approximation to {@code 2 * log3 (x)}.
  2677.      *
  2678.      * <p>The result is between {@code 2*floor(log3(x))} and {@code 2*ceil(log3(x))}.
  2679.      * The result is correctly rounded when {@code x +/- 1} is a power of 3.
  2680.      *
  2681.      * @param x Value.
  2682.      * @return maximum recursion depth
  2683.      */
  2684.     static int dualPivotMaxDepth(int x) {
  2685.         // log3(2) ~ 1.5849625
  2686.         // log3(x) ~ log2(x) * 0.630929753... ~ log2(x) * 323 / 512 (0.630859375)
  2687.         // Use (floor(log2(x))+1) * 323 / 256
  2688.         return ((32 - Integer.numberOfLeadingZeros(x)) * 323) >>> 8;
  2689.     }

  2690.     /**
  2691.      * Configure the sort select size for dual pivot partitioning.
  2692.      *
  2693.      * @param k1 First key of interest.
  2694.      * @param kn Last key of interest.
  2695.      * @return the sort select size.
  2696.      */
  2697.     private static int dualPivotSortSelectSize(int k1, int kn) {
  2698.         // Configure the sort select size based on the index density
  2699.         // l---k1---k---k-----k--k------kn----r
  2700.         //
  2701.         // For a full sort the dual-pivot quicksort can switch to insertion sort
  2702.         // when the length is small. The optimum value is dependent on the
  2703.         // hardware and the insertion sort implementation. Benchmarks show that
  2704.         // insertion sort can be used at length 80-120.
  2705.         //
  2706.         // During selection the SORTSELECT_SIZE specifies the distance from the edge
  2707.         // to use sort select. When keys are not dense there may be a small length
  2708.         // that is ignored by sort select due to the presence of another key.
  2709.         // Diagram of k-l = SORTSELECT_SIZE and r-k < SORTSELECT_SIZE where a second
  2710.         // key b is blocking the use of sort select. The key b is closest it can be to the right
  2711.         // key to enable blocking; it could be further away (up to k = left).
  2712.         //
  2713.         // |--SORTSELECT_SIZE--|
  2714.         //    |--SORTSELECT_SIZE--|
  2715.         // l--b----------------k--r
  2716.         // l----b--------------k----r
  2717.         // l------b------------k------r
  2718.         // l--------b----------k--------r
  2719.         // l----------b--------k----------r
  2720.         // l------------b------k------------r
  2721.         // l--------------b----k--------------r
  2722.         // l----------------b--k----------------r
  2723.         // l------------------bk------------------r
  2724.         //                    |--SORTSELECT_SIZE--|
  2725.         //
  2726.         // For all these cases the partitioning method would have to run. Assuming ideal
  2727.         // dual-pivot partitioning into thirds, and that the left key is randomly positioned
  2728.         // in [left, k) it is more likely that after partitioning 2 partitions will have to
  2729.         // be processed rather than 1 partition. In this case the options are:
  2730.         // - split the range using partitioning; sort select next iteration
  2731.         // - use sort select with a edge distance above the optimum length for single k selection
  2732.         //
  2733.         // Contrast with a longer length:
  2734.         // |--SORTSELECT_SIZE--|
  2735.         // l-------------------k-----k-------k-------------------r
  2736.         //                                   |--SORTSELECT_SIZE--|
  2737.         // Here partitioning has to run and 1, 2, or 3 partitions processed. But all k can
  2738.         // be found with a sort. In this case sort select could be used with a much higher
  2739.         // length (e.g. 80 - 120).
  2740.         //
  2741.         // When keys are extremely sparse (never within SORTSELECT_SIZE) then no switch
  2742.         // to sort select based on length is *required*. It may still be beneficial to avoid
  2743.         // partitioning if the length is very small due to the overhead of partitioning.
  2744.         //
  2745.         // Benchmarking with different lengths for a switch to sort select show inconsistent
  2746.         // behaviour across platforms due to the variable speed of insertion sort at longer
  2747.         // lengths. Attempts to transition the length based on various ramps schemes can
  2748.         // be incorrect and result is a slowdown rather than speed-up (if the correct threshold
  2749.         // is not chosen).
  2750.         //
  2751.         // Here we use a much simpler scheme based on these observations:
  2752.         // - If the average separation is very high then no length will collect extra indices
  2753.         // from a sort select over the current trigger of using the distance from the end. But
  2754.         // using a length dependence will not effect the work done by sort select as it only
  2755.         // performs the minimum sorting required.
  2756.         // - If the average separation is within the SORTSELECT_SIZE then a round of
  2757.         // partitioning will create multiple regions that all require a sort selection.
  2758.         // Thus a partitioning round can be avoided if the length is small.
  2759.         // - If the keys are at the end with nothing in between then partitioning will be able
  2760.         // to split them but a sort will have to sort the entire range:
  2761.         // lk-------------------------------kr
  2762.         // After partitioning starts the chance of keys being at the ends is low as keys
  2763.         // should be random within the divided range.
  2764.         // - Extremely high density keys is rare. It is only expected to saturate the range
  2765.         // with short lengths, e.g. 100 quantiles for length 1000 = separation 10 (high density)
  2766.         // but for length 10000 = separation 100 (low density).
  2767.         // - The density of (non-uniform) keys is hard to predict without complex analysis.
  2768.         //
  2769.         // Benchmarking using random keys at various density show no performance loss from
  2770.         // using a fixed size for the length dependence of sort select, if the size is small.
  2771.         // A large length can impact performance with low density keys, and on machines
  2772.         // where insertion sort is slower. Extreme performance gains occur when the average
  2773.         // separation of random keys is below 8-16, or of uniform keys around 32, by using a
  2774.         // sort at lengths up to 90. But this threshold shows performance loss greater than
  2775.         // the gains with separation of 64-128 on random keys, and on machines with slow
  2776.         // insertion sort. The transition to using an insertion sort of a longer length
  2777.         // is difficult to predict for all situations.

  2778.         // Let partitioning run if the initial length is small.
  2779.         // Use kn - k1 as a proxy for the length. If length is actually very large then
  2780.         // the final selection is insignificant. This avoids slowdown for small lengths
  2781.         // where the keys may only be at the ends. Note ideal dual-pivot partitioning
  2782.         // creates thirds so 1 iteration on SORTSELECT_SIZE * 3 should create
  2783.         // SORTSELECT_SIZE partitions.
  2784.         if (kn - k1 < DP_SORTSELECT_SIZE * 3) {
  2785.             return 0;
  2786.         }
  2787.         // Here partitioning will run at least once.
  2788.         // Stable performance across platforms using a modest length dependence.
  2789.         return DP_SORTSELECT_SIZE * 2;
  2790.     }
  2791. }