/* ------------------------------------------------------------------------------------------ ------------------------------- 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_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; }