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.examples.jmh.arrays; 18 19 /** 20 * A cache of pivot indices used for partitioning an array into multiple regions. 21 * 22 * <p>A pivot is an index position that contains a value equal to the value in a fully 23 * sorted array. 24 * 25 * <p>For a pivot {@code p}: 26 * 27 * <pre>{@code 28 * i < p < j 29 * data[i] <= data[p] <= data[j] 30 * }</pre> 31 * 32 * <p>Partitioning moves data in a range {@code [lower, upper]} so that the pivot 33 * {@code p} partitions the data. During this process many pivots may be found 34 * before the search ends. A pivot cache supports storing these pivots so that 35 * they can be used to bracket further searches in the array. 36 * 37 * <p>A pivot cache supports finding a search bracket to partition an index {@code k} 38 * within an array of length {@code n}. The bracket should be an enclosing bound 39 * of known pivots. All data can be rearranged within this bracket without destroying 40 * other regions of the partitioned array. The support for {@code k} is provided within 41 * an inclusive range {@code [left, right]} where {@code 0 <= left <= right < n}. 42 * Thus {@code [left, right]} denotes the region containing all target indices {@code k} 43 * for multi-region partitioning. 44 * 45 * <p>The cache provides the following functionality: 46 * 47 * <ul> 48 * <li>Test if an index {@code [left <= k <= right]} is a known pivot. 49 * <li>Return a {@code lower} bounding pivot for a partition of an index {@code [left <= k <= right]}. 50 * <li>Return an {@code upper} bounding pivot for a partition of an index {@code [left <= k <= right]}. 51 * </ul> 52 * 53 * <p>Note that searching with the bound {@code [lower, upper]} will reorder data 54 * and pivots within this range may be invalidated by moving of data. To prevent 55 * error the bound provided by a cache must use the closest bracketing pivots. 56 * 57 * <p>At least two strategies can be used: 58 * 59 * <ol> 60 * <li>Process {@code k} indices in any order. Store all pivots during the partitioning. 61 * Each subsequent search after the first can use adjacent pivots to bracket the search. 62 * <li>Process {@code k} indices in sorted order. The {@code lower} bound for {@code k+1} 63 * will be {@code k <= lower}. This does not require a cache as {@code upper} can be set 64 * using the end of the data {@code n}. For this case a cache can store pivots which can 65 * be used to bracket the search for {@code k+1}. 66 * </ol> 67 * 68 * <p>Implementations may assume indices are positive. 69 * 70 * @since 1.2 71 */ 72 interface PivotCache extends PivotStore { 73 /** 74 * The start (inclusive) of the range of indices supported. 75 * 76 * @return start of the supported range 77 */ 78 int left(); 79 80 /** 81 * The end (inclusive) of the range of indices supported. 82 * 83 * @return end of the supported range 84 */ 85 int right(); 86 87 /** 88 * Returns {@code true} if the cache supports storing some of the pivots in the supported 89 * range. A sparse cache can provide approximate bounds for partitioning. These bounds may be 90 * smaller than using the bounds of the entire array. Note that partitioning may destroy 91 * previous pivots within a range. Thus a sparse cache should be used to partition indices 92 * in sorted order so that bounds generated by each iteration do not overlap the bounds 93 * of a previous partition. This can be done by using the previous {@code k} as the left 94 * bound. 95 * 96 * <p>A sparse cache can be created to store 1 pivot between all {@code k} of interest 97 * after the first {@code k}, and optionally two pivots that bracket the entire supported 98 * range. In the following example the partition of {@code k1} stores pivots {@code p}. 99 * These can be used to bracket {@code k2, k3}. An alternative scheme 100 * where no pivots are stored is shown for comparison: 101 * 102 * <pre> 103 * Partition: 104 * 0------k1----------k2------k3---------N 105 * 106 * Iteration 1: 107 * 0------k1------p--------p---------p---N 108 * 109 * Iteration 2: 110 * l---k2---r 111 * or: l-----------k2-----------------N 112 * 113 * Iteration 3: 114 * l--k3-----r 115 * or: l-------k3---------N 116 * </pre> 117 * 118 * <p>If false then the cache will store all pivots within the supported range and 119 * ideally provide the closest bounding pivot around the supported range. 120 * 121 * @return true if sparse 122 */ 123 boolean sparse(); 124 125 /** 126 * Test if the index {@code k} is a pivot. 127 * 128 * <p><em>If {@code index < left} or {@code index > right} the behavior is not 129 * defined.</em></p> 130 * 131 * @param k Index. 132 * @return true if the index is a pivot within the supported range 133 */ 134 boolean contains(int k); 135 136 /** 137 * Returns the nearest pivot index that occurs on or before the specified starting 138 * index. If none exist then {@code -1} is returned. 139 * 140 * @param k Index to start checking from (inclusive). 141 * @return the index of the previous pivot, or {@code -1} if there is no index 142 */ 143 int previousPivot(int k); 144 145 /** 146 * Returns the nearest pivot index that occurs on or after the specified starting 147 * index. If none exist then {@code -1} is returned. 148 * 149 * @param k Index to start checking from (inclusive). 150 * @return the index of the next pivot, or {@code -1} if there is no index 151 */ 152 default int nextPivot(int k) { 153 return nextPivotOrElse(k, -1); 154 } 155 156 /** 157 * Returns the nearest pivot index that occurs on or after the specified starting 158 * index. If none exist then {@code other} is returned. 159 * 160 * @param k Index to start checking from (inclusive). 161 * @param other Other value. 162 * @return the index of the next pivot, or {@code other} if there is no index 163 */ 164 int nextPivotOrElse(int k, int other); 165 }