1 # a "yield" version of the REMAP algorithm. a little easier to read
2 # than the Finite State Machine version
4 # python "yield" can be iterated. use this to make it clear how
5 # the indices are generated by using natural-looking nested loops
6 def iterate_indices(SVSHAPE):
7 # get indices to iterate over, in the required order
8 xd = SVSHAPE.lims[0]
9 yd = SVSHAPE.lims[1]
10 zd = SVSHAPE.lims[2]
11 # create lists of indices to iterate over in each dimension
12 x_r = list(range(xd))
13 y_r = list(range(yd))
14 z_r = list(range(zd))
15 # invert the indices if needed
16 if SVSHAPE.invxyz[0]: x_r.reverse()
17 if SVSHAPE.invxyz[1]: y_r.reverse()
18 if SVSHAPE.invxyz[2]: z_r.reverse()
19 # start an infinite (wrapping) loop
20 step = 0 # track src/dst step
21 while True:
22 for z in z_r: # loop over 1st order dimension
23 z_end = z == z_r[-1]
24 for y in y_r: # loop over 2nd order dimension
25 y_end = y == y_r[-1]
26 for x in x_r: # loop over 3rd order dimension
27 x_end = x == x_r[-1]
28 # ok work out which order to construct things in.
29 # start by creating a list of tuples of the dimension
30 # and its limit
31 vals = [(SVSHAPE.lims[0], x, "x"),
32 (SVSHAPE.lims[1], y, "y"),
33 (SVSHAPE.lims[2], z, "z")
34 ]
35 # now select those by order. this allows us to
36 # create schedules for [z][x], [x][y], or [y][z]
37 # for matrix multiply.
38 vals = [vals[SVSHAPE.order[0]],
39 vals[SVSHAPE.order[1]],
40 vals[SVSHAPE.order[2]]
41 ]
42 # ok now we can construct the result, using bits of
43 # "order" to say which ones get stacked on
44 result = 0
45 mult = 1
46 for i in range(3):
47 lim, idx, dbg = vals[i]
48 # some of the dimensions can be "skipped". the order
49 # was actually selected above on all 3 dimensions,
50 # e.g. [z][x][y] or [y][z][x]. "skip" allows one of
51 # those to be knocked out
52 if SVSHAPE.skip == i+1: continue
53 #print ("select %d %s" % (i, dbg))
54 idx *= mult # shifts up by previous dimension(s)
55 result += idx # adds on this dimension
56 mult *= lim # for the next dimension
58 loopends = (x_end |
59 ((y_end and x_end)<<1) |
60 ((y_end and x_end and z_end)<<2))
62 if hasattr(SVSHAPE, "postprocess"): # for Indexed mode
63 result = SVSHAPE.postprocess(result, step)
64 yield result + SVSHAPE.offset, loopends
65 step += 1
67 def demo():
68 # set the dimension sizes here
69 xdim = 3
70 ydim = 2
71 zdim = 4
73 # set total (can repeat, e.g. VL=x*y*z*4)
74 VL = xdim * ydim * zdim
76 # set up an SVSHAPE
77 class SVSHAPE:
78 pass
79 SVSHAPE0 = SVSHAPE()
80 SVSHAPE0.lims = [xdim, ydim, zdim]
81 SVSHAPE0.order = [1,0,2] # experiment with different permutations, here
82 SVSHAPE0.mode = 0b00
83 SVSHAPE0.skip = 0b00
84 SVSHAPE0.offset = 0 # experiment with different offset, here
85 SVSHAPE0.invxyz = [0,0,0] # inversion if desired
87 # enumerate over the iterator function, getting new indices
88 for idx, (new_idx, end) in enumerate(iterate_indices(SVSHAPE0)):
89 if idx >= VL:
90 break
91 print ("%d->%d" % (idx, new_idx), "end", bin(end)[2:])
93 # run the demo
94 if __name__ == '__main__':
95 demo()