#include #include #include #include #include // #include #define maxThreads 30 // #define expectedVertices 12 #define maxWidth 400 #define maxHeight 300 #define currentMaxDegree 5 #define sizeOfGraph 73 #define maxFaceSize 10 #define maxNumberOfFaces 20 #define allInformation tableau,vertices,anglesUpTo,vertexDegrees,faceArray,numberOfFaces,heightOfTableau,widthOfTableau,¤tRow,¤tSlackVariable #define addInequalityToAnglesInfo tableau,currentRow,currentSlackVariable,heightOfTableau,widthOfTableau,inequalityValue #define ALL_VERTEX 100 #define ALL_FACE 101 #define ADJACENT_FACE 102 #define OPPOSITE_FACE 103 #define INDIVIDUAL_ANGLE 300 #define SUM_ANGLE 301 #define SUBTRACT_ANGLE 302 #define GEQ 400 #define LEQ 401 #define separatorASCIICode 32 int expectedVertices=0; int totalCorrectGraphs=0; int totalProcessedGraphs = 0; int outputAsASCII = 0; int feasableSimplex(float tableau[maxHeight][maxWidth],int heightOfTableau,int widthOfTableau) { /* Input arguments: heightOfTableau is the height of the tableau not including the objective row widthOfTableau is the number of variables in the tableau Runs the simplex algorithm on a tableau and returns false if the objective function is not sufficiently small at the end of execution*/ int pivotColumn,pivotRow; //provides the location of the pivot int continueSimplex = 1; int k=0; float currentMaximum; //used to calculate the maximum from an array float currentMinimum; //used to calculate the minimum from an array float valueAtPivotColumn; //used to calculate the pivot row float pivotValue; int i,j; //inner and outerloop variables float objectiveValue; float subtractionFactor = 0; //used when subtracting one row from another float subtractionAmount = 0; while(1) { //Step 1 - Determine which column to pivot on (or whether we are optimal) currentMaximum = 0; pivotColumn = -1; for(i = 0; i < widthOfTableau; i++) { if(tableau[heightOfTableau][i] > currentMaximum) { currentMaximum = tableau[heightOfTableau][i]; pivotColumn = i; } } if(pivotColumn == -1) { break; }//we cannot optimize any further /*Step 2 - Determine which row to pivot on (or whether the problem is unbounded)*/ currentMinimum = FLT_MAX; pivotRow = -1; //test each row for minimum ratio for(i = 0; i < heightOfTableau; i++) { valueAtPivotColumn = tableau[i][pivotColumn]; /*valueAtPivotColumn stores the value of the tableau on row i, column pivotColumn*/ if(valueAtPivotColumn>0 && (((tableau[i][widthOfTableau])/valueAtPivotColumn)-0.001 && objectiveValue<0.001) { return 1; } return 0; //check whether or not we should allow the graph } void splitGraphToVertices(int graph[sizeOfGraph],int lengthOfGraph,int vertexDegrees[expectedVertices],int vertices[expectedVertices][currentMaxDegree]) { int currentEdge = 0; //used to temporarily store the current edge or a 0 if the end of the vertex is specified int currentVertexPosition = 0; //the current degree of the vertex int currentGraphEntry=0; //the current entry in the graph int vertexNumber = 0; //how many vertices have we currently processed int edgeProcessed = 0; //how many edges have we processed for the current vertex for(currentGraphEntry = 1;currentGraphEntry < lengthOfGraph; currentGraphEntry++) { currentEdge = graph[currentGraphEntry]; if(currentEdge != 0) { vertices[vertexNumber][currentVertexPosition] = currentEdge - 1; //plantri outputs vertices starting from vertex 1, but we would prefer to label them from 0 currentVertexPosition++; } else { //we have finished processing this vertex vertexDegrees[vertexNumber] = currentVertexPosition; currentVertexPosition = 0; vertexNumber++; } } if(vertexNumber != expectedVertices) { fprintf(stderr,"A graph was passed to splitGraphToVertices with the incorrect number of vertices. %i vertices were passed and %i vertices were expected\n",vertexNumber,expectedVertices); } } int findNextVertex(int vertices[expectedVertices][currentMaxDegree],int previousVertex,int nextVertex,int currentVertexDegree) { /* We consider the list of vertices connected to the vertex we are currently at. Once we have found the edge that we just took to reach this vertex (by finding the previous vertex in the aforementioned list) we take the next edge in the list to get the next vertex (clockwise) */ int i = 0; int returnValue = -1; for(i = 0; i < (currentVertexDegree - 1); i++) { if((vertices[nextVertex][i]) == previousVertex) { //We have found the edge that we just took returnValue = vertices[nextVertex][i+1]; //this is the next edge clockwise break; } } if(i == (currentVertexDegree - 1)) { /*the final edge of the current vertex connects to the previous vertex: thus the next edge to traverse clockwise is the first edge listed*/ returnValue = vertices[nextVertex][0]; } return returnValue; } void getAnglesUpTo(int vertexDegrees[expectedVertices],int anglesUpTo[expectedVertices]) { int i; anglesUpTo[0]=0; for(i=1;i 2) { // we need to add this face to the list of faces for(i = 0; i < faceSides; i++) { faceArray[(faceSides - 1)][numberOfFaces[(faceSides - 1)]][i] = currentFace[i]; } numberOfFaces[(faceSides - 1)]++; } } } } } int makeTableau(int graph[sizeOfGraph],int lengthOfGraph) { //takes a graph and produces a tableau ready for the simplex algorithm. int vertexDegrees[expectedVertices]; int anglesUpTo[expectedVertices]; float tableau[maxHeight][maxWidth]; int vertices[expectedVertices][currentMaxDegree]; int faceArray[maxFaceSize][maxNumberOfFaces][maxFaceSize]; int numberOfFaces[maxFaceSize]; int heightOfTableau; int widthOfTableau; int currentRow = 0; int currentSlackVariable = 0; int totalInequalities,totalSlackVariables,totalAngles; int i; //used to iterate through the tableau splitGraphToVertices(graph,lengthOfGraph,vertexDegrees,vertices); retrieveFaces(vertexDegrees,vertices,faceArray,numberOfFaces); getAnglesUpTo(vertexDegrees,anglesUpTo); totalAngles = anglesUpTo[(expectedVertices - 1)] + vertexDegrees[(expectedVertices - 1)]; //the number of angles /*MODIFY THIS TO SUIT YOUR OWN SIMPLEX PROBLEM */ totalInequalities = totalAngles; //each angle induces an inequality totalInequalities += (2 * expectedVertices); //there are 2 inequalities for each vertex: the sum of all angles around a point <= 2pi, >=2pi totalInequalities += 3 * (numberOfFaces[2]); //there are 3 inequalities for each triangle : each angle in a triangle is less than or equal to arccos(1/3) totalInequalities += 4 * (numberOfFaces[3]); //four inequalities for each quadrilateral : each angle in a quadrilateral is less than or equal to 2arccos(1/3) totalInequalities += 4 * (numberOfFaces[3]); //an additional 4 inequalities for each quadrilateral: there are exactly 2 pairs of opposite angles in a quadrilateral and 2 inequalities for each pair totalInequalities += 8 * (numberOfFaces[3]); //there are 4 adjacent pairs of angles in a quadrilateral and each pair has exactly two inequalities totalInequalities += 5 * (numberOfFaces[4]); //there is one inequality for each angle in a pentagon: there are 5 angles in a pentagon totalSlackVariables = totalInequalities; //each inequality will introduce a slack variable //DO NOT EDIT THE NEXT FEW LINES widthOfTableau = totalAngles + totalSlackVariables; heightOfTableau = totalInequalities; currentSlackVariable = totalAngles;//start from the final angle for(i=0;i<(widthOfTableau + 1);i++) { tableau[heightOfTableau][i] = 0; } /*MODIFY THIS TO SUIT YOUR OWN SIMPLEX PROBLEM */ addInequality(allInformation,ALL_VERTEX,INDIVIDUAL_ANGLE,0,1.2309f,GEQ); addInequality(allInformation,ALL_VERTEX,SUM_ANGLE,0,6.2832f,LEQ); addInequality(allInformation,ALL_VERTEX,SUM_ANGLE,0,6.2831f,GEQ); addInequality(allInformation,ALL_FACE,INDIVIDUAL_ANGLE,3,1.231f,LEQ); addInequality(allInformation,ALL_FACE,INDIVIDUAL_ANGLE,4,2.462f,LEQ); addInequality(allInformation,OPPOSITE_FACE,SUBTRACT_ANGLE,4,0,LEQ); addInequality(allInformation,ADJACENT_FACE,SUM_ANGLE,4,3.8213f,LEQ); addInequality(allInformation,ADJACENT_FACE,SUM_ANGLE,4,3.6928f,GEQ); addInequality(allInformation,ALL_FACE,INDIVIDUAL_ANGLE,5, 3.6929f,LEQ); if(feasableSimplex(tableau,heightOfTableau,widthOfTableau)) return 1; return 0; } void convertGraphToASCII(int graph[sizeOfGraph],int lengthOfGraph) { int i; //used to iterate through the graph for(i=1;iomp_get_num_threads()) { threadsToUse = omp_get_num_threads(); //if the user has asked for too many threads then the number of threads will be reset to the optimal number } fprintf(stderr,"%i threads will be used to execute this program \n",threadsToUse); } } #pragma omp barrier #pragma omp parallel private(graph,lengthOfGraph,a) shared(exitLoop) num_threads(threadsToUse) //each thread has it's own graph, length of graph and input character(a). The flag to exit the loop is shared between all threads { a = 0; while(!exitLoop) { //if exitloop is set then all threads will eventually exit this loop #pragma omp critical(readGraph) //reading a graph needs to be done in serial, not parallel. { //a thread may enter this section of code even though there are no graphs left to process. Consequently we need to check whether or not another thread has set exitloop lengthOfGraph = 0; if(!exitLoop) //we have not necessarily reached the end of file { a = getchar(); //read the first character if(expectedVertices==0) {expectedVertices = a;} if(a!=expectedVertices) { if(a!=EOF) { fprintf(stderr,"A graph started with %i vertices when %i vertices were expected\n",a,expectedVertices); } else { exitLoop = 1; //now we have reached the end of the file. Signal to all other threads to stop processing new graphs } } else { //read in the graph: there are some vertices left graph[0] = a; for(vertexCount=0;vertexCount