{Select active(s.Bit(15)); ... }A better way would be
{Select active(s >= 0); ... }But, sometimes you just need to access a particular bit. Bits are numbered starting at zero from the least significant to the most significant(1).
The InsertBits(2) methods allow you to set particular bits in a plane. For example, the following code implements the absolute value function for floating point planes by setting the sign bits to zero(3).
FloatPlane absf(FloatPlane arg) { return arg.InsertBits(0,1,31,0); // Set sign to zero }There are three forms of arguments that InsertBits will allow.
InsertBits(plane source, int length, int to, int from) InsertBits(scalar source, int length, int to, int from) InsertBits(BitPlane source, int to)The source is the source of the bits that will be inserted into the plane to which the method is applied(4). length specifies the number of bits starting at the from position in the source. The to position specifies where in the destination the bits will be inserted.
The algorithm for the case with the scalar source and a CharPlane is given below.
CharPlane insert_bits (CharPlane &dest, int source, int length, int to, int from) { int mask = (1 << length) - 1; return (dest & ~(mask << to)) | (((source >> from) & mask) << to); }
One way to process one value at a time is to simply select a single value using the activity. Then, the operations performed will only affect that single value. To select a single PE, that PE must be unique in some way that may be tested. It must have a unique value stored in it. We test for this value and use the result to set the activity. One thing that is unique about any PE is its row and column index.
A more probable need is to use an individual PE's value in the ACU. For example, the following program will extract the values from a CharPlane and store them in an array.
void to_array(CharPlane x, char* x_copy) { Everywhere active; int rows, cols; BitPlane row(x.Size()); rows = x.RowSize(); cols = x.ColSize(); for (int i = 0; i < rows; i++) { row = (x.RowIndex() == i); for (int j = 0; j < cols; j++) *(x_copy + j + i * cols) = x.Access(row & x.ColIndex() == j); } }This program works because the Access method, applied to the plane x, returns the selected value. If there is more than one selected PE, then Access returns the bit-wise logical OR of the bits of the different values selected in x. The inverse to the above code is shown below.
void from_array(CharPlane &x, char* x_copy) { Everywhere active; int rows, cols; rows = x.RowSize(); cols = x.ColSize(); for (int i = 0; i < rows; i++) { Select active((x.RowIndex()== i); for (int j = 0; j < cols; j++) { Select active(x.ColIndex() == j); x = *(x_copy + j + i * cols); } } }The definition of Access for CharPlanes is simple.
char Access(CharPlane source, BitPlane selected) { char result = 0; for (int i = 7; i >= 0; i--) { result = result << 1; result |= (selected & source.Bit(i)).Any(); } return result; }
ToArray(array, int rows, int cols) FromArray(array, int rows, int cols)The rows and cols arguments specify the size of the array. If the plane is larger, only the top, left corner of the plane is used. If the plane is smaller, ToArray leaves the unmatched locations of the array alone. The following code is safe if not correct.
IntPlane x(200,300); CharPlane y(64,128); short x_copy[100][200]; x.ToArray((short *)x_copy,100,200); y.FromArray((short *)x_copy,100,200);Type conversions are used as needed. The above example converts from int to short to char. Because of the expected applications for these methods, these data movement methods are not affected by the activity(5). The ToArray and FromArray method implementations use a different, more parallel, mechanism than that used in the example functions above.
BitPlane vertex(256,256); char vertic_c[256][256]; ... vertex.ToArray((char *)vertic_c,256,256); for (int i = 0; i < 256; i++) for (int j = 0; j < 256; j++) if (vertic_c[i][j]) printf("Vertex at (%d,%d).\n",i,j);This program will execute the if statement 65000 times. Let us rewrite this to use the SelectMin method. This new program will loop as many times as there are vertices. SelectMin(6) finds the set of selected PEs with the minimum value for the plane to which it is applied(7).
BitPlane vertex(ps); .... { Everywhere active; BitPlane remaining(ps); BitPlane min(ps); remaining = vertex; while (remaining.Any()) { // While any not processed // Select minimum of those remaining min = (vertex.Index()).SelectMin(remaining)); printf("Vertex at (%d,%d).\n", (vertex.RowIndex()).Access(min), (vertex.ColIndex()).Access(min)); remaining &= ~min; } }The result is a printed list of the vertices in row major order because SelectMin selects the minimum PE index for the active PEs with each iteration. Whichever one is selected, it can not be selected the next time because its value for remaining is set to zero. Note that the two Select declarations can not be combined as shown below.
{Select active(remaining & (vertex.Index()).SelectMin()); ... }because, after the first iteration, the set of active PEs would be empty. We must select the minimum of the remaining PEs.
A program to print out all of the unique values, of some UShortPlane from the largest to the smallest value, is given below to illustrate the SelectMax method. There may be more than one PE active and responding to the Access method, but each of these PEs will have the same value.
void print_unique(ShortPlane vals) { Everywhere active; BitPlane remaining(vals.Size()); remaining = 1; int count = 0; while (remaining.Any()) { Select active(remaining); {Select active (vals.SelectMax()); printf("%5d ",vals.Access()); if ((++count % 10) == 0) printf("\n"); remaining = 0; } } printf("There were %d different values.\n",count); }
As an example, let us use a typical technique of smoothing an image and then do sub-sampling. We will smooth by selecting the minimum value in each two by two window as the value of the PE in the center of the window.
UCharPlane original_image(ps); UCharPlane smoothed_image(ps); UCharPlane east(ps), west(ps); .... smoothed_image = original_image; east = original_image.East(); west = original_image.West(); {Select active(smoothed_image > east); smoothed_image = east; } {Select active(smoothed_image > west); smoothed_image = west; } {Select active(smoothed_image > east.North()); smoothed_image = east.North(); } {Select active(smoothed_image > west.North()); smoothed_image = west.North(); } {Select active(smoothed_image > east.South()); smoothed_image = east.South(); } {Select active(smoothed_image > west.South()); smoothed_image = west.South(); } {Select active(smoothed_image > original_image.South()); smoothed_image = original_image.South(); } {Select active(smoothed_image > original_image.North()); smoothed_image = original_image.North(); }We will now sub-sample by selecting every upper-left PE in that 2 by 2 window.
{Select active((~(smoothed_image.RowIndex()).Bit(0)) & (~(smoothed_image.ColIndex()).Bit(0))); .... }There are several problems with this algorithm. First, we have not made the planes any smaller so there is no chance that we will use fewer tiles and run faster. Second, if we wish to do any non-trivial processing on this reduced image, we will have trouble because no PE's neighbor in the reduced image is their physical neighbor. Therefore, mesh and Coterie operations will be difficult. We must actually reduce the image by moving the values. Though there are faster ways, we will use Route to move the values.
UCharPlane reduced(ps); UShortPlane row_address(ps); UShortPlane col_address(ps); row_address = 0xffff; // Non-existent PE address {Select active((~(smoothed_image.RowIndex()).Bit(0)) & (~(smoothed_image.ColIndex()).Bit(0))); row_address = smoothed_image.RowIndex() >> 1; col_address = smoothed_image.ColIndex() >> 1; } reduced = smoothed_image.Route(row_address, col_address);Now, the values we are interested in are in the upper-left corner of the reduced plane. We routed the values from the other PEs to non-existent destinations. But, this plane is no smaller than the smoothed_image plane. One last step will finish the job.
int sr = reduced.RowSize() / 2; int sc = reduced.ColSize() / 2; UCharPlane small_reduced(sr, sc); small_reduced = reduced.Resize(sr,sc);The Resize method creates a new plane from the original one and gives it the size specified(8). If the new size is larger, the upper-left corner is set with the values from the source plane and values at other PEs are undefined. If the new size is smaller, only the corresponding upper-left corner of the source plane is used.