RandomPermutation.cpp
Go to the documentation of this file.
00001 /**
00002  * \file RandomPermutation.cpp
00003  * \brief Prints a random permutation of integers
00004  *
00005  *   Usage: RandomPermutation [-o] [-d] [-x] [-s seed] [-v] [-r] [-h] [num]
00006  *
00007  * Print a random permutation of numbers from 0 thru num-1 on standard output.
00008  * num is supplied on the command line as a decimal number (default is 100).
00009  * Optional arguments -o, -d, and -x selection octal, decimal, and hexadecimal
00010  * output base (default decimal). -s seed sets the seed.  -v prints seed on
00011  * standard error. -r produces a reverse permutation.  -h prints this help.
00012  *
00013  * seed is typically a list of comma-separated numbers,
00014  * e.g., -s ""; -s 1234; -s 1,2,3,4; etc.  You can repeat a permutation by
00015  * using the form of the seed printed to standard error with -v as the
00016  * argument to -s, e.g., -s "[671916,1201036551,9299,562196172,2008]".  If the
00017  * seed is omitted, a "unique" seed is used.
00018  *
00019  * The reverse permutation can be used to undo a shuffle.  But it only makes
00020  * sense if -s or -v is given so that the same seed can be supplied to produce
00021  * the forward and reverse permutations.
00022  *
00023  * This is used by the "shuffle" script to shuffle the lines of a file.
00024  *
00025  * Written by Charles Karney <charles@karney.com> and licensed under the GPL.
00026  * For more information, see http://randomlib.sourceforge.net/
00027  **********************************************************************/
00028 
00029 #include "RandomLib/Random.hpp"
00030 #include <iostream>
00031 #include <iomanip>
00032 #include <sstream>
00033 #include <vector>
00034 
00035 #define RANDOMPERMUTATION_CPP "$Id: RandomPermutation.cpp 6723 2010-01-11 14:20:10Z ckarney $"
00036 RCSID_DECL(RANDOMPERMUTATION_CPP)
00037 
00038 void usage(const std::string name, int retval) {
00039   ( retval == 0 ? std::cout : std::cerr )
00040     << "Usage: " << name
00041     << " [-o] [-d] [-x] [-s seed] [-v] [-r] [-h] [num]\n\
00042 \n\
00043 Print a random permutation of numbers from 0 thru num-1\n\
00044 on standard output.  num is supplied on the command line\n\
00045 as a decimal number (default is 100).  Optional arguments\n\
00046 -o, -d, and -x selection octal, decimal, and hexadecimal\n\
00047 output base (default decimal). -s seed sets the seed.\n\
00048 -v prints seed on standard error. -h prints this help.\n";
00049   exit(retval);
00050 }
00051 
00052 int main(int argc, char* argv[]) {
00053   try{
00054   unsigned n = 100;
00055   unsigned base = 10;
00056   bool verbose = false;
00057   bool seedgiven = false;
00058   bool reverse = false;
00059   std::string seed;
00060   std::string arg;
00061   int m = 0;
00062   while (++m < argc) {
00063     arg = std::string(argv[m]);
00064     if (arg[0] != '-')
00065       break;                    // Exit loop if not option
00066     if (arg == "-o")
00067       base = 8;
00068     else if (arg == "-d")
00069       base = 10;
00070     else if (arg == "-x")
00071       base = 16;
00072     else if (arg == "-v")
00073       verbose = true;
00074     else if (arg == "-r")
00075       reverse = true;
00076     else if (arg == "-s") {
00077       seedgiven = true;
00078       if (++m == argc)
00079         usage(argv[0], 1);      // Missing seed
00080       seed = std::string(argv[m]);
00081     } else if (arg == "-h")
00082       usage(argv[0], 0);
00083     else
00084       usage(argv[0], 1);        // Unknown option
00085   }
00086   if (m == argc - 1) {
00087     std::istringstream str(arg); // First non-option argument
00088     str >> n;
00089   } else if (m != argc)
00090     usage(argv[0], 1);          // Left over arguments
00091 
00092   unsigned k = 0;               // Figure width of output
00093   for (unsigned i = n - 1; i; i /= base) k++;
00094 
00095   std::vector<unsigned> a(n);
00096   for (unsigned i = n; i--;) a[i] = i;
00097 
00098   RandomLib::Random r = seedgiven ? RandomLib::Random(seed) :
00099     RandomLib::Random(RandomLib::Random::SeedVector());
00100   if (verbose)
00101     std::cerr << "Seed: " << r.SeedString() << "\n";
00102   std::random_shuffle(a.begin(), a.end(), r);
00103 
00104   if (reverse) {
00105     std::vector< std::pair<unsigned, unsigned> > b(n);
00106     for (unsigned i = n; i--;) b[i] = std::pair<unsigned, unsigned>(a[i], i);
00107     std::sort(b.begin(), b.end());
00108     // Use the n - 1 - i construct because a is printed in reverse order.
00109     for (unsigned i = n; i--;) a[i] = n - 1 - b[n - 1 - i].second;
00110   }
00111 
00112   std::cout << std::setfill('0')
00113             << (base == 16 ? std::hex : (base == 8 ? std::oct : std::dec));
00114   for (unsigned i = n; i--;)
00115     std::cout << std::setw(k) << a[i] << "\n";
00116 
00117   return 0;
00118   }
00119   catch (...) {
00120     std::cerr << "Unexpected error" << "\n";
00121   }
00122 }