void Rasterizer::scanInterpolate(CameraDefinition *camera, ScanPoint *v1, ScanPoint *diff, double value, ScanPoint *result) { result->pixel.x = v1->pixel.x + diff->pixel.x * value; result->pixel.y = v1->pixel.y + diff->pixel.y * value; result->pixel.z = v1->pixel.z + diff->pixel.z * value; if (perspective_correction) { Vector3 vec1(v1->pixel.x, v1->pixel.y, v1->pixel.z); Vector3 vecdiff(diff->pixel.x, diff->pixel.y, diff->pixel.z); double v1depth = 1.0 / camera->getRealDepth(vec1); double v2depth = 1.0 / camera->getRealDepth(vec1.add(vecdiff)); double factor = 1.0 / ((1.0 - value) * v1depth + value * v2depth); result->location.x = ((1.0 - value) * (v1->location.x * v1depth) + value * (v1->location.x + diff->location.x) * v2depth) * factor; result->location.y = ((1.0 - value) * (v1->location.y * v1depth) + value * (v1->location.y + diff->location.y) * v2depth) * factor; result->location.z = ((1.0 - value) * (v1->location.z * v1depth) + value * (v1->location.z + diff->location.z) * v2depth) * factor; } else { result->location.x = v1->location.x + diff->location.x * value; result->location.y = v1->location.y + diff->location.y * value; result->location.z = v1->location.z + diff->location.z * value; } result->client = v1->client; result->front_facing = v1->front_facing; }
// calculate a normalized vector pointint from one vector to another void pointat(const GLfloat *from, const GLfloat *to, float *result){ int i=0; float dist; assert(NULL != from); assert(NULL != to); assert(NULL != result); vecdiff(from,to,result); dist = veclen(result); assert(dist > 0); for(;i<3;i++){ result[i] /= dist; } }
int localReconstruct ( lRecon * z, bCntr * bsc, int nC, int D, int * per, double * dom ) { double E = 0.0; int i=0,j; bCntr * ip; double Zi[D]; double zi; double phi, gphi; z->e=0.0; for (j=0;j<D;j++) { z->f[j]=0.0; } for (i=0;i<nC;i++) { ip=&bsc[i]; vecdiff(Zi,z->r,ip->r,D,per,dom); zi=norm(Zi,D); kernel(zi,ip->s,&phi,&gphi); z->e+=ip->a*phi; for (j=0;j<D;j++) { z->f[j]-=(zi>0)?ip->a*Zi[j]/zi*gphi:0.0; } } return 0; }
int lbfgs( int n, T *x, T *ptr_fx, typename FuncWrapper<T>::lbfgs_evaluate_t proc_evaluate, typename FuncWrapper<T>::lbfgs_progress_t proc_progress, void *instance, lbfgs_parameter_t *_param ) { int ret; int i, j, k, ls, end, bound; T step; /* Constant parameters and their default values. */ lbfgs_parameter_t param = (_param != NULL) ? (*_param) : _defparam; const int m = param.m; T *xp = NULL; T *g = NULL, *gp = NULL, *pg = NULL; T *d = NULL, *w = NULL, *pf = NULL; iteration_data_t<T> *lm = NULL; iteration_data_t<T>*it = NULL; T ys, yy; T xnorm, gnorm, beta; T fx = 0.; T rate = 0.; typename LineSearchWrapper<T>::line_search_proc linesearch = line_search_morethuente; /* Construct a callback data. */ callback_data_t<T> cd; cd.n = n; cd.instance = instance; cd.proc_evaluate = proc_evaluate; cd.proc_progress = proc_progress; #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) /* Round out the number of variables. */ n = round_out_variables(n); #endif/*defined(USE_SSE)*/ /* Check the input parameters for errors. */ if (n <= 0) { return LBFGSERR_INVALID_N; } #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) if (n % 8 != 0) { return LBFGSERR_INVALID_N_SSE; } if ((uintptr_t)(const void*)x % 16 != 0) { return LBFGSERR_INVALID_X_SSE; } #endif/*defined(USE_SSE)*/ if (param.epsilon < 0.) { return LBFGSERR_INVALID_EPSILON; } if (param.past < 0) { return LBFGSERR_INVALID_TESTPERIOD; } if (param.delta < 0.) { return LBFGSERR_INVALID_DELTA; } if (param.min_step < 0.) { return LBFGSERR_INVALID_MINSTEP; } if (param.max_step < param.min_step) { return LBFGSERR_INVALID_MAXSTEP; } if (param.ftol < 0.) { return LBFGSERR_INVALID_FTOL; } if (param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE || param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE) { if (param.wolfe <= param.ftol || 1. <= param.wolfe) { return LBFGSERR_INVALID_WOLFE; } } if (param.gtol < 0.) { return LBFGSERR_INVALID_GTOL; } if (param.xtol < 0.) { return LBFGSERR_INVALID_XTOL; } if (param.max_linesearch <= 0) { return LBFGSERR_INVALID_MAXLINESEARCH; } if (param.orthantwise_c < 0.) { return LBFGSERR_INVALID_ORTHANTWISE; } if (param.orthantwise_start < 0 || n < param.orthantwise_start) { return LBFGSERR_INVALID_ORTHANTWISE_START; } if (param.orthantwise_end < 0) { param.orthantwise_end = n; } if (n < param.orthantwise_end) { return LBFGSERR_INVALID_ORTHANTWISE_END; } if (param.orthantwise_c != 0.) { switch (param.linesearch) { case LBFGS_LINESEARCH_BACKTRACKING: linesearch = line_search_backtracking_owlqn; break; default: /* Only the backtracking method is available. */ return LBFGSERR_INVALID_LINESEARCH; } } else { switch (param.linesearch) { case LBFGS_LINESEARCH_MORETHUENTE: linesearch = line_search_morethuente; break; case LBFGS_LINESEARCH_BACKTRACKING_ARMIJO: case LBFGS_LINESEARCH_BACKTRACKING_WOLFE: case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE: linesearch = line_search_backtracking; break; default: return LBFGSERR_INVALID_LINESEARCH; } } /* Allocate working space. */ xp = (T*)vecalloc(n * sizeof(T)); g = (T*)vecalloc(n * sizeof(T)); gp = (T*)vecalloc(n * sizeof(T)); d = (T*)vecalloc(n * sizeof(T)); w = (T*)vecalloc(n * sizeof(T)); if (xp == NULL || g == NULL || gp == NULL || d == NULL || w == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } if (param.orthantwise_c != 0.) { /* Allocate working space for OW-LQN. */ pg = (T*)vecalloc(n * sizeof(T)); if (pg == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } } /* Allocate limited memory storage. */ lm = (iteration_data_t<T>*)vecalloc(m * sizeof(iteration_data_t<T>)); if (lm == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } /* Initialize the limited memory. */ for (i = 0;i < m;++i) { it = &lm[i]; it->alpha = 0; it->ys = 0; it->s = (T*)vecalloc(n * sizeof(T)); it->y = (T*)vecalloc(n * sizeof(T)); if (it->s == NULL || it->y == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } } /* Allocate an array for storing previous values of the objective function. */ if (0 < param.past) { pf = (T*)vecalloc(param.past * sizeof(T)); } /* Evaluate the function value and its gradient. */ fx = cd.proc_evaluate(cd.instance, x, g, cd.n, 0); if (0. != param.orthantwise_c) { /* Compute the L1 norm of the variable and add it to the object value. */ xnorm = owlqn_x1norm(x, param.orthantwise_start, param.orthantwise_end); fx += xnorm * param.orthantwise_c; owlqn_pseudo_gradient( pg, x, g, n, T(param.orthantwise_c), param.orthantwise_start, param.orthantwise_end ); } /* Store the initial value of the objective function. */ if (pf != NULL) { pf[0] = fx; } /* Compute the direction; we assume the initial hessian matrix H_0 as the identity matrix. */ if (param.orthantwise_c == 0.) { vecncpy(d, g, n); } else { vecncpy(d, pg, n); } /* Make sure that the initial variables are not a minimizer. */ vec2norm(&xnorm, x, n); if (param.orthantwise_c == 0.) { vec2norm(&gnorm, g, n); } else { vec2norm(&gnorm, pg, n); } if (xnorm < 1.0) xnorm = 1.0; if (gnorm / xnorm <= param.epsilon) { ret = LBFGS_ALREADY_MINIMIZED; goto lbfgs_exit; } /* Compute the initial step: step = 1.0 / sqrt(vecdot(d, d, n)) */ vec2norminv(&step, d, n); k = 1; end = 0; for (;;) { /* Store the current position and gradient vectors. */ veccpy(xp, x, n); veccpy(gp, g, n); /* Search for an optimal step. */ if (param.orthantwise_c == 0.) { ls = linesearch(n, x, &fx, g, d, &step, xp, gp, w, &cd, ¶m); } else { ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, ¶m); owlqn_pseudo_gradient( pg, x, g, n, T(param.orthantwise_c), param.orthantwise_start, param.orthantwise_end ); } if (ls < 0) { /* Revert to the previous point. */ veccpy(x, xp, n); veccpy(g, gp, n); ret = ls; goto lbfgs_exit; } /* Compute x and g norms. */ vec2norm(&xnorm, x, n); if (param.orthantwise_c == 0.) { vec2norm(&gnorm, g, n); } else { vec2norm(&gnorm, pg, n); } /* Report the progress. */ if (cd.proc_progress) { if ((ret = cd.proc_progress(cd.instance, x, g, fx, xnorm, gnorm, step, cd.n, k, ls))) { goto lbfgs_exit; } } /* Convergence test. The criterion is given by the following formula: |g(x)| / \max(1, |x|) < \epsilon */ if (xnorm < 1.0) xnorm = 1.0; if (gnorm / xnorm <= param.epsilon) { /* Convergence. */ ret = LBFGS_SUCCESS; break; } /* Test for stopping criterion. The criterion is given by the following formula: (f(past_x) - f(x)) / f(x) < \delta */ if (pf != NULL) { /* We don't test the stopping criterion while k < past. */ if (param.past <= k) { /* Compute the relative improvement from the past. */ rate = (pf[k % param.past] - fx) / fx; /* The stopping criterion. */ if (rate < param.delta) { ret = LBFGS_STOP; break; } } /* Store the current value of the objective function. */ pf[k % param.past] = fx; } if (param.max_iterations != 0 && param.max_iterations < k+1) { /* Maximum number of iterations. */ ret = LBFGSERR_MAXIMUMITERATION; break; } /* Update vectors s and y: s_{k+1} = x_{k+1} - x_{k} = \step * d_{k}. y_{k+1} = g_{k+1} - g_{k}. */ it = &lm[end]; vecdiff(it->s, x, xp, n); vecdiff(it->y, g, gp, n); /* Compute scalars ys and yy: ys = y^t \cdot s = 1 / \rho. yy = y^t \cdot y. Notice that yy is used for scaling the hessian matrix H_0 (Cholesky factor). */ vecdot(&ys, it->y, it->s, n); vecdot(&yy, it->y, it->y, n); it->ys = ys; /* Recursive formula to compute dir = -(H \cdot g). This is described in page 779 of: Jorge Nocedal. Updating Quasi-Newton Matrices with Limited Storage. Mathematics of Computation, Vol. 35, No. 151, pp. 773--782, 1980. */ bound = (m <= k) ? m : k; ++k; end = (end + 1) % m; /* Compute the steepest direction. */ if (param.orthantwise_c == 0.) { /* Compute the negative of gradients. */ vecncpy(d, g, n); } else { vecncpy(d, pg, n); } j = end; for (i = 0;i < bound;++i) { j = (j + m - 1) % m; /* if (--j == -1) j = m-1; */ it = &lm[j]; /* \alpha_{j} = \rho_{j} s^{t}_{j} \cdot q_{k+1}. */ vecdot(&it->alpha, it->s, d, n); it->alpha /= it->ys; /* q_{i} = q_{i+1} - \alpha_{i} y_{i}. */ vecadd(d, it->y, -it->alpha, n); } vecscale(d, ys / yy, n); for (i = 0;i < bound;++i) { it = &lm[j]; /* \beta_{j} = \rho_{j} y^t_{j} \cdot \gamma_{i}. */ vecdot(&beta, it->y, d, n); beta /= it->ys; /* \gamma_{i+1} = \gamma_{i} + (\alpha_{j} - \beta_{j}) s_{j}. */ vecadd(d, it->s, it->alpha - beta, n); j = (j + 1) % m; /* if (++j == m) j = 0; */ } /* Constrain the search direction for orthant-wise updates. */ if (param.orthantwise_c != 0.) { for (i = param.orthantwise_start;i < param.orthantwise_end;++i) { if (d[i] * pg[i] >= 0) { d[i] = 0; } } } /* Now the search direction d is ready. We try step = 1 first. */ step = 1.0; } lbfgs_exit: /* Return the final value of the objective function. */ if (ptr_fx != NULL) { *ptr_fx = fx; } vecfree(pf); /* Free memory blocks used by this function. */ if (lm != NULL) { for (i = 0;i < m;++i) { vecfree(lm[i].s); vecfree(lm[i].y); } vecfree(lm); } vecfree(pg); vecfree(w); vecfree(d); vecfree(gp); vecfree(g); vecfree(xp); return ret; }
int lbfgs( int n, lbfgsfloatval_t *x, lbfgsfloatval_t *ptr_fx, lbfgs_evaluate_t proc_evaluate, lbfgs_progress_t proc_progress, void *instance, lbfgs_parameter_t *_param ) { int ret; int i, j, k, ls, end, bound; lbfgsfloatval_t step; /* Constant parameters and their default values. */ const lbfgs_parameter_t* param = (_param != NULL) ? _param : &_defparam; const int m = param->m; lbfgsfloatval_t *xp = NULL, *g = NULL, *gp = NULL, *d = NULL, *w = NULL; iteration_data_t *lm = NULL, *it = NULL; lbfgsfloatval_t ys, yy; lbfgsfloatval_t norm, xnorm, gnorm, beta; lbfgsfloatval_t fx = 0.; line_search_proc linesearch = line_search_morethuente; /* Construct a callback data. */ callback_data_t cd; cd.n = n; cd.instance = instance; cd.proc_evaluate = proc_evaluate; cd.proc_progress = proc_progress; #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) /* Round out the number of variables. */ n = round_out_variables(n); #endif/*defined(USE_SSE)*/ /* Check the input parameters for errors. */ if (n <= 0) { return LBFGSERR_INVALID_N; } #if defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__)) if (n % 8 != 0) { return LBFGSERR_INVALID_N_SSE; } if (((unsigned short)x & 0x000F) != 0) { return LBFGSERR_INVALID_X_SSE; } #endif/*defined(USE_SSE)*/ if (param->min_step < 0.) { return LBFGSERR_INVALID_MINSTEP; } if (param->max_step < param->min_step) { return LBFGSERR_INVALID_MAXSTEP; } if (param->ftol < 0.) { return LBFGSERR_INVALID_FTOL; } if (param->gtol < 0.) { return LBFGSERR_INVALID_GTOL; } if (param->xtol < 0.) { return LBFGSERR_INVALID_XTOL; } if (param->max_linesearch <= 0) { return LBFGSERR_INVALID_MAXLINESEARCH; } if (param->orthantwise_c < 0.) { return LBFGSERR_INVALID_ORTHANTWISE; } if (param->orthantwise_start < 0 || n < param->orthantwise_start) { return LBFGSERR_INVALID_ORTHANTWISE_START; } switch (param->linesearch) { case LBFGS_LINESEARCH_MORETHUENTE: linesearch = line_search_morethuente; break; case LBFGS_LINESEARCH_BACKTRACKING: linesearch = line_search_backtracking; break; default: return LBFGSERR_INVALID_LINESEARCH; } /* Allocate working space. */ xp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); g = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); gp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); d = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); w = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); if (xp == NULL || g == NULL || gp == NULL || d == NULL || w == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } /* Allocate limited memory storage. */ lm = (iteration_data_t*)vecalloc(m * sizeof(iteration_data_t)); if (lm == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } /* Initialize the limited memory. */ for (i = 0;i < m;++i) { it = &lm[i]; it->alpha = 0; it->ys = 0; it->s = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); it->y = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t)); if (it->s == NULL || it->y == NULL) { ret = LBFGSERR_OUTOFMEMORY; goto lbfgs_exit; } } /* Evaluate the function value and its gradient. */ fx = cd.proc_evaluate(cd.instance, x, g, cd.n, 0); if (0. < param->orthantwise_c) { /* Compute L1-regularization factor and add it to the object value. */ norm = 0.; for (i = param->orthantwise_start;i < n;++i) { norm += fabs(x[i]); } fx += norm * param->orthantwise_c; } /* We assume the initial hessian matrix H_0 as the identity matrix. */ if (param->orthantwise_c == 0.) { vecncpy(d, g, n); } else { /* Compute the negative of gradients. */ for (i = 0;i < param->orthantwise_start;++i) { d[i] = -g[i]; } /* Compute the negative of psuedo-gradients. */ for (i = param->orthantwise_start;i < n;++i) { if (x[i] < 0.) { /* Differentiable. */ d[i] = -g[i] + param->orthantwise_c; } else if (0. < x[i]) { /* Differentiable. */ d[i] = -g[i] - param->orthantwise_c; } else { if (g[i] < -param->orthantwise_c) { /* Take the right partial derivative. */ d[i] = -g[i] - param->orthantwise_c; } else if (param->orthantwise_c < g[i]) { /* Take the left partial derivative. */ d[i] = -g[i] + param->orthantwise_c; } else { d[i] = 0.; } } } } /* Make sure that the initial variables are not a minimizer. */ vecnorm(&gnorm, g, n); vecnorm(&xnorm, x, n); if (xnorm < 1.0) xnorm = 1.0; if (gnorm / xnorm <= param->epsilon) { ret = LBFGS_ALREADY_MINIMIZED; goto lbfgs_exit; } /* Compute the initial step: step = 1.0 / sqrt(vecdot(d, d, n)) */ vecrnorm(&step, d, n); k = 1; end = 0; for (;;) { /* Store the current position and gradient vectors. */ veccpy(xp, x, n); veccpy(gp, g, n); /* Search for an optimal step. */ ls = linesearch(n, x, &fx, g, d, &step, w, &cd, param); if (ls < 0) { ret = ls; goto lbfgs_exit; } /* Compute x and g norms. */ vecnorm(&gnorm, g, n); vecnorm(&xnorm, x, n); /* Report the progress. */ if (cd.proc_progress) { if (ret = cd.proc_progress(cd.instance, x, g, fx, xnorm, gnorm, step, cd.n, k, ls)) { goto lbfgs_exit; } } /* Convergence test. The criterion is given by the following formula: |g(x)| / \max(1, |x|) < \epsilon */ if (xnorm < 1.0) xnorm = 1.0; if (gnorm / xnorm <= param->epsilon) { /* Convergence. */ ret = LBFGS_SUCCESS; break; } if (param->max_iterations != 0 && param->max_iterations < k+1) { /* Maximum number of iterations. */ ret = LBFGSERR_MAXIMUMITERATION; break; } /* Update vectors s and y: s_{k+1} = x_{k+1} - x_{k} = \step * d_{k}. y_{k+1} = g_{k+1} - g_{k}. */ it = &lm[end]; vecdiff(it->s, x, xp, n); vecdiff(it->y, g, gp, n); /* Compute scalars ys and yy: ys = y^t \cdot s = 1 / \rho. yy = y^t \cdot y. Notice that yy is used for scaling the hessian matrix H_0 (Cholesky factor). */ vecdot(&ys, it->y, it->s, n); vecdot(&yy, it->y, it->y, n); it->ys = ys; /* Recursive formula to compute dir = -(H \cdot g). This is described in page 779 of: Jorge Nocedal. Updating Quasi-Newton Matrices with Limited Storage. Mathematics of Computation, Vol. 35, No. 151, pp. 773--782, 1980. */ bound = (m <= k) ? m : k; ++k; end = (end + 1) % m; if (param->orthantwise_c == 0.) { /* Compute the negative of gradients. */ vecncpy(d, g, n); } else { /* Compute the negative of gradients. */ for (i = 0;i < param->orthantwise_start;++i) { d[i] = -g[i]; } /* Compute the negative of psuedo-gradients. */ for (i = param->orthantwise_start;i < n;++i) { if (x[i] < 0.) { /* Differentiable. */ d[i] = -g[i] + param->orthantwise_c; } else if (0. < x[i]) { /* Differentiable. */ d[i] = -g[i] - param->orthantwise_c; } else { if (g[i] < -param->orthantwise_c) { /* Take the right partial derivative. */ d[i] = -g[i] - param->orthantwise_c; } else if (param->orthantwise_c < g[i]) { /* Take the left partial derivative. */ d[i] = -g[i] + param->orthantwise_c; } else { d[i] = 0.; } } } /* Store the steepest direction.*/ veccpy(w, d, n); } j = end; for (i = 0;i < bound;++i) { j = (j + m - 1) % m; /* if (--j == -1) j = m-1; */ it = &lm[j]; /* \alpha_{j} = \rho_{j} s^{t}_{j} \cdot q_{k+1}. */ vecdot(&it->alpha, it->s, d, n); it->alpha /= it->ys; /* q_{i} = q_{i+1} - \alpha_{i} y_{i}. */ vecadd(d, it->y, -it->alpha, n); } vecscale(d, ys / yy, n); for (i = 0;i < bound;++i) { it = &lm[j]; /* \beta_{j} = \rho_{j} y^t_{j} \cdot \gamma_{i}. */ vecdot(&beta, it->y, d, n); beta /= it->ys; /* \gamma_{i+1} = \gamma_{i} + (\alpha_{j} - \beta_{j}) s_{j}. */ vecadd(d, it->s, it->alpha - beta, n); j = (j + 1) % m; /* if (++j == m) j = 0; */ } /* Constrain the search direction for orthant-wise updates. */ if (param->orthantwise_c != 0.) { for (i = param->orthantwise_start;i < n;++i) { if (d[i] * w[i] <= 0) { d[i] = 0; } } } /* Now the search direction d is ready. We try step = 1 first. */ step = 1.0; } lbfgs_exit: /* Return the final value of the objective function. */ if (ptr_fx != NULL) { *ptr_fx = fx; } /* Free memory blocks used by this function. */ if (lm != NULL) { for (i = 0;i < m;++i) { vecfree(lm[i].s); vecfree(lm[i].y); } vecfree(lm); } vecfree(w); vecfree(d); vecfree(gp); vecfree(g); vecfree(xp); return ret; }
int lbfgs( int n, double* x, double* pfx, lbfgs_evaluate_t evaluate, lbfgs_progress_t progress, void* instance, const lbfgs_parameter_t* _param ) { int ret; int i, j, k, ls, end, bound, n_evaluate = 0; int enalbe_owlqn; double step; lbfgs_parameter_t param = (_param) ? (*_param) : default_param; const int m = param.m; double* xp; double* g, *gp, *pg = 0; double* d, *w, *pf = 0; iteration_data_t* lm = 0, *it = 0; double ys, yy; double xnorm, gnorm, rate, beta; double fx; line_search_proc_t linesearch = line_search_morethuente; callback_data_t cd; cd.n = n; cd.instance = instance; cd.evaluate = evaluate; cd.progress = (progress) ? progress : default_lbfgs_progress; /* Check the input parameters for errors. */ if (n <= 0) { return LBFGSERR_INVALID_N; } if (param.epsilon < 0.0) { return LBFGSERR_INVALID_EPSILON; } if (param.past < 0) { return LBFGSERR_INVALID_TESTPERIOD; } if (param.delta < 0.0) { return LBFGSERR_INVALID_DELTA; } if (param.min_step < 0.0) { return LBFGSERR_INVALID_MINSTEP; } if (param.max_step < param.min_step) { return LBFGSERR_INVALID_MAXSTEP; } if (param.ftol < 0.0) { return LBFGSERR_INVALID_FTOL; } if (param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE || param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE) { if (param.wolfe <= param.ftol || 1. <= param.wolfe) { return LBFGSERR_INVALID_WOLFE; } } if (param.gtol < 0.0) { return LBFGSERR_INVALID_GTOL; } if (param.xtol < 0.0) { return LBFGSERR_INVALID_XTOL; } if (param.max_linesearch <= 0) { return LBFGSERR_INVALID_MAXLINESEARCH; } if (param.orthantwise_c < 0.0) { return LBFGSERR_INVALID_ORTHANTWISE; } if (param.orthantwise_start < 0 || param.orthantwise_start > n) { return LBFGSERR_INVALID_ORTHANTWISE_START; } if (param.orthantwise_end < 0) { param.orthantwise_end = n; } if (param.orthantwise_end > n) { return LBFGSERR_INVALID_ORTHANTWISE_END; } enalbe_owlqn = (param.orthantwise_c != 0.0); if (enalbe_owlqn) { switch (param.linesearch) { case LBFGS_LINESEARCH_BACKTRACKING_WOLFE: linesearch = line_search_backtracking_owlqn; break; default: /* Only the backtracking method is available. */ return LBFGSERR_INVALID_LINESEARCH; } } else { switch (param.linesearch) { case LBFGS_LINESEARCH_MORETHUENTE: linesearch = line_search_morethuente; break; case LBFGS_LINESEARCH_BACKTRACKING_ARMIJO: case LBFGS_LINESEARCH_BACKTRACKING_WOLFE: case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE: linesearch = line_search_backtracking; break; default: return LBFGSERR_INVALID_LINESEARCH; } } /* Allocate working space. */ xp = vecalloc(n); g = vecalloc(n); gp = vecalloc(n); d = vecalloc(n); w = vecalloc(n); /* Allocate pseudo gradient. */ if (enalbe_owlqn) { pg = vecalloc(n); } /* Allocate and initialize the limited memory storage. */ lm = (iteration_data_t*)xalloc(m * sizeof(iteration_data_t)); for (i = 0; i < m; i++) { it = &lm[i]; it->alpha = 0.0; it->s = vecalloc(n); it->y = vecalloc(n); it->ys = 0.0; } /* Allocate an array for storing previous values of the objective function. */ if (param.past > 0) { pf = vecalloc((size_t)param.past); } fx = cd.evaluate(cd.instance, cd.n, x, g, 0); n_evaluate++; if (enalbe_owlqn) { xnorm = owlqn_x1norm(x, param.orthantwise_start, param.orthantwise_end); fx += xnorm * param.orthantwise_c; owlqn_pseudo_gradient( pg, x, g, n, param.orthantwise_c, param.orthantwise_start, param.orthantwise_end); } /* Store the initial value of the objective function. */ if (pf) { pf[0] = fx; } /** * Compute the direction. * we assume the initial hessian matrix H_0 as the identity matrix. */ if (!enalbe_owlqn) { vecncpy(d, g, n); } else { vecncpy(d, pg, n); } /** * Make sure that the initial variables are not a minimizer. */ vec2norm(&xnorm, x, n); if (!enalbe_owlqn) { vec2norm(&gnorm, g, n); } else { vec2norm(&gnorm, pg, n); } if (xnorm < 1.0) { xnorm = 1.0; } if (gnorm / xnorm <= param.epsilon) { ret = LBFGS_ALREADY_MINIMIZED; goto lbfgs_exit; } /** * Compute the initial step: * step = 1.0 / ||d|| */ vec2norminv(&step, d, n); k = 1; end = 0; for (;;) { /* Store the current position and gradient vectors. */ veccpy(xp, x, n); veccpy(gp, g, n); /* Search for an optimal step. */ if (!enalbe_owlqn) { ls = linesearch(n, x, &fx, g, d, &step, xp, gp, w, &cd, ¶m); } else { ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, ¶m); owlqn_pseudo_gradient( pg, x, g, n, param.orthantwise_c, param.orthantwise_start, param.orthantwise_end ); } if (ls < 0) { /* Revert to the previous point. */ veccpy(x, xp, n); veccpy(g, gp, n); ret = ls; break; } n_evaluate += ls; /* Compute x and g norms. */ vec2norm(&xnorm, x, n); if (!enalbe_owlqn) { vec2norm(&gnorm, g, n); } else { vec2norm(&gnorm, pg, n); } /* Report the progress. */ if ((ret = cd.progress(cd.instance, cd.n, x, g, fx, xnorm, gnorm, step, k, n_evaluate)) != 0) { ret = LBFGSERR_CANCELED; break; } /* Convergence test. */ if (xnorm < 1.0) { xnorm = 1.0; } if (gnorm / xnorm <= param.epsilon) { ret = LBFGS_CONVERGENCE; break; } /* Stopping criterion test. */ if (pf) { /* We don't test the stopping criterion while k < past. */ if (param.past <= k) { /* Compute the relative improvement from the past. */ rate = (pf[k % param.past] - fx) / fx; /* The stopping criterion. */ if (rate < param.delta) { ret = LBFGS_CONVERGENCE_DELTA; break; } } /* Store the current value of the objective function. */ pf[k % param.past] = fx; } if (param.max_iterations != 0 && param.max_iterations < k + 1) { ret = LBFGSERR_MAXIMUMITERATION; break; } /** * Update s and y: * s_{k+1} = x_{k+1} - x_{k} = step * d_{k} * y_{k+1} = g_{k+1} - g_{k} */ it = &lm[end]; vecdiff(it->s, x, xp, n); vecdiff(it->y, g, gp, n); /** * Compute scalars ys and yy: * ys = y^t s = 1 / \rho * yy = y^t y * Notice that yy is used for scaling the hessian matrix H_0 (Cholesky factor). */ vecdot(&ys, it->y, it->s, n); vecdot(&yy, it->y, it->y, n); it->ys = ys; /** * Recursive formula to compute d = -(H g). * This is described in page 779 of: * Jorge Nocedal. * Updating Quasi-Newton Matrices with Limited Storage. * Mathematics of Computation, Vol. 35, No. 151, * pp. 773--782, 1980. */ bound = (m <= k) ? m : k; k++; end = (end + 1) % m; /* Compute the steepest direction. */ /* Compute the negative of (pseudo) gradient. */ if (!enalbe_owlqn) { vecncpy(d, g, n); } else { vecncpy(d, pg, n); } j = end; for (i = 0; i < bound; i++) { j = (j + m - 1) % m; /* if (--j == -1) j = m-1; */ it = &lm[j]; /* \alpha_{j} = \rho_{j} s^{t}_{j} q_{k+1} */ vecdot(&it->alpha, it->s, d, n); it->alpha /= it->ys; /* q_{i} = q_{i+1} - \alpha_{i} y_{i} */ vecadd(d, it->y, -it->alpha, n); } vecscale(d, ys / yy, n); for (i = 0; i < bound; i++) { it = &lm[j]; /* \beta_{j} = \rho_{j} y^t_{j} \gamma_{i} */ vecdot(&beta, it->y, d, n); beta /= it->ys; /* \gamma_{i+1} = \gamma_{i} + (\alpha_{j} - \beta_{j}) s_{j} */ vecadd(d, it->s, it->alpha - beta, n); j = (j + 1) % m; /* if (++j == m) j = 0; */ } /* Constrain the search direction for orthant-wise updates. */ if (enalbe_owlqn) { owlqn_contrain_line_search(d, pg, param.orthantwise_start, param.orthantwise_end); } /* Now the search direction d is ready. We try step = 1 first. */ step = 1.0; } lbfgs_exit: /* Return the final value of the objective function. */ if (pfx) { *pfx = fx; } vecfree(pf); if (lm != 0) { for (i = 0; i < m; i++) { vecfree(lm[i].s); vecfree(lm[i].y); } xfree(lm); } vecfree(pg); vecfree(w); vecfree(d); vecfree(gp); vecfree(g); vecfree(xp); return ret; }
int main( int argc, /* arg count */ char * argv[] /* arg vector */ ){ static char * context = "main(chain)"; char * stem = NULL; /* dump filename stem */ char * suffix = NULL; /* dump filename suffix */ char * suff2 = NULL; /* last half of suffix */ int nr, nc; /* integer matrix sizes */ int n; /* square matrix/vector size */ real base_x, base_y; /* base of Mandelbrot */ real ext_x, ext_y; /* extent of Mandelbrot */ int limit, seed; /* randmat controls */ real fraction; /* invperc/thresh filling */ int itersLife; /* life iterations */ int itersElastic, relax; /* elastic controls */ int2D i2D; /* integer matrix */ bool2D b2D; /* boolean matrix */ pt1D cities; /* cities point vector */ int n_cities; /* number of cities */ pt1D net; /* net point vector */ int n_net; /* number of net points */ real2D r2D_gauss; /* real matrix for Gaussian */ real2D r2D_sor; /* real matrix for SOR */ real1D r1D_gauss_v; /* real vector input for Gaussian */ real1D r1D_sor_v; /* real vector input for SOR */ real1D r1D_gauss_a; /* real vector answer for Gaussian */ real1D r1D_sor_a; /* real vector answer for SOR */ real1D r1D_gauss_c; /* real vector check for Gaussian */ real1D r1D_sor_c; /* real vector check for SOR */ real tol; /* SOR tolerance */ real realDiff; /* vector difference */ bool choicesSet = FALSE; /* path choices set? */ bool doMandel = TRUE; /* mandel vs. randmat */ bool doInvperc = TRUE; /* invperc vs. thresholding */ bool doDump = FALSE; /* dump intermediate results? */ int argd = 1; /* argument index */ /* arguments */ #if NUMA MAIN_INITENV(,32000000) #endif while (argd < argc){ CHECK(argv[argd][0] == '-', fail(context, "bad argument", "index", "%d", argd, NULL)); switch(argv[argd][1]){ case 'E' : /* elastic */ itersElastic = arg_int(context, argc, argv, argd+1, argv[argd]); relax = arg_int(context, argc, argv, argd+2, argv[argd]); argd += 3; break; case 'F' : /* fraction (invperc/thresh) */ fraction = arg_real(context, argc, argv, argd+1, argv[argd]); argd += 2; break; case 'L' : /* life */ itersLife = arg_int(context, argc, argv, argd+1, argv[argd]); argd += 2; break; case 'M' : /* mandel */ base_x = arg_real(context, argc, argv, argd+1, argv[argd]); base_y = arg_real(context, argc, argv, argd+2, argv[argd]); ext_x = arg_real(context, argc, argv, argd+3, argv[argd]); ext_y = arg_real(context, argc, argv, argd+4, argv[argd]); argd += 5; break; case 'N' : /* winnow */ n_cities = arg_int(context, argc, argv, argd+1, argv[argd]); argd += 2; break; case 'R' : /* randmat */ limit = arg_int(context, argc, argv, argd+1, argv[argd]); seed = arg_int(context, argc, argv, argd+2, argv[argd]); argd += 3; break; case 'S' : /* matrix size */ nr = arg_int(context, argc, argv, argd+1, argv[argd]); nc = arg_int(context, argc, argv, argd+2, argv[argd]); argd += 3; break; case 'T' : /* SOR tolerance */ tol = arg_real(context, argc, argv, argd+1, argv[argd]); argd += 2; break; case 'c' : /* choice */ CHECK(!choicesSet, fail(context, "choices already set", NULL)); suffix = arg_str(context, argc, argv, argd+1, argv[argd]); argd += 2; switch(suffix[0]){ case 'i' : doInvperc = TRUE; break; case 't' : doInvperc = FALSE; break; default : fail(context, "unknown choice(s)", "choice", "%s", suffix, NULL); } switch(suffix[1]){ case 'm' : doMandel = TRUE; break; case 'r' : doMandel = FALSE; break; default : fail(context, "unknown choice(s)", "choice", "%s", suffix, NULL); } suff2 = suffix+1; choicesSet = TRUE; break; case 'd' : /* dump */ doDump = TRUE; argd += 1; if ((argd < argc) && (argv[argd][0] != '-')){ stem = arg_str(context, argc, argv, argd, argv[argd-1]); argd += 1; } break; #if GRAPHICS case 'g' : gfx_open(app_chain, arg_gfxCtrl(context, argc, argv, argd+1, argv[argd])); argd += 2; break; #endif #if MIMD case 'p' : DataDist = arg_dataDist(context, argc, argv, argd+1, argv[argd]); ParWidth = arg_int(context, argc, argv, argd+2, argv[argd]); argd += 3; break; #endif case 'u' : io_init(FALSE); argd += 1; break; default : fail(context, "unknown flag", "flag", "%s", argv[argd], NULL); break; } } CHECK(choicesSet, fail("context", "choices not set using -c flag", NULL)); /* initialize */ #if MIMD sch_init(DataDist); #endif /* mandel vs. randmat */ if (doMandel){ mandel(i2D, nr, nc, base_x, base_y, ext_x, ext_y); if (doDump) io_wrInt2D(context, mkfname(stem, NULL, suff2, "i2"), i2D, nr, nc); } else { randmat(i2D, nr, nc, limit, seed); if (doDump) io_wrInt2D(context, mkfname(stem, NULL, suff2, "i2"), i2D, nr, nc); } /* half */ half(i2D, nr, nc); if (doDump) io_wrInt2D(context, mkfname(stem, "h", suff2, "i2"), i2D, nr, nc); /* invperc vs. thresh */ if (doInvperc){ invperc(i2D, b2D, nr, nc, fraction); if (doDump) io_wrBool2D(context, mkfname(stem, NULL, suffix, "b2"), b2D, nr, nc); } else { thresh(i2D, b2D, nr, nc, fraction); if (doDump) io_wrBool2D(context, mkfname(stem, NULL, suffix, "b2"), b2D, nr, nc); } /* life */ life(b2D, nr, nc, itersLife); if (doDump) io_wrBool2D(context, mkfname(stem, "l", suffix, "b2"), b2D, nr, nc); /* winnow */ winnow(i2D, b2D, nr, nc, cities, n_cities); if (doDump) io_wrPt1D(context, mkfname(stem, "w", suffix, "p1"), cities, n_cities); /* norm */ norm(cities, n_cities); if (doDump) io_wrPt1D(context, mkfname(stem, "n", suffix, "p1"), cities, n_cities); /* elastic */ n_net = (int)(ELASTIC_RATIO * n_cities); CHECK(n_net <= MAXEXT, fail(context, "too many net points required", "number of net points", "%d", n_net, NULL)); elastic(cities, n_cities, net, n_net, itersElastic, relax); if (doDump) io_wrPt1D(context, mkfname(stem, "e", suffix, "p1"), net, n_net); /* outer */ n = n_net; outer(net, r2D_gauss, r1D_gauss_v, n); if (doDump){ io_wrReal2D(context, mkfname(stem, "o", suffix, "r2"), r2D_gauss, n, n); io_wrReal1D(context, mkfname(stem, "o", suffix, "r1"), r1D_gauss_v, n); } cpReal2D(r2D_gauss, r2D_sor, n, n); cpReal1D(r1D_gauss_v, r1D_sor_v, n); /* gauss */ gauss(r2D_gauss, r1D_gauss_v, r1D_gauss_a, n); if (doDump) io_wrReal1D(context, mkfname(stem, "g", suffix, "r1"), r1D_gauss_a, n); /* product (gauss) */ product(r2D_gauss, r1D_gauss_a, r1D_gauss_c, n, n); if (doDump) io_wrReal1D(context, mkfname(stem, "pg", suffix, "r1"), r1D_gauss_c, n); /* sor */ sor(r2D_sor, r1D_sor_v, r1D_sor_a, n, tol); if (doDump) io_wrReal1D(context, mkfname(stem, "s", suffix, "r1"), r1D_gauss_a, n); /* product (sor) */ product(r2D_sor, r1D_sor_a, r1D_sor_c, n, n); if (doDump) io_wrReal1D(context, mkfname(stem, "ps", suffix, "r1"), r1D_gauss_c, n); /* difference */ vecdiff(r1D_gauss_a, r1D_sor_a, n, &realDiff); if (doDump) io_wrReal0D(context, mkfname(stem, "v", suffix, "r0"), realDiff); #if IEEE ieee_retrospective(stderr); #endif #if NUMA MAIN_END; #endif return 0; }