view liboctave/NPSOL.cc @ 255:98246fedc941

[project @ 1993-12-08 22:55:41 by jwe]
author jwe
date Wed, 08 Dec 1993 22:55:52 +0000
parents 780cbbc57b7c
children 6027a905fc06
line wrap: on
line source

// NPSOL.cc                                                -*- C++ -*-
/*

Copyright (C) 1992, 1993 John W. Eaton

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <math.h>

#ifndef NPSOL_MISSING

#include "NPSOL.h"
#include "f77-uscore.h"
#include "sun-utils.h"

extern "C"
{
  int F77_FCN (npoptn) (char *, long);

  int F77_FCN (npsol) (int *, int *, int *, int *, int *, int *,
		       double *, double *, double *,
		       int (*)(int*, int*, int*, int*, int*, double*,
			       double*, double*, int*),
		       int (*)(int*, int*, double*, double*, double*, int*),
		       int *, int *, int *, double *,
		       double *, double *, double *, double *,
		       double *, double *, int *, int *, double *,
		       int *); 
}

// XXX FIXME XXX -- would be nice to not have to have this global
// variable.
// Nonzero means an error occurred in the calculation of the objective
// function, and the user wants us to quit.
int npsol_objective_error = 0;

static objective_fcn user_phi;
static gradient_fcn user_grad;
static nonlinear_fcn user_g;
static jacobian_fcn user_jac;

int
npsol_objfun (int *mode, int *n, double *xx, double *objf,
	      double *objgrd, int *nstate) 
{
  int nn = *n;
  Vector tmp_x (nn);

  npsol_objective_error = 0;

  for (int i = 0; i < nn; i++)
    tmp_x.elem (i) = xx[i];

  if (*mode == 0 || *mode == 2)
    {
      double value = (*user_phi) (tmp_x);

      if (npsol_objective_error)
	{
	  *mode = -1;
	  return 0;
	}

#if defined (sun) && defined (__GNUC__)
      assign_double (objf, value);
#else
      *objf = value;
#endif
    }

  if ((*mode == 1 || *mode == 2) && user_grad != NULL)
    {
      Vector tmp_grad (nn);

      tmp_grad = (*user_grad) (tmp_x);

      if (tmp_grad.length () == 0)
	*mode = -1;
      else
	{
	  for (i = 0; i < nn; i++)
	    objgrd[i] = tmp_grad.elem (i);
	}
    }

  return 0;
}

int
npsol_confun (int *mode, int *ncnln, int *n, int *nrowj, int *needc,
	      double *xx, double *cons, double *cjac, int *nstate)
{
  int nn = *n, nncnln = *ncnln;
  Vector tmp_x (nn);
  Vector tmp_c (nncnln);

  for (int i = 0; i < nn; i++)
    tmp_x.elem (i) = xx[i];

  tmp_c = (*user_g) (tmp_x);

  if (tmp_c.length () == 0)
    {
      *mode = -1;
      return 0;
    }
  else
    {
      for (i = 0; i < nncnln; i++)
	cons[i] = tmp_c.elem (i);
    }

  if (user_jac != NULL)
    {
      Matrix tmp_jac (nncnln, nn);

      tmp_jac = (*user_jac) (tmp_x);

      if (tmp_jac.rows () == 0 || tmp_jac.columns () == 0)
	*mode = -1;
      else
	{
	  int ld = *nrowj;
	  for (int j = 0; j < nn; j++)
	    for (i = 0; i < nncnln; i++)
	      cjac[i+j*ld] = tmp_jac (i, j);
	}
    }

  return 0;
}

Vector
NPSOL::minimize (void)
{
  double objf;
  int inform;
  Vector lambda;
  return minimize (objf, inform, lambda);
}

Vector
NPSOL::minimize (double& objf)
{
  int inform;
  Vector lambda;
  return minimize (objf, inform, lambda);
}

Vector
NPSOL::minimize (double& objf, int& inform)
{
  Vector lambda;
  return minimize (objf, inform, lambda);
}

Vector
NPSOL::minimize (double& objf, int& inform, Vector& lambda)
{
  // Dimensions of various things.

  int n     = x.capacity ();
  int nclin = lc.size ();
  int ncnln = nlc.size ();
  int nrowa = 1 > nclin ? 1 : nclin;
  int nrowj = 1 > ncnln ? 1 : ncnln;
  int nrowr = n;

  // Informative stuff.

  int iter;
  int *istate = new int [n+nclin+ncnln];

  // User defined function stuff is defined above in the functions
  // npsol_confun() and npsol_objfun();

  // Constraint stuff.

  double dummy;
  double *pclin = &dummy;
  Matrix clin;
  if (nclin > 0)
    {
      clin = lc.constraint_matrix ();
      pclin  = clin.fortran_vec ();
    }

  double *clow = new double [n+nclin+ncnln];
  double *cup = new double [n+nclin+ncnln];

  if (bnds.size () > 0)
    {
      for (int i = 0; i < n; i++)
	{
	  clow[i] = bnds.lower_bound (i);
	  cup[i] = bnds.upper_bound (i);
	}
    }
  else
    {
      double huge = 1.0e30;
      for (int i = 0; i < n; i++)
	{
	  clow[i] = -huge;
	  cup[i] = huge;
	}
    }

  for (int i = 0; i < nclin; i++)
    {
      clow[i+n] = lc.lower_bound (i);
      cup[i+n] = lc.upper_bound (i);
    }

  for (i = 0; i < ncnln; i++)
    {
      clow[i+n+nclin] = nlc.lower_bound (i);
      cup[i+n+nclin] = nlc.upper_bound (i);
    }

  double *c = &dummy;
  double *cjac = &dummy;
  if (ncnln > 0)
    {
      c = new double [ncnln];
      cjac = new double [nrowj*n];
    }

  // Objective stuff.

  double *objgrd = new double [n];

  // Other stuff.

  double *r = new double [n*n];

  lambda.resize (n+nclin+ncnln);
  double *pclambda = lambda.fortran_vec ();

  // Decision variable stuff.

  double *px = x.fortran_vec ();

  // Workspace parameters.

  int lenw;
  int leniw = 3 * n + nclin + 2 * ncnln;
  if (nclin == 0 && ncnln == 0)
    lenw = 20*n;
  else if (ncnln == 0)
    lenw = 2*n*(10 + n) + 11*nclin;
  else
    lenw = 2*n*(n + 10) + nclin*(n + 11) + ncnln*(2*n + 21);

  int *iw = new int [leniw];
  double *w = new double [lenw];

  user_phi  = phi.objective_function ();
  user_grad = phi.gradient_function ();
  user_g    = nlc.function ();
  user_jac  = nlc.jacobian_function ();

  // Solve the damn thing.

  if (user_jac == NULL && user_grad == NULL)
    F77_FCN (npoptn) ("Derivative Level = 0", 20L);
  else if (user_jac == NULL && user_grad != NULL)
    F77_FCN (npoptn) ("Derivative Level = 1", 20L);
  else if (user_jac != NULL && user_grad == NULL)
    F77_FCN (npoptn) ("Derivative Level = 2", 20L);
  else if (user_jac != NULL && user_grad != NULL)
    F77_FCN (npoptn) ("Derivative Level = 3", 20L);

  int attempt = 0;
  while (attempt++ < 5)
    {

      F77_FCN (npsol) (&n, &nclin, &ncnln, &nrowa, &nrowj, &nrowr, pclin,
		       clow, cup, npsol_confun, npsol_objfun, &inform,
		       &iter, istate, c, cjac, pclambda, &objf, objgrd, r,
		       px, iw, &leniw, w, &lenw);

      if (inform == 6 || inform == 1)
	continue;
      else
	break;
    }

  // See how it went.

  return x;
}

Vector
NPSOL::minimize (const Vector& xnew)
{
  x = xnew;
  return minimize ();
}

Vector
NPSOL::minimize (const Vector& xnew, double& objf)
{
  x = xnew;
  return minimize (objf);
}

Vector
NPSOL::minimize (const Vector& xnew, double& objf, int& inform)
{
  x = xnew;
  return minimize (objf, inform);
}

Vector
NPSOL::minimize (const Vector& xnew, double& objf, int& inform, Vector& lambda)
{
  x = xnew;
  return minimize (objf, inform, lambda);
}

NPSOL&
NPSOL::option (char *s)
{
  long len = strlen (s);
  F77_FCN (npoptn) (s, len);
  return *this;
}

void
NPSOL::set_default_options (void)
{
  F77_FCN (npoptn) ("Nolist", 6L);
  F77_FCN (npoptn) ("Defaults", 8L);
  F77_FCN (npoptn) ("Print Level 0", 13L);
}

#endif /* NPSOL_MISSING */

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; page-delimiter: "^/\\*" ***
;;; End: ***
*/