59
59
2016, Denver, CO, USA, pages 57-58, New York, NY, USA: ACM.
60
60
ISBN: 978-1-4503-4323-7. https://doi.org/10.1145/2908961.2909001
61
61
"""
62
- from typing import Callable , Final
62
+ from typing import Final
63
63
64
64
import numba # type: ignore
65
65
import numpy as np
69
69
70
70
71
71
@numba .njit (cache = True , inline = "always" , fastmath = True , boundscheck = False )
72
- def try_single_rotate ( arr : np . ndarray , i1 : int , i2 : int ) -> bool : # +book
72
+ def rotate ( random : Generator , dest : np . ndarray , x : np . ndarray ) -> None :
73
73
"""
74
- Rotate a portion of an array to the left or right in place.
74
+ Copy `x` into `dest` and then rotate a subsequence by one step.
75
+
76
+ The function repeatedly tries to rotate a portion of an array to the left
77
+ or right in place. It will continue trying until something changed.
78
+ In each step, it draws two indices `i1` and `i2`.
75
79
76
80
If `i1 < i2`, then a left rotation by one step is performed. In other
77
81
words, the element at index `i1 + 1` goes to index `i1`, the element at
78
82
index `i1 + 2` goes to index `i1 + 1`, and so on. The lst element, i.e.,
79
83
the one at index `i2` goes to index `i2 - 1`. Finally, the element that
80
84
originally was at index `i1` goes to index `i2`. If any element in the
81
- array has changed, this function returns `False` , otherwise `True` .
85
+ array has changed, this function is done , otherwise it tries again .
82
86
83
87
If `i1 > i2`, then a right rotation by one step is performed. In other
84
88
words, the element at index `i1 - 1` goes to index `i1`, the element at
85
89
index `i1 - 2` goes to index `i1 - 1`, and so on. Finally, the element
86
90
that originally was at index `i1` goes to index `i2`. If any element in
87
- the array has changed, this function returns `False` , otherwise `True` .
91
+ the array has changed, this function tries again , otherwise it stops .
88
92
89
93
This corresponds to extracting the element at index `i1` and re-inserting
90
94
it at index `i2`.
91
95
92
- :param arr: the array to rotate
93
- :param i1: the start index, in `0..len(arr)-1`
94
- :param i2: the end index, in `0..len(arr)-1`
95
- :returns: whether the array was *unchanged*
96
- :retval False: if the array `arr` is now different from before
97
- :retval True: if the array `arr` has not changed
98
-
99
- >>> import numpy as npx
100
- >>> dest = npx.array(range(10))
101
- >>> print(dest)
102
- [0 1 2 3 4 5 6 7 8 9]
103
- >>> try_single_rotate(dest, 3, 4)
104
- False
105
- >>> print(dest)
106
- [0 1 2 4 3 5 6 7 8 9]
107
- >>> try_single_rotate(dest, 3, 4)
108
- False
109
- >>> print(dest)
110
- [0 1 2 3 4 5 6 7 8 9]
111
- >>> try_single_rotate(dest, 4, 3)
112
- False
113
- >>> print(dest)
114
- [0 1 2 4 3 5 6 7 8 9]
115
- >>> try_single_rotate(dest, 4, 3)
116
- False
117
- >>> print(dest)
118
- [0 1 2 3 4 5 6 7 8 9]
119
- >>> try_single_rotate(dest, 3, 6)
120
- False
121
- >>> print(dest)
122
- [0 1 2 4 5 6 3 7 8 9]
123
- >>> try_single_rotate(dest, 6, 3)
124
- False
125
- >>> print(dest)
126
- [0 1 2 3 4 5 6 7 8 9]
127
- >>> try_single_rotate(dest, 0, len(dest) - 1)
128
- False
129
- >>> print(dest)
130
- [1 2 3 4 5 6 7 8 9 0]
131
- >>> try_single_rotate(dest, len(dest) - 1, 0)
132
- False
133
- >>> print(dest)
134
- [0 1 2 3 4 5 6 7 8 9]
135
- >>> try_single_rotate(dest, 7, 7)
136
- True
137
- >>> dest = np.array([0, 1, 2, 3, 3, 3, 3, 3, 8, 9])
138
- >>> try_single_rotate(dest, 7, 7)
139
- True
140
- >>> try_single_rotate(dest, 4, 6)
141
- True
142
- >>> print(dest)
143
- [0 1 2 3 3 3 3 3 8 9]
144
- >>> try_single_rotate(dest, 6, 4)
145
- True
146
- >>> print(dest)
147
- [0 1 2 3 3 3 3 3 8 9]
148
- >>> try_single_rotate(dest, 4, 7)
149
- True
150
- >>> print(dest)
151
- [0 1 2 3 3 3 3 3 8 9]
152
- >>> try_single_rotate(dest, 6, 7)
153
- True
154
- >>> print(dest)
155
- [0 1 2 3 3 3 3 3 8 9]
156
- >>> try_single_rotate(dest, 4, 8)
157
- False
158
- >>> print(dest)
159
- [0 1 2 3 3 3 3 8 3 9]
160
- >>> try_single_rotate(dest, 8, 4)
161
- False
162
- >>> print(dest)
163
- [0 1 2 3 3 3 3 3 8 9]
164
- >>> try_single_rotate(dest, 9, 4)
165
- False
166
- >>> print(dest)
167
- [0 1 2 3 9 3 3 3 3 8]
168
- >>> try_single_rotate(dest, 4, 9)
169
- False
170
- >>> print(dest)
171
- [0 1 2 3 3 3 3 3 8 9]
172
- """
173
- # start book
174
- if i1 == i2 : # nothing to be done
175
- return True # array will not be changed
176
-
177
- unchanged : bool = True # initially, assume that there is no change
178
-
179
- if i1 < i2 : # rotate to the left: move elements to lower indices?
180
- first = arr [i1 ] # get the element to be removed
181
- while i1 < i2 : # iterate the indices
182
- i3 = i1 + 1 # get next higher index
183
- cpy = arr [i3 ] # get next element at that higher index
184
- unchanged = unchanged and (cpy == arr [i1 ]) # is a change?
185
- arr [i1 ] = cpy # store next element at the lower index
186
- i1 = i3 # move to next higher index
187
- unchanged = unchanged and (first == arr [i2 ]) # check if change
188
- arr [i2 ] = first # store removed element at highest index
189
- return unchanged # return True if something changed, else False
190
-
191
- last = arr [i1 ] # last element; rotate right: move elements up
192
- while i2 < i1 : # iterate over indices
193
- i3 = i1 - 1 # get next lower index
194
- cpy = arr [i3 ] # get element at that lower index
195
- unchanged = unchanged and (cpy == arr [i1 ]) # is a change?
196
- arr [i1 ] = cpy # store element at higher index
197
- i1 = i3 # move to next lower index
198
- unchanged = unchanged and (last == arr [i2 ]) # check if change
199
- arr [i2 ] = last # store removed element at lowest index
200
- return unchanged # return True if something changed, else False
201
- # end book
202
-
203
-
204
- # Temporary fix for https://github.com/numba/numba/issues/9103
205
- def rotate (random : Generator , dest : np .ndarray , # +book
206
- x : np .ndarray ) -> None : # +book
207
- """
208
- Copy `x` into `dest` and then rotate a subsequence by one step.
209
-
210
96
:param random: the random number generator
211
97
:param dest: the array to receive the modified copy of `x`
212
98
:param x: the existing point in the search space
@@ -227,14 +113,37 @@ def rotate(random: Generator, dest: np.ndarray, # +book
227
113
>>> print(out)
228
114
[0 1 2 3 4 8 5 6 7 9]
229
115
"""
230
- # start book
231
116
dest [:] = x [:]
232
117
length : Final [int ] = len (dest ) # Get the length of `dest`.
233
- rint : Callable [[int , int ], int ] = random .integers # fast call
234
-
118
+ unchanged : bool = True
235
119
# try to rotate the dest array until something changes
236
- while try_single_rotate (dest , rint (0 , length ), rint (0 , length )):
237
- pass # do nothing in the loop, but try rotating again
120
+ while unchanged :
121
+ i1 : int = random .integers (0 , length )
122
+ i2 : int = random .integers (0 , length )
123
+ if i1 == i2 : # nothing to be done
124
+ continue # array will not be changed
125
+
126
+ if i1 < i2 : # rotate to the left: move elements to lower indices?
127
+ first = dest [i1 ] # get the element to be removed
128
+ while i1 < i2 : # iterate the indices
129
+ i3 = i1 + 1 # get next higher index
130
+ cpy = dest [i3 ] # get next element at that higher index
131
+ unchanged &= (cpy == dest [i1 ]) # is a change?
132
+ dest [i1 ] = cpy # store next element at the lower index
133
+ i1 = i3 # move to next higher index
134
+ unchanged &= (first == dest [i2 ]) # check if change
135
+ dest [i2 ] = first # store removed element at highest index
136
+ continue
137
+
138
+ last = dest [i1 ] # last element; rotate right: move elements up
139
+ while i2 < i1 : # iterate over indices
140
+ i3 = i1 - 1 # get next lower index
141
+ cpy = dest [i3 ] # get element at that lower index
142
+ unchanged &= (cpy == dest [i1 ]) # is a change?
143
+ dest [i1 ] = cpy # store element at higher index
144
+ i1 = i3 # move to next lower index
145
+ unchanged &= (last == dest [i2 ]) # check if change
146
+ dest [i2 ] = last # store removed element at lowest index
238
147
239
148
240
149
class Op1Insert1 (Op1 ):
@@ -254,7 +163,6 @@ def __init__(self) -> None:
254
163
"""Initialize the object."""
255
164
super ().__init__ ()
256
165
self .op1 = rotate # type: ignore # use function directly
257
- # end book
258
166
259
167
def __str__ (self ) -> str :
260
168
"""
0 commit comments