first matrix-multiply REMAP demo using generators
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 1 Jul 2021 22:54:39 +0000 (23:54 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 1 Jul 2021 22:54:39 +0000 (23:54 +0100)
openpower/sv/remap.py
openpower/sv/remapmatrix.py
openpower/sv/remapyield.py
openpower/sv/shape_table_format.mdwn

index 387b90ae26e320afacea9a35b91e7b8a28165e4d..4721d8148bed66e907099bfeb5cb66d80b128548 100644 (file)
@@ -10,6 +10,7 @@ VL = xdim * ydim * zdim # set total (can repeat, e.g. VL=x*y*z*4)
 
 lims = [xdim, ydim, zdim]
 idxs = [0,0,0]   # starting indices
+applydim = [1, 1]   # apply lower dims
 order = [1,0,2]  # experiment with different permutations, here
 offset = 0       # experiment with different offsetet, here
 invxyz = [0,1,0] # inversion allowed
@@ -33,7 +34,11 @@ for idx in range(VL):
         ix[i] = idxs[i]
         if invxyz[i]:
             ix[i] = lims[i] - 1 - ix[i]
-    new_idx = ix[0] + ix[1] * xdim + ix[2] * xdim * ydim
+    new_idx = ix[2]
+    if applydim[1]:
+        new_idx = new_idx * ydim + ix[1]
+    if applydim[0]:
+        new_idx = new_idx * xdim + ix[0]
     print ("%d->%d" % (idx, new_idx)),
     break_count += 1
     if break_count == lims[order[0]]:
index 7c94b8947e534fe2c358537d829586ed52f9cf7f..54d73e93f4e7cd58db7723def7a0e56bec21a388 100644 (file)
@@ -1,13 +1,29 @@
 from remapyield import iterate_indices
+from functools import reduce
+import operator
+
+
+def iterate_triple(SVSHAPE0, SVSHAPE1, SVSHAPE2):
+    # zip three iterators together, yields a synchronised
+    # tuple of three indices at a time
+    yield from zip(iterate_indices(SVSHAPE0),
+                   iterate_indices(SVSHAPE1),
+                   iterate_indices(SVSHAPE2))
+
 
 def matrix_demo():
+    #### test matrices 1
+    # 3x2 matrix
     X = [[1, 2, 3],
           [3, 4, 5],
          ]
+    # 2x3 matrix
     Y = [[6, 7],
           [8, 9],
           [10, 11],
          ]
+
+    #### test matrices 2
     # 3x3 matrix
     X = [[12,7,3],
         [4 ,5,6],
@@ -16,23 +32,100 @@ def matrix_demo():
     Y = [[5,8,1,2],
         [6,7,3,0],
         [4,5,9,1]]
+
+    # get the dimensions of the 2 matrices
     xdim1 = len(X[0])
     ydim1 = len(X)
     xdim2 = len(Y[0])
     ydim2 = len(Y)
+
+    # print out X and Y
+    print ("X:")
+    for r in X:
+        print ("\t", r)
+    print ("Y:")
+    for r in Y:
+        print ("\t", r)
+
+    # first, calculate the result matrix manually.
     # set up result matrix of correct size
     result = []
     for _ in range(ydim1):
         result.append([0]*xdim2)
-    # iterate through rows of X
-    for i in range(len(X)):
-       # iterate through columns of Y
-       for j in range(len(Y[0])):
-           # iterate through rows of Y
-           for k in range(len(Y)):
+    # iterate through rows of Y
+    for k in range(len(Y)):       # ydim2
+        # iterate through rows of X
+        for i in range(len(X)):              # ydim1
+           # iterate through columns of Y
+           for j in range(len(Y[0])):        # xdim2
+               print ("order res %d   X %d   Y %d" % \
+                        ((i*xdim2)+j, # result linear array index
+                         (i*xdim1)+k,  # X linear array index
+                         (k*xdim2)+j))   # Y linear array index
                result[i][j] += X[i][k] * Y[k][j]
+    print ("expected result")
     for r in result:
-        print (r)
+        print ("\t", r)
+
+    # now. flatten the X and Y matrices into linear 1D Arrays.
+    # linear rows are sequentially-packed first (inner loop),
+    # columns next (outer loop):
+    #   0 1 2 3
+    #   4 5 6 7
+    #   8 9 10 11
+    # =>
+    #   0 1 2 3 4 .... 10 11
+    xf = reduce(operator.add, X)
+    yf = reduce(operator.add, Y)
+    print ("flattened X,Y")
+    print ("\t", xf)
+    print ("\t", yf)
+    # and create a linear result2, same scheme
+    result2 = [0] * (ydim1*xdim2)
+
+    ########
+    # now create the schedule. we use three generators, zipped
+    # together
+
+    class SVSHAPE:
+        pass
+    # result uses SVSHAPE0
+    SVSHAPE0 = SVSHAPE()
+    SVSHAPE0.lims = [ydim2, xdim2, 1]
+    SVSHAPE0.order = [0,2,1]  # result iterates through i and j (modulo)
+    SVSHAPE0.mode = 0b00
+    SVSHAPE0.offset = 0       # no offset
+    SVSHAPE0.invxyz = [0,0,0] # no inversion
+    # X uses SVSHAPE1
+    SVSHAPE1 = SVSHAPE()
+    SVSHAPE1.lims = [ydim2, xdim2, ydim1]
+    SVSHAPE1.order = [1,2,0]  # X iterates through i and k
+    SVSHAPE1.mode = 0b10
+    SVSHAPE1.offset = 0       # no offset
+    SVSHAPE1.invxyz = [0,0,0] # no inversion
+    # y-selector uses SHAPE2
+    SVSHAPE2 = SVSHAPE()
+    SVSHAPE2.lims = [ydim2, xdim2, ydim1]
+    SVSHAPE2.order = [1,2,0]  # Y iterates through k and j
+    SVSHAPE2.mode = 0b01
+    SVSHAPE2.offset = 0       # no offset
+    SVSHAPE2.invxyz = [0,0,0] # no inversion
+
+    # perform the iteration over the *linear* arrays using the
+    # schedules
+    VL = ydim2 * xdim2 * ydim1
+    i = 0
+    for i, idxs in enumerate(iterate_triple(SVSHAPE0, SVSHAPE1, SVSHAPE2)):
+        if i == VL:
+            break
+        print ("idxs", idxs, len(result2), len(xf), len(yf))
+        r_idx, x_idx, y_idx = idxs
+        result2[r_idx] += xf[x_idx] * yf[y_idx]
+
+    # now print out sections of result array, assuming elements of a "row"
+    # are in sequence (inner loop), columns are outer
+    for i in range(0, len(result2), xdim2):
+        print ("\t", result2[i:i+xdim2])
 
 if __name__ == '__main__':
     matrix_demo()
index 4cca1f39ab16edb2645ae8f46cf4e29727478815..ac3217b84a4c4161e5b2808c0600fdbe07cfdce3 100644 (file)
@@ -27,7 +27,22 @@ def iterate_indices(SVSHAPE):
                         skip += 1
                         continue
                     # construct the (up to) 3D remap schedule
-                    yield (x + y * xd + z * xd * yd)
+                    if SVSHAPE.mode == 0b00:
+                        result = z
+                        result += y * zd
+                        result += x * zd * yd
+                    elif SVSHAPE.mode == 0b01:
+                        result = z
+                        result += x * zd
+                        #result = z
+                        #result = result * xd + x
+                        #result = result * yd + y
+                    elif SVSHAPE.mode == 0b10:
+                        result = x
+                        result += y * xd
+                        #result += z * xd * yd
+
+                    yield result
 
 def demo():
     # set the dimension sizes here
@@ -43,10 +58,10 @@ def demo():
         pass
     SVSHAPE0 = SVSHAPE()
     SVSHAPE0.lims = [xdim, ydim, zdim]
-    SVSHAPE0.idxs = [0,0,0]   # starting indices
     SVSHAPE0.order = [1,0,2]  # experiment with different permutations, here
+    SVSHAPE0.mode = 0b00
     SVSHAPE0.offset = 0       # experiment with different offset, here
-    SVSHAPE0.invxyz = [0,1,0] # inversion if desired
+    SVSHAPE0.invxyz = [0,0,0] # inversion if desired
 
     # enumerate over the iterator function, getting new indices
     for idx, new_idx in enumerate(iterate_indices(SVSHAPE0)):
index 417dcc89366a70dce9ca39fbb0acbdd4087aa162..082c8e30128542ded9d4e3bcd01fdb6b5071cf71 100644 (file)
@@ -7,9 +7,9 @@ disabled: the register's elements are a linear (1D) vector.
 
 mode sets different behaviours (straight matrix multiply, FFT, DCT).
 
-* **mode=0b00** sets matrix multiply
-* **mode=0b01** sets FFT
-* **mode=0b10** is reserved
+* **mode=0b00** sets straight permute
+* **mode=0b01** sets "skip 2nd dimension"
+* **mode=0b10** sets "skip 1st dimension"
 * **mode=0b11** is reserved
 
 invxyz will invert the start index of each of x, y or z. If invxyz[0] is