예제 #1
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;
}
예제 #2
0
파일: vmlmb.c 프로젝트: emmt/OptimPack
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;
}
예제 #3
0
파일: vmlmn.c 프로젝트: advanpix/OptimPack
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;
}