std::vector<Points> fastPartition(const Points &polygon) { // Hertel-Mehlhorn partitioning // Triangulate polygon std::vector<int> triangles = triProcess(polygon); // Get a list of unique diagonals // Every edge not part of the outline is a diagonal. // Outline edges are all consecutive. std::vector<Diagonal> diagonals; std::unordered_set<int> dset; const int c = polygon.size(); for(unsigned int i=0;i<triangles.size();i+=3) { addDiagonal(triangles, i, i+1, c, diagonals, dset); addDiagonal(triangles, i+1, i+2, c, diagonals, dset); addDiagonal(triangles, i+2, i, c, diagonals, dset); } // Order diagonal list: v1 ascending, v2 descending std::sort(diagonals.begin(), diagonals.end(), [](const Diagonal &i, const Diagonal &j)->bool { if(i.v1 == j.v1) return i.v2>=j.v2; return i.v1<j.v1; }); // Check which vertices are reflex. std::vector<bool> reflex; reflex.push_back(isReflex(polygon[polygon.size()-1], polygon[0], polygon[1])); for(unsigned int i=1;i<polygon.size()-1;++i) reflex.push_back(isReflex(polygon[i-1], polygon[i], polygon[i+1])); reflex.push_back(isReflex(polygon[polygon.size()-2], polygon[polygon.size()-1], polygon[0])); // Remove inessential diagonals. for(unsigned int i=0;i<diagonals.size();++i) { Diagonal &di = diagonals[i]; // See if removing this diagonal would create a reflex vertex di.removed = !(reflex[di.v1] && isDiagonalEssential1(polygon, diagonals, i)) && !(reflex[di.v2] && isDiagonalEssential2(polygon, diagonals, i)); } // Split into polygons std::vector<Points> result(1); std::vector<bool> visited(polygon.size()); polySplit(polygon, diagonals, 0, 0, visited, result); result.pop_back(); // remove the last empty polygon return result; }
int main (int argc, char** argv) { // aim for a nonzero density given by sparsity: sparsity = 0.2; // nz = sparsity*100% of the size of the matrix /* * we say 'aim' here, since of course initially exactly * nz = sparsity * N^2 * nonzeroes will be generated at random spots, but because * the matrix must be symmetric and diagonally positive, the * actual number of nonzeroes will probably not be exactly * the projected number. */ // read the desired size of the matrix from command line if (argc < 2) { printf("Usage: %s N [mu] [sparsity]\n", argv[0]); exit(-1); } if(sscanf(argv[1], "%d", &N) != 1) { printf("couldn't read command-line argument for N. must be an integer.\n"); exit(-2); } double mu; mu = 2.5; //default scalar for making matrix diagonal-dominant // maybe the user supplied a different mu if(argc > 2 && sscanf(argv[2], "%lf", &mu) != 1) { exit(-2); } // maybe the user supplied a different sparsity if(argc > 3 && sscanf(argv[3], "%lf", &sparsity) != 1) { exit(-2); } int nz = sparsity*N*N; int* xs; int* ys; double* vals; fprintf(stderr,"Generating matrix. N=%d, density=%lf, target nz=%d, ", N, sparsity, nz); fprintf(stderr, "mu = %lf\n", mu); // seed the random generator. srandom((unsigned)time(NULL)); xs = vecalloci(nz); ys = vecalloci(nz); vals = vecallocd(nz); bool* diag_done; diag_done = malloc(N*sizeof(bool)); int i; for(i = 0; i<N; i++) { diag_done[i] = false; } int nz_generated; int x,y; nz_generated = 0; double fake_transpose; x=0;y=0; while(x<N && y<N) { //don't escape matrix bounds. if (nz_generated % 1000000 == 0) { fprintf(stderr,"progress: %f%%\r", (double)nz_generated/(double)(nz/2.0)*100.0); } if(x==y) { //diagonal, so always generate. xs[nz_generated]=x; ys[nz_generated]=y; vals[nz_generated]=ran()*2.0-1.0; diag_done[x] = true; #ifdef DEBUG fprintf(stderr,"generated A[//][%d]=%lf\n" , ys[nz_generated] , vals[nz_generated]); #endif nz_generated++; } else { // not a diagonal. only add if in // lower triangular half if(x<y) { if(nz_generated > nz) { // this should NEVER happen, although all that's // stopping it from happening is our ran() being // well-behaved........... printf("EEK! something went wrong!!\n"); exit(666); } xs[nz_generated]= x; ys[nz_generated]= y; // simulate the distribution of values which // would occur if we do A+A^T afterwards. if (ran() < sparsity) { fake_transpose = ran()*2.0-1.0; vals[nz_generated]= ran()*2.0-1.0 + fake_transpose; } else { vals[nz_generated]= ran()*2.0-1.0; } #ifdef DEBUG fprintf(stderr,"generated A[%d][%d]=%lf\n", xs[nz_generated] , ys[nz_generated] , vals[nz_generated]); #endif nz_generated++; } } x += 1/sparsity * (ran() + 0.5); if( x >= N ) { y += x/N; x = x%N; } } fprintf(stderr, "generated initial randoms\n"); int diagonals_present = 0; for(i=0; i<nz_generated; i++) { if(xs[i]==ys[i]) diagonals_present++; } fprintf(stderr,"generated %d nzeros, array was %d big.\n", nz_generated, nz); #ifdef DEBUG fprintf(stderr, "found %d diagonal(s), still need %d more.\n", diagonals_present, (N-diagonals_present)); #endif // add the missing diagonals, and add mu to each diagonal. int newsize = nz_generated + (N - diagonals_present); fprintf(stderr,"reallocating values array to %lluM \n", (unsigned long long)(SZDBL+2*SZINT)*newsize/1048576); int* diag_i; int* diag_j; double* diag_val; diag_i = realloc(xs ,SZINT*newsize); diag_j = realloc(ys ,SZINT*newsize); diag_val = realloc(vals,SZDBL*newsize); if(diag_i == NULL || diag_j == NULL || diag_val == NULL) { printf("out of memory!"); exit(44); } addDiagonal(mu, diag_i, diag_j, diag_val, nz_generated, newsize, diag_done); nz_generated=newsize; #ifdef DEBUG for(i=0;i<newsize;i++) { fprintf(stderr,"after addDiagonal A[%d][%d]=%lf\n", diag_i[i],diag_j[i], diag_val[i]); } fprintf(stderr, "Going to make symmetric now... (nz_generated = %d)\n", nz_generated); #endif // now we explicitly fill the array with the // upper triangle values // things must be symmetric, but they aren't, yet // ... here's a good place to do the transposing thing. newsize = nz_generated * 2 - N; //number of real nonzeros, don't // count diagonals twice. int *new_i; int *new_j; double *new_v; new_i = realloc(diag_i ,SZINT*newsize); new_j = realloc(diag_j ,SZINT*newsize); new_v = realloc(diag_val,SZDBL*newsize); if(new_i == NULL || new_i == NULL || new_v == NULL) { printf("out of memory (2)!"); exit(44); } diag_i = new_i; diag_j = new_j; diag_val = new_v; addTranspose(newsize,diag_i,diag_j,diag_val, nz_generated); #ifdef DEBUG for(i=0;i<newsize;i++) // to make diags stand out. if(diag_i[i]==diag_j[i]) fprintf(stderr,"after transpose A[%d][%d]=%lf \\\\\n", diag_i[i],diag_j[i], diag_val[i]); else fprintf(stderr,"after transpose A[%d][%d]=%lf\n", diag_i[i],diag_j[i], diag_val[i]); #endif checkStrictDiagonallyDominant(diag_i,diag_j,diag_val, newsize); // now quickly generate a test-vector to solve against: double *vec = vecallocd(N); for(i=0;i<N;i++) vec[i]=ran(); fprintf(stderr,"Left with %d nonzeroes; nonzero density = %lf (desired=%lf)\n", newsize, newsize/((double)N*N), sparsity); fprintf(stderr,"========== OUTPUTTING ... ==========\n"); outputMondriaanMatrix(newsize, diag_i, diag_j, diag_val, vec); outputMathematicaMatrix(newsize, diag_i, diag_j, diag_val, vec); free(diag_done); free(vec); free(diag_i); free(diag_j); free(diag_val); return 0; }