laser.mpi.util.shuffle
Class TranspositionShuffler
java.lang.Object
|
+--laser.mpi.util.shuffle.Shuffler
|
+--laser.mpi.util.shuffle.TranspositionShuffler
- public class TranspositionShuffler
- extends Shuffler
A TranspositionShuffler provides functionality to move around
elements of a distributed array using MPI. The context is as
follows: each process in an MPI communicator has a local array
which we will call localData. The user wishes to move these
elements around, within and between processes. To do this, the user
provides a map which tells precisely what is to be moved where.
The map is specified using "coordinates." A coordinate is a pair of
integers (proc, locPos), where proc is the process ID (or "rank" in
MPIese), and locPos is the index in the localData array on
proc. The map then consists of a list of pairs (source, target) of
coordinates. The source is the coordinate for the item one wishes
to move, and target is the coordinate for the position one wishes
to move it to.
The relation defined by the map must be an injective function. For
we do not allow one to move an item to two different locations, nor
do we allow moving two distinct items to the same location.
However, it is not required that the function be defined on the
entire domain (i.e., on all possible coordinates), nor is it
required that the function be onto. Therefore, it is possible to
move an item from position p to position q, but not to move
anything to position p. In this case, the data at position p will
not be erased---it will still remain there, along with another copy
at position q.
This is a concrete class extending the abstract class Shuffler.
The algorithm defined here (described below) is very simple, but
uses more Sends and Receives than are required. See the
CycleShiftShuffler for an algorithm which minimizes the number of
sends and receives.
The usual way to use this class is to invoke the static method
shuffle. Every proc in the communicator must invoke this method,
and with the same map.
This class has been written using the mpiJava package. You must
have mpiJava installed to compile and execute this class. If
.../mpiJava/lib/classes is in your CLASSPATH you should be able to
compile this class normally using javac. To execute from the
command line you say, for example, "prunjava 4
laser.mpi.util.shuffle.TranspositionShuffler". prunjava is a
script which comes with mpiJava, and I am assuming it is in your
PATH. This executes some tests which are in the test suite. The 4
means to create 4 procs. You can use any positive integer you want
in place of 4, and the tests should all pass. For each test, you
will see the map, the localData arrays before shuffling, and the
localData arrays after shuffling. If everything comes out as
expected, this is all you will see. If anything goes wrong, you
will also get a message telling you what went wrong. If this
happens, please email me with a bug report.
The algorithm: the basic idea is the following. First, one
enumerates, using the integers 0,1,...,n-1 all the coordinates
which occur as sources or targets in the map. In this enumeration,
each coordinate occurs precisely once. Now we rewrite the map as a
function from a subset of X={0,1,...,n-1} (the domain) to X. To do
this we use a constant called UNDEFINED, and we represent the map
as an array of length n with elements in X+{UNDEFINED}. We call
this array p.
Now we construct an array q which is just the inverse of p. Hence
the domain of p is the range of q, and the range of p is the domain
of q, and, for all i in the domain of p and all j in the domain of
q: p[i] == j iff q[j] == i.
Now, p and q will both be changing during reordering, but at each
stage we will maintain the inverse relationship described above.
The algorithm essentially involves realizing the map as a product
of transpositions. If the map were an actual permutation (i.e., if
p were defined on all of X), then this is exactly what would
happen. However, some care must be taken for the undefined
values.
The easiest way to describe the algorithm is just to give
the body of the reoder method:
for (int i = 0; i < p.length; i++) {
int j = q[i];
int k = p[i];
if (j == UNDEFINED) {
if (k != UNDEFINED) {
int i2 = k;
k = p[k];
while (k != UNDEFINED) {
i2 = k;
k = p[k];
}
j = q[i2];
while (j != UNDEFINED) {
copyData(i2, j);
p[i2] = i2;
p[j] = UNDEFINED;
q[i2] = i2;
i2 = j;
j = q[j];
}
}
}
else {
p[i] = i;
p[j] = k;
if (k == UNDEFINED) {
copyData(i, j);
}
else {
switchData(i, j);
q[k] = j;
}
q[i] = i;
}
}
The idea is that, after each iteration through the outermost loop,
the localData will have the correct values for global positions
0,...,i. The complexity of the j = UNDEFINED case is for dealing
with "shifts", in which case one must search backwards for the
beginning of the shift.
This performs, in the worst case 2n sends and 2n receives. This is
really twice as many as is needed: the more complicated
CycleShiftShuffler performs at most n sends and n receives.
Field Summary |
private Coordinate[] |
coordinates
An array containing all the coordinates which occur as a source
or target in map. |
private int[][] |
indices
An array of length nProcs of arrays of ints. |
private int[] |
p
This is the map, using the global indices instead of
coordinates. |
private int[] |
q
This is simply the inverse of p. |
static int |
UNDEFINED
A constant used to represent an undefined value for the
functions p or q. |
Constructor Summary |
TranspositionShuffler()
Constructs a trivial instance of this class. |
TranspositionShuffler(java.lang.String name,
mpi.Intracomm comm,
int tag,
Mapping[] map,
java.lang.Object[] localData)
Constructs a new instance of this class with the given name,
communicator, tag, map and localData. |
Method Summary |
(package private) void |
copyData(int i,
int j)
Copies the locaData entry at global index j to the localData
entry with global index i. |
static void |
main(java.lang.String[] args)
This simply executes a number of tests described in the test
cases. |
Shuffler |
newInstance(java.lang.String name,
mpi.Intracomm comm,
int tag,
Mapping[] map,
java.lang.Object[] localData)
Creates a new instance with the given name, communicator, tag,
map and localData. |
void |
printState(int rank)
|
void |
reorder()
This is the main method which carries out the reordering. |
static void |
shuffle(mpi.Intracomm comm,
int tag,
Mapping[] map,
java.lang.Object[] localData)
This is the main static method which is the usual way for using
this class. |
(package private) void |
switchData(int i,
int j)
Exchanges the localData with global indices i and j. |
Methods inherited from class laser.mpi.util.shuffle.Shuffler |
addSends, comm, debug, debug, globalNumSendrecvs, globalNumSends, lengths, localData, map, myAssert, myRank, name, nProcs, nSendrecvs, nSends, printArray, printLocalData, printMap, tag |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
UNDEFINED
public static final int UNDEFINED
- A constant used to represent an undefined value for the
functions p or q.
- See Also:
- Constant Field Values
indices
private int[][] indices
- An array of length nProcs of arrays of ints. This array is
built up using the information provided by map. The i-th
element of this array is an array of length lengths[i]. The
j-th element of that array is a unique integer (the "index")
corresponding to the coordinate (i,j) (i.e., position j of
localData on proc i).
coordinates
private Coordinate[] coordinates
- An array containing all the coordinates which occur as a source
or target in map. Each such coordinate occurs exactly once in
this list. The position at which a coordinate occurs in this
array is called its "index".
p
private int[] p
- This is the map, using the global indices instead of
coordinates. It means: move the data with global index i to
position with global index p[i]. For those positions i for
which there is no move, the value of p[i] will be UNDEFINED.
By the domain of p, we mean the set of all i such that p[i] is
not UNDEFINED. By the range of p, we mean the set of all
integers of the form p[i] for some i in the domain of p.
Notice that p will be changed in the process of reordering.
q
private int[] q
- This is simply the inverse of p. I.e., the domain of q is the
range of p, and the range of q is the domain of p, and for all
i in the domain of p and all j in the domain of q: p[i] == j
iff q[j] == i. Notice that q will be changed during reordering,
but at each stage it will be the inverse of p.
TranspositionShuffler
public TranspositionShuffler(java.lang.String name,
mpi.Intracomm comm,
int tag,
Mapping[] map,
java.lang.Object[] localData)
throws mpi.MPIException
- Constructs a new instance of this class with the given name,
communicator, tag, map and localData. Keep in mind that each
proc in the MPI system must create its own instance of this
class, and when they do so they should all provide the same
map. It is the user's responsibility to make sure this is so,
or else anything could happen!
This constructor checks the map to make sure it defines an
injective function and that there are no references into
localData which exceed the length of that array. It also
constructs the lengths array, and the indices array, and the
permutation arrays p and q.
- Parameters:
name
- a name to be given to this Shufflercomm
- the MPI communicator to be used for all MPI callstag
- the MPI tag to be used for all MPI communicationmap
- the array of Mappings describing how to shuffle the datalocalData
- the local data array for this proc
- Throws:
mpi.MPIException
- if an MPI call goes awry
java.lang.IllegalArgumentException
- if name, comm, map, or
localData is null, or if tag == MPI.ANY_TAG
TranspositionShuffler
public TranspositionShuffler()
throws mpi.MPIException
- Constructs a trivial instance of this class.
shuffle
public static void shuffle(mpi.Intracomm comm,
int tag,
Mapping[] map,
java.lang.Object[] localData)
throws mpi.MPIException
- This is the main static method which is the usual way for using
this class. The user provides the communicator, tag, map, and the
localData, and upon return the data will be moved around
according to the instructions in the map. This method is to be
called by all procs in the communicator, and with the same map
and communicator, (although obviously with different
localDatas).
It is best to choose a tag which is not being used by other
program components.
- Parameters:
comm
- The MPI communicatortag
- the MPI tag to be used for all MPI communication in
this classmap
- the array of Mappings telling what is to be moved wherelocalData
- the local data array for this proc
- Throws:
mpi.MPIException
- if an MPI call goes awry
java.lang.IllegalArgumentException
- if name, comm, map, or localData
is null, or if tag == MPI.ANY_TAG
main
public static void main(java.lang.String[] args)
throws mpi.MPIException
- This simply executes a number of tests described in the test
cases.
- Parameters:
args
- the command line arguments
- Throws:
mpi.MPIException
- if an MPI call goes awry
newInstance
public Shuffler newInstance(java.lang.String name,
mpi.Intracomm comm,
int tag,
Mapping[] map,
java.lang.Object[] localData)
throws mpi.MPIException
- Creates a new instance with the given name, communicator, tag,
map and localData. Keep in mind that each proc in the MPI
system must create its own instance of this class, and when
they do so they should all provide the same map. It is the
user's responsibility to make sure this is so, or else anything
could happen!
This method check the map to make sure it defines an injective
function and that there are no references into localData which
exceed the length of that array.
- Specified by:
newInstance
in class Shuffler
- Parameters:
name
- a name to be given to this Shufflercomm
- the MPI communicator to be used for all MPI callstag
- the MPI tag to be used for all MPI communicationmap
- the array of Mappings describing how to shuffle the datalocalData
- the local data array for this proc
- Throws:
mpi.MPIException
- if an MPI call goes awry
java.lang.IllegalArgumentException
- if name, comm, map, or localData
is null, or if tag == MPI.ANY_TAG
printState
public void printState(int rank)
reorder
public void reorder()
throws mpi.MPIException
- This is the main method which carries out the reordering.
- Specified by:
reorder
in class Shuffler
- Throws:
mpi.MPIException
- if the MPI calls go awry
switchData
void switchData(int i,
int j)
throws mpi.MPIException
- Exchanges the localData with global indices i and j.
- Parameters:
i
- the global index of one of the coordinatesj
- the global index of the other coordinate
- Throws:
mpi.MPIException
- if the MPI calls go awry
copyData
void copyData(int i,
int j)
throws mpi.MPIException
- Copies the locaData entry at global index j to the localData
entry with global index i.
- Parameters:
i
- the global index of the datum to be copiedj
- the global index of the position to which it is to be
copied
- Throws:
mpi.MPIException
- if the MPI calls go awry