Documentation for the naginterfaces Python Package

Package Summary

Python interfaces for the NAG Library Engine, which is the software implementation of NAG’s collection of several hundred mathematical and statistical routines serving a diverse range of application areas.

Subpackage Summary

Interfaces to the NAG Library are provided in the library subpackage.

The base.utils submodule contains a number of core utilities for working with the supplied Library interfaces. See the documentation for the base subpackage for more information.

Some utilities for interacting with the NAG Kusari licence-management system are in a kusari submodule.

Submodules must be imported separately:

>>> from naginterfaces.library import opt, roots

for instance, and module entities may be imported using, for example

>>> from naginterfaces.base.utils import NagException

For brevity, support entities appear with unqualified names in the documentation for the package. For example, the base.utils.Handle data type is referenced merely as Handle. In code these entities must still be imported from their host module using any of the regular python idioms, such as

>>> from naginterfaces.base.utils import Handle

Attributes

ENGINE_LIBDIRstr

The absolute path to the underlying directory housing the NAG library and its dependent binaries.

Algorithmic Contents

The package supplies all algorithmic functionality from the NAG Engine except:

  • there is only one ‘implementation details’ function supplied in the info (a00) Chapter;

  • the stat (g01) line-print functions plot_stem_leaf and plot_box_whisker are deemed redundant in Python;

  • the file (x04) and time (x05) Chapters are not required so are absent.

For detailed documentation on the algorithms provided by this package refer to the NAG Library document

https://www.nag.com/numeric/nl/nagdoc_30/flhtml/frontmatter/manconts.html

LAPACK functions are supplied as a single variant within a given installation of the package. An installation of the vendor math library version of naginterfaces only supplies the vendor-enabled variants of LAPACK functions, and conversely a self-contained naginterfaces only supplies the NAG variants of LAPACK functions.

Functions or submodules that are scheduled for withdrawal at some future release will issue a warning, class NagWithdrawalWarning, when called or imported, respectively. The documentation for a deprecated object also provides a note of the pending withdrawal. Both the warning and the documentation give advice on how to make a replacement.

Interface Features

In what follows we describe the calling conventions used by functions in the package. Because Python is dynamically typed there is naturally a great amount of flexibility in how the interfaces might be used. This makes an accurate description of the behaviour and allowed usage of the interfaces be quite extensive. Nevertheless, the interfaces are designed so that common-sense usage expectations should in most cases be met.

The package’s documentation uses a type-classification scheme that differs slightly from Python terminology. The discussion of types is divided into: ‘Intrinsic Types’ for built-in scalar numeric types, Booleans and also strings; and ‘Non-intrinsic Types’ for NAG-defined classes required for certain arguments. We use the term ‘container’ for sequence types (list, numpy.ndarray, …) excluding strings, including dict. ‘Array’ means any non-dict container, and ‘scalar’ is used to encompass any non-container type.

Output data is generally always returned on the left-hand side of function calls, apart from in those special cases (primarily, communication—see below) when it is modified in place on the right-hand side of the call.

When a function returns a tuple (i.e., when it has more than one return argument on the left-hand side), the returned entity is always a collections.namedtuple (with a class name reflecting the associated NAG function, for example Dim1FinWellReturnData). The field names in the namedtuple correspond to the names of the output arguments.

Optional keyword dummy arguments are used whenever a reasonable default value is known, or whenever an algorithm has modes of operation that can be triggered by the absence or presence of supplied data in the call.

Some routines allow certain output arguments to be suppressed or declined. In these cases the respective output entity is present in the return data from the routine, but is set to None.

Intrinsic Types

For maximum flexibility the interfaces in the package allow intrinsic-typed arguments to be typed using one of a number of synonyms or equivalent types.

Integer data is always permitted to be supplied as the native int.

In a number of cases, floating-point data may be supplied as an integer. Such values will be promoted internally to floats. Note that some very large integer values are not exactly representable as floating-point values. The NAG wrappers make no diagnosis of this, so it is the responsibility of the caller to be aware of this possibility.

For brevity of documentation the individual function signature annotations in the package refer to numeric types by category, with the following meanings:

str

Native bytes or str, NumPy types numpy.bytes_ or numpy.str_.

Input string data is treated in a case-insensitive manner by the NAG Library; that is, the following are considered equivalent

nag_fun('Spam', ...)
nag_fun('spaM', ...)

Therefore, in documented constraints for string input it is implicit that the constraint is independent of the string’s case.

complex64

NumPy type numpy.complex64.

complex

Native complex, NumPy type numpy.complex128.

float32

Native int;

ctypes.c_float;

NumPy types numpy.float32, numpy.int32 or numpy.int64.

float

Native float or int;

ctypes.c_double;

NumPy types numpy.float64, numpy.int32 or numpy.int64.

int

Native int;

If on Windows the ctypes types ctypes.c_long or ctypes.c_longlong, if not on Windows the ctypes types ctypes.c_int or ctypes.c_long;

NumPy types numpy.int32 or numpy.int64.

bool

Native bool, NumPy np.bool_.

Some of the intrinsic types have additional constraints enforced on them as follows:

str

Must be ASCII data. The package will raise NagValueError if this is not the case. Some str arguments have an expected string length. Data shorter than such a specified length will be blank padded on the right before being passed to the NAG Engine. Longer data will be truncated.

int

Must be in range for the underlying NAG Engine integer type. The package will raise NagOverflowError if an out-of-range int is supplied. The size of the NAG Engine integer is available for reference by calling the implementation-details function from the info submodule. Additionally, the base.utils submodule supplies two classes—EngineIntNumPyType and EngineIntCType—that can be used as integer data types to ensure compatibility with the NAG Engine integer.

The package will raise NagTypeError if an incorrectly-typed argument is supplied.

Non-intrinsic Types

Instances of a Handle class (which is supplied by the base.utils submodule) must be used for arguments in some routines. Generally an instance will be constructed by an initialization function for the suite of which the handle is a part.

In some NAG functions a ‘null Handle’ is permitted to be supplied on input, or may be returned on output. By ‘null Handle’ we mean a Handle instance having value attribute set to None. On input, a freshly-constructed Handle instance will suffice for such an argument.

It is prohibited to use the Python copy module to copy Handle instances. The package will raise NagAttributeError if this is attempted.

Input/Output

The base.utils submodule also supplies a class called FileObjManager that must be used with some NAG functions when I/O is being performed. Instances of the class help translate between Python file objects and NAG Engine I/O units.

Scalars

Scalars are always returned on the left-hand side of calls. This also applies in the signatures of callback functions.

Scalars returned from NAG functions use native Python types when one exists, else the NumPy type is used according to the type scheme above.

Arrays

Arrays not of Handle data can be passed as (subclasses of) numpy.ndarray.

Some arguments are permitted to be any ‘array-like’ container. The documentation for the numpy.array function defines this term in detail, but for simple purposes an ‘array-like’ container is an instance of numpy.ndarray or a (nested) sequence (for example, [[42, 43], [44, 45]] used to represent a 2 by 2 matrix). Additionally, NAG functions accept scalars being supplied where rank-1 arrays are expected. In such a case the scalar is promoted internally to a length-1 one-dimensional array. In the NAG documentation ‘array-like’ should be understood to include this special case.

When a NAG function will modify array data in place (e.g., in communication contexts, see below) numpy.ndarray (or subclass) is the only allowed container. Furthermore, automatic promotion of integer data to floating point will not be made for these arrays because doing so requires an array copy; that is, floating-point arrays that are to be modified in place must use a compatible floating-point data type.

The package will raise NagTypeError if an illegal container is supplied for an argument.

When a dummy argument has a documented expected shape, the corresponding actual argument must match this shape precisely. Oversized arrays are not permitted. The package will raise NagShapeError if an actual argument has an incorrect shape. The shape match restriction is relaxed slightly for zero-sized dummy arrays (having expected extent zero in one or more dimension), for which any zero-sized actual array argument is permitted irrespective of its precise shape.

On occasion an array element may need to be accessed by a NAG wrapper before a shape check can be performed for the array. In these situations an index validation will be made for the element. The package will raise NagIndexError when such a requested index is out of range.

The contents of containers of str or int data are subject to the same constraints as the corresponding scalars; i.e., being ASCII, or not overflowing the NAG Engine integer, respectively. The checking is omitted if the data is output only.

All multi-dimensional array arguments supplied on the right-hand side to a NAG function or returned from user-supplied callback functions must be contiguous in either the C or Fortran sense, or both. The package will raise NagTypeError if this is not the case. Most arrays will usually satisfy this requirement, but care must be taken when slicing numpy.ndarray data: for example, a ‘reversed’ two-dimensional array becomes discontiguous:

>>> import numpy as np
>>> is_discontig = lambda a: not (
...     a.flags.c_contiguous or a.flags.f_contiguous
... )
>>> z = np.array([[42, 43], [44, 45]])
>>> z_r = z[::-1, ::-1]
>>> is_discontig(z_r)
True

The NumPy utilities numpy.ascontiguousarray and numpy.asfortranarray can be used to convert to contiguous arrays in the desired sense:

>>> z_r_c = np.ascontiguousarray(z_r)
>>> is_discontig(z_r_c)
False
>>> z_r_f = np.asfortranarray(z_r)
>>> is_discontig(z_r_f)
False

If more than one multi-dimensional argument is to be supplied on the right-hand side of a function, these arguments must use a mutually consistent storage order in memory. The package will raise NagTypeError if this is not the case.

NumPy treats ‘spiked’ arrays (that is, with unit extent in all but one dimension, or with total size 1) as being contiguous in both the Fortran and C senses. If all multi-dimensional input arguments are spiked and hence dually contiguous in this manner, and there are no callbacks that return multi-dimensional arrays in the interface of the NAG function, then Fortran storage is assumed for efficiency in the NAG Engine.

In some interfaces an output array is semantically an updated copy of an input array: for example, when factorizing a matrix. This is usually apparent in the API description for the interface, where the input and output arrays will have the same name.

The return type for array data on the left-hand side of function calls is always as numpy.ndarray with a NumPy-type dtype. When such data is an updated copy of an input argument, subclasses of numpy.ndarray will be preserved in the output.

When an array is returned on the left-hand side of a call it will use the mutual storage order inferred from input arrays in the call, or NumPy’s default storage order (C contiguous) if there were no multi-dimensional input arrays.

A returned array that has an input equivalent will use the same dtype as that input equivalent. Otherwise the dtype will be the NumPy type for the array’s data-type category according to the type scheme above. Output-only str arrays use numpy.str_ dtype, and output-only int arrays use the NAG Engine integer data type.

Arguments representing index values (e.g. pivot indices defining a permutation matrix) always contain or are expected to contain (if supplied on input) elements relating to the mathematical entity that is being indexed, as base-1 (not base-0) values.

Some error messages in exceptions raised by the package mention ‘dimensions’ of arrays, which should also be understood to be indexed from 1.

Certain routines describe ‘increment‘ parameters for arrays (e.g., a parameter called incx). These are legacy features of the underlying linear algebra, useful for languages which lack native slicing of arrays. In this package such increments are suppressed from the user interface and set internally to 1.

Communication

Some NAG routines or suites of routines use arrays for self or suite communication. In argument lists in naginterfaces these arrays are merged together into a single dict, usually called comm.

The keys of a communication dict are the names of the arrays that were merged to form the dict. In cases where part of a communication array is documented as having some direct significance, the original array can be referenced using the corresponding key in the dict.

For a suite having a distinct initialization function the communication dict is returned on the initializer’s left-hand side.

Functions that modify a communication dict do so in place on the right-hand side of the call.

The package will raise NagTypeError if a communication dict dummy argument receives an actual argument of a different type. It will raise NagKeyError if the dict is not a valid communication structure for the context in which it is being used (for example, if it is being used with the wrong suite of routines).

Individual array arguments used in communication contexts are always modified in place on the right-hand side of calls. This includes in calls to reverse-communication functions. Arguments of the special Handle data type are also modified in this manner.

Consequently, communication arguments must be mutable, and in particular must be named entities (and not literals). It is the responsibility of the caller to ensure this: it is not possible for the NAG wrappers to detect when a literal or an expression has been supplied.

When a distinct initializer for the function does not exist communication arguments must be pre-declared before calling the NAG function. In particular a communication dict must be declared as an empty dict (i.e., comm = {}, say) which will signal to the NAG function that an initialization call (as opposed to a continuation call) is being made.

After initialization and as long as communication between NAG functions is still required, unless you are instructed otherwise you must not modify communication arguments directly in your own code, only by calls to associated NAG functions.

Arbitrary communication data can be passed to a callback function through its argument list if so desired via an optional data argument. When this facility is not needed the data argument can be omitted from the definition of the callback. The None-ness of the corresponding data argument supplied in the call to the NAG function is used to determine whether to invoke all callback functions with data supplied, or to omit this argument from all callback invocations. That is, in a call like

nag_fun(callback1, callback2, data=something)

in which callback1 wishes to use the none-None communication data something but callback2 does not need to, both callback1 and callback2 will be called by the NAG wrapper with something supplied as a data dummy argument. Both callbacks must therefore be defined to have such a dummy argument.

The example naginterfaces.library.examples.tsa.kalman_unscented_state_ex.main() demonstrates passing user-defined communication data to callback functions.

User-supplied Function Arguments

It is permitted to raise exceptions in callback functions if desired.

The package uses the following general calling conventions for user-supplied callbacks:

  • input scalars use native Python types when one exists, else the NumPy type is used according to the type scheme above;

  • output scalars are checked using the same rules as input scalars in wrappers (e.g., strings must be ASCII);

  • array input data is always supplied as numpy.ndarray with a NumPy-type dtype;

  • array integer data uses the same data type as the NAG Engine integer, and for efficiency output values are not individually checked for overflow: the callback is responsible for ensuring that the elements of output integer arrays are in range;

  • likewise, string data is passed as byte strings for efficiency;

  • output arrays returned from callback functions can be as any array-like container. Documented requirements for expected data type, expected shape, etc., still apply. The storage order used by these arrays must be the same as the overall storage order used by the enclosing NAG wrapper.

    When only spiked arrays have been supplied to the enclosing NAG function (see Arrays above) then you may specify the storage order to use for multi-dimensional arrays returned by callbacks via the outer spiked_sorder argument, which defaults to requesting C contiguous storage.

Some NAG Python functions have NagCallbackTerminateWarning warning exits. The callbacks associated with these exits permit you to request early termination of the algorithm if you raise the special exception UserCallbackTerminate. If you do this then the NAG Python function will interpret that exception in such a way that the appropriate corresponding NagCallbackTerminateWarning is raised for you after the NAG Engine has exited. If you use the Python warnings module to promote the warning to an exception then you can retrieve your original exception(s) via the exception’s cb_excs attribute.

The example naginterfaces.library.examples.opt.handle_solve_dfno_ex.main() demonstrates terminating early in a callback function.

Initialization of Input Data

Functions in this package may document that certain arguments are not referenced in some situations: for example, ‘under a cold start istate is not referenced’. Being referenced or not referenced is meant in the sense of the underlying algorithm in the NAG Library Engine. There are circumstances where the NAG Python wrapper may still copy the data, or type check it (if the type is str or int, say).

For arguments that are documented as sometimes not being referenced by the NAG Library Engine, we recommend always initializing the data to a valid Python value (such as 0 for int data, or blank for str).

Optional Algorithmic Parameters

Some NAG functions allow additional configurability via optional algorithmic parameters, to control aspects of the algorithm, methodology used, logic or output. Such a function will be associated with one or more option-handling utilities, which will be listed in the preamble of the function’s documentation. These option-handling utilities can be used to change or query the values of the main solver’s optional parameters. The parameters are usually communicated between the utilities and the main solver through a communication dict or Handle argument. Each optional parameter has an associated default value, so option setting is only necessary when a default is not suitable for your particular problem. The list of optional parameters recognized by a given solver is supplied in the solver’s documentation.

Please consult the individual documentation for your required option-handling utilities for usage information on interacting with optional parameters; some utilities allow optional parameters to be specified as a single string 'option_name = option_value' while some may have distinct utilities for setting only option names of a certain numeric type.

The example naginterfaces.library.examples.opt.handle_solve_dfls_ex.main() demonstrates setting optional parameters in a problem handle for solving an optimization problem.

Error Handling

Error and warning cases in the package are managed using subclasses of the core Python Exception and Warning classes. See the documentation of the base.utils submodule for more information—specifically the classes NagException and NagWarning, and their descendants and ancestors.

Documentation Structure

Each individual wrapper contains a docstring showing its API description.

The general structure of a function docstring is

(Short description.)

(Link to the document for the function in the NAG Library Manual.)

Parameters
----------
...

Returns
-------
...

Other Parameters
----------------
...

Raises
------
...

Warns
-----
...

Notes
-----
...

References
----------
...

See Also
--------
...

Each of the subsections is optional.

Within the Parameters and Returns sections, arguments are annotated in the following manner (square brackets denote text that may not be present in all circumstances, and ellipses denote a continued line for this document).

For data

arg-name : type-category[, communication object] ...
           ... [, [container-restriction, ] shape shape-tuple] ...
           ... [, optional][, modified in place]

with the type and container categories as covered above.

For procedures

proc-name : callable rtn-data = proc-name(proc-arg-name-list, ...
                                      ... proc-kwarg-name-list)
    (Short description.)

    Parameters
        arg-name : annotation
            ...

        ...

    Returns
        rtn-name : annotation
            ...

        ...

Annotation strings for wrapper arguments and callback arguments are identical apart from the ‘modification’ substring: for wrapper arguments modified in place obviously denotes that the argument will have been modified on exit from the wrapper; in user-supplied procedures the term used is modifiable in place to indicate when changes must be made directly to the dummy entity from the argument list in order for those changes to have any effect once the procedure exits.

When a function uses optional algorithmic parameters, these are documented in an Other Parameters section using the following format

opt-name : type-category
   [Default[ = def-value]]

   Description.

opt-name is documented as a string. The type-category may be any of the standard categories as covered previously, or it could be valueless. The latter indicates that the opt-name itself will act as a toggle. An example of this is 'Defaults', used by some functions to reset all optional parameters to their initial default values.

The default value for an optional parameter, which will be used by the solver unless you have explicitly set a new value using one of the option-handling utilities, is given in the Default line if it is meaningful to do so. When def-value is omitted this is because the optional parameter is valueless but the control aspect supplied by it is the default for the solver.

The symbol (epsilon) in an Other Parameters section denotes the machine precision (see precision()).

The Raises (respectively Warns) section in a function’s docstring lists error (resp. warning) cases (if any) that may be raised. The entries are limited specifically to algorithmic cases that the routine may diagnose. No attempt is made to document every possible Python exception that could occur. Each list is sorted by the corresponding error number or expression as used by the Library. In some text for exit cases a ‘<value>’ placeholder appears, which is used to indicate text that will be filled in at runtime by the NAG wrapper.

Notes gives details of any special considerations that may need to be made if porting Python calls over to calls to C functions in the NAG Library, and then covers expanded algorithmic details for the routine.

References lists any external publications that complement the text in the NAG document.

The See Also section is used to cross reference to example files that call the function.

Performance Tips

Setting up array data as a (homogenous) numpy.ndarray (or a subclass thereof) before calling a NAG function may be slightly more efficient than supplying an array-like container instead and having the NAG function make the conversion. Any performance loss when using the latter would be especially acute in a callback function, so the recommendation there would be to always return array data as an instance of numpy.ndarray.

For numpy.ndarray input where the NAG wrapper expects floating-point values, note that supplying such data as integer values requires a copy to be made of the array. Therefore supplying the data with a compatible floating-point dtype from the offset will be more efficient.

The NAG Engine operates in such a way that supplying multi-dimensional data in Fortran contiguous (column-major) storage order will always be more efficient than using C contiguous data. The storage order of a numpy.ndarray instance can be configured using the order argument in many of the NumPy array-creation routines. For dually contiguous spiked arrays (see the Arrays section above) setting the optional argument spiked_sorder to 'F' when this is present in a NAG routine’s interface (see the User-supplied Function Arguments section above) requests that Fortran storage order is to be used.

It may be more efficient to supply string data as byte strings, although this is likely to give only small gains since the data must still be checked for being ASCII.

Likewise, I/O from NAG routines should perform better through file objects opened in binary mode.

If convenient then supplying integer data using one of the NAG-provided EngineInt*Type data-type classes (EngineIntNumPyType or EngineIntCType) should prove more efficient, particularly when used instead of the unlimited-precision int from Python 3.

Thread Safety Considerations

The underlying NAG Engine is thread safe when accessed from this package unless explicitly stated otherwise in an entity’s documentation.

In routines which take Handle arguments, the internal data structures referenced by the handles may be freely read from and written to by the NAG Engine. As such, when calling a routine that has a handle argument in a threaded region each thread must have its own (deep) copy of the handle, either initialized directly on the thread or explicitly copied via a call to a relevant Library routine where one exists.

In the context of the purely-Python parts of the package, special care must be taken if using the data mechanism to pass communication data to callback functions—the data object you supply to the naginterfaces function you call is shared by all instances of your callback function.

Porting to other NAG Libraries

If you are prototyping in Python but developing production compiled code that uses the NAG Library there is usually a simple correspondence between a given Python function in this package and its compiled alternative. The correspondence is by the Python routine’s unqualified name.

For example, the unqualified name for optimizer nlp1_solve() is nlp1_solve. Performing a keyword search for nlp1_solve in the documentation for the secondary NAG product you are using should locate the corresponding routine(s).

In case of problems using the unqualified name, a secondary correspondence to try is by the unique five-letter short routine name that is given in the introductory section of the Python function’s documentation.

For example, the short name for optimizer nlp1_solve() is seen from the routine’s Python documentation to be e04uc. Performing a keyword search for e04uc in the documentation for the secondary NAG product you are using will locate the corresponding routine(s).

The NAG Technical Support Service will gladly assist in case of difficulties. See also section Technical Support.

NAG C Interfaces

In some cases there is no equivalent NAG C interface for a given NAG Python function. When an equivalent does exist there are also cases where the NAG C function uses a different algorithmic base. The Python function’s documentation will contain a note whenever these situations occur. The corresponding algorithm that uses the same base can still be accessed from C via the NAG FL Interface and associated C header files.

NAG Fortran Interfaces

Apart from the exceptions given in the Algorithmic Contents section above, all NAG Python functions have equivalents in the NAG FL Interfaces, each of which uses the same algorithmic base.

Migrating from Earlier Releases of the NAG Library for Python

The NAG Library for Python at Mark 26.0 and earlier supplied a package called nag4py, which was a set of Python interfaces to the NAG C Library.

For algorithmic functionality and usability, nag4py is superseded by the naginterfaces package.

The canonical algorithmic base supplied by naginterfaces significantly overlaps the NAG C Library in terms of numerics, thus in many cases when moving from nag4py to naginterfaces there should be a clear function-to-function upgrade path.

However, the interfaces to matching algorithms as supplied by naginterfaces compared to nag4py are likely to be noticeably different.

The best general advice on how to successfully migrate to naginterfaces is to identify the naginterfaces function (or functions) semantically most close to the functions you are using from nag4py, then carefully reconstruct the call sequence.

Given a ‘short’ nag4py function name (using the NAG C Library form, such as z99zzc), the corresponding naginterfaces function can be located by searching for the initial five-letter prefix (z99zz in this case) in the naginterfaces documentation.

No general guarantee can be given about equal performance or bitwise reproducibility of results across the two packages.

The NAG Technical Support Service will gladly assist in case of difficulties. See also section Technical Support.

Numbering Scheme

This package uses a modification of the well-known Semantic Versioning scheme, extended to a sequence of four digits (X.W.Y.Z) instead of the usual three.

The initial pair—X.W—denotes the algorithmic functionality available from the underlying NAG Library. With the exception of any listed unsupported Python interfaces described by the naginterfaces subpackages, all routines from Mark X.W of the NAG Library are available.

The penultimate and final digits—Y and Z—have the same meaning as with Semantic Versioning; that is, within the X.W release series Y tracks backwards-compatible functionality additions and Z tracks backwards-compatible bug fixes.

naginterfaces.quick_check()[source]

Sanity check for the package.

Checks availability of a licence, and correct loading and basic operation of the underlying compiled libraries.

Returns zero on success and non-zero on failure.

Subpackages