opk_vmlmb_t* opk_new_vmlmb_optimizer(const opk_vmlmb_options_t* opts, opk_vspace_t* space, opk_lnsrch_t* lnsrch, opk_convexset_t* box) { opk_vmlmb_options_t options; opk_vmlmb_t* opt; size_t s_offset, y_offset, alpha_offset, rho_offset, size; opk_index_t k, m; /* Check options. */ if (opts == NULL) { /* Use default options. */ opk_get_vmlmb_default_options(&options); opts = &options; } if (opk_check_vmlmb_options(opts) != OPK_SUCCESS) { errno = EINVAL; return NULL; } m = opts->mem; /* Check other input arguments for errors. */ if (space == NULL) { errno = EFAULT; return NULL; } if (space->size < 1 || m < 1) { errno = EINVAL; return NULL; } if (m > space->size) { m = space->size; } if (box != NULL && box->space != space) { errno = EINVAL; return NULL; } /* Allocate enough memory for the workspace and its arrays. */ s_offset = ROUND_UP(sizeof(opk_vmlmb_t), sizeof(opk_vector_t*)); y_offset = s_offset + m*sizeof(opk_vector_t*); alpha_offset = ROUND_UP(y_offset + m*sizeof(opk_vector_t*), sizeof(double)); rho_offset = alpha_offset + m*sizeof(double); size = rho_offset + m*sizeof(double); opt = (opk_vmlmb_t*)opk_allocate_object(finalize_vmlmb, size); if (opt == NULL) { return NULL; } opt->s = ADDRESS(opk_vector_t*, opt, s_offset); opt->y = ADDRESS(opk_vector_t*, opt, y_offset); opt->alpha = ADDRESS(double, opt, alpha_offset); opt->rho = ADDRESS(double, opt, rho_offset); opt->m = m; opt->gamma = 1.0; opt->delta = opts->delta; opt->epsilon = opts->epsilon; opt->grtol = opts->grtol; opt->gatol = opts->gatol; opt->stpmin = opts->stpmin; opt->stpmax = opts->stpmax; opt->save_memory = opts->save_memory; if (box == NULL) { opt->method = OPK_LBFGS; } else if (opts->blmvm) { /* For the BLMVM method, the scratch vector is used to store the projected gradient. */ opt->method = OPK_BLMVM; opt->gp = opk_vcreate(space); if (opt->gp == NULL) { goto error; } } else { opt->method = OPK_VMLMB; } /* Allocate work vectors. If saving memory, x0 and g0 will be weak references to one of the saved vectors in the LBFGS operator. */ for (k = 0; k < m; ++k) { opt->s[k] = opk_vcreate(space); if (opt->s[k] == NULL) { goto error; } opt->y[k] = opk_vcreate(space); if (opt->y[k] == NULL) { goto error; } } opt->vspace = OPK_HOLD_VSPACE(space); if (lnsrch != NULL) { opt->lnsrch = OPK_HOLD_LNSRCH(lnsrch); } else { if (box != NULL) { opt->lnsrch = opk_lnsrch_new_backtrack(SFTOL, SAMIN); } else { opt->lnsrch = opk_lnsrch_new_csrch(SFTOL, SGTOL, SXTOL); } if (opt->lnsrch == NULL) { goto error; } } if (! opt->save_memory) { opt->x0 = opk_vcreate(space); if (opt->x0 == NULL) { goto error; } opt->g0 = opk_vcreate(space); if (opt->g0 == NULL) { goto error; } } opt->d = opk_vcreate(space); if (opt->d == NULL) { goto error; } if (box != NULL) { opt->box = OPK_HOLD_CONVEXSET(box); opt->w = opk_vcreate(space); if (opt->w == NULL) { goto error; } } /* Enforce calling opk_vmlmb_start and return the optimizer. */ failure(opt, OPK_NOT_STARTED); return opt; error: OPK_DROP(opt); return NULL; }
opk_vmlmn_t* opk_new_vmlmn_optimizer(opk_vspace_t* space, opk_index_t m, unsigned int flags, opk_bound_t* xl, opk_bound_t* xu, opk_lnsrch_t* lnsrch) { opk_vmlmn_t* opt; size_t s_offset, y_offset, beta_offset, rho_offset, size; opk_index_t k; int bounds; /* Check the input arguments for errors. */ if (space == NULL) { errno = EFAULT; return NULL; } if (space->size < 1 || m < 1) { errno = EINVAL; return NULL; } if (m > space->size) { m = space->size; } bounds = 0; if (xl != NULL) { if (xl->owner != space) { errno = EINVAL; return NULL; } if (xl->type == OPK_BOUND_SCALAR) { bounds += 1; } else if (xl->type == OPK_BOUND_VECTOR) { bounds += 2; } else { /* Discard unused bound. */ xl = NULL; } } if (xu != NULL) { if (xu->owner != space) { errno = EINVAL; return NULL; } if (xu->type == OPK_BOUND_SCALAR) { bounds += 3; } else if (xu->type == OPK_BOUND_VECTOR) { bounds += 6; } else { /* Discard unused bound. */ xu = NULL; } } /* Allocate enough memory for the workspace and its arrays. */ s_offset = ROUND_UP(sizeof(opk_vmlmn_t), sizeof(opk_vector_t*)); y_offset = s_offset + m*sizeof(opk_vector_t*); beta_offset = ROUND_UP(y_offset + m*sizeof(opk_vector_t*), sizeof(double)); rho_offset = beta_offset + m*sizeof(double); size = rho_offset + m*sizeof(double); opt = (opk_vmlmn_t*)opk_allocate_object(finalize_vmlmn, size); if (opt == NULL) { return NULL; } opt->s = ADDRESS(opk_vector_t*, opt, s_offset); opt->y = ADDRESS(opk_vector_t*, opt, y_offset); opt->beta = ADDRESS(double, opt, beta_offset); opt->rho = ADDRESS(double, opt, rho_offset); opt->m = m; opt->gamma = 1.0; opt->bounds = bounds; opt->flags = flags; if (opt->bounds == 0) { opt->method = OPK_LBFGS; } else if ((flags & OPK_EMULATE_BLMVM) != 0) { /* For the BLMVM method, the scratch vector is used to store the projected gradient. */ opt->method = OPK_BLMVM; opt->tmp = opk_vcreate(space); if (opt->tmp == NULL) { goto error; } } else { opt->method = OPK_VMLMN; } opk_set_vmlmn_options(opt, NULL); /* Allocate work vectors. If saving memory, x0 and g0 will be weak references to one of the saved vectors in the LBFGS operator. */ for (k = 0; k < m; ++k) { opt->s[k] = opk_vcreate(space); if (opt->s[k] == NULL) { goto error; } opt->y[k] = opk_vcreate(space); if (opt->y[k] == NULL) { goto error; } } opt->vspace = OPK_HOLD_VSPACE(space); if (lnsrch != NULL) { opt->lnsrch = OPK_HOLD_LNSRCH(lnsrch); } else { if (bounds != 0) { opt->lnsrch = opk_lnsrch_new_backtrack(SFTOL, SAMIN); } else { opt->lnsrch = opk_lnsrch_new_csrch(SFTOL, SGTOL, SXTOL); } if (opt->lnsrch == NULL) { goto error; } } if (xl != NULL) { opt->xl = OPK_HOLD_BOUND(xl); } if (xu != NULL) { opt->xu = OPK_HOLD_BOUND(xu); } #if ! SAVE_MEMORY opt->x0 = opk_vcreate(space); if (opt->x0 == NULL) { goto error; } opt->g0 = opk_vcreate(space); if (opt->g0 == NULL) { goto error; } #endif opt->d = opk_vcreate(space); if (opt->d == NULL) { goto error; } if (opt->bounds != 0) { opt->w = opk_vcreate(space); if (opt->w == NULL) { goto error; } } /* Enforce calling opk_vmlmn_start and return the optimizer. */ failure(opt, OPK_NOT_STARTED); return opt; error: OPK_DROP(opt); return NULL; }