opk_task_t opk_iterate_vmlmb(opk_vmlmb_t* opt, opk_vector_t* x, double f, opk_vector_t* g) { double dtg, gtest, stpmin, stpmax; opk_index_t k; opk_status_t status; opk_lnsrch_task_t lnsrch_task; opk_bool_t bounded; if (opt == NULL) { return OPK_TASK_ERROR; } bounded = (opt->box != NULL); switch (opt->task) { case OPK_TASK_COMPUTE_FG: /* Caller has computed the function value and the gradient at the current point. */ ++opt->evaluations; if (opt->evaluations > 1) { /* A line search is in progress, check whether it has converged. */ if (opk_lnsrch_use_deriv(opt->lnsrch)) { if (bounded) { /* Compute the directional derivative as the inner product between the effective step and the gradient divided by the step length. */ #if 0 if (opt->tmp == NULL && (opt->tmp = opk_vcreate(opt->vspace)) == NULL) { return failure(opt, OPK_INSUFFICIENT_MEMORY); } AXPBY(opt->tmp, 1, x, -1, opt->x0); dtg = DOT(opt->tmp, g)/opt->stp; #else dtg = (DOT(x, g) - DOT(opt->x0, g))/opt->stp; #endif } else { /* Compute the directional derivative. */ dtg = -opk_vdot(opt->d, g); } } else { /* Line search does not need directional derivative. */ dtg = 0; } lnsrch_task = opk_lnsrch_iterate(opt->lnsrch, &opt->stp, f, dtg); if (lnsrch_task == OPK_LNSRCH_SEARCH) { /* Line search has not yet converged, break to compute a new trial point along the search direction. */ break; } if (lnsrch_task != OPK_LNSRCH_CONVERGENCE) { /* An error may have occurred during the line search. Figure out whether this error can be safely ignored. */ status = opk_lnsrch_get_status(opt->lnsrch); if (lnsrch_task != OPK_LNSRCH_WARNING || status != OPK_ROUNDING_ERRORS_PREVENT_PROGRESS) { return failure(opt, status); } } ++opt->iterations; } /* The current step is acceptable. Check for global convergence. */ if (bounded) { /* Determine the set of free variables. */ status = opk_get_free_variables(opt->w, x, opt->box, g, OPK_ASCENT); if (status != OPK_SUCCESS) { return failure(opt, status); } } if (opt->method == OPK_VMLMB) { /* Compute the Euclidean norm of the projected gradient. */ opt->gnorm = WNORM2(g); } else if (opt->method == OPK_BLMVM) { /* Compute the projected gradient and its norm. */ opk_vproduct(opt->gp, opt->w, g); opt->gnorm = NORM2(opt->gp); } else { /* Compute the Euclidean norm of the gradient. */ opt->gnorm = NORM2(g); } if (opt->evaluations == 1) { opt->ginit = opt->gnorm; } gtest = max3(0.0, opt->gatol, opt->grtol*opt->ginit); return success(opt, (opt->gnorm <= gtest ? OPK_TASK_FINAL_X : OPK_TASK_NEW_X)); case OPK_TASK_NEW_X: case OPK_TASK_FINAL_X: /* Compute a new search direction. */ if (opt->iterations >= 1) { /* Update L-BFGS approximation of the Hessian. */ update(opt, x, (opt->method == OPK_BLMVM ? opt->gp : g)); } status = apply(opt, g); if (status == OPK_SUCCESS) { /* The L-BFGS approximation produces a search direction D. To warrant convergence, we have to check whether -D is a sufficient descent direction (that is to say that D is a sufficient ascent direction). As shown by Zoutendijk, this is true if cos(theta) = (D/|D|)'.(G/|G|) is larger or equal EPSILON > 0, where G is the gradient at X and D the, ascent for us, search direction. */ if (bounded) { /* Project the search direction produced by the L-BFGS recursion. */ status = opk_project_direction(opt->d, x, opt->box, opt->d, OPK_ASCENT); if (status != OPK_SUCCESS) { return failure(opt, status); } } dtg = -DOT(opt->d, g); if (opt->epsilon > 0 && -dtg < opt->epsilon*NORM2(opt->d)*opt->gnorm) { /* -D is not a sufficient descent direction. Set the directional derivative to zero to force using the steepest descent direction. */ dtg = 0.0; } } else { /* The L-BFGS approximation is not available (first iteration or just after a reset) or failed to produce a direction. Set the directional derivative to zero to use the steepest descent direction. */ dtg = 0.0; } /* Determine the initial step length. */ if (dtg < 0) { /* A sufficient descent direction has been produced by L-BFGS recursion. An initial unit step will be used. */ opt->stp = 1.0; } else { /* First iteration or L-BFGS recursion failed to produce a sufficient descent direction, use the (projected) gradient as a search direction. */ if (opt->mp > 0) { /* L-BFGS recursion did not produce a sufficient descent direction. */ ++opt->restarts; opt->mp = 0; } if (opt->method == OPK_VMLMB) { /* Use the projected gradient. */ opk_vproduct(opt->d, opt->w, g); } else if (opt->method == OPK_BLMVM) { /* Use the projected gradient (which has already been computed and * stored in the scratch vector). */ opk_vcopy(opt->d, opt->gp); } else { /* Use the gradient. */ opk_vcopy(opt->d, g); } dtg = -opt->gnorm*opt->gnorm; if (f != 0) { opt->stp = 2*fabs(f/dtg); } else { /* Use a small step compared to X. */ double dnorm = opt->gnorm; double xnorm = (bounded ? WNORM2(x) : NORM2(x)); if (xnorm > 0) { opt->stp = opt->delta*xnorm/dnorm; } else { opt->stp = opt->delta/dnorm; } } } stpmin = opt->stp*opt->stpmin; stpmax = opt->stp*opt->stpmax; if (bounded) { /* Shortcut the step length. */ double bsmin1, bsmin2, bsmax; status = opk_get_step_limits(&bsmin1, &bsmin2, &bsmax, x, opt->box, opt->d, OPK_ASCENT); if (bsmin1 < 0) { fprintf(stderr, "FIXME: SMIN1 =%g, SMIN2 =%g, SMAX =%g\n", bsmin1, bsmin2, bsmax); } if (status != OPK_SUCCESS) { return failure(opt, status); } if (bsmax <= 0) { return failure(opt, OPK_WOULD_BLOCK); } if (opt->stp > bsmax) { opt->stp = bsmax; } if (stpmax > bsmax) { stpmax = bsmax; } opt->bsmin = bsmin2; } /* Save current point. */ if (opt->save_memory) { k = SLOT(0); opt->x0 = S(k); /* weak reference */ opt->g0 = Y(k); /* weak reference */ if (opt->mp == opt->m) { --opt->mp; } } COPY(opt->x0, x); COPY(opt->g0, (opt->method == OPK_BLMVM ? opt->gp : g)); opt->f0 = f; /* Start the line search and break to take the first step along the line search. */ if (opk_lnsrch_start(opt->lnsrch, f, dtg, opt->stp, stpmin, stpmax) != OPK_LNSRCH_SEARCH) { return failure(opt, opk_lnsrch_get_status(opt->lnsrch)); } break; default: /* There must be something wrong. */ return opt->task; } /* Compute a new trial point along the line search. */ opk_vaxpby(x, 1, opt->x0, -opt->stp, opt->d); if (bounded && opt->stp > opt->bsmin) { opk_status_t status = opk_project_variables(x, x, opt->box); if (status != OPK_SUCCESS) { return failure(opt, status); } } return success(opt, OPK_TASK_COMPUTE_FG); }
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_task_t opk_iterate_vmlmn(opk_vmlmn_t* opt, opk_vector_t* x, double f, opk_vector_t* g) { double dtg; opk_index_t k; opk_status_t status; opk_lnsrch_task_t lnsrch_task; opk_bool_t bounded, final; bounded = (opt->bounds != 0); switch (opt->task) { case OPK_TASK_COMPUTE_FG: /* Caller has computed the function value and the gradient at the current point. */ ++opt->evaluations; if (opt->evaluations > 1) { /* A line search is in progress, check whether it has converged. */ if (opk_lnsrch_use_deriv(opt->lnsrch)) { if (bounded) { /* Compute the directional derivative as the inner product between the effective step and the gradient. */ #if 0 if (opt->tmp == NULL && (opt->tmp = opk_vcreate(opt->vspace)) == NULL) { return failure(opt, OPK_INSUFFICIENT_MEMORY); } AXPBY(opt->tmp, 1, x, -1, opt->x0); dtg = DOT(opt->tmp, g)/opt->stp; #else dtg = (DOT(x, g) - DOT(opt->x0, g))/opt->stp; #endif } else { /* Compute the directional derivative. */ dtg = -opk_vdot(opt->d, g); } } else { /* Line search does not need directional derivative. */ dtg = 0; } lnsrch_task = opk_lnsrch_iterate(opt->lnsrch, &opt->stp, f, dtg); if (lnsrch_task == OPK_LNSRCH_SEARCH) { /* Line search has not yet converged, break to compute a new trial point along the search direction. */ break; } if (lnsrch_task != OPK_LNSRCH_CONVERGENCE) { status = opk_lnsrch_get_status(opt->lnsrch); if (lnsrch_task != OPK_LNSRCH_WARNING || status != OPK_ROUNDING_ERRORS_PREVENT_PROGRESS) { return failure(opt, status); } } ++opt->iterations; } if (bounded) { /* Determine the set of free variables. */ status = opk_box_get_free_variables(opt->w, x, opt->xl, opt->xu, g, OPK_ASCENT); if (status != OPK_SUCCESS) { return failure(opt, status); } } /* Check for global convergence. */ if (opt->method == OPK_VMLMN) { /* Compute the Euclidean norm of the projected gradient. */ opt->gnorm = WNORM2(g); } else if (opt->method == OPK_BLMVM) { /* Compute the projected gradient and its norm. */ opk_vproduct(opt->tmp, opt->w, g); opt->gnorm = NORM2(opt->tmp); } else { /* Compute the Euclidean norm of the gradient. */ opt->gnorm = NORM2(g); } if (opt->evaluations == 1) { opt->ginit = opt->gnorm; } final = (opt->gnorm <= max3(0.0, opt->gatol, opt->grtol*opt->ginit)); return success(opt, (final ? OPK_TASK_FINAL_X : OPK_TASK_NEW_X)); case OPK_TASK_NEW_X: case OPK_TASK_FINAL_X: /* Compute a new search direction. */ if (opt->iterations >= 1) { /* Update L-BFGS approximation of the Hessian. */ update(opt, x, (opt->method == OPK_BLMVM ? opt->tmp : g)); } if (apply(opt, g) == OPK_SUCCESS) { /* We take care of checking whether -D is a sufficient descent direction (that is to say that D is a sufficient ascent direction). As shown by Zoutendijk, this is true if cos(theta) = (D/|D|)'.(G/|G|) is larger or equal EPSILON > 0, where G is the gradient at X and D the (ascent for us) search direction. */ dtg = -DOT(opt->d, g); if (opt->epsilon > 0 && dtg > -opt->epsilon*NORM2(opt->d)*opt->gnorm) { /* We do not have a sufficient descent direction. Set the directional derivative to zero to force using the steepest descent direction. */ dtg = 0.0; } } else { /* The L-BFGS approximation is unset (first iteration) or failed to produce a direction. Set the directional derivative to zero to use the steepest descent direction. */ dtg = 0.0; } /* Determine the initial step length. */ if (dtg < 0) { /* A sufficient descent direction has been produced by L-BFGS recursion. An initial unit step will be used. */ opt->stp = 1.0; } else { /* First iteration or L-BFGS recursion failed to produce a sufficient descent direction, use the (projected) gradient as a search direction. */ if (opt->mp > 0) { /* L-BFGS recursion did not produce a sufficient descent direction. */ ++opt->restarts; opt->mp = 0; } if (opt->method == OPK_VMLMN) { /* Use the projected gradient. */ opk_vproduct(opt->d, opt->w, g); } else if (opt->method == OPK_BLMVM) { /* Use the projected gradient (which has aready been computed and * stored in the scratch vector). */ opk_vcopy(opt->d, opt->tmp); } else { /* Use the gradient. */ opk_vcopy(opt->d, g); } dtg = -opt->gnorm*opt->gnorm; if (f != 0) { opt->stp = 2*fabs(f/dtg); } else { /* Use a small step compared to X. */ double dnorm = opt->gnorm; double xnorm = (bounded ? WNORM2(x) : NORM2(x)); if (xnorm > 0) { opt->stp = opt->delta*xnorm/dnorm; } else { opt->stp = opt->delta/dnorm; } } } if (bounded) { /* Shortcut the step length. */ double bsmin, bsmax, wolfe; status = opk_box_get_step_limits(&bsmin, &wolfe, &bsmax, x, opt->xl, opt->xu, opt->d, OPK_ASCENT); if (status != OPK_SUCCESS) { return failure(opt, status); } if (bsmax <= 0) { return failure(opt, OPK_WOULD_BLOCK); } if (opt->stp > bsmax) { opt->stp = bsmax; } opt->bsmin = bsmin; } /* Save current point. */ #if SAVE_MEMORY k = slot(opt, 0); opt->x0 = S(k); /* weak reference */ opt->g0 = Y(k); /* weak reference */ if (opt->mp == opt->m) { --opt->mp; } #endif COPY(opt->x0, x); COPY(opt->g0, (opt->method == OPK_BLMVM ? opt->tmp : g)); opt->f0 = f; /* Start the line search and break to take the first step along the line search. */ if (opk_lnsrch_start(opt->lnsrch, f, dtg, opt->stp, opt->stp*opt->stpmin, opt->stp*opt->stpmax) != OPK_LNSRCH_SEARCH) { return failure(opt, opk_lnsrch_get_status(opt->lnsrch)); } break; default: /* There must be something wrong. */ return opt->task; }
/* ------------------------------------------------------------------------------------------ ------------------------------- FONCTION INITIALISATION ------------------------------------- --------------------------------------------------------------------------------------------- */ static PyObject * opk_initialisation(PyObject * self, PyObject * args, PyObject * keywds) { // ------------------------------------- DECLARATIONS ---------------------------------- #define TRUE 1 #define FALSE 0 // Parameters of the minimization problem. They will receive values according to what the user asks opk_lnsrch_t *lnsrch = NULL; int autostep = 0; // Input arguments in c void *x; char *linesrch_name = "quadratic"; char *autostep_name = "ShannoPhua"; char *nlcgmeth_name = "FletcherReeves"; char *vmlmbmeth_name = "OPK_LBFGS"; double delta; // No need for default value double epsilon; // No need for default value int delta_given; // No need for default value int epsilon_given; // No need for default value double gatol = 1.0e-6; double grtol = 0.0; double bl = 0; // Value if user doesn't specifie anything and algorithm is vmlmb double bu = 1e6; // Value if user doesn't specifie anything and algorithm is vmlmb int bound_given = 0; // No Default boundries int mem = 5; // Value if user doesn't specifie anything and algorithm is vmlmb int powell = FALSE; int single = FALSE; // Input x as a PyObject PyObject *x_obj = NULL; PyObject *x_arr = NULL; // Other local variables opk_vector_t *vbl; // bounds opk_vector_t *vbu; // bounds double sftol = 1e-4; // Values used in linesearch setting double sgtol = 0.9; // Values used in linesearch setting double sxtol = 1e-15; // Values used in linesearch setting double samin = 0.1; // Values used in linesearch setting opk_bound_t *lower; // bounds opk_bound_t *upper; // bounds // Returned value PyObject *task_py; // Print the error messages in an external file "text.txt" FILE* fichier = NULL; fichier = fopen("text.txt", "w"); if (fichier == NULL) { return Py_None; } // ------------------------------------------------------------------------------------- // --------------------- PYTHON OBJECT ARE CONVERTED TO C OBJECT ----------------------- /* i = int s = string f = float d = double p = predicate (bool) = int | = other arguments are optionals */ static char *kwlist[] = { "x", "algorithm", "linesearch", "autostep", "_nlcg", "_vmlmb", "delta", "epsilon", "delta_given", "epsilon_given", "gatol", "grtol", "bl", "bu", "bound_given", "mem", "powell", "single", "_limited", NULL }; if (!PyArg_ParseTupleAndKeywords (args, keywds, "Osssssddiiddddiiiii", kwlist, &x_obj, &_algorithm_name, &linesrch_name, &autostep_name, &nlcgmeth_name, &vmlmbmeth_name, &delta, &epsilon, &delta_given, &epsilon_given, &gatol, &grtol, &bl, &bu, &bound_given, &mem, &powell, &single, &_limited)) { return NULL; } // ------------------------------------------------------------------------------------- // ------------------------------ VSPACE IS DESCRIBED VIA X ---------------------------- if (x_obj == NULL) { return NULL; } // FIXME get single value trough PyArray_IsPythonNumber(NPY_FLOAT), do not ask user for this value if (single == FALSE) { x_arr = PyArray_FROM_OTF(x_obj, NPY_DOUBLE, NPY_IN_ARRAY); } else { x_arr = PyArray_FROM_OTF(x_obj, NPY_FLOAT, NPY_IN_ARRAY); } if (x_arr == NULL) { return NULL; } int nd = PyArray_NDIM(x_arr); npy_intp *shape = PyArray_DIMS(x_arr); _problem_size = shape[0]; if (nd != 1) { fprintf(fichier, "We need 1D arrays\n"); return NULL; } if (single == FALSE) { x = (double *) PyArray_DATA(x_arr); } else { x = (float *) PyArray_DATA(x_arr); } if (x == NULL) { return NULL; } // ------------------------------------------------------------------------------------- // ------------------- SETTING OF LNSRCH, AUTOSTEP, NLCG AND VMLMB --------------------- // linesearch if (strcasecmp(linesrch_name, "quadratic") == 0) { lnsrch = opk_lnsrch_new_backtrack(sftol, samin); } else if (strcasecmp(linesrch_name, "Armijo") == 0) { lnsrch = opk_lnsrch_new_backtrack(sftol, 0.5); } else if (strcasecmp(linesrch_name, "cubic") == 0) { lnsrch = opk_lnsrch_new_csrch(sftol, sgtol, sxtol); } else if (strcasecmp(linesrch_name, "nonmonotone") == 0) { lnsrch = opk_lnsrch_new_nonmonotone(mem, 1e-4, 0.1, 0.9); } else { fprintf(fichier, "Unknown line search method\n"); lnsrch = NULL; return NULL; } // autstep if (strcasecmp(autostep_name, "ShannoPhua") == 0) { autostep = OPK_NLCG_SHANNO_PHUA; } /* else if (strcasecmp (autostep_name, "OrenSpedicato") == 0) {autostep = OPK_NLCG_OREN_SPEDICATO;} else if (strcasecmp (autostep_name, "BarzilaiBorwein") == 0) {autostep = OPK_NLCG_BARZILAI_BORWEIN;} */ else { fprintf(fichier, "Unknown line search method\n"); return NULL; } // nlcg method if (strcasecmp(nlcgmeth_name, "FletcherReeves") == 0) { _nlcg_method = OPK_NLCG_FLETCHER_REEVES; } else if (strcasecmp(nlcgmeth_name, "HestenesStiefel") == 0) { _nlcg_method = OPK_NLCG_HESTENES_STIEFEL; } else if (strcasecmp(nlcgmeth_name, "PolakRibierePolyak") == 0) { _nlcg_method = OPK_NLCG_POLAK_RIBIERE_POLYAK; } else if (strcasecmp(nlcgmeth_name, "Fletcher") == 0) { _nlcg_method = OPK_NLCG_FLETCHER; } else if (strcasecmp(nlcgmeth_name, "LiuStorey") == 0) { _nlcg_method = OPK_NLCG_LIU_STOREY; } else if (strcasecmp(nlcgmeth_name, "DaiYuan") == 0) { _nlcg_method = OPK_NLCG_DAI_YUAN; } else if (strcasecmp(nlcgmeth_name, "PerryShanno") == 0) { _nlcg_method = OPK_NLCG_PERRY_SHANNO; } else if (strcasecmp(nlcgmeth_name, "HagerZhang") == 0) { _nlcg_method = OPK_NLCG_HAGER_ZHANG; } else { ; fprintf(fichier, "Unknown line search method for nlcg\n"); return NULL; } // vmlmb method if (strcasecmp(vmlmbmeth_name, "blmvm") == 0) { _vmlmb_method = OPK_BLMVM; } else if (strcasecmp(vmlmbmeth_name, "vmlmb") == 0) { _vmlmb_method = OPK_VMLMB; } else if (strcasecmp(vmlmbmeth_name, "lbfgs") == 0) { _vmlmb_method = OPK_LBFGS; } else { fprintf(fichier, "Unknown line search method for vmlmb\n"); return NULL; } // Type of the variable if (single == TRUE) { _type = OPK_FLOAT; } else { _type = OPK_DOUBLE; } // ------------------------------------------------------------------------------------- // ----------------------------- BIT TO BIT COMPARISON --------------------------------- if (powell) { _nlcg_method |= OPK_NLCG_POWELL; } if (autostep != 0) { _nlcg_method |= autostep; } // ------------------------------------------------------------------------------------- // --------------------------------- CONSTRUCTION OF VSPACE ---------------------------- // _vspace only relies on the size of x _vspace = opk_new_simple_double_vector_space(_problem_size); if (_vspace == NULL) { fprintf(fichier, "Failed to allocate vector space\n"); return NULL; } // x is transformed into a vector of the new space vector vspace // Should be free instead of NULL _vx = opk_wrap_simple_double_vector(_vspace, x, NULL, x); if (_vx == NULL) { fprintf(fichier, "Failed to wrap vectors\n"); return NULL; } // ------------------------------------------------------------------------------------- // ----------------------------- CONSTRUCTION OF THE BOUNDS ---------------------------- // These are declared anyway because they are dropped later on (avoids a loop) if (single == TRUE) { bl = (float) (bl); bu = (float) (bu); } vbl = opk_wrap_simple_double_vector(_vspace, &bl, NULL, &bl); vbu = opk_wrap_simple_double_vector(_vspace, &bu, NULL, &bu); // If used asked for bounds: 1 = lower, 2 = upper, 3 = both if (bound_given == 1) { lower = opk_new_bound(_vspace, OPK_BOUND_VECTOR, vbl); if (lower == NULL) { fprintf(fichier, "Failed to wrap lower bounds\n"); return NULL; } upper = NULL; } else if (bound_given == 2) { upper = opk_new_bound(_vspace, OPK_BOUND_VECTOR, vbu); if (upper == NULL) { fprintf(fichier, "Failed to wrap upper bounds\n"); return NULL; } lower = NULL; } else if (bound_given == 3) { lower = opk_new_bound(_vspace, OPK_BOUND_VECTOR, vbl); upper = opk_new_bound(_vspace, OPK_BOUND_VECTOR, vbu); if (lower == NULL) { fprintf(fichier, "Failed to wrap lower bounds\n"); return NULL; } if (upper == NULL) { fprintf(fichier, "Failed to wrap upper bounds\n"); return NULL; } } else { lower = NULL; upper = NULL; } // ------------------------------------------------------------------------------------- // ------------------------------ CREATION OF THE OPTIMIZER ---------------------------- // The optimizer and task are created depending on the chosen algorithm. if (_limited == 0) { // VMLMB -------------------------------- if (strcasecmp(_algorithm_name, "vmlmb") == 0) { // Creation of the optimizer _vmlmb = opk_new_vmlmb_optimizer(_vspace, mem, _vmlmb_method, lower, upper, lnsrch); if (_vmlmb == NULL) { fprintf(fichier, "Failed to create VMLMB optimizer\n"); return NULL; } // Creation of _vgp _vgp = opk_vcreate(_vspace); if (_vgp == NULL) { fprintf(fichier, "Failed to create projected gradient vector\n"); return NULL; } // Options are set opk_get_vmlmb_options(&_options_vmlmb, _vmlmb); _options_vmlmb.gatol = grtol; _options_vmlmb.grtol = gatol; if (delta_given) { _options_vmlmb.delta = delta; } if (epsilon_given) { _options_vmlmb.epsilon = epsilon; } if (opk_set_vmlmb_options(_vmlmb, &_options_vmlmb) != OPK_SUCCESS) { fprintf(fichier, "Bad VMLMB options\n"); return NULL; } _task = opk_start_vmlmb (_vmlmb, _vx); } // NLCG --------------------------------- else if (strcasecmp(_algorithm_name, "nlcg") == 0) { _nlcg = opk_new_nlcg_optimizer(_vspace, _nlcg_method, lnsrch); if (_nlcg == NULL) { fprintf(fichier, "Failed to create NLCG optimizer\n"); return NULL; } opk_get_nlcg_options(&_options_nlcg, _nlcg); _options_nlcg.gatol = gatol; _options_nlcg.grtol = grtol; if (delta_given) { _options_nlcg.delta = delta; } if (epsilon_given) { _options_nlcg.epsilon = epsilon; } if (opk_set_nlcg_options(_nlcg, &_options_nlcg) != OPK_SUCCESS) { fprintf(fichier, "Bad NLCG options\n"); return NULL; } _task = opk_start_nlcg(_nlcg, _vx); } else { fprintf(fichier, "Bad algorithm\n"); return NULL; } } // Limited Memory --------------------------------- else { opk_algorithm_t limited_algorithm; if (strcasecmp(_algorithm_name, "nlcg") == 0) { limited_algorithm = OPK_ALGORITHM_NLCG; _limited_method = _nlcg_method; } else if (strcasecmp(_algorithm_name, "vmlmb") == 0) { limited_algorithm = OPK_ALGORITHM_VMLMB; _limited_method = _vmlmb_method; } else { fprintf(fichier, "Bad algorithm\n"); return NULL; } // optimizer if (bound_given == 1) { _limited_optimizer = opk_new_optimizer(limited_algorithm, _type, shape[0], mem, _limited_method, _type, &bl, OPK_BOUND_NONE, NULL, lnsrch); } else if (bound_given == 2) { _limited_optimizer = opk_new_optimizer(limited_algorithm, _type, shape[0], mem, _limited_method, OPK_BOUND_NONE, NULL, _type, &bu, lnsrch); } else if (bound_given == 3) { _limited_optimizer = opk_new_optimizer(limited_algorithm, _type, shape[0], mem, _limited_method, _type, &bl, _type, &bu, lnsrch); } else { _limited_optimizer = opk_new_optimizer(limited_algorithm, _type, shape[0], mem, _limited_method, OPK_BOUND_NONE, NULL, OPK_BOUND_NONE, NULL, lnsrch); } if (_limited_optimizer == NULL) { fprintf(fichier, "Failed to create limited optimizer\n"); return NULL; } _task = opk_start(_limited_optimizer, _type, shape[0], x); } // Free workspace OPK_DROP(vbl); OPK_DROP(vbu); fclose(fichier); // Return value is OPK_TASK_COMPUTE_FG if (_task == OPK_TASK_COMPUTE_FG) { task_py = Py_BuildValue("s", "OPK_TASK_COMPUTE_FG"); } else if (_task == OPK_TASK_START) { task_py = Py_BuildValue("s", "OPK_TASK_START"); } else if (_task == OPK_TASK_NEW_X) { task_py = Py_BuildValue("s", "OPK_TASK_NEW_X"); } else if (_task == OPK_TASK_FINAL_X) { task_py = Py_BuildValue("s", "OPK_TASK_FINAL_X"); } else if (_task == OPK_TASK_WARNING) { task_py = Py_BuildValue("s", "OPK_TASK_WARNING"); } else if (_task == OPK_TASK_ERROR) { task_py = Py_BuildValue("s", "OPK_TASK_ERROR"); } else { task_py = Py_BuildValue("s", "INITIALIZATION_ERROR"); } return task_py; }
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; }