Math::NLopt

NLopt <https://github.com/stevengj/nlopt> is a

  library for nonlinear local and global optimization, for functions
  with and without gradient information. It is designed as a simple,
  unified interface and packaging of several free/open-source
  nonlinear optimization libraries.

Math::NLopt is a Perl binding to NLopt. It uses the Alien::NLopt module
to find or install a Perl local instance of the NLopt library.

This module provides an interface using native Perl arrays.

The main documentation for NLopt may be found at
<https://nlopt.readthedocs.io/>; this document focuses on the Perl
specific implementation, which is more Perlish than the C API (and is
very similar to the Python one).

  API

The Perl API uses an object, constructed by the "new" class method, to
maintain state. The optimization process is controlled by invoking
methods on the object.

*In general* results are returned directly from the methods; method
parameters are used primarily as input data for the methods (the
objective and constraint callbacks more closely follow the C API).

The Perl methods are named similarly to the C functions, e.g.

   nlopt_<method>( opt, ... );

becomes

  $opt->method( ... );

Where $opt is provided by the "new" class method.

As an example, the C API for starting the optimization process is

   nlopt_result nlopt_optimize(nlopt_opt opt, double *x, double *opt_f);

where x is used for both passing in the initial model parameters as well
as retrieving their final values. The final value of the optimization
function is stored in opt_f. A code specifying the success or failure of
the process is returned.

The Perl interface (similar to the Python and C++ versions) is

   \@final = $opt->optimize( \@initial_pars );
   $opt_f = $opt->last_optimum_value;
   $result_code = $opt->last_optimize_result;

The Perl API throws exceptions on failures, similar to the behavior of
the C++ and Python APIs. Where the C API returns an error code,
"Math::NLopt" normally returns the corresponding numeric result code on
success and throws an object in the corresponding exception class on
failure. These classes extend Math::NLopt::Exception; see it for more
information on retrieving messages from the objects.

  Constants

Math::NLopt defines constants for the optimization algorithms, result
codes, and utilities.

The algorithm constants have the same names as the NLopt constants, and
may be imported individually by name or en-masse with the ':algorithms'
tag:

  use Math::NLopt 'NLOPT_LD_MMA';
  use Math::NLopt ':algorithms';

Importing result codes is similar:

  use Math::NLopt 'NLOPT_FORCED_STOP';
  use Math::NLopt ':results';

  NLopt Results, Errors and Exceptions

   Result codes

While most methods (excluding "new" and "optimize") return a result code
of NLOPT_SUCCESS upon success, they will all throw on error.

Methods returning arrays or other values either return that value or
throw if the underlying operation fails.

   Exceptions

"Math::NLopt" will throw exceptions if the underlying NLopt library
detects an error.

Unfortunately, this behavior affects the results returned by "optimize",
which are lost when an exception is raised. Depending upon the error,
the results may actually be valid, so this is truly unfortunate.

There are a couple of ways to avoid the loss of information.

*   The simplest is to retrieve them via the "last_optimum_params"
    method.

*   Disable exceptions from NLopt result codes for "optimize" via the
    "set_exceptions_enabled" method. This is the approach used by the
    Python and C++ APIs.

    "optimize" will always return the last set of evaluated parameters.
    However, the caller will have to call "last_optimize_result" to
    determine how the optimization concluded, and whether the results
    are valid.

    Disabling exceptions only affects errors reported by "optimize".
    Other methods continue to throw exceptions, and exceptions thrown by
    user-provided objective, constraint, or pre-conditioner callbacks
    are always propagated.

  Callbacks

NLopt handles the optimization of the objective function, relying upon
user provided subroutines to calculate the objective function and
non-linear constraints (see below for the required calling signature).

The callback subroutines are called with a user-provided structure which
can be used to pass additional information to the callback (or the
subroutines can use closures).

   Exceptions thrown by Callback subroutines

Exceptions thrown by callback subroutines during processing by
"optimize" are caught so that they do not unwind through the NLopt C
stack. The optimization is halted with a forced stop (as if by
"force_stop") and the original exception is rethrown after NLopt has
returned. "last_optimize_result" will return "NLOPT_FORCED_STOP".

   Objective Functions

Objective functions callbacks are registered via either

  $opt->set_min_objective( \&func, ?$data );
  $opt->set_max_objective( \&func, ?$data );

where $data is an optional scalar, reference, or other Perl value passed
to the callback unchanged.

The objective function has the signature

  $value = sub ( \@params, \@gradient, $data ) { ... }

It returns the value of the optimization function for the passed set
parameters, @params.

if \@gradient is not "undef", it must be filled in by the objective
function.

$data is the value registered with the callback. It will be "undef" if
none was provided.

  Non-linear Constraints

   Scalar-valued Constraints

Scalar constraint callbacks are registered via either of

  $opt->add_equality_constraint( \&func, %options );
  $opt->add_inequality_constraint( \&func, %options );

%options accepts the following entries.

"tol" *scalar* [optional]
    The tolerance. Defaults to 0.

"data" [optional]
    A structure passed to the callback function.

The constraint function has the signature

  $value = sub ( \@params, \@gradient, $data ) { ... }

and must return exactly one numeric value, the value of the constraint
function for the passed set of parameters, @params.

   Vector-valued Constraints

Vector-valued callbacks are registered via either of

  $opt->add_equality_mconstraint( \&func, %options );
  $opt->add_inequality_mconstraint( \&func, %options );

%options accepts the following entries.

"m" *integer*
    The length of the vector.

"tol" *arrayref*
    An array of length "m" containing the tolerance for each component
    of the vector.

"data" [optional]
    an optional scalar, reference, or other Perl value passed to the
    callback unchanged.

One of "m" or "tol" must be provided. If "tol" is provided without "m",
its length is used for "m". If both are provided, the number of array
elements in "tol" must be equal to "m".

Vector valued constraints callbacks have the signature

  sub ( \@result, \@params, \@gradient, $data ) { ... }

The $m length vector of constraints should be stored in "\@result". If
"\@gradient" is not "undef", it is an $m by $n two-dimensional array
which should be filled by the callback.

The outer dimension indexes the $m constraint components, and the inner
dimension indexes the $n optimization parameters; in other words,
"$gradient->[$i][$j]" is the derivative of constraint $i with respect to
parameter $j.

$data is the optional structure passed to the callback.

   Preconditioned Objectives

These are registered via one of

  $opt->set_precond_min_objective( \&func, \&precond, ?$data);
  $opt->set_precond_max_objective( \&func, \&precond, ?$data);

"\&func" has the same signature as before (see "Objective Functions"),
and $data is as before.

The "\&precond" fallback has this signature:

   sub (\@x, \@v, \@vpre, $data) {...}

"\@x", "\@v", and "\@vpre" are arrays of length $n. "\@x" and "\@v" are
inputs. "\@vpre" must be filled in by the routine before it returns.

INSTALLATION

This is a Perl module distribution. It should be installed with whichever
tool you use to manage your installation of Perl, e.g. any of

  cpanm .
  cpan  .
  cpanp -i .

Consult http://www.cpan.org/modules/INSTALL.html for further instruction.
Should you wish to install this module manually, the procedure is

  perl Makefile.PL
  make
  make test
  make install

COPYRIGHT AND LICENSE

This software is Copyright (c) 2024 by Smithsonian Astrophysical
Observatory.

This is free software, licensed under:

  The GNU General Public License, Version 3, June 2007
