Esempio n. 1
0
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);
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;

  }
Esempio n. 4
0
/* ------------------------------------------------------------------------------------------
------------------------------- 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;
}
Esempio n. 5
0
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;
}