#include #include #include #include #include "mpi.h" #define MAX_DEPTH 500 #define PUZZLE_SIZE 10 using namespace std; //A structure defined to represent the state of each node /state typedef struct { int grid[PUZZLE_SIZE][PUZZLE_SIZE]; char path[MAX_DEPTH]; int blankROW; int blankCOL; int depth; int hVal; } puzzleStruct; class puzzle { // basic node for 15 puzzle private: puzzleStruct myPuzzle; public: puzzle* parent; puzzle(); // default constructor puzzle(puzzle* p1); // copy puzzle constructor void print(); // print puzzle void printPath(); // print path to void randomPath(int i); int moveNorth(); // operators int moveSouth(); int moveWest(); int moveEast(); int equals(puzzle p1); // equality test int getDepth(); int gethVal(); //template list successorFunction() // successor function { list daughters; puzzle *temp; temp = new puzzle( this ); if (temp->moveNorth()) daughters.push_back(*temp); temp = new puzzle( this ); if (temp->moveSouth()) daughters.push_back(*temp); temp = new puzzle( this ); if (temp->moveEast()) daughters.push_back(*temp); temp = new puzzle( this ); if (temp->moveWest()) daughters.push_back(*temp); return daughters; } int sendNode(int proc, int tag); // function for distributing the user defined type i.e puzzleStruct int receiveNode(int proc, int tag); // function for collecting the user defined type i.e puzzleStruct bool operator < (puzzle &p1); int calculateHeristic(); void resetDepth(); void generateStart(int i); char* getPath(); ~puzzle(); }; puzzle::~puzzle() { }; //default constructor for initialing the puzzle class object puzzle::puzzle() { myPuzzle.blankROW = 0; myPuzzle.blankCOL = 0; myPuzzle.depth = 0; myPuzzle.path[0] = '\0'; for (int i = 0; imyPuzzle.blankROW; myPuzzle.blankCOL = p1->myPuzzle.blankCOL; strcpy(myPuzzle.path, p1->myPuzzle.path); myPuzzle.depth = p1->myPuzzle.depth; myPuzzle.hVal = p1->gethVal(); for (int i = 0; imyPuzzle.grid[i][j]; } } } // fucntion for keeping track of the nodes/states traversed void puzzle::printPath(){ int i = 0; char c = myPuzzle.path[i]; cout << "depth: " << myPuzzle.depth << "\n"; while(c != '\0'){ c = myPuzzle.path[i]; if( c == '\n' ){ cout << "[" << "newLine" << "] "; } else if( c == '\t'){ cout << "[" << "tab" << "] "; } else { cout << "[" << c << "] "; } i++; } cout << "[" << "null" << "]"; cout << endl; } //function for returning the path of the puzzle char* puzzle::getPath(){ return myPuzzle.path; } void puzzle::print() { //function for printing the state / node cout << "Puzzle State: w/ path: (" << myPuzzle.path << ") depth: " << myPuzzle.depth << " and h-value: " << myPuzzle.hVal << "\n"; for (int i=0; i puzzle::successorFunction() { list daughters; puzzle *temp; temp = new puzzle( this ); if (temp->moveNorth()) daughters.push_back(*temp); temp = new puzzle( this ); if (temp->moveSouth()) daughters.push_back(*temp); temp = new puzzle( this ); if (temp->moveEast()) daughters.push_back(*temp); temp = new puzzle( this ); if (temp->moveWest()) daughters.push_back(*temp); return daughters; } */ // A function for defining a structure for MPI to distribute the node/state object through out the processes int puzzle::sendNode(int proc, int tag) { int blockcounts[3] = {PUZZLE_SIZE*PUZZLE_SIZE,MAX_DEPTH, 4};//count of the blocks of the subsequent type MPI_Datatype types[3];//number of the types used in the mpi struct MPI_Aint displs[3];//record of the displacement from the beginning of a particular type block MPI_Datatype puzzletype;// name of the mpi structure object // initialize types and displs with addresses of items MPI_Address( &myPuzzle.grid, &displs[0] ); MPI_Address( &myPuzzle.path, &displs[1] ); MPI_Address( &myPuzzle.blankROW, &displs[2] ); //consecutive types in mpi types[0] = MPI_INT; types[1] = MPI_CHAR; types[2] = MPI_INT; for (int i = 2; i >= 0; i --) //substracting the base address from the subsequent displacements displs [i] -= displs [0]; //MPI_Type_struct( no, blockcounts, displs, types,mpi_structure); MPI_Type_struct( 3, blockcounts, displs, types, &puzzletype ); //use the structure in mpi MPI_Type_commit( &puzzletype ); // send the mpi structure MPI_Send(&myPuzzle, 1, puzzletype, proc, tag, MPI_COMM_WORLD); return 1; } // A function for defining a structure for MPI to collect the node/state object through out the processes int puzzle::receiveNode(int proc, int tag) { int blockcounts[3] = {PUZZLE_SIZE*PUZZLE_SIZE,MAX_DEPTH, 4}; MPI_Datatype types[3]; MPI_Aint displs[3]; MPI_Datatype puzzletype; MPI_Status status; // initialize types and displs with addresses of items MPI_Address( &myPuzzle.grid, &displs[0] ); MPI_Address( &myPuzzle.path, &displs[1] ); MPI_Address( &myPuzzle.blankROW, &displs[2] ); types[0] = MPI_INT; types[1] = MPI_CHAR; types[2] = MPI_INT; for (int i = 2; i >= 0; i --) displs [i] -= displs [0]; MPI_Type_struct( 3, blockcounts, displs, types, &puzzletype ); MPI_Type_commit( &puzzletype ); MPI_Recv(&myPuzzle, 1, puzzletype, proc, tag, MPI_COMM_WORLD, &status); return 1; } void puzzle::randomPath( int i ) { srand( time(NULL) ); int r; while( getDepth() < i ) { r = rand() % 4; if(r == 0){ moveNorth(); } else if(r == 1){ moveEast(); } else if(r == 2){ moveSouth(); } else if(r == 3){ moveWest(); } } } void puzzle::generateStart(int i) { moveSouth(); moveEast(); moveEast(); moveNorth(); moveWest(); if(i == 5) return; moveWest(); moveSouth(); moveSouth(); moveSouth(); moveEast(); if(i == 10) return; moveNorth(); moveEast(); moveEast(); moveNorth(); moveWest(); if(i == 15) return; moveSouth(); moveSouth(); moveWest(); moveNorth(); moveNorth(); if(i == 20) return; moveEast(); moveEast(); moveSouth(); moveSouth(); moveWest(); if(i == 25) return; moveNorth(); moveWest(); moveNorth(); moveEast(); moveSouth(); if(i == 30) return; } class searchFunctions { private: int rank; int size; int depth; int numNodesExpanded; int numNodesGenerated; int numDeletedNodes; double myStartTime, myEndTime; bool goalFound; public: searchFunctions(); puzzle* BFS(puzzle* start, puzzle* goal); puzzle* DFS(puzzle* start, puzzle* goal, int depthBound); puzzle* aStar(puzzle* start, puzzle* goal); puzzle* IDDFS(puzzle* start, puzzle* goal, int depthBound, int increment); puzzle* parallelAStar(puzzle* start, puzzle* goal); int parallelBFS(puzzle* start, puzzle* goal); puzzle* parallelDFS(puzzle* start, puzzle* goal, int depthBound); puzzle* parallelIDDFS(puzzle* start, puzzle* goal, int depthBound, int increment); puzzle* parallelIDAStar(puzzle* start, puzzle* goal); int checkOpenClosed(puzzle *curPuzzle, list *openList, list *closedList); puzzle* IDA_STAR(puzzle* start, puzzle* goal); int DFS_star(puzzle* start, puzzle* goal, int Bound); void printStats(); }; int searchFunctions::DFS_star(puzzle* start, puzzle* goal, int Bound) { int min_bound=0; int h,B; list openList; list closedList; puzzle curPuzzle; if((start->gethVal()-start->getDepth())>Bound) { h=(start->gethVal()-start->getDepth()); return h; } else if(start->gethVal()==0) { return 1; } else { openList = start->successorFunction(); openList.sort(); while(!openList.empty()) { curPuzzle = *openList.begin(); openList.pop_front(); closedList.push_back(curPuzzle); B = curPuzzle.gethVal()-curPuzzle.getDepth(); if(B <= Bound) { if(curPuzzle.equals(*goal)) { return 1; } numNodesExpanded++; numNodesGenerated += checkOpenClosed( &curPuzzle, &openList,&closedList ); } if(min_bound>B) { min_bound=B; } *start=curPuzzle; openList.sort(); numNodesExpanded++; numNodesGenerated += checkOpenClosed( &curPuzzle, &openList, &closedList ); } return min_bound; } numNodesExpanded = 0; numNodesGenerated = openList.size(); } puzzle* searchFunctions::IDA_STAR(puzzle* start, puzzle* goal) { int bound=start->gethVal(); myStartTime = MPI_Wtime(); // Get Start time while(!(start->equals(*goal))) { bound=DFS_star(start,goal,bound); if(bound==0) { cout<<"still working"<gethVal()-start->getDepth() << " with path: " << start->getPath() << endl; myEndTime = MPI_Wtime(); // Get End time cout<<"goal met"< openList; list::const_iterator openListITR; list closedList; list::const_iterator closedListITR; openList = start->successorFunction(); numNodesExpanded = 0; numNodesGenerated = openList.size(); while(!openList.empty()) { puzzle curPuzzle = *openList.begin(); openList.pop_front(); closedList.push_back(curPuzzle); if(curPuzzle.equals(*goal)) { depth = curPuzzle.getDepth(); goalFound = true; return new puzzle( &curPuzzle); } list daughters = curPuzzle.successorFunction(); numNodesExpanded ++; numNodesGenerated += daughters.size(); openList.splice( openList.end(), daughters ); } return NULL; } puzzle* searchFunctions::DFS(puzzle* start, puzzle* goal, int depthBound) { list openList; list closedList; puzzle curPuzzle; openList = start->successorFunction(); numNodesExpanded = 0; numNodesGenerated = openList.size(); while(!openList.empty()) { curPuzzle = *openList.begin(); openList.pop_front(); closedList.push_back(curPuzzle); depth = curPuzzle.getDepth(); if(depth <= depthBound) { if(curPuzzle.equals(*goal)) { goalFound = true; return new puzzle( &curPuzzle); } numNodesExpanded++; numNodesGenerated += checkOpenClosed( &curPuzzle, &openList, &closedList ); } } return NULL; } puzzle* searchFunctions::parallelDFS(puzzle* start, puzzle* goal, int depthBound) { //initialize nodes puzzle myNode; puzzle *myGoal; myGoal = new puzzle(); // Generate nodes to send to each proc if(rank == 0) { puzzle tempsend; list openList; openList = start->successorFunction(); // for each processor, make sure it has a node to start with while(openList.size() < size) { tempsend = *openList.begin(); openList.pop_front(); list daughters = tempsend.successorFunction(); openList.splice( openList.end(), daughters ); } //Distribute nodes to each proc cout << "Distributing " << openList.size() << " Start Nodes to Processors\n"; for(int i=1; igetDepth() << " with path: " << myGoal->getPath() << endl; myEndTime = MPI_Wtime(); myGoal->print(); } //Check if anyone else has found the goal MPI_Test(&request, &myFlag, &myStatus); //If someone else has found the goal if(myFlag == 1 && myGoal == NULL) { // cout<<"checked"< *openList, list *closedList) { list daughters = curPuzzle->successorFunction(); list::iterator daughtersITR; list::iterator tempDaughtersITR; list::const_iterator openITR; list::const_iterator closedITR; int daughterSize = 0; bool deletedNode = false; puzzle daughterPuz, openPuz, closedPuz; for(daughtersITR = daughters.begin(); daughtersITR != daughters.end(); ++daughtersITR) { deletedNode = false; daughterPuz = *daughtersITR; for(openITR = openList->begin(); openITR != openList->end(); ++openITR) { openPuz = *openITR; if(openPuz.equals( daughterPuz )) { tempDaughtersITR = daughtersITR; ++tempDaughtersITR; daughters.erase( daughtersITR ); daughtersITR = tempDaughtersITR; deletedNode = true; numDeletedNodes++; break; } } if(deletedNode) break; for(closedITR = closedList->begin(); closedITR != closedList->end(); ++closedITR) { closedPuz = *closedITR; if(closedPuz.equals( daughterPuz )) { tempDaughtersITR = daughtersITR; ++tempDaughtersITR; daughters.erase( daughtersITR ); daughtersITR = tempDaughtersITR; deletedNode = true; numDeletedNodes++; break; } } } daughterSize = daughters.size(); openList->splice( openList->begin(), daughters ); return daughterSize; } puzzle* searchFunctions::aStar(puzzle* start, puzzle* goal) { list openList; list closedList; myStartTime = MPI_Wtime(); puzzle curPuzzle; numNodesExpanded = 0; numNodesGenerated = openList.size(); openList = start->successorFunction(); openList.sort(); while(!openList.empty()){ curPuzzle = *openList.begin(); openList.pop_front(); closedList.push_back(curPuzzle); depth = curPuzzle.getDepth(); if(curPuzzle.equals(*goal)) { goalFound = true; myEndTime = MPI_Wtime(); // Get End time cout << "Found Goal! at depth: " << depth << " with path: " << curPuzzle.getPath() << endl; return new puzzle( &curPuzzle); } numNodesExpanded++; numNodesGenerated += checkOpenClosed( &curPuzzle, &openList, &closedList ); openList.sort(); } return NULL; } puzzle* searchFunctions::parallelAStar(puzzle* start, puzzle* goal){ //initialize nodes puzzle myNode; puzzle *myGoal; myGoal = new puzzle(); int myFound = 0; // if this proc finds the goal this get sets to 1 int found = 0; // when another proc finds the goal this gets set to the rank of the last proc to find the goal int myFlag = 0; // this gets checked with MPI_Test MPI_Status myStatus; //status used by MPI_Test MPI_Request request; //request used by MPI_Irecv MPI_Request requestS; //request used by MPI_Isend //Set up a receive from any processor that has found the goal MPI_Irecv(&found, 1, MPI_INT, MPI_ANY_SOURCE, 420, MPI_COMM_WORLD, &request); // Generate nodes to send to each proc if(rank == 0) { puzzle tempsend; list openList; openList = start->successorFunction(); // for each processor, make sure it has a node to start with while(openList.size() < size){ tempsend = *openList.begin(); openList.pop_front(); list daughters = tempsend.successorFunction(); openList.splice( openList.end(), daughters ); } //Distribute nodes to each proc cout << "Distributing " << openList.size() << " Start Nodes to Processors\n"; for(int i=1; i openList; list closedList; numNodesExpanded = 0; numNodesGenerated = 0; int counter = 0; int syncRate = 10; openList = myNode.successorFunction(); openList.sort(); while(!openList.empty()){ counter++; myNode = *openList.begin(); openList.pop_front(); closedList.push_back(myNode); depth = myNode.getDepth(); //cout << rank << ": looking at node with path: " << myNode.getPath() << endl; if(myNode.equals(*goal)) { goalFound = true; myFound = 1; //set my found to 1 //Tell other processors your rank and that you found the goal for(int i=0; i openList; openList = start->successorFunction(); // for each processor, make sure it has a node to start with while(openList.size() < size){ tempsend = *openList.begin(); openList.pop_front(); list daughters = tempsend.successorFunction(); openList.splice( openList.end(), daughters ); } //Distribute nodes to each proc cout << "Distributing " << openList.size() << " Start Nodes to Processors\n"; for(int i=1; i openList; list closedList; numNodesExpanded = 0; numNodesGenerated = 0; int counter = 0; int syncRate = 10; openList = myNode.successorFunction(); openList.sort(); while(!openList.empty()) { counter++; myNode = *openList.begin(); openList.pop_front(); closedList.push_back(myNode); // myNode=IDA_STAR(&myNode,goal); //cout << rank << ": looking at node with path: " << myNode.getPath() << endl; if(myNode.equals(*goal)) { goalFound = true; myFound = 1; //set my found to 1 //Tell other processors your rank and that you found the goal for(int i=0; igetDepth() << " with path: " << foundPuzzle->getPath() << endl; myEndTime = MPI_Wtime(); // Get End time return foundPuzzle; } int searchFunctions::parallelBFS(puzzle* start, puzzle* goal) { //pseudo: //- on each processor return 0; } puzzle* searchFunctions::parallelIDDFS(puzzle* start, puzzle* goal, int depthBound, int increment) { //initialize nodes puzzle myNode; puzzle *myGoal; myGoal = new puzzle(); // Generate nodes to send to each proc if(rank == 0) { puzzle tempsend; list openList; openList = start->successorFunction(); // for each processor, make sure it has a node to start with while(openList.size() < size){ tempsend = *openList.begin(); openList.pop_front(); list daughters = tempsend.successorFunction(); openList.splice( openList.end(), daughters ); } //Distribute nodes to each proc cout << "Distributing " << openList.size() << " Start Nodes to Processors\n"; for(int i=1; igetDepth() << " with path: " << myGoal->getPath() << endl; myEndTime = MPI_Wtime(); } //Check if anyone else has found the goal MPI_Test(&request, &myFlag, &myStatus); //If someone else has found the goal if(myFlag == 1 && myGoal == NULL) { //Print out who found it and where you are in the tree cout << rank << ": Stopping. Goal found by: " << found << " while I was searching at depth bound " << myDepth << endl; myEndTime = MPI_Wtime(); return NULL; } // If no one has found the goal increment depth and loop if(myGoal == NULL && myFlag != 1){ myDepth += increment; cout << rank << ": Incrementing Depth Bound to " << myDepth << endl; } else return NULL; } while (myGoal == NULL && myFlag != 1); //everyone ends at the same time MPI_Barrier(MPI_COMM_WORLD); myEndTime = MPI_Wtime(); return myGoal; } void parse_command_line(int argc, char *argv[]); void exit_with_help(); int depthBound=100, searchType=0; int main(int argc, char *argv[]) { MPI::Init(argc, argv); int rank = MPI::COMM_WORLD.Get_rank(); int size = MPI::COMM_WORLD.Get_size(); parse_command_line(argc, argv); //////////////////////////////////////////////////////////////////////////////// puzzle *start, *goal, *found; start = new puzzle(); goal = new puzzle(); found = new puzzle(); goal->randomPath(30); goal->print(); //////////////////////////////////////////////////////////////////////////////// searchFunctions puzSearch; start = new puzzle(); goal = new puzzle(); found = new puzzle(); if(rank == 0) { //cout << "Generating start node with random depth: " << depthBound << endl; //start->randomPath(depthBound); cout << "Generating start node depth: " << depthBound << endl; start->generateStart(depthBound); start->print(); start->resetDepth(); double myStartTime = MPI_Wtime(); // rank 0 sends goal to others if(size > 1){ for(int i=1; isendNode(i, i*10); } } else if(size > 1) goal->receiveNode(0, rank*10); // others receive goal node //aStar(puzzle* start, puzzle* goal) if(searchType == 0) { if(size <= 1) found = puzSearch.IDA_STAR(start, goal); else found = puzSearch.parallelIDAStar(start,goal); if(rank == 0) found->print(); puzSearch.printStats(); } else if(searchType == 1) { if(size <= 1) found = puzSearch.aStar(start, goal); else found = puzSearch.parallelAStar(start, goal); if(rank == 0) found->print(); puzSearch.printStats(); } else if(searchType == 2) { puzSearch.aStar(start,goal); if(size <= 1) found = puzSearch.DFS(start,goal,5); else found = puzSearch.parallelDFS(start, goal,5); if(rank == 0) found->print(); puzSearch.printStats(); } else if(searchType == 3) { puzSearch.aStar(start,goal); if(size <= 1) found = puzSearch.IDDFS( start, goal,depthBound,2); else found = puzSearch.parallelIDDFS(start,goal, depthBound,2); if(rank == 0) found->print(); puzSearch.printStats(); } double myEndTime = MPI_Wtime(); //cout << rank << ": Elapsed Time: " << (myEndTime - myStartTime) << endl; MPI::Finalize(); return 0; } void parse_command_line(int argc, char *argv[]) { int i; // default values searchType = 0; depthBound = 5; // parse options for(i=1;i