├── LICENSE ├── README.md ├── images ├── auxiliary.gif ├── bridge.gif ├── bridge_helix_trinity_reversal.png ├── contrev_piston_griesmills_juggler.png ├── grail.gif ├── griesmills.gif ├── helix.gif ├── juggling.gif ├── piston.gif ├── reversal.gif └── trinity.gif └── src ├── bench.c └── rotate.h /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014-2023 Igor van den Hoven ivdhoven@gmail.com 3 | */ 4 | 5 | /* 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The most commonly used rotation algorithms (aka block swaps) were documented around 1981 and haven't notably changed since. 2 | 3 | Below I'll describe the known variants as well as three novel rotation algorithms introduced in 2021, notably the [trinity rotation](https://github.com/scandum/rotate#Trinity-Rotation), followed by some [benchmarks](https://github.com/scandum/rotate#Benchmarks). 4 | 5 | [C source code](https://github.com/scandum/rotate/tree/main/src) is available for all rotations described. 6 | 7 | Introduction to rotating 8 | ------------------------ 9 | A rotation is to swap the left side of an array with the right side. 10 | ```c 11 | ┌──────────────────────────┬─────────────────┐ 12 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 13 | └──────────────────────────┴─────────────────┘ 14 | ``` 15 | After the rotation the data is as following. 16 | ```c 17 | ┌─────────────────┬──────────────────────────┐ 18 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 19 | └─────────────────┴──────────────────────────┘ 20 | ``` 21 | 22 | Utility of rotating 23 | ------------------- 24 | According to Sean Parent rotations are a very common operation: https://www.youtube.com/watch?v=UZmeDQL4LaE 25 | 26 | Auxiliary Rotation 27 | ------------------ 28 | This is an easy and fast way to rotate, but since it requires auxiliary memory it is of little interest to in-place algorithms. It's a good strategy for array sizes of 1000 elements or less. 29 | 30 | Typically the smaller half is copied to swap memory, the larger half is moved, and the swap memory is copied back to the main array. 31 | ```c 32 | ┌──────────────────────────┬─────────────────┐ 33 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 34 | └──────────────────────────┴─────────────────┘ 35 | └──┴──┴──┴──┴──┴────┬──┬──┬──┬──┬──┐ 36 | ┌──────────────────────────┬─────────────────┐ ┌─────────────────┐ 37 | │ 1 2 3 4 5 6 7 8 9│ │ │10 11 12 13 14 15│ 38 | └──────────────────────────┴─────────────────┘ └─────────────────┘ 39 | └──┴──┴──┴──┴──┴──┼──┼──┼──┬──┬──┬──┬──┬──┐ 40 | ┌─────────────────┬──────────────────────────┐ ┌─────────────────┐ 41 | │ │ 1 2 3 4 5 6 7 8 9│ │10 11 12 13 14 15│ 42 | └─────────────────┴──────────────────────────┘ └─────────────────┘ 43 | ┌──┬──┬──┬──┬──┬───────────────────────────────┴──┴──┴──┴──┴──┘ 44 | ┌─────────────────┬──────────────────────────┐ 45 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 46 | └─────────────────┴──────────────────────────┘ 47 | ``` 48 | 49 | [![auxiliary rotation](/images/auxiliary.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=0s) 50 | 51 | Bridge Rotation 52 | --------------- 53 | This is a slightly more complex auxiliary rotation that reduces the maximum auxiliary memory requirement from 50% to 33%. If the overlap between the two halves is smaller than the halves themselves it copies the overlap to swap memory instead. Its first known publication was in 2021 by Igor van den Hoven.[^1] 54 | ```c 55 | ┌──────────────────────────┬─────────────────┐ 56 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 57 | └──────────────────────────┴─────────────────┘ 58 | └──┴──┴──────────────────────┬──┬──┐ 59 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 60 | │ 1 2 3 4 5 6│ │10 11 12 13 14 15│ │ 7 8 9│ 61 | └─────────────────┴────────┴─────────────────┘ └────────┘ 62 | ├─────────────────┬────────┘ 63 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 64 | │10 2 3 4 5 6│ 1 │ 11 12 13 14 15│ │ 7 8 9│ 65 | └─────────────────┴────────┴─────────────────┘ └────────┘ 66 | ├─────────────────┬────────┘ 67 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 68 | │10 11 3 4 5 6│ 1 2 │ 12 13 14 15│ │ 7 8 9│ 69 | └─────────────────┴────────┴─────────────────┘ └────────┘ 70 | ├─────────────────┬────────┘ 71 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 72 | │10 11 12 4 5 6│ 1 2 3│ 13 14 15│ │ 7 8 9│ 73 | └─────────────────┴────────┴─────────────────┘ └────────┘ 74 | ├─────────────────┬────────┘ 75 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 76 | │10 11 12 13 5 6│ 1 2 3│ 4 14 15│ │ 7 8 9│ 77 | └─────────────────┴────────┴─────────────────┘ └────────┘ 78 | ├─────────────────┬────────┘ 79 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 80 | │10 11 12 13 14 6│ 1 2 3│ 4 5 15│ │ 7 8 9│ 81 | └─────────────────┴────────┴─────────────────┘ └────────┘ 82 | ├─────────────────┬────────┘ 83 | ┌─────────────────┬────────┬─────────────────┐ ┌────────┐ 84 | │10 11 12 13 14 15│ 1 2 3│ 4 5 6 │ │ 7 8 9│ 85 | └─────────────────┴────────┴─────────────────┘ └────────┘ 86 | ┌──┬──┬────┴──┴──┘ 87 | ┌─────────────────┬──────────────────────────┐ 88 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 89 | └─────────────────┴──────────────────────────┘ 90 | ``` 91 | 92 | [![bridge rotation](/images/bridge.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=15s) 93 | 94 | Juggling Rotation 95 | ----------------- 96 | Also known as the dolphin algorithm. This is a relatively complex and inefficient way to rotate in-place, though it does so in the minimal number of moves. Its first known publication was in 1966.[^2] 97 | 98 | It computes the greatest common divisor and uses a loop to create a chain of consecutive swaps. 99 | 100 | ```c 101 | ┌──────────────────────────┬─────────────────┐ 102 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 103 | └──────────────────────────┴─────────────────┘ 104 | ↓ ↓ ↓ ↓ ↓ 105 | ┌──────────────────────────┬─────────────────┐ 106 | │10 2 3 13 5 6 1 8 9│ 4 11 12 7 14 15│ 107 | └──────────────────────────┴─────────────────┘ 108 | ↓ ↓ ↓ ↓ ↓ 109 | ┌──────────────────────────┬─────────────────┐ 110 | │10 11 3 13 14 6 1 2 9│ 4 5 12 7 8 15│ 111 | └──────────────────────────┴─────────────────┘ 112 | ↓ ↓ ↓ ↓ ↓ 113 | ┌─────────────────┬──────────────────────────┐ 114 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 115 | └─────────────────┴──────────────────────────┘ 116 | ``` 117 | [![juggling rotation](/images/juggling.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=119s) 118 | 119 | Triple Reversal Rotation 120 | ------------------------ 121 | This is an easy and reliable way to rotate in-place. You reverse the left side, next you reverse the right side, next you reverse the entire array. Upon completion the left and right block will be swapped. There's no known first publication, but it was prior to 1981.[^3] 122 | ```c 123 | ┌──────────────────────────┬─────────────────┐ 124 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 125 | └──────────────────────────┴─────────────────┘ 126 | ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 127 | ┌──────────────────────────┬─────────────────┐ 128 | │ 9 8 7 6 5 4 3 2 1│10 11 12 13 14 15│ 129 | └──────────────────────────┴─────────────────┘ 130 | ↓ ↓ ↓ ↓ ↓ ↓ 131 | ┌──────────────────────────┬─────────────────┐ 132 | │ 9 8 7 6 5 4 3 2 1│15 14 13 12 11 10│ 133 | └──────────────────────────┴─────────────────┘ 134 | ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ 135 | ┌─────────────────┬──────────────────────────┐ 136 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 137 | └─────────────────┴──────────────────────────┘ 138 | ``` 139 | 140 | [![reversal rotation](/images/reversal.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=23s) 141 | 142 | Gries-Mills Rotation 143 | -------------------- 144 | In some cases this rotation outperforms the classic triple reversal rotation while making fewer moves. You swap the smallest array linearly towards its proper location, since the blocks behind it are in the proper location you can forget about them. What remains of the larger array is now the smallest array, which you rotate in a similar manner, until the smallest side shrinks to 0 elements. Its first known publication was in 1981 by David Gries and Harlan Mills.[^3] 145 | ```c 146 | ┌──────────────────────────┬─────────────────┐ 147 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 148 | └──────────────────────────┴─────────────────┘ 149 | ┌──┬──┬──┬──┬──┬──┴──┴──┴──┴──┴──┘ 150 | ┌────────┬─────────────────┬─────────────────┐ 151 | │ 1 2 3│10 11 12 13 14 15│ 4 5 6 7 8 9│ 152 | └────────┴─────────────────┴─────────────────┘ 153 | └──┴──┴──┬──┬──┐ 154 | ┌────────┬────────┬──────────────────────────┐ 155 | │10 11 12│ 1 2 3│13 14 15 4 5 6 7 8 9│ 156 | └────────┴────────┴──────────────────────────┘ 157 | └──┴──┴──┬──┬──┐ 158 | ┌─────────────────┬──────────────────────────┐ 159 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 160 | └─────────────────┴──────────────────────────┘ 161 | ``` 162 | 163 | [![griesmills rotation](/images/griesmills.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=47s) 164 | 165 | Successive Rotation 166 | ------------------- 167 | First described by Gries and Mills in 1981, this rotation is very similar to the Gries-Mills rotation but performs non-linear swaps.[^3] It is implemented as the Piston Rotation in the benchmark, named after a loop optimization that removes up to `log n` branch mispredictions by performing both a left and rightward rotation in each loop. 168 | 169 | ```c 170 | ┌──────────────────────────┬─────────────────┐ 171 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 172 | └──────────────────────────┴─────────────────┘ 173 | ┌──┬──┬──┬──┬──┬───────────┴──┴──┴──┴──┴──┘ 174 | ┌─────────────────┬────────┬─────────────────┐ 175 | │10 11 12 13 14 15│ 7 8 9│ 1 2 3 4 5 6│ 176 | └─────────────────┴────────┴─────────────────┘ 177 | └──┴──┴───────────┬──┬──┐ 178 | ┌─────────────────┬────────┬────────┬────────┐ 179 | │10 11 12 13 14 15│ 4 5 6│ 1 2 3│ 7 8 9│ 180 | └─────────────────┴────────┴────────┴────────┘ 181 | ┌──┬──┬──┴──┴──┘ 182 | ┌─────────────────┬──────────────────────────┐ 183 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 184 | └─────────────────┴──────────────────────────┘ 185 | ``` 186 | 187 | [![piston rotation](/images/piston.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=87s) 188 | 189 | Grail Rotation 190 | -------------- 191 | The grail rotation from the Holy Grail Sort Project is Gries-Mills derived and tries to improve locality by shifting memory either left or right depending on which side it's swapped from.[^4] In addition it performs an auxiliary rotation on stack memory when the smallest side reaches a size of 1 element, which is the worst case for the Gries-Mills rotation. The flow diagram is identical to that of Gries-Mills, but due to memory being shifted from the right the visualization differs. 192 | 193 | [![grail rotation](/images/grail.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=67s) 194 | 195 | Helix Rotation 196 | --------------- 197 | The helix rotation has similarities with the Gries-Mills rotation but has a distinct sequential movement pattern. It is an improvement upon the Grail rotation by merging the two inner loops into a single loop, significantly improving performance when the relative size difference between the two halves is large. In addition it doesn't stop when the smallest block no longer fits, but continues and recalculates the left or right side. The utilization of the merged loops is counter-intuitive and is likely novel. Its first known publication was in 2021 by Control from the Holy Grail Sort Project.[^4] 198 | ```c 199 | ┌──────────────────────────┬─────────────────┐ 200 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 201 | └──────────────────────────┴─────────────────┘ 202 | ┌──┬──┬──┬──┬──┬──┴──┴──┴──┴──┴──┘ 203 | ┌────────┬─────────────────┬─────────────────┐ 204 | │ 1 2 3│10 11 12 13 14 15│ 4 5 6 7 8 9│ 205 | └────────┴─────────────────┴─────────────────┘ 206 | ┌──┬──┬───────────┴──┴──┘ 207 | ┌─────────────────┬──────────────────────────┐ 208 | │13 14 15 10 11 12│ 1 2 3 4 5 6 7 8 9│ 209 | └─────────────────┴──────────────────────────┘ 210 | └──┴──┴──┬──┬──┐ 211 | ┌─────────────────┬──────────────────────────┐ 212 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 213 | └─────────────────┴──────────────────────────┘ 214 | ``` 215 | 216 | [![helix rotation](/images/helix.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=108s) 217 | 218 | Drill Rotation 219 | -------------- 220 | The drill rotation is a grail variant that utilizes a piston main loop and a helix inner loop. Performance is similar to the helix rotation. The flow diagram and visualization are identical to the grail rotation. 221 | 222 | Trinity Rotation 223 | ---------------- 224 | The trinity rotation (aka conjoined triple reversal) is derived from the triple reversal rotation. Rather than three separate reversals it conjoins the three reversals, improving locality and reducing the number of moves. Optionally, if the overlap is smaller than 8 elements, it skips the trinity rotation and performs an auxiliary or bridge rotation on stack memory. Its first known publication was in 2021 by Igor van den Hoven.[^1] 225 | ```c 226 | ┌──────────────────────────┬─────────────────┐ 227 | │ 1 2 3 4 5 6 7 8 9│10 11 12 13 14 15│ 228 | └──────────────────────────┴─────────────────┘ 229 | ↓ ↓ ↓ ↓ 230 | ┌──────────────────────────┬─────────────────┐ 231 | │10 2 3 4 5 6 7 8 1│15 11 12 13 14 9│ 232 | └──────────────────────────┴─────────────────┘ 233 | ↓ ↓ ↓ ↓ 234 | ┌──────────────────────────┬─────────────────┐ 235 | │10 11 3 4 5 6 7 2 1│15 14 12 13 8 9│ 236 | └──────────────────────────┴─────────────────┘ 237 | ↓ ↓ ↓ ↓ 238 | ┌──────────────────────────┬─────────────────┐ 239 | │10 11 12 4 5 6 3 2 1│15 14 13 7 8 9│ 240 | └──────────────────────────┴─────────────────┘ 241 | ↓ ↓ ↓ 242 | ┌──────────────────────────┬─────────────────┐ 243 | │10 11 12 13 5 4 3 2 1│15 14 6 7 8 9│ 244 | └──────────────────────────┴─────────────────┘ 245 | ↓ ↓ 246 | ┌──────────────────────────┬─────────────────┐ 247 | │10 11 12 13 14 4 3 2 1│15 5 6 7 8 9│ 248 | └──────────────────────────┴─────────────────┘ 249 | ↓ ↓ 250 | ┌──────────────────────────┬─────────────────┐ 251 | │10 11 12 13 14 15 3 2 1│ 4 5 6 7 8 9│ 252 | └──────────────────────────┴─────────────────┘ 253 | ↓ ↓ 254 | ┌─────────────────┬──────────────────────────┐ 255 | │10 11 12 13 14 15│ 1 2 3 4 5 6 7 8 9│ 256 | └─────────────────┴──────────────────────────┘ 257 | ``` 258 | 259 | [![trinity rotation](/images/trinity.gif)](https://www.youtube.com/watch?v=rHubUT40FDc&t=35s) 260 | 261 | Benchmarks 262 | ---------- 263 | Since the auxiliary/bridge rotations are fairly similar I've omitted the auxiliary rotation from the benchmark graph. Similarly the grail rotation has been omitted since it's fundamentally slower than the helix rotation. The contrev rotation is the trinity rotation without auxiliary memory. 264 | 265 | While performance may vary depending on the specific implemention and array size, from worst to best the order is: 266 | 267 | * Juggling Rotation (juggler) 268 | * Auxiliary Rotation 269 | * Gries-Mills Rotation (griesmills) 270 | * Successive Rotation (piston) 271 | * Grail Rotation 272 | * Bridge Rotation (bridge) 273 | * Triple Reversal Rotation (reversal) 274 | * Helix Rotation (helix) 275 | * Conjoined Triple Reversal Rotation (contrev) 276 | * Trinity Rotation (trinity) 277 | 278 | It should be noted that the auxiliary Rotation performs better for smaller arrays and when the relative size difference between the two halves is large. 279 | 280 | The following benchmark was on WSL 2 gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04). The source code was compiled using `gcc -O3 bench.c`. Each test was ran 1,000 times with the time (in seconds) reported of the best and average run. 281 | 282 | ![rotation graph](/images/bridge_helix_trinity_reversal.png) 283 | 284 |
data table 285 | 286 | | Name | Items | Type | Best | Average | Loops | Samples | Distribution | 287 | | --------- | -------- | ---- | -------- | -------- | --------- | ------- | ---------------- | 288 | | bridge | 1000000 | 32 | 0.000389 | 0.000510 | 1 | 200 | 1/999999 | 289 | | helix | 1000000 | 32 | 0.000383 | 0.000457 | 1 | 200 | 1/999999 | 290 | | trinity | 1000000 | 32 | 0.000395 | 0.000482 | 1 | 200 | 1/999999 | 291 | | reversal | 1000000 | 32 | 0.000517 | 0.000617 | 1 | 200 | 1/999999 | 292 | | | | | | | | | | 293 | | bridge | 1000000 | 32 | 0.000385 | 0.000445 | 1 | 200 | 1000/999000 | 294 | | helix | 1000000 | 32 | 0.000487 | 0.000559 | 1 | 200 | 1000/999000 | 295 | | trinity | 1000000 | 32 | 0.000412 | 0.000469 | 1 | 200 | 1000/999000 | 296 | | reversal | 1000000 | 32 | 0.000507 | 0.000581 | 1 | 200 | 1000/999000 | 297 | | | | | | | | | | 298 | | bridge | 1000000 | 32 | 0.000456 | 0.000616 | 1 | 200 | 99999/900001 | 299 | | helix | 1000000 | 32 | 0.000543 | 0.000619 | 1 | 200 | 99999/900001 | 300 | | trinity | 1000000 | 32 | 0.000446 | 0.000551 | 1 | 200 | 99999/900001 | 301 | | reversal | 1000000 | 32 | 0.000519 | 0.000598 | 1 | 200 | 99999/900001 | 302 | | | | | | | | | | 303 | | bridge | 1000000 | 32 | 0.000495 | 0.000595 | 1 | 200 | 199998/800002 | 304 | | helix | 1000000 | 32 | 0.000572 | 0.000656 | 1 | 200 | 199998/800002 | 305 | | trinity | 1000000 | 32 | 0.000447 | 0.000513 | 1 | 200 | 199998/800002 | 306 | | reversal | 1000000 | 32 | 0.000519 | 0.000636 | 1 | 200 | 199998/800002 | 307 | | | | | | | | | | 308 | | bridge | 1000000 | 32 | 0.000557 | 0.000659 | 1 | 200 | 299997/700003 | 309 | | helix | 1000000 | 32 | 0.000519 | 0.000694 | 1 | 200 | 299997/700003 | 310 | | trinity | 1000000 | 32 | 0.000441 | 0.000544 | 1 | 200 | 299997/700003 | 311 | | reversal | 1000000 | 32 | 0.000515 | 0.000701 | 1 | 200 | 299997/700003 | 312 | | | | | | | | | | 313 | | bridge | 1000000 | 32 | 0.000527 | 0.000612 | 1 | 200 | 399996/600004 | 314 | | helix | 1000000 | 32 | 0.000481 | 0.000553 | 1 | 200 | 399996/600004 | 315 | | trinity | 1000000 | 32 | 0.000437 | 0.000506 | 1 | 200 | 399996/600004 | 316 | | reversal | 1000000 | 32 | 0.000506 | 0.000602 | 1 | 200 | 399996/600004 | 317 | | | | | | | | | | 318 | | bridge | 1000000 | 32 | 0.000394 | 0.000488 | 1 | 200 | 499995/500005 | 319 | | helix | 1000000 | 32 | 0.000669 | 0.000746 | 1 | 200 | 499995/500005 | 320 | | trinity | 1000000 | 32 | 0.000398 | 0.000498 | 1 | 200 | 499995/500005 | 321 | | reversal | 1000000 | 32 | 0.000511 | 0.000590 | 1 | 200 | 499995/500005 | 322 | 323 |
324 | 325 | ![rotation graph](/images/contrev_piston_griesmills_juggler.png) 326 | 327 |
data table 328 | 329 | | Name | Items | Type | Best | Average | Loops | Samples | Distribution | 330 | | --------- | -------- | ---- | -------- | -------- | --------- | ------- | ---------------- | 331 | | contrev | 1000000 | 32 | 0.000717 | 0.000840 | 1 | 200 | 1/999999 | 332 | | piston | 1000000 | 32 | 0.002091 | 0.002398 | 1 | 200 | 1/999999 | 333 | |griesmills | 1000000 | 32 | 0.002436 | 0.002565 | 1 | 200 | 1/999999 | 334 | | juggler | 1000000 | 32 | 0.000612 | 0.000701 | 1 | 200 | 1/999999 | 335 | | | | | | | | | | 336 | | contrev | 1000000 | 32 | 0.000416 | 0.000487 | 1 | 200 | 1000/999000 | 337 | | piston | 1000000 | 32 | 0.000474 | 0.000549 | 1 | 200 | 1000/999000 | 338 | |griesmills | 1000000 | 32 | 0.000490 | 0.000581 | 1 | 200 | 1000/999000 | 339 | | juggler | 1000000 | 32 | 0.001234 | 0.001339 | 1 | 200 | 1000/999000 | 340 | | | | | | | | | | 341 | | contrev | 1000000 | 32 | 0.000448 | 0.000512 | 1 | 200 | 99999/900001 | 342 | | piston | 1000000 | 32 | 0.000534 | 0.000682 | 1 | 200 | 99999/900001 | 343 | |griesmills | 1000000 | 32 | 0.000550 | 0.000619 | 1 | 200 | 99999/900001 | 344 | | juggler | 1000000 | 32 | 0.001279 | 0.001570 | 1 | 200 | 99999/900001 | 345 | | | | | | | | | | 346 | | contrev | 1000000 | 32 | 0.000446 | 0.000528 | 1 | 200 | 199998/800002 | 347 | | piston | 1000000 | 32 | 0.000564 | 0.000630 | 1 | 200 | 199998/800002 | 348 | |griesmills | 1000000 | 32 | 0.000578 | 0.000687 | 1 | 200 | 199998/800002 | 349 | | juggler | 1000000 | 32 | 0.001282 | 0.001783 | 1 | 200 | 199998/800002 | 350 | | | | | | | | | | 351 | | contrev | 1000000 | 32 | 0.000444 | 0.000517 | 1 | 200 | 299997/700003 | 352 | | piston | 1000000 | 32 | 0.000517 | 0.000626 | 1 | 200 | 299997/700003 | 353 | |griesmills | 1000000 | 32 | 0.000527 | 0.000612 | 1 | 200 | 299997/700003 | 354 | | juggler | 1000000 | 32 | 0.002259 | 0.002476 | 1 | 200 | 299997/700003 | 355 | | | | | | | | | | 356 | | contrev | 1000000 | 32 | 0.000431 | 0.000502 | 1 | 200 | 399996/600004 | 357 | | piston | 1000000 | 32 | 0.000505 | 0.000610 | 1 | 200 | 399996/600004 | 358 | |griesmills | 1000000 | 32 | 0.000509 | 0.000588 | 1 | 200 | 399996/600004 | 359 | | juggler | 1000000 | 32 | 0.001983 | 0.002230 | 1 | 200 | 399996/600004 | 360 | | | | | | | | | | 361 | | contrev | 1000000 | 32 | 0.000443 | 0.000543 | 1 | 200 | 499995/500005 | 362 | | piston | 1000000 | 32 | 0.000667 | 0.000755 | 1 | 200 | 499995/500005 | 363 | |griesmills | 1000000 | 32 | 0.000681 | 0.000776 | 1 | 200 | 499995/500005 | 364 | | juggler | 1000000 | 32 | 0.001304 | 0.001475 | 1 | 200 | 499995/500005 | 365 | 366 |
367 | 368 | Footnotes 369 | --------- 370 | 371 | [^1]: [A collection of array rotation algorithms, Igor van den Hoven, May 2021](https://raw.githubusercontent.com/scandum/rotate/ae113459f2f2ad236666f841f230ec13446e242e/src/rotate.h) 372 | [^2]: [Algorithm 284: Interchange of two blocks of data, William Fletcher and Roland Silver, May 1966](https://dl.acm.org/doi/10.1145/355592.365609) 373 | [^3]: [SWAPPING SECTIONS, David Gries and Harlan Mills, January 1981](https://ecommons.cornell.edu/bitstream/handle/1813/6292/81-452.pdf) 374 | [^4]: [The Holy Grail Sort Project](https://github.com/HolyGrailSortProject) 375 | -------------------------------------------------------------------------------- /images/auxiliary.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/auxiliary.gif -------------------------------------------------------------------------------- /images/bridge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/bridge.gif -------------------------------------------------------------------------------- /images/bridge_helix_trinity_reversal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/bridge_helix_trinity_reversal.png -------------------------------------------------------------------------------- /images/contrev_piston_griesmills_juggler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/contrev_piston_griesmills_juggler.png -------------------------------------------------------------------------------- /images/grail.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/grail.gif -------------------------------------------------------------------------------- /images/griesmills.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/griesmills.gif -------------------------------------------------------------------------------- /images/helix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/helix.gif -------------------------------------------------------------------------------- /images/juggling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/juggling.gif -------------------------------------------------------------------------------- /images/piston.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/piston.gif -------------------------------------------------------------------------------- /images/reversal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/reversal.gif -------------------------------------------------------------------------------- /images/trinity.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scandum/rotate/6d0d2d56d10454def027e35921890200b45fe82c/images/trinity.gif -------------------------------------------------------------------------------- /src/bench.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014-2021 Igor van den Hoven ivdhoven@gmail.com 3 | */ 4 | 5 | /* 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /* 27 | To compile use: 28 | 29 | gcc -O3 bench.c 30 | 31 | or 32 | 33 | g++ -O3 -w -fpermissive bench.c 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "rotate.h" 45 | 46 | long long utime() 47 | { 48 | struct timeval now_time; 49 | 50 | gettimeofday(&now_time, NULL); 51 | 52 | return now_time.tv_sec * 1000000LL + now_time.tv_usec; 53 | } 54 | 55 | typedef void ROTATEFUNC(int *array, size_t left, size_t right); 56 | 57 | void test_sort(void *array, void *unsorted, void *valid, int max, int samples, int repetitions, int left, int right, const char *name, char *desc, size_t size) 58 | { 59 | ROTATEFUNC *rotate; 60 | long long start, end, total, best, average; 61 | size_t rep, sam; 62 | int *pta = (int *) array, *ptv = (int *) valid, cnt; 63 | static int legend; 64 | 65 | if (*name == '*') 66 | { 67 | if (legend == 0) 68 | { 69 | legend = 1; 70 | 71 | printf("%s\n", "| Name | Items | Type | Best | Average | Loops | Samples | Distribution |"); 72 | printf("%s\n", "| --------- | -------- | ---- | -------- | -------- | --------- | ------- | ---------------- |"); 73 | } 74 | else 75 | { 76 | printf("%s\n", "| | | | | | | | |"); 77 | } 78 | return; 79 | } 80 | 81 | switch (name[0] + name[1] * 128 + name[2] * 16384) 82 | { 83 | case 'a' + 'u' * 128 + 'x' * 16384: 84 | rotate = auxiliary_rotation; 85 | break; 86 | 87 | case 'b' + 'r' * 128 + 'i' * 16384: 88 | rotate = bridge_rotation; 89 | break; 90 | 91 | case 'c' + 'o' * 128 + 'n' * 16384: 92 | rotate = contrev_rotation; 93 | break; 94 | 95 | case 'd' + 'r' * 128 + 'i' * 16384: 96 | rotate = drill_rotation; 97 | break; 98 | 99 | case 'g' + 'r' * 128 + 'a' * 16384: 100 | rotate = grail_rotation; 101 | break; 102 | 103 | case 'g' + 'r' * 128 + 'i' * 16384: 104 | rotate = griesmills_rotation; 105 | break; 106 | 107 | case 'h' + 'e' * 128 + 'l' * 16384: 108 | rotate = helix_rotation; 109 | break; 110 | 111 | case 'j' + 'u' * 128 + 'g' * 16384: 112 | rotate = juggling_rotation; 113 | break; 114 | 115 | case 'p' + 'i' * 128 + 's' * 16384: 116 | rotate = piston_rotation; 117 | break; 118 | 119 | case 'r' + 'e' * 128 + 'v' * 16384: 120 | rotate = reversal_rotation; 121 | break; 122 | 123 | case 't' + 'r' * 128 + 'i' * 16384: 124 | rotate = trinity_rotation; 125 | break; 126 | 127 | default: 128 | printf("Unknown rotation: (%s). Valid rotations are: auxiliary, bridge, contrev, drill, grail, griesmills, helix, juggling, piston, reversal, trinity\n", name); 129 | return; 130 | } 131 | 132 | best = average = 0; 133 | 134 | for (sam = 0 ; sam < samples ; sam++) 135 | { 136 | total = 0; 137 | 138 | start = utime(); 139 | 140 | for (rep = 0 ; rep < repetitions ; rep++) 141 | { 142 | memcpy(array, unsorted, max * size); 143 | 144 | rotate(array, left, right); 145 | } 146 | end = utime(); 147 | 148 | total = end - start; 149 | 150 | if (!best || total < best) 151 | { 152 | best = total; 153 | } 154 | average += total; 155 | } 156 | 157 | average /= samples; 158 | 159 | printf("|%10s | %8d | %4d | %f | %f | %9d | %7d | %16s |\n", name, max, (int) size * 8, best / 1000000.0, average / 1000000.0, repetitions, samples, desc); 160 | 161 | for (cnt = 0 ; cnt < max ; cnt++) 162 | { 163 | if (pta[cnt] != ptv[cnt]) 164 | { 165 | printf(" validate: array[%d] != valid[%d]. (%d vs %d\n", cnt, cnt, pta[cnt], ptv[cnt]); 166 | break; 167 | } 168 | } 169 | } 170 | 171 | int main(int argc, char **argv) 172 | { 173 | int max = 1000000; 174 | int samples = 200; 175 | int repetitions = 1; 176 | int seed = 0; 177 | int cnt, left, right, index; 178 | int *a_array, *r_array, *v_array; 179 | char dist[40], *sorts[] = { "*", "bridge", "helix", "trinity", "reversal" }; 180 | // char dist[40], *sorts[] = { "*", "contrev", "piston", "griesmills", "juggler" }; 181 | // char dist[40], *sorts[] = { "*", "auxiliary", "bridge", "contrev", "drill", "grail", "griesmills", "helix", "juggling", "piston", "reversal", "trinity" }; 182 | 183 | if (argc >= 1 && argv[1] && *argv[1]) 184 | { 185 | max = atoi(argv[1]); 186 | } 187 | 188 | if (argc >= 2 && argv[2] && *argv[2]) 189 | { 190 | samples = atoi(argv[2]); 191 | } 192 | 193 | if (argc >= 3 && argv[3] && *argv[3]) 194 | { 195 | repetitions = atoi(argv[3]); 196 | } 197 | 198 | if (argc >= 4 && argv[4] && *argv[4]) 199 | { 200 | seed = atoi(argv[4]); 201 | } 202 | 203 | printf("Benchmark: array size: %d, samples: %d, repetitions: %d, seed: %d\n\n", max, samples, repetitions, seed); 204 | 205 | // 32 bit 206 | 207 | a_array = (int *) malloc(max * sizeof(int)); 208 | r_array = (int *) malloc(max * sizeof(int)); 209 | v_array = (int *) malloc(max * sizeof(int)); 210 | 211 | for (cnt = 0 ; cnt < max ; cnt++) 212 | { 213 | r_array[cnt] = cnt; 214 | } 215 | 216 | int values[] = { 1, 1000, 99999, 199998, 299997, 399996, 499995, 0}; 217 | 218 | for (index = 0 ; values[index] != 0 ; index++) 219 | { 220 | left = values[index]; 221 | 222 | right = max - left; 223 | 224 | memcpy(v_array, r_array, max * sizeof(int)); 225 | 226 | auxiliary_rotation(v_array, left, right); 227 | 228 | sprintf(dist, "%d/%d", left, right); 229 | 230 | for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++) 231 | { 232 | test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int)); 233 | } 234 | } 235 | 236 | for (left = 1 ; left <= 9 ; left ++) 237 | { 238 | right = max - left; 239 | 240 | memcpy(v_array, r_array, max * sizeof(int)); 241 | 242 | auxiliary_rotation(v_array, left, right); 243 | 244 | sprintf(dist, "%d/%d", left, right); 245 | 246 | for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++) 247 | { 248 | test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int)); 249 | } 250 | } 251 | 252 | for (left = max / 3 ; left < max / 3 + 5 ; left++) 253 | { 254 | right = max - left; 255 | 256 | memcpy(v_array, r_array, max * sizeof(int)); 257 | 258 | auxiliary_rotation(v_array, left, right); 259 | 260 | sprintf(dist, "%d/%d", left, right); 261 | 262 | for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++) 263 | { 264 | test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int)); 265 | } 266 | } 267 | 268 | for (left = max / 2 ; left < max / 2 + 9 ; left++) 269 | { 270 | right = max - left; 271 | 272 | memcpy(v_array, r_array, max * sizeof(int)); 273 | 274 | auxiliary_rotation(v_array, left, right); 275 | 276 | sprintf(dist, "%d/%d", left, right); 277 | 278 | for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++) 279 | { 280 | test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int)); 281 | } 282 | } 283 | 284 | for (left = max * 10 / 100 - 1 ; left < max ; left += max * 10 / 100 - 1) 285 | { 286 | right = max - left; 287 | 288 | memcpy(v_array, r_array, max * sizeof(int)); 289 | 290 | auxiliary_rotation(v_array, left, right); 291 | 292 | sprintf(dist, "%d/%d", left, right); 293 | 294 | for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++) 295 | { 296 | test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int)); 297 | } 298 | } 299 | 300 | free(a_array); 301 | free(r_array); 302 | free(v_array); 303 | 304 | return 0; 305 | } 306 | -------------------------------------------------------------------------------- /src/rotate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2021 Igor van den Hoven ivdhoven@gmail.coms 3 | */ 4 | 5 | /* 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | /* 27 | rotate 1.2 28 | */ 29 | 30 | #ifndef ROTATE_H 31 | #define ROTATE_H 32 | 33 | void outsidein_reversal(int *array, size_t block_size) 34 | { 35 | int *pta, *ptb, swap; 36 | 37 | pta = array; 38 | ptb = array + block_size; 39 | 40 | block_size /= 2; 41 | 42 | while (block_size--) 43 | { 44 | swap = *pta; *pta++ = *--ptb; *ptb = swap; 45 | } 46 | } 47 | 48 | void insideout_reversal(int *array, size_t block_size) 49 | { 50 | int *pta, *ptb, swap; 51 | 52 | ptb = array + block_size; 53 | 54 | block_size /= 2; 55 | 56 | pta = array + block_size; 57 | ptb -= block_size; 58 | 59 | while (block_size--) 60 | { 61 | swap = *--pta; *pta = *ptb; *ptb++ = swap; 62 | } 63 | } 64 | 65 | void forward_block_swap(int *array, const size_t start1, const size_t start2, size_t block_size) 66 | { 67 | int *pta, *ptb, swap; 68 | 69 | pta = array + start1; 70 | ptb = array + start2; 71 | 72 | while (block_size--) 73 | { 74 | swap = *pta; *pta++ = *ptb; *ptb++ = swap; 75 | } 76 | } 77 | 78 | void backward_block_swap(int *array, const size_t start1, const size_t start2, size_t block_size) 79 | { 80 | int *pta, *ptb, swap; 81 | 82 | pta = array + start1 + block_size; 83 | ptb = array + start2 + block_size; 84 | 85 | while (block_size--) 86 | { 87 | swap = *--pta; *pta = *--ptb; *ptb = swap; 88 | } 89 | } 90 | 91 | void auxiliary_rotation(int *array, size_t left, size_t right) 92 | { 93 | int *pta, *ptb, *ptc, *swap; 94 | 95 | pta = array; 96 | ptb = array + left; 97 | ptc = array + right; 98 | 99 | if (left < right) 100 | { 101 | swap = malloc(left * sizeof(int)); 102 | 103 | memcpy(swap, pta, left * sizeof(int)); 104 | 105 | memmove(pta, ptb, right * sizeof(int)); 106 | 107 | memcpy(ptc, swap, left * sizeof(int)); 108 | } 109 | else 110 | { 111 | swap = malloc(right * sizeof(int)); 112 | 113 | memcpy(swap, ptb, right * sizeof(int)); 114 | 115 | memmove(ptc, pta, left * sizeof(int)); 116 | 117 | memcpy(pta, swap, right * sizeof(int)); 118 | } 119 | free(swap); 120 | } 121 | 122 | void stack_rotation(int *array, size_t left, size_t right) 123 | { 124 | int *pta, *ptb, *ptc, swap[8]; 125 | 126 | pta = array; 127 | ptb = array + left; 128 | ptc = array + right; 129 | 130 | if (left < right) 131 | { 132 | memcpy(swap, pta, left * sizeof(int)); 133 | 134 | memmove(pta, ptb, right * sizeof(int)); 135 | 136 | memcpy(ptc, swap, left * sizeof(int)); 137 | } 138 | else 139 | { 140 | memcpy(swap, ptb, right * sizeof(int)); 141 | 142 | memmove(ptc, pta, left * sizeof(int)); 143 | 144 | memcpy(pta, swap, right * sizeof(int)); 145 | } 146 | } 147 | 148 | // 3 reversal - Origin unknown, but prior to 1981 149 | 150 | void reversal_rotation(int *array, size_t left, size_t right) 151 | { 152 | outsidein_reversal(array, left); 153 | outsidein_reversal(array + left, right); 154 | outsidein_reversal(array, left + right); 155 | } 156 | 157 | // 2021 - Bridge rotation by Igor van den Hoven 158 | 159 | void bridge_rotation(int *array, size_t left, size_t right) 160 | { 161 | int *pta, *ptb, *ptc, *ptd, *swap; 162 | 163 | pta = array; 164 | ptb = pta + left; 165 | ptc = pta + right; 166 | ptd = ptc + left; 167 | 168 | if (left < right) 169 | { 170 | size_t bridge = right - left; 171 | 172 | if (bridge < left) 173 | { 174 | swap = malloc(bridge * sizeof(int)); 175 | 176 | memcpy(swap, ptb, bridge * sizeof(int)); 177 | 178 | while (left--) 179 | { 180 | *--ptc = *--ptd; *ptd = *--ptb; 181 | } 182 | memcpy(pta, swap, bridge * sizeof(int)); 183 | } 184 | else 185 | { 186 | swap = malloc(left * sizeof(int)); 187 | memcpy(swap, pta, left * sizeof(int)); 188 | memmove(pta, ptb, right * sizeof(int)); 189 | memcpy(ptc, swap, left * sizeof(int)); 190 | } 191 | } 192 | else if (right < left) 193 | { 194 | size_t bridge = left - right; 195 | 196 | if (bridge < right) 197 | { 198 | swap = malloc(bridge * sizeof(int)); 199 | 200 | memcpy(swap, ptc, bridge * sizeof(int)); 201 | 202 | while (right--) 203 | { 204 | *ptc++ = *pta; *pta++ = *ptb++; 205 | } 206 | memcpy(ptd - bridge, swap, bridge * sizeof(int)); 207 | } 208 | else 209 | { 210 | swap = malloc(right * sizeof(int)); 211 | memcpy(swap, ptb, right * sizeof(int)); 212 | memmove(ptc, pta, left * sizeof(int)); 213 | memcpy(pta, swap, right * sizeof(int)); 214 | } 215 | } 216 | else 217 | { 218 | swap = malloc(1 * sizeof(int)); 219 | 220 | while (left--) 221 | { 222 | *swap = *pta; *pta++ = *ptb; *ptb++ = *swap; 223 | } 224 | } 225 | free(swap); 226 | } 227 | 228 | // 2021 - Conjoined Triple Reversal rotation by Igor van den Hoven 229 | 230 | void contrev_rotation(int *array, size_t left, size_t right) 231 | { 232 | int *pta, *ptb, *ptc, *ptd, swap; 233 | size_t loop; 234 | 235 | pta = array; 236 | ptb = array + left; 237 | ptc = array + left; 238 | ptd = array + left + right; 239 | 240 | if (left > right) 241 | { 242 | loop = right / 2; 243 | 244 | while (loop--) 245 | { 246 | swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = swap; 247 | } 248 | 249 | loop = (ptb - pta) / 2; 250 | 251 | while (loop--) 252 | { 253 | swap = *--ptb; *ptb = *pta; *pta++ = *--ptd; *ptd = swap; 254 | } 255 | loop = (ptd - pta) / 2; 256 | 257 | while (loop--) 258 | { 259 | swap = *pta; *pta++ = *--ptd; *ptd = swap; 260 | } 261 | } 262 | else if (left < right) 263 | { 264 | loop = left / 2; 265 | 266 | while (loop--) 267 | { 268 | swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = swap; 269 | } 270 | 271 | loop = (ptd - ptc) / 2; 272 | 273 | while (loop--) 274 | { 275 | swap = *ptc; *ptc++ = *--ptd; *ptd = *pta; *pta++ = swap; 276 | } 277 | loop = (ptd - pta) / 2; 278 | 279 | while (loop--) 280 | { 281 | swap = *pta; *pta++ = *--ptd; *ptd = swap; 282 | } 283 | } 284 | else 285 | { 286 | loop = left; 287 | 288 | while (loop--) 289 | { 290 | swap = *pta; *pta++ = *ptb; *ptb++ = swap; 291 | } 292 | } 293 | } 294 | 295 | // 2021 - Trinity rotation by Igor van den Hoven (Conjoined Triple Reversal + Bridge rotation) 296 | 297 | #define MAX_AUX 8 298 | 299 | void trinity_rotation(int *array, size_t left, size_t right) 300 | { 301 | int *pta, *ptb, *ptc, *ptd, swap[MAX_AUX]; 302 | size_t loop; 303 | 304 | if (left < right) 305 | { 306 | if (left <= MAX_AUX) 307 | { 308 | memcpy(swap, array, left * sizeof(int)); 309 | memmove(array, array + left, right * sizeof(int)); 310 | memcpy(array + right, swap, left * sizeof(int)); 311 | } 312 | else 313 | { 314 | pta = array; 315 | ptb = pta + left; 316 | 317 | loop = right - left; 318 | 319 | if (loop <= MAX_AUX && loop > 3) 320 | { 321 | ptc = pta + right; 322 | ptd = ptc + left; 323 | 324 | memcpy(swap, ptb, loop * sizeof(int)); 325 | 326 | while (left--) 327 | { 328 | *--ptc = *--ptd; *ptd = *--ptb; 329 | } 330 | memcpy(pta, swap, loop * sizeof(int)); 331 | } 332 | else 333 | { 334 | ptc = ptb; 335 | ptd = ptc + right; 336 | 337 | loop = left / 2; 338 | 339 | while (loop--) 340 | { 341 | *swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = *swap; 342 | } 343 | 344 | loop = (ptd - ptc) / 2; 345 | 346 | while (loop--) 347 | { 348 | *swap = *ptc; *ptc++ = *--ptd; *ptd = *pta; *pta++ = *swap; 349 | } 350 | 351 | loop = (ptd - pta) / 2; 352 | 353 | while (loop--) 354 | { 355 | *swap = *pta; *pta++ = *--ptd; *ptd = *swap; 356 | } 357 | } 358 | } 359 | } 360 | else if (right < left) 361 | { 362 | if (right <= MAX_AUX) 363 | { 364 | memcpy(swap, array + left, right * sizeof(int)); 365 | memmove(array + right, array, left * sizeof(int)); 366 | memcpy(array, swap, right * sizeof(int)); 367 | } 368 | else 369 | { 370 | pta = array; 371 | ptb = pta + left; 372 | 373 | loop = left - right; 374 | 375 | if (loop <= MAX_AUX && loop > 3) 376 | { 377 | ptc = pta + right; 378 | ptd = ptc + left; 379 | 380 | memcpy(swap, ptc, loop * sizeof(int)); 381 | 382 | while (right--) 383 | { 384 | *ptc++ = *pta; *pta++ = *ptb++; 385 | } 386 | memcpy(ptd - loop, swap, loop * sizeof(int)); 387 | } 388 | else 389 | { 390 | ptc = ptb; 391 | ptd = ptc + right; 392 | 393 | loop = right / 2; 394 | 395 | while (loop--) 396 | { 397 | *swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = *swap; 398 | } 399 | 400 | loop = (ptb - pta) / 2; 401 | 402 | while (loop--) 403 | { 404 | *swap = *--ptb; *ptb = *pta; *pta++ = *--ptd; *ptd = *swap; 405 | } 406 | 407 | loop = (ptd - pta) / 2; 408 | 409 | while (loop--) 410 | { 411 | *swap = *pta; *pta++ = *--ptd; *ptd = *swap; 412 | } 413 | } 414 | } 415 | } 416 | else 417 | { 418 | pta = array; 419 | ptb = pta + left; 420 | 421 | while (left--) 422 | { 423 | *swap = *pta; *pta++ = *ptb; *ptb++ = *swap; 424 | } 425 | } 426 | } 427 | 428 | #undef MAX_AUX 429 | 430 | // 1981 - Gries-Mills rotation by David Gries and Harlan Mills 431 | 432 | void griesmills_rotation(int *array, size_t left, size_t right) 433 | { 434 | size_t start = 0; 435 | 436 | while (left && right) 437 | { 438 | if (left <= right) 439 | { 440 | do 441 | { 442 | forward_block_swap(array, start, start + left, left); 443 | 444 | start += left; 445 | right -= left; 446 | } 447 | while (left <= right); 448 | } 449 | else 450 | { 451 | do 452 | { 453 | forward_block_swap(array, start + left - right, start + left, right); 454 | 455 | left -= right; 456 | } 457 | while (right <= left); 458 | } 459 | } 460 | } 461 | 462 | // 2020 - Grail rotation by the Holy Grail Sort project (Gries-Mills derived) 463 | 464 | void grail_rotation(int *array, size_t left, size_t right) 465 | { 466 | size_t min = left <= right ? left : right; 467 | size_t start = 0; 468 | 469 | while (min > 1) 470 | { 471 | if (left <= right) 472 | { 473 | do 474 | { 475 | forward_block_swap(array, start, start + left, left); 476 | 477 | start += left; 478 | right -= left; 479 | } 480 | while (left <= right); 481 | 482 | min = right; 483 | } 484 | else 485 | { 486 | do 487 | { 488 | backward_block_swap(array, start + left - right, start + left, right); 489 | 490 | left -= right; 491 | } 492 | while (right <= left); 493 | 494 | min = left; 495 | } 496 | } 497 | 498 | if (min) 499 | { 500 | stack_rotation(array + start, left, right); 501 | } 502 | } 503 | 504 | // 2021 - Piston rotation by Igor van den Hoven. Based on the successive swap described by Gries and Mills in 1981. 505 | 506 | void piston_rotation(int *array, size_t left, size_t right) 507 | { 508 | size_t start = 0; 509 | 510 | while (left > 0) 511 | { 512 | while (left <= right) 513 | { 514 | forward_block_swap(array, start, start + right, left); 515 | right -= left; 516 | } 517 | if (right <= 0) 518 | { 519 | break; 520 | } 521 | do 522 | { 523 | forward_block_swap(array, start, start + left, right); 524 | left -= right; 525 | start += right; 526 | } 527 | while (right <= left); 528 | } 529 | 530 | /* if (left && right) 531 | { 532 | stack_rotation(array + start, left, right); 533 | }*/ 534 | } 535 | 536 | // 2021 - Helix rotation by Control (grail derived) 537 | 538 | void helix_rotation(int *array, size_t left, size_t right) 539 | { 540 | int swap; 541 | size_t start = 0; 542 | size_t end = left + right; 543 | size_t mid = left; 544 | 545 | while (1) 546 | { 547 | if (left > right) 548 | { 549 | if (right <= 1) 550 | { 551 | break; 552 | } 553 | 554 | while (mid > start) 555 | { 556 | swap = array[--mid]; array[mid] = array[--end]; array[end] = swap; 557 | } 558 | mid += (left %= right); 559 | right = end - mid; 560 | } 561 | else 562 | { 563 | if (left <= 1) 564 | { 565 | break; 566 | } 567 | 568 | while (mid < end) 569 | { 570 | swap = array[mid]; array[mid++] = array[start]; array[start++] = swap; 571 | } 572 | mid -= (right %= left); 573 | left = mid - start; 574 | } 575 | } 576 | 577 | if (left && right) 578 | { 579 | stack_rotation(array + start, left, right); 580 | } 581 | } 582 | 583 | // 2021 - Drill rotation by Igor van den Hoven (grail derived with piston and helix loops) 584 | 585 | void drill_rotation(int *array, size_t left, size_t right) 586 | { 587 | int swap; 588 | size_t start = 0; 589 | size_t end = left + right; 590 | size_t mid = left; 591 | size_t loop; 592 | 593 | while (left > 1) 594 | { 595 | if (left <= right) 596 | { 597 | loop = end - mid - (right %= left); 598 | 599 | do 600 | { 601 | swap = array[mid]; array[mid++] = array[start]; array[start++] = swap; 602 | } 603 | while (--loop); 604 | } 605 | 606 | if (right <= 1) 607 | { 608 | break; 609 | } 610 | 611 | loop = mid - start - (left %= right); 612 | 613 | do 614 | { 615 | swap = array[--mid]; array[mid] = array[--end]; array[end] = swap; 616 | } 617 | while (--loop); 618 | } 619 | 620 | if (left && right) 621 | { 622 | stack_rotation(array + start, left, right); 623 | } 624 | } 625 | 626 | // 1965 - Juggling aka Dolphin rotation 627 | 628 | int gcd(int a, int b) 629 | { 630 | int r; 631 | 632 | while (b) 633 | { 634 | r = a % b; 635 | a = b; 636 | b = r; 637 | } 638 | return a; 639 | } 640 | 641 | void juggling_rotation(int *array, size_t left, size_t right) 642 | { 643 | int *pta, *ptb, *ptc, *ptd, swap; 644 | const size_t nmemb = left + right; 645 | 646 | if (left == 0) 647 | { 648 | return; 649 | } 650 | 651 | ptd = array + gcd(left, nmemb); 652 | 653 | for (ptc = array ; ptc < ptd ; ptc++) 654 | { 655 | swap = *ptc; 656 | pta = ptc; 657 | 658 | while (1) 659 | { 660 | ptb = pta + left; 661 | 662 | if (ptb >= array + nmemb) 663 | { 664 | ptb -= nmemb; 665 | 666 | if (ptb == ptc) 667 | { 668 | break; 669 | } 670 | } 671 | *pta = *ptb; 672 | pta = ptb; 673 | } 674 | *pta = swap; 675 | } 676 | } 677 | 678 | #endif 679 | --------------------------------------------------------------------------------