| SVM2 | I | # | 3.0B | svshape2 | REMAP shape instruction (2) |
| SVI | I | # | 3.0B | svindex | REMAP General-purpose Indexing |
+## REMAP 2D/3D Matrix pseudocode
+
+Written in python3 the following stand-alone executable source code is the Canonical
+Specification for Matrix (2D/3D) REMAP. Vectors of "loopends" are returned when Rc=1
+in Vectors of CR Fields on `sv.svstep.`, or a single CR Field CR0 on
+`svstep.` in Vertical-First Mode. The `SVSTATE.srcstep` or `SVSTATE.dststep` sequential
+offset is put through this algorithm to determine the actual Element Offset.
+
+```
+# python "yield" can be iterated. use this to make it clear how
+# the indices are generated by using natural-looking nested loops
+def iterate_indices(SVSHAPE):
+ # get indices to iterate over, in the required order
+ xd = SVSHAPE.lims[0]
+ yd = SVSHAPE.lims[1]
+ zd = SVSHAPE.lims[2]
+ # create lists of indices to iterate over in each dimension
+ x_r = list(range(xd))
+ y_r = list(range(yd))
+ z_r = list(range(zd))
+ # invert the indices if needed
+ if SVSHAPE.invxyz[0]: x_r.reverse()
+ if SVSHAPE.invxyz[1]: y_r.reverse()
+ if SVSHAPE.invxyz[2]: z_r.reverse()
+ # start an infinite (wrapping) loop
+ step = 0 # track src/dst step
+ while True:
+ for z in z_r: # loop over 1st order dimension
+ z_end = z == z_r[-1]
+ for y in y_r: # loop over 2nd order dimension
+ y_end = y == y_r[-1]
+ for x in x_r: # loop over 3rd order dimension
+ x_end = x == x_r[-1]
+ # ok work out which order to construct things in.
+ # start by creating a list of tuples of the dimension
+ # and its limit
+ vals = [(SVSHAPE.lims[0], x, "x"),
+ (SVSHAPE.lims[1], y, "y"),
+ (SVSHAPE.lims[2], z, "z")
+ ]
+ # now select those by order. this allows us to
+ # create schedules for [z][x], [x][y], or [y][z]
+ # for matrix multiply.
+ vals = [vals[SVSHAPE.order[0]],
+ vals[SVSHAPE.order[1]],
+ vals[SVSHAPE.order[2]]
+ ]
+ # ok now we can construct the result, using bits of
+ # "order" to say which ones get stacked on
+ result = 0
+ mult = 1
+ for i in range(3):
+ lim, idx, dbg = vals[i]
+ # some of the dimensions can be "skipped". the order
+ # was actually selected above on all 3 dimensions,
+ # e.g. [z][x][y] or [y][z][x]. "skip" allows one of
+ # those to be knocked out
+ if SVSHAPE.skip == i+1: continue
+ #print ("select %d %s" % (i, dbg))
+ idx *= mult # shifts up by previous dimension(s)
+ result += idx # adds on this dimension
+ mult *= lim # for the next dimension
+
+ loopends = (x_end |
+ ((y_end and x_end)<<1) |
+ ((y_end and x_end and z_end)<<2))
+
+ if hasattr(SVSHAPE, "postprocess"): # for Indexed mode
+ result = SVSHAPE.postprocess(result, step)
+ yield result + SVSHAPE.offset, loopends
+ step += 1
+
+def demo():
+ # set the dimension sizes here
+ xdim = 3
+ ydim = 2
+ zdim = 4
+
+ # set total (can repeat, e.g. VL=x*y*z*4)
+ VL = xdim * ydim * zdim
+
+ # set up an SVSHAPE
+ class SVSHAPE:
+ pass
+ SVSHAPE0 = SVSHAPE()
+ SVSHAPE0.lims = [xdim, ydim, zdim]
+ SVSHAPE0.order = [1,0,2] # experiment with different permutations, here
+ SVSHAPE0.mode = 0b00
+ SVSHAPE0.skip = 0b00
+ SVSHAPE0.offset = 0 # experiment with different offset, here
+ SVSHAPE0.invxyz = [0,0,0] # inversion if desired
+
+ # enumerate over the iterator function, getting new indices
+ for idx, (new_idx, end) in enumerate(iterate_indices(SVSHAPE0)):
+ if idx >= VL:
+ break
+ print ("%d->%d" % (idx, new_idx), "end", bin(end)[2:])
+
+# run the demo
+if __name__ == '__main__':
+ demo()
+```
+
[[!tag opf_rfc]]