Example #1
0
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;
}
Example #2
0
// 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;
	}
}
Example #3
0
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;
}
Example #4
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, &param);
        } else {
            ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, &param);
            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;
}
Example #5
0
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;
}
Example #6
0
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, &param);
    } else {
      ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, &param);
      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;
}
Example #7
0
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;
}