/** * Returns the value for Perlin noise at a 3D location. */ VuoReal VuoGradientNoise_perlin_VuoPoint3d_VuoReal(VuoPoint3d point) { VuoReal x = point.x; VuoReal y = point.y; VuoReal z = point.z; VuoInteger X, Y, Z; VuoReal u, v, w; VuoInteger A, AA, AB, B, BA, BB; X = (int)floor(x) & 255; // Integer part of x Y = (int)floor(y) & 255; // Integer part of y Z = (int)floor(z) & 255; // Integer part of z x = x - floor(x); // Fractional part of x y = y - floor(y); // Fractional part of y z = z - floor(z); // Fractional part of z u = fade(x); v = fade(y); w = fade(z); A = perm[X ] + Y; AA = perm[A ] + Z; AB = perm[A+1] + Z; B = perm[X+1] + Y; BA = perm[B ] + Z; BB = perm[B+1] + Z; return lerp(w, lerp(v, lerp(u, grad3d(perm[AA ], x , y , z), grad3d(perm[BA ], x-1, y , z)), lerp(u, grad3d(perm[AB ], x , y-1, z), grad3d(perm[BB ], x-1, y-1, z))), lerp(v, lerp(u, grad3d(perm[AA+1], x , y , z-1), grad3d(perm[BA+1], x-1, y , z-1)), lerp(u, grad3d(perm[AB+1], x , y-1, z-1), grad3d(perm[BB+1], x-1, y-1, z-1)))); }
/** * Returns the value for Simplex noise at a 3D location. */ VuoReal VuoGradientNoise_simplex_VuoPoint3d_VuoReal(VuoPoint3d point) { VuoReal x = point.x; VuoReal y = point.y; VuoReal z = point.z; // Simple skewing factors for the 3D case VuoReal F3 = 0.333333333; VuoReal G3 = 0.166666667; VuoReal n0, n1, n2, n3; // Noise contributions from the four corners // Skew the input space to determine which simplex cell we're in VuoReal s = (x + y + z) * F3; // Very nice and simple skew factor for 3D VuoReal xs = x + s; VuoReal ys = y + s; VuoReal zs = z + s; VuoInteger i = (int)floor(xs); VuoInteger j = (int)floor(ys); VuoInteger k = (int)floor(zs); VuoReal t = (VuoReal)(i + j + k) * G3; VuoReal X0 = i - t; // Unskew the cell origin back to (x,y,z) space VuoReal Y0 = j - t; VuoReal Z0 = k - t; VuoReal x0 = x - X0; // The x,y,z distances from the cell origin VuoReal y0 = y - Y0; VuoReal z0 = z - Z0; // For the 3D case, the simplex shape is a slightly irregular tetrahedron. // Determine which simplex we are in. VuoInteger i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords VuoInteger i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords if (x0 >= y0) { if (y0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order } else { // x0 < y0 if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } // Z Y X order else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } // Y Z X order else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // Y X Z order } // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where // c = 1/6. VuoReal x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords VuoReal y1 = y0 - j1 + G3; VuoReal z1 = z0 - k1 + G3; VuoReal x2 = x0 - i2 + 2.0f * G3; // Offsets for third corner in (x,y,z) coords VuoReal y2 = y0 - j2 + 2.0f * G3; VuoReal z2 = z0 - k2 + 2.0f * G3; VuoReal x3 = x0 - 1.0f + 3.0f * G3; // Offsets for last corner in (x,y,z) coords VuoReal y3 = y0 - 1.0f + 3.0f * G3; VuoReal z3 = z0 - 1.0f + 3.0f * G3; // Wrap the VuoIntegereger indices at 256, to avoid indexing perm[] out of bounds VuoInteger ii = i & 0xff; VuoInteger jj = j & 0xff; VuoInteger kk = k & 0xff; // Calculate the contribution from the four corners VuoReal t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0; if (t0 < 0.0f) n0 = 0.0f; else { t0 *= t0; n0 = t0 * t0 * grad3d(perm[ii+perm[jj+perm[kk]]], x0, y0, z0); } VuoReal t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1; if (t1 < 0.0f) n1 = 0.0f; else { t1 *= t1; n1 = t1 * t1 * grad3d(perm[ii+i1+perm[jj+j1+perm[kk+k1]]], x1, y1, z1); } VuoReal t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2; if (t2 < 0.0f) n2 = 0.0f; else { t2 *= t2; n2 = t2 * t2 * grad3d(perm[ii+i2+perm[jj+j2+perm[kk+k2]]], x2, y2, z2); } VuoReal t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3; if (t3 < 0.0f) n3 = 0.0f; else { t3 *= t3; n3 = t3 * t3 * grad3d(perm[ii+1+perm[jj+1+perm[kk+1]]], x3, y3, z3); } // Add contributions from each corner to get the final noise value. // The result is scaled to stay just inside [-1,1] return 32.0f * (n0 + n1 + n2 + n3); // TODO: The scale factor is preliminary! }
void opt3d ( struct vtx_data **graph, /* data structure containing vertex weights */ double **yvecs, /* eigenvectors */ int nvtxs, /* total number of vertices */ int nmyvtxs, /* number of vertices I own */ double *vwsqrt, /* square root of vertex weights */ double *ptheta, double *pphi, double *pgamma, /* return optimal angles */ int using_vwgts /* are vertex weights being used? */ ) /* Compute rotation angle to minimize distance to discrete points. */ { extern int DEBUG_OPTIMIZE; /* debug flag for optimization */ extern int OPT3D_NTRIES; /* number of local opts to find global min */ double *aptr, *bptr, *cptr; /* loop through yvecs */ double *wsptr; /* loops through vwsqrt */ double coeffs[25]; /* various products of yvecs */ double vars[3]; /* angular variables */ double best[3]; /* best minimizer found so far */ double grad[3]; /* gradiant of the function */ double gradc[3]; /* gradiant of the constraint */ double hess[3][3]; /* hessian of the function */ double hessc[3][3]; /* hessian of the constraint */ double step[3]; /* Newton step in optimization */ double grad_norm; /* norm of the gradient */ double grad_min; /* acceptable gradient for convergence */ double a, b, c; /* temporary values */ double funcf=0.0, funcc; /* values of function to be minimized */ double step_size; /* norm of step */ double step_max; /* maximum allowed step */ double step_min; /* minimum step => convergence */ double early_step_min; /* min step for early convergence stages */ double final_step_min; /* min step for final convergence */ double hess_min; /* value for hessian if < 0 */ double hess_tol; /* smallest possible positive hess_min */ double hfact; /* scales minimum tolerated hessian */ double w, ws=0; /* vertex weight squared or to the 1.5 */ double mult; /* multiplier for constraint violation */ double max_constraint; /* maximum allowed value for constraint */ double eval; /* smallest eigenvalue of Hessian */ double pdtol; /* eval < tol considered to be 0 */ double mfactor; /* scaling for constraint growth */ double mstart; /* starting value for constraint scaling */ double bestf; /* value of best minimizer so far */ double res; /* returned eigen-residual */ int pdflag; /* converging to non-minimum? */ int inner; /* number of iterations at each stage */ int inner1; int total; /* total number of iterations */ int ntries, maxtries; /* number of local minimizations */ int i, j; /* loop counter */ int kk; double func3d(), constraint(); double drandom(); void grad3d(), hess3d(), gradcon(), hesscon(), kramer3(), ch_eigenvec3(); void ch_evals3(); /* Set parameters. */ best[0]=best[1]=best[2]=0.0; a = sqrt((double) nvtxs); step_max = PI / 4; early_step_min = 2.0e-4; final_step_min = early_step_min / 10; grad_min = 1.0e-7; hfact = 2; hess_tol = 1.0e-6; pdtol = 1.0e-7; max_constraint = 1.0e-12 * a; mfactor = 20.0; mstart = 5.0 * a; for (i = 0; i < 25; i++) coeffs[i] = 0; aptr = yvecs[1] + 1; bptr = yvecs[2] + 1; cptr = yvecs[3] + 1; wsptr = vwsqrt + 1; for (i = 1; i <= nmyvtxs; i++) { a = *aptr++; b = *bptr++; c = *cptr++; w = graph[i]->vwgt; if (using_vwgts) ws = *wsptr++; if (w == 1) { coeffs[0] += a * a * a * a; coeffs[1] += b * b * b * b; coeffs[2] += c * c * c * c; coeffs[3] += a * a * a * b; coeffs[4] += a * a * b * b; coeffs[5] += a * b * b * b; coeffs[6] += a * a * a * c; coeffs[7] += a * a * c * c; coeffs[8] += a * c * c * c; coeffs[9] += b * b * b * c; coeffs[10] += b * b * c * c; coeffs[11] += b * c * c * c; coeffs[12] += a * a * b * c; coeffs[13] += a * b * b * c; coeffs[14] += a * b * c * c; coeffs[15] += a * a * a; coeffs[16] += b * b * b; coeffs[17] += c * c * c; coeffs[18] += a * a * b; coeffs[19] += a * a * c; coeffs[20] += a * b * b; coeffs[21] += b * b * c; coeffs[22] += a * c * c; coeffs[23] += b * c * c; coeffs[24] += a * b * c; } else { w = 1 / (w * w); ws = 1 / ws; coeffs[0] += a * a * a * a * w; coeffs[1] += b * b * b * b * w; coeffs[2] += c * c * c * c * w; coeffs[3] += a * a * a * b * w; coeffs[4] += a * a * b * b * w; coeffs[5] += a * b * b * b * w; coeffs[6] += a * a * a * c * w; coeffs[7] += a * a * c * c * w; coeffs[8] += a * c * c * c * w; coeffs[9] += b * b * b * c * w; coeffs[10] += b * b * c * c * w; coeffs[11] += b * c * c * c * w; coeffs[12] += a * a * b * c * w; coeffs[13] += a * b * b * c * w; coeffs[14] += a * b * c * c * w; coeffs[15] += a * a * a * ws; coeffs[16] += b * b * b * ws; coeffs[17] += c * c * c * ws; coeffs[18] += a * a * b * ws; coeffs[19] += a * a * c * ws; coeffs[20] += a * b * b * ws; coeffs[21] += b * b * c * ws; coeffs[22] += a * c * c * ws; coeffs[23] += b * c * c * ws; coeffs[24] += a * b * c * ws; } } /* Adjust for normalization of eigenvectors. */ /* This should make convergence criteria insensitive to problem size. */ /* Note that the relative sizes of funcf and funcc depend on normalization of eigenvectors, and I'm assuming them normalized to 1. */ for (i = 0; i < 15; i++) coeffs[i] *= nvtxs; a = sqrt((double) nvtxs); for (i = 15; i < 25; i++) coeffs[i] *= a; bestf = 0; maxtries = OPT3D_NTRIES; for (ntries = 1; ntries <= maxtries; ntries++) { /* Initialize the starting guess randomly. */ vars[0] = TWOPI * (drandom() - .5); vars[1] = acos(2.0 * drandom() - 1.0) - HALFPI; vars[2] = TWOPI * (drandom() - .5); inner1 = 0; total = 0; mult = mstart; step_min = early_step_min; funcc = max_constraint; while (funcc >= max_constraint && total < 70) { inner = 0; step_size = step_min; pdflag = FALSE; grad_norm = 0; while (step_size >= step_min && (!pdflag || grad_norm > grad_min) && inner < 15) { funcf = func3d(coeffs, vars[0], vars[1], vars[2]); grad3d(coeffs, grad, vars[0], vars[1], vars[2]); hess3d(coeffs, hess); /* Compute contribution of constraint term. */ funcc = constraint(&coeffs[15]); /* func = funcf + mult*funcc; */ gradcon(&coeffs[15], gradc); hesscon(&coeffs[15], hessc); /* If in final pass, tighten convergence criterion. */ if (funcc < max_constraint) step_min = final_step_min; kk = 0; if (kk) { ch_evals3(hessc, &eval, &res, &res); } for (i = 0; i < 3; i++) { /* Note: I'm taking negative of gradient here. */ grad[i] = -grad[i] - mult * gradc[i]; for (j = 0; j < 3; j++) hess[i][j] += mult * hessc[i][j]; } grad_norm = fabs(grad[0]) + fabs(grad[1]) + fabs(grad[2]); hess_min = hfact * grad_norm / step_max; if (hess_min < hess_tol) hess_min = hess_tol; /* Find smallest eigenvalue of hess. */ ch_evals3(hess, &eval, &res, &res); /* If eval < 0, add to diagonal to make pos def. */ if (eval < -pdtol) pdflag = FALSE; else pdflag = TRUE; if (eval < hess_min) { for (i = 0; i < 3; i++) hess[i][i] += hess_min - eval; } /* Now solve linear system for step sizes. */ kramer3(hess, grad, step); /* Scale step down if too big. */ step_size = fabs(step[0]) + fabs(step[1]) + fabs(step[2]); if (step_size > step_max) { a = step_max / step_size; for (i = 0; i < 3; i++) step[i] *= a; } if ((step_size < step_min || grad_norm < grad_min) && !pdflag) { /* Convergence to non-min. */ for (i = 0; i < 3; i++) hess[i][i] -= hess_min - eval; ch_eigenvec3(hess, eval, step, &res); step_size = fabs(step[0]) + fabs(step[1]) + fabs(step[2]); a = step_min / step_size; for (i = 0; i < 3; i++) step[i] *= a; step_size = step_min; } for (i = 0; i < 3; i++) vars[i] += step[i]; inner++; } if (inner1 == 0) inner1 = inner; total += inner; mult *= mfactor; } if (DEBUG_OPTIMIZE > 0) { printf("On try %d, After %d (%d) passes, funcf=%e, funcc=%e (%f, %f, %f)\n", ntries, total, inner1, funcf, funcc, vars[0], vars[1], vars[2]); } if (ntries == 1 || funcf < bestf) { bestf = funcf; for (i = 0; i < 3; i++) best[i] = vars[i]; } } *ptheta = best[0]; *pphi = best[1]; *pgamma = best[2]; }