MPI etc

         Minimal Weight (MPI Final)

A. Fifth Edition
This is the programming assignment of comp6661 and we are requested to use "revolving door algorithm" to find minimal 
weight for an error-correcting-code. I struggled for a whole day and finally finished as planned even though a little bit
more time than expected. And after I found out that my MPI first version ran for more than a whole day, I began to do a 
testing to compare efficiency between "unrank" and "successor". Quite to my surprise, "unrank" is almost 200 times slower
than "successor" function. This made me finally decide to implement my MPI in "successor" manner.
(I didn't read the question carefully and did something stupid.)
B.The problem
3. (9 marks total)
(a) (5 marks) Write a program to generate combinations in the revolving door order.
Provide printouts to demonstrate that your program is working.
(b) (4 marks) Next, you use the combinations generated in part (a) in an application
involving error-correcting codes.
A (n, k) binary linear error correcting code is a k-dimensional vector space of
length n over the finite field with 2 elements, namely, 0 and 1. Given a basis,
which is a set of k linearly independent vectors r1, r2, . . . , rn, all the vectors in
the vector space can be expressed as a linear combinations
 
for (i=1 to n) summation(ci * ri)

where the coefficients ci¨s are in {0, 1}.
A generator matrix G, where row i is the vector ri, is a convenient way of representing
a basis. A linear combination with coefficents ci¨s is just an xor of the
subset of rows ri where the corresponding coefficient ci = 1.
For simplicity, we shall shorten the term binary linear error-correcting code to
just code. The vectors in such a code are usually called codewords or even words.
1
The weight of a word is the number of 1¨s in the word. The minimum weight of
a code is the minimum weight of its non-zero codewords. The minimum weight
of a code is important because it determines the number of errors that the code
can correct.
You will be using the combination generation you developed in part (a) to find the
minimum weight of a code, in the special case where the leftmost k〜k submatrix
of the generator matrix is an identity matrix. If the generator matrix is in this
form, you can show that the minimum weight is d by showing that there exists
a linear combination with weight d, and that all the linear combinations defined
by the r-subsets of rows, with r d, have weights at least d.
For this part of the program, you should use the bit array data structure you
developed in assignment 1 to represent the rows of the generator matrix. You
should also use the setorder routine to find the weight of a word.
You should use the (7, 4) Hamming code to debug your program. A few test cases
will also be provided in the course web page. For each test case, the first line
contains the values of n, k, d, and it is followed by k lines each containing a length
n vector of 0¨s and 1¨s. The 0¨s and 1¨s are separated by blanks. Your program
should establish whether the code has minimum weight d. You may assume that
n is at most 96.
2
 
C.The idea of program
 

1. Using revolve-door unrank function in textbook to generate index array for subset combination. So, we can generate arbitary subset by given its rank. This is used for partition our searching job. This method is comparatively a bit slow than other "successor" function. (And this is only my original estimation. After I made a program to compare the three algorithm I found out that "unrank" is extremely slow, about 200 times slower than "successor".


2. Improved on basis of first version so that two consecutive subset combination don't need calculate repeated xor. Instead
I compare the difference in two subsets and use previous result to xor with two changed vector. In order to keep both
current and previous subset combination, I use two integer array, oldArray and newArray. instead of using a pointer to point to them alternatively in my previous version, I have to backup newArray into oldArray because Knuth's "successor" is depending on previous results and modifies them directly.

3. Based on second version and use MPI to distribute computation to other nodes. My idea is straight forward. If we can
start any computation by giving a rank, then we can divide the total computation job with different range of rank. That's
why I implement my algorithm by using "unrank" function.
4. Root node read from data file and broadcast n,k,d and vector to all other nodes.
5. Then all slave nodes start computation by iterate all subset size from 1 to k. And each node knows its part of range
because of its MPI_Rank. For example, for n=32,k=16,d=7 the total number of combination of subset 5 is (16,5)=11440. If
MPI_Size=9 which means 8 slave nodes, then each node will be given a range of 11440/8 and they don't need further instruction
from root node and can start working as soon as they receive all setup information.
5. I choose to let root node be specializing in listening to simplify programming because we don't know when and which node
will report discovery. So, we have to use non-blocking "recv" method in MPI. If I give computation job to root node, I have
to use multi-thread for listening which is too complicated and has only suspicious performance gain. Therefore, the root
node will "post" a recieve request to all slave nodes and then "test" requests in a loop. The slave nodes will first answer
"yes" or "no" to discovery. If "yes", it will send combination of vector which has smaller weight than d seperately. If "no",
no further informatio is sent. By counting "no" replies or receiving "yes" reply, root node can decide if we find or not.

6. Originally I write my program in windows and in order to run and test in Linux, I have to change some data type. For example, in windows, "size_t" is one of primitive type while in Linux, I have to typedef it to "unsigned int". And in windows, I am using VC++ special type __int64 which is 64 bit integer while in Linux, I have to type define it to "long long". So, if you need to run them in windows, comment out those typedef's in "myset.h".

7. One of few things changed here is just to adjust the searching scope from n to d which reduces greatly so that all test

cases become reachable. I made myself a fool by writing email and claimed that test case 7 required three years to finish.

The other thing I changed here is how to decide running result. I read the requirement and divide the task into two parts.

One is to confirm if the code has a linear combination of weight equal to d. The other one is to find out if there is a

even smaller weight. These two sub tasks are distinctive.

8. The returning protocol is like this:

For all slave node:

If in any searching node, a smaller weight is found, the size of that subset is sent and program returns by sending all combinations in an array.

If only a minimal weight exactly equal to d is found, the size of that subset is sent as size*(-1) and that particular combination is sent in an array.

In other cases, a single 0 is sent to indicate nothing found.

For master node:

Post receiving requests on each slave node and test in a big loop until one of the following two conditions are satisfied: a weight smaller than d is found or all slave nodes returns. (either 0 or negative)

 

D.The major functions
In both text book and Knuth's notes, there are generating algorithms for subset of order of minimal change. However, I 
choose unusual "unrank" function to implement it which is not efficient. There is another simple reason apart from that MPI
mentioned above. It is the only thing I can work out!. I even tried both algorithms and repeatedly got error. Then I suspected
both of them. And time is ticking. I only got one whole day for this program because I must leave some time for theory and
possible testing, documenting. So, I have to give it up. And you can find the commented Knuth's code. Efficient and 
terrible with no offence. You see, his style is typical assembly language like and I both envy and hate. 
The only useful, stupid and painful tip I got is that in windows VC++ long is not __int64 and it is only meaningful in java.
In VC++, long is similar to int and the counterpart of __int64 in Linux is long long.
 
So, this is what I wrote in previous version.

E.Further improvement
Originally I thought like this when I didn't give one second to reading the requirement.

Here it goes:

I think the task is just mission impossible because I only finished case 5 with 22945 seconds which is roughly six hours more. But please note that I am using MPI to run this program on 9 high performance servers and I am already using the optimize "xor" strategy mentioned by prof. in class which means I only "xor" the last result with two changed vector. Still it costs more then six hours. And case 6 is more than 10 times bigger in size of subset combination than case 5. And case 7 is even six thousand times bigger than case 5 .    (Purely in number of subset combination:  2 ^(52-36)) And I haven't mentioned about the length of vector which  is much longer than case 5.

So, my estimate is that to finish case 7, I may need more than three years. Is that correct estimation?

 

Here it comes:

I took a quick look at the attached program (hopefully deleted from
this email). I think the program can still be speeded up. I think you
are only using 8 bits per word, whereas one should use all 32 bits.
For example, for case 5, with n=72, you should only need 3 words to
store the bit array, but your program seems to be using 72/8=9 words.
You can speed up your program by a factor of 4 just by packing the bits
tighter.

Another point is that your "look" table is only of size 2^8=256. If you
use a table of size 2^16, it will go faster (provided you do pack 32
bits into one word).

 

Here it goes:

By the way, I want to take back part of comment last time on error-correcting-code when I said it is mission impossible. First I didn't read question carefully and my program is actually testing all subset combination from size 1 to size k instead of required from 1 to d. This is a big difference. And I modified my program this morning and rerun the test. It looks like this:

test5 runs 649 seconds. test6 has been running for more than several hours.

And I made a simple calculation comparison between test6 and test5.

test5= (36,1)+(36,2)+(36,3)+...(36,12)

test6= (40,1)+(40,2)+(40,3)+...(40,16)

test6/test5=65

This means at least test6 needs to run for about 65x649 seconds

And test7=(52,1)+(52,2)+...(52,20)

test7/test5=126909

So, test7 needs to run for about 126909x649seconds=953(days) It should be running a little less than three years.

Of course I haven't made the optimization mentioned by you last time, however, I feel the speedup is quite limited. My reason is that for each round of operation, I have a lot of work to be done.

1. backup current index array in an old array because I need two array to compare to find out which two index are changed. 2. a rather complicated algorithm to compare two index array to find out which two index array are changed. (Maybe homogeneous order can save the work a bit.)

3. Knuth's algorithm to generate next subset.

4. xor previous result with two changed rows to get new result 5. check order of current result

You see these operations will probably have more than one thousand instructions and what you suggested may save just a few instructions here. By Amdahl's law in speedup in computer achitecture, the total speedup is just very small.

Here it goes:

I thought you might be interested in knowing the running result of my MPI program in test6. It runs roughly 12 hours which is a quite precise match with my prediction in my last email: test5 runs 649seconds and test6 is roughly 65 times bigger than test5. So, I expect it runs for more than 11 hours. At least my program is consistent in two test cases. This makes me suspect how fast is my classmate's program who claimed to finish test6 within a few hours with 4 cpu and 4 threads. How come his desktop can defeat our cluster computer? I am really curious about his program!

I let my program run for test7, but I will probably stop it in a few days because it seems to need to run for more than two years.

 
F.File listing
 
Minimal weight searching. (don't be confused by two main file, one is for MPI, the other is just
				usual main. They should be compiled seperately.)
1. mpi.cpp  (main for MPI, compiled by make mpi)
2. main.cpp (main for local single node, compiled by make myset)
3. myset.h
4. myset.cpp
5. revolve.h
6. revolve.cpp
7. makefile
to compile:
mpic++ mpi.cpp myset.cpp revolve.cpp -o mpimyset.exe

to run:
>time mpirun -np 9 mpimyset.exe test5.txt >result5.txt &
And here is the data file you need to feed when running
file name: mpi.cpp
#include "myset.h"
#include "revolve.h"
#include <iostream>
#include <mpi.h>
#include <time.h>
//#include <math>

using namespace std;

//#define myabs(x) ((x>0)?x:(-x))
int myabs(int x)
{
	return (x>0)?x:(-x);
}

extern size_t n, k, d;
extern size_t* buffer;//please note the master and slave has different way to initialize buffer
extern MySet* sets;
extern MySet current;
extern size_t bufferSize;
extern size_t* resultArray;//the pointer
extern int resultSize;


int mpi_rank, mpi_size;
bool hasSmaller=false;

size_t context[3]; //n,k,d

int main(int argc, char* argv[])
{
	time_t start;

	MPI_Init(&argc, &argv);                 /* Initialize MPI       */
        MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); /* Get my rank          */
    	MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);   

	if (mpi_rank==0)
	{
		start=time(0);
		int i,  counter=0;
		//indicating which node returns
		int* flags=new int[mpi_size-1];
		//contain the result for each node
		int *results=new int[mpi_size-1];
		MPI_Status  status;
		MPI_Request* requests=new MPI_Request[mpi_size-1];
		if (argc<2)
		{
			cout<<"usage: myset.exe filename\n";
			MPI_Finalize();
			return 1;
		}
		readFromFile(argv[1]);
		initialize(n, k, d, buffer);
		context[0]=n;
		context[1]=k;
		context[2]=d;
		MPI_Bcast(context, 3, MPI_INT, 0, MPI_COMM_WORLD);
		MPI_Bcast(buffer, bufferSize, MPI_INT, 0, MPI_COMM_WORLD);
		for (i=1; i<mpi_size; i++)
		{
			flags[i-1]=0;
			MPI_Irecv(results+i-1, 1, MPI_INT, i, 0, MPI_COMM_WORLD, requests+ i-1);			
		}
		while (counter<mpi_size-1&&!hasSmaller)
		{
			for (i=1; i<mpi_size; i++)
			{
				if (!flags[i-1])
				{
					MPI_Test(requests+i-1, flags+i-1, &status);
					if (flags[i-1])//negative means find the combination equal to d
					{
						counter++;//counter inc anyway
						//means we find smaller than d
						size_t resultLength=myabs(results[i-1]);
						//cout<<"resultLength="<<resultLength<<endl;
						int* dataBuf=new int[resultLength];
						if (results[i-1]>0)
						{
							cout<<"node "<<i<<" has smaller weight"<<endl;
							hasSmaller=true;
						}
						else
						{
							if (results[i-1]<0)
							{
								cout<<"node "<<i<<" has found a combination of weight equal to d\n";
							}
						}
						if (resultLength>0)
						{
							MPI_Recv(dataBuf, resultLength, MPI_INT, i, 0, MPI_COMM_WORLD, &status);
							cout<<"The combination is:\n[";
							for (int j=0; j<resultLength; j++)
							{
								cout<<dataBuf[j];
								if (j!=resultLength-1)
								{
									cout<<",";
								}
							}
							cout<<"]\n";
							if (results[i-1]>0)
							{
								break;
							}
						}
					}
				}
			}
			if (counter==mpi_size-1&&!hasSmaller)
			{
				cout<<"no small weight found in any node\n";
				break;
			}
		}
		cout<<"the total time in seconds is "<<time(0)-start<<endl;

	}
	else
	{
		long long start, total, mySize;
		int size;
		size_t subset;
		MPI_Bcast(context, 3, MPI_INT, 0, MPI_COMM_WORLD);
		n=context[0];
		k=context[1];
		d=context[2];
		size=n/32;
		if (n%32!=0)
		{
			size++;
		}
		bufferSize=size*k;
		buffer=new size_t[bufferSize];
		MPI_Bcast(buffer, bufferSize, MPI_INT, 0, MPI_COMM_WORLD);
		initialize(n,k,d, buffer);
		for(subset=1; subset<=d; subset++)
		{
			total=combineNumber(k, subset);
			mySize= total/(mpi_size-1);
			start=mySize*(mpi_rank-1);
			//if I am the last one, I have to take care all of rest part
			if (mpi_rank==mpi_size-1)
			{
				mySize=total-mySize*(mpi_size-2);
			}
			//false means we find the smaller than d
			if (!weightTest(start, mySize, subset))
			{
				//resultSize=subset;//true
				//memcpy(resultArray, newArray, sizeof(size_t)*(n+1));				
				break;
			}
		}
		//cout<<"node "<<mpi_rank<<endl;
		MPI_Send(&resultSize, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
		//cout<<"myabs="<<myabs(resultSize)<<endl;
		if (resultSize!=0)
		{
			MPI_Send(resultArray, myabs(resultSize), MPI_INT, 0, 0, MPI_COMM_WORLD);
		}
	}
	
	MPI_Finalize();                         
	return 0;
}

  
file name: myset.h
 
#ifndef MYSET_H
#define MYSET_H

typedef unsigned char HashTableType;
typedef long long __int64;
typedef unsigned int size_t;

const size_t DefaultGroundSetSize=32;//4*8=32
const size_t DigitBitCount=sizeof(size_t)*8;//one byte
const size_t DefaultBitState=0;
const size_t HashTableSize=256;
const size_t DeleteMask=0xFFFFFFFF;
const size_t ComplementMask=DeleteMask;
const size_t SetOrderMask=0xFF;
const size_t SetOrderMaskCount=sizeof(size_t)/sizeof(HashTableType);

const size_t MaxGroundSetSize=1024;
const size_t MaxDigitCount=MaxGroundSetSize/8/sizeof(size_t);

size_t fact(size_t size);

size_t combine(size_t n, size_t k);

class MySet
{
public:
	//constructor
	MySet(size_t size=DefaultGroundSetSize);
	~MySet();

	//copy constructor
	MySet(const MySet& copy);

	//basic set operations
	
	//unary operations
	bool MemberOfSet(size_t index) const;
	void SetInsert(size_t index);
	void SetDelete(size_t index);
	size_t SetOrder();
	MySet Complement();

	//binary operations
	MySet Union(const MySet& other);	
	MySet Intersection(const MySet& other);	
	MySet Difference(const MySet& other);

	//operator overloading
	//set assignment
	MySet& operator=(const MySet& other);
	MySet& operator=(const size_t* array);

	//xor operation
	MySet& operator^(const MySet& other);
	
	bool operator==(const MySet& other);
	bool operator[](size_t index);
	

	//utility operations
	void display() const;
	void initialize(size_t size);
	void randomSet();
	size_t getSize(){ return groundSetSize;}	
	void flip(size_t index);
	void createByArray(size_t array[], size_t arraySize);

	
	//special set utility operations
	size_t LexRank();	
	void LexUnrank(size_t number);

	//subset utility
	//lexico
	size_t SubsetLexRank(size_t subsetSize);
	void SubsetLexUnRank(size_t subsetSize, size_t rank);
	void SubsetLexSuccessor(size_t subsetSize);

	//colex
	void SubsetColexSuccessor(size_t subsetSize);

	int getDigitCount()const {return digitCount;}
protected:
	static HashTableType hashTable[HashTableSize];
	static bool need2hash;
	int groundSetSize;
	size_t digitCount;
	size_t* digits;
	//int lastDigitSize;
	void initHashTable();
	void checkSize(size_t index)const;
	void checkSize(const MySet& other) const;
	void setSize(size_t size);//this should not be called by user!!!! try initialize(i);
	
	void clear();
	
};

#endif
 
 
file name: myset.cpp
#include "myset.h"
#include <iostream>

//typedef  int* set ;

using namespace std;

//pure for testing
long lastResult;



HashTableType MySet::hashTable[256];

bool MySet::need2hash=true;

MySet::MySet(size_t size)
{
	groundSetSize=0;
	initialize(size);
	//because we only need to initialize hash table once for all set objects
	if (need2hash)
	{
		initHashTable();
		need2hash=false;
	}
}

MySet::~MySet()
{
	delete[]digits;
}

//a copy constructor
MySet::MySet(const MySet& copy)
{
	//set groundsetsize to 0 to indicate this is the first time creating set
	groundSetSize=0;
	initialize(copy.groundSetSize);
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]=copy.digits[i];
	}
}


void MySet::initHashTable()
{
	size_t i, j;
	//int lowIndex=0, highIndex=1;
	//initialize half byte first
	hashTable[0]=0;
	hashTable[1]=1;
	hashTable[2]=1;
	hashTable[3]=2;
	hashTable[4]=1;
	hashTable[5]=2;
	hashTable[6]=2;
	hashTable[7]=3;
	for (i=0; i<8; i++)
	{
		hashTable[8+i]=hashTable[i]+1;
	}
	//initialize one byte and use it as a pattern in following
	for (i=1; i<16; i++)
	{
		for (j=0; j<16; j++)
		{
			hashTable[i*16+j]=hashTable[i]+hashTable[j];
		}	
	}
}

void MySet::display() const
{
	cout<<"\n[";
	for (int i=0; i<groundSetSize; i++)
	{
		if (MemberOfSet(i))
		{
			cout<<"1";
		}
		else
		{
			cout<<"0";
		}
	}
	cout<<"]\n";
}


void MySet::checkSize(size_t index) const
{
	if (index>=groundSetSize)
	{
		cout<<"error exceeding boundary";
		exit(1);
	}
}

//difference=A intersection complement(B)
MySet MySet::Difference(const MySet& other)
{
	checkSize(other);
	MySet result=other;
	result.Complement();
	return Intersection(result);
}

MySet MySet::Complement()
{
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i] ^= ComplementMask;
	}
	return *this;
}

//element starts from 1 instead of 0
bool MySet::MemberOfSet(size_t index) const
{
	size_t i,j;
	checkSize(index);
	i=index/DigitBitCount;
	j=index%DigitBitCount;
	return (digits[i]>>j)&1==1;		
}

//assume element is starting from 1 instead of 0
void MySet::SetInsert(size_t index)
{
	size_t i,j;
	checkSize(index);
	i=index/DigitBitCount;
	j=index%DigitBitCount;
	digits[i]|=(((size_t)1)<<j);
}

//assume element starts from 1 instead of 0
void MySet::SetDelete(size_t index)
{
	size_t i,j;
	size_t mask=DeleteMask;
	checkSize(index);
	i=index/DigitBitCount;
	j=index%DigitBitCount;
	mask^=(1<<j);
	digits[i]&=mask;
}

void MySet::checkSize(const MySet& other) const
{
	if (groundSetSize!=other.groundSetSize)
	{
		cout<<"two set has different ground set size!\n";
		exit(1);
	}
}

//return value instead of dynamic new memory
MySet MySet::Union(const MySet& other)
{
	checkSize(other);
	//choose the bigger groundsetsize of two 

	MySet result(groundSetSize);

	for (size_t i=0; i<digitCount; i++)
	{
		result.digits[i]=digits[i] | other.digits[i];
	}
	return result;
}

//set assignment maybe use set variable with old data
MySet& MySet::operator =(const MySet& other)
{
	//initialize(other.groundSetSize);
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]=other.digits[i];
	}
	return *this;
}

MySet& MySet::operator =(const size_t* array)
{
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]=array[i];
	}
	return *this;
}


MySet& MySet::operator ^(const MySet& other)
{
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]^=other.digits[i];
	}
	return *this;
}

//set is equal only when the ground set size is equal and all element equal	
bool MySet::operator ==(const MySet& other)
{
	if (groundSetSize!=other.groundSetSize)
	{
		return false;
	}
	for (size_t i=0; i<digitCount; i++)
	{
		if (digits[i]!=other.digits[i])
		{
			return false;
		}
	}
	return true;
}

//set intersection
MySet MySet::Intersection(const MySet& other)
{
	checkSize(other);
	MySet result(groundSetSize);
	for (size_t i=0; i<digitCount; i++)
	{
		result.digits[i]=digits[i]&other.digits[i];
	}
	return result;
}


	
size_t MySet::SetOrder()
{
	size_t result=0;
	size_t index;
	for (size_t i=0; i<digitCount; i++)
	{
		for (size_t j=0; j<SetOrderMaskCount; j++)
		{
			index=(digits[i]>>(j*8))&SetOrderMask;

			result+=hashTable[index];
		}
	}

	return result;
}	


void MySet::flip(size_t index)
{
	size_t i,j;
	checkSize(index);
	i=index/DigitBitCount;
	j=index%DigitBitCount;
	digits[i]^=((size_t)1<<j);	
}


void MySet::setSize(size_t size)
{
	groundSetSize=size;

	//DigitBitCount=ByteSize=8
	digitCount=groundSetSize/DigitBitCount;
	//last digit size is stored so that calculation will only be 
	//done once for all

	//if modulo 8==0, we don't need extra digit
	if (groundSetSize%DigitBitCount!=0)
	{
		digitCount++;
	}

}


void MySet::initialize(size_t size)
{
	//DefaultBitState is 0 for unset;
	
	if (size>0)
	{
		if (groundSetSize>=size)
		{
			//we don't have to reallocate memory
			setSize(size);
		}
		else
		{
			if (groundSetSize!=0)
			{
				delete[]digits;
			}
			setSize(size);
			
			digits= new size_t[digitCount];
			if (digits==NULL)
			{
				cout<<"unable allocate memory for ground set size of "<<groundSetSize<<endl;
				exit(1);
			}	
		}
		//memset(digits, DefaultBitState, digitCount);
		for (size_t i=0; i<digitCount; i++)
		{
			digits[i]=0;
		}

		//memset(digits, 0, digitCount);
	}
	else
	{
		groundSetSize=digitCount=0;
		digits=NULL;
	}
}


//colex
void MySet::SubsetColexSuccessor(size_t subsetSize)
{
	size_t result=0, i,j;
	size_t* array;
	if (SetOrder()!=subsetSize)
	{
		cout<<"subset size is not what it should be!\n";
		exit(1);
	}
	//first create an index array
	array=new size_t[subsetSize+1];
	array[0]=0;
	j=0;
	//translate into index array
	for (i=groundSetSize; i>=1; i--)
	{
		if (MemberOfSet(i-1))
		{
			array[j+1]=i;
			j++;
		}
	}

	i=1;
	while (i<=subsetSize&&array[i]==groundSetSize-i+1)
	{
		i++;
	}
	if (i==subsetSize+1)
	{
		cout<<"undefined";		
	}
	else
	{
		result=array[i];
		for (j=i; j<=subsetSize; j++)
		{
			array[j]=result+1-(j-i);
		}
		j=subsetSize;
		for (i=0; i<groundSetSize; i++)
		{
			if (i+1==array[j])
			{
				SetInsert(i);
				j--;
			}
			else
			{
				SetDelete(i);
			}
		}
	}
	delete[]array;
}


//this is limited within groundset size of 32 or less
//the order is lexicographic order
void MySet::SubsetLexUnRank(size_t subsetSize, size_t rank)
{
	size_t x=1, temp;
	if (subsetSize>groundSetSize)
	{
		cout<<"wrong subset size!\n";
		exit(1);
	}
	clear();
	for (size_t i=1; i<=subsetSize; i++)
	{
		temp=combine(groundSetSize-x, subsetSize-i);
		while (temp<=rank)
		{
			rank-=temp;
			x++;
			temp=combine(groundSetSize-x, subsetSize-i);
		}
		SetInsert(x-1);
		x++;
	}
}

//this is limited within groundset size of 32 or less
//the order is lexicographic order
void MySet::SubsetLexSuccessor(size_t subsetSize)
{
	size_t result=0, i,j;
	size_t* array;
	if (SetOrder()!=subsetSize)
	{
		cout<<"subset size is not what it should be!\n";
		exit(1);
	}
	//first create an index array
	array=new size_t[subsetSize+1];
	array[0]=0;
	j=0;
	//translate into index array
	for (i=0; i<groundSetSize; i++)
	{
		if (MemberOfSet(i))
		{
			array[j+1]=i+1;
			j++;
		}
	}

	i=subsetSize;
	while (i>=1&&array[i]==(groundSetSize-subsetSize+i))
	{
		i--;
	}
	if (i==0)
	{
		cout<<"undefined";		
	}
	else
	{
		result=array[i];
		for (j=i; j<=subsetSize; j++)
		{
			array[j]=result+1+j-i;
		}
		j=1;
		for (i=0; i<groundSetSize; i++)
		{
			if (i+1==array[j])
			{
				SetInsert(i);
				j++;
			}
			else
			{
				SetDelete(i);
			}
		}
	}
	delete[]array;
}

		



//this is limited within groundset size of 32 or less
//the order is lexicographic order
size_t MySet::SubsetLexRank(size_t subsetSize)
{
	size_t result=0, i,j;
	size_t* array;
	if (SetOrder()!=subsetSize)
	{
		cout<<"subset size is not what it should be!\n";
		exit(1);
	}
	//first create an index array
	array=new size_t[subsetSize+1];
	array[0]=0;
	j=0;
	//translate into index array
	for (i=0; i<groundSetSize; i++)
	{
		if (MemberOfSet(i))
		{
			array[j+1]=i+1;
			j++;
		}
	}

	
	for (i=1; i<=subsetSize; i++)
	{
		if (array[i-1]+1<array[i])
		{
			for (j=array[i-1]+1; j<array[i]; j++)
			{
				result+=combine(groundSetSize-j, subsetSize-i);
			}
		}
	}
	delete []array;
	return result;
}


void MySet::createByArray(size_t array[], size_t arraySize)
{
	//let's have a simple groundsetsize as for 
	initialize(arraySize*sizeof(size_t)*8);

	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]=array[i];
	}
}

//I would leave big number problem to future
size_t MySet::LexRank()
{
	//temporarily I would assume there is only a small set
	return digits[0];
}


//I would wait for future for big ground set problem
void MySet::LexUnrank(size_t number)
{
	initialize(sizeof(size_t)*8);
	digits[0]=number;
}


void MySet::randomSet()
{
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]=rand();
	}
}


bool MySet::operator [](size_t index)
{	
	return MemberOfSet(index);
}

void MySet::clear()
{
	size_t mask=0;
	for (size_t i=0; i<digitCount; i++)
	{
		digits[i]=mask;
	}
}


size_t fact(size_t size)
{
	size_t result=1;
	for (int i=2; i<=size; i++)
	{
		result*=i;
	}
	return result;
}


size_t combine(size_t n, size_t k)
{
	size_t result=1;
	if (n<k)
	{
		cout<<"combine number is wrong!\n";
		exit(1);
	}
	for (int i=0; i<k; i++)
	{
		result*=(n-i);
	}
	return result/fact(k);
}
	
	
file name: revolve.h
#include <iostream>
#include "myset.h"

using namespace std;

void displayArray(size_t* array, size_t start, size_t size);
void revolveUnRank(long theRank, size_t subSize, size_t* array);
void readFromFile(char* fileName);
bool weightTest(__int64 startRank, __int64 count, int subSize);
void initialize(size_t theN, size_t theK, size_t theD, size_t* array);
__int64 combineNumber(size_t n, size_t k);
void algoR(size_t k, size_t* array);
const int NoResult=-1000;


	
 
file name: revolve.cpp
#include "revolve.h"
#include "myset.h"

#include <iostream>
#include <fstream>


using namespace std;


size_t groundsetSize, subsetSize;

size_t n, k, d;
size_t* buffer;
size_t bufferSize;
MySet* sets;
int resultSize=0;



MySet current;
//bool findEqual=false;
size_t* resultArray=NULL; //this is used to return the array with weight of d
size_t* oldArray=NULL;
size_t* newArray=NULL;
size_t* c;


__int64  combineNumber(size_t n, size_t k)
{
	__int64 result =1;
	for (size_t i=0; i<k; i++)
	{
		result=result*(n-i)/(i+1);
	}

	return result;
}


void revolveUnRank(__int64 theRank, size_t subSize, size_t* c)
{
	__int64 last=-1, curr=-1, r=theRank;
	int i;
	size_t x=groundsetSize;
	subsetSize=subSize;

	for (i=subsetSize; i>=1; i--)
	{
		do
		{
			last=curr;
			curr=combineNumber(x, i);
			if (curr>r)
			{
				x--;
			}
			else
			{
				break;
			}
		}while (true);
	
		if (last==r)
		{
			c[i]=x-1;	
		}
		else
		{
			c[i]=x;	
		}
		r=last-r-1;
	}

}

int findSmallest(int& oldIndex, int& newIndex)
{
	while (oldIndex<=subsetSize&&newIndex<=subsetSize)
	{
		if (oldArray[oldIndex]==newArray[newIndex])
		{
			oldIndex++;
			newIndex++;
		}
		else
		{
			if (oldArray[oldIndex]<newArray[newIndex])
			{
				//must make easy for next 
				return oldArray[oldIndex++];
			}
			else
			{				
				return newArray[newIndex++];
			}
		}
	}
	
	if (oldIndex==newIndex&&oldIndex==subsetSize+2)
	{
		cout<<"find smallest failed, check array!\n";
		exit(1);
	}
	else
	{
		if (oldIndex<newIndex)
		{
			return oldArray[oldIndex];
		}
		else
		{
			return newArray[newIndex];
		}
	}
}

void displayArray(size_t* array, size_t start, size_t size)
{
	cout<<"[";
	for (size_t i=start; i<size; i++)
	{
		cout<<array[i];
		if (i!=start+size-1)
		{
			cout<<",";
		}
	}
	cout<<"]\n";
}					

void findChangedVectorIndex(int& first, int& second)
{
	int oldIndex=1, newIndex=1;
	first=findSmallest(oldIndex, newIndex);
	second=findSmallest(oldIndex, newIndex);
}

//return true means there is no exception, and false means we find smaller d
bool weightTest(__int64 startRank, __int64 count,  int subSize)
{
	subsetSize=subSize;
	int left, right;
	for (__int64 i=0; i<count; i++)
	{
		//I cannot use two arrays to alternatively, it is too complicated
		/*
		for (int j=0; j<subSize+1; j++)
		{
			oldArray[j]=newArray[j];
		}
		*/
		memcpy(oldArray, newArray, sizeof(size_t)*(n+1));
		//for the first time, we need this to initialize
		if (i==0)
		{
			revolveUnRank(startRank+i, subSize, newArray);
			//displayArray(newArray, 1, subSize);
		}
		else
		{
			algoR(subSize, newArray);
			//displayArray(newArray, 1, subSize);
		}

		if (i==0)
		{
			//things become more complicated because unrank starts from index 1
			current=sets[newArray[1]];
			for (int j=2; j<subSize+1; j++)
			{
				current^(sets[newArray[j]]);
			}
		}
		else
		{
			findChangedVectorIndex(left, right);//not the index of array
			current^(sets[left]);
			current^(sets[right]);
		}
		size_t temp=current.SetOrder();	
		if (temp<d)
		{
			/*
			cout<<"this means we find the combination with weight smaller than d:\n";
			for (int m=1; m<subSize+1; m++)
			{
				cout<<newArray[m]<<",";
			}
			*/
			resultSize=subSize;
			//resultArray[0]=subSize;
			memcpy(resultArray, newArray+1, sizeof(size_t)*subSize);
			return false;//means we find the 
		}
		else
		{
			if (temp==d)
			{
				//findEqual=true;
				resultSize=-subSize;
				//resultArray[0]=-subSize;
				memcpy(resultArray, newArray+1, sizeof(size_t)*subSize);
			}
		}
	}
	return true;
}

void initialize(size_t theN, size_t theK, size_t theD, size_t* array)
{
	groundsetSize=theK;
	n=theN;
	k=theK;
	d=theD;

	sets=new MySet[k];
	for (int i=0; i<k; i++)
	{
		sets[i].initialize(n);
		//this may seem to be odd, I overload the operator= for size_t* to copy array
		sets[i]=array+(i*sets[i].getDigitCount());
	}
	current.initialize(n);
	oldArray=new size_t[n+1];
	newArray=new size_t[n+1];
	resultArray=new size_t[n+1];	
}


void readFromFile(char* fileName)
{
	//size_t* array;
	size_t temp, size, mask=1;
	int i, j;
	int number;
	ifstream in(fileName);
	in>>n;
	cout<<"n="<<n<<", ";
	in>>k;
	cout<<"k="<<k<<", ";
	in>>d;
	cout<<"d="<<d<<"\n";

	size=n/32;
	if (n%32!=0)
	{
		size++;
	}
	bufferSize=size*k;

	buffer=new size_t[bufferSize];
	for (i=0; i<k; i++)
	{		
		number=-1;//the number of int
		cout<<"[";
		for (j=0; j<n; j++)
		{
			if (j%32==0)
			{
				number++;
				buffer[i*size+number]=0;
			}
			in>>temp;		
			cout<<temp;
			if (temp!=0)
			{
				buffer[i*size+number] |= (mask<<j);				
			}	
		}
		cout<<"]\n";
	}	
}


void algoR(size_t t, size_t* c)
{
	size_t j;

	if (t%2==1)
	{
		if (c[1]+1<c[2])
		{
			c[1]++;
			return;
			//goto R2;
		}
		else
		{
			j=2;
			goto R4;	
		}
	}
	else
	{
		if (c[1]>0)
		{
			c[1]--;
			return;
			//goto R2;
		}
		else
		{
			j=2;
			goto R5;
		}
	}

R4:
	if (c[j]>=j)
	{
		c[j]=c[j-1];
		c[j-1]=j-2;
		return;
		//goto R2;
	}
	else
	{
		j++;
	}
R5:
	if (c[j]+1<c[j+1])
	{
		c[j-1]=c[j];
		c[j]++;
		return;
		//goto R2;
	}
	else
	{
		j++;
		if (j<=t)
		{
			goto R4;
		}
	}
}
		








file name: makefile

myset : main.cpp myset.cpp myset.h revolve.cpp revolve.h
g++ -g main.cpp myset.cpp revolve.cpp -o myset.exe


mpi : mpi.cpp myset.cpp myset.h revolve.cpp revolve.h
mpic++ mpi.cpp myset.cpp revolve.cpp -o mpimyset.exe








test files: 
1. test0.txt
2. test1.txt
3. test2.txt
4. test3.txt
5. test4.txt
6. test5.txt
Result:
result0.txt to result4.txt are all run by local program which is very fast. Currently I can only
finish MPI version running for case 5 which takes 22945 seconds. And then I decide to run both 
case 6 and case 7 on "breca" and it is expected to run for very long because the complexity of 
case 6 is almost ten times bigger than case 5. And case 7 is more than six thousand times bigger.
file name: test0.txt
7 4 4
1 0 0 0 1 1 0
0 1 0 0 1 0 1
0 0 1 0 0 1 1
0 0 0 1 1 1 1

file name: test1.txt

23 12 8
1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 0 0 0 1
0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 1 0
0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 1 1 0 0 0 1 0 1
0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 0 1 1
0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 1 0 1 1 0
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 0 1
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1
0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 1 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 0 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 1 1 1 0 0 0
file name: test2.txt
24 12 8
1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 0 0 0 1 0
0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 1 0 1
0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 1 1 0 0 0 1 0 1 1
0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 0 1 1 0
0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 1 0 1 1 0 1
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 0 1 1
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 1 0 1 1 1 0
0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 1 0 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 1 1 1 0 0 0 1
 
 
file name: test3.txt
32 16 7
 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 0 1
 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1
 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 1
 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0
 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0
 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 0 1 0
 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 0 0 1 0 1
 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 0 0 1 1
 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 0 0 0
 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 1 0 1 1 0 0 1 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 1 1 0 1 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 1 1 0 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 0 1 1
 
file name: test4.txt
48 24 12
 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 1
 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 0 0 1 1 0 0 1
 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 0 0 1 1 0 1
 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 0 0 1 1 1
 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 1 1 0 1 0 0 1 0
 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 1 0 0 1 0 1 1 0 0 1
 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 1 0 0 1 0 1 1 0 1
 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0 1 0 0 1 0 1 1 1
 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 1 0
 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 1 1 0 0 0 0 1 1 0 1
 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 0 1 1 1 1 0 0 0 0 1 1 1
 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 1 1 0 0 1 1 1 0 1 0 1 1 1 1 1 0 0 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 1 0 0 1 1 0 0 1 0 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 1 0 0 1 1 0 0 1 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 1 0 0 1 1 0 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 1 0 1 0 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 1 0 1 0 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 1 0 1 0 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 1 0 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 1 0 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 1 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 1 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 1 1
 
 
file name: test5.txt
72 36 12
 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0 1
 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1
 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 0 0 0 1 1 0 0 1 0 0
 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 0 0 1 0 1 0 1 0 1 0 0 0 0 1 1 0 0 0 1 1 0 0 1 0
 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 0 0 1 1 1 0 1
 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 0 0 1 1 1 1
 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 1 1 1 0 0 1 0 1 0 0 0 1 0
 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 1 1 1 0 1 0 1 0 1
 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 1 1 1 0 1 0 1 1
 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 1 0 0 0 1 1 0 1 1 0 0 0 1 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 1 1 0 1 0 1 0 0 0 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 1 1 0 1 0 1 0 0 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 1 1 0 1 0 1 0 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 1 1 0 1 0 1 0 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 1 1 0 1 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 0 1 1 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 0 1 1 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 0 1 1 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 0 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 1 0 0 1 1 1 0 1 1 1 0 0 0 0 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1 1 0 1 0 0 0 1 1 0 0 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 1 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0 1 1
 

(There are originally more test cases but I haven't even finished running test5!)
A snapshot of running automated testing:
[qingz_hu@breca knuth]$ mpirun -np 9 ./mpimyset.exe test0.txt
n=7, k=4, d=4
[1000110]
[0100101]
[0010011]
[0001111]
node 8 has smaller weight
The combination is:
[0]
the total time in seconds is 0
[qingz_hu@breca knuth]$ mpirun -np 9 ./mpimyset.exe test2.txt
n=24, k=12, d=8
[100000000000011111111111]
[010000000000111011100010]
[001000000000110111000101]
[000100000000101110001011]
[000010000000111100010110]
[000001000000111000101101]
[000000100000110001011011]
[000000010000100010110111]
[000000001000100101101110]
[000000000100101011011100]
[000000000010110110111000]
[000000000001101101110001]
node 4 has found a combination of weight equal to d
The combination is:
[0,1,2,4,5,6,10]
node 5 has found a combination of weight equal to d
The combination is:
[0,2,3,4,8,10,11]
node 1 has found a combination of weight equal to d
The combination is:
[0,1,2,3,4]
node 8 has found a combination of weight equal to d
The combination is:
[0,2,3,5,6,7,11]
node 2 has found a combination of weight equal to d
The combination is:
[1,2,3,5,6,9]
node 3 has found a combination of weight equal to d
The combination is:
[0,3,5,6,8,9,10]
node 6 has found a combination of weight equal to d
The combination is:
[0,1,3,4,5,9,11]
node 7 has found a combination of weight equal to d
The combination is:
[0,1,2,6,8,9,11]
no small weight found in any node
the total time in seconds is 0
[qingz_hu@breca knuth]$ mpirun -np 9 ./mpimyset.exe test3.txt
n=32, k=16, d=7
[10000000000000001110001100001001]
[01000000000000000111000110000101]
[00100000000000000011100011000011]
[00010000000000001111111101101000]
[00001000000000000111111110110100]
[00000100000000000011111111011010]
[00000010000000001111110011100101]
[00000001000000000111111001110011]
[00000000100000001101110000110000]
[00000000010000000110111000011000]
[00000000001000000011011100001100]
[00000000000100000001101110000110]
[00000000000010001110111011001011]
[00000000000001001001010001101100]
[00000000000000100100101000110110]
[00000000000000011100011000010011]
no small weight found in any node
the total time in seconds is 0
[qingz_hu@breca knuth]$ mpirun -np 9 ./mpimyset.exe test4.txt
n=48, k=24, d=12
[100000000000000000000000111101110110111000110001]
[010000000000000000000000011110111011011100011001]
[001000000000000000000000001111011101101110001101]
[000100000000000000000000000111101110110111000111]
[000010000000000000000000111110000001100011010010]
[000001000000000000000000100010110110001001011001]
[000000100000000000000000010001011011000100101101]
[000000010000000000000000001000101101100010010111]
[000000001000000000000000111001100000001001111010]
[000000000100000000000000100001000110111100001101]
[000000000010000000000000010000100011011110000111]
[000000000001000000000000110101100111010111110010]
[000000000000100000000000100111000101010011001001]
[000000000000010000000000010011100010101001100101]
[000000000000001000000000001001110001010100110011]
[000000000000000100000000111001001110010010101000]
[000000000000000010000000011100100111001001010100]
[000000000000000001000000001110010011100100101010]
[000000000000000000100000111010111111001010100101]
[000000000000000000010000011101011111100101010011]
[000000000000000000001000110011011001001010011000]
[000000000000000000000100011001101100100101001100]
[000000000000000000000010001100110110010010100110]
[000000000000000000000001111011101101110001100011]
node 3 has found a combination of weight equal to d
The combination is:
[3,4,10,11,12,14,15,16,17,21]
node 2 has found a combination of weight equal to d
The combination is:
[2,3,9,10,11,13,14,15,16,20]
node 7 has found a combination of weight equal to d
The combination is:
[1,2,3,6,7,15,18,19,20,21,23]
node 1 has found a combination of weight equal to d
The combination is:
[0,1,2]
node 4 has found a combination of weight equal to d
The combination is:
[0,1,2,3,4,11,12,16,17,19,22]
node 5 has found a combination of weight equal to d
The combination is:
[4,5,11,12,13,15,16,17,18,22]
node 6 has found a combination of weight equal to d
The combination is:
[1,2,4,6,7,8,9,21,22,23]
node 8 has found a combination of weight equal to d
The combination is:
[0,4,5,8,9,11,12,15,18,20,23]
no small weight found in any node
the total time in seconds is 2
[qingz_hu@breca knuth]$ mpirun -np 9 ./mpimyset.exe test5.txt
n=72, k=36, d=12
[100000000000000000000000000000000000110011011000010001000000111110000101]
[010000000000000000000000000000000000011001101100001000100000011111000011]
[001000000000000000000000000000000000111111101110010101010000110001100100]
[000100000000000000000000000000000000011111110111001010101000011000110010]
[000010000000000000000000000000000000111100100011110100010100110010011101]
[000001000000000000000000000000000000011110010001111010001010011001001111]
[000000100000000000000000000000000000111100010000101100000101110010100010]
[000000010000000000000000000000000000101101010000000111000010000111010101]
[000000001000000000000000000000000000010110101000000011100001000011101011]
[000000000100000000000000000000000000111000001100010000110000011111110000]
[000000000010000000000000000000000000011100000110001000011000001111111000]
[000000000001000000000000000000000000001110000011000100001100000111111100]
[000000000000100000000000000000000000000111000001100010000110000011111110]
[000000000000010000000000000000000000110000111000100000000011111111111011]
[000000000000001000000000000000000000101011000100000001000001000001111000]
[000000000000000100000000000000000000010101100010000000100000100000111100]
[000000000000000010000000000000000000001010110001000000010000010000011110]
[000000000000000001000000000000000000110110000000110001001000110110001011]
[000000000000000000100000000000000000101000011000001001100100100101000000]
[000000000000000000010000000000000000010100001100000100110010010010100000]
[000000000000000000001000000000000000001010000110000010011001001001010000]
[000000000000000000000100000000000000000101000011000001001100100100101000]
[000000000000000000000010000000000000000010100001100000100110010010010100]
[000000000000000000000001000000000000000001010000110000010011001001001010]
[000000000000000000000000100000000000110011110000001001001001011010100001]
[000000000000000000000000010000000000011001111000000100100100101101010001]
[000000000000000000000000001000000000001100111100000010010010010110101001]
[000000000000000000000000000100000000000110011110000001001001001011010101]
[000000000000000000000000000010000000000011001111000000100100100101101011]
[000000000000000000000000000001000000110010111111110001010010101100110000]
[000000000000000000000000000000100000011001011111111000101001010110011000]
[000000000000000000000000000000010000001100101111111100010100101011001100]
[000000000000000000000000000000001000000110010111111110001010010101100110]
[000000000000000000000000000000000100110000010011101110000101110100110111]
[000000000000000000000000000000000010101011010001100110000010000100011110]
[000000000000000000000000000000000001100110110000100010000001111100001011]
node 7 has found a combination of weight equal to d
The combination is:
[6,8,13,14,20,23,24,27,30,33,35]
node 5 has found a combination of weight equal to d
The combination is:
[5,7,12,13,19,22,23,26,29,32,34]
node 4 has found a combination of weight equal to d
The combination is:
[4,6,11,12,18,21,22,25,28,31,33]
node 2 has found a combination of weight equal to d
The combination is:
[0,2,3,7,15,21,27,28,29,30]
node 8 has found a combination of weight equal to d
The combination is:
[3,6,11,13,16,17,21,23,28,35]
node 6 has found a combination of weight equal to d
The combination is:
[2,5,10,12,15,16,20,22,27,34]
node 3 has found a combination of weight equal to d
The combination is:
[3,5,10,11,17,20,21,24,27,30,32]
no small weight found in any node
the total time in seconds is 649

			
n=80, k=40, d=16
[10000000000000000000000000000000000000001110110000010110101111001111011100011001]
[01000000000000000000000000000000000000000111011000001011010111100111101110001101]
[00100000000000000000000000000000000000000011101100000101101011110011110111000111]
[00010000000000000000000000000000000000001111000110010100011010110110100111111010]
[00001000000000000000000000000000000000001001010011011100100010010100001111100101]
[00000100000000000000000000000000000000000100101001101110010001001010000111110011]
[00000010000000000000000000000000000000001100100100100001100111101010011111100000]
[00000001000000000000000000000000000000000110010010010000110011110101001111110000]
[00000000100000000000000000000000000000000011001001001000011001111010100111111000]
[00000000010000000000000000000000000000000001100100100100001100111101010011111100]
[00000000001000000000000000000000000000000000110010010010000110011110101001111110]
[00000000000100000000000000000000000000001110101001011111101100000000001000100111]
[00000000000010000000000000000000000000001001100100111001011001001111011000001010]
[00000000000001000000000000000000000000001010000010001010000011101000110000011101]
[00000000000000100000000000000000000000000101000001000101000001110100011000001111]
[00000000000000010000000000000000000000001100010000110100001111110101010000011110]
[00000000000000001000000000000000000000001000111000001100101000110101110100010111]
[00000000000000000100000000000000000000001010101100010000111011010101100110010010]
[00000000000000000010000000000000000000001011100110011110110010100101101111010001]
[00000000000000000001000000000000000000000101110011001111011001010010110111101001]
[00000000000000000000100000000000000000000010111001100111101100101001011011110101]
[00000000000000000000010000000000000000000001011100110011110110010100101101111011]
[00000000000000000000001000000000000000001110011110001111010100000101001010100100]
[00000000000000000000000100000000000000000111001111000111101010000010100101010010]
[00000000000000000000000010000000000000001101010111110101011010001110001110110001]
[00000000000000000000000001000000000000000110101011111010101101000111000111011001]
[00000000000000000000000000100000000000000011010101111101010110100011100011101101]
[00000000000000000000000000010000000000000001101010111110101011010001110001110111]
[00000000000000000000000000001000000000001110000101001001111010100111100100100010]
[00000000000000000000000000000100000000001001110010110010010010011100101110001001]
[00000000000000000000000000000010000000000100111001011001001001001110010111000101]
[00000000000000000000000000000001000000000010011100101100100100100111001011100011]
[00000000000000000000000000000000100000001111111110000000111101011100111001101000]
[00000000000000000000000000000000010000000111111111000000011110101110011100110100]
[00000000000000000000000000000000001000000011111111100000001111010111001110011010]
[00000000000000000000000000000000000100001111001111100110101000100100111011010101]
[00000000000000000000000000000000000010000111100111110011010100010010011101101011]
[00000000000000000000000000000000000001001101000011101111000101000110010010101100]
[00000000000000000000000000000000000000100110100001110111100010100011001001010110]
[00000000000000000000000000000000000000011101100000101101011110011110111000110011]
node 8 has found a combination of weight equal to d
The combination is:
[0,5,6,8,9,10,12,13,20,24,29,30,32,33,39]
node 6 has found a combination of weight equal to d
The combination is:
[0,1,6,7,8,9,11,12,13,20,21,24,25,38]
node 7 has found a combination of weight equal to d
The combination is:
[1,2,6,11,12,13,23,25,28,30,33,34,36,39]
node 4 has found a combination of weight equal to d
The combination is:
[3,4,6,7,8,10,11,18,22,27,28,30,31,37]
node 5 has found a combination of weight equal to d
The combination is:
[0,1,4,5,6,7,8,18,22,28,30,33,34,38]
node 3 has found a combination of weight equal to d
The combination is:
[2,3,5,6,7,9,10,17,21,26,27,29,30,36]
node 2 has found a combination of weight equal to d
The combination is:
[1,2,4,5,6,8,9,16,20,25,26,28,29,35]
no small weight found in any node
the total time in seconds is 43590
				 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)