# Contents

Introduction

Getting started with ALGLIB

FAQ

AP library description

AMP library description

ALGLIB reference manual

# Introduction

### Sections

- ALGLIB license
- Documentation license
- Reference Manual and User Guide
- Acknowledgements

## ALGLIB license

ALGLIB is a free software which is distributed under a GPL license - version 2 or (at your option) any later version. A copy of the GNU General Public License is available at http://www.fsf.org/licensing/licenses

## Documentation license

This reference manual is licensed under BSD-like documentation license:

Copyright 1994-2009 Sergey Bochkanov, ALGLIB Project. All rights reserved.

Redistribution and use of this document (ALGLIB Reference Manual) with or without modification, are permitted provided that such redistributions will retain the above copyright notice, this condition and the following disclaimer as the first (or last) lines of this file.

THIS DOCUMENTATION IS PROVIDED BY THE ALGLIB PROJECT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ALGLIB PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

## Reference Manual and User Guide

ALGLIB Project provides two sources of information: ALGLIB Reference Manual (this document) and ALGLIB User Guide.

ALGLIB Reference Manual contains full description of all publicly accessible ALGLIB units accompanied with examples. Reference Manual is focused on the source code: it documents units, functions, structures and so on. If you want to know what unit `YYY` can do or what subroutines unit `ZZZ` contains Reference Manual is a place to go. Free software needs free documentation - that's why ALGLIB Reference Manual is licensed under BSD-like documentation license.

Additionally to the Reference Manual we provide you User Guide. User Guide is focused on more general questions: how fast ALGLIB is? how reliable it is? what are the strong and weak sides of the algorithms used? We aim to make ALGLIB User Guide an important source of information both about ALGLIB and numerical analysis algorithms in general. We want it to be a book about algorithms, not just software documentation. And we want it to be unique - that's why ALGLIB User Guide is distributed under less-permissive personal-use-only license.

## Acknowledgements

ALGLIB was not possible without the contribution of next open source projects:

- LAPACK
- Cephes
- GNU MP
- MPFR

# Getting started with ALGLIB

### Sections

- Compiling ALGLIB
- Testing ALGLIB
- Executing examples

## Compiling ALGLIB

ALGLIB has a script-based compilation system. 'Script-based' means that you don't have to use `make` to compile ALGLIB. ALGLIB distribution contains Bash scripts and BAT-files (for Windows users) which will compile and test ALGLIB for you. Each script (`build`/`check`/...) is provided in two identical versions: as a Bash script and as a Windows batch file. The only difference is a set of compilers script supports.

### Selecting/configuring your compiler

If you are *nix user, your environment is ready for the ALGLIB compilation. If you are Windows user, make sure that your compiler is in your PATH. MSVC users have to execute `vcvars32.bat`, `vcvarsx86_amd64.bat` or `vcvarsx86_ia64.bat` (depending on the hardware they use) in a shell window. These scripts are located in the MS SDK or MS Visual Studio directories.

### Installing precompiled GMP/MPFR

Multiple precision version of ALGLIB rely on GMP/MPFR for numerical calculations. It needs following static libraries copied in the `./mpfr` subdirectory of the ALGLIB root: `mpn`, `gmp`, `mpfr`. If you are *nix user, you must compile/copy GMP/MPFR static libraries yourself. If you are Windows user, you can use precompiled static libraries (they are installed by executing `precompiled_mpfr.bat`

### Compiling ALGLIB

To compile ALGLIB you just need to `cd` into ALGLIB directory and to execute compilation script `./build` (or `build.bat` for Windows users). You must specify compiler name and you can specify additional compiler parameters. Multiple parameters must be enclosed in double quotes.

`./build` | returns full list of compilers supported
`./build gcc` | compilation using GCC
`build.bat msvc` | compilation using MSVC
`./build gcc -m32` | one additonal parameter, no quotes
`./build gcc "-m32 -O3"` | multiple parameters in double quotes

Successful compilation will be completely silent. Compiler messages will be redirected to the `log.txt` in the ALGLIB root directory. In the case of the error you will get short message, but the most detailed info will be in a log file. After compilation is done, header files, `libmpalglib` static library and GMP/MPFR static libraries will be copied to the `out` folder of the ALGLIB root directory. ALGLIB is ready to use!

## Testing ALGLIB

After ALGLIB compilation it can be tested:

`check.bat` | short help
`check.bat msvc all` | all the library is tested
`check.bat msvc all_silent` | silent mode, only errors are echo'ed
`./check gcc fft` | `fft.cpp` is tested
`./check gcc fft "-m32 -O3"` | custom parameters are passed

## Executing examples

Some units are accompanied by examples which can be executed by you. Example sources are stored in `./examples` directory. They can be modified - feel free to experiment with them.

`example.bat list autogk` | list examples for `autogk.cpp` unit
`example.bat view autogk_smooth` | view example source
`./example gcc autogk_smooth` | execute example
`./example gcc autogk_smooth "-m32 -O3"` | custom parameters are passed

# FAQ

### Sections

- What is the blank file `stdafx.h` here for?
- Why are round brackets used when addressing arrays, not square brackets?
- What is the AMP library?
- What is the AP library?
- Why do some algorithms (for instance, optimization methods) use reverse communication instead of function pointers, delegates and other means of my programming language?
- What is ALGLIB aimed at?
- What is the difference between ALGLIB and other similar projects?
- What is AlgoPascal?

## What is the blank file `stdafx.h` here for?

MSVC and some other compilers require the `#include <stdafx.h>` directive in the program code to manage precompiled headers, and create the stfafx.h file when generating a new project. However, some compilers (e.g. BCB) use other tools to manage precompiled headers. In this case the `#include <stdafx.h>` directive as such doesn't hinder their operation, however if the file with this name is absent, a compilation error occurs. The blank file called `stfafx.h` is created to avoid this error. If your development environment already created the file, leave it unchanged.

## Why are round brackets used when addressing arrays, not square brackets?

Imagine you are addressing the a matrix element in the common notation: `a[x][y]` instead of `a(x,y)`. Actually there are two index operators called here instead of one. The first is indexing of a matrix by `x`, that returns a reference to a temporary structure that describes the matrix row. The second is indexing that temporary structure by `y`, which returns the reference to the needed element. Addressing through overloading the round brackets is much more effective, as no temporary structures are required.

## What is the AMP library?

The AMP library (ALGLIB Multiple Precision) is an object oriented interface for the MPFR library, which is used by the ALGLIB programs.

## What is the AP library?

AP library is a generic name for a set of libraries in several programming languages performing low-level tasks depending on specific programming languages. The AP library carries out tasks such as working with dynamic one- and multidimensional arrays in languages which do not support this data type, contains implementation of basic linear algebra algorithms, etc. The library is distributed as source codes under GPL 2+ license (GPL 2 or later). The library is attached to the ALGLIB package.

## Why do some algorithms (for instance, optimization methods) use reverse communication instead of function pointers, delegates and other means of my programming language?

Optimization, integration and other similar methods are united by one common trait. They need to have a way of calculating the meaning of a function defined by the user at a point defined by the method.

The most convenient way of solving this problem is transferring a function pointer into the module. However bear in mind that ALGLIB package is written using pseudocode that is automatically translated into different programming languages. While each language has its own function pointer analog that is often different from other languages. When the ALGLIB pseudocode was developed, at some point is became clear that adding function pointers in it will be very complex as this feature is implemented differently in every language. This is why reverse communication was chosen as a different kind of solution.

## What is ALGLIB aimed at?

It is aimed at creating a convenient and efficient multilingual scientific software library.

## What is the difference between ALGLIB and other similar projects?

The ALGLIB package:

- is a multilingual project. The main feature of the project is that each algorithm is represented by programs in several languages and the language list is the same for every algorithm. This is the main advantage of the site before other similar collections - one algorithm, several languages, identical functionality in each language.
- is focused on numerical analysis. There are some other directions in the project but numerical analysis is a priority.
- is easy to use. To use the ALGLIB package you don't need to learn an unknown programming language, attach additional external libraries or work with an inconvenient interface to a code written in another programming language.

## What is AlgoPascal?

AlgoPascal is a programming language, designed particularly for this project. The programs, written in this language, are processed by an automatic translator and translated into other programming languages. Almost all ALGLIB source is produced by the AlgoPascal translator.

# AP library description

### Sections

- Introduction
- Conditionals
- Constants
- Functions
- `ap::ap_error` class
- Array classes: basic concepts
- `ap::template_1d_array` class
- `ap::template_2d_array` class
- Basic subroutines of linear algebra
- `ap::complex` class

## Introduction

The document describes a C++ version of the AP library. The AP library for C++ contains a basic set of mathematical functions and classes needed to compile ALGLIB package. The library includes the only module `ap.cpp`.

## Conditionals

AP_ASSERT
This symbol enables checking of the array boundaries. If it is set by the "define" directive, then at each addressing to the dynamic array elements, the transferred index is verified for its correctness. In case of error the `ap::ap_error` exception is thrown. Checking the array boundaries makes the program more reliable, but slows down the program operation.

NO_AP_ASSERT
This symbol disables checking of the array boundaries. If it is set by the "define" directive, then the index being outside the array boundaries is not checked when the dynamic array elements are addressed.

## Constants

ap::machineepsilon
The constant represents the accuracy of machine operations times some small number r>1.

ap::maxrealnumber
The constant represents the highest value of the positive real number, which could be represented on this machine. The constant may be taken "oversized", that is real boundary can be even higher.

ap::minrealnumber
The constant represents the lowest value of positive real number, which could be represented on this machine. The constant may be taken "oversized", that is real boundary can be even lower.

## Functions

int ap::sign(double x)
Returns:
+1, if X>0
-1, if X<0
0, if X=0

double ap::randomreal()
Returns a random real number from half-interval [0,1).

int ap::randominteger(int maxv)
Returns a random integer between 0 and maxv-1.

double ap::round(double x)
Returns the nearest integer to x. If x is right in the middle between two integers, then the function result depends on the implementation.

double ap::trunc(double x)
Truncates the fractional part of x.
trunc(1.3) = 1
trunc(-1.3)= -1

double ap::pi()
Returns the constant π

double ap::sqr(double x)
Returns x2.

double ap::maxreal(double m1, double m2)
Returns the maximum of two real numbers.

double ap::minreal(double m1, double m2)
Returns the minimum of two real numbers.

int ap::maxint(int m1, int m2)
Returns the maximum of two integers.

int ap::minint(int m1, int m2)
Returns the minimum of two integers.

## `ap::ap_error` class

This is a class of exception which is thrown when different errors occur in the AP library, for example - if the array index is found incorrect when the array boundaries check is enabled. Class contains one member - `msg` field which may contain additional information in textual form.

## Array classes: basic concepts

First we will discuss general principles of working with array classes, then describe the classes and their methods.

Classes of the standard library allow operations with matrixes and vectors (one-dimensional and two-dimensional arrays) of variable size and with variable numeration of elements, that is, the array numeration can start at any number, end at any number and change dynamically. Because the array classes are templates, the arrays of the same dimension have the same set of member functions. And as the member functions of arrays with different dimensions differ only by the number of arguments, there is little difference between two-dimensional and one-dimenstional arrays.

Working with an array starts with the array creation. You should distinguish the creation of array class instance and the memory allocation for the array. When creating the class instance, you can use constructor without any parameters, that creates an empty array without any elements, or you can use copy and assignment constructors that copy one array into another. In case the array is created by the default constructor, it contains no elements and an attempt to address them may cause the program failure. If, during the copy operation, the source array has no memory allocated for the array elements, destination array will contain no elements either. If the source array has memory allocated for its elements, destination array will allocate the same amount of memory and copy the elements there. That is, the copy operation yields into two independent arrays with indentical contents.

After an empty array has been created, you should allocate the memory for its elements, using the `setlength` method. The content of the created array elements is not defined. If the `setlength` method is called for the array with already allocated memory, then, after changing its parameters, the newly allocated elements also become undefined and the old content is destroyed.

To address the array elements, an overloaded `operator()` is used. That is, the code addressing the element of array `a` with indexes `a(i,j,k)` will look like `a(i,j,k)`. Below is given an example of factorial array calculation, illustrating the work with arrays.

    integer_1d_array factarr(int n)
    {
        integer_1d_array result;
        result.setbounds(1,n);
        result(1) = 1;
        for(int i=2; i<=n; i++)
            result(i) = result(i-1)*i;
        return result;
    }

## `ap::template_1d_array` class

This class is a template of dynamical one-dimensional array with variable upper and lower boundaries. Based on this class, the following classes are constructed:

    typedef template_1d_array<int>     integer_1d_array;
    typedef template_1d_array<double>  real_1d_array;
    typedef template_1d_array<bool>    boolean_1d_array;
    typedef template_1d_array<complex> complex_1d_array;

### member functions

template_1d_array()
Constructor. Creates an empty array.

~template_1d_array()
Destructor. Frees memory, which had been allocated for the array.

template_1d_array(const template_1d_array &rhs)
Copy constructor. Allocates the separate storage and copies source array content there.

const template_1d_array& operator=(const template_1d_array &rhs)
Assignment constructor. Deletes destination array content, frees allocated memory, then allocates a separate storage and copies source array content there.

T& operator()(int i)
Addressing the i-th array element.

void setbounds(int iLow, int iHigh)
Memory allocation for the array. Deletes the array content, frees allocated memory, then allocates a separate storage for iHigh-iLow+1 elements.
The elements numeration in the new array starts from `iLow` and ends at `iHigh`. The content of the new array is not defined.

void setlength(int iLen)
Memory allocation for the array. Deletes the array content, frees allocated memory, then allocates a separate storage for `iLen` elements.
The elements numeration in the new array starts from zero. The content of the new array is not defined.

void setcontent(int iLow, int iHigh, const T *pContent)
The method is similar to the `setbounds()` method, but after allocating a memory for a destination array it copies the content of `pContent[]` there.

T* getcontent()
const T* getcontent() const
Returns pointer to the array. The data pointed by the returned pointer can be changed, and the array content will be changed as well.

int getlowbound()
int gethighbound()
Get lower and upper boundaries.

raw_vector<T> getvector(int iStart, int iEnd)
The method is used by the basic subroutines of linear algebra to get access to the internal memory of the array. The method returns an object, holding the pointer to a vector part (starting from the element with `iStart` index value and finishing with `iEnd` index value). If iEnd<iStart, then an empty vector is considered to be set.

const_raw_vector<T> getvector(int iStart, int iEnd) const
The method is used by the basic subroutines of linear algebra to get access to the internal memory of the array in the read only mode. The method returns an object, holding the pointer to a vector part (starting from the element with `iStart` index value and finishing with `iEnd` index value). If iEnd<iStart, then an empty vector is considered to be set.

## `ap::template_2d_array` class

This class is a template of dynamical two-dimensional array with variable upper and lower boundaries. Based on this class, the following classes are constructed:

    typedef template_2d_array<int>     integer_2d_array;
    typedef template_2d_array<double>  real_2d_array;
    typedef template_2d_array<bool>    boolean_2d_array;
    typedef template_2d_array<complex> complex_2d_array;

### Class members

template_2d_array()
Constructor. Creates an empty array.

~template_2d_array()
Destructor. Frees memory, which had been allocated for the array.

template_2d_array(const template_2d_array &rhs)
Copy constructor. Allocates the separate storage and copies source array content there.

const template_2d_array& operator=(const template_2d_array &rhs)
Assignment constructor. Deletes destination array content, frees allocated memory, then allocates a separate storage and copies source array content there.

T& operator()(int i1, int i2)
const T& operator()(int i1, int i2) const
Array element access.

void setbounds(int iLow1, int iHigh1, int iLow2, int iHigh2)
Memory allocation for the array . Deletes the array content, frees allocated memory, then allocates a separate storage for (iHigh1-iLow1+1)*(iHigh2-iLow2+1) elements.
The elements numeration in the new array starts from `iLow1` and finishes at `iHigh1` for the first dimension, and similarly for the second dimension.
The content of the new array is not defined.

void setlength(int iLen1, int iLen2)
Same as `setbounds`. but make zero-based array allocation.

void setcontent(int iLow1, int iHigh1, int iLow2, int iHigh2, const T *pContent)
The method is similar to the setbounds() method, but after allocating a memory for a destination array it copies the content of pContent[] there.
The pContent array contains two-dimensional array, written in line, that is, the first element is [iLow1, iLow2], then goes [iLow1, iLow2+1], and so on.

int getlowbound(int iBoundNum)
int gethighbound(int iBoundNum)
Get lower and upper boundaries of one-dimensional array with number iBoundNum.

raw_vector getcolumn(int iColumn, int iRowStart, int iRowEnd)
const_raw_vector getcolumn(int iColumn, int iRowStart, int iRowEnd) const
The methods are used by the basic subroutines of linear algebra to get access to the internal memory of the array. The methods return the object holding the pointer to the part of column iColumn (starting from the line iRowStart and finishing with the line iRowEnd).
The iColumn parameter must be the valid column number (that is be within the boundaries of the array). If iRowEnd<iRowStart, then an empty column is considered to be set.

raw_vector getrow(int iRow, int iColumnStart, int iColumnEnd)
const_raw_vector getrow(int iRow, int iColumnStart, int iColumnEnd) const
The methods are used by the basic subroutines of linear algebra to get access to the internal memory of the array. The methods return the object holding the pointer to the part of line iRow (starting from the column iColumnStart and finishing with the column iColumnEnd).
The iRow parameter must be the valid line number (that is be within the boundaries of the array). If iColumnEnd<iColumnStart, then an empty line is considered to be set.

int getstride() const
Returns stride (in bytes), i.e. span between first elements of adjacent rows.

## Basic subroutines of linear algebra

Basic subroutines of linear algebra included into the AP library are close by their functions to the Level 1 BLAS, allowing to perform the simplest operations with vectors and with the matrix lines and columns.

### General and slow interface

Subroutines should be used in the following way. First you need to get an object of the `raw_vector` type or `const_raw_vector` type, pointing to the part of the matrix or array being processed using the methods `getcolumn`/`getrow` (for the matrix), or `getvector` (for the array). The object holds the pointer for the line (or column) start, the number of elements in the processed line (column), and the interval between the two adjacent elements. When using a standard scheme for matrixes storage in the memory (that is, by lines), the interval between the elements of one line equals 1, and the interval between the adjacent elements of one column equals the number of columns. The received object is transferred as argument to the corresponding subroutine, which performs operations on the matrix part pointed by the internal object pointer.

Below is given the list of basic subroutines of linear algebra, available in the AP library.

template<class T> T vdotproduct(const_raw_vector<T> v1, const_raw_vector<T> v2)
The subroutine calculates the scalar product of transferred vectors.

template<class T> void vmove(raw_vector<T> vdst, const_raw_vector<T> vsrc)
template<class T> void vmoveneg(raw_vector<T> vdst, const_raw_vector<T> vsrc)
template<class T, class T2> void vmove(raw_vector<T> vdst, const_raw_vector<T> vsrc, T2 alpha)
This subroutine set is used to copy one vector content to another vector using different methods: simple copy, copy multiplied by -1, copy multiplied by a number.

template<class T> void vadd(raw_vector<T> vdst, const_raw_vector<T> vsrc)
template<class T, class T2> void vadd(raw_vector<T> vdst, const_raw_vector<T> vsrc, T2 alpha)
This subroutine set is used to add one vector to another using different methods: simple addition or addition multiplied by a number.

template<class T> void vsub(raw_vector<T> vdst, const_raw_vector<T> vsrc)
template<class T, class T2> void vsub(raw_vector<T> vdst, const_raw_vector<T> vsrc, T2 alpha)
This subroutine set is used to subtract one vector from another using different methods: simple subtraction or subtraction multiplied by a number.

template<class T, class T2> void vmul(raw_vector<T> vdst, T2 alpha)
Multiplies vector by a number and stores the result in the same place.

### Alternative syntax (faster)

If both operands are vectors/rows with interval between the elements equals 1 and length equals N, alternative syntax can be used.

template<class T> T vdotproduct(const T *v1, const T *v2, int N)
template<class T> void vmove(T *vdst, const T *vsrc, int N)
template<class T> void vmoveneg(T *vdst, const T *vsrc, int N)
template<class T, class T2> void vmove(T *vdst, const T *vsrc, int N, T2 alpha)
template<class T> void vadd(T *vdst, const T *vsrc, int N)
template<class T, class T2> void vadd(T *vdst, const T *vsrc, int N, T2 alpha)
template<class T> void vsub(T *vdst, const T *vsrc, int N)
template<class T, class T2> void vsub(T *vdst, const T *vsrc, int N, T2 alpha)
template<class T, class T2> void vmul(T *vdst, int N, T2 alpha)

## `ap::complex` class

AP library includes the `ap::complex` class that allows operations with compex numbers. Access to real and imaginary parts of complex number is implemented through the public fields `x` and `y`. Arithmetical operations are supported, the same as with embedded data types, by overloading of operations: addition, subtraction, multiplication and division. Addition, subtraction and multiplication are performed by a usual way (i.e., according to their definition which can be found in any textdook in algebra), division is performed using so called "safe" algorithm that could never cause overflow when calculating intermediate results. The library also includes several functions performing elementary operations with complex numbers.

const double abscomplex(const ap::complex &z)
Returns the modulus of complex number z. It should be noted that the modulus calculation is performed using so called "safe" algorithm, that could never cause overflow when calculating intermediate results.

const ap::complex conj(const ap::complex &z)
Returns complex conjugate of z.

const ap::complex csqr(const ap::complex &z)
Returns the square of z.

# AMP library description

### Sections

- Introduction
- AMP basics
- Exception classes
- `amp::mpfr_record` and `amp::mpfr_storage` classes
- `amp::ampf` class
- Vectors, matrices and basic linear algebra operations
- `amp::campf` class

## Introduction

The AMP library (ALGLIB Multiple Precision) is an object oriented interface for the MPFR library. This interface was created as part of the ALGLIB project. In order to illustrate the reason why it was necessary to create yet another interface for MPFR, we should first give a brief introduction to the ALGLIB project.

The goal of the project is to create a numerical analysis library which provides programs in different programming languages for each algorithm. This goal is attained by using automatic translation. Algorithms are stored as a pseudocode which can then be translated into the required programming language. Pseudocode syntax allows automatic translation into the most popular programming languages (e.g. C++, C#, Pascal etc.). It should be noted that, in a number of cases, programs in pseudocode can be modified to use multiple precision arithmetic. For this purpose, the AMP library is used as an interface for MPFR substituting standard double precision data type.

Programs using AMP were originally implemented to work with a 64-bit accuracy. This fact has an impact on a library design. Because of this, the following features had appeared: compile time precision definition (in AMP accuracy is given by using the template class parameterization) and prohibition to operate with numbers of different precisions (e.g. addition of 256 bit and 512 bit numbers). These restrictions are necessary in order to use the library within the ALGLIB project.

It should be noted that although AMP was designed especially for the ALGLIB project, it could be useful as just an MPFR interface. Particularly, automatic garbage collection could be useful for a number of applications. It is this part of functionality that we are going to develop, because the ALGLIB part has already been developed accurately enough and doesn't need any extension.

## AMP basics

Real numbers. MPFR (and, therefore, AMP) is almost compliant with IEE-754 which describes real number arithmetic implementation requirements. The following features are available: signed zeros, finite numbers, positive and negative infinites, NANs. Denormalized numbers are not supported.

Operations and rounding. MPFR supports four types of rounding: round towards plus infinity, round towards minus infinity, round to zero and round to the nearest representable value. AMP always uses the last one. Thus, all the real number operations are performed by using exact rounding. Special values (infinites or NaNs) appearing during the calculation don't cause exception generation and the calculation is continued under normal conditions. Operations with infinites and signed zeros are performed according to the rules of limits.

Precision. Real number precision is a number of bits in a floating-point mantissa, including the high-order one (non-zero bit). For example, if the precision of a given number is equal to 53, this number is of a standard `double` type. The AMP library allows to set any precision no less than 32 (which represents the `signed long` type) including numbers which are not powers of two. The restriction was added due to compatibility reasons: a number of mathematical programs suppose that we can set any integer value to the real variable without any loss of accuracy.

Compile time precision definition. The main feature of the AMP library is that class performing multiple precision real numbers operations is a template class with one parameter specifying precision of a stored value. Hence, the precision to perform the calculation with is known at the compile time (on template specialization) and could not be changed in run-time. This restriction was introduced knowingly. The reason is that the AMP library was designed to be used mainly within the ALGLIB project. In that case, the AMP library is used by the automatically translated programs. Automatically generated codes cannot work with dynamic precision real numbers due to the number of problems. For example, we can't say what precision ought to be used when some elements of the matrix have 128 bit precision and some have 256 bit. That's the reason why this restriction was introduced.

Mixed precision operands. There are several floating point types in C++: `float`, `double`, `long double`. At that, if operands have a different precision, it is usually performed by automatic casting from less to finer precision (e.g. sum of `float` and `double` is `double`). The AMP library does not allow automatic casting of operands with different precision. For example, the sum of `amp::ampf<128>` and `amp::ampf<144>` will cause compilation errors because it is required to cast operand types. It is partly defined by C++ restrictions (which could be overcome), and partly by the developer's conviction that in numerical analysis such functionality is very seldom required.

Garbage collection. Since in MPFR the memory for real numbers is allocated dynamically, real number initialization takes a great deal of time comparatively. In order to increase performance, the AMP library doesn't free used memory, but puts needless variables into the list. When it is necessary to create a new real number, it is taken from the list.

No multithreading. The AMP library doesn't support multithreading. The library can work in a multithreaded environment, but it can't be used by two or more threads simultaneously.

## Exception classes

The AMP library includes the following exception classes:

1. `amp::incorrectPrecision` - generated when the real number of an invalid precision is initialized (less than 32 or more than MPFR library limitations)
2. `amp::invalidConversion` - generated when the real number to be rounded using `trunc`/`round`/`ceil`/`floor` doesn't fit in the `signed long` type
3. `amp::internalError` - generated when an internal AMP library error occurs (it should not happen under normal conditions)

## `amp::mpfr_record` and `amp::mpfr_storage` classes

These classes are service classes. Although these classes are available to the programmer, he shouldn't use them, because they aren't intended to be used outside the AMP library.

## `amp::ampf` class

### Key Concepts

`amp::ampf class` is a template class incapsulating real numbers in MPFR library format. Class implements memory allocation, memory release and garbage collection. Arithmetic operations are overloaded. In most cases, code using this class is almost the same as code working with real numbers.

### amp::ampf members

        template<unsigned int Precision>
        class ampf
        {
        public:
            ~ampf();

            ampf ();
            ampf (long double v);
            ampf (double v);
            ampf (float v);
            ampf (signed long v);
            ampf (unsigned long v);
            ampf (signed int v);
            ampf (unsigned int v);
            ampf (signed short v);
            ampf (unsigned short v);
            ampf (signed char v);
            ampf (unsigned char v);
            ampf (const std::string &s);
            ampf (const char *s);

            ampf(const ampf& r);
            template<unsigned int Precision2>
            ampf(const ampf<Precision2>& r);

            ampf& operator= (long double v);
            ampf& operator= (double v);
            ampf& operator= (float v);
            ampf& operator= (signed long v);
            ampf& operator= (unsigned long v);
            ampf& operator= (signed int v);
            ampf& operator= (unsigned int v);
            ampf& operator= (signed short v);
            ampf& operator= (unsigned short v);
            ampf& operator= (signed char v);
            ampf& operator= (unsigned char v);
            ampf& operator= (const char *s);
            ampf& operator= (const std::string &s);
            ampf& operator= (const ampf& r);
            template<unsigned int Precision2>
            ampf& operator= (const ampf<Precision2>& r);

            template<class T>
            ampf& operator+=(const T& v);
            template<class T>
            ampf& operator-=(const T& v);
            template<class T>
            ampf& operator*=(const T& v);
            template<class T>
            ampf& operator/=(const T& v);

            mpfr_srcptr getReadPtr() const;
            mpfr_ptr getWritePtr();

            bool isFiniteNumber() const;
            bool isPositiveNumber() const;
            bool isZero() const;
            bool isNegativeNumber() const;
            const ampf getUlpOf();

            double toDouble() const;
            std::string toHex() const;
            std::string toDec() const;

            static const ampf getUlpOf(const ampf &x);
            static const ampf getUlp();
            static const ampf getUlp256();
            static const ampf getUlp512();
            static const ampf getMaxNumber();
            static const ampf getMinNumber();
            static const ampf getAlgoPascalEpsilon();
            static const ampf getAlgoPascalMaxNumber();
            static const ampf getAlgoPascalMinNumber();
            static const ampf getRandom();
        };

### Variable Declaration and Initialization

`amp::ampf` is a template class having one parameter which specifies the precision of a real number. Thus, it is necessary to determine what degree of precision is required before using this class. A number of constructors are defined for class initialization. They can take instance of the same class, integer numbers, standard real numbers (float, double, long double) and strings as the input. Strings can have fractional ("12.34") or exponential form, at that the mantissa could be decimal or hexadecimal (see MPFR library description).

Example:

        int i = 3;
        double d = 2.5;
        amp::ampf<128> a(i), b(d), c("2.33");
        a = "1.56E-3";
        b = a;

### Text Conversions

To convert a number into a text form, you can use member functions `toDec()` and `toHex()`. They return decimal and hexadecimal exponential representation of a number (at that, the hexadecimal conversion is performed faster than the decimal one, therefore if performance is critical it is better to use the hexadecimal conversion). You can't set the format of the result: all significant digits of the number are output.

Example:

        amp::ampf<128> a;
        a = "11";
        printf("%s\n", amp::sqrt(a).toDec().c_str());

### Properties Checking

In order to check whether a real number is finite (as opposed to one of the special values), positive, zero or negative, use member function `isFiniteNumber()`, `isPositiveNumber()`, `isZero()`, `isNegativeNumber()`.

### Information Functions

A number of functions were designed to get information about data type properties:

- member function `getUlpOf()` returns a value of the ULP, Unit-in-Last-Place, of the given `x`. This value is similar to machine precision. Static function `getUlpOf()` has the same functionality.
- static function `getUlp()` is equivalent to `amp::ampf<Precision>::getUlpOf(1)`
- static function `getMaxNumber()` returns the biggest representable (using this data type) positive number
- static function `getMinNumber()` returns the smallest representable (using this data type) positive number
- functions `getAlgoPascalEpsilon()`, `getAlgoPascalMaxNumber()`, `getAlgoPascalMinNumber()` are similar to the above-mentioned ones, but they return values with safety margin. These functions are used by the ALGLIB project programs.

### Access to the `mpfr_t` Pointer

The `getReadPtr()` and `getWritePtr()` functions provide access to mpfr_t pointer. The `getReadPtr()` function allows to get a read-only pointer, which can be passed into an MPFR library function as an argument. The `getWritePtr()` function allows to get a writable pointer, which can be passed into an MPFR library function as a place to store the result in.

It should be noted that the AMP library uses copy-on-write technique, i.e. pointer which has been received by `getReadPtr()` could be common to several objects. Thus, such a pointer must not be used in operations which can change its contents.

A pointer which has been received by `getWritePtr()` can be used in operations which can change its contents, but these operations should not change the precision of a pointer contents. You should take into account that due to its using copy-on-write technique, the pointer which has been received by `getWritePtr()` could differ from the pointer which had previously been received by `getReadPtr()`.

### Random Numbers Generation

In order to generate random numbers from [0, 1), use the static function `getRandom()`. At first, the call function initializes a random number generator using system time.

### Arithmetic Operations

`amp::ampf` class overloads comparison, addition, subtraction, multiplication and division operations. The result is rounded by using exact rounding. Two objects of `amp::ampf` class with the same precision could be the operands. It is acceptable to use objects of `amp::ampf` class and variables of standard data types. You can also use two objects of `amp::ampf` class with different precision as operands, but one of them should be casted to precision of another one.

Example:

        amp::ampf<128> a(3), b(4), c(99);
        amp::ampf<256> d(1);

        a = b+c;          //
        b = c+2.3;        // acceptable  expressions
        c = (2*a-5)/b;    //

        a = b+d;          // compile time error -
                          // arguments of a different type

        a = b + amp::ampf<128>(d); // this is the right way

        a = d;            // this is also acceptable

### Mathematical functions

All functions described here are members of the `amp` namespace. Thus, when you call, for example, the `sqr` function, you should write `amp::sqr`. Unless otherwise specified, the result is rounded up by using exact rounding.

template<unsigned int Precision>
const ampf<Precision> sqr(const ampf<Precision> &x)
Returns the square of `x`.

template<unsigned int Precision>
const int sign(const ampf<Precision> &x)
Returns:
+1, if X>0
-1, if X<0
0, if X=0

template<unsigned int Precision>
const ampf<Precision> abs(const ampf<Precision> &x)
Returns the absolute value of `x`.

template<unsigned int Precision>
const ampf<Precision> maximum(const ampf<Precision> &x, const ampf<Precision> &y)
Returns the maximum of two integers.

template<unsigned int Precision>
const ampf<Precision> minimum(const ampf<Precision> &x, const ampf<Precision> &y)
Returns the minimum of two real numbers.

template<unsigned int Precision>
const ampf<Precision> sqrt(const ampf<Precision> &x)
Returns the square root of `x`.

template<unsigned int Precision>
const signed long trunc(const ampf<Precision> &x)
Rounds towards zero. Throws `amp::invalidConversion` if result doesn't fit in the in the `signed long` type.

template<unsigned int Precision>
const ampf<Precision> frac(const ampf<Precision> &x)
Returns `x-trunc(x)`.

template<unsigned int Precision>
const signed long floor(const ampf<Precision> &x)
Rounds towards minus infinity. Throws `amp::invalidConversion` if result doesn't fit in the in the `signed long` type.

template<unsigned int Precision>
const signed long ceil(const ampf<Precision> &x)
Rounds towards plus infinity. Throws `amp::invalidConversion` if result doesn't fit in the in the `signed long` type.

template<unsigned int Precision>
const signed long round(const ampf<Precision> &x)
Rounds towards nearest integer, rounding halfway cases away from zero. Throws `amp::invalidConversion` if result doesn't fit in the in the `signed long` type.

template<unsigned int Precision>
const ampf<Precision> frexp2(const ampf<Precision> &x, mp_exp_t *exponent)
Splits a number into mantissa and exponent.

template<unsigned int Precision>
const ampf<Precision> ldexp2(const ampf<Precision> &x, mp_exp_t exponent)
Calculates x*2exponent.

template<unsigned int Precision>
const ampf<Precision> pi()
Returns `Pi`.

template<unsigned int Precision>
const ampf<Precision> halfpi()
Returns `0.5*Pi`.

template<unsigned int Precision>
const ampf<Precision> twopi()
Returns `2*Pi`.

template<unsigned int Precision>
const ampf<Precision> sin(const ampf<Precision> &x)
Calculates the sine of a value.

template<unsigned int Precision>
const ampf<Precision> cos(const ampf<Precision> &x)
Calculates the cosine of a value.

template<unsigned int Precision>
const ampf<Precision> tan(const ampf<Precision> &x)
Calculates the tangent of a value.

template<unsigned int Precision>
const ampf<Precision> asin(const ampf<Precision> &x)
Calculates the arcsine of a value.

template<unsigned int Precision>
const ampf<Precision> acos(const ampf<Precision> &x)
Calculates the arccosine of a value.

template<unsigned int Precision>
const ampf<Precision> atan(const ampf<Precision> &x)
Calculates the arctangent of a value.

template<unsigned int Precision>
const ampf<Precision> atan2(const ampf<Precision> &y, const ampf<Precision> &x)
Calculates the arc tangent of y/x. It produces correct results even when the resulting angle is near pi/2 or -pi/2 (x near 0).

template<unsigned int Precision>
const ampf<Precision> log(const ampf<Precision> &x)
Calculates the natural logarithm of x.

template<unsigned int Precision>
const ampf<Precision> log2(const ampf<Precision> &x)
Calculates the binary logarithm of x.

template<unsigned int Precision>
const ampf<Precision> log10(const ampf<Precision> &x)
Calculates the base 10 logarithm of x.

template<unsigned int Precision>
const ampf<Precision> exp(const ampf<Precision> &_x)
Calculates the exponential e to the x.

template<unsigned int Precision>
const ampf<Precision> sinh(const ampf<Precision> &x)
Calculates the hyperbolic sine of a value.

template<unsigned int Precision>
const ampf<Precision> cosh(const ampf<Precision> &_x)
Calculates the hyperbolic cosine of a value.

template<unsigned int Precision>
const ampf<Precision> tanh(const ampf<Precision> &_x)
Calculates the hyperbolic tangent of a value.

template<unsigned int Precision>
const ampf<Precision> pow(const ampf<Precision> &x, const ampf<Precision> &y)
Calculates x to the power of y.

## Vectors, matrices and basic linear algebra operations

### Introduction

The AP library, part of the ALGLIB project, includes vector and matrix template classes as well as subroutines performing basic linear algebra operations (Level 1 BLAS). Since the AP library implements matrix classes using templates, you can use these classes when working with matrices of multiple precision numbers. Therefore, the AMP library doesn't include vector and matrix classes. Basic linear algebra operations are also implemented by using templates in the AP library, but AMP includes its own classes specially designed to work with multiple precision numbers. The AMP library subroutines are optimized to reduce memory manager loading, thus it is better to use these subroutines when performing vector operations over multiple precision numbers.

### Description

template<unsigned int Precision>
ampf<Precision> vDotProduct(ap::const_raw_vector< ampf<Precision> > v1, ap::const_raw_vector< ampf<Precision> > v2)
The subroutine calculates the scalar product of two vectors. For more information about `ap::const_raw_vector` see description of AP library.

template<unsigned int Precision>
void vMove(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc)
This function copies `vSrc` vector to `vDst`.

template<unsigned int Precision>
void vMoveNeg(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc)
This function copies `-vSrc` vector to `vDst`.

template<unsigned int Precision, class T2>
void vMove(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc, T2 alpha)
This function copies `alpha*vSrc` vector to `vDst`.

template<unsigned int Precision>
void vAdd(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc)
This function adds `vSrc` vector to `vDst`.

template<unsigned int Precision, class T2>
void vAdd(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc, T2 alpha)
This function adds `alpha*vSrc` vector to `vDst`.

template<unsigned int Precision>
void vSub(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc)
This function subtracts `vSrc` vector from `vDst` vector.

template<unsigned int Precision, class T2>
void vSub(ap::raw_vector< ampf<Precision> > vDst, ap::const_raw_vector< ampf<Precision> > vSrc, T2 alpha)
This function subtracts `alpha*vSrc` from `vDst` vector.

template<unsigned int Precision, class T2>
void vMul(ap::raw_vector< ampf<Precision> > vDst, T2 alpha)
This function multiplies vector by a number and stores the result in the same place

## `amp::campf` class

### Key concepts

`amp::campf` class implements multiple precision complex number operations. Real and imaginary parts are stored in `x` and `y` fields of type `amp::ampf`. You can perform arithmetic and comparison operations over the objects of this class. Moreover, a number of standard mathematical functions are defined for this data type.

### `amp::ampf` members

        template<unsigned int Precision>
        class campf
        {
        public:
            campf():x(0),y(0);
            campf(long double v);
            campf(double v);
            campf(float v);
            campf(signed long v);
            campf(unsigned long v);
            campf(signed int v);
            campf(unsigned int v);
            campf(signed short v);
            campf(unsigned short v);
            campf(signed char v);
            campf(unsigned char v);
            campf(const ampf<Precision> &_x);
            campf(const ampf<Precision> &_x, const ampf<Precision> &_y);
            campf(const campf &z):x(z.x),y(z.y);
            template<unsigned int Prec2>
            campf(const campf<Prec2> &z);

            campf& operator= (long double v);
            campf& operator= (double v);
            campf& operator= (float v);
            campf& operator= (signed long v);
            campf& operator= (unsigned long v);
            campf& operator= (signed int v);
            campf& operator= (unsigned int v);
            campf& operator= (signed short v);
            campf& operator= (unsigned short v);
            campf& operator= (signed char v);
            campf& operator= (unsigned char v);
            campf& operator= (const char *s);
            campf& operator= (const std::string &s);
            campf& operator= (const campf& r);
            template<unsigned int Precision2>
            campf& operator= (const campf<Precision2>& r);

            ampf<Precision> x, y;
        };

### Arithmetic Operations

`amp::campf` class overrides comparison, addition, subtraction, multiplication and division operations. Two objects of `amp::campf` class of the same precision could be the operands. It is acceptable to use objects of `amp::campf` and `amp::ampf` types and variables of standard data types as operands. You can also use `amp::campf` instances with different precision, but they should be casted.

### Standard Functions

template<unsigned int Precision>
const ampf<Precision> abscomplex(const campf<Precision> &z)
Returns the modulus of complex number z. It should be noted that the modulus calculation is performed using so called "safe" algorithm, that could never cause overflow when calculating intermediate results.

template<unsigned int Precision>
const campf<Precision> conj(const campf<Precision> &z)
Returns complex conjugate of z.

template<unsigned int Precision>
const campf<Precision> csqr(const campf<Precision> &z)
Returns the square of z.

# ALGLIB reference manual

## Packages and units

`DiffEquations` package
odesolver |  | Ordinary differential equation solver
`FastTransforms` package
conv |  | Fast real/complex convolution
corr |  | Fast real/complex cross-correlation
fft |  | Real/complex FFT
fht |  | Real Fast Hartley Transform
`Integration` package
autogk |  | Adaptive 1-dimensional integration
gkq |  | Gauss-Kronrod quadrature generator
gq |  | Gaussian quadrature generator
`Interpolation` package
idwint |  | Inverse distance weighting: interpolation/fitting
lsfit |  | Linear and nonlinear least-squares solvers
polint |  | Polynomial interpolation/fitting
pspline |  | Parametric spline interpolation
ratint |  | Rational interpolation/fitting
spline1d |  | 1D spline interpolation/fitting
spline2d |  | 2D spline interpolation
`LinAlg` package
ablas |  | Level 2 and Level 3 BLAS operations
bdsvd |  | Bidiagonal SVD
evd |  | Eigensolvers
inverseupdate |  | Sherman-Morrison update of the inverse matrix
ldlt |  | LDLT decomposition
matdet |  | Determinant calculation
matgen |  | Random matrix generation
matinv |  | Matrix inverse
ortfac |  | Real/complex QR, LQ, bi(tri)diagonal, Hessenberg decompositions
rcond |  | Condition number estimate
schur |  | Schur decomposition
sdet |  | Determinant of a symmetric matrix
sinverse |  | Symmetric inversion
spdgevd |  | Generalized symmetric eigensolver
srcond |  | Condition number estimate for symmetric matrices
svd |  | Singular value decomposition
trfac |  | LU and Cholesky decompositions
`Optimization` package
minasa |  | ASA bound constrained optimizer
mincg |  | Conjugate gradient optimizer
minlbfgs |  | Limited memory BFGS optimizer
minlm |  | Improved Levenberg-Marquardt optimizer
`Solvers` package
densesolver |  | Dense linear system solver
ssolve |  | Symmetric dense linear system solver

## `ablas` unit

### Functions

ablasblocksize
ablascomplexblocksize
ablascomplexsplitlength
ablasmicroblocksize
ablassplitlength
cmatrixcopy
cmatrixgemm
cmatrixlefttrsm
cmatrixmv
cmatrixrank1
cmatrixrighttrsm
cmatrixsyrk
cmatrixtranspose
rmatrixcopy
rmatrixgemm
rmatrixlefttrsm
rmatrixmv
rmatrixrank1
rmatrixrighttrsm
rmatrixsyrk
rmatrixtranspose

### `ablasblocksize` function

    /*************************************************************************
    Returns block size - subdivision size where  cache-oblivious  soubroutines
    switch to the optimized kernel.

    INPUT PARAMETERS
        A   -   real matrix, is passed to ensure that we didn't split
                complex matrix using real splitting subroutine.
                matrix itself is not changed.

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    int ablasblocksize(const ap::template_2d_array< amp::ampf<Precision> >& a);

### `ablascomplexblocksize` function

    /*************************************************************************
    Block size for complex subroutines.

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    int ablascomplexblocksize(const ap::template_2d_array< amp::campf<Precision> >& a);

### `ablascomplexsplitlength` function

    /*************************************************************************
    Complex ABLASSplitLength

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void ablascomplexsplitlength(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        int& n1,
        int& n2);

### `ablasmicroblocksize` function

    /*************************************************************************
    Microblock size

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    int ablasmicroblocksize();

### `ablassplitlength` function

    /*************************************************************************
    Splits matrix length in two parts, left part should match ABLAS block size

    INPUT PARAMETERS
        A   -   real matrix, is passed to ensure that we didn't split
                complex matrix using real splitting subroutine.
                matrix itself is not changed.
        N   -   length, N>0

    OUTPUT PARAMETERS
        N1  -   length
        N2  -   length

    N1+N2=N, N1>=N2, N2 may be zero

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void ablassplitlength(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        int& n1,
        int& n2);

### `cmatrixcopy` function

    /*************************************************************************
    Copy

    Input parameters:
        M   -   number of rows
        N   -   number of columns
        A   -   source matrix, MxN submatrix is copied and transposed
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        B   -   destination matrix
        IB  -   submatrix offset (row index)
        JB  -   submatrix offset (column index)
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixcopy(int m,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& a,
        int ia,
        int ja,
        ap::template_2d_array< amp::campf<Precision> >& b,
        int ib,
        int jb);

### `cmatrixgemm` function

    /*************************************************************************
    This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where:
    * C is MxN general matrix
    * op1(A) is MxK matrix
    * op2(B) is KxN matrix
    * "op" may be identity transformation, transposition, conjugate transposition

    Additional info:
    * cache-oblivious algorithm is used.
    * multiplication result replaces C. If Beta=0, C elements are not used in
      calculations (not multiplied by zero - just not referenced)
    * if Alpha=0, A is not used (not multiplied by zero - just not referenced)
    * if both Beta and Alpha are zero, C is filled by zeros.

    INPUT PARAMETERS
        N       -   matrix size, N>0
        M       -   matrix size, N>0
        K       -   matrix size, K>0
        Alpha   -   coefficient
        A       -   matrix
        IA      -   submatrix offset
        JA      -   submatrix offset
        OpTypeA -   transformation type:
                    * 0 - no transformation
                    * 1 - transposition
                    * 2 - conjugate transposition
        B       -   matrix
        IB      -   submatrix offset
        JB      -   submatrix offset
        OpTypeB -   transformation type:
                    * 0 - no transformation
                    * 1 - transposition
                    * 2 - conjugate transposition
        Beta    -   coefficient
        C       -   matrix
        IC      -   submatrix offset
        JC      -   submatrix offset

      -- ALGLIB routine --
         16.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixgemm(int m,
        int n,
        int k,
        amp::campf<Precision> alpha,
        const ap::template_2d_array< amp::campf<Precision> >& a,
        int ia,
        int ja,
        int optypea,
        const ap::template_2d_array< amp::campf<Precision> >& b,
        int ib,
        int jb,
        int optypeb,
        amp::campf<Precision> beta,
        ap::template_2d_array< amp::campf<Precision> >& c,
        int ic,
        int jc);

### `cmatrixlefttrsm` function

    /*************************************************************************
    This subroutine calculates op(A^-1)*X where:
    * X is MxN general matrix
    * A is MxM upper/lower triangular/unitriangular matrix
    * "op" may be identity transformation, transposition, conjugate transposition

    Multiplication result replaces X.
    Cache-oblivious algorithm is used.

    INPUT PARAMETERS
        N   -   matrix size, N>=0
        M   -   matrix size, N>=0
        A       -   matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1]
        I1      -   submatrix offset
        J1      -   submatrix offset
        IsUpper -   whether matrix is upper triangular
        IsUnit  -   whether matrix is unitriangular
        OpType  -   transformation type:
                    * 0 - no transformation
                    * 1 - transposition
                    * 2 - conjugate transposition
        C   -   matrix, actial matrix is stored in C[I2:I2+M-1,J2:J2+N-1]
        I2  -   submatrix offset
        J2  -   submatrix offset

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlefttrsm(int m,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& a,
        int i1,
        int j1,
        bool isupper,
        bool isunit,
        int optype,
        ap::template_2d_array< amp::campf<Precision> >& x,
        int i2,
        int j2);

### `cmatrixmv` function

    /*************************************************************************
    Matrix-vector product: y := op(A)*x

    INPUT PARAMETERS:
        M   -   number of rows of op(A)
                M>=0
        N   -   number of columns of op(A)
                N>=0
        A   -   target matrix
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        OpA -   operation type:
                * OpA=0     =>  op(A) = A
                * OpA=1     =>  op(A) = A^T
                * OpA=2     =>  op(A) = A^H
        X   -   input vector
        IX  -   subvector offset
        IY  -   subvector offset

    OUTPUT PARAMETERS:
        Y   -   vector which stores result

    if M=0, then subroutine does nothing.
    if N=0, Y is filled by zeros.

      -- ALGLIB routine --

         28.01.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixmv(int m,
        int n,
        ap::template_2d_array< amp::campf<Precision> >& a,
        int ia,
        int ja,
        int opa,
        ap::template_1d_array< amp::campf<Precision> >& x,
        int ix,
        ap::template_1d_array< amp::campf<Precision> >& y,
        int iy);

### `cmatrixrank1` function

    /*************************************************************************
    Rank-1 correction: A := A + u*v'

    INPUT PARAMETERS:
        M   -   number of rows
        N   -   number of columns
        A   -   target matrix, MxN submatrix is updated
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        U   -   vector #1
        IU  -   subvector offset
        V   -   vector #2
        IV  -   subvector offset
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixrank1(int m,
        int n,
        ap::template_2d_array< amp::campf<Precision> >& a,
        int ia,
        int ja,
        ap::template_1d_array< amp::campf<Precision> >& u,
        int iu,
        ap::template_1d_array< amp::campf<Precision> >& v,
        int iv);

### `cmatrixrighttrsm` function

    /*************************************************************************
    This subroutine calculates X*op(A^-1) where:
    * X is MxN general matrix
    * A is NxN upper/lower triangular/unitriangular matrix
    * "op" may be identity transformation, transposition, conjugate transposition

    Multiplication result replaces X.
    Cache-oblivious algorithm is used.

    INPUT PARAMETERS
        N   -   matrix size, N>=0
        M   -   matrix size, N>=0
        A       -   matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1]
        I1      -   submatrix offset
        J1      -   submatrix offset
        IsUpper -   whether matrix is upper triangular
        IsUnit  -   whether matrix is unitriangular
        OpType  -   transformation type:
                    * 0 - no transformation
                    * 1 - transposition
                    * 2 - conjugate transposition
        C   -   matrix, actial matrix is stored in C[I2:I2+M-1,J2:J2+N-1]
        I2  -   submatrix offset
        J2  -   submatrix offset

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixrighttrsm(int m,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& a,
        int i1,
        int j1,
        bool isupper,
        bool isunit,
        int optype,
        ap::template_2d_array< amp::campf<Precision> >& x,
        int i2,
        int j2);

### `cmatrixsyrk` function

    /*************************************************************************
    This subroutine calculates  C=alpha*A*A^H+beta*C  or  C=alpha*A^H*A+beta*C
    where:
    * C is NxN Hermitian matrix given by its upper/lower triangle
    * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise

    Additional info:
    * cache-oblivious algorithm is used.
    * multiplication result replaces C. If Beta=0, C elements are not used in
      calculations (not multiplied by zero - just not referenced)
    * if Alpha=0, A is not used (not multiplied by zero - just not referenced)
    * if both Beta and Alpha are zero, C is filled by zeros.

    INPUT PARAMETERS
        N       -   matrix size, N>=0
        K       -   matrix size, K>=0
        Alpha   -   coefficient
        A       -   matrix
        IA      -   submatrix offset
        JA      -   submatrix offset
        OpTypeA -   multiplication type:
                    * 0 - A*A^H is calculated
                    * 2 - A^H*A is calculated
        Beta    -   coefficient
        C       -   matrix
        IC      -   submatrix offset
        JC      -   submatrix offset
        IsUpper -   whether C is upper triangular or lower triangular

      -- ALGLIB routine --
         16.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixsyrk(int n,
        int k,
        amp::ampf<Precision> alpha,
        const ap::template_2d_array< amp::campf<Precision> >& a,
        int ia,
        int ja,
        int optypea,
        amp::ampf<Precision> beta,
        ap::template_2d_array< amp::campf<Precision> >& c,
        int ic,
        int jc,
        bool isupper);

### `cmatrixtranspose` function

    /*************************************************************************
    Cache-oblivous complex "copy-and-transpose"

    Input parameters:
        M   -   number of rows
        N   -   number of columns
        A   -   source matrix, MxN submatrix is copied and transposed
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        A   -   destination matrix
        IB  -   submatrix offset (row index)
        JB  -   submatrix offset (column index)
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixtranspose(int m,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& a,
        int ia,
        int ja,
        ap::template_2d_array< amp::campf<Precision> >& b,
        int ib,
        int jb);

### `rmatrixcopy` function

    /*************************************************************************
    Copy

    Input parameters:
        M   -   number of rows
        N   -   number of columns
        A   -   source matrix, MxN submatrix is copied and transposed
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        B   -   destination matrix
        IB  -   submatrix offset (row index)
        JB  -   submatrix offset (column index)
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixcopy(int m,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& a,
        int ia,
        int ja,
        ap::template_2d_array< amp::ampf<Precision> >& b,
        int ib,
        int jb);

### `rmatrixgemm` function

    /*************************************************************************
    Same as CMatrixGEMM, but for real numbers.
    OpType may be only 0 or 1.

      -- ALGLIB routine --
         16.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixgemm(int m,
        int n,
        int k,
        amp::ampf<Precision> alpha,
        const ap::template_2d_array< amp::ampf<Precision> >& a,
        int ia,
        int ja,
        int optypea,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        int ib,
        int jb,
        int optypeb,
        amp::ampf<Precision> beta,
        ap::template_2d_array< amp::ampf<Precision> >& c,
        int ic,
        int jc);

### `rmatrixlefttrsm` function

    /*************************************************************************
    Same as CMatrixLeftTRSM, but for real matrices

    OpType may be only 0 or 1.

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlefttrsm(int m,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& a,
        int i1,
        int j1,
        bool isupper,
        bool isunit,
        int optype,
        ap::template_2d_array< amp::ampf<Precision> >& x,
        int i2,
        int j2);

### `rmatrixmv` function

    /*************************************************************************
    Matrix-vector product: y := op(A)*x

    INPUT PARAMETERS:
        M   -   number of rows of op(A)
        N   -   number of columns of op(A)
        A   -   target matrix
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        OpA -   operation type:
                * OpA=0     =>  op(A) = A
                * OpA=1     =>  op(A) = A^T
        X   -   input vector
        IX  -   subvector offset
        IY  -   subvector offset

    OUTPUT PARAMETERS:
        Y   -   vector which stores result

    if M=0, then subroutine does nothing.
    if N=0, Y is filled by zeros.

      -- ALGLIB routine --

         28.01.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixmv(int m,
        int n,
        ap::template_2d_array< amp::ampf<Precision> >& a,
        int ia,
        int ja,
        int opa,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        int ix,
        ap::template_1d_array< amp::ampf<Precision> >& y,
        int iy);

### `rmatrixrank1` function

    /*************************************************************************
    Rank-1 correction: A := A + u*v'

    INPUT PARAMETERS:
        M   -   number of rows
        N   -   number of columns
        A   -   target matrix, MxN submatrix is updated
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        U   -   vector #1
        IU  -   subvector offset
        V   -   vector #2
        IV  -   subvector offset
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixrank1(int m,
        int n,
        ap::template_2d_array< amp::ampf<Precision> >& a,
        int ia,
        int ja,
        ap::template_1d_array< amp::ampf<Precision> >& u,
        int iu,
        ap::template_1d_array< amp::ampf<Precision> >& v,
        int iv);

### `rmatrixrighttrsm` function

    /*************************************************************************
    Same as CMatrixRightTRSM, but for real matrices

    OpType may be only 0 or 1.

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixrighttrsm(int m,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& a,
        int i1,
        int j1,
        bool isupper,
        bool isunit,
        int optype,
        ap::template_2d_array< amp::ampf<Precision> >& x,
        int i2,
        int j2);

### `rmatrixsyrk` function

    /*************************************************************************
    Same as CMatrixSYRK, but for real matrices

    OpType may be only 0 or 1.

      -- ALGLIB routine --
         16.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixsyrk(int n,
        int k,
        amp::ampf<Precision> alpha,
        const ap::template_2d_array< amp::ampf<Precision> >& a,
        int ia,
        int ja,
        int optypea,
        amp::ampf<Precision> beta,
        ap::template_2d_array< amp::ampf<Precision> >& c,
        int ic,
        int jc,
        bool isupper);

### `rmatrixtranspose` function

    /*************************************************************************
    Cache-oblivous real "copy-and-transpose"

    Input parameters:
        M   -   number of rows
        N   -   number of columns
        A   -   source matrix, MxN submatrix is copied and transposed
        IA  -   submatrix offset (row index)
        JA  -   submatrix offset (column index)
        A   -   destination matrix
        IB  -   submatrix offset (row index)
        JB  -   submatrix offset (column index)
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixtranspose(int m,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& a,
        int ia,
        int ja,
        ap::template_2d_array< amp::ampf<Precision> >& b,
        int ib,
        int jb);

## `autogk` unit

### Structures

autogkreport
autogkstate

### Functions

autogkiteration
autogkresults
autogksingular
autogksmooth
autogksmoothw

### Examples

autogk_singular
autogk_smooth

### `autogkreport` structure

    /*************************************************************************
    Integration report:
    * TerminationType = completetion code:
        * -5    non-convergence of Gauss-Kronrod nodes
                calculation subroutine.
        * -1    incorrect parameters were specified
        *  1    OK
    * Rep.NFEV countains number of function calculations
    * Rep.NIntervals contains number of intervals [a,b]
      was partitioned into.
    *************************************************************************/
    template<unsigned int Precision>
    class autogkreport
    {
    public:
        int terminationtype;
        int nfev;
        int nintervals;
    };

### `autogkstate` structure

    /*************************************************************************
    This structure stores internal state of the integration algorithm  between
    subsequent calls of the AutoGKIteration() subroutine.
    *************************************************************************/
    template<unsigned int Precision>
    class autogkstate
    {
    public:
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;
        amp::ampf<Precision> alpha;
        amp::ampf<Precision> beta;
        amp::ampf<Precision> xwidth;
        amp::ampf<Precision> x;
        amp::ampf<Precision> xminusa;
        amp::ampf<Precision> bminusx;
        amp::ampf<Precision> f;
        int wrappermode;
        autogkinternalstate<Precision> internalstate;
        amp::rcommstate<Precision> rstate;
        amp::ampf<Precision> v;
        int terminationtype;
        int nfev;
        int nintervals;
    };

### `autogkiteration` function

    /*************************************************************************
    One step of adaptive integration process.

    Called after initialization with one of AutoGKXXX subroutines.
    See HTML documentation for examples.

    Input parameters:
        State   -   structure which stores algorithm state between  calls  and
                    which  is  used  for   reverse   communication.   Must  be
                    initialized with one of AutoGKXXX subroutines.

    If suborutine returned False, iterative proces has converged. If subroutine
    returned True, caller should calculate function value State.F  at  State.X
    and call AutoGKIteration again.

    NOTE:

    When integrating "difficult" functions with integrable singularities like

        F(x) = (x-A)^alpha * (B-x)^beta

    subroutine may require the value of F at points which are too close to A/B.
    Sometimes to calculate integral with high enough precision we  may need to
    calculate F(A+delta) when delta is less than machine  epsilon.  In  finite
    precision arithmetics A+delta will be effectively equal to A,  so  we  may
    find us in situation when  we  are  trying  to  calculate  something  like
    1/sqrt(1-1).

    To avoid  such  situations,  AutoGKIteration  subroutine  fills  not  only
    State.X  field,  but  also   State.XMinusA   (which  equals  to  X-A)  and
    State.BMinusX  (which  equals to B-X) fields.  If X is too close to A or B
    (X-A<0.001*A, or B-X<0.001*B, for example) use  these  fields  instead  of
    State.X

      -- ALGLIB --
         Copyright 07.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool autogkiteration(autogkstate<Precision>& state);

Examples: autogk_singular autogk_smooth

### `autogkresults` function

    /*************************************************************************
    Adaptive integration results

    Called after AutoGKIteration returned False.

    Input parameters:
        State   -   algorithm state (used by AutoGKIteration).

    Output parameters:
        V       -   integral(f(x)dx,a,b)
        Rep     -   optimization report (see AutoGKReport description)

      -- ALGLIB --
         Copyright 14.11.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void autogkresults(const autogkstate<Precision>& state,
        amp::ampf<Precision>& v,
        autogkreport<Precision>& rep);

Examples: autogk_singular autogk_smooth

### `autogksingular` function

    /*************************************************************************
    Integration on a finite interval [A,B].
    Integrand have integrable singularities at A/B.

    F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B,  with known
    alpha/beta (alpha>-1, beta>-1).  If alpha/beta  are  not known,  estimates
    from below can be used (but these estimates should be greater than -1 too).

    One  of  alpha/beta variables (or even both alpha/beta) may be equal to 0,
    which means than function F(x) is non-singular at A/B. Anyway (singular at
    bounds or not), function F(x) is supposed to be continuous on (A,B).

    Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result
    is calculated with accuracy close to the machine precision.

    INPUT PARAMETERS:
        A, B    -   interval boundaries (A<B, A=B or A>B)
        Alpha   -   power-law coefficient of the F(x) at A,
                    Alpha>-1
        Beta    -   power-law coefficient of the F(x) at B,
                    Beta>-1

    OUTPUT PARAMETERS
        State   -   structure which stores algorithm state between  subsequent
                    calls of AutoGKIteration.  Used for reverse communication.
                    This structure should be  passed  to  the  AutoGKIteration
                    subroutine.

    SEE ALSO
        AutoGKSmooth, AutoGKSmoothW, AutoGKIteration, AutoGKResults.

      -- ALGLIB --
         Copyright 06.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void autogksingular(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        amp::ampf<Precision> alpha,
        amp::ampf<Precision> beta,
        autogkstate<Precision>& state);

Examples: autogk_singular

### `autogksmooth` function

    /*************************************************************************
    Integration of a smooth function F(x) on a finite interval [a,b].

    Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result
    is calculated with accuracy close to the machine precision.

    Algorithm works well only with smooth integrands.  It  may  be  used  with
    continuous non-smooth integrands, but with  less  performance.

    It should never be used with integrands which have integrable singularities
    at lower or upper limits - algorithm may crash. Use AutoGKSingular in such
    cases.

    INPUT PARAMETERS:
        A, B    -   interval boundaries (A<B, A=B or A>B)

    OUTPUT PARAMETERS
        State   -   structure which stores algorithm state between  subsequent
                    calls of AutoGKIteration.  Used for reverse communication.
                    This structure should be  passed  to  the  AutoGKIteration
                    subroutine.

    SEE ALSO
        AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults.

      -- ALGLIB --
         Copyright 06.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void autogksmooth(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        autogkstate<Precision>& state);

Examples: autogk_smooth

### `autogksmoothw` function

    /*************************************************************************
    Integration of a smooth function F(x) on a finite interval [a,b].

    This subroutine is same as AutoGKSmooth(), but it guarantees that interval
    [a,b] is partitioned into subintervals which have width at most XWidth.

    Subroutine  can  be  used  when  integrating nearly-constant function with
    narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth
    subroutine can overlook them.

    INPUT PARAMETERS:
        A, B    -   interval boundaries (A<B, A=B or A>B)

    OUTPUT PARAMETERS
        State   -   structure which stores algorithm state between  subsequent
                    calls of AutoGKIteration.  Used for reverse communication.
                    This structure should be  passed  to  the  AutoGKIteration
                    subroutine.

    SEE ALSO
        AutoGKSmooth, AutoGKSingular, AutoGKIteration, AutoGKResults.

      -- ALGLIB --
         Copyright 06.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void autogksmoothw(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        amp::ampf<Precision> xwidth,
        autogkstate<Precision>& state);

### autogk_singular example

        autogk::autogkstate<Precision> state;
        amp::ampf<Precision> v;
        autogk::autogkreport<Precision> rep;
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;
        amp::ampf<Precision> alpha;

        //
        // f1(x) = (1+x)*(x-a)^alpha, alpha=-0.3
        // Exact answer is (B-A)^(Alpha+2)/(Alpha+2) + (1+A)*(B-A)^(Alpha+1)/(Alpha+1)
        //
        // This code demonstrates use of the State.XMinusA (State.BMinusX) field.
        //
        // If we try to use State.X instead of State.XMinusA,
        // we will end up dividing by zero! (in 64-bit precision)
        //
        a = amp::ampf<Precision>("1.0");
        b = amp::ampf<Precision>("5.0");
        alpha = -amp::ampf<Precision>("0.9");
        autogk::autogksingular<Precision>(a, b, alpha, amp::ampf<Precision>("0.0"), state);
        while( autogk::autogkiteration<Precision>(state) )
        {
            state.f = amp::pow<Precision>(state.xminusa, alpha)*(1+state.x);
        }
        autogk::autogkresults<Precision>(state, v, rep);
        printf("integral((1+x)*(x-a)^alpha) on [%0.1lf; %0.1lf] = %0.2lf\nExact answer is %0.2lf\n",
            double(amp::ampf<Precision>(a).toDouble()),
            double(amp::ampf<Precision>(b).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(amp::pow<Precision>(b-a, alpha+2)/(alpha+2)+(1+a)*amp::pow<Precision>(b-a, alpha+1)/(alpha+1)).toDouble()));

### autogk_smooth example

        autogk::autogkstate<Precision> state;
        amp::ampf<Precision> v;
        autogk::autogkreport<Precision> rep;

        //
        // f(x) = x*sin(x), integrated at [-pi, pi].
        // Exact answer is 2*pi
        //
        autogk::autogksmooth<Precision>(-amp::pi<Precision>(), +amp::pi<Precision>(), state);
        while( autogk::autogkiteration<Precision>(state) )
        {
            state.f = state.x*amp::sin<Precision>(state.x);
        }
        autogk::autogkresults<Precision>(state, v, rep);
        printf("integral(x*sin(x),-pi,+pi) = %0.2lf\nExact answer is %0.2lf\n",
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(2*amp::pi<Precision>()).toDouble()));

## `bdsvd` unit

### Functions

rmatrixbdsvd

### `rmatrixbdsvd` function

    /*************************************************************************
    Singular value decomposition of a bidiagonal matrix (extended algorithm)

    The algorithm performs the singular value decomposition  of  a  bidiagonal
    matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and  P -
    orthogonal matrices, S - diagonal matrix with non-negative elements on the
    main diagonal, in descending order.

    The  algorithm  finds  singular  values.  In  addition,  the algorithm can
    calculate  matrices  Q  and P (more precisely, not the matrices, but their
    product  with  given  matrices U and VT - U*Q and (P^T)*VT)).  Of  course,
    matrices U and VT can be of any type, including identity. Furthermore, the
    algorithm can calculate Q'*C (this product is calculated more  effectively
    than U*Q,  because  this calculation operates with rows instead  of matrix
    columns).

    The feature of the algorithm is its ability to find  all  singular  values
    including those which are arbitrarily close to 0  with  relative  accuracy
    close to  machine precision. If the parameter IsFractionalAccuracyRequired
    is set to True, all singular values will have high relative accuracy close
    to machine precision. If the parameter is set to False, only  the  biggest
    singular value will have relative accuracy  close  to  machine  precision.
    The absolute error of other singular values is equal to the absolute error
    of the biggest singular value.

    Input parameters:
        D       -   main diagonal of matrix B.
                    Array whose index ranges within [0..N-1].
        E       -   superdiagonal (or subdiagonal) of matrix B.
                    Array whose index ranges within [0..N-2].
        N       -   size of matrix B.
        IsUpper -   True, if the matrix is upper bidiagonal.
        IsFractionalAccuracyRequired -
                    accuracy to search singular values with.
        U       -   matrix to be multiplied by Q.
                    Array whose indexes range within [0..NRU-1, 0..N-1].
                    The matrix can be bigger, in that case only the  submatrix
                    [0..NRU-1, 0..N-1] will be multiplied by Q.
        NRU     -   number of rows in matrix U.
        C       -   matrix to be multiplied by Q'.
                    Array whose indexes range within [0..N-1, 0..NCC-1].
                    The matrix can be bigger, in that case only the  submatrix
                    [0..N-1, 0..NCC-1] will be multiplied by Q'.
        NCC     -   number of columns in matrix C.
        VT      -   matrix to be multiplied by P^T.
                    Array whose indexes range within [0..N-1, 0..NCVT-1].
                    The matrix can be bigger, in that case only the  submatrix
                    [0..N-1, 0..NCVT-1] will be multiplied by P^T.
        NCVT    -   number of columns in matrix VT.

    Output parameters:
        D       -   singular values of matrix B in descending order.
        U       -   if NRU>0, contains matrix U*Q.
        VT      -   if NCVT>0, contains matrix (P^T)*VT.
        C       -   if NCC>0, contains matrix Q'*C.

    Result:
        True, if the algorithm has converged.
        False, if the algorithm hasn't converged (rare case).

    Additional information:
        The type of convergence is controlled by the internal  parameter  TOL.
        If the parameter is greater than 0, the singular values will have
        relative accuracy TOL. If TOL<0, the singular values will have
        absolute accuracy ABS(TOL)*norm(B).
        By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon,
        where Epsilon is the machine precision. It is not  recommended  to  use
        TOL less than 10*Epsilon since this will  considerably  slow  down  the
        algorithm and may not lead to error decreasing.
    History:
        * 31 March, 2007.
            changed MAXITR from 6 to 12.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         October 31, 1999.
    *************************************************************************/
    template<unsigned int Precision>
    bool rmatrixbdsvd(ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_1d_array< amp::ampf<Precision> > e,
        int n,
        bool isupper,
        bool isfractionalaccuracyrequired,
        ap::template_2d_array< amp::ampf<Precision> >& u,
        int nru,
        ap::template_2d_array< amp::ampf<Precision> >& c,
        int ncc,
        ap::template_2d_array< amp::ampf<Precision> >& vt,
        int ncvt);

## `conv` unit

### Functions

convc1d
convc1dcircular
convc1dcircularinv
convc1dinv
convc1dx
convr1d
convr1dcircular
convr1dcircularinv
convr1dinv
convr1dx

### `convc1d` function

    /*************************************************************************
    1-dimensional complex convolution.

    For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
    choose between three implementations: straightforward O(M*N)  formula  for
    very small N (or M), overlap-add algorithm for  cases  where  max(M,N)  is
    significantly larger than min(M,N), but O(M*N) algorithm is too slow,  and
    general FFT-based formula for cases where two previois algorithms are  too
    slow.

    Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.

    INPUT PARAMETERS
        A   -   array[0..M-1] - complex function to be transformed
        M   -   problem size
        B   -   array[0..N-1] - complex function to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..N+M-2].

    NOTE:
        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
    functions have non-zero values at negative T's, you  can  still  use  this
    subroutine - just shift its result correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convc1d(const ap::template_1d_array< amp::campf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& r);

### `convc1dcircular` function

    /*************************************************************************
    1-dimensional circular complex convolution.

    For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
    complexity for any M/N.

    IMPORTANT:  normal convolution is commutative,  i.e.   it  is symmetric  -
    conv(A,B)=conv(B,A).  Cyclic convolution IS NOT.  One function - S - is  a
    signal,  periodic function, and another - R - is a response,  non-periodic
    function with limited length.

    INPUT PARAMETERS
        S   -   array[0..M-1] - complex periodic signal
        M   -   problem size
        B   -   array[0..N-1] - complex non-periodic response
        N   -   problem size

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..M-1].

    NOTE:
        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
    negative T's, you can still use this subroutine - just  shift  its  result
    correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convc1dcircular(const ap::template_1d_array< amp::campf<Precision> >& s,
        int m,
        const ap::template_1d_array< amp::campf<Precision> >& r,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& c);

### `convc1dcircularinv` function

    /*************************************************************************
    1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).

    Algorithm has M*log(M)) complexity for any M (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..M-1] - convolved periodic signal, A = conv(R, B)
        M   -   convolved signal length
        B   -   array[0..N-1] - non-periodic response
        N   -   response length

    OUTPUT PARAMETERS
        R   -   deconvolved signal. array[0..M-1].

    NOTE:
        deconvolution is unstable process and may result in division  by  zero
    (if your response function is degenerate, i.e. has zero Fourier coefficient).

    NOTE:
        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
    negative T's, you can still use this subroutine - just  shift  its  result
    correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convc1dcircularinv(const ap::template_1d_array< amp::campf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& r);

### `convc1dinv` function

    /*************************************************************************
    1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).

    Algorithm has M*log(M)) complexity for any M (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..M-1] - convolved signal, A = conv(R, B)
        M   -   convolved signal length
        B   -   array[0..N-1] - response
        N   -   response length, N<=M

    OUTPUT PARAMETERS
        R   -   deconvolved signal. array[0..M-N].

    NOTE:
        deconvolution is unstable process and may result in division  by  zero
    (if your response function is degenerate, i.e. has zero Fourier coefficient).

    NOTE:
        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
    functions have non-zero values at negative T's, you  can  still  use  this
    subroutine - just shift its result correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convc1dinv(const ap::template_1d_array< amp::campf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& r);

### `convc1dx` function

    /*************************************************************************
    1-dimensional complex convolution.

    Extended subroutine which allows to choose convolution algorithm.
    Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular().

    INPUT PARAMETERS
        A   -   array[0..M-1] - complex function to be transformed
        M   -   problem size
        B   -   array[0..N-1] - complex function to be transformed
        N   -   problem size, N<=M
        Alg -   algorithm type:
                *-2     auto-select Q for overlap-add
                *-1     auto-select algorithm and parameters
                * 0     straightforward formula for small N's
                * 1     general FFT-based code
                * 2     overlap-add with length Q
        Q   -   length for overlap-add

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..N+M-1].

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convc1dx(const ap::template_1d_array< amp::campf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int n,
        bool circular,
        int alg,
        int q,
        ap::template_1d_array< amp::campf<Precision> >& r);

### `convr1d` function

    /*************************************************************************
    1-dimensional real convolution.

    Analogous to ConvC1D(), see ConvC1D() comments for more details.

    INPUT PARAMETERS
        A   -   array[0..M-1] - real function to be transformed
        M   -   problem size
        B   -   array[0..N-1] - real function to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..N+M-2].

    NOTE:
        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
    functions have non-zero values at negative T's, you  can  still  use  this
    subroutine - just shift its result correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convr1d(const ap::template_1d_array< amp::ampf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& r);

### `convr1dcircular` function

    /*************************************************************************
    1-dimensional circular real convolution.

    Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.

    INPUT PARAMETERS
        S   -   array[0..M-1] - real signal
        M   -   problem size
        B   -   array[0..N-1] - real response
        N   -   problem size

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..M-1].

    NOTE:
        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
    negative T's, you can still use this subroutine - just  shift  its  result
    correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convr1dcircular(const ap::template_1d_array< amp::ampf<Precision> >& s,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& r,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& c);

### `convr1dcircularinv` function

    /*************************************************************************
    1-dimensional complex deconvolution (inverse of ConvC1D()).

    Algorithm has M*log(M)) complexity for any M (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..M-1] - convolved signal, A = conv(R, B)
        M   -   convolved signal length
        B   -   array[0..N-1] - response
        N   -   response length

    OUTPUT PARAMETERS
        R   -   deconvolved signal. array[0..M-N].

    NOTE:
        deconvolution is unstable process and may result in division  by  zero
    (if your response function is degenerate, i.e. has zero Fourier coefficient).

    NOTE:
        It is assumed that B is zero at T<0. If  it  has  non-zero  values  at
    negative T's, you can still use this subroutine - just  shift  its  result
    correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convr1dcircularinv(const ap::template_1d_array< amp::ampf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& r);

### `convr1dinv` function

    /*************************************************************************
    1-dimensional real deconvolution (inverse of ConvC1D()).

    Algorithm has M*log(M)) complexity for any M (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..M-1] - convolved signal, A = conv(R, B)
        M   -   convolved signal length
        B   -   array[0..N-1] - response
        N   -   response length, N<=M

    OUTPUT PARAMETERS
        R   -   deconvolved signal. array[0..M-N].

    NOTE:
        deconvolution is unstable process and may result in division  by  zero
    (if your response function is degenerate, i.e. has zero Fourier coefficient).

    NOTE:
        It is assumed that A is zero at T<0, B is zero too.  If  one  or  both
    functions have non-zero values at negative T's, you  can  still  use  this
    subroutine - just shift its result correspondingly.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convr1dinv(const ap::template_1d_array< amp::ampf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& r);

### `convr1dx` function

    /*************************************************************************
    1-dimensional real convolution.

    Extended subroutine which allows to choose convolution algorithm.
    Intended for internal use, ALGLIB users should call ConvR1D().

    INPUT PARAMETERS
        A   -   array[0..M-1] - complex function to be transformed
        M   -   problem size
        B   -   array[0..N-1] - complex function to be transformed
        N   -   problem size, N<=M
        Alg -   algorithm type:
                *-2     auto-select Q for overlap-add
                *-1     auto-select algorithm and parameters
                * 0     straightforward formula for small N's
                * 1     general FFT-based code
                * 2     overlap-add with length Q
        Q   -   length for overlap-add

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..N+M-1].

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void convr1dx(const ap::template_1d_array< amp::ampf<Precision> >& a,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int n,
        bool circular,
        int alg,
        int q,
        ap::template_1d_array< amp::ampf<Precision> >& r);

## `corr` unit

### Functions

corrc1d
corrc1dcircular
corrr1d
corrr1dcircular

### `corrc1d` function

    /*************************************************************************
    1-dimensional complex cross-correlation.

    For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).

    Correlation is calculated using reduction to  convolution.  Algorithm with
    max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
    about performance).

    IMPORTANT:
        for  historical reasons subroutine accepts its parameters in  reversed
        order: CorrC1D(Signal, Pattern) = Pattern x Signal (using  traditional
        definition of cross-correlation, denoting cross-correlation as "x").

    INPUT PARAMETERS
        Signal  -   array[0..N-1] - complex function to be transformed,
                    signal containing pattern
        N       -   problem size
        Pattern -   array[0..M-1] - complex function to be transformed,
                    pattern to search withing signal
        M       -   problem size

    OUTPUT PARAMETERS
        R       -   cross-correlation, array[0..N+M-2]:
                    * positive lags are stored in R[0..N-1],
                      R[i] = sum(conj(pattern[j])*signal[i+j]
                    * negative lags are stored in R[N..N+M-2],
                      R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]

    NOTE:
        It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
    on [-K..M-1],  you can still use this subroutine, just shift result by K.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void corrc1d(const ap::template_1d_array< amp::campf<Precision> >& signal,
        int n,
        const ap::template_1d_array< amp::campf<Precision> >& pattern,
        int m,
        ap::template_1d_array< amp::campf<Precision> >& r);

### `corrc1dcircular` function

    /*************************************************************************
    1-dimensional circular complex cross-correlation.

    For given Pattern/Signal returns corr(Pattern,Signal) (circular).
    Algorithm has linearithmic complexity for any M/N.

    IMPORTANT:
        for  historical reasons subroutine accepts its parameters in  reversed
        order:   CorrC1DCircular(Signal, Pattern) = Pattern x Signal    (using
        traditional definition of cross-correlation, denoting cross-correlation
        as "x").

    INPUT PARAMETERS
        Signal  -   array[0..N-1] - complex function to be transformed,
                    periodic signal containing pattern
        N       -   problem size
        Pattern -   array[0..M-1] - complex function to be transformed,
                    non-periodic pattern to search withing signal
        M       -   problem size

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..M-1].

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void corrc1dcircular(const ap::template_1d_array< amp::campf<Precision> >& signal,
        int m,
        const ap::template_1d_array< amp::campf<Precision> >& pattern,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& c);

### `corrr1d` function

    /*************************************************************************
    1-dimensional real cross-correlation.

    For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).

    Correlation is calculated using reduction to  convolution.  Algorithm with
    max(N,N)*log(max(N,N)) complexity is used (see  ConvC1D()  for  more  info
    about performance).

    IMPORTANT:
        for  historical reasons subroutine accepts its parameters in  reversed
        order: CorrR1D(Signal, Pattern) = Pattern x Signal (using  traditional
        definition of cross-correlation, denoting cross-correlation as "x").

    INPUT PARAMETERS
        Signal  -   array[0..N-1] - real function to be transformed,
                    signal containing pattern
        N       -   problem size
        Pattern -   array[0..M-1] - real function to be transformed,
                    pattern to search withing signal
        M       -   problem size

    OUTPUT PARAMETERS
        R       -   cross-correlation, array[0..N+M-2]:
                    * positive lags are stored in R[0..N-1],
                      R[i] = sum(pattern[j]*signal[i+j]
                    * negative lags are stored in R[N..N+M-2],
                      R[N+M-1-i] = sum(pattern[j]*signal[-i+j]

    NOTE:
        It is assumed that pattern domain is [0..M-1].  If Pattern is non-zero
    on [-K..M-1],  you can still use this subroutine, just shift result by K.

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void corrr1d(const ap::template_1d_array< amp::ampf<Precision> >& signal,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& pattern,
        int m,
        ap::template_1d_array< amp::ampf<Precision> >& r);

### `corrr1dcircular` function

    /*************************************************************************
    1-dimensional circular real cross-correlation.

    For given Pattern/Signal returns corr(Pattern,Signal) (circular).
    Algorithm has linearithmic complexity for any M/N.

    IMPORTANT:
        for  historical reasons subroutine accepts its parameters in  reversed
        order:   CorrR1DCircular(Signal, Pattern) = Pattern x Signal    (using
        traditional definition of cross-correlation, denoting cross-correlation
        as "x").

    INPUT PARAMETERS
        Signal  -   array[0..N-1] - real function to be transformed,
                    periodic signal containing pattern
        N       -   problem size
        Pattern -   array[0..M-1] - real function to be transformed,
                    non-periodic pattern to search withing signal
        M       -   problem size

    OUTPUT PARAMETERS
        R   -   convolution: A*B. array[0..M-1].

      -- ALGLIB --
         Copyright 21.07.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void corrr1dcircular(const ap::template_1d_array< amp::ampf<Precision> >& signal,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& pattern,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& c);

## `densesolver` unit

### Functions

cmatrixlusolve
cmatrixlusolvem
cmatrixmixedsolve
cmatrixmixedsolvem
cmatrixsolve
cmatrixsolvem
hpdmatrixcholeskysolve
hpdmatrixcholeskysolvem
hpdmatrixsolve
hpdmatrixsolvem
rmatrixlusolve
rmatrixlusolvem
rmatrixmixedsolve
rmatrixmixedsolvem
rmatrixsolve
rmatrixsolvels
rmatrixsolvem
spdmatrixcholeskysolve
spdmatrixcholeskysolvem
spdmatrixsolve
spdmatrixsolvem

### `cmatrixlusolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixLUSolve(), but for complex matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(N^2) complexity
    * condition number estimation

    No iterative refinement is provided because exact form of original matrix
    is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        LUA     -   array[0..N-1,0..N-1], LU decomposition, CMatrixLU result
        P       -   array[0..N-1], pivots array, CMatrixLU result
        N       -   size of A
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlusolve(const ap::template_2d_array< amp::campf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::campf<Precision> >& x);

### `cmatrixlusolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixLUSolveM(), but for complex matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(M*N^2) complexity
    * condition number estimation

    No iterative refinement  is provided because exact form of original matrix
    is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        LUA     -   array[0..N-1,0..N-1], LU decomposition, RMatrixLU result
        P       -   array[0..N-1], pivots array, RMatrixLU result
        N       -   size of A
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlusolvem(const ap::template_2d_array< amp::campf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::campf<Precision> >& x);

### `cmatrixmixedsolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixMixedSolve(), but for complex matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(N^2) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        LUA     -   array[0..N-1,0..N-1], LU decomposition, CMatrixLU result
        P       -   array[0..N-1], pivots array, CMatrixLU result
        N       -   size of A
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolveM
        Rep     -   same as in RMatrixSolveM
        X       -   same as in RMatrixSolveM

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixmixedsolve(const ap::template_2d_array< amp::campf<Precision> >& a,
        const ap::template_2d_array< amp::campf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::campf<Precision> >& x);

### `cmatrixmixedsolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(M*N^2) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        LUA     -   array[0..N-1,0..N-1], LU decomposition, CMatrixLU result
        P       -   array[0..N-1], pivots array, CMatrixLU result
        N       -   size of A
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolveM
        Rep     -   same as in RMatrixSolveM
        X       -   same as in RMatrixSolveM

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixmixedsolvem(const ap::template_2d_array< amp::campf<Precision> >& a,
        const ap::template_2d_array< amp::campf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::campf<Precision> >& x);

### `cmatrixsolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixSolve(), but for complex matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(N^3) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixsolve(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::campf<Precision> >& x);

### `cmatrixsolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixSolveM(), but for complex matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(N^3+M*N^2) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size
        RFS     -   iterative refinement switch:
                    * True - refinement is used.
                      Less performance, more precision.
                    * False - refinement is not used.
                      More performance, less precision.

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixsolvem(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        const ap::template_2d_array< amp::campf<Precision> >& b,
        int m,
        bool rfs,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::campf<Precision> >& x);

### `hpdmatrixcholeskysolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixLUSolve(), but for  HPD matrices  represented
    by their Cholesky decomposition.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(N^2) complexity
    * condition number estimation
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        CHA     -   array[0..N-1,0..N-1], Cholesky decomposition,
                    SPDMatrixCholesky result
        N       -   size of A
        IsUpper -   what half of CHA is provided
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixcholeskysolve(const ap::template_2d_array< amp::campf<Precision> >& cha,
        int n,
        bool isupper,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::campf<Precision> >& x);

### `hpdmatrixcholeskysolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices  represented
    by their Cholesky decomposition.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(M*N^2) complexity
    * condition number estimation
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        CHA     -   array[0..N-1,0..N-1], Cholesky decomposition,
                    HPDMatrixCholesky result
        N       -   size of CHA
        IsUpper -   what half of CHA is provided
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixcholeskysolvem(const ap::template_2d_array< amp::campf<Precision> >& cha,
        int n,
        bool isupper,
        const ap::template_2d_array< amp::campf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::campf<Precision> >& x);

### `hpdmatrixsolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixSolve(),  but for Hermitian positive definite
    matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * O(N^3) complexity
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        IsUpper -   what half of A is provided
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
                    Returns -3 for non-HPD matrices.
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixsolve(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        const ap::template_1d_array< amp::campf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::campf<Precision> >& x);

### `hpdmatrixsolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite
    matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * O(N^3+M*N^2) complexity
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        IsUpper -   what half of A is provided
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve.
                    Returns -3 for non-HPD matrices.
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixsolvem(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        const ap::template_2d_array< amp::campf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::campf<Precision> >& x);

### `rmatrixlusolve` function

    /*************************************************************************
    Dense solver.

    This  subroutine  solves  a  system  A*X=B,  where A is NxN non-denegerate
    real matrix given by its LU decomposition, X and B are NxM real matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(N^2) complexity
    * condition number estimation

    No iterative refinement  is provided because exact form of original matrix
    is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        LUA     -   array[0..N-1,0..N-1], LU decomposition, RMatrixLU result
        P       -   array[0..N-1], pivots array, RMatrixLU result
        N       -   size of A
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlusolve(const ap::template_2d_array< amp::ampf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `rmatrixlusolvem` function

    /*************************************************************************
    Dense solver.

    Similar to RMatrixLUSolve() but solves task with multiple right parts
    (where b and x are NxM matrices).

    Algorithm features:
    * automatic detection of degenerate cases
    * O(M*N^2) complexity
    * condition number estimation

    No iterative refinement  is provided because exact form of original matrix
    is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        LUA     -   array[0..N-1,0..N-1], LU decomposition, RMatrixLU result
        P       -   array[0..N-1], pivots array, RMatrixLU result
        N       -   size of A
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlusolvem(const ap::template_2d_array< amp::ampf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::ampf<Precision> >& x);

### `rmatrixmixedsolve` function

    /*************************************************************************
    Dense solver.

    This  subroutine  solves  a  system  A*x=b,  where BOTH ORIGINAL A AND ITS
    LU DECOMPOSITION ARE KNOWN. You can use it if for some  reasons  you  have
    both A and its LU decomposition.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(N^2) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        LUA     -   array[0..N-1,0..N-1], LU decomposition, RMatrixLU result
        P       -   array[0..N-1], pivots array, RMatrixLU result
        N       -   size of A
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolveM
        Rep     -   same as in RMatrixSolveM
        X       -   same as in RMatrixSolveM

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixmixedsolve(const ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_2d_array< amp::ampf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `rmatrixmixedsolvem` function

    /*************************************************************************
    Dense solver.

    Similar to RMatrixMixedSolve() but  solves task with multiple right  parts
    (where b and x are NxM matrices).

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(M*N^2) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        LUA     -   array[0..N-1,0..N-1], LU decomposition, RMatrixLU result
        P       -   array[0..N-1], pivots array, RMatrixLU result
        N       -   size of A
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolveM
        Rep     -   same as in RMatrixSolveM
        X       -   same as in RMatrixSolveM

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixmixedsolvem(const ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_2d_array< amp::ampf<Precision> >& lua,
        const ap::template_1d_array< int >& p,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::ampf<Precision> >& x);

### `rmatrixsolve` function

    /*************************************************************************
    Dense solver.

    This  subroutine  solves  a  system  A*x=b,  where A is NxN non-denegerate
    real matrix, x and b are vectors.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * iterative refinement
    * O(N^3) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   return code:
                    * -3    A is singular, or VERY close to singular.
                            X is filled by zeros in such cases.
                    * -1    N<=0 was passed
                    *  1    task is solved (but matrix A may be ill-conditioned,
                            check R1/RInf parameters for condition numbers).
        Rep     -   solver report, see below for more info
        X       -   array[0..N-1], it contains:
                    * solution of A*x=b if A is non-singular (well-conditioned
                      or ill-conditioned, but not very close to singular)
                    * zeros,  if  A  is  singular  or  VERY  close to singular
                      (in this case Info=-3).

    SOLVER REPORT

    Subroutine sets following fields of the Rep structure:
    * R1        reciprocal of condition number: 1/cond(A), 1-norm.
    * RInf      reciprocal of condition number: 1/cond(A), inf-norm.

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixsolve(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `rmatrixsolvels` function

    /*************************************************************************
    Dense solver.

    This subroutine finds solution of the linear system A*X=B with non-square,
    possibly degenerate A.  System  is  solved in the least squares sense, and
    general least squares solution  X = X0 + CX*y  which  minimizes |A*X-B| is
    returned. If A is non-degenerate, solution in the  usual sense is returned

    Algorithm features:
    * automatic detection of degenerate cases
    * iterative refinement
    * O(N^3) complexity

    INPUT PARAMETERS
        A       -   array[0..NRows-1,0..NCols-1], system matrix
        NRows   -   vertical size of A
        NCols   -   horizontal size of A
        B       -   array[0..NCols-1], right part
        Threshold-  a number in [0,1]. Singular values  beyond  Threshold  are
                    considered  zero.  Set  it to 0.0, if you don't understand
                    what it means, so the solver will choose good value on its
                    own.

    OUTPUT PARAMETERS
        Info    -   return code:
                    * -4    SVD subroutine failed
                    * -1    if NRows<=0 or NCols<=0 or Threshold<0 was passed
                    *  1    if task is solved
        Rep     -   solver report, see below for more info
        X       -   array[0..N-1,0..M-1], it contains:
                    * solution of A*X=B if A is non-singular (well-conditioned
                      or ill-conditioned, but not very close to singular)
                    * zeros,  if  A  is  singular  or  VERY  close to singular
                      (in this case Info=-3).

    SOLVER REPORT

    Subroutine sets following fields of the Rep structure:
    * R2        reciprocal of condition number: 1/cond(A), 2-norm.
    * N         = NCols
    * K         dim(Null(A))
    * CX        array[0..N-1,0..K-1], kernel of A.
                Columns of CX store such vectors that A*CX[i]=0.

      -- ALGLIB --
         Copyright 24.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixsolvels(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int nrows,
        int ncols,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        amp::ampf<Precision> threshold,
        int& info,
        densesolverlsreport<Precision>& rep,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `rmatrixsolvem` function

    /*************************************************************************
    Dense solver.

    Similar to RMatrixSolve() but solves task with multiple right parts (where
    b and x are NxM matrices).

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * optional iterative refinement
    * O(N^3+M*N^2) complexity

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size
        RFS     -   iterative refinement switch:
                    * True - refinement is used.
                      Less performance, more precision.
                    * False - refinement is not used.
                      More performance, less precision.

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixsolvem(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        int m,
        bool rfs,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::ampf<Precision> >& x);

### `spdmatrixcholeskysolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixLUSolve(), but for  SPD matrices  represented
    by their Cholesky decomposition.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(N^2) complexity
    * condition number estimation
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        CHA     -   array[0..N-1,0..N-1], Cholesky decomposition,
                    SPDMatrixCholesky result
        N       -   size of A
        IsUpper -   what half of CHA is provided
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixcholeskysolve(const ap::template_2d_array< amp::ampf<Precision> >& cha,
        int n,
        bool isupper,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `spdmatrixcholeskysolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices  represented
    by their Cholesky decomposition.

    Algorithm features:
    * automatic detection of degenerate cases
    * O(M*N^2) complexity
    * condition number estimation
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        CHA     -   array[0..N-1,0..N-1], Cholesky decomposition,
                    SPDMatrixCholesky result
        N       -   size of CHA
        IsUpper -   what half of CHA is provided
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixcholeskysolvem(const ap::template_2d_array< amp::ampf<Precision> >& cha,
        int n,
        bool isupper,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::ampf<Precision> >& x);

### `spdmatrixsolve` function

    /*************************************************************************
    Dense solver. Same as RMatrixSolve(), but for SPD matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * O(N^3) complexity
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        IsUpper -   what half of A is provided
        B       -   array[0..N-1], right part

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve
                    Returns -3 for non-SPD matrices.
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixsolve(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `spdmatrixsolvem` function

    /*************************************************************************
    Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite
    matrices.

    Algorithm features:
    * automatic detection of degenerate cases
    * condition number estimation
    * O(N^3+M*N^2) complexity
    * matrix is represented by its upper or lower triangle

    No iterative refinement is provided because such partial representation of
    matrix does not allow efficient calculation of extra-precise  matrix-vector
    products for large matrices. Use RMatrixSolve or RMatrixMixedSolve  if  you
    need iterative refinement.

    INPUT PARAMETERS
        A       -   array[0..N-1,0..N-1], system matrix
        N       -   size of A
        IsUpper -   what half of A is provided
        B       -   array[0..N-1,0..M-1], right part
        M       -   right part size

    OUTPUT PARAMETERS
        Info    -   same as in RMatrixSolve.
                    Returns -3 for non-SPD matrices.
        Rep     -   same as in RMatrixSolve
        X       -   same as in RMatrixSolve

      -- ALGLIB --
         Copyright 27.01.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixsolvem(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        int m,
        int& info,
        densesolverreport<Precision>& rep,
        ap::template_2d_array< amp::ampf<Precision> >& x);

## `evd` unit

### Functions

hmatrixevd
hmatrixevdi
hmatrixevdr
rmatrixevd
smatrixevd
smatrixevdi
smatrixevdr
smatrixtdevd
smatrixtdevdi
smatrixtdevdr

### `hmatrixevd` function

    /*************************************************************************
    Finding the eigenvalues and eigenvectors of a Hermitian matrix

    The algorithm finds eigen pairs of a Hermitian matrix by  reducing  it  to
    real tridiagonal form and using the QL/QR algorithm.

    Input parameters:
        A       -   Hermitian matrix which is given  by  its  upper  or  lower
                    triangular part.
                    Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.
        ZNeeded -   flag controlling whether the eigenvectors  are  needed  or
                    not. If ZNeeded is equal to:
                     * 0, the eigenvectors are not returned;
                     * 1, the eigenvectors are returned.

    Output parameters:
        D       -   eigenvalues in ascending order.
                    Array whose index ranges within [0..N-1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains the eigenvectors.
                    Array whose indexes range within [0..N-1, 0..N-1].
                    The eigenvectors are stored in the matrix columns.

    Result:
        True, if the algorithm has converged.
        False, if the algorithm hasn't converged (rare case).

    Note:
        eigenvectors of Hermitian matrix are defined up to  multiplication  by
        a complex number L, such that |L|=1.

      -- ALGLIB --
         Copyright 2005, 23 March 2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool hmatrixevd(ap::template_2d_array< amp::campf<Precision> > a,
        int n,
        int zneeded,
        bool isupper,
        ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_2d_array< amp::campf<Precision> >& z);

### `hmatrixevdi` function

    /*************************************************************************
    Subroutine for finding the eigenvalues and  eigenvectors  of  a  Hermitian
    matrix with given indexes by using bisection and inverse iteration methods

    Input parameters:
        A       -   Hermitian matrix which is given  by  its  upper  or  lower
                    triangular part.
                    Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        ZNeeded -   flag controlling whether the eigenvectors  are  needed  or
                    not. If ZNeeded is equal to:
                     * 0, the eigenvectors are not returned;
                     * 1, the eigenvectors are returned.
        IsUpperA -  storage format of matrix A.
        I1, I2 -    index interval for searching (from I1 to I2).
                    0 <= I1 <= I2 <= N-1.

    Output parameters:
        W       -   array of the eigenvalues found.
                    Array whose index ranges within [0..I2-I1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains eigenvectors.
                    Array whose indexes range within [0..N-1, 0..I2-I1].
                    In  that  case,  the eigenvectors are stored in the matrix
                    columns.

    Result:
        True, if successful. W contains the eigenvalues, Z contains the
        eigenvectors (if needed).

        False, if the bisection method subroutine  wasn't  able  to  find  the
        eigenvalues  in  the  given  interval  or  if  the  inverse  iteration
        subroutine wasn't able to find  all  the  corresponding  eigenvectors.
        In that case, the eigenvalues and eigenvectors are not returned.

    Note:
        eigen vectors of Hermitian matrix are defined up to multiplication  by
        a complex number L, such as |L|=1.

      -- ALGLIB --
         Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey.
    *************************************************************************/
    template<unsigned int Precision>
    bool hmatrixevdi(ap::template_2d_array< amp::campf<Precision> > a,
        int n,
        int zneeded,
        bool isupper,
        int i1,
        int i2,
        ap::template_1d_array< amp::ampf<Precision> >& w,
        ap::template_2d_array< amp::campf<Precision> >& z);

### `hmatrixevdr` function

    /*************************************************************************
    Subroutine for finding the eigenvalues (and eigenvectors) of  a  Hermitian
    matrix  in  a  given half-interval (A, B] by using a bisection and inverse
    iteration

    Input parameters:
        A       -   Hermitian matrix which is given  by  its  upper  or  lower
                    triangular  part.  Array  whose   indexes   range   within
                    [0..N-1, 0..N-1].
        N       -   size of matrix A.
        ZNeeded -   flag controlling whether the eigenvectors  are  needed  or
                    not. If ZNeeded is equal to:
                     * 0, the eigenvectors are not returned;
                     * 1, the eigenvectors are returned.
        IsUpperA -  storage format of matrix A.
        B1, B2 -    half-interval (B1, B2] to search eigenvalues in.

    Output parameters:
        M       -   number of eigenvalues found in a given half-interval, M>=0
        W       -   array of the eigenvalues found.
                    Array whose index ranges within [0..M-1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains eigenvectors.
                    Array whose indexes range within [0..N-1, 0..M-1].
                    The eigenvectors are stored in the matrix columns.

    Result:
        True, if successful. M contains the number of eigenvalues in the given
        half-interval (could be equal to 0), W contains the eigenvalues,
        Z contains the eigenvectors (if needed).

        False, if the bisection method subroutine  wasn't  able  to  find  the
        eigenvalues  in  the  given  interval  or  if  the  inverse  iteration
        subroutine  wasn't  able  to  find all the corresponding eigenvectors.
        In that case, the eigenvalues and eigenvectors are not returned, M  is
        equal to 0.

    Note:
        eigen vectors of Hermitian matrix are defined up to multiplication  by
        a complex number L, such as |L|=1.

      -- ALGLIB --
         Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey.
    *************************************************************************/
    template<unsigned int Precision>
    bool hmatrixevdr(ap::template_2d_array< amp::campf<Precision> > a,
        int n,
        int zneeded,
        bool isupper,
        amp::ampf<Precision> b1,
        amp::ampf<Precision> b2,
        int& m,
        ap::template_1d_array< amp::ampf<Precision> >& w,
        ap::template_2d_array< amp::campf<Precision> >& z);

### `rmatrixevd` function

    /*************************************************************************
    Finding eigenvalues and eigenvectors of a general matrix

    The algorithm finds eigenvalues and eigenvectors of a general matrix by
    using the QR algorithm with multiple shifts. The algorithm can find
    eigenvalues and both left and right eigenvectors.

    The right eigenvector is a vector x such that A*x = w*x, and the left
    eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex
    conjugate transposition of vector y).

    Input parameters:
        A       -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        VNeeded -   flag controlling whether eigenvectors are needed or not.
                    If VNeeded is equal to:
                     * 0, eigenvectors are not returned;
                     * 1, right eigenvectors are returned;
                     * 2, left eigenvectors are returned;
                     * 3, both left and right eigenvectors are returned.

    Output parameters:
        WR      -   real parts of eigenvalues.
                    Array whose index ranges within [0..N-1].
        WR      -   imaginary parts of eigenvalues.
                    Array whose index ranges within [0..N-1].
        VL, VR  -   arrays of left and right eigenvectors (if they are needed).
                    If WI[i]=0, the respective eigenvalue is a real number,
                    and it corresponds to the column number I of matrices VL/VR.
                    If WI[i]>0, we have a pair of complex conjugate numbers with
                    positive and negative imaginary parts:
                        the first eigenvalue WR[i] + sqrt(-1)*WI[i];
                        the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1];
                        WI[i]>0
                        WI[i+1] = -WI[i] < 0
                    In that case, the eigenvector  corresponding to the first
                    eigenvalue is located in i and i+1 columns of matrices
                    VL/VR (the column number i contains the real part, and the
                    column number i+1 contains the imaginary part), and the vector
                    corresponding to the second eigenvalue is a complex conjugate to
                    the first vector.
                    Arrays whose indexes range within [0..N-1, 0..N-1].

    Result:
        True, if the algorithm has converged.
        False, if the algorithm has not converged.

    Note 1:
        Some users may ask the following question: what if WI[N-1]>0?
        WI[N] must contain an eigenvalue which is complex conjugate to the
        N-th eigenvalue, but the array has only size N?
        The answer is as follows: such a situation cannot occur because the
        algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is
        strictly less than N-1.

    Note 2:
        The algorithm performance depends on the value of the internal parameter
        NS of the InternalSchurDecomposition subroutine which defines the number
        of shifts in the QR algorithm (similarly to the block width in block-matrix
        algorithms of linear algebra). If you require maximum performance
        on your machine, it is recommended to adjust this parameter manually.

    See also the InternalTREVC subroutine.

    The algorithm is based on the LAPACK 3.0 library.
    *************************************************************************/
    template<unsigned int Precision>
    bool rmatrixevd(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        int vneeded,
        ap::template_1d_array< amp::ampf<Precision> >& wr,
        ap::template_1d_array< amp::ampf<Precision> >& wi,
        ap::template_2d_array< amp::ampf<Precision> >& vl,
        ap::template_2d_array< amp::ampf<Precision> >& vr);

### `smatrixevd` function

    /*************************************************************************
    Finding the eigenvalues and eigenvectors of a symmetric matrix

    The algorithm finds eigen pairs of a symmetric matrix by reducing it to
    tridiagonal form and using the QL/QR algorithm.

    Input parameters:
        A       -   symmetric matrix which is given by its upper or lower
                    triangular part.
                    Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.
        ZNeeded -   flag controlling whether the eigenvectors are needed or not.
                    If ZNeeded is equal to:
                     * 0, the eigenvectors are not returned;
                     * 1, the eigenvectors are returned.

    Output parameters:
        D       -   eigenvalues in ascending order.
                    Array whose index ranges within [0..N-1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains the eigenvectors.
                    Array whose indexes range within [0..N-1, 0..N-1].
                    The eigenvectors are stored in the matrix columns.

    Result:
        True, if the algorithm has converged.
        False, if the algorithm hasn't converged (rare case).

      -- ALGLIB --
         Copyright 2005-2008 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixevd(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        int zneeded,
        bool isupper,
        ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_2d_array< amp::ampf<Precision> >& z);

### `smatrixevdi` function

    /*************************************************************************
    Subroutine for finding the eigenvalues and  eigenvectors  of  a  symmetric
    matrix with given indexes by using bisection and inverse iteration methods.

    Input parameters:
        A       -   symmetric matrix which is given by its upper or lower
                    triangular part. Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        ZNeeded -   flag controlling whether the eigenvectors are needed or not.
                    If ZNeeded is equal to:
                     * 0, the eigenvectors are not returned;
                     * 1, the eigenvectors are returned.
        IsUpperA -  storage format of matrix A.
        I1, I2 -    index interval for searching (from I1 to I2).
                    0 <= I1 <= I2 <= N-1.

    Output parameters:
        W       -   array of the eigenvalues found.
                    Array whose index ranges within [0..I2-I1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains eigenvectors.
                    Array whose indexes range within [0..N-1, 0..I2-I1].
                    In that case, the eigenvectors are stored in the matrix columns.

    Result:
        True, if successful. W contains the eigenvalues, Z contains the
        eigenvectors (if needed).

        False, if the bisection method subroutine wasn't able to find the
        eigenvalues in the given interval or if the inverse iteration subroutine
        wasn't able to find all the corresponding eigenvectors.
        In that case, the eigenvalues and eigenvectors are not returned.

      -- ALGLIB --
         Copyright 07.01.2006 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixevdi(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        int zneeded,
        bool isupper,
        int i1,
        int i2,
        ap::template_1d_array< amp::ampf<Precision> >& w,
        ap::template_2d_array< amp::ampf<Precision> >& z);

### `smatrixevdr` function

    /*************************************************************************
    Subroutine for finding the eigenvalues (and eigenvectors) of  a  symmetric
    matrix  in  a  given half open interval (A, B] by using  a  bisection  and
    inverse iteration

    Input parameters:
        A       -   symmetric matrix which is given by its upper or lower
                    triangular part. Array [0..N-1, 0..N-1].
        N       -   size of matrix A.
        ZNeeded -   flag controlling whether the eigenvectors are needed or not.
                    If ZNeeded is equal to:
                     * 0, the eigenvectors are not returned;
                     * 1, the eigenvectors are returned.
        IsUpperA -  storage format of matrix A.
        B1, B2 -    half open interval (B1, B2] to search eigenvalues in.

    Output parameters:
        M       -   number of eigenvalues found in a given half-interval (M>=0).
        W       -   array of the eigenvalues found.
                    Array whose index ranges within [0..M-1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains eigenvectors.
                    Array whose indexes range within [0..N-1, 0..M-1].
                    The eigenvectors are stored in the matrix columns.

    Result:
        True, if successful. M contains the number of eigenvalues in the given
        half-interval (could be equal to 0), W contains the eigenvalues,
        Z contains the eigenvectors (if needed).

        False, if the bisection method subroutine wasn't able to find the
        eigenvalues in the given interval or if the inverse iteration subroutine
        wasn't able to find all the corresponding eigenvectors.
        In that case, the eigenvalues and eigenvectors are not returned,
        M is equal to 0.

      -- ALGLIB --
         Copyright 07.01.2006 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixevdr(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        int zneeded,
        bool isupper,
        amp::ampf<Precision> b1,
        amp::ampf<Precision> b2,
        int& m,
        ap::template_1d_array< amp::ampf<Precision> >& w,
        ap::template_2d_array< amp::ampf<Precision> >& z);

### `smatrixtdevd` function

    /*************************************************************************
    Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix

    The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by
    using an QL/QR algorithm with implicit shifts.

    Input parameters:
        D       -   the main diagonal of a tridiagonal matrix.
                    Array whose index ranges within [0..N-1].
        E       -   the secondary diagonal of a tridiagonal matrix.
                    Array whose index ranges within [0..N-2].
        N       -   size of matrix A.
        ZNeeded -   flag controlling whether the eigenvectors are needed or not.
                    If ZNeeded is equal to:
                     * 0, the eigenvectors are not needed;
                     * 1, the eigenvectors of a tridiagonal matrix
                       are multiplied by the square matrix Z. It is used if the
                       tridiagonal matrix is obtained by the similarity
                       transformation of a symmetric matrix;
                     * 2, the eigenvectors of a tridiagonal matrix replace the
                       square matrix Z;
                     * 3, matrix Z contains the first row of the eigenvectors
                       matrix.
        Z       -   if ZNeeded=1, Z contains the square matrix by which the
                    eigenvectors are multiplied.
                    Array whose indexes range within [0..N-1, 0..N-1].

    Output parameters:
        D       -   eigenvalues in ascending order.
                    Array whose index ranges within [0..N-1].
        Z       -   if ZNeeded is equal to:
                     * 0, Z hasn’t changed;
                     * 1, Z contains the product of a given matrix (from the left)
                       and the eigenvectors matrix (from the right);
                     * 2, Z contains the eigenvectors.
                     * 3, Z contains the first row of the eigenvectors matrix.
                    If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1].
                    In that case, the eigenvectors are stored in the matrix columns.
                    If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1].

    Result:
        True, if the algorithm has converged.
        False, if the algorithm hasn't converged.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         September 30, 1994
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixtdevd(ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_1d_array< amp::ampf<Precision> > e,
        int n,
        int zneeded,
        ap::template_2d_array< amp::ampf<Precision> >& z);

### `smatrixtdevdi` function

    /*************************************************************************
    Subroutine for finding tridiagonal matrix eigenvalues/vectors with given
    indexes (in ascending order) by using the bisection and inverse iteraion.

    Input parameters:
        D       -   the main diagonal of a tridiagonal matrix.
                    Array whose index ranges within [0..N-1].
        E       -   the secondary diagonal of a tridiagonal matrix.
                    Array whose index ranges within [0..N-2].
        N       -   size of matrix. N>=0.
        ZNeeded -   flag controlling whether the eigenvectors are needed or not.
                    If ZNeeded is equal to:
                     * 0, the eigenvectors are not needed;
                     * 1, the eigenvectors of a tridiagonal matrix are multiplied
                       by the square matrix Z. It is used if the
                       tridiagonal matrix is obtained by the similarity transformation
                       of a symmetric matrix.
                     * 2, the eigenvectors of a tridiagonal matrix replace
                       matrix Z.
        I1, I2  -   index interval for searching (from I1 to I2).
                    0 <= I1 <= I2 <= N-1.
        Z       -   if ZNeeded is equal to:
                     * 0, Z isn't used and remains unchanged;
                     * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1])
                       which reduces the given symmetric matrix to  tridiagonal form;
                     * 2, Z isn't used (but changed on the exit).

    Output parameters:
        D       -   array of the eigenvalues found.
                    Array whose index ranges within [0..I2-I1].
        Z       -   if ZNeeded is equal to:
                     * 0, doesn't contain any information;
                     * 1, contains the product of a given NxN matrix Z (from the left) and
                       Nx(I2-I1) matrix of the eigenvectors found (from the right).
                       Array whose indexes range within [0..N-1, 0..I2-I1].
                     * 2, contains the matrix of the eigenvalues found.
                       Array whose indexes range within [0..N-1, 0..I2-I1].

    Result:

        True, if successful. In that case, D contains the eigenvalues,
        Z contains the eigenvectors (if needed).
        It should be noted that the subroutine changes the size of arrays D and Z.

        False, if the bisection method subroutine wasn't able to find the eigenvalues
        in the given interval or if the inverse iteration subroutine wasn't able
        to find all the corresponding eigenvectors. In that case, the eigenvalues
        and eigenvectors are not returned.

      -- ALGLIB --
         Copyright 25.12.2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixtdevdi(ap::template_1d_array< amp::ampf<Precision> >& d,
        const ap::template_1d_array< amp::ampf<Precision> >& e,
        int n,
        int zneeded,
        int i1,
        int i2,
        ap::template_2d_array< amp::ampf<Precision> >& z);

### `smatrixtdevdr` function

    /*************************************************************************
    Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a
    given half-interval (A, B] by using bisection and inverse iteration.

    Input parameters:
        D       -   the main diagonal of a tridiagonal matrix.
                    Array whose index ranges within [0..N-1].
        E       -   the secondary diagonal of a tridiagonal matrix.
                    Array whose index ranges within [0..N-2].
        N       -   size of matrix, N>=0.
        ZNeeded -   flag controlling whether the eigenvectors are needed or not.
                    If ZNeeded is equal to:
                     * 0, the eigenvectors are not needed;
                     * 1, the eigenvectors of a tridiagonal matrix are multiplied
                       by the square matrix Z. It is used if the tridiagonal
                       matrix is obtained by the similarity transformation
                       of a symmetric matrix.
                     * 2, the eigenvectors of a tridiagonal matrix replace matrix Z.
        A, B    -   half-interval (A, B] to search eigenvalues in.
        Z       -   if ZNeeded is equal to:
                     * 0, Z isn't used and remains unchanged;
                     * 1, Z contains the square matrix (array whose indexes range
                       within [0..N-1, 0..N-1]) which reduces the given symmetric
                       matrix to tridiagonal form;
                     * 2, Z isn't used (but changed on the exit).

    Output parameters:
        D       -   array of the eigenvalues found.
                    Array whose index ranges within [0..M-1].
        M       -   number of eigenvalues found in the given half-interval (M>=0).
        Z       -   if ZNeeded is equal to:
                     * 0, doesn't contain any information;
                     * 1, contains the product of a given NxN matrix Z (from the
                       left) and NxM matrix of the eigenvectors found (from the
                       right). Array whose indexes range within [0..N-1, 0..M-1].
                     * 2, contains the matrix of the eigenvectors found.
                       Array whose indexes range within [0..N-1, 0..M-1].

    Result:

        True, if successful. In that case, M contains the number of eigenvalues
        in the given half-interval (could be equal to 0), D contains the eigenvalues,
        Z contains the eigenvectors (if needed).
        It should be noted that the subroutine changes the size of arrays D and Z.

        False, if the bisection method subroutine wasn't able to find the
        eigenvalues in the given interval or if the inverse iteration subroutine
        wasn't able to find all the corresponding eigenvectors. In that case,
        the eigenvalues and eigenvectors are not returned, M is equal to 0.

      -- ALGLIB --
         Copyright 31.03.2008 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixtdevdr(ap::template_1d_array< amp::ampf<Precision> >& d,
        const ap::template_1d_array< amp::ampf<Precision> >& e,
        int n,
        int zneeded,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        int& m,
        ap::template_2d_array< amp::ampf<Precision> >& z);

## `fft` unit

### Functions

fftc1d
fftc1dinv
fftr1d
fftr1dinternaleven
fftr1dinv
fftr1dinvinternaleven

### `fftc1d` function

    /*************************************************************************
    1-dimensional complex FFT.

    Array size N may be arbitrary number (composite or prime).  Composite  N's
    are handled with cache-oblivious variation of  a  Cooley-Tukey  algorithm.
    Small prime-factors are transformed using hard coded  codelets (similar to
    FFTW codelets, but without low-level  optimization),  large  prime-factors
    are handled with Bluestein's algorithm.

    Fastests transforms are for smooth N's (prime factors are 2, 3,  5  only),
    most fast for powers of 2. When N have prime factors  larger  than  these,
    but orders of magnitude smaller than N, computations will be about 4 times
    slower than for nearby highly composite N's. When N itself is prime, speed
    will be 6 times lower.

    Algorithm has O(N*logN) complexity for any N (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..N-1] - complex function to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        A   -   DFT of a input array, array[0..N-1]
                A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)

      -- ALGLIB --
         Copyright 29.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fftc1d(ap::template_1d_array< amp::campf<Precision> >& a,
        int n);

### `fftc1dinv` function

    /*************************************************************************
    1-dimensional complex inverse FFT.

    Array size N may be arbitrary number (composite or prime).  Algorithm  has
    O(N*logN) complexity for any N (composite or prime).

    See FFTC1D() description for more information about algorithm performance.

    INPUT PARAMETERS
        A   -   array[0..N-1] - complex array to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        A   -   inverse DFT of a input array, array[0..N-1]
                A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)

      -- ALGLIB --
         Copyright 29.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fftc1dinv(ap::template_1d_array< amp::campf<Precision> >& a,
        int n);

### `fftr1d` function

    /*************************************************************************
    1-dimensional real FFT.

    Algorithm has O(N*logN) complexity for any N (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..N-1] - real function to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        F   -   DFT of a input array, array[0..N-1]
                F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)

    NOTE:
        F[] satisfies symmetry property F[k] = conj(F[N-k]),  so just one half
    of  array  is  usually needed. But for convinience subroutine returns full
    complex array (with frequencies above N/2), so its result may be  used  by
    other FFT-related subroutines.

      -- ALGLIB --
         Copyright 01.06.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fftr1d(const ap::template_1d_array< amp::ampf<Precision> >& a,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& f);

### `fftr1dinternaleven` function

    /*************************************************************************
    Internal subroutine. Never call it directly!

      -- ALGLIB --
         Copyright 01.06.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fftr1dinternaleven(ap::template_1d_array< amp::ampf<Precision> >& a,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& buf,
        ftbase::ftplan<Precision>& plan);

### `fftr1dinv` function

    /*************************************************************************
    1-dimensional real inverse FFT.

    Algorithm has O(N*logN) complexity for any N (composite or prime).

    INPUT PARAMETERS
        F   -   array[0..floor(N/2)] - frequencies from forward real FFT
        N   -   problem size

    OUTPUT PARAMETERS
        A   -   inverse DFT of a input array, array[0..N-1]

    NOTE:
        F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just  one
    half of frequencies array is needed - elements from 0 to floor(N/2).  F[0]
    is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd,  then
    F[floor(N/2)] has no special properties.

    Relying on properties noted above, FFTR1DInv subroutine uses only elements
    from 0th to floor(N/2)-th. It ignores imaginary part of F[0],  and in case
    N is even it ignores imaginary part of F[floor(N/2)] too.  So you can pass
    either frequencies array with N elements or reduced array with roughly N/2
    elements - subroutine will successfully transform both.

      -- ALGLIB --
         Copyright 01.06.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fftr1dinv(const ap::template_1d_array< amp::campf<Precision> >& f,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& a);

### `fftr1dinvinternaleven` function

    /*************************************************************************
    Internal subroutine. Never call it directly!

      -- ALGLIB --
         Copyright 01.06.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fftr1dinvinternaleven(ap::template_1d_array< amp::ampf<Precision> >& a,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& buf,
        ftbase::ftplan<Precision>& plan);

## `fht` unit

### Functions

fhtr1d
fhtr1dinv

### `fhtr1d` function

    /*************************************************************************
    1-dimensional Fast Hartley Transform.

    Algorithm has O(N*logN) complexity for any N (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..N-1] - real function to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        A   -   FHT of a input array, array[0..N-1],
                A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)

      -- ALGLIB --
         Copyright 04.06.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fhtr1d(ap::template_1d_array< amp::ampf<Precision> >& a,
        int n);

### `fhtr1dinv` function

    /*************************************************************************
    1-dimensional inverse FHT.

    Algorithm has O(N*logN) complexity for any N (composite or prime).

    INPUT PARAMETERS
        A   -   array[0..N-1] - complex array to be transformed
        N   -   problem size

    OUTPUT PARAMETERS
        A   -   inverse FHT of a input array, array[0..N-1]

      -- ALGLIB --
         Copyright 29.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void fhtr1dinv(ap::template_1d_array< amp::ampf<Precision> >& a,
        int n);

## `gkq` unit

### Functions

gkqgenerategaussjacobi
gkqgenerategausslegendre
gkqgeneraterec
gkqlegendrecalc
gkqlegendretbl

### `gkqgenerategaussjacobi` function

    /*************************************************************************
    Returns   Gauss   and   Gauss-Kronrod   nodes/weights   for   Gauss-Jacobi
    quadrature on [-1,1] with weight function

        W(x)=Power(1-x,Alpha)*Power(1+x,Beta).

    INPUT PARAMETERS:
        N           -   number of Kronrod nodes, must be odd number, >=3.
        Alpha       -   power-law coefficient, Alpha>-1
        Beta        -   power-law coefficient, Beta>-1

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -5    no real and positive Gauss-Kronrod formula can
                                be created for such a weight function  with  a
                                given number of nodes.
                        * -4    an  error  was   detected   when   calculating
                                weights/nodes. Alpha or  Beta  are  too  close
                                to -1 to obtain weights/nodes with high enough
                                accuracy, or, may be, N is too large.  Try  to
                                use multiple precision version.
                        * -3    internal eigenproblem solver hasn't converged
                        * -1    incorrect N was passed
                        * +1    OK
                        * +2    OK, but quadrature rule have exterior  nodes,
                                x[0]<-1 or x[n-1]>+1
        X           -   array[0..N-1] - array of quadrature nodes, ordered in
                        ascending order.
        WKronrod    -   array[0..N-1] - Kronrod weights
        WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
                        corresponding to extended Kronrod nodes).

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gkqgenerategaussjacobi(int n,
        amp::ampf<Precision> alpha,
        amp::ampf<Precision> beta,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& wkronrod,
        ap::template_1d_array< amp::ampf<Precision> >& wgauss);

### `gkqgenerategausslegendre` function

    /*************************************************************************
    Returns   Gauss   and   Gauss-Kronrod   nodes/weights  for  Gauss-Legendre
    quadrature with N points.

    GKQLegendreCalc (calculation) or  GKQLegendreTbl  (precomputed  table)  is
    used depending on machine precision and number of nodes.

    INPUT PARAMETERS:
        N           -   number of Kronrod nodes, must be odd number, >=3.

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -4    an  error   was   detected   when  calculating
                                weights/nodes.  N  is  too  large   to  obtain
                                weights/nodes  with  high   enough   accuracy.
                                Try  to   use   multiple   precision  version.
                        * -3    internal eigenproblem solver hasn't converged
                        * -1    incorrect N was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes, ordered in
                        ascending order.
        WKronrod    -   array[0..N-1] - Kronrod weights
        WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
                        corresponding to extended Kronrod nodes).

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gkqgenerategausslegendre(int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& wkronrod,
        ap::template_1d_array< amp::ampf<Precision> >& wgauss);

### `gkqgeneraterec` function

    /*************************************************************************
    Computation of nodes and weights of a Gauss-Kronrod quadrature formula

    The algorithm generates the N-point Gauss-Kronrod quadrature formula  with
    weight  function  given  by  coefficients  alpha  and beta of a recurrence
    relation which generates a system of orthogonal polynomials:

        P-1(x)   =  0
        P0(x)    =  1
        Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)

    and zero moment Mu0

        Mu0 = integral(W(x)dx,a,b)

    INPUT PARAMETERS:
        Alpha       –   alpha coefficients, array[0..floor(3*K/2)].
        Beta        –   beta coefficients,  array[0..ceil(3*K/2)].
                        Beta[0] is not used and may be arbitrary.
                        Beta[I]>0.
        Mu0         –   zeroth moment of the weight function.
        N           –   number of nodes of the Gauss-Kronrod quadrature formula,
                        N >= 3,
                        N =  2*K+1.

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -5    no real and positive Gauss-Kronrod formula can
                                be created for such a weight function  with  a
                                given number of nodes.
                        * -4    N is too large, task may be ill  conditioned -
                                x[i]=x[i+1] found.
                        * -3    internal eigenproblem solver hasn't converged
                        * -2    Beta[i]<=0
                        * -1    incorrect N was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes,
                        in ascending order.
        WKronrod    -   array[0..N-1] - Kronrod weights
        WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
                        corresponding to extended Kronrod nodes).

      -- ALGLIB --
         Copyright 08.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gkqgeneraterec(ap::template_1d_array< amp::ampf<Precision> > alpha,
        ap::template_1d_array< amp::ampf<Precision> > beta,
        amp::ampf<Precision> mu0,
        int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& wkronrod,
        ap::template_1d_array< amp::ampf<Precision> >& wgauss);

### `gkqlegendrecalc` function

    /*************************************************************************
    Returns Gauss and Gauss-Kronrod nodes for quadrature with N points.

    Reduction to tridiagonal eigenproblem is used.

    INPUT PARAMETERS:
        N           -   number of Kronrod nodes, must be odd number, >=3.

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -4    an  error   was   detected   when  calculating
                                weights/nodes.  N  is  too  large   to  obtain
                                weights/nodes  with  high   enough   accuracy.
                                Try  to   use   multiple   precision  version.
                        * -3    internal eigenproblem solver hasn't converged
                        * -1    incorrect N was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes, ordered in
                        ascending order.
        WKronrod    -   array[0..N-1] - Kronrod weights
        WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
                        corresponding to extended Kronrod nodes).

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gkqlegendrecalc(int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& wkronrod,
        ap::template_1d_array< amp::ampf<Precision> >& wgauss);

### `gkqlegendretbl` function

    /*************************************************************************
    Returns Gauss and Gauss-Kronrod nodes for quadrature with N  points  using
    pre-calculated table. Nodes/weights were  computed  with  accuracy  up  to
    1.0E-32 (if MPFR version of ALGLIB is used). In standard double  precision
    accuracy reduces to something about 2.0E-16 (depending  on your compiler's
    handling of long floating point constants).

    INPUT PARAMETERS:
        N           -   number of Kronrod nodes.
                        N can be 15, 21, 31, 41, 51, 61.

    OUTPUT PARAMETERS:
        X           -   array[0..N-1] - array of quadrature nodes, ordered in
                        ascending order.
        WKronrod    -   array[0..N-1] - Kronrod weights
        WGauss      -   array[0..N-1] - Gauss weights (interleaved with zeros
                        corresponding to extended Kronrod nodes).

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gkqlegendretbl(int n,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& wkronrod,
        ap::template_1d_array< amp::ampf<Precision> >& wgauss,
        amp::ampf<Precision>& eps);

## `gq` unit

### Functions

gqgenerategausshermite
gqgenerategaussjacobi
gqgenerategausslaguerre
gqgenerategausslegendre
gqgenerategausslobattorec
gqgenerategaussradaurec
gqgeneraterec

### `gqgenerategausshermite` function

    /*************************************************************************
    Returns  nodes/weights  for  Gauss-Hermite  quadrature on (-inf,+inf) with
    weight function W(x)=Exp(-x*x)

    INPUT PARAMETERS:
        N           -   number of nodes, >=1

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -4    an  error  was   detected   when   calculating
                                weights/nodes.  May be, N is too large. Try to
                                use multiple precision version.
                        * -3    internal eigenproblem solver hasn't converged
                        * -1    incorrect N/Alpha was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes,
                        in ascending order.
        W           -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgenerategausshermite(int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `gqgenerategaussjacobi` function

    /*************************************************************************
    Returns  nodes/weights  for  Gauss-Jacobi quadrature on [-1,1] with weight
    function W(x)=Power(1-x,Alpha)*Power(1+x,Beta).

    INPUT PARAMETERS:
        N           -   number of nodes, >=1
        Alpha       -   power-law coefficient, Alpha>-1
        Beta        -   power-law coefficient, Beta>-1

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -4    an  error  was   detected   when   calculating
                                weights/nodes. Alpha or  Beta  are  too  close
                                to -1 to obtain weights/nodes with high enough
                                accuracy, or, may be, N is too large.  Try  to
                                use multiple precision version.
                        * -3    internal eigenproblem solver hasn't converged
                        * -1    incorrect N/Alpha/Beta was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes,
                        in ascending order.
        W           -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgenerategaussjacobi(int n,
        amp::ampf<Precision> alpha,
        amp::ampf<Precision> beta,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `gqgenerategausslaguerre` function

    /*************************************************************************
    Returns  nodes/weights  for  Gauss-Laguerre  quadrature  on  [0,+inf) with
    weight function W(x)=Power(x,Alpha)*Exp(-x)

    INPUT PARAMETERS:
        N           -   number of nodes, >=1
        Alpha       -   power-law coefficient, Alpha>-1

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -4    an  error  was   detected   when   calculating
                                weights/nodes. Alpha is too  close  to  -1  to
                                obtain weights/nodes with high enough accuracy
                                or, may  be,  N  is  too  large.  Try  to  use
                                multiple precision version.
                        * -3    internal eigenproblem solver hasn't converged
                        * -1    incorrect N/Alpha was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes,
                        in ascending order.
        W           -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgenerategausslaguerre(int n,
        amp::ampf<Precision> alpha,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `gqgenerategausslegendre` function

    /*************************************************************************
    Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N
    nodes.

    INPUT PARAMETERS:
        N           -   number of nodes, >=1

    OUTPUT PARAMETERS:
        Info        -   error code:
                        * -4    an  error   was   detected   when  calculating
                                weights/nodes.  N  is  too  large   to  obtain
                                weights/nodes  with  high   enough   accuracy.
                                Try  to   use   multiple   precision  version.
                        * -3    internal eigenproblem solver hasn't  converged
                        * -1    incorrect N was passed
                        * +1    OK
        X           -   array[0..N-1] - array of quadrature nodes,
                        in ascending order.
        W           -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 12.05.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgenerategausslegendre(int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `gqgenerategausslobattorec` function

    /*************************************************************************
    Computation of nodes and weights for a Gauss-Lobatto quadrature formula

    The algorithm generates the N-point Gauss-Lobatto quadrature formula  with
    weight function given by coefficients alpha and beta of a recurrence which
    generates a system of orthogonal polynomials.

    P-1(x)   =  0
    P0(x)    =  1
    Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)

    and zeroth moment Mu0

    Mu0 = integral(W(x)dx,a,b)

    INPUT PARAMETERS:
        Alpha   –   array[0..N-2], alpha coefficients
        Beta    –   array[0..N-2], beta coefficients.
                    Zero-indexed element is not used, may be arbitrary.
                    Beta[I]>0
        Mu0     –   zeroth moment of the weighting function.
        A       –   left boundary of the integration interval.
        B       –   right boundary of the integration interval.
        N       –   number of nodes of the quadrature formula, N>=3
                    (including the left and right boundary nodes).

    OUTPUT PARAMETERS:
        Info    -   error code:
                    * -3    internal eigenproblem solver hasn't converged
                    * -2    Beta[i]<=0
                    * -1    incorrect N was passed
                    *  1    OK
        X       -   array[0..N-1] - array of quadrature nodes,
                    in ascending order.
        W       -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 2005-2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgenerategausslobattorec(ap::template_1d_array< amp::ampf<Precision> > alpha,
        ap::template_1d_array< amp::ampf<Precision> > beta,
        amp::ampf<Precision> mu0,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `gqgenerategaussradaurec` function

    /*************************************************************************
    Computation of nodes and weights for a Gauss-Radau quadrature formula

    The algorithm generates the N-point Gauss-Radau  quadrature  formula  with
    weight function given by the coefficients alpha and  beta  of a recurrence
    which generates a system of orthogonal polynomials.

    P-1(x)   =  0
    P0(x)    =  1
    Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)

    and zeroth moment Mu0

    Mu0 = integral(W(x)dx,a,b)

    INPUT PARAMETERS:
        Alpha   –   array[0..N-2], alpha coefficients.
        Beta    –   array[0..N-1], beta coefficients
                    Zero-indexed element is not used.
                    Beta[I]>0
        Mu0     –   zeroth moment of the weighting function.
        A       –   left boundary of the integration interval.
        N       –   number of nodes of the quadrature formula, N>=2
                    (including the left boundary node).

    OUTPUT PARAMETERS:
        Info    -   error code:
                    * -3    internal eigenproblem solver hasn't converged
                    * -2    Beta[i]<=0
                    * -1    incorrect N was passed
                    *  1    OK
        X       -   array[0..N-1] - array of quadrature nodes,
                    in ascending order.
        W       -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 2005-2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgenerategaussradaurec(ap::template_1d_array< amp::ampf<Precision> > alpha,
        ap::template_1d_array< amp::ampf<Precision> > beta,
        amp::ampf<Precision> mu0,
        amp::ampf<Precision> a,
        int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `gqgeneraterec` function

    /*************************************************************************
    Computation of nodes and weights for a Gauss quadrature formula

    The algorithm generates the N-point Gauss quadrature formula  with  weight
    function given by coefficients alpha and beta  of  a  recurrence  relation
    which generates a system of orthogonal polynomials:

    P-1(x)   =  0
    P0(x)    =  1
    Pn+1(x)  =  (x-alpha(n))*Pn(x)  -  beta(n)*Pn-1(x)

    and zeroth moment Mu0

    Mu0 = integral(W(x)dx,a,b)

    INPUT PARAMETERS:
        Alpha   –   array[0..N-1], alpha coefficients
        Beta    –   array[0..N-1], beta coefficients
                    Zero-indexed element is not used and may be arbitrary.
                    Beta[I]>0.
        Mu0     –   zeroth moment of the weight function.
        N       –   number of nodes of the quadrature formula, N>=1

    OUTPUT PARAMETERS:
        Info    -   error code:
                    * -3    internal eigenproblem solver hasn't converged
                    * -2    Beta[i]<=0
                    * -1    incorrect N was passed
                    *  1    OK
        X       -   array[0..N-1] - array of quadrature nodes,
                    in ascending order.
        W       -   array[0..N-1] - array of quadrature weights.

      -- ALGLIB --
         Copyright 2005-2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void gqgeneraterec(const ap::template_1d_array< amp::ampf<Precision> >& alpha,
        const ap::template_1d_array< amp::ampf<Precision> >& beta,
        amp::ampf<Precision> mu0,
        int n,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& w);

## `idwint` unit

### Structures

idwinterpolant

### Functions

idwbuildmodifiedshepard
idwbuildmodifiedshepardr
idwbuildnoisy
idwcalc

### `idwinterpolant` structure

    /*************************************************************************
    IDW interpolant.
    *************************************************************************/
    template<unsigned int Precision>
    class idwinterpolant
    {
    public:
        int n;
        int nx;
        int d;
        amp::ampf<Precision> r;
        int nw;
        nearestneighbor::kdtree<Precision> tree;
        int modeltype;
        ap::template_2d_array< amp::ampf<Precision> > q;
        ap::template_1d_array< amp::ampf<Precision> > xbuf;
        ap::template_1d_array< int > tbuf;
        ap::template_1d_array< amp::ampf<Precision> > rbuf;
        ap::template_2d_array< amp::ampf<Precision> > xybuf;
        int debugsolverfailures;
        amp::ampf<Precision> debugworstrcond;
        amp::ampf<Precision> debugbestrcond;
    };

### `idwbuildmodifiedshepard` function

    /*************************************************************************
    IDW interpolant using modified Shepard method for uniform point
    distributions.

    INPUT PARAMETERS:
        XY  -   X and Y values, array[0..N-1,0..NX].
                First NX columns contain X-values, last column contain
                Y-values.
        N   -   number of nodes, N>0.
        NX  -   space dimension, NX>=1.
        D   -   nodal function type, either:
                * 0     constant  model.  Just  for  demonstration only, worst
                        model ever.
                * 1     linear model, least squares fitting. Simpe  model  for
                        datasets too small for quadratic models
                * 2     quadratic  model,  least  squares  fitting. Best model
                        available (if your dataset is large enough).
                * -1    "fast"  linear  model,  use  with  caution!!!   It  is
                        significantly  faster than linear/quadratic and better
                        than constant model. But it is less robust (especially
                        in the presence of noise).
        NQ  -   number of points used to calculate  nodal  functions  (ignored
                for constant models). NQ should be LARGER than:
                * max(1.5*(1+NX),2^NX+1) for linear model,
                * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model.
                Values less than this threshold will be silently increased.
        NW  -   number of points used to calculate weights and to interpolate.
                Required: >=2^NX+1, values less than this  threshold  will  be
                silently increased.
                Recommended value: about 2*NQ

    OUTPUT PARAMETERS:
        Z   -   IDW interpolant.

    NOTES:
      * best results are obtained with quadratic models, worst - with constant
        models
      * when N is large, NQ and NW must be significantly smaller than  N  both
        to obtain optimal performance and to obtain optimal accuracy. In 2  or
        3-dimensional tasks NQ=15 and NW=25 are good values to start with.
      * NQ  and  NW  may  be  greater  than  N.  In  such  cases  they will be
        automatically decreased.
      * this subroutine is always succeeds (as long as correct parameters  are
        passed).
      * see  'Multivariate  Interpolation  of Large Sets of Scattered Data' by
        Robert J. Renka for more information on this algorithm.
      * this subroutine assumes that point distribution is uniform at the small
        scales.  If  it  isn't  -  for  example,  points are concentrated along
        "lines", but "lines" distribution is uniform at the larger scale - then
        you should use IDWBuildModifiedShepardR()

      -- ALGLIB PROJECT --
         Copyright 02.03.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void idwbuildmodifiedshepard(const ap::template_2d_array< amp::ampf<Precision> >& xy,
        int n,
        int nx,
        int d,
        int nq,
        int nw,
        idwinterpolant<Precision>& z);

### `idwbuildmodifiedshepardr` function

    /*************************************************************************
    IDW interpolant using modified Shepard method for non-uniform datasets.

    This type of model uses  constant  nodal  functions and interpolates using
    all nodes which are closer than user-specified radius R. It  may  be  used
    when points distribution is non-uniform at the small scale, but it  is  at
    the distances as large as R.

    INPUT PARAMETERS:
        XY  -   X and Y values, array[0..N-1,0..NX].
                First NX columns contain X-values, last column contain
                Y-values.
        N   -   number of nodes, N>0.
        NX  -   space dimension, NX>=1.
        R   -   radius, R>0

    OUTPUT PARAMETERS:
        Z   -   IDW interpolant.

    NOTES:
    * if there is less than IDWKMin points within  R-ball,  algorithm  selects
      IDWKMin closest ones, so that continuity properties of  interpolant  are
      preserved even far from points.

      -- ALGLIB PROJECT --
         Copyright 11.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void idwbuildmodifiedshepardr(const ap::template_2d_array< amp::ampf<Precision> >& xy,
        int n,
        int nx,
        amp::ampf<Precision> r,
        idwinterpolant<Precision>& z);

### `idwbuildnoisy` function

    /*************************************************************************
    IDW model for noisy data.

    This subroutine may be used to handle noisy data, i.e. data with noise  in
    OUTPUT values.  It differs from IDWBuildModifiedShepard() in the following
    aspects:
    * nodal functions are not constrained to pass through  nodes:  Qi(xi)<>yi,
      i.e. we have fitting  instead  of  interpolation.
    * weights which are used during least  squares fitting stage are all equal
      to 1.0 (independently of distance)
    * "fast"-linear or constant nodal functions are not supported (either  not
      robust enough or too rigid)

    This problem require far more complex tuning than interpolation  problems.
    Below you can find some recommendations regarding this problem:
    * focus on tuning NQ; it controls noise reduction. As for NW, you can just
      make it equal to 2*NQ.
    * you can use cross-validation to determine optimal NQ.
    * optimal NQ is a result of complex tradeoff  between  noise  level  (more
      noise = larger NQ required) and underlying  function  complexity  (given
      fixed N, larger NQ means smoothing of compex features in the data).  For
      example, NQ=N will reduce noise to the minimum level possible,  but  you
      will end up with just constant/linear/quadratic (depending on  D)  least
      squares model for the whole dataset.

    INPUT PARAMETERS:
        XY  -   X and Y values, array[0..N-1,0..NX].
                First NX columns contain X-values, last column contain
                Y-values.
        N   -   number of nodes, N>0.
        NX  -   space dimension, NX>=1.
        D   -   nodal function degree, either:
                * 1     linear model, least squares fitting. Simpe  model  for
                        datasets too small for quadratic models (or  for  very
                        noisy problems).
                * 2     quadratic  model,  least  squares  fitting. Best model
                        available (if your dataset is large enough).
        NQ  -   number of points used to calculate nodal functions.  NQ should
                be  significantly   larger   than  1.5  times  the  number  of
                coefficients in a nodal function to overcome effects of noise:
                * larger than 1.5*(1+NX) for linear model,
                * larger than 3/4*(NX+2)*(NX+1) for quadratic model.
                Values less than this threshold will be silently increased.
        NW  -   number of points used to calculate weights and to interpolate.
                Required: >=2^NX+1, values less than this  threshold  will  be
                silently increased.
                Recommended value: about 2*NQ or larger

    OUTPUT PARAMETERS:
        Z   -   IDW interpolant.

    NOTES:
      * best results are obtained with quadratic models, linear models are not
        recommended to use unless you are pretty sure that it is what you want
      * this subroutine is always succeeds (as long as correct parameters  are
        passed).
      * see  'Multivariate  Interpolation  of Large Sets of Scattered Data' by
        Robert J. Renka for more information on this algorithm.

      -- ALGLIB PROJECT --
         Copyright 02.03.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void idwbuildnoisy(const ap::template_2d_array< amp::ampf<Precision> >& xy,
        int n,
        int nx,
        int d,
        int nq,
        int nw,
        idwinterpolant<Precision>& z);

### `idwcalc` function

    /*************************************************************************
    IDW interpolation

    INPUT PARAMETERS:
        Z   -   IDW interpolant built with one of model building
                subroutines.
        X   -   array[0..NX-1], interpolation point

    Result:
        IDW interpolant Z(X)

      -- ALGLIB --
         Copyright 02.03.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> idwcalc(idwinterpolant<Precision>& z,
        const ap::template_1d_array< amp::ampf<Precision> >& x);

## `inverseupdate` unit

### Functions

rmatrixinvupdatecolumn
rmatrixinvupdaterow
rmatrixinvupdatesimple
rmatrixinvupdateuv

### `rmatrixinvupdatecolumn` function

    /*************************************************************************
    Inverse matrix update by the Sherman-Morrison formula

    The algorithm updates matrix A^-1 when adding a vector to a column
    of matrix A.

    Input parameters:
        InvA        -   inverse of matrix A.
                        Array whose indexes range within [0..N-1, 0..N-1].
        N           -   size of matrix A.
        UpdColumn   -   the column of A whose vector U was added.
                        0 <= UpdColumn <= N-1
        U           -   the vector to be added to a column.
                        Array whose index ranges within [0..N-1].

    Output parameters:
        InvA        -   inverse of modified matrix A.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixinvupdatecolumn(ap::template_2d_array< amp::ampf<Precision> >& inva,
        int n,
        int updcolumn,
        const ap::template_1d_array< amp::ampf<Precision> >& u);

### `rmatrixinvupdaterow` function

    /*************************************************************************
    Inverse matrix update by the Sherman-Morrison formula

    The algorithm updates matrix A^-1 when adding a vector to a row
    of matrix A.

    Input parameters:
        InvA    -   inverse of matrix A.
                    Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        UpdRow  -   the row of A whose vector V was added.
                    0 <= Row <= N-1
        V       -   the vector to be added to a row.
                    Array whose index ranges within [0..N-1].

    Output parameters:
        InvA    -   inverse of modified matrix A.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixinvupdaterow(ap::template_2d_array< amp::ampf<Precision> >& inva,
        int n,
        int updrow,
        const ap::template_1d_array< amp::ampf<Precision> >& v);

### `rmatrixinvupdatesimple` function

    /*************************************************************************
    Inverse matrix update by the Sherman-Morrison formula

    The algorithm updates matrix A^-1 when adding a number to an element
    of matrix A.

    Input parameters:
        InvA    -   inverse of matrix A.
                    Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        UpdRow  -   row where the element to be updated is stored.
        UpdColumn - column where the element to be updated is stored.
        UpdVal  -   a number to be added to the element.

    Output parameters:
        InvA    -   inverse of modified matrix A.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixinvupdatesimple(ap::template_2d_array< amp::ampf<Precision> >& inva,
        int n,
        int updrow,
        int updcolumn,
        amp::ampf<Precision> updval);

### `rmatrixinvupdateuv` function

    /*************************************************************************
    Inverse matrix update by the Sherman-Morrison formula

    The algorithm computes the inverse of matrix A+u*v’ by using the given matrix
    A^-1 and the vectors u and v.

    Input parameters:
        InvA    -   inverse of matrix A.
                    Array whose indexes range within [0..N-1, 0..N-1].
        N       -   size of matrix A.
        U       -   the vector modifying the matrix.
                    Array whose index ranges within [0..N-1].
        V       -   the vector modifying the matrix.
                    Array whose index ranges within [0..N-1].

    Output parameters:
        InvA - inverse of matrix A + u*v'.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixinvupdateuv(ap::template_2d_array< amp::ampf<Precision> >& inva,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& u,
        const ap::template_1d_array< amp::ampf<Precision> >& v);

## `ldlt` unit

### Functions

smatrixldlt

### `smatrixldlt` function

    /*************************************************************************
    LDLTDecomposition of a symmetric matrix

    The algorithm represents a symmetric matrix (which is not necessarily
    positive definite) as A=L*D*L' or A = U*D*U', where D is a block-diagonal
    matrix with blocks 1x1 or 2x2, matrix L (matrix U) is a product of lower
    (upper) triangular matrices with unit diagonal and permutation matrices.

    Input parameters:
        A       -   factorized matrix, array with elements [0..N-1, 0..N-1].
                    If IsUpper – True, then the upper triangle contains
                    elements of symmetric matrix A, and the lower triangle is
                    not used.
                    The same applies if IsUpper = False.
        N       -   size of factorized matrix.
        IsUpper -   parameter which shows a method of matrix definition (lower
                    or upper triangle).

    Output parameters:
        A       -   matrices D and U, if IsUpper = True, or L, if IsUpper = False,
                    in compact form, replacing the upper (lower) triangle of
                    matrix A. In that case, the elements under (over) the main
                    diagonal are not used nor modified.
        Pivots  -   tables of performed permutations (see below).

    If IsUpper = True, then A = U*D*U', U = P(n)*U(n)*...*P(k)*U(k), where
    P(k) is the permutation matrix, U(k) - upper triangular matrix with its
    unit main diagonal and k decreases from n with step s which is equal to
    1 or 2 (according to the size of the blocks of matrix D).

            (   I    v    0   )   k-s+1
    U(k) =  (   0    I    0   )   s
            (   0    0    I   )   n-k-1
               k-s+1 s   n-k-1

    If Pivots[k]>=0, then s=1, P(k) - permutation of rows k and Pivots[k], the
    vectorv forming matrix U(k) is stored in elements A(0:k-1,k), D(k) replaces
    A(k,k). If Pivots[k]=Pivots[k-1]<0 then s=2, P(k) - permutation of rows k-1
    and N+Pivots[k-1], the vector v forming matrix U(k) is stored in elements
    A(0:k-1,k:k+1), the upper triangle of block D(k) is stored in A(k,k),
    A(k,k+1) and A(k+1,k+1).

    If IsUpper = False, then A = L*D*L', L=P(0)*L(0)*...*P(k)*L(k), where P(k)
    is the permutation matrix, L(k) – lower triangular matrix with unit main
    diagonal and k decreases from 1 with step s which is equal to 1 or 2
    (according to the size of the blocks of matrix D).

            (   I    0     0   )  k-1
    L(k) =  (   0    I     0   )  s
            (   0    v     I   )  n-k-s+1
               k-1   s  n-k-s+1

    If Pivots[k]>=0 then s=1, P(k) – permutation of rows k and Pivots[k], the
    vector v forming matrix L(k) is stored in elements A(k+1:n-1,k), D(k)
    replaces A(k,k). If Pivots[k]=Pivots[k+1]<0 then s=2, P(k) - permutation
    of rows k+1 and N+Pivots[k+1], the vector v forming matrix L(k) is stored
    in elements A(k+2:n-1,k:k+1), the lower triangle of block D(k) is stored in
    A(k,k), A(k+1,k) and A(k+1,k+1).

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         June 30, 1999
    *************************************************************************/
    template<unsigned int Precision>
    void smatrixldlt(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        ap::template_1d_array< int >& pivots);

## `lsfit` unit

### Structures

lsfitreport

### Functions

lsfitlinear
lsfitlinearc
lsfitlinearw
lsfitlinearwc
lsfitnonlinearfg
lsfitnonlinearfgh
lsfitnonlineariteration
lsfitnonlinearresults
lsfitnonlinearsetcond
lsfitnonlinearsetstpmax
lsfitnonlinearwfg
lsfitnonlinearwfgh

### Examples

lsfit_linear
lsfit_nonlinear
lsfit_nonlinear2

### `lsfitreport` structure

    /*************************************************************************
    Least squares fitting report:
        TaskRCond       reciprocal of task's condition number
        RMSError        RMS error
        AvgError        average error
        AvgRelError     average relative error (for non-zero Y[I])
        MaxError        maximum error
    *************************************************************************/
    template<unsigned int Precision>
    class lsfitreport
    {
    public:
        amp::ampf<Precision> taskrcond;
        amp::ampf<Precision> rmserror;
        amp::ampf<Precision> avgerror;
        amp::ampf<Precision> avgrelerror;
        amp::ampf<Precision> maxerror;
    };

### `lsfitlinear` function

    /*************************************************************************
    Linear least squares fitting, without weights.

    See LSFitLinearW for more information.

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitlinear(const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_2d_array< amp::ampf<Precision> >& fmatrix,
        int n,
        int m,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& c,
        lsfitreport<Precision>& rep);

Examples: lsfit_linear

### `lsfitlinearc` function

    /*************************************************************************
    Constained linear least squares fitting, without weights.

    See LSFitLinearWC() for more information.

      -- ALGLIB --
         Copyright 07.09.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitlinearc(ap::template_1d_array< amp::ampf<Precision> > y,
        const ap::template_2d_array< amp::ampf<Precision> >& fmatrix,
        const ap::template_2d_array< amp::ampf<Precision> >& cmatrix,
        int n,
        int m,
        int k,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& c,
        lsfitreport<Precision>& rep);

Examples: lsfit_linear

### `lsfitlinearw` function

    /*************************************************************************
    Weighted linear least squares fitting.

    QR decomposition is used to reduce task to MxM, then triangular solver  or
    SVD-based solver is used depending on condition number of the  system.  It
    allows to maximize speed and retain decent accuracy.

    INPUT PARAMETERS:
        Y       -   array[0..N-1] Function values in  N  points.
        W       -   array[0..N-1]  Weights  corresponding to function  values.
                    Each summand in square  sum  of  approximation  deviations
                    from  given  values  is  multiplied  by  the   square   of
                    corresponding weight.
        FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
                    FMatrix[I, J] - value of J-th basis function in I-th point.
        N       -   number of points used. N>=1.
        M       -   number of basis functions, M>=1.

    OUTPUT PARAMETERS:
        Info    -   error code:
                    * -4    internal SVD decomposition subroutine failed (very
                            rare and for degenerate systems only)
                    * -1    incorrect N/M were specified
                    *  1    task is solved
        C       -   decomposition coefficients, array[0..M-1]
        Rep     -   fitting report. Following fields are set:
                    * Rep.TaskRCond     reciprocal of condition number
                    * RMSError          rms error on the (X,Y).
                    * AvgError          average error on the (X,Y).
                    * AvgRelError       average relative error on the non-zero Y
                    * MaxError          maximum error
                                        NON-WEIGHTED ERRORS ARE CALCULATED

    SEE ALSO
        LSFitLinear
        LSFitLinearC
        LSFitLinearWC

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitlinearw(const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        const ap::template_2d_array< amp::ampf<Precision> >& fmatrix,
        int n,
        int m,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& c,
        lsfitreport<Precision>& rep);

Examples: lsfit_linear

### `lsfitlinearwc` function

    /*************************************************************************
    Weighted constained linear least squares fitting.

    This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
    that  K  additional  constaints  C*x=bc are satisfied. It reduces original
    task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
    is called.

    INPUT PARAMETERS:
        Y       -   array[0..N-1] Function values in  N  points.
        W       -   array[0..N-1]  Weights  corresponding to function  values.
                    Each summand in square  sum  of  approximation  deviations
                    from  given  values  is  multiplied  by  the   square   of
                    corresponding weight.
        FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
                    FMatrix[I,J] - value of J-th basis function in I-th point.
        CMatrix -   a table of constaints, array[0..K-1,0..M].
                    I-th row of CMatrix corresponds to I-th linear constraint:
                    CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
        N       -   number of points used. N>=1.
        M       -   number of basis functions, M>=1.
        K       -   number of constraints, 0 <= K < M
                    K=0 corresponds to absence of constraints.

    OUTPUT PARAMETERS:
        Info    -   error code:
                    * -4    internal SVD decomposition subroutine failed (very
                            rare and for degenerate systems only)
                    * -3    either   too   many  constraints  (M   or   more),
                            degenerate  constraints   (some   constraints  are
                            repetead twice) or inconsistent  constraints  were
                            specified.
                    * -1    incorrect N/M/K were specified
                    *  1    task is solved
        C       -   decomposition coefficients, array[0..M-1]
        Rep     -   fitting report. Following fields are set:
                    * RMSError          rms error on the (X,Y).
                    * AvgError          average error on the (X,Y).
                    * AvgRelError       average relative error on the non-zero Y
                    * MaxError          maximum error
                                        NON-WEIGHTED ERRORS ARE CALCULATED

    IMPORTANT:
        this subroitine doesn't calculate task's condition number for K<>0.

    SEE ALSO
        LSFitLinear
        LSFitLinearC
        LSFitLinearWC

      -- ALGLIB --
         Copyright 07.09.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitlinearwc(ap::template_1d_array< amp::ampf<Precision> > y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        const ap::template_2d_array< amp::ampf<Precision> >& fmatrix,
        ap::template_2d_array< amp::ampf<Precision> > cmatrix,
        int n,
        int m,
        int k,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& c,
        lsfitreport<Precision>& rep);

Examples: lsfit_linear

### `lsfitnonlinearfg` function

    /*************************************************************************
    Nonlinear least squares fitting, no individual weights.
    See LSFitNonlinearWFG for more information.

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearfg(const ap::template_2d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& c,
        int n,
        int m,
        int k,
        bool cheapfg,
        lsfitstate<Precision>& state);

Examples: lsfit_nonlinear

### `lsfitnonlinearfgh` function

    /*************************************************************************
    Nonlinear least squares fitting using gradient/Hessian without  individual
    weights. See LSFitNonlinearWFGH() for more information.

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearfgh(const ap::template_2d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& c,
        int n,
        int m,
        int k,
        lsfitstate<Precision>& state);

Examples: lsfit_nonlinear2

### `lsfitnonlineariteration` function

    /*************************************************************************
    Nonlinear least squares fitting. Algorithm iteration.

    Called after inialization of the State structure with  LSFitNonlinearXXX()
    subroutine. See HTML docs for examples.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between  subsequent
                    calls and which is used for reverse communication. Must be
                    initialized with LSFitNonlinearXXX() call first.

    RESULT
    1. If subroutine returned False, iterative algorithm has converged.
    2. If subroutine returned True, then if:
    * if State.NeedF=True,      function value F(X,C) is required
    * if State.NeedFG=True,     function value F(X,C) and gradient  dF/dC(X,C)
                                are required
    * if State.NeedFGH=True     function value F(X,C), gradient dF/dC(X,C) and
                                Hessian are required

    One and only one of this fields can be set at time.

    Function, its gradient and Hessian are calculated at  (X,C),  where  X  is
    stored in State.X[0..M-1] and C is stored in State.C[0..K-1].

    Results are stored:
    * function value            -   in State.F
    * gradient                  -   in State.G[0..K-1]
    * Hessian                   -   in State.H[0..K-1,0..K-1]

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool lsfitnonlineariteration(lsfitstate<Precision>& state);

Examples: lsfit_nonlinear lsfit_nonlinear2

### `lsfitnonlinearresults` function

    /*************************************************************************
    Nonlinear least squares fitting results.

    Called after LSFitNonlinearIteration() returned False.

    INPUT PARAMETERS:
        State   -   algorithm state (used by LSFitNonlinearIteration).

    OUTPUT PARAMETERS:
        Info    -   completetion code:
                        * -1    incorrect parameters were specified
                        *  1    relative function improvement is no more than
                                EpsF.
                        *  2    relative step is no more than EpsX.
                        *  4    gradient norm is no more than EpsG
                        *  5    MaxIts steps was taken
        C       -   array[0..K-1], solution
        Rep     -   optimization report. Following fields are set:
                    * Rep.TerminationType completetion code:
                    * RMSError          rms error on the (X,Y).
                    * AvgError          average error on the (X,Y).
                    * AvgRelError       average relative error on the non-zero Y
                    * MaxError          maximum error
                                        NON-WEIGHTED ERRORS ARE CALCULATED

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearresults(const lsfitstate<Precision>& state,
        int& info,
        ap::template_1d_array< amp::ampf<Precision> >& c,
        lsfitreport<Precision>& rep);

Examples: lsfit_nonlinear lsfit_nonlinear2

### `lsfitnonlinearsetcond` function

    /*************************************************************************
    Stopping conditions for nonlinear least squares fitting.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with LSFitNonLinearCreate???()
        EpsF    -   stopping criterion. Algorithm stops if
                    |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}
        EpsX    -   stopping criterion. Algorithm stops if
                    |X(k+1)-X(k)| <= EpsX*(1+|X(k)|)
        MaxIts  -   stopping criterion. Algorithm stops after MaxIts iterations.
                    MaxIts=0 means no stopping criterion.

    NOTE

    Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic
    stopping criterion selection (according to the scheme used by MINLM unit).

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearsetcond(lsfitstate<Precision>& state,
        amp::ampf<Precision> epsf,
        amp::ampf<Precision> epsx,
        int maxits);

### `lsfitnonlinearsetstpmax` function

    /*************************************************************************
    This function sets maximum step length

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with LSFitNonLinearCreate???()
        StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
                    want to limit step length.

    Use this subroutine when you optimize target function which contains exp()
    or  other  fast  growing  functions,  and optimization algorithm makes too
    large  steps  which  leads  to overflow. This function allows us to reject
    steps  that  are  too  large  (and  therefore  expose  us  to the possible
    overflow) without actually calculating function value at the x+stp*d.

    NOTE: non-zero StpMax leads to moderate  performance  degradation  because
    intermediate  step  of  preconditioned L-BFGS optimization is incompatible
    with limits on step size.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearsetstpmax(lsfitstate<Precision>& state,
        amp::ampf<Precision> stpmax);

### `lsfitnonlinearwfg` function

    /*************************************************************************
    Weighted nonlinear least squares fitting using gradient and Hessian.

    Nonlinear task min(F(c)) is solved, where

        F(c) = (w[0]*(f(x[0],c)-y[0]))^2 + ... + (w[n-1]*(f(x[n-1],c)-y[n-1]))^2,

        * N is a number of points,
        * M is a dimension of a space points belong to,
        * K is a dimension of a space of parameters being fitted,
        * w is an N-dimensional vector of weight coefficients,
        * x is a set of N points, each of them is an M-dimensional vector,
        * c is a K-dimensional vector of parameters being fitted

    This subroutine uses only f(x[i],c) and its gradient.

    INPUT PARAMETERS:
        X       -   array[0..N-1,0..M-1], points (one row = one point)
        Y       -   array[0..N-1], function values.
        W       -   weights, array[0..N-1]
        C       -   array[0..K-1], initial approximation to the solution,
        N       -   number of points, N>1
        M       -   dimension of space
        K       -   number of parameters being fitted
        CheapFG -   boolean flag, which is:
                    * True  if both function and gradient calculation complexity
                            are less than O(M^2).  An improved  algorithm  can
                            be  used  which corresponds  to  FGJ  scheme  from
                            MINLM unit.
                    * False otherwise.
                            Standard Jacibian-bases  Levenberg-Marquardt  algo
                            will be used (FJ scheme).

    OUTPUT PARAMETERS:
        State   -   structure which stores algorithm state between subsequent
                    calls  of   LSFitNonlinearIteration.   Used  for  reverse
                    communication.  This  structure   should   be  passed  to
                    LSFitNonlinearIteration subroutine.

    See also:
        LSFitNonlinearIteration
        LSFitNonlinearResults
        LSFitNonlinearFG (fitting without weights)
        LSFitNonlinearWFGH (fitting using Hessian)
        LSFitNonlinearFGH (fitting using Hessian, without weights)

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearwfg(const ap::template_2d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        const ap::template_1d_array< amp::ampf<Precision> >& c,
        int n,
        int m,
        int k,
        bool cheapfg,
        lsfitstate<Precision>& state);

Examples: lsfit_nonlinear

### `lsfitnonlinearwfgh` function

    /*************************************************************************
    Weighted nonlinear least squares fitting using gradient/Hessian.

    Nonlinear task min(F(c)) is solved, where

        F(c) = (w[0]*(f(x[0],c)-y[0]))^2 + ... + (w[n-1]*(f(x[n-1],c)-y[n-1]))^2,

        * N is a number of points,
        * M is a dimension of a space points belong to,
        * K is a dimension of a space of parameters being fitted,
        * w is an N-dimensional vector of weight coefficients,
        * x is a set of N points, each of them is an M-dimensional vector,
        * c is a K-dimensional vector of parameters being fitted

    This subroutine uses f(x[i],c), its gradient and its Hessian.

    See LSFitNonlinearWFG() subroutine for information about function
    parameters.

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void lsfitnonlinearwfgh(const ap::template_2d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        const ap::template_1d_array< amp::ampf<Precision> >& c,
        int n,
        int m,
        int k,
        lsfitstate<Precision>& state);

Examples: lsfit_nonlinear2

### lsfit_linear example

        int m;
        int n;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_2d_array< amp::ampf<Precision> > fmatrix;
        ap::template_2d_array< amp::ampf<Precision> > cmatrix;
        lsfit::lsfitreport<Precision> rep;
        int info;
        ap::template_1d_array< amp::ampf<Precision> > c;
        int i;
        int j;
        amp::ampf<Precision> x;
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;

        printf("\n\nFitting tan(x) by third degree polynomial\n\n");
        printf("Fit type             rms.err max.err    p(0)   dp(0)\n");

        //
        // Fitting tan(x) at [0, 0.4*pi] by third degree polynomial:
        // a) without constraints
        // b) constrained at x=0: p(0)=0
        // c) constrained at x=0: p'(0)=1
        // c) constrained at x=0: p(0)=0, p'(0)=1
        //
        m = 4;
        n = 100;
        a = 0;
        b = amp::ampf<Precision>("0.4")*amp::pi<Precision>();

        //
        // Prepare task matrix
        //
        y.setlength(n);
        fmatrix.setlength(n, m);
        for(i=0; i<=n-1; i++)
        {
            x = a+(b-a)*i/(n-1);
            y(i) = amp::tan<Precision>(x);
            fmatrix(i,0) = amp::ampf<Precision>("1.0");
            for(j=1; j<=m-1; j++)
            {
                fmatrix(i,j) = x*fmatrix(i,j-1);
            }
        }

        //
        // Solve unconstrained task
        //
        lsfit::lsfitlinear<Precision>(y, fmatrix, n, m, info, c, rep);
        printf("Unconstrained        %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(c(0)).toDouble()),
            double(amp::ampf<Precision>(c(1)).toDouble()));

        //
        // Solve constrained task, p(0)=0
        // Prepare constraints matrix:
        // * first M columns store values of basis functions at X=0
        // * last column stores zero (desired value at X=0)
        //
        cmatrix.setlength(1, m+1);
        cmatrix(0,0) = 1;
        for(i=1; i<=m-1; i++)
        {
            cmatrix(0,i) = 0;
        }
        cmatrix(0,m) = 0;
        lsfit::lsfitlinearc<Precision>(y, fmatrix, cmatrix, n, m, 1, info, c, rep);
        printf("Constrained, p(0)=0  %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(c(0)).toDouble()),
            double(amp::ampf<Precision>(c(1)).toDouble()));

        //
        // Solve constrained task, p'(0)=0
        // Prepare constraints matrix:
        // * first M columns store derivatives of basis functions at X=0
        // * last column stores 1.0 (desired derivative at X=0)
        //
        cmatrix.setlength(1, m+1);
        for(i=0; i<=m-1; i++)
        {
            cmatrix(0,i) = 0;
        }
        cmatrix(0,1) = 1;
        cmatrix(0,m) = 1;
        lsfit::lsfitlinearc<Precision>(y, fmatrix, cmatrix, n, m, 1, info, c, rep);
        printf("Constrained, dp(0)=1 %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(c(0)).toDouble()),
            double(amp::ampf<Precision>(c(1)).toDouble()));

        //
        // Solve constrained task, p(0)=0, p'(0)=0
        // Prepare constraints matrix:
        // * first M columns store values/derivatives of basis functions at X=0
        // * last column stores desired values/derivative at X=0
        //
        cmatrix.setlength(2, m+1);
        cmatrix(0,0) = 1;
        for(i=1; i<=m-1; i++)
        {
            cmatrix(0,i) = 0;
        }
        cmatrix(0,m) = 0;
        for(i=0; i<=m-1; i++)
        {
            cmatrix(1,i) = 0;
        }
        cmatrix(1,1) = 1;
        cmatrix(1,m) = 1;
        lsfit::lsfitlinearc<Precision>(y, fmatrix, cmatrix, n, m, 2, info, c, rep);
        printf("Constrained, both    %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(c(0)).toDouble()),
            double(amp::ampf<Precision>(c(1)).toDouble()));
        printf("\n\n");

### lsfit_nonlinear example

        int m;
        int n;
        int k;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_2d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > c;
        lsfit::lsfitreport<Precision> rep;
        lsfit::lsfitstate<Precision> state;
        int info;
        amp::ampf<Precision> epsf;
        amp::ampf<Precision> epsx;
        int maxits;
        int i;
        int j;
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;

        printf("Fitting 0.5(1+cos(x)) on [-pi,+pi] with exp(-alpha*x^2)\n");

        //
        // Fitting 0.5(1+cos(x)) on [-pi,+pi] with Gaussian exp(-alpha*x^2):
        // * without Hessian (gradient only)
        // * using alpha=1 as initial value
        // * using 1000 uniformly distributed points to fit to
        //
        // Notes:
        // * N - number of points
        // * M - dimension of space where points reside
        // * K - number of parameters being fitted
        //
        n = 1000;
        m = 1;
        k = 1;
        a = -amp::pi<Precision>();
        b = +amp::pi<Precision>();

        //
        // Prepare task matrix
        //
        y.setlength(n);
        x.setlength(n, m);
        c.setlength(k);
        for(i=0; i<=n-1; i++)
        {
            x(i,0) = a+(b-a)*i/(n-1);
            y(i) = amp::ampf<Precision>("0.5")*(1+amp::cos<Precision>(x(i,0)));
        }
        c(0) = amp::ampf<Precision>("1.0");
        epsf = amp::ampf<Precision>("0.0");
        epsx = amp::ampf<Precision>("0.0001");
        maxits = 0;

        //
        // Solve
        //
        lsfit::lsfitnonlinearfg<Precision>(x, y, c, n, m, k, true, state);
        lsfit::lsfitnonlinearsetcond<Precision>(state, epsf, epsx, maxits);
        while( lsfit::lsfitnonlineariteration<Precision>(state) )
        {
            if( state.needf )
            {

                //
                // F(x) = Exp(-alpha*x^2)
                //
                state.f = amp::exp<Precision>(-state.c(0)*amp::sqr<Precision>(state.x(0)));
            }
            if( state.needfg )
            {

                //
                // F(x)      = Exp(-alpha*x^2)
                // dF/dAlpha = (-x^2)*Exp(-alpha*x^2)
                //
                state.f = amp::exp<Precision>(-state.c(0)*amp::sqr<Precision>(state.x(0)));
                state.g(0) = -amp::sqr<Precision>(state.x(0))*state.f;
            }
        }
        lsfit::lsfitnonlinearresults<Precision>(state, info, c, rep);
        printf("alpha:   %0.3lf\n",
            double(amp::ampf<Precision>(c(0)).toDouble()));
        printf("rms.err: %0.3lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()));
        printf("max.err: %0.3lf\n",
            double(amp::ampf<Precision>(rep.maxerror).toDouble()));
        printf("Termination type: %0ld\n",
            long(info));
        printf("\n\n");

### lsfit_nonlinear2 example

        int m;
        int n;
        int k;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_2d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > c;
        lsfit::lsfitreport<Precision> rep;
        lsfit::lsfitstate<Precision> state;
        int info;
        amp::ampf<Precision> epsf;
        amp::ampf<Precision> epsx;
        int maxits;
        int i;
        int j;
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;

        printf("Fitting 1-x^2 on [-1,+1] with cos(alpha*pi*x)+beta\n");

        //
        // Fitting 1-x^2 on [-1,+1] with cos(alpha*pi*x)+beta:
        // * using Hessian
        // * using alpha=1 and beta=0 as initial values
        // * using 1000 uniformly distributed points to fit to
        //
        // Notes:
        // * N - number of points
        // * M - dimension of space where points reside
        // * K - number of parameters being fitted
        //
        n = 1000;
        m = 1;
        k = 2;
        a = -1;
        b = +1;

        //
        // Prepare task matrix
        //
        y.setlength(n);
        x.setlength(n, m);
        c.setlength(k);
        for(i=0; i<=n-1; i++)
        {
            x(i,0) = a+(b-a)*i/(n-1);
            y(i) = 1-amp::sqr<Precision>(x(i,0));
        }
        c(0) = amp::ampf<Precision>("1.0");
        c(1) = amp::ampf<Precision>("0.0");
        epsf = amp::ampf<Precision>("0.0");
        epsx = amp::ampf<Precision>("0.0001");
        maxits = 0;

        //
        // Solve
        //
        lsfit::lsfitnonlinearfgh<Precision>(x, y, c, n, m, k, state);
        lsfit::lsfitnonlinearsetcond<Precision>(state, epsf, epsx, maxits);
        while( lsfit::lsfitnonlineariteration<Precision>(state) )
        {

            //
            // F(x) = Cos(alpha*pi*x)+beta
            //
            state.f = amp::cos<Precision>(state.c(0)*amp::pi<Precision>()*state.x(0))+state.c(1);

            //
            // F(x)      = Cos(alpha*pi*x)+beta
            // dF/dAlpha = -pi*x*Sin(alpha*pi*x)
            // dF/dBeta  = 1.0
            //
            if( state.needfg || state.needfgh )
            {
                state.g(0) = -amp::pi<Precision>()*state.x(0)*amp::sin<Precision>(state.c(0)*amp::pi<Precision>()*state.x(0));
                state.g(1) = amp::ampf<Precision>("1.0");
            }

            //
            // F(x)            = Cos(alpha*pi*x)+beta
            // d2F/dAlpha2     = -(pi*x)^2*Cos(alpha*pi*x)
            // d2F/dAlphadBeta = 0
            // d2F/dBeta2     =  0
            //
            if( state.needfgh )
            {
                state.h(0,0) = -amp::sqr<Precision>(amp::pi<Precision>()*state.x(0))*amp::cos<Precision>(state.c(0)*amp::pi<Precision>()*state.x(0));
                state.h(0,1) = amp::ampf<Precision>("0.0");
                state.h(1,0) = amp::ampf<Precision>("0.0");
                state.h(1,1) = amp::ampf<Precision>("0.0");
            }
        }
        lsfit::lsfitnonlinearresults<Precision>(state, info, c, rep);
        printf("alpha:   %0.3lf\n",
            double(amp::ampf<Precision>(c(0)).toDouble()));
        printf("beta:    %0.3lf\n",
            double(amp::ampf<Precision>(c(1)).toDouble()));
        printf("rms.err: %0.3lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()));
        printf("max.err: %0.3lf\n",
            double(amp::ampf<Precision>(rep.maxerror).toDouble()));
        printf("Termination type: %0ld\n",
            long(info));
        printf("\n\n");

## `matdet` unit

### Functions

cmatrixdet
cmatrixludet
rmatrixdet
rmatrixludet
spdmatrixcholeskydet
spdmatrixdet

### `cmatrixdet` function

    /*************************************************************************
    Calculation of the determinant of a general matrix

    Input parameters:
        A       -   matrix, array[0..N-1, 0..N-1]
        N       -   size of matrix A.

    Result: determinant of matrix A.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::campf<Precision> cmatrixdet(ap::template_2d_array< amp::campf<Precision> > a,
        int n);

### `cmatrixludet` function

    /*************************************************************************
    Determinant calculation of the matrix given by its LU decomposition.

    Input parameters:
        A       -   LU decomposition of the matrix (output of
                    RMatrixLU subroutine).
        Pivots  -   table of permutations which were made during
                    the LU decomposition.
                    Output of RMatrixLU subroutine.
        N       -   size of matrix A.

    Result: matrix determinant.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::campf<Precision> cmatrixludet(const ap::template_2d_array< amp::campf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        int n);

### `rmatrixdet` function

    /*************************************************************************
    Calculation of the determinant of a general matrix

    Input parameters:
        A       -   matrix, array[0..N-1, 0..N-1]
        N       -   size of matrix A.

    Result: determinant of matrix A.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixdet(ap::template_2d_array< amp::ampf<Precision> > a,
        int n);

### `rmatrixludet` function

    /*************************************************************************
    Determinant calculation of the matrix given by its LU decomposition.

    Input parameters:
        A       -   LU decomposition of the matrix (output of
                    RMatrixLU subroutine).
        Pivots  -   table of permutations which were made during
                    the LU decomposition.
                    Output of RMatrixLU subroutine.
        N       -   size of matrix A.

    Result: matrix determinant.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixludet(const ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        int n);

### `spdmatrixcholeskydet` function

    /*************************************************************************
    Determinant calculation of the matrix given by the Cholesky decomposition.

    Input parameters:
        A   -   Cholesky decomposition,
                output of SMatrixCholesky subroutine.
        N   -   size of matrix A.

    As the determinant is equal to the product of squares of diagonal elements,
    it’s not necessary to specify which triangle - lower or upper - the matrix
    is stored in.

    Result:
        matrix determinant.

      -- ALGLIB --
         Copyright 2005-2008 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spdmatrixcholeskydet(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n);

### `spdmatrixdet` function

    /*************************************************************************
    Determinant calculation of the symmetric positive definite matrix.

    Input parameters:
        A       -   matrix. Array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   if IsUpper = True, then the symmetric matrix A is given by
                    its upper triangle, and the lower triangle isn’t used by
                    subroutine. Similarly, if IsUpper = False, then A is given
                    by its lower triangle.

    Result:
        determinant of matrix A.
        If matrix A is not positive definite, then subroutine returns -1.

      -- ALGLIB --
         Copyright 2005-2008 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spdmatrixdet(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        bool isupper);

## `matgen` unit

### Functions

cmatrixrndcond
cmatrixrndorthogonal
cmatrixrndorthogonalfromtheleft
cmatrixrndorthogonalfromtheright
hmatrixrndcond
hmatrixrndmultiply
hpdmatrixrndcond
rmatrixrndcond
rmatrixrndorthogonal
rmatrixrndorthogonalfromtheleft
rmatrixrndorthogonalfromtheright
smatrixrndcond
smatrixrndmultiply
spdmatrixrndcond

### `cmatrixrndcond` function

    /*************************************************************************
    Generation of random NxN complex matrix with given condition number C and
    norm2(A)=1

    INPUT PARAMETERS:
        N   -   matrix size
        C   -   condition number (in 2-norm)

    OUTPUT PARAMETERS:
        A   -   random matrix with norm2(A)=1 and cond(A)=C

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixrndcond(int n,
        amp::ampf<Precision> c,
        ap::template_2d_array< amp::campf<Precision> >& a);

### `cmatrixrndorthogonal` function

    /*************************************************************************
    Generation of a random Haar distributed orthogonal complex matrix

    INPUT PARAMETERS:
        N   -   matrix size, N>=1

    OUTPUT PARAMETERS:
        A   -   orthogonal NxN matrix, array[0..N-1,0..N-1]

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixrndorthogonal(int n,
        ap::template_2d_array< amp::campf<Precision> >& a);

### `cmatrixrndorthogonalfromtheleft` function

    /*************************************************************************
    Multiplication of MxN complex matrix by MxM random Haar distributed
    complex orthogonal matrix

    INPUT PARAMETERS:
        A   -   matrix, array[0..M-1, 0..N-1]
        M, N-   matrix size

    OUTPUT PARAMETERS:
        A   -   Q*A, where Q is random MxM orthogonal matrix

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixrndorthogonalfromtheleft(ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n);

### `cmatrixrndorthogonalfromtheright` function

    /*************************************************************************
    Multiplication of MxN complex matrix by NxN random Haar distributed
    complex orthogonal matrix

    INPUT PARAMETERS:
        A   -   matrix, array[0..M-1, 0..N-1]
        M, N-   matrix size

    OUTPUT PARAMETERS:
        A   -   A*Q, where Q is random NxN orthogonal matrix

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixrndorthogonalfromtheright(ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n);

### `hmatrixrndcond` function

    /*************************************************************************
    Generation of random NxN Hermitian matrix with given condition number  and
    norm2(A)=1

    INPUT PARAMETERS:
        N   -   matrix size
        C   -   condition number (in 2-norm)

    OUTPUT PARAMETERS:
        A   -   random matrix with norm2(A)=1 and cond(A)=C

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hmatrixrndcond(int n,
        amp::ampf<Precision> c,
        ap::template_2d_array< amp::campf<Precision> >& a);

### `hmatrixrndmultiply` function

    /*************************************************************************
    Hermitian multiplication of NxN matrix by random Haar distributed
    complex orthogonal matrix

    INPUT PARAMETERS:
        A   -   matrix, array[0..N-1, 0..N-1]
        N   -   matrix size

    OUTPUT PARAMETERS:
        A   -   Q^H*A*Q, where Q is random NxN orthogonal matrix

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hmatrixrndmultiply(ap::template_2d_array< amp::campf<Precision> >& a,
        int n);

### `hpdmatrixrndcond` function

    /*************************************************************************
    Generation of random NxN Hermitian positive definite matrix with given
    condition number and norm2(A)=1

    INPUT PARAMETERS:
        N   -   matrix size
        C   -   condition number (in 2-norm)

    OUTPUT PARAMETERS:
        A   -   random HPD matrix with norm2(A)=1 and cond(A)=C

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixrndcond(int n,
        amp::ampf<Precision> c,
        ap::template_2d_array< amp::campf<Precision> >& a);

### `rmatrixrndcond` function

    /*************************************************************************
    Generation of random NxN matrix with given condition number and norm2(A)=1

    INPUT PARAMETERS:
        N   -   matrix size
        C   -   condition number (in 2-norm)

    OUTPUT PARAMETERS:
        A   -   random matrix with norm2(A)=1 and cond(A)=C

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixrndcond(int n,
        amp::ampf<Precision> c,
        ap::template_2d_array< amp::ampf<Precision> >& a);

### `rmatrixrndorthogonal` function

    /*************************************************************************
    Generation of a random uniformly distributed (Haar) orthogonal matrix

    INPUT PARAMETERS:
        N   -   matrix size, N>=1

    OUTPUT PARAMETERS:
        A   -   orthogonal NxN matrix, array[0..N-1,0..N-1]

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixrndorthogonal(int n,
        ap::template_2d_array< amp::ampf<Precision> >& a);

### `rmatrixrndorthogonalfromtheleft` function

    /*************************************************************************
    Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix

    INPUT PARAMETERS:
        A   -   matrix, array[0..M-1, 0..N-1]
        M, N-   matrix size

    OUTPUT PARAMETERS:
        A   -   Q*A, where Q is random MxM orthogonal matrix

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixrndorthogonalfromtheleft(ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n);

### `rmatrixrndorthogonalfromtheright` function

    /*************************************************************************
    Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix

    INPUT PARAMETERS:
        A   -   matrix, array[0..M-1, 0..N-1]
        M, N-   matrix size

    OUTPUT PARAMETERS:
        A   -   A*Q, where Q is random NxN orthogonal matrix

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixrndorthogonalfromtheright(ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n);

### `smatrixrndcond` function

    /*************************************************************************
    Generation of random NxN symmetric matrix with given condition number  and
    norm2(A)=1

    INPUT PARAMETERS:
        N   -   matrix size
        C   -   condition number (in 2-norm)

    OUTPUT PARAMETERS:
        A   -   random matrix with norm2(A)=1 and cond(A)=C

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void smatrixrndcond(int n,
        amp::ampf<Precision> c,
        ap::template_2d_array< amp::ampf<Precision> >& a);

### `smatrixrndmultiply` function

    /*************************************************************************
    Symmetric multiplication of NxN matrix by random Haar distributed
    orthogonal  matrix

    INPUT PARAMETERS:
        A   -   matrix, array[0..N-1, 0..N-1]
        N   -   matrix size

    OUTPUT PARAMETERS:
        A   -   Q'*A*Q, where Q is random NxN orthogonal matrix

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void smatrixrndmultiply(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n);

### `spdmatrixrndcond` function

    /*************************************************************************
    Generation of random NxN symmetric positive definite matrix with given
    condition number and norm2(A)=1

    INPUT PARAMETERS:
        N   -   matrix size
        C   -   condition number (in 2-norm)

    OUTPUT PARAMETERS:
        A   -   random SPD matrix with norm2(A)=1 and cond(A)=C

      -- ALGLIB routine --
         04.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixrndcond(int n,
        amp::ampf<Precision> c,
        ap::template_2d_array< amp::ampf<Precision> >& a);

## `matinv` unit

### Functions

cmatrixinverse
cmatrixluinverse
cmatrixtrinverse
hpdmatrixcholeskyinverse
hpdmatrixinverse
rmatrixinverse
rmatrixluinverse
rmatrixtrinverse
spdmatrixcholeskyinverse
spdmatrixinverse

### `cmatrixinverse` function

    /*************************************************************************
    Inversion of a general matrix.

    Input parameters:
        A   -   matrix, array[0..N-1,0..N-1].
        N   -   size of A.

    Output parameters:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixinverse(ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        int& info,
        matinvreport<Precision>& rep);

### `cmatrixluinverse` function

    /*************************************************************************
    Inversion of a matrix given by its LU decomposition.

    INPUT PARAMETERS:
        A       -   LU decomposition of the matrix (output of CMatrixLU subroutine).
        Pivots  -   table of permutations which were made during the LU decomposition
                    (the output of CMatrixLU subroutine).
        N       -   size of matrix A.

    OUTPUT PARAMETERS:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

      -- ALGLIB routine --
         05.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixluinverse(ap::template_2d_array< amp::campf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        int n,
        int& info,
        matinvreport<Precision>& rep);

### `cmatrixtrinverse` function

    /*************************************************************************
    Triangular matrix inverse (complex)

    The subroutine inverts the following types of matrices:
        * upper triangular
        * upper triangular with unit diagonal
        * lower triangular
        * lower triangular with unit diagonal

    In case of an upper (lower) triangular matrix,  the  inverse  matrix  will
    also be upper (lower) triangular, and after the end of the algorithm,  the
    inverse matrix replaces the source matrix. The elements  below (above) the
    main diagonal are not changed by the algorithm.

    If  the matrix  has a unit diagonal, the inverse matrix also  has  a  unit
    diagonal, and the diagonal elements are not passed to the algorithm.

    Input parameters:
        A       -   matrix, array[0..N-1, 0..N-1].
        N       -   size of A.
        IsUpper -   True, if the matrix is upper triangular.
        IsUnit  -   True, if the matrix has a unit diagonal.

    Output parameters:
        Info    -   same as for RMatrixLUInverse
        Rep     -   same as for RMatrixLUInverse
        A       -   same as for RMatrixLUInverse.

      -- ALGLIB --
         Copyright 05.02.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixtrinverse(ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        bool isunit,
        int& info,
        matinvreport<Precision>& rep);

### `hpdmatrixcholeskyinverse` function

    /*************************************************************************
    Inversion of a Hermitian positive definite matrix which is given
    by Cholesky decomposition.

    Input parameters:
        A       -   Cholesky decomposition of the matrix to be inverted:
                    A=U’*U or A = L*L'.
                    Output of  HPDMatrixCholesky subroutine.
        N       -   size of matrix A.
        IsUpper –   storage format.
                    If IsUpper = True, then matrix A is given as A = U'*U
                    (matrix contains upper triangle).
                    Similarly, if IsUpper = False, then A = L*L'.

    Output parameters:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

      -- ALGLIB routine --
         10.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixcholeskyinverse(ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        int& info,
        matinvreport<Precision>& rep);

### `hpdmatrixinverse` function

    /*************************************************************************
    Inversion of a Hermitian positive definite matrix.

    Given an upper or lower triangle of a Hermitian positive definite matrix,
    the algorithm generates matrix A^-1 and saves the upper or lower triangle
    depending on the input.

    Input parameters:
        A       -   matrix to be inverted (upper or lower triangle).
                    Array with elements [0..N-1,0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.
                    If IsUpper = True, then the upper triangle of matrix A is
                    given, otherwise the lower triangle is given.

    Output parameters:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

      -- ALGLIB routine --
         10.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hpdmatrixinverse(ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        int& info,
        matinvreport<Precision>& rep);

### `rmatrixinverse` function

    /*************************************************************************
    Inversion of a general matrix.

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.

    Output parameters:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

    Result:
        True, if the matrix is not singular.
        False, if the matrix is singular.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        int& info,
        matinvreport<Precision>& rep);

### `rmatrixluinverse` function

    /*************************************************************************
    Inversion of a matrix given by its LU decomposition.

    INPUT PARAMETERS:
        A       -   LU decomposition of the matrix (output of RMatrixLU subroutine).
        Pivots  -   table of permutations which were made during the LU decomposition
                    (the output of RMatrixLU subroutine).
        N       -   size of matrix A.

    OUTPUT PARAMETERS:
        Info    -   return code:
                    * -3    A is singular, or VERY close to singular.
                            it is filled by zeros in such cases.
                    * -1    N<=0 was passed, or incorrect Pivots was passed
                    *  1    task is solved (but matrix A may be ill-conditioned,
                            check R1/RInf parameters for condition numbers).
        Rep     -   solver report, see below for more info
        A       -   inverse of matrix A.
                    Array whose indexes range within [0..N-1, 0..N-1].

    SOLVER REPORT

    Subroutine sets following fields of the Rep structure:
    * R1        reciprocal of condition number: 1/cond(A), 1-norm.
    * RInf      reciprocal of condition number: 1/cond(A), inf-norm.

      -- ALGLIB routine --
         05.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixluinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        int n,
        int& info,
        matinvreport<Precision>& rep);

### `rmatrixtrinverse` function

    /*************************************************************************
    Triangular matrix inverse (real)

    The subroutine inverts the following types of matrices:
        * upper triangular
        * upper triangular with unit diagonal
        * lower triangular
        * lower triangular with unit diagonal

    In case of an upper (lower) triangular matrix,  the  inverse  matrix  will
    also be upper (lower) triangular, and after the end of the algorithm,  the
    inverse matrix replaces the source matrix. The elements  below (above) the
    main diagonal are not changed by the algorithm.

    If  the matrix  has a unit diagonal, the inverse matrix also  has  a  unit
    diagonal, and the diagonal elements are not passed to the algorithm.

    Input parameters:
        A       -   matrix, array[0..N-1, 0..N-1].
        N       -   size of A.
        IsUpper -   True, if the matrix is upper triangular.
        IsUnit  -   True, if the matrix has a unit diagonal.

    Output parameters:
        Info    -   same as for RMatrixLUInverse
        Rep     -   same as for RMatrixLUInverse
        A       -   same as for RMatrixLUInverse.

      -- ALGLIB --
         Copyright 05.02.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixtrinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        bool isunit,
        int& info,
        matinvreport<Precision>& rep);

### `spdmatrixcholeskyinverse` function

    /*************************************************************************
    Inversion of a symmetric positive definite matrix which is given
    by Cholesky decomposition.

    Input parameters:
        A       -   Cholesky decomposition of the matrix to be inverted:
                    A=U’*U or A = L*L'.
                    Output of  SPDMatrixCholesky subroutine.
        N       -   size of matrix A.
        IsUpper –   storage format.
                    If IsUpper = True, then matrix A is given as A = U'*U
                    (matrix contains upper triangle).
                    Similarly, if IsUpper = False, then A = L*L'.

    Output parameters:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

      -- ALGLIB routine --
         10.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixcholeskyinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        int& info,
        matinvreport<Precision>& rep);

### `spdmatrixinverse` function

    /*************************************************************************
    Inversion of a symmetric positive definite matrix.

    Given an upper or lower triangle of a symmetric positive definite matrix,
    the algorithm generates matrix A^-1 and saves the upper or lower triangle
    depending on the input.

    Input parameters:
        A       -   matrix to be inverted (upper or lower triangle).
                    Array with elements [0..N-1,0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.
                    If IsUpper = True, then the upper triangle of matrix A is
                    given, otherwise the lower triangle is given.

    Output parameters:
        Info    -   return code, same as in RMatrixLUInverse
        Rep     -   solver report, same as in RMatrixLUInverse
        A       -   inverse of matrix A, same as in RMatrixLUInverse

      -- ALGLIB routine --
         10.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spdmatrixinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        int& info,
        matinvreport<Precision>& rep);

## `minasa` unit

### Functions

minasacreate
minasaiteration
minasaresults
minasasetalgorithm
minasasetcond
minasasetstpmax
minasasetxrep

### Examples

minasa_1
minasa_2

### `minasacreate` function

    /*************************************************************************
                  NONLINEAR BOUND CONSTRAINED OPTIMIZATION USING
                                   MODIFIED
                       WILLIAM W. HAGER AND HONGCHAO ZHANG
                             ACTIVE SET ALGORITHM

    The  subroutine  minimizes  function  F(x)  of  N  arguments  with   bound
    constraints: BndL[i] <= x[i] <= BndU[i]

    This method is  globally  convergent  as  long  as  grad(f)  is  Lipschitz
    continuous on a level set: L = { x : f(x)<=f(x0) }.

    INPUT PARAMETERS:
        N       -   problem dimension. N>0
        X       -   initial solution approximation, array[0..N-1].
        BndL    -   lower bounds, array[0..N-1].
                    all elements MUST be specified,  i.e.  all  variables  are
                    bounded. However, if some (all) variables  are  unbounded,
                    you may specify very small number as bound: -1000,  -1.0E6
                    or -1.0E300, or something like that.
        BndU    -   upper bounds, array[0..N-1].
                    all elements MUST be specified,  i.e.  all  variables  are
                    bounded. However, if some (all) variables  are  unbounded,
                    you may specify very large number as bound: +1000,  +1.0E6
                    or +1.0E300, or something like that.
        EpsG    -   positive number which  defines  a  precision  of  search.  The
                    subroutine finishes its work if the condition ||G|| < EpsG  is
                    satisfied, where ||.|| means Euclidian norm, G - gradient, X -
                    current approximation.
        EpsF    -   positive number which  defines  a  precision  of  search.  The
                    subroutine finishes its work if on iteration  number  k+1  the
                    condition |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}    is
                    satisfied.
        EpsX    -   positive number which  defines  a  precision  of  search.  The
                    subroutine finishes its work if on iteration number k+1    the
                    condition |X(k+1)-X(k)| <= EpsX is fulfilled.
        MaxIts  -   maximum number of iterations. If MaxIts=0, the number of
                    iterations is unlimited.

    OUTPUT PARAMETERS:
        State - structure used for reverse communication.

    This function  initializes  State   structure  with  default  optimization
    parameters (stopping conditions, step size, etc.).  Use  MinASASet??????()
    functions to tune optimization parameters.

    After   all   optimization   parameters   are   tuned,   you   should  use
    MinASAIteration() function to advance algorithm iterations.

    NOTES:

    1. you may tune stopping conditions with MinASASetCond() function
    2. if target function contains exp() or other fast growing functions,  and
       optimization algorithm makes too large steps which leads  to  overflow,
       use MinASASetStpMax() function to bound algorithm's steps.

      -- ALGLIB --
         Copyright 25.03.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minasacreate(int n,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& bndl,
        const ap::template_1d_array< amp::ampf<Precision> >& bndu,
        minasastate<Precision>& state);

Examples: minasa_1 minasa_2

### `minasaiteration` function

    /*************************************************************************
    One ASA iteration

    Called after initialization with MinASACreate.
    See HTML documentation for examples.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinASACreate.
    RESULT:
    * if function returned False, iterative proces has converged.
      Use MinLBFGSResults() to obtain optimization results.
    * if subroutine returned True, then, depending on structure fields, we
      have one of the following situations

    === FUNC/GRAD REQUEST ===
    State.NeedFG is True => function value/gradient are needed.
    Caller should calculate function value State.F and gradient
    State.G[0..N-1] at State.X[0..N-1] and call MinLBFGSIteration() again.

    === NEW INTERATION IS REPORTED ===
    State.XUpdated is True => one more iteration was made.
    State.X contains current position, State.F contains function value at X.
    You can read info from these fields, but never modify  them  because  they
    contain the only copy of optimization algorithm state.

    One and only one of these fields (NeedFG, XUpdated) is true on return. New
    iterations are reported only when reports  are  explicitly  turned  on  by
    MinLBFGSSetXRep() function, so if you never called it, you can expect that
    NeedFG is always True.

      -- ALGLIB --
         Copyright 20.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool minasaiteration(minasastate<Precision>& state);

Examples: minasa_1 minasa_2

### `minasaresults` function

    /*************************************************************************
    Conjugate gradient results

    Called after MinASA returned False.

    INPUT PARAMETERS:
        State   -   algorithm state (used by MinASAIteration).

    OUTPUT PARAMETERS:
        X       -   array[0..N-1], solution
        Rep     -   optimization report:
                    * Rep.TerminationType completetion code:
                        * -2    rounding errors prevent further improvement.
                                X contains best point found.
                        * -1    incorrect parameters were specified
                        *  1    relative function improvement is no more than
                                EpsF.
                        *  2    relative step is no more than EpsX.
                        *  4    gradient norm is no more than EpsG
                        *  5    MaxIts steps was taken
                        *  7    stopping conditions are too stringent,
                                further improvement is impossible
                    * Rep.IterationsCount contains iterations count
                    * NFEV countains number of function calculations
                    * ActiveConstraints contains number of active constraints

      -- ALGLIB --
         Copyright 20.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minasaresults(const minasastate<Precision>& state,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        minasareport<Precision>& rep);

Examples: minasa_1 minasa_2

### `minasasetalgorithm` function

    /*************************************************************************
    This function sets optimization algorithm.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinASACreate()
        UAType  -   algorithm type:
                    * -1    automatic selection of the best algorithm
                    * 0     DY (Dai and Yuan) algorithm
                    * 1     Hybrid DY-HS algorithm

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minasasetalgorithm(minasastate<Precision>& state,
        int algotype);

### `minasasetcond` function

    /*************************************************************************
    This function sets stopping conditions for the ASA optimization algorithm.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinASACreate()
        EpsG    -   >=0
                    The  subroutine  finishes  its  work   if   the  condition
                    ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
                    G - gradient.
        EpsF    -   >=0
                    The  subroutine  finishes  its work if on k+1-th iteration
                    the  condition  |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1}
                    is satisfied.
        EpsX    -   >=0
                    The subroutine finishes its work if  on  k+1-th  iteration
                    the condition |X(k+1)-X(k)| <= EpsX is fulfilled.
        MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
                    iterations is unlimited.

    Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
    automatic stopping criterion selection (small EpsX).

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minasasetcond(minasastate<Precision>& state,
        amp::ampf<Precision> epsg,
        amp::ampf<Precision> epsf,
        amp::ampf<Precision> epsx,
        int maxits);

### `minasasetstpmax` function

    /*************************************************************************
    This function sets maximum step length

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinCGCreate()
        StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
                    want to limit step length.

    Use this subroutine when you optimize target function which contains exp()
    or  other  fast  growing  functions,  and optimization algorithm makes too
    large  steps  which  leads  to overflow. This function allows us to reject
    steps  that  are  too  large  (and  therefore  expose  us  to the possible
    overflow) without actually calculating function value at the x+stp*d.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minasasetstpmax(minasastate<Precision>& state,
        amp::ampf<Precision> stpmax);

### `minasasetxrep` function

    /*************************************************************************
    This function turns on/off reporting.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinASACreate()
        NeedXRep-   whether iteration reports are needed or not

    Usually  algorithm  returns from  MinASAIteration()  only  when  it  needs
    function/gradient. However, with this function we can let  it  stop  after
    each  iteration  (one  iteration  may  include   more  than  one  function
    evaluation), which is indicated by XUpdated field.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minasasetxrep(minasastate<Precision>& state,
        bool needxrep);

### minasa_1 example

        int n;
        int i;
        minasa::minasastate<Precision> state;
        minasa::minasareport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        ap::template_1d_array< amp::ampf<Precision> > bndl;
        ap::template_1d_array< amp::ampf<Precision> > bndu;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;
        amp::ampf<Precision> z;

        //
        // Function being minimized:
        //     F = x+2y+3z subject to 0<=x<=1, 0<=y<=1, 0<=z<=1.
        //
        n = 3;
        s.setlength(n);
        bndl.setlength(n);
        bndu.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            s(i) = 1;
            bndl(i) = 0;
            bndu(i) = 1;
        }
        minasa::minasacreate<Precision>(n, s, bndl, bndu, state);
        minasa::minasasetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.00001"), 0);
        minasa::minasasetxrep<Precision>(state, true);
        printf("\n\nF = x+2y+3z subject to 0<=x<=1, 0<=y<=1, 0<=z<=1\n");
        printf("OPTIMIZATION STARTED\n");
        while( minasa::minasaiteration<Precision>(state) )
        {
            if( state.needfg )
            {
                x = state.x(0);
                y = state.x(1);
                z = state.x(2);
                state.f = x+2*y+3*z;
                state.g(0) = 1;
                state.g(1) = 2;
                state.g(2) = 3;
            }
            if( state.xupdated )
            {
                printf("    F(%4.2lf,%4.2lf,%4.2lf)=%0.3lf\n",
                    double(amp::ampf<Precision>(state.x(0)).toDouble()),
                    double(amp::ampf<Precision>(state.x(1)).toDouble()),
                    double(amp::ampf<Precision>(state.x(2)).toDouble()),
                    double(amp::ampf<Precision>(state.f).toDouble()));
            }
        }
        printf("OPTIMIZATION STOPPED\n");
        minasa::minasaresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (should be 0.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (should be 0.00)\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));
        printf("Z = %4.2lf (should be 0.00)\n\n\n",
            double(amp::ampf<Precision>(s(2)).toDouble()));

### minasa_2 example

        int n;
        int i;
        minasa::minasastate<Precision> state;
        minasa::minasareport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        ap::template_1d_array< amp::ampf<Precision> > bndl;
        ap::template_1d_array< amp::ampf<Precision> > bndu;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;
        amp::ampf<Precision> z;

        //
        // Function being minimized:
        //     F = x+4y+9z subject to 0<=x<=1, 0<=y<=1, 0<=z<=1.
        //
        // Take a look at MinASASetStpMax() - it restricts step length by
        // a small value, so we can see the current point traveling through
        // a feasible set, sticking to its bounds.
        //
        n = 3;
        s.setlength(n);
        bndl.setlength(n);
        bndu.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            s(i) = 1;
            bndl(i) = 0;
            bndu(i) = 1;
        }
        minasa::minasacreate<Precision>(n, s, bndl, bndu, state);
        minasa::minasasetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.00001"), 0);
        minasa::minasasetxrep<Precision>(state, true);
        minasa::minasasetstpmax<Precision>(state, amp::ampf<Precision>("0.2"));
        printf("\n\nF = x+4y+9z subject to 0<=x<=1, 0<=y<=1, 0<=z<=1\n");
        printf("OPTIMIZATION STARTED\n");
        while( minasa::minasaiteration<Precision>(state) )
        {
            if( state.needfg )
            {
                x = state.x(0);
                y = state.x(1);
                z = state.x(2);
                state.f = x+4*y+9*z;
                state.g(0) = 1;
                state.g(1) = 4;
                state.g(2) = 9;
            }
            if( state.xupdated )
            {
                printf("    F(%4.2lf, %4.2lf, %4.2lf) = %0.3lf\n",
                    double(amp::ampf<Precision>(state.x(0)).toDouble()),
                    double(amp::ampf<Precision>(state.x(1)).toDouble()),
                    double(amp::ampf<Precision>(state.x(2)).toDouble()),
                    double(amp::ampf<Precision>(state.f).toDouble()));
            }
        }
        printf("OPTIMIZATION STOPPED\n");
        minasa::minasaresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (should be 0.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (should be 0.00)\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));
        printf("Z = %4.2lf (should be 0.00)\n\n\n",
            double(amp::ampf<Precision>(s(2)).toDouble()));

## `mincg` unit

### Functions

mincgcreate
mincgiteration
mincgresults
mincgsetcgtype
mincgsetcond
mincgsetstpmax
mincgsetxrep

### Examples

mincg_1
mincg_2

### `mincgcreate` function

    /*************************************************************************
            NONLINEAR CONJUGATE GRADIENT METHOD

    The subroutine minimizes function F(x) of N arguments by using one of  the
    nonlinear conjugate gradient methods.

    These CG methods are globally convergent (even on non-convex functions) as
    long as grad(f) is Lipschitz continuous in  a  some  neighborhood  of  the
    L = { x : f(x)<=f(x0) }.

    INPUT PARAMETERS:
        N       -   problem dimension. N>0
        X       -   initial solution approximation, array[0..N-1].
        EpsG    -   positive number which  defines  a  precision  of  search.  The
                    subroutine finishes its work if the condition ||G|| < EpsG  is
                    satisfied, where ||.|| means Euclidian norm, G - gradient, X -
                    current approximation.
        EpsF    -   positive number which  defines  a  precision  of  search.  The
                    subroutine finishes its work if on iteration  number  k+1  the
                    condition |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1}    is
                    satisfied.
        EpsX    -   positive number which  defines  a  precision  of  search.  The
                    subroutine finishes its work if on iteration number k+1    the
                    condition |X(k+1)-X(k)| <= EpsX is fulfilled.
        MaxIts  -   maximum number of iterations. If MaxIts=0, the number of
                    iterations is unlimited.

    OUTPUT PARAMETERS:
        State - structure used for reverse communication.

    See also MinCGIteration, MinCGResults

    NOTE:

    Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
    automatic stopping criterion selection (small EpsX).

      -- ALGLIB --
         Copyright 25.03.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void mincgcreate(int n,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        mincgstate<Precision>& state);

Examples: mincg_2 mincg_1

### `mincgiteration` function

    /*************************************************************************
    One conjugate gradient iteration

    Called after initialization with MinCG.
    See HTML documentation for examples.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinCG.

    RESULT:
    * if function returned False, iterative proces has converged.
      Use MinLBFGSResults() to obtain optimization results.
    * if subroutine returned True, then, depending on structure fields, we
      have one of the following situations

    === FUNC/GRAD REQUEST ===
    State.NeedFG is True => function value/gradient are needed.
    Caller should calculate function value State.F and gradient
    State.G[0..N-1] at State.X[0..N-1] and call MinLBFGSIteration() again.

    === NEW INTERATION IS REPORTED ===
    State.XUpdated is True => one more iteration was made.
    State.X contains current position, State.F contains function value at X.
    You can read info from these fields, but never modify  them  because  they
    contain the only copy of optimization algorithm state.

    One and only one of these fields (NeedFG, XUpdated) is true on return. New
    iterations are reported only when reports  are  explicitly  turned  on  by
    MinLBFGSSetXRep() function, so if you never called it, you can expect that
    NeedFG is always True.

      -- ALGLIB --
         Copyright 20.04.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool mincgiteration(mincgstate<Precision>& state);

Examples: mincg_2 mincg_1

### `mincgresults` function

    /*************************************************************************
    Conjugate gradient results

    Called after MinCG returned False.

    INPUT PARAMETERS:
        State   -   algorithm state (used by MinCGIteration).

    OUTPUT PARAMETERS:
        X       -   array[0..N-1], solution
        Rep     -   optimization report:
                    * Rep.TerminationType completetion code:
                        * -2    rounding errors prevent further improvement.
                                X contains best point found.
                        * -1    incorrect parameters were specified
                        *  1    relative function improvement is no more than
                                EpsF.
                        *  2    relative step is no more than EpsX.
                        *  4    gradient norm is no more than EpsG
                        *  5    MaxIts steps was taken
                        *  7    stopping conditions are too stringent,
                                further improvement is impossible
                    * Rep.IterationsCount contains iterations count
                    * NFEV countains number of function calculations

      -- ALGLIB --
         Copyright 20.04.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void mincgresults(const mincgstate<Precision>& state,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        mincgreport<Precision>& rep);

Examples: mincg_2 mincg_1

### `mincgsetcgtype` function

    /*************************************************************************
    This function sets CG algorithm.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinCGCreate()
        CGType  -   algorithm type:
                    * -1    automatic selection of the best algorithm
                    * 0     DY (Dai and Yuan) algorithm
                    * 1     Hybrid DY-HS algorithm

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void mincgsetcgtype(mincgstate<Precision>& state,
        int cgtype);

### `mincgsetcond` function

    /*************************************************************************
    This function sets stopping conditions for CG optimization algorithm.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinCGCreate()
        EpsG    -   >=0
                    The  subroutine  finishes  its  work   if   the  condition
                    ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
                    G - gradient.
        EpsF    -   >=0
                    The  subroutine  finishes  its work if on k+1-th iteration
                    the  condition  |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1}
                    is satisfied.
        EpsX    -   >=0
                    The subroutine finishes its work if  on  k+1-th  iteration
                    the condition |X(k+1)-X(k)| <= EpsX is fulfilled.
        MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
                    iterations is unlimited.

    Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
    automatic stopping criterion selection (small EpsX).

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void mincgsetcond(mincgstate<Precision>& state,
        amp::ampf<Precision> epsg,
        amp::ampf<Precision> epsf,
        amp::ampf<Precision> epsx,
        int maxits);

### `mincgsetstpmax` function

    /*************************************************************************
    This function sets maximum step length

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinCGCreate()
        StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
                    want to limit step length.

    Use this subroutine when you optimize target function which contains exp()
    or  other  fast  growing  functions,  and optimization algorithm makes too
    large  steps  which  leads  to overflow. This function allows us to reject
    steps  that  are  too  large  (and  therefore  expose  us  to the possible
    overflow) without actually calculating function value at the x+stp*d.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void mincgsetstpmax(mincgstate<Precision>& state,
        amp::ampf<Precision> stpmax);

### `mincgsetxrep` function

    /*************************************************************************
    This function turns on/off reporting.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinCGCreate()
        NeedXRep-   whether iteration reports are needed or not

    Usually  algorithm  returns  from  MinCGIteration()  only  when  it  needs
    function/gradient. However, with this function we can let  it  stop  after
    each  iteration  (one  iteration  may  include   more  than  one  function
    evaluation), which is indicated by XUpdated field.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void mincgsetxrep(mincgstate<Precision>& state,
        bool needxrep);

### mincg_1 example

        int n;
        mincg::mincgstate<Precision> state;
        mincg::mincgreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Function minimized:
        //     F = (x-1)^4 + (y-x)^2
        // N = 2 - task dimension.
        //
        n = 2;
        s.setlength(2);
        s(0) = 10;
        s(1) = 11;
        mincg::mincgcreate<Precision>(n, s, state);
        mincg::mincgsetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.00001"), 0);
        mincg::mincgsetxrep<Precision>(state, true);
        printf("\n\nF = (x-1)^4 + (y-x)^2\n");
        printf("OPTIMIZATION STARTED\n");
        while( mincg::mincgiteration<Precision>(state) )
        {
            if( state.needfg )
            {
                x = state.x(0);
                y = state.x(1);
                state.f = amp::sqr<Precision>(amp::sqr<Precision>(x-1))+amp::sqr<Precision>(y-x);
                state.g(0) = 4*amp::sqr<Precision>(x-1)*(x-1)+2*(x-y);
                state.g(1) = 2*(y-x);
            }
            if( state.xupdated )
            {
                printf("    F(%8.5lf,%8.5lf)=%0.5lf\n",
                    double(amp::ampf<Precision>(state.x(0)).toDouble()),
                    double(amp::ampf<Precision>(state.x(1)).toDouble()),
                    double(amp::ampf<Precision>(state.f).toDouble()));
            }
        }
        printf("OPTIMIZATION STOPPED\n");
        mincg::mincgresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (should be 1.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (should be 1.00)\n\n\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));

### mincg_2 example

        int n;
        mincg::mincgstate<Precision> state;
        mincg::mincgreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Function minimized:
        //     F = exp(x-1) + exp(1-x) + (y-x)^2
        // N = 2 - task dimension.
        //
        // Take a look at MinCGSetStpMax() call - it prevents us
        // from overflow (which may be result of too large step).
        // Try to comment it and see what will happen.
        //
        n = 2;
        s.setlength(2);
        s(0) = 10;
        s(1) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        mincg::mincgcreate<Precision>(n, s, state);
        mincg::mincgsetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0001"), 0);
        mincg::mincgsetxrep<Precision>(state, true);
        mincg::mincgsetstpmax<Precision>(state, amp::ampf<Precision>("1.0"));
        printf("\n\nF = exp(x-1) + exp(1-x) + (y-x)^2\n");
        printf("OPTIMIZATION STARTED\n");
        while( mincg::mincgiteration<Precision>(state) )
        {
            if( state.needfg )
            {
                x = state.x(0);
                y = state.x(1);
                state.f = amp::exp<Precision>(x-1)+amp::exp<Precision>(1-x)+amp::sqr<Precision>(y-x);
                state.g(0) = amp::exp<Precision>(x-1)-amp::exp<Precision>(1-x)+2*(x-y);
                state.g(1) = 2*(y-x);
            }
            if( state.xupdated )
            {
                printf("    F(%8.5lf,%8.5lf)=%0.5lf\n",
                    double(amp::ampf<Precision>(state.x(0)).toDouble()),
                    double(amp::ampf<Precision>(state.x(1)).toDouble()),
                    double(amp::ampf<Precision>(state.f).toDouble()));
            }
        }
        printf("OPTIMIZATION STOPPED\n");
        mincg::mincgresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (should be 1.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (should be 1.00)\n\n\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));

## `minlbfgs` unit

### Functions

minlbfgscreate
minlbfgscreatex
minlbfgsiteration
minlbfgsresults
minlbfgssetcond
minlbfgssetstpmax
minlbfgssetxrep

### Examples

minlbfgs_1
minlbfgs_2

### `minlbfgscreate` function

    /*************************************************************************
            LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION

    The subroutine minimizes function F(x) of N arguments by  using  a  quasi-
    Newton method (LBFGS scheme) which is optimized to use  a  minimum  amount
    of memory.

    The subroutine generates the approximation of an inverse Hessian matrix by
    using information about the last M steps of the algorithm  (instead of N).
    It lessens a required amount of memory from a value  of  order  N^2  to  a
    value of order 2*N*M.

    INPUT PARAMETERS:
        N       -   problem dimension. N>0
        M       -   number of corrections in the BFGS scheme of Hessian
                    approximation update. Recommended value:  3<=M<=7. The smaller
                    value causes worse convergence, the bigger will  not  cause  a
                    considerably better convergence, but will cause a fall in  the
                    performance. M<=N.
        X       -   initial solution approximation, array[0..N-1].

    OUTPUT PARAMETERS:
        State   -   structure used for reverse communication.

    This function  initializes  State   structure  with  default  optimization
    parameters (stopping conditions, step size, etc.). Use MinLBFGSSet??????()
    functions to tune optimization parameters.

    After   all   optimization   parameters   are   tuned,   you   should  use
    MinLBFGSIteration() function to advance algorithm iterations.

    NOTES:

    1. you may tune stopping conditions with MinLBFGSSetCond() function
    2. if target function contains exp() or other fast growing functions,  and
       optimization algorithm makes too large steps which leads  to  overflow,
       use MinLBFGSSetStpMax() function to bound algorithm's  steps.  However,
       L-BFGS rarely needs such a tuning.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlbfgscreate(int n,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        minlbfgsstate<Precision>& state);

Examples: minlbfgs_1 minlbfgs_2

### `minlbfgscreatex` function

    /*************************************************************************
    Extended subroutine for internal use only.

    Accepts additional parameters:

        Flags - additional settings:
                * Flags = 0     means no additional settings
                * Flags = 1     "do not allocate memory". used when solving
                                a many subsequent tasks with  same N/M  values.
                                First  call MUST  be without this flag bit set,
                                subsequent  calls   of   MinLBFGS   with   same
                                MinLBFGSState structure can set Flags to 1.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlbfgscreatex(int n,
        int m,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        int flags,
        minlbfgsstate<Precision>& state);

### `minlbfgsiteration` function

    /*************************************************************************
    L-BFGS iterations

    Called after initialization with MinLBFGSCreate() function.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinLBFGSCreate()

    RESULT:
    * if function returned False, iterative proces has converged.
      Use MinLBFGSResults() to obtain optimization results.
    * if subroutine returned True, then, depending on structure fields, we
      have one of the following situations

    === FUNC/GRAD REQUEST ===
    State.NeedFG is True => function value/gradient are needed.
    Caller should calculate function value State.F and gradient
    State.G[0..N-1] at State.X[0..N-1] and call MinLBFGSIteration() again.

    === NEW INTERATION IS REPORTED ===
    State.XUpdated is True => one more iteration was made.
    State.X contains current position, State.F contains function value at X.
    You can read info from these fields, but never modify  them  because  they
    contain the only copy of optimization algorithm state.

    One and only one of these fields (NeedFG, XUpdated) is true on return. New
    iterations are reported only when reports  are  explicitly  turned  on  by
    MinLBFGSSetXRep() function, so if you never called it, you can expect that
    NeedFG is always True.

      -- ALGLIB --
         Copyright 20.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool minlbfgsiteration(minlbfgsstate<Precision>& state);

Examples: minlbfgs_1 minlbfgs_2

### `minlbfgsresults` function

    /*************************************************************************
    L-BFGS algorithm results

    Called after MinLBFGSIteration() returned False.

    INPUT PARAMETERS:
        State   -   algorithm state (used by MinLBFGSIteration).

    OUTPUT PARAMETERS:
        X       -   array[0..N-1], solution
        Rep     -   optimization report:
                    * Rep.TerminationType completetion code:
                        * -2    rounding errors prevent further improvement.
                                X contains best point found.
                        * -1    incorrect parameters were specified
                        *  1    relative function improvement is no more than
                                EpsF.
                        *  2    relative step is no more than EpsX.
                        *  4    gradient norm is no more than EpsG
                        *  5    MaxIts steps was taken
                        *  7    stopping conditions are too stringent,
                                further improvement is impossible
                    * Rep.IterationsCount contains iterations count
                    * NFEV countains number of function calculations

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlbfgsresults(const minlbfgsstate<Precision>& state,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        minlbfgsreport<Precision>& rep);

Examples: minlbfgs_1 minlbfgs_2

### `minlbfgssetcond` function

    /*************************************************************************
    This function sets stopping conditions for L-BFGS optimization algorithm.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinLBFGSCreate()
        EpsG    -   >=0
                    The  subroutine  finishes  its  work   if   the  condition
                    ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
                    G - gradient.
        EpsF    -   >=0
                    The  subroutine  finishes  its work if on k+1-th iteration
                    the  condition  |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1}
                    is satisfied.
        EpsX    -   >=0
                    The subroutine finishes its work if  on  k+1-th  iteration
                    the condition |X(k+1)-X(k)| <= EpsX is fulfilled.
        MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
                    iterations is unlimited.

    Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
    automatic stopping criterion selection (small EpsX).

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlbfgssetcond(minlbfgsstate<Precision>& state,
        amp::ampf<Precision> epsg,
        amp::ampf<Precision> epsf,
        amp::ampf<Precision> epsx,
        int maxits);

### `minlbfgssetstpmax` function

    /*************************************************************************
    This function sets maximum step length

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinLBFGSCreate()
        StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
                    want to limit step length.

    Use this subroutine when you optimize target function which contains exp()
    or  other  fast  growing  functions,  and optimization algorithm makes too
    large  steps  which  leads  to overflow. This function allows us to reject
    steps  that  are  too  large  (and  therefore  expose  us  to the possible
    overflow) without actually calculating function value at the x+stp*d.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlbfgssetstpmax(minlbfgsstate<Precision>& state,
        amp::ampf<Precision> stpmax);

### `minlbfgssetxrep` function

    /*************************************************************************
    This function turns on/off reporting.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinLBFGSCreate()
        NeedXRep-   whether iteration reports are needed or not

    Usually algorithm returns  from  MinLBFGSIteration()  only when  it  needs
    function/gradient/ (which is indicated by NeedFG field. However, with this
    function we can let it  stop  after  each  iteration  (one  iteration  may
    include more than one function evaluation), which is indicated by XUpdated
    field.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlbfgssetxrep(minlbfgsstate<Precision>& state,
        bool needxrep);

### minlbfgs_1 example

        int n;
        int m;
        minlbfgs::minlbfgsstate<Precision> state;
        minlbfgs::minlbfgsreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Function minimized:
        //     F = exp(x-1) + exp(1-x) + (y-x)^2
        // N = 2 - task dimension
        // M = 1 - build tank-1 model
        //
        n = 2;
        m = 1;
        s.setlength(2);
        s(0) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        s(1) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        minlbfgs::minlbfgscreate<Precision>(n, m, s, state);
        minlbfgs::minlbfgssetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0001"), 0);
        while( minlbfgs::minlbfgsiteration<Precision>(state) )
        {
            if( state.needfg )
            {
                x = state.x(0);
                y = state.x(1);
                state.f = amp::exp<Precision>(x-1)+amp::exp<Precision>(1-x)+amp::sqr<Precision>(y-x);
                state.g(0) = amp::exp<Precision>(x-1)-amp::exp<Precision>(1-x)+2*(x-y);
                state.g(1) = 2*(y-x);
            }
        }
        minlbfgs::minlbfgsresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("\n\nF = exp(x-1) + exp(1-x) + (y-x)^2\n");
        printf("X = %4.2lf (should be 1.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (should be 1.00)\n\n\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));

### minlbfgs_2 example

        int n;
        int m;
        minlbfgs::minlbfgsstate<Precision> state;
        minlbfgs::minlbfgsreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Function minimized:
        //     F = exp(x-1) + exp(1-x) + (y-x)^2
        // N = 2 - task dimension
        // M = 1 - build tank-1 model
        //
        n = 2;
        m = 1;
        s.setlength(2);
        s(0) = 10;
        s(1) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        minlbfgs::minlbfgscreate<Precision>(n, m, s, state);
        minlbfgs::minlbfgssetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0001"), 0);
        minlbfgs::minlbfgssetxrep<Precision>(state, true);
        printf("\n\nF = exp(x-1) + exp(1-x) + (y-x)^2\n");
        printf("OPTIMIZATION STARTED\n");
        while( minlbfgs::minlbfgsiteration<Precision>(state) )
        {
            if( state.needfg )
            {
                x = state.x(0);
                y = state.x(1);
                state.f = amp::exp<Precision>(x-1)+amp::exp<Precision>(1-x)+amp::sqr<Precision>(y-x);
                state.g(0) = amp::exp<Precision>(x-1)-amp::exp<Precision>(1-x)+2*(x-y);
                state.g(1) = 2*(y-x);
            }
            if( state.xupdated )
            {
                printf("    F(%8.5lf,%8.5lf)=%0.5lf\n",
                    double(amp::ampf<Precision>(state.x(0)).toDouble()),
                    double(amp::ampf<Precision>(state.x(1)).toDouble()),
                    double(amp::ampf<Precision>(state.f).toDouble()));
            }
        }
        printf("OPTIMIZATION STOPPED\n");
        minlbfgs::minlbfgsresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (should be 1.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (should be 1.00)\n\n\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));

## `minlm` unit

### Functions

minlmcreatefgh
minlmcreatefgj
minlmcreatefj
minlmiteration
minlmresults
minlmsetcond
minlmsetstpmax
minlmsetxrep

### Examples

minlm_fgh
minlm_fgj
minlm_fj
minlm_fj2

### `minlmcreatefgh` function

    /*************************************************************************
        LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION

    Optimization using function gradient and Hessian.  Algorithm -  Levenberg-
    Marquardt   modification   with   L-BFGS   pre-optimization  and  internal
    pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step.

    Function F has general form (not "sum-of-squares"):

        F = F(x[0], ..., x[n-1])

    EXAMPLE

    See HTML-documentation.

    INPUT PARAMETERS:
        N       -   dimension, N>1
        X       -   initial solution, array[0..N-1]

    OUTPUT PARAMETERS:
        State   -   structure which stores algorithm state between subsequent
                    calls of MinLMIteration. Used for reverse communication.
                    This structure should be passed to MinLMIteration subroutine.

    See also MinLMIteration, MinLMResults.

    NOTES:

    1. you may tune stopping conditions with MinLMSetCond() function
    2. if target function contains exp() or other fast growing functions,  and
       optimization algorithm makes too large steps which leads  to  overflow,
       use MinLMSetStpMax() function to bound algorithm's steps.

      -- ALGLIB --
         Copyright 30.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmcreatefgh(const int& n,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        minlmstate<Precision>& state);

Examples: minlm_fgh

### `minlmcreatefgj` function

    /*************************************************************************
        LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION

    Optimization using function gradient and Jacobian.  Algorithm -  Levenberg-
    Marquardt   modification   with   L-BFGS   pre-optimization  and  internal
    pre-conditioned L-BFGS optimization after each Levenberg-Marquardt step.

    Function F is represented as sum of squares:

        F = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])

    EXAMPLE

    See HTML-documentation.

    INPUT PARAMETERS:
        N       -   dimension, N>1
        M       -   number of functions f[i]
        X       -   initial solution, array[0..N-1]

    OUTPUT PARAMETERS:
        State   -   structure which stores algorithm state between subsequent
                    calls of MinLMIteration. Used for reverse communication.
                    This structure should be passed to MinLMIteration subroutine.

    See also MinLMIteration, MinLMResults.

    NOTES:

    1. you may tune stopping conditions with MinLMSetCond() function
    2. if target function contains exp() or other fast growing functions,  and
       optimization algorithm makes too large steps which leads  to  overflow,
       use MinLMSetStpMax() function to bound algorithm's steps.

      -- ALGLIB --
         Copyright 30.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmcreatefgj(const int& n,
        const int& m,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        minlmstate<Precision>& state);

Examples: minlm_fgj

### `minlmcreatefj` function

    /*************************************************************************
        CLASSIC LEVENBERG-MARQUARDT METHOD FOR NON-LINEAR OPTIMIZATION

    Optimization using Jacobi matrix. Algorithm  -  classic Levenberg-Marquardt
    method.

    Function F is represented as sum of squares:

        F = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1])

    EXAMPLE

    See HTML-documentation.

    INPUT PARAMETERS:
        N       -   dimension, N>1
        M       -   number of functions f[i]
        X       -   initial solution, array[0..N-1]

    OUTPUT PARAMETERS:
        State   -   structure which stores algorithm state between subsequent
                    calls of MinLMIteration. Used for reverse communication.
                    This structure should be passed to MinLMIteration subroutine.

    See also MinLMIteration, MinLMResults.

    NOTES:

    1. you may tune stopping conditions with MinLMSetCond() function
    2. if target function contains exp() or other fast growing functions,  and
       optimization algorithm makes too large steps which leads  to  overflow,
       use MinLMSetStpMax() function to bound algorithm's steps.

      -- ALGLIB --
         Copyright 30.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmcreatefj(const int& n,
        const int& m,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        minlmstate<Precision>& state);

Examples: minlm_fj minlm_fj2

### `minlmiteration` function

    /*************************************************************************
    One Levenberg-Marquardt iteration.

    Called after inialization of State structure with MinLMXXX subroutine.
    See HTML docs for examples.

    Input parameters:
        State   -   structure which stores algorithm state between subsequent
                    calls and which is used for reverse communication. Must be
                    initialized with MinLMXXX call first.

    If subroutine returned False, iterative algorithm has converged.

    If subroutine returned True, then:
    * if State.NeedF=True,      -   function value F at State.X[0..N-1]
                                    is required
    * if State.NeedFG=True      -   function value F and gradient G
                                    are required
    * if State.NeedFiJ=True     -   function vector f[i] and Jacobi matrix J
                                    are required
    * if State.NeedFGH=True     -   function value F, gradient G and Hesian H
                                    are required
    * if State.XUpdated=True    -   algorithm reports about new iteration,
                                    State.X contains current point,
                                    State.F contains function value.

    One and only one of this fields can be set at time.

    Results are stored:
    * function value            -   in MinLMState.F
    * gradient                  -   in MinLMState.G[0..N-1]
    * Jacobi matrix             -   in MinLMState.J[0..M-1,0..N-1]
    * Hessian                   -   in MinLMState.H[0..N-1,0..N-1]

      -- ALGLIB --
         Copyright 10.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool minlmiteration(minlmstate<Precision>& state);

Examples: minlm_fgh minlm_fgj minlm_fj minlm_fj2

### `minlmresults` function

    /*************************************************************************
    Levenberg-Marquardt algorithm results

    Called after MinLMIteration returned False.

    Input parameters:
        State   -   algorithm state (used by MinLMIteration).

    Output parameters:
        X       -   array[0..N-1], solution
        Rep     -   optimization report:
                    * Rep.TerminationType completetion code:
                        * -1    incorrect parameters were specified
                        *  1    relative function improvement is no more than
                                EpsF.
                        *  2    relative step is no more than EpsX.
                        *  4    gradient is no more than EpsG.
                        *  5    MaxIts steps was taken
                        *  7    stopping conditions are too stringent,
                                further improvement is impossible
                    * Rep.IterationsCount contains iterations count
                    * Rep.NFunc     - number of function calculations
                    * Rep.NJac      - number of Jacobi matrix calculations
                    * Rep.NGrad     - number of gradient calculations
                    * Rep.NHess     - number of Hessian calculations
                    * Rep.NCholesky - number of Cholesky decomposition calculations

      -- ALGLIB --
         Copyright 10.03.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmresults(const minlmstate<Precision>& state,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        minlmreport<Precision>& rep);

Examples: minlm_fgh minlm_fgj minlm_fj minlm_fj2

### `minlmsetcond` function

    /*************************************************************************
    This function sets stopping conditions for Levenberg-Marquardt optimization
    algorithm.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be initialized
                    with MinLMCreate???()
        EpsG    -   >=0
                    The  subroutine  finishes  its  work   if   the  condition
                    ||G||<EpsG is satisfied, where ||.|| means Euclidian norm,
                    G - gradient.
        EpsF    -   >=0
                    The  subroutine  finishes  its work if on k+1-th iteration
                    the  condition  |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1}
                    is satisfied.
        EpsX    -   >=0
                    The subroutine finishes its work if  on  k+1-th  iteration
                    the condition |X(k+1)-X(k)| <= EpsX is fulfilled.
        MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
                    iterations   is    unlimited.   Only   Levenberg-Marquardt
                    iterations  are  counted  (L-BFGS/CG  iterations  are  NOT
                    counted  because their cost is very low copared to that of
                    LM).

    Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to
    automatic stopping criterion selection (small EpsX).

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmsetcond(minlmstate<Precision>& state,
        amp::ampf<Precision> epsg,
        amp::ampf<Precision> epsf,
        amp::ampf<Precision> epsx,
        int maxits);

### `minlmsetstpmax` function

    /*************************************************************************
    This function sets maximum step length

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinCGCreate???()
        StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
                    want to limit step length.

    Use this subroutine when you optimize target function which contains exp()
    or  other  fast  growing  functions,  and optimization algorithm makes too
    large  steps  which  leads  to overflow. This function allows us to reject
    steps  that  are  too  large  (and  therefore  expose  us  to the possible
    overflow) without actually calculating function value at the x+stp*d.

    NOTE: non-zero StpMax leads to moderate  performance  degradation  because
    intermediate  step  of  preconditioned L-BFGS optimization is incompatible
    with limits on step size.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmsetstpmax(minlmstate<Precision>& state,
        amp::ampf<Precision> stpmax);

### `minlmsetxrep` function

    /*************************************************************************
    This function turns on/off reporting.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between calls and
                    which is used for reverse communication. Must be
                    initialized with MinLMCreate???()
        NeedXRep-   whether iteration reports are needed or not

    Usually  algorithm  returns  from  MinLMIteration()  only  when  it  needs
    function/gradient/Hessian. However, with this function we can let it  stop
    after  each  iteration  (one iteration may include  more than one function
    evaluation), which is indicated by XUpdated field.

    Both Levenberg-Marquardt and L-BFGS iterations are reported.

      -- ALGLIB --
         Copyright 02.04.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void minlmsetxrep(minlmstate<Precision>& state,
        bool needxrep);

### minlm_fgh example

        minlm::minlmstate<Precision> state;
        minlm::minlmreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Example of solving simple task using FGH scheme.
        //
        // Function minimized:
        //     F = (x-2*y)^2 + (x-2)^2 + (y-1)^2
        // exact solution is (2,1).
        //
        s.setlength(2);
        s(0) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        s(1) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        minlm::minlmcreatefgh<Precision>(2, s, state);
        minlm::minlmsetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.001"), 0);
        while( minlm::minlmiteration<Precision>(state) )
        {
            x = state.x(0);
            y = state.x(1);
            if( state.needf )
            {
                state.f = amp::sqr<Precision>(x-2*y)+amp::sqr<Precision>(x-2)+amp::sqr<Precision>(y-1);
            }
            if( state.needfg )
            {
                state.f = amp::sqr<Precision>(x-2*y)+amp::sqr<Precision>(x-2)+amp::sqr<Precision>(y-1);
                state.g(0) = 2*(x-2*y)+2*(x-2)+0;
                state.g(1) = -4*(x-2*y)+0+2*(y-1);
            }
            if( state.needfgh )
            {
                state.f = amp::sqr<Precision>(x-2*y)+amp::sqr<Precision>(x-2)+amp::sqr<Precision>(y-1);
                state.g(0) = 2*(x-2*y)+2*(x-2)+0;
                state.g(1) = -4*(x-2*y)+0+2*(y-1);
                state.h(0,0) = 4;
                state.h(1,0) = -4;
                state.h(0,1) = -4;
                state.h(1,1) = 10;
            }
        }
        minlm::minlmresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (correct value - 2.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (correct value - 1.00)\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));
        printf("TerminationType = %0ld (should be 2 - stopping when step is small enough)\n",
            long(rep.terminationtype));
        printf("NFunc = %0ld\n",
            long(rep.nfunc));
        printf("NJac  = %0ld\n",
            long(rep.njac));
        printf("NGrad = %0ld\n",
            long(rep.ngrad));
        printf("NHess = %0ld\n",
            long(rep.nhess));

### minlm_fgj example

        minlm::minlmstate<Precision> state;
        minlm::minlmreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Example of solving simple task using FGJ scheme.
        //
        // Function minimized:
        //     F = (x-2*y)^2 + (x-2)^2 + (y-1)^2
        // exact solution is (2,1).
        //
        s.setlength(2);
        s(0) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        s(1) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        minlm::minlmcreatefgj<Precision>(2, 3, s, state);
        minlm::minlmsetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.001"), 0);
        while( minlm::minlmiteration<Precision>(state) )
        {
            x = state.x(0);
            y = state.x(1);
            if( state.needf )
            {
                state.f = amp::sqr<Precision>(x-2*y)+amp::sqr<Precision>(x-2)+amp::sqr<Precision>(y-1);
            }
            if( state.needfg )
            {
                state.f = amp::sqr<Precision>(x-2*y)+amp::sqr<Precision>(x-2)+amp::sqr<Precision>(y-1);
                state.g(0) = 2*(x-2*y)+2*(x-2)+0;
                state.g(1) = -4*(x-2*y)+0+2*(y-1);
            }
            if( state.needfij )
            {
                state.fi(0) = x-2*y;
                state.fi(1) = x-2;
                state.fi(2) = y-1;
                state.j(0,0) = 1;
                state.j(0,1) = -2;
                state.j(1,0) = 1;
                state.j(1,1) = 0;
                state.j(2,0) = 0;
                state.j(2,1) = 1;
            }
        }
        minlm::minlmresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (correct value - 2.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (correct value - 1.00)\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));
        printf("TerminationType = %0ld (should be 2 - stopping when step is small enough)\n",
            long(rep.terminationtype));
        printf("NFunc = %0ld\n",
            long(rep.nfunc));
        printf("NJac  = %0ld\n",
            long(rep.njac));
        printf("NGrad = %0ld\n",
            long(rep.ngrad));
        printf("NHess = %0ld\n",
            long(rep.nhess));

### minlm_fj example

        minlm::minlmstate<Precision> state;
        minlm::minlmreport<Precision> rep;
        ap::template_1d_array< amp::ampf<Precision> > s;
        amp::ampf<Precision> x;
        amp::ampf<Precision> y;

        //
        // Example of solving simple task using FJ scheme.
        //
        // Function minimized:
        //     F = (x-2*y)^2 + (x-2)^2 + (y-1)^2
        // exact solution is (2,1).
        //
        s.setlength(2);
        s(0) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        s(1) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        minlm::minlmcreatefj<Precision>(2, 3, s, state);
        minlm::minlmsetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.001"), 0);
        while( minlm::minlmiteration<Precision>(state) )
        {
            x = state.x(0);
            y = state.x(1);
            if( state.needf )
            {
                state.f = amp::sqr<Precision>(x-2*y)+amp::sqr<Precision>(x-2)+amp::sqr<Precision>(y-1);
            }
            if( state.needfij )
            {
                state.fi(0) = x-2*y;
                state.fi(1) = x-2;
                state.fi(2) = y-1;
                state.j(0,0) = 1;
                state.j(0,1) = -2;
                state.j(1,0) = 1;
                state.j(1,1) = 0;
                state.j(2,0) = 0;
                state.j(2,1) = 1;
            }
        }
        minlm::minlmresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("X = %4.2lf (correct value - 2.00)\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("Y = %4.2lf (correct value - 1.00)\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));
        printf("TerminationType = %0ld (should be 2 - stopping when step is small enough)\n",
            long(rep.terminationtype));
        printf("NFunc = %0ld\n",
            long(rep.nfunc));
        printf("NJac  = %0ld\n",
            long(rep.njac));
        printf("NGrad = %0ld\n",
            long(rep.ngrad));
        printf("NHess = %0ld\n",
            long(rep.nhess));

### minlm_fj2 example

        minlm::minlmstate<Precision> state;
        minlm::minlmreport<Precision> rep;
        int i;
        ap::template_1d_array< amp::ampf<Precision> > s;
        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        amp::ampf<Precision> fi;
        int n;
        int m;

        //
        // Example of solving polynomial approximation task using FJ scheme.
        //
        // Data points:
        //     xi are random numbers from [-1,+1],
        //
        // Function being fitted:
        //     yi = exp(xi) - sin(xi) - x^3/3
        //
        // Function being minimized:
        //     F(a,b,c) =
        //         (a + b*x0 + c*x0^2 - y0)^2 +
        //         (a + b*x1 + c*x1^2 - y1)^2 + ...
        //
        n = 3;
        s.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            s(i) = amp::ampf<Precision>::getRandom()-amp::ampf<Precision>("0.5");
        }
        m = 100;
        x.setlength(m);
        y.setlength(m);
        for(i=0; i<=m-1; i++)
        {
            x(i) = amp::ampf<Precision>(2*i)/(amp::ampf<Precision>(m-1))-1;
            y(i) = amp::exp<Precision>(x(i))-amp::sin<Precision>(x(i))-x(i)*x(i)*x(i)/3;
        }

        //
        // Now S stores starting point, X and Y store points being fitted.
        //
        minlm::minlmcreatefj<Precision>(n, m, s, state);
        minlm::minlmsetcond<Precision>(state, amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.0"), amp::ampf<Precision>("0.001"), 0);
        while( minlm::minlmiteration<Precision>(state) )
        {
            if( state.needf )
            {
                state.f = 0;
            }
            for(i=0; i<=m-1; i++)
            {

                //
                // "a" is stored in State.X[0]
                // "b" - State.X[1]
                // "c" - State.X[2]
                //
                fi = state.x(0)+state.x(1)*x(i)+state.x(2)*amp::sqr<Precision>(x(i))-y(i);
                if( state.needf )
                {

                    //
                    // F is equal to sum of fi squared.
                    //
                    state.f = state.f+amp::sqr<Precision>(fi);
                }
                if( state.needfij )
                {

                    //
                    // Fi
                    //
                    state.fi(i) = fi;

                    //
                    // dFi/da
                    //
                    state.j(i,0) = 1;

                    //
                    // dFi/db
                    //
                    state.j(i,1) = x(i);

                    //
                    // dFi/dc
                    //
                    state.j(i,2) = amp::sqr<Precision>(x(i));
                }
            }
        }
        minlm::minlmresults<Precision>(state, s, rep);

        //
        // output results
        //
        printf("A = %4.2lf\n",
            double(amp::ampf<Precision>(s(0)).toDouble()));
        printf("B = %4.2lf\n",
            double(amp::ampf<Precision>(s(1)).toDouble()));
        printf("C = %4.2lf\n",
            double(amp::ampf<Precision>(s(2)).toDouble()));
        printf("TerminationType = %0ld (should be 2 - stopping when step is small enough)\n",
            long(rep.terminationtype));

## `odesolver` unit

### Functions

odesolveriteration
odesolverresults
odesolverrkck

### Examples

ode_example1
ode_example2

### `odesolveriteration` function

    /*************************************************************************
    One iteration of ODE solver.

    Called after inialization of State structure with OdeSolverXXX subroutine.
    See HTML docs for examples.

    INPUT PARAMETERS:
        State   -   structure which stores algorithm state between subsequent
                    calls and which is used for reverse communication. Must be
                    initialized with OdeSolverXXX() call first.

    If subroutine returned False, algorithm have finished its work.
    If subroutine returned True, then user should:
    * calculate F(State.X, State.Y)
    * store it in State.DY
    Here State.X is real, State.Y and State.DY are arrays[0..N-1] of reals.

      -- ALGLIB --
         Copyright 01.09.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool odesolveriteration(odesolverstate<Precision>& state);

Examples: ode_example1 ode_example2

### `odesolverresults` function

    /*************************************************************************
    ODE solver results

    Called after OdeSolverIteration returned False.

    INPUT PARAMETERS:
        State   -   algorithm state (used by OdeSolverIteration).

    OUTPUT PARAMETERS:
        M       -   number of tabulated values, M>=1
        XTbl    -   array[0..M-1], values of X
        YTbl    -   array[0..M-1,0..N-1], values of Y in X[i]
        Rep     -   solver report:
                    * Rep.TerminationType completetion code:
                        * -2    X is not ordered  by  ascending/descending  or
                                there are non-distinct X[],  i.e.  X[i]=X[i+1]
                        * -1    incorrect parameters were specified
                        *  1    task has been solved
                    * Rep.NFEV contains number of function calculations

      -- ALGLIB --
         Copyright 01.09.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void odesolverresults(const odesolverstate<Precision>& state,
        int& m,
        ap::template_1d_array< amp::ampf<Precision> >& xtbl,
        ap::template_2d_array< amp::ampf<Precision> >& ytbl,
        odesolverreport<Precision>& rep);

Examples: ode_example1 ode_example2

### `odesolverrkck` function

    /*************************************************************************
    Cash-Karp adaptive ODE solver.

    This subroutine solves ODE  Y'=f(Y,x)  with  initial  conditions  Y(xs)=Ys
    (here Y may be single variable or vector of N variables).

    INPUT PARAMETERS:
        Y       -   initial conditions, array[0..N-1].
                    contains values of Y[] at X[0]
        N       -   system size
        X       -   points at which Y should be tabulated, array[0..M-1]
                    integrations starts at X[0], ends at X[M-1],  intermediate
                    values at X[i] are returned too.
                    SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!!!
        M       -   number of intermediate points + first point + last point:
                    * M>2 means that you need both Y(X[M-1]) and M-2 values at
                      intermediate points
                    * M=2 means that you want just to integrate from  X[0]  to
                      X[1] and don't interested in intermediate values.
                    * M=1 means that you don't want to integrate :)
                      it is degenerate case, but it will be handled correctly.
                    * M<1 means error
        Eps     -   tolerance (absolute/relative error on each  step  will  be
                    less than Eps). When passing:
                    * Eps>0, it means desired ABSOLUTE error
                    * Eps<0, it means desired RELATIVE error.  Relative errors
                      are calculated with respect to maximum values of  Y seen
                      so far. Be careful to use this criterion  when  starting
                      from Y[] that are close to zero.
        H       -   initial  step  lenth,  it  will  be adjusted automatically
                    after the first  step.  If  H=0,  step  will  be  selected
                    automatically  (usualy  it  will  be  equal  to  0.001  of
                    min(x[i]-x[j])).

    OUTPUT PARAMETERS
        State   -   structure which stores algorithm state between  subsequent
                    calls of OdeSolverIteration. Used for reverse communication.
                    This structure should be passed  to the OdeSolverIteration
                    subroutine.

    SEE ALSO
        AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults.

      -- ALGLIB --
         Copyright 01.09.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void odesolverrkck(const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& x,
        int m,
        amp::ampf<Precision> eps,
        amp::ampf<Precision> h,
        odesolverstate<Precision>& state);

Examples: ode_example1 ode_example2

### ode_example1 example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_2d_array< amp::ampf<Precision> > ytbl;
        amp::ampf<Precision> eps;
        amp::ampf<Precision> h;
        int m;
        int i;
        odesolver::odesolverstate<Precision> state;
        odesolver::odesolverreport<Precision> rep;

        //
        // ODESolver unit is used to solve simple ODE:
        // y' = y, y(0) = 1.
        //
        // Its solution is well known in academic circles :)
        //
        // No intermediate values are calculated,
        // just starting and final points.
        //
        y.setlength(1);
        y(0) = 1;
        x.setlength(2);
        x(0) = 0;
        x(1) = 1;
        eps = amp::ampf<Precision>("1.0E-4");
        h = amp::ampf<Precision>("0.01");
        odesolver::odesolverrkck<Precision>(y, 1, x, 2, eps, h, state);
        while( odesolver::odesolveriteration<Precision>(state) )
        {
            state.dy(0) = state.y(0);
        }
        odesolver::odesolverresults<Precision>(state, m, x, ytbl, rep);
        printf("    X  Y(X)\n");
        for(i=0; i<=m-1; i++)
        {
            printf("%5.3lf %5.3lf\n",
                double(amp::ampf<Precision>(x(i)).toDouble()),
                double(amp::ampf<Precision>(ytbl(i,0)).toDouble()));
        }

### ode_example2 example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_2d_array< amp::ampf<Precision> > ytbl;
        amp::ampf<Precision> eps;
        amp::ampf<Precision> h;
        int m;
        int i;
        odesolver::odesolverstate<Precision> state;
        odesolver::odesolverreport<Precision> rep;

        //
        // ODESolver unit is used to solve simple ODE:
        // y'' = -y, y(0) = 0, y'(0)=1.
        //
        // This ODE may be written as first-order system:
        // y' =  z
        // z' = -y
        //
        // Its solution is well known in academic circles :)
        //
        // Three intermediate values are calculated,
        // plus starting and final points.
        //
        y.setlength(2);
        y(0) = 0;
        y(1) = 1;
        x.setlength(5);
        x(0) = amp::pi<Precision>()*0/4;
        x(1) = amp::pi<Precision>()*1/4;
        x(2) = amp::pi<Precision>()*2/4;
        x(3) = amp::pi<Precision>()*3/4;
        x(4) = amp::pi<Precision>()*4/4;
        eps = amp::ampf<Precision>("1.0E-8");
        h = amp::ampf<Precision>("0.01");
        odesolver::odesolverrkck<Precision>(y, 2, x, 5, eps, h, state);
        while( odesolver::odesolveriteration<Precision>(state) )
        {
            state.dy(0) = state.y(1);
            state.dy(1) = -state.y(0);
        }
        odesolver::odesolverresults<Precision>(state, m, x, ytbl, rep);
        printf("     X   Y(X)     Error\n");
        for(i=0; i<=m-1; i++)
        {
            printf("%6.3lf %6.3lf  %8.1le\n",
                double(amp::ampf<Precision>(x(i)).toDouble()),
                double(amp::ampf<Precision>(ytbl(i,0)).toDouble()),
                double(amp::ampf<Precision>(amp::abs<Precision>(ytbl(i,0)-amp::sin<Precision>(x(i)))).toDouble()));
        }

## `ortfac` unit

### Functions

cmatrixlq
cmatrixlqunpackl
cmatrixlqunpackq
cmatrixqr
cmatrixqrunpackq
cmatrixqrunpackr
hmatrixtd
hmatrixtdunpackq
rmatrixbd
rmatrixbdmultiplybyp
rmatrixbdmultiplybyq
rmatrixbdunpackdiagonals
rmatrixbdunpackpt
rmatrixbdunpackq
rmatrixhessenberg
rmatrixhessenbergunpackh
rmatrixhessenbergunpackq
rmatrixlq
rmatrixlqunpackl
rmatrixlqunpackq
rmatrixqr
rmatrixqrunpackq
rmatrixqrunpackr
smatrixtd
smatrixtdunpackq

### `cmatrixlq` function

    /*************************************************************************
    LQ decomposition of a rectangular complex matrix of size MxN

    Input parameters:
        A   -   matrix A whose indexes range within [0..M-1, 0..N-1]
        M   -   number of rows in matrix A.
        N   -   number of columns in matrix A.

    Output parameters:
        A   -   matrices Q and L in compact form
        Tau -   array of scalar factors which are used to form matrix Q. Array
                whose indexes range within [0.. Min(M,N)-1]

    Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size
    MxM, L - lower triangular (or lower trapezoid) matrix of size MxN.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         September 30, 1994
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlq(ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& tau);

### `cmatrixlqunpackl` function

    /*************************************************************************
    Unpacking of matrix L from the LQ decomposition of a matrix A

    Input parameters:
        A       -   matrices Q and L in compact form.
                    Output of CMatrixLQ subroutine.
        M       -   number of rows in given matrix A. M>=0.
        N       -   number of columns in given matrix A. N>=0.

    Output parameters:
        L       -   matrix L, array[0..M-1, 0..N-1].

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlqunpackl(const ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        ap::template_2d_array< amp::campf<Precision> >& l);

### `cmatrixlqunpackq` function

    /*************************************************************************
    Partial unpacking of matrix Q from LQ decomposition of a complex matrix A.

    Input parameters:
        A           -   matrices Q and R in compact form.
                        Output of CMatrixLQ subroutine .
        M           -   number of rows in matrix A. M>=0.
        N           -   number of columns in matrix A. N>=0.
        Tau         -   scalar factors which are used to form Q.
                        Output of CMatrixLQ subroutine .
        QRows       -   required number of rows in matrix Q. N>=QColumns>=0.

    Output parameters:
        Q           -   first QRows rows of matrix Q.
                        Array whose index ranges within [0..QRows-1, 0..N-1].
                        If QRows=0, array isn't changed.

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlqunpackq(const ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        const ap::template_1d_array< amp::campf<Precision> >& tau,
        int qrows,
        ap::template_2d_array< amp::campf<Precision> >& q);

### `cmatrixqr` function

    /*************************************************************************
    QR decomposition of a rectangular complex matrix of size MxN

    Input parameters:
        A   -   matrix A whose indexes range within [0..M-1, 0..N-1]
        M   -   number of rows in matrix A.
        N   -   number of columns in matrix A.

    Output parameters:
        A   -   matrices Q and R in compact form
        Tau -   array of scalar factors which are used to form matrix Q. Array
                whose indexes range within [0.. Min(M,N)-1]

    Matrix A is represented as A = QR, where Q is an orthogonal matrix of size
    MxM, R - upper triangular (or upper trapezoid) matrix of size MxN.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         September 30, 1994
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixqr(ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< amp::campf<Precision> >& tau);

### `cmatrixqrunpackq` function

    /*************************************************************************
    Partial unpacking of matrix Q from QR decomposition of a complex matrix A.

    Input parameters:
        A           -   matrices Q and R in compact form.
                        Output of CMatrixQR subroutine .
        M           -   number of rows in matrix A. M>=0.
        N           -   number of columns in matrix A. N>=0.
        Tau         -   scalar factors which are used to form Q.
                        Output of CMatrixQR subroutine .
        QColumns    -   required number of columns in matrix Q. M>=QColumns>=0.

    Output parameters:
        Q           -   first QColumns columns of matrix Q.
                        Array whose index ranges within [0..M-1, 0..QColumns-1].
                        If QColumns=0, array isn't changed.

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixqrunpackq(const ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        const ap::template_1d_array< amp::campf<Precision> >& tau,
        int qcolumns,
        ap::template_2d_array< amp::campf<Precision> >& q);

### `cmatrixqrunpackr` function

    /*************************************************************************
    Unpacking of matrix R from the QR decomposition of a matrix A

    Input parameters:
        A       -   matrices Q and R in compact form.
                    Output of CMatrixQR subroutine.
        M       -   number of rows in given matrix A. M>=0.
        N       -   number of columns in given matrix A. N>=0.

    Output parameters:
        R       -   matrix R, array[0..M-1, 0..N-1].

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixqrunpackr(const ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        ap::template_2d_array< amp::campf<Precision> >& r);

### `hmatrixtd` function

    /*************************************************************************
    Reduction of a Hermitian matrix which is given  by  its  higher  or  lower
    triangular part to a real  tridiagonal  matrix  using  unitary  similarity
    transformation: Q'*A*Q = T.

    Input parameters:
        A       -   matrix to be transformed
                    array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format. If IsUpper = True, then matrix A is  given
                    by its upper triangle, and the lower triangle is not  used
                    and not modified by the algorithm, and vice versa
                    if IsUpper = False.

    Output parameters:
        A       -   matrices T and Q in  compact form (see lower)
        Tau     -   array of factors which are forming matrices H(i)
                    array with elements [0..N-2].
        D       -   main diagonal of real symmetric matrix T.
                    array with elements [0..N-1].
        E       -   secondary diagonal of real symmetric matrix T.
                    array with elements [0..N-2].

      If IsUpper=True, the matrix Q is represented as a product of elementary
      reflectors

         Q = H(n-2) . . . H(2) H(0).

      Each H(i) has the form

         H(i) = I - tau * v * v'

      where tau is a complex scalar, and v is a complex vector with
      v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in
      A(0:i-1,i+1), and tau in TAU(i).

      If IsUpper=False, the matrix Q is represented as a product of elementary
      reflectors

         Q = H(0) H(2) . . . H(n-2).

      Each H(i) has the form

         H(i) = I - tau * v * v'

      where tau is a complex scalar, and v is a complex vector with
      v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i),
      and tau in TAU(i).

      The contents of A on exit are illustrated by the following examples
      with n = 5:

      if UPLO = 'U':                       if UPLO = 'L':

        (  d   e   v1  v2  v3 )              (  d                  )
        (      d   e   v2  v3 )              (  e   d              )
        (          d   e   v3 )              (  v0  e   d          )
        (              d   e  )              (  v0  v1  e   d      )
        (                  d  )              (  v0  v1  v2  e   d  )

    where d and e denote diagonal and off-diagonal elements of T, and vi
    denotes an element of the vector defining H(i).

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         October 31, 1992
    *************************************************************************/
    template<unsigned int Precision>
    void hmatrixtd(ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        ap::template_1d_array< amp::campf<Precision> >& tau,
        ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_1d_array< amp::ampf<Precision> >& e);

### `hmatrixtdunpackq` function

    /*************************************************************************
    Unpacking matrix Q which reduces a Hermitian matrix to a real  tridiagonal
    form.

    Input parameters:
        A       -   the result of a HMatrixTD subroutine
        N       -   size of matrix A.
        IsUpper -   storage format (a parameter of HMatrixTD subroutine)
        Tau     -   the result of a HMatrixTD subroutine

    Output parameters:
        Q       -   transformation matrix.
                    array with elements [0..N-1, 0..N-1].

      -- ALGLIB --
         Copyright 2005-2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void hmatrixtdunpackq(const ap::template_2d_array< amp::campf<Precision> >& a,
        const int& n,
        const bool& isupper,
        const ap::template_1d_array< amp::campf<Precision> >& tau,
        ap::template_2d_array< amp::campf<Precision> >& q);

### `rmatrixbd` function

    /*************************************************************************
    Reduction of a rectangular matrix to  bidiagonal form

    The algorithm reduces the rectangular matrix A to  bidiagonal form by
    orthogonal transformations P and Q: A = Q*B*P.

    Input parameters:
        A       -   source matrix. array[0..M-1, 0..N-1]
        M       -   number of rows in matrix A.
        N       -   number of columns in matrix A.

    Output parameters:
        A       -   matrices Q, B, P in compact form (see below).
        TauQ    -   scalar factors which are used to form matrix Q.
        TauP    -   scalar factors which are used to form matrix P.

    The main diagonal and one of the  secondary  diagonals  of  matrix  A  are
    replaced with bidiagonal  matrix  B.  Other  elements  contain  elementary
    reflections which form MxM matrix Q and NxN matrix P, respectively.

    If M>=N, B is the upper  bidiagonal  MxN  matrix  and  is  stored  in  the
    corresponding  elements  of  matrix  A.  Matrix  Q  is  represented  as  a
    product   of   elementary   reflections   Q = H(0)*H(1)*...*H(n-1),  where
    H(i) = 1-tau*v*v'. Here tau is a scalar which is stored  in  TauQ[i],  and
    vector v has the following  structure:  v(0:i-1)=0, v(i)=1, v(i+1:m-1)  is
    stored   in   elements   A(i+1:m-1,i).   Matrix   P  is  as  follows:  P =
    G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i],
    u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1).

    If M<N, B is the  lower  bidiagonal  MxN  matrix  and  is  stored  in  the
    corresponding   elements  of  matrix  A.  Q = H(0)*H(1)*...*H(m-2),  where
    H(i) = 1 - tau*v*v', tau is stored in TauQ, v(0:i)=0, v(i+1)=1, v(i+2:m-1)
    is    stored    in   elements   A(i+2:m-1,i).    P = G(0)*G(1)*...*G(m-1),
    G(i) = 1-tau*u*u', tau is stored in  TauP,  u(0:i-1)=0, u(i)=1, u(i+1:n-1)
    is stored in A(i,i+1:n-1).

    EXAMPLE:

    m=6, n=5 (m > n):               m=5, n=6 (m < n):

    (  d   e   u1  u1  u1 )         (  d   u1  u1  u1  u1  u1 )
    (  v1  d   e   u2  u2 )         (  e   d   u2  u2  u2  u2 )
    (  v1  v2  d   e   u3 )         (  v1  e   d   u3  u3  u3 )
    (  v1  v2  v3  d   e  )         (  v1  v2  e   d   u4  u4 )
    (  v1  v2  v3  v4  d  )         (  v1  v2  v3  e   d   u5 )
    (  v1  v2  v3  v4  v5 )

    Here vi and ui are vectors which form H(i) and G(i), and d and e -
    are the diagonal and off-diagonal elements of matrix B.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         September 30, 1994.
         Sergey Bochkanov, ALGLIB project, translation from FORTRAN to
         pseudocode, 2007-2010.
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixbd(ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& tauq,
        ap::template_1d_array< amp::ampf<Precision> >& taup);

### `rmatrixbdmultiplybyp` function

    /*************************************************************************
    Multiplication by matrix P which reduces matrix A to  bidiagonal form.

    The algorithm allows pre- or post-multiply by P or P'.

    Input parameters:
        QP          -   matrices Q and P in compact form.
                        Output of RMatrixBD subroutine.
        M           -   number of rows in matrix A.
        N           -   number of columns in matrix A.
        TAUP        -   scalar factors which are used to form P.
                        Output of RMatrixBD subroutine.
        Z           -   multiplied matrix.
                        Array whose indexes range within [0..ZRows-1,0..ZColumns-1].
        ZRows       -   number of rows in matrix Z. If FromTheRight=False,
                        ZRows=N, otherwise ZRows can be arbitrary.
        ZColumns    -   number of columns in matrix Z. If FromTheRight=True,
                        ZColumns=N, otherwise ZColumns can be arbitrary.
        FromTheRight -  pre- or post-multiply.
        DoTranspose -   multiply by P or P'.

    Output parameters:
        Z - product of Z and P.
                    Array whose indexes range within [0..ZRows-1,0..ZColumns-1].
                    If ZRows=0 or ZColumns=0, the array is not modified.

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixbdmultiplybyp(const ap::template_2d_array< amp::ampf<Precision> >& qp,
        int m,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& taup,
        ap::template_2d_array< amp::ampf<Precision> >& z,
        int zrows,
        int zcolumns,
        bool fromtheright,
        bool dotranspose);

### `rmatrixbdmultiplybyq` function

    /*************************************************************************
    Multiplication by matrix Q which reduces matrix A to  bidiagonal form.

    The algorithm allows pre- or post-multiply by Q or Q'.

    Input parameters:
        QP          -   matrices Q and P in compact form.
                        Output of ToBidiagonal subroutine.
        M           -   number of rows in matrix A.
        N           -   number of columns in matrix A.
        TAUQ        -   scalar factors which are used to form Q.
                        Output of ToBidiagonal subroutine.
        Z           -   multiplied matrix.
                        array[0..ZRows-1,0..ZColumns-1]
        ZRows       -   number of rows in matrix Z. If FromTheRight=False,
                        ZRows=M, otherwise ZRows can be arbitrary.
        ZColumns    -   number of columns in matrix Z. If FromTheRight=True,
                        ZColumns=M, otherwise ZColumns can be arbitrary.
        FromTheRight -  pre- or post-multiply.
        DoTranspose -   multiply by Q or Q'.

    Output parameters:
        Z           -   product of Z and Q.
                        Array[0..ZRows-1,0..ZColumns-1]
                        If ZRows=0 or ZColumns=0, the array is not modified.

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixbdmultiplybyq(const ap::template_2d_array< amp::ampf<Precision> >& qp,
        int m,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& tauq,
        ap::template_2d_array< amp::ampf<Precision> >& z,
        int zrows,
        int zcolumns,
        bool fromtheright,
        bool dotranspose);

### `rmatrixbdunpackdiagonals` function

    /*************************************************************************
    Unpacking of the main and secondary diagonals of bidiagonal decomposition
    of matrix A.

    Input parameters:
        B   -   output of RMatrixBD subroutine.
        M   -   number of rows in matrix B.
        N   -   number of columns in matrix B.

    Output parameters:
        IsUpper -   True, if the matrix is upper bidiagonal.
                    otherwise IsUpper is False.
        D       -   the main diagonal.
                    Array whose index ranges within [0..Min(M,N)-1].
        E       -   the secondary diagonal (upper or lower, depending on
                    the value of IsUpper).
                    Array index ranges within [0..Min(M,N)-1], the last
                    element is not used.

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixbdunpackdiagonals(const ap::template_2d_array< amp::ampf<Precision> >& b,
        int m,
        int n,
        bool& isupper,
        ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_1d_array< amp::ampf<Precision> >& e);

### `rmatrixbdunpackpt` function

    /*************************************************************************
    Unpacking matrix P which reduces matrix A to bidiagonal form.
    The subroutine returns transposed matrix P.

    Input parameters:
        QP      -   matrices Q and P in compact form.
                    Output of ToBidiagonal subroutine.
        M       -   number of rows in matrix A.
        N       -   number of columns in matrix A.
        TAUP    -   scalar factors which are used to form P.
                    Output of ToBidiagonal subroutine.
        PTRows  -   required number of rows of matrix P^T. N >= PTRows >= 0.

    Output parameters:
        PT      -   first PTRows columns of matrix P^T
                    Array[0..PTRows-1, 0..N-1]
                    If PTRows=0, the array is not modified.

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixbdunpackpt(const ap::template_2d_array< amp::ampf<Precision> >& qp,
        int m,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& taup,
        int ptrows,
        ap::template_2d_array< amp::ampf<Precision> >& pt);

### `rmatrixbdunpackq` function

    /*************************************************************************
    Unpacking matrix Q which reduces a matrix to bidiagonal form.

    Input parameters:
        QP          -   matrices Q and P in compact form.
                        Output of ToBidiagonal subroutine.
        M           -   number of rows in matrix A.
        N           -   number of columns in matrix A.
        TAUQ        -   scalar factors which are used to form Q.
                        Output of ToBidiagonal subroutine.
        QColumns    -   required number of columns in matrix Q.
                        M>=QColumns>=0.

    Output parameters:
        Q           -   first QColumns columns of matrix Q.
                        Array[0..M-1, 0..QColumns-1]
                        If QColumns=0, the array is not modified.

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixbdunpackq(const ap::template_2d_array< amp::ampf<Precision> >& qp,
        int m,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& tauq,
        int qcolumns,
        ap::template_2d_array< amp::ampf<Precision> >& q);

### `rmatrixhessenberg` function

    /*************************************************************************
    Reduction of a square matrix to  upper Hessenberg form: Q'*A*Q = H,
    where Q is an orthogonal matrix, H - Hessenberg matrix.

    Input parameters:
        A       -   matrix A with elements [0..N-1, 0..N-1]
        N       -   size of matrix A.

    Output parameters:
        A       -   matrices Q and P in  compact form (see below).
        Tau     -   array of scalar factors which are used to form matrix Q.
                    Array whose index ranges within [0..N-2]

    Matrix H is located on the main diagonal, on the lower secondary  diagonal
    and above the main diagonal of matrix A. The elements which are used to
    form matrix Q are situated in array Tau and below the lower secondary
    diagonal of matrix A as follows:

    Matrix Q is represented as a product of elementary reflections

    Q = H(0)*H(2)*...*H(n-2),

    where each H(i) is given by

    H(i) = 1 - tau * v * (v^T)

    where tau is a scalar stored in Tau[I]; v - is a real vector,
    so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i).

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         October 31, 1992
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixhessenberg(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& tau);

### `rmatrixhessenbergunpackh` function

    /*************************************************************************
    Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form)

    Input parameters:
        A   -   output of RMatrixHessenberg subroutine.
        N   -   size of matrix A.

    Output parameters:
        H   -   matrix H. Array whose indexes range within [0..N-1, 0..N-1].

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixhessenbergunpackh(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        ap::template_2d_array< amp::ampf<Precision> >& h);

### `rmatrixhessenbergunpackq` function

    /*************************************************************************
    Unpacking matrix Q which reduces matrix A to upper Hessenberg form

    Input parameters:
        A   -   output of RMatrixHessenberg subroutine.
        N   -   size of matrix A.
        Tau -   scalar factors which are used to form Q.
                Output of RMatrixHessenberg subroutine.

    Output parameters:
        Q   -   matrix Q.
                Array whose indexes range within [0..N-1, 0..N-1].

      -- ALGLIB --
         2005-2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixhessenbergunpackq(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& tau,
        ap::template_2d_array< amp::ampf<Precision> >& q);

### `rmatrixlq` function

    /*************************************************************************
    LQ decomposition of a rectangular matrix of size MxN

    Input parameters:
        A   -   matrix A whose indexes range within [0..M-1, 0..N-1].
        M   -   number of rows in matrix A.
        N   -   number of columns in matrix A.

    Output parameters:
        A   -   matrices L and Q in compact form (see below)
        Tau -   array of scalar factors which are used to form
                matrix Q. Array whose index ranges within [0..Min(M,N)-1].

    Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size
    MxM, L - lower triangular (or lower trapezoid) matrix of size M x N.

    The elements of matrix L are located on and below  the  main  diagonal  of
    matrix A. The elements which are located in Tau array and above  the  main
    diagonal of matrix A are used to form matrix Q as follows:

    Matrix Q is represented as a product of elementary reflections

    Q = H(k-1)*H(k-2)*...*H(1)*H(0),

    where k = min(m,n), and each H(i) is of the form

    H(i) = 1 - tau * v * (v^T)

    where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0,
    v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1).

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlq(ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& tau);

### `rmatrixlqunpackl` function

    /*************************************************************************
    Unpacking of matrix L from the LQ decomposition of a matrix A

    Input parameters:
        A       -   matrices Q and L in compact form.
                    Output of RMatrixLQ subroutine.
        M       -   number of rows in given matrix A. M>=0.
        N       -   number of columns in given matrix A. N>=0.

    Output parameters:
        L       -   matrix L, array[0..M-1, 0..N-1].

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlqunpackl(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        ap::template_2d_array< amp::ampf<Precision> >& l);

### `rmatrixlqunpackq` function

    /*************************************************************************
    Partial unpacking of matrix Q from the LQ decomposition of a matrix A

    Input parameters:
        A       -   matrices L and Q in compact form.
                    Output of RMatrixLQ subroutine.
        M       -   number of rows in given matrix A. M>=0.
        N       -   number of columns in given matrix A. N>=0.
        Tau     -   scalar factors which are used to form Q.
                    Output of the RMatrixLQ subroutine.
        QRows   -   required number of rows in matrix Q. N>=QRows>=0.

    Output parameters:
        Q       -   first QRows rows of matrix Q. Array whose indexes range
                    within [0..QRows-1, 0..N-1]. If QRows=0, the array remains
                    unchanged.

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlqunpackq(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& tau,
        int qrows,
        ap::template_2d_array< amp::ampf<Precision> >& q);

### `rmatrixqr` function

    /*************************************************************************
    QR decomposition of a rectangular matrix of size MxN

    Input parameters:
        A   -   matrix A whose indexes range within [0..M-1, 0..N-1].
        M   -   number of rows in matrix A.
        N   -   number of columns in matrix A.

    Output parameters:
        A   -   matrices Q and R in compact form (see below).
        Tau -   array of scalar factors which are used to form
                matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)].

    Matrix A is represented as A = QR, where Q is an orthogonal matrix of size
    MxM, R - upper triangular (or upper trapezoid) matrix of size M x N.

    The elements of matrix R are located on and above the main diagonal of
    matrix A. The elements which are located in Tau array and below the main
    diagonal of matrix A are used to form matrix Q as follows:

    Matrix Q is represented as a product of elementary reflections

    Q = H(0)*H(2)*...*H(k-1),

    where k = min(m,n), and each H(i) is in the form

    H(i) = 1 - tau * v * (v^T)

    where tau is a scalar stored in Tau[I]; v - real vector,
    so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i).

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixqr(ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< amp::ampf<Precision> >& tau);

### `rmatrixqrunpackq` function

    /*************************************************************************
    Partial unpacking of matrix Q from the QR decomposition of a matrix A

    Input parameters:
        A       -   matrices Q and R in compact form.
                    Output of RMatrixQR subroutine.
        M       -   number of rows in given matrix A. M>=0.
        N       -   number of columns in given matrix A. N>=0.
        Tau     -   scalar factors which are used to form Q.
                    Output of the RMatrixQR subroutine.
        QColumns -  required number of columns of matrix Q. M>=QColumns>=0.

    Output parameters:
        Q       -   first QColumns columns of matrix Q.
                    Array whose indexes range within [0..M-1, 0..QColumns-1].
                    If QColumns=0, the array remains unchanged.

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixqrunpackq(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& tau,
        int qcolumns,
        ap::template_2d_array< amp::ampf<Precision> >& q);

### `rmatrixqrunpackr` function

    /*************************************************************************
    Unpacking of matrix R from the QR decomposition of a matrix A

    Input parameters:
        A       -   matrices Q and R in compact form.
                    Output of RMatrixQR subroutine.
        M       -   number of rows in given matrix A. M>=0.
        N       -   number of columns in given matrix A. N>=0.

    Output parameters:
        R       -   matrix R, array[0..M-1, 0..N-1].

      -- ALGLIB routine --
         17.02.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixqrunpackr(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        ap::template_2d_array< amp::ampf<Precision> >& r);

### `smatrixtd` function

    /*************************************************************************
    Reduction of a symmetric matrix which is given by its higher or lower
    triangular part to a tridiagonal matrix using orthogonal similarity
    transformation: Q'*A*Q=T.

    Input parameters:
        A       -   matrix to be transformed
                    array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format. If IsUpper = True, then matrix A is given
                    by its upper triangle, and the lower triangle is not used
                    and not modified by the algorithm, and vice versa
                    if IsUpper = False.

    Output parameters:
        A       -   matrices T and Q in  compact form (see lower)
        Tau     -   array of factors which are forming matrices H(i)
                    array with elements [0..N-2].
        D       -   main diagonal of symmetric matrix T.
                    array with elements [0..N-1].
        E       -   secondary diagonal of symmetric matrix T.
                    array with elements [0..N-2].

      If IsUpper=True, the matrix Q is represented as a product of elementary
      reflectors

         Q = H(n-2) . . . H(2) H(0).

      Each H(i) has the form

         H(i) = I - tau * v * v'

      where tau is a real scalar, and v is a real vector with
      v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in
      A(0:i-1,i+1), and tau in TAU(i).

      If IsUpper=False, the matrix Q is represented as a product of elementary
      reflectors

         Q = H(0) H(2) . . . H(n-2).

      Each H(i) has the form

         H(i) = I - tau * v * v'

      where tau is a real scalar, and v is a real vector with
      v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i),
      and tau in TAU(i).

      The contents of A on exit are illustrated by the following examples
      with n = 5:

      if UPLO = 'U':                       if UPLO = 'L':

        (  d   e   v1  v2  v3 )              (  d                  )
        (      d   e   v2  v3 )              (  e   d              )
        (          d   e   v3 )              (  v0  e   d          )
        (              d   e  )              (  v0  v1  e   d      )
        (                  d  )              (  v0  v1  v2  e   d  )

      where d and e denote diagonal and off-diagonal elements of T, and vi
      denotes an element of the vector defining H(i).

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         October 31, 1992
    *************************************************************************/
    template<unsigned int Precision>
    void smatrixtd(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        ap::template_1d_array< amp::ampf<Precision> >& tau,
        ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_1d_array< amp::ampf<Precision> >& e);

### `smatrixtdunpackq` function

    /*************************************************************************
    Unpacking matrix Q which reduces symmetric matrix to a tridiagonal
    form.

    Input parameters:
        A       -   the result of a SMatrixTD subroutine
        N       -   size of matrix A.
        IsUpper -   storage format (a parameter of SMatrixTD subroutine)
        Tau     -   the result of a SMatrixTD subroutine

    Output parameters:
        Q       -   transformation matrix.
                    array with elements [0..N-1, 0..N-1].

      -- ALGLIB --
         Copyright 2005-2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void smatrixtdunpackq(const ap::template_2d_array< amp::ampf<Precision> >& a,
        const int& n,
        const bool& isupper,
        const ap::template_1d_array< amp::ampf<Precision> >& tau,
        ap::template_2d_array< amp::ampf<Precision> >& q);

## `polint` unit

### Structures

polynomialfitreport

### Functions

polynomialbuild
polynomialbuildcheb1
polynomialbuildcheb2
polynomialbuildeqdist
polynomialcalccheb1
polynomialcalccheb2
polynomialcalceqdist
polynomialfit
polynomialfitwc

### Examples

polint_cheb1
polint_cheb2
polint_eqdist
polint_fit
polint_gen

### `polynomialfitreport` structure

    /*************************************************************************
    Polynomial fitting report:
        TaskRCond       reciprocal of task's condition number
        RMSError        RMS error
        AvgError        average error
        AvgRelError     average relative error (for non-zero Y[I])
        MaxError        maximum error
    *************************************************************************/
    template<unsigned int Precision>
    class polynomialfitreport
    {
    public:
        amp::ampf<Precision> taskrcond;
        amp::ampf<Precision> rmserror;
        amp::ampf<Precision> avgerror;
        amp::ampf<Precision> avgrelerror;
        amp::ampf<Precision> maxerror;
    };

### `polynomialbuild` function

    /*************************************************************************
    Lagrange intepolant: generation of the model on the general grid.
    This function has O(N^2) complexity.

    INPUT PARAMETERS:
        X   -   abscissas, array[0..N-1]
        Y   -   function values, array[0..N-1]
        N   -   number of points, N>=1

    OIYTPUT PARAMETERS
        P   -   barycentric model which represents Lagrange interpolant
                (see ratint unit info and BarycentricCalc() description for
                more information).

      -- ALGLIB --
         Copyright 02.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void polynomialbuild(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        ratint::barycentricinterpolant<Precision>& p);

Examples: polint_gen

### `polynomialbuildcheb1` function

    /*************************************************************************
    Lagrange intepolant on Chebyshev grid (first kind).
    This function has O(N) complexity.

    INPUT PARAMETERS:
        A   -   left boundary of [A,B]
        B   -   right boundary of [A,B]
        Y   -   function values at the nodes, array[0..N-1],
                Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
        N   -   number of points, N>=1
                for N=1 a constant model is constructed.

    OIYTPUT PARAMETERS
        P   -   barycentric model which represents Lagrange interpolant
                (see ratint unit info and BarycentricCalc() description for
                more information).

      -- ALGLIB --
         Copyright 03.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void polynomialbuildcheb1(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        ratint::barycentricinterpolant<Precision>& p);

Examples: polint_cheb1

### `polynomialbuildcheb2` function

    /*************************************************************************
    Lagrange intepolant on Chebyshev grid (second kind).
    This function has O(N) complexity.

    INPUT PARAMETERS:
        A   -   left boundary of [A,B]
        B   -   right boundary of [A,B]
        Y   -   function values at the nodes, array[0..N-1],
                Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
        N   -   number of points, N>=1
                for N=1 a constant model is constructed.

    OIYTPUT PARAMETERS
        P   -   barycentric model which represents Lagrange interpolant
                (see ratint unit info and BarycentricCalc() description for
                more information).

      -- ALGLIB --
         Copyright 03.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void polynomialbuildcheb2(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        ratint::barycentricinterpolant<Precision>& p);

Examples: polint_cheb2

### `polynomialbuildeqdist` function

    /*************************************************************************
    Lagrange intepolant: generation of the model on equidistant grid.
    This function has O(N) complexity.

    INPUT PARAMETERS:
        A   -   left boundary of [A,B]
        B   -   right boundary of [A,B]
        Y   -   function values at the nodes, array[0..N-1]
        N   -   number of points, N>=1
                for N=1 a constant model is constructed.

    OIYTPUT PARAMETERS
        P   -   barycentric model which represents Lagrange interpolant
                (see ratint unit info and BarycentricCalc() description for
                more information).

      -- ALGLIB --
         Copyright 03.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void polynomialbuildeqdist(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        ratint::barycentricinterpolant<Precision>& p);

Examples: polint_eqdist

### `polynomialcalccheb1` function

    /*************************************************************************
    Fast polynomial interpolation function on Chebyshev points (first kind)
    with O(N) complexity.

    INPUT PARAMETERS:
        A   -   left boundary of [A,B]
        B   -   right boundary of [A,B]
        F   -   function values, array[0..N-1]
        N   -   number of points on Chebyshev grid (first kind),
                X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
                for N=1 a constant model is constructed.
        T   -   position where P(x) is calculated

    RESULT
        value of the Lagrange interpolant at T

    IMPORTANT
        this function provides fast interface which is not overflow-safe
        nor it is very precise.
        the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
        subroutines unless you are pretty sure that your data will not result
        in overflow.

      -- ALGLIB --
         Copyright 02.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> polynomialcalccheb1(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        const ap::template_1d_array< amp::ampf<Precision> >& f,
        int n,
        amp::ampf<Precision> t);

### `polynomialcalccheb2` function

    /*************************************************************************
    Fast polynomial interpolation function on Chebyshev points (second kind)
    with O(N) complexity.

    INPUT PARAMETERS:
        A   -   left boundary of [A,B]
        B   -   right boundary of [A,B]
        F   -   function values, array[0..N-1]
        N   -   number of points on Chebyshev grid (second kind),
                X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
                for N=1 a constant model is constructed.
        T   -   position where P(x) is calculated

    RESULT
        value of the Lagrange interpolant at T

    IMPORTANT
        this function provides fast interface which is not overflow-safe
        nor it is very precise.
        the best option is to use PolIntBuildCheb2()/BarycentricCalc()
        subroutines unless you are pretty sure that your data will not result
        in overflow.

      -- ALGLIB --
         Copyright 02.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> polynomialcalccheb2(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        const ap::template_1d_array< amp::ampf<Precision> >& f,
        int n,
        amp::ampf<Precision> t);

### `polynomialcalceqdist` function

    /*************************************************************************
    Fast equidistant polynomial interpolation function with O(N) complexity

    INPUT PARAMETERS:
        A   -   left boundary of [A,B]
        B   -   right boundary of [A,B]
        F   -   function values, array[0..N-1]
        N   -   number of points on equidistant grid, N>=1
                for N=1 a constant model is constructed.
        T   -   position where P(x) is calculated

    RESULT
        value of the Lagrange interpolant at T

    IMPORTANT
        this function provides fast interface which is not overflow-safe
        nor it is very precise.
        the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
        subroutines unless you are pretty sure that your data will not result
        in overflow.

      -- ALGLIB --
         Copyright 02.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> polynomialcalceqdist(amp::ampf<Precision> a,
        amp::ampf<Precision> b,
        const ap::template_1d_array< amp::ampf<Precision> >& f,
        int n,
        amp::ampf<Precision> t);

### `polynomialfit` function

    /*************************************************************************
    Least squares fitting by polynomial.

    This subroutine is "lightweight" alternative for more complex and feature-
    rich PolynomialFitWC().  See  PolynomialFitWC() for more information about
    subroutine parameters (we don't duplicate it here because of length)

      -- ALGLIB PROJECT --
         Copyright 12.10.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void polynomialfit(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        int m,
        int& info,
        ratint::barycentricinterpolant<Precision>& p,
        polynomialfitreport<Precision>& rep);

Examples: polint_fit

### `polynomialfitwc` function

    /*************************************************************************
    Weighted  fitting  by  Chebyshev  polynomial  in  barycentric  form,  with
    constraints on function values or first derivatives.

    Small regularizing term is used when solving constrained tasks (to improve
    stability).

    Task is linear, so linear least squares solver is used. Complexity of this
    computational scheme is O(N*M^2), mostly dominated by least squares solver

    SEE ALSO:
        PolynomialFit()

    INPUT PARAMETERS:
        X   -   points, array[0..N-1].
        Y   -   function values, array[0..N-1].
        W   -   weights, array[0..N-1]
                Each summand in square  sum  of  approximation deviations from
                given  values  is  multiplied  by  the square of corresponding
                weight. Fill it by 1's if you don't  want  to  solve  weighted
                task.
        N   -   number of points, N>0.
        XC  -   points where polynomial values/derivatives are constrained,
                array[0..K-1].
        YC  -   values of constraints, array[0..K-1]
        DC  -   array[0..K-1], types of constraints:
                * DC[i]=0   means that P(XC[i])=YC[i]
                * DC[i]=1   means that P'(XC[i])=YC[i]
                SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
        K   -   number of constraints, 0<=K<M.
                K=0 means no constraints (XC/YC/DC are not used in such cases)
        M   -   number of basis functions (= polynomial_degree + 1), M>=1

    OUTPUT PARAMETERS:
        Info-   same format as in LSFitLinearW() subroutine:
                * Info>0    task is solved
                * Info<=0   an error occured:
                            -4 means inconvergence of internal SVD
                            -3 means inconsistent constraints
                            -1 means another errors in parameters passed
                               (N<=0, for example)
        P   -   interpolant in barycentric form.
        Rep -   report, same format as in LSFitLinearW() subroutine.
                Following fields are set:
                * RMSError      rms error on the (X,Y).
                * AvgError      average error on the (X,Y).
                * AvgRelError   average relative error on the non-zero Y
                * MaxError      maximum error
                                NON-WEIGHTED ERRORS ARE CALCULATED

    IMPORTANT:
        this subroitine doesn't calculate task's condition number for K<>0.

    SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:

    Setting constraints can lead  to undesired  results,  like ill-conditioned
    behavior, or inconsistency being detected. From the other side,  it allows
    us to improve quality of the fit. Here we summarize  our  experience  with
    constrained regression splines:
    * even simple constraints can be inconsistent, see  Wikipedia  article  on
      this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
    * the  greater  is  M (given  fixed  constraints),  the  more chances that
      constraints will be consistent
    * in the general case, consistency of constraints is NOT GUARANTEED.
    * in the one special cases, however, we can  guarantee  consistency.  This
      case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)

    Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
    can't solve your task without them. Anything beyond  special  cases  given
    above is not guaranteed and may result in inconsistency.

      -- ALGLIB PROJECT --
         Copyright 10.12.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void polynomialfitwc(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        int n,
        ap::template_1d_array< amp::ampf<Precision> > xc,
        ap::template_1d_array< amp::ampf<Precision> > yc,
        const ap::template_1d_array< int >& dc,
        int k,
        int m,
        int& info,
        ratint::barycentricinterpolant<Precision>& p,
        polynomialfitreport<Precision>& rep);

Examples: polint_fit

### polint_cheb1 example

        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        ratint::barycentricinterpolant<Precision> p;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;
        amp::ampf<Precision> d2v;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Demonstration
        //
        printf("POLYNOMIAL INTERPOLATION\n\n");
        printf("F(x)=sin(x), [0, pi]\n");
        printf("Second degree polynomial is used\n\n");

        //
        // Create polynomial interpolant
        //
        n = 3;
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            y(i) = amp::sin<Precision>(amp::ampf<Precision>("0.5")*amp::pi<Precision>()*(amp::ampf<Precision>("1.0")+amp::cos<Precision>(amp::pi<Precision>()*(2*i+1)/(2*n))));
        }
        polint::polynomialbuildcheb1<Precision>(amp::ampf<Precision>(0), amp::pi<Precision>(), y, n, p);

        //
        // Output results
        //
        ratint::barycentricdiff2<Precision>(p, amp::ampf<Precision>(0), v, dv, d2v);
        printf("                 P(x)    F(x) \n");
        printf("function       %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(ratint::barycentriccalc<Precision>(p, amp::ampf<Precision>(0))).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("d/dx(0)        %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(dv).toDouble()),
            double(amp::ampf<Precision>(1).toDouble()));
        printf("d2/dx2(0)      %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(d2v).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("\n\n");

### polint_cheb2 example

        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        ratint::barycentricinterpolant<Precision> p;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;
        amp::ampf<Precision> d2v;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Demonstration
        //
        printf("POLYNOMIAL INTERPOLATION\n\n");
        printf("F(x)=sin(x), [0, pi]\n");
        printf("Second degree polynomial is used\n\n");

        //
        // Create polynomial interpolant
        //
        n = 3;
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            y(i) = amp::sin<Precision>(amp::ampf<Precision>("0.5")*amp::pi<Precision>()*(amp::ampf<Precision>("1.0")+amp::cos<Precision>(amp::pi<Precision>()*i/(n-1))));
        }
        polint::polynomialbuildcheb2<Precision>(amp::ampf<Precision>(0), amp::pi<Precision>(), y, n, p);

        //
        // Output results
        //
        ratint::barycentricdiff2<Precision>(p, amp::ampf<Precision>(0), v, dv, d2v);
        printf("                 P(x)    F(x) \n");
        printf("function       %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(ratint::barycentriccalc<Precision>(p, amp::ampf<Precision>(0))).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("d/dx(0)        %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(dv).toDouble()),
            double(amp::ampf<Precision>(1).toDouble()));
        printf("d2/dx2(0)      %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(d2v).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("\n\n");

### polint_eqdist example

        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        ratint::barycentricinterpolant<Precision> p;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;
        amp::ampf<Precision> d2v;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Demonstration
        //
        printf("POLYNOMIAL INTERPOLATION\n\n");
        printf("F(x)=sin(x), [0, pi]\n");
        printf("Second degree polynomial is used\n\n");

        //
        // Create polynomial interpolant
        //
        n = 3;
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            y(i) = amp::sin<Precision>(amp::pi<Precision>()*i/(n-1));
        }
        polint::polynomialbuildeqdist<Precision>(amp::ampf<Precision>(0), amp::pi<Precision>(), y, n, p);

        //
        // Output results
        //
        ratint::barycentricdiff2<Precision>(p, amp::ampf<Precision>(0), v, dv, d2v);
        printf("                 P(x)    F(x) \n");
        printf("function       %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(ratint::barycentriccalc<Precision>(p, amp::ampf<Precision>(0))).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("d/dx(0)        %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(dv).toDouble()),
            double(amp::ampf<Precision>(1).toDouble()));
        printf("d2/dx2(0)      %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(d2v).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("\n\n");

### polint_fit example

        int m;
        int n;
        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_1d_array< amp::ampf<Precision> > w;
        ap::template_1d_array< amp::ampf<Precision> > xc;
        ap::template_1d_array< amp::ampf<Precision> > yc;
        ap::template_1d_array< int > dc;
        polint::polynomialfitreport<Precision> rep;
        int info;
        ratint::barycentricinterpolant<Precision> p;
        int i;
        int j;
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;

        printf("\n\nFitting exp(2*x) at [-1,+1] by polinomial\n\n");
        printf("Fit type             rms.err max.err    p(0)   dp(0)\n");

        //
        // Prepare points
        //
        m = 5;
        a = -1;
        b = +1;
        n = 1000;
        x.setlength(n);
        y.setlength(n);
        w.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = a+(b-a)*i/(n-1);
            y(i) = amp::exp<Precision>(2*x(i));
            w(i) = amp::ampf<Precision>("1.0");
        }

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5th degree polynomial
        // c) without constraints
        //
        polint::polynomialfit<Precision>(x, y, n, m, info, p, rep);
        ratint::barycentricdiff1<Precision>(p, amp::ampf<Precision>("0.0"), v, dv);
        printf("Unconstrained        %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()));

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5th degree polynomial
        // c) constrained: p(0)=1
        //
        xc.setlength(1);
        yc.setlength(1);
        dc.setlength(1);
        xc(0) = 0;
        yc(0) = 1;
        dc(0) = 0;
        polint::polynomialfitwc<Precision>(x, y, w, n, xc, yc, dc, 1, m, info, p, rep);
        ratint::barycentricdiff1<Precision>(p, amp::ampf<Precision>("0.0"), v, dv);
        printf("Constrained, p(0)=1  %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()));

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5th degree polynomial
        // c) constrained: dp(0)=2
        //
        xc.setlength(1);
        yc.setlength(1);
        dc.setlength(1);
        xc(0) = 0;
        yc(0) = 2;
        dc(0) = 1;
        polint::polynomialfitwc<Precision>(x, y, w, n, xc, yc, dc, 1, m, info, p, rep);
        ratint::barycentricdiff1<Precision>(p, amp::ampf<Precision>("0.0"), v, dv);
        printf("Constrained, dp(0)=2 %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()));

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5th degree polynomial
        // c) constrained: p(0)=1, dp(0)=2
        //
        xc.setlength(2);
        yc.setlength(2);
        dc.setlength(2);
        xc(0) = 0;
        yc(0) = 1;
        dc(0) = 0;
        xc(1) = 0;
        yc(1) = 2;
        dc(1) = 1;
        polint::polynomialfitwc<Precision>(x, y, w, n, xc, yc, dc, 2, m, info, p, rep);
        ratint::barycentricdiff1<Precision>(p, amp::ampf<Precision>("0.0"), v, dv);
        printf("Constrained, both    %7.4lf %7.4lf %7.4lf %7.4lf\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()));
        printf("\n\n");

### polint_gen example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        ratint::barycentricinterpolant<Precision> p;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;
        amp::ampf<Precision> d2v;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Demonstration
        //
        printf("POLYNOMIAL INTERPOLATION\n\n");
        printf("F(x)=sin(x), [0, pi]\n");
        printf("Second degree polynomial is used\n\n");

        //
        // Create polynomial interpolant
        //
        n = 3;
        x.setlength(n);
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
        }
        polint::polynomialbuild<Precision>(x, y, n, p);

        //
        // Output results
        //
        ratint::barycentricdiff2<Precision>(p, amp::ampf<Precision>(0), v, dv, d2v);
        printf("                 P(x)    F(x) \n");
        printf("function       %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(ratint::barycentriccalc<Precision>(p, amp::ampf<Precision>(0))).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("d/dx(0)        %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(dv).toDouble()),
            double(amp::ampf<Precision>(1).toDouble()));
        printf("d2/dx2(0)      %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(d2v).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("\n\n");

## `pspline` unit

### Structures

pspline2interpolant
pspline3interpolant

### Functions

pspline2arclength
pspline2build
pspline2buildperiodic
pspline2calc
pspline2diff
pspline2diff2
pspline2parametervalues
pspline2tangent
pspline3arclength
pspline3build
pspline3buildperiodic
pspline3calc
pspline3diff
pspline3diff2
pspline3parametervalues
pspline3tangent

### `pspline2interpolant` structure

    /*************************************************************************
    Parametric spline inteprolant: 2-dimensional curve.

    You should not try to access its members directly - use PSpline2XXXXXXXX()
    functions instead.
    *************************************************************************/
    template<unsigned int Precision>
    class pspline2interpolant
    {
    public:
        int n;
        bool periodic;
        ap::template_1d_array< amp::ampf<Precision> > p;
        spline1d::spline1dinterpolant<Precision> x;
        spline1d::spline1dinterpolant<Precision> y;
    };

### `pspline3interpolant` structure

    /*************************************************************************
    Parametric spline inteprolant: 3-dimensional curve.

    You should not try to access its members directly - use PSpline3XXXXXXXX()
    functions instead.
    *************************************************************************/
    template<unsigned int Precision>
    class pspline3interpolant
    {
    public:
        int n;
        bool periodic;
        ap::template_1d_array< amp::ampf<Precision> > p;
        spline1d::spline1dinterpolant<Precision> x;
        spline1d::spline1dinterpolant<Precision> y;
        spline1d::spline1dinterpolant<Precision> z;
    };

### `pspline2arclength` function

    /*************************************************************************
    This function  calculates  arc length, i.e. length of  curve  between  t=a
    and t=b.

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        A,B -   parameter values corresponding to arc ends:
                * B>A will result in positive length returned
                * B<A will result in negative length returned

    RESULT:
        length of arc starting at T=A and ending at T=B.

      -- ALGLIB PROJECT --
         Copyright 30.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> pspline2arclength(const pspline2interpolant<Precision>& p,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b);

### `pspline2build` function

    /*************************************************************************
    This function  builds  non-periodic 2-dimensional parametric spline  which
    starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]).

    INPUT PARAMETERS:
        XY  -   points, array[0..N-1,0..1].
                XY[I,0:1] corresponds to the Ith point.
                Order of points is important!
        N   -   points count, N>=5 for Akima splines, N>=2 for other types  of
                splines.
        ST  -   spline type:
                * 0     Akima spline
                * 1     parabolically terminated Catmull-Rom spline (Tension=0)
                * 2     parabolically terminated cubic spline
        PT  -   parameterization type:
                * 0     uniform
                * 1     chord length
                * 2     centripetal

    OUTPUT PARAMETERS:
        P   -   parametric spline interpolant

    NOTES:
    * this function  assumes  that  there all consequent points  are distinct.
      I.e. (x0,y0)<>(x1,y1),  (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so on.
      However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
      =(x2,y2).

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2build(ap::template_2d_array< amp::ampf<Precision> > xy,
        int n,
        int st,
        int pt,
        pspline2interpolant<Precision>& p);

### `pspline2buildperiodic` function

    /*************************************************************************
    This  function  builds  periodic  2-dimensional  parametric  spline  which
    starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then
    back to (X[0],Y[0]).

    INPUT PARAMETERS:
        XY  -   points, array[0..N-1,0..1].
                XY[I,0:1] corresponds to the Ith point.
                XY[N-1,0:1] must be different from XY[0,0:1].
                Order of points is important!
        N   -   points count, N>=3 for other types of splines.
        ST  -   spline type:
                * 1     Catmull-Rom spline (Tension=0) with cyclic boundary conditions
                * 2     cubic spline with cyclic boundary conditions
        PT  -   parameterization type:
                * 0     uniform
                * 1     chord length
                * 2     centripetal

    OUTPUT PARAMETERS:
        P   -   parametric spline interpolant

    NOTES:
    * this function  assumes  that there all consequent points  are  distinct.
      I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so  on.
      However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
      =(x2,y2).
    * last point of sequence is NOT equal to the first  point.  You  shouldn't
      make curve "explicitly periodic" by making them equal.

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2buildperiodic(ap::template_2d_array< amp::ampf<Precision> > xy,
        int n,
        int st,
        int pt,
        pspline2interpolant<Precision>& p);

### `pspline2calc` function

    /*************************************************************************
    This function  calculates  the value of the parametric spline for a  given
    value of parameter T

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X   -   X-position
        Y   -   Y-position

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2calc(const pspline2interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& y);

### `pspline2diff` function

    /*************************************************************************
    This function calculates derivative, i.e. it returns (dX/dT,dY/dT).

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X   -   X-value
        DX  -   X-derivative
        Y   -   Y-value
        DY  -   Y-derivative

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2diff(const pspline2interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& dx,
        amp::ampf<Precision>& y,
        amp::ampf<Precision>& dy);

### `pspline2diff2` function

    /*************************************************************************
    This function calculates first and second derivative with respect to T.

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X   -   X-value
        DX  -   derivative
        D2X -   second derivative
        Y   -   Y-value
        DY  -   derivative
        D2Y -   second derivative

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2diff2(const pspline2interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& dx,
        amp::ampf<Precision>& d2x,
        amp::ampf<Precision>& y,
        amp::ampf<Precision>& dy,
        amp::ampf<Precision>& d2y);

### `pspline2parametervalues` function

    /*************************************************************************
    This function returns vector of parameter values correspoding to points.

    I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P)  we
    have
        (X[0],Y[0]) = PSpline2Calc(P,U[0]),
        (X[1],Y[1]) = PSpline2Calc(P,U[1]),
        (X[2],Y[2]) = PSpline2Calc(P,U[2]),
        ...

    INPUT PARAMETERS:
        P   -   parametric spline interpolant

    OUTPUT PARAMETERS:
        N   -   array size
        T   -   array[0..N-1]

    NOTES:
    * for non-periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]=1
    * for periodic splines     U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]<1

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2parametervalues(const pspline2interpolant<Precision>& p,
        int& n,
        ap::template_1d_array< amp::ampf<Precision> >& t);

### `pspline2tangent` function

    /*************************************************************************
    This function  calculates  tangent vector for a given value of parameter T

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X    -   X-component of tangent vector (normalized)
        Y    -   Y-component of tangent vector (normalized)

    NOTE:
        X^2+Y^2 is either 1 (for non-zero tangent vector) or 0.

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline2tangent(const pspline2interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& y);

### `pspline3arclength` function

    /*************************************************************************
    This function  calculates  arc length, i.e. length of  curve  between  t=a
    and t=b.

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        A,B -   parameter values corresponding to arc ends:
                * B>A will result in positive length returned
                * B<A will result in negative length returned

    RESULT:
        length of arc starting at T=A and ending at T=B.

      -- ALGLIB PROJECT --
         Copyright 30.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> pspline3arclength(const pspline3interpolant<Precision>& p,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b);

### `pspline3build` function

    /*************************************************************************
    This function  builds  non-periodic 3-dimensional parametric spline  which
    starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]).

    Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
    description here.

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3build(ap::template_2d_array< amp::ampf<Precision> > xy,
        int n,
        int st,
        int pt,
        pspline3interpolant<Precision>& p);

### `pspline3buildperiodic` function

    /*************************************************************************
    This  function  builds  periodic  3-dimensional  parametric  spline  which
    starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1])
    and then back to (X[0],Y[0],Z[0]).

    Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
    description here.

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3buildperiodic(ap::template_2d_array< amp::ampf<Precision> > xy,
        int n,
        int st,
        int pt,
        pspline3interpolant<Precision>& p);

### `pspline3calc` function

    /*************************************************************************
    This function  calculates  the value of the parametric spline for a  given
    value of parameter T.

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X   -   X-position
        Y   -   Y-position
        Z   -   Z-position

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3calc(const pspline3interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& y,
        amp::ampf<Precision>& z);

### `pspline3diff` function

    /*************************************************************************
    This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT).

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X   -   X-value
        DX  -   X-derivative
        Y   -   Y-value
        DY  -   Y-derivative
        Z   -   Z-value
        DZ  -   Z-derivative

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3diff(const pspline3interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& dx,
        amp::ampf<Precision>& y,
        amp::ampf<Precision>& dy,
        amp::ampf<Precision>& z,
        amp::ampf<Precision>& dz);

### `pspline3diff2` function

    /*************************************************************************
    This function calculates first and second derivative with respect to T.

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X   -   X-value
        DX  -   derivative
        D2X -   second derivative
        Y   -   Y-value
        DY  -   derivative
        D2Y -   second derivative
        Z   -   Z-value
        DZ  -   derivative
        D2Z -   second derivative

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3diff2(const pspline3interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& dx,
        amp::ampf<Precision>& d2x,
        amp::ampf<Precision>& y,
        amp::ampf<Precision>& dy,
        amp::ampf<Precision>& d2y,
        amp::ampf<Precision>& z,
        amp::ampf<Precision>& dz,
        amp::ampf<Precision>& d2z);

### `pspline3parametervalues` function

    /*************************************************************************
    This function returns vector of parameter values correspoding to points.

    Same as PSpline2ParameterValues(), but for 3D.

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3parametervalues(const pspline3interpolant<Precision>& p,
        int& n,
        ap::template_1d_array< amp::ampf<Precision> >& t);

### `pspline3tangent` function

    /*************************************************************************
    This function  calculates  tangent vector for a given value of parameter T

    INPUT PARAMETERS:
        P   -   parametric spline interpolant
        T   -   point:
                * T in [0,1] corresponds to interval spanned by points
                * for non-periodic splines T<0 (or T>1) correspond to parts of
                  the curve before the first (after the last) point
                * for periodic splines T<0 (or T>1) are projected  into  [0,1]
                  by making T=T-floor(T).

    OUTPUT PARAMETERS:
        X    -   X-component of tangent vector (normalized)
        Y    -   Y-component of tangent vector (normalized)
        Z    -   Z-component of tangent vector (normalized)

    NOTE:
        X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0.

      -- ALGLIB PROJECT --
         Copyright 28.05.2010 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void pspline3tangent(const pspline3interpolant<Precision>& p,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& x,
        amp::ampf<Precision>& y,
        amp::ampf<Precision>& z);

## `ratint` unit

### Structures

barycentricfitreport
barycentricinterpolant

### Functions

barycentricbuildfloaterhormann
barycentricbuildxyw
barycentriccalc
barycentriccopy
barycentricdiff1
barycentricdiff2
barycentricfitfloaterhormann
barycentricfitfloaterhormannwc
barycentriclintransx
barycentriclintransy
barycentricserialize
barycentricunpack
barycentricunserialize

### Examples

ratint_fit

### `barycentricfitreport` structure

    /*************************************************************************
    Barycentric fitting report:
        TaskRCond       reciprocal of task's condition number
        RMSError        RMS error
        AvgError        average error
        AvgRelError     average relative error (for non-zero Y[I])
        MaxError        maximum error
    *************************************************************************/
    template<unsigned int Precision>
    class barycentricfitreport
    {
    public:
        amp::ampf<Precision> taskrcond;
        int dbest;
        amp::ampf<Precision> rmserror;
        amp::ampf<Precision> avgerror;
        amp::ampf<Precision> avgrelerror;
        amp::ampf<Precision> maxerror;
    };

### `barycentricinterpolant` structure

    /*************************************************************************
    Barycentric interpolant.
    *************************************************************************/
    template<unsigned int Precision>
    class barycentricinterpolant
    {
    public:
        int n;
        amp::ampf<Precision> sy;
        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_1d_array< amp::ampf<Precision> > w;
    };

### `barycentricbuildfloaterhormann` function

    /*************************************************************************
    Rational interpolant without poles

    The subroutine constructs the rational interpolating function without real
    poles  (see  'Barycentric rational interpolation with no  poles  and  high
    rates of approximation', Michael S. Floater. and  Kai  Hormann,  for  more
    information on this subject).

    Input parameters:
        X   -   interpolation nodes, array[0..N-1].
        Y   -   function values, array[0..N-1].
        N   -   number of nodes, N>0.
        D   -   order of the interpolation scheme, 0 <= D <= N-1.
                D<0 will cause an error.
                D>=N it will be replaced with D=N-1.
                if you don't know what D to choose, use small value about 3-5.

    Output parameters:
        B   -   barycentric interpolant.

    Note:
        this algorithm always succeeds and calculates the weights  with  close
        to machine precision.

      -- ALGLIB PROJECT --
         Copyright 17.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricbuildfloaterhormann(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        int d,
        barycentricinterpolant<Precision>& b);

### `barycentricbuildxyw` function

    /*************************************************************************
    Rational interpolant from X/Y/W arrays

    F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))

    INPUT PARAMETERS:
        X   -   interpolation nodes, array[0..N-1]
        F   -   function values, array[0..N-1]
        W   -   barycentric weights, array[0..N-1]
        N   -   nodes count, N>0

    OUTPUT PARAMETERS:
        B   -   barycentric interpolant built from (X, Y, W)

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricbuildxyw(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        int n,
        barycentricinterpolant<Precision>& b);

### `barycentriccalc` function

    /*************************************************************************
    Rational interpolation using barycentric formula

    F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))

    Input parameters:
        B   -   barycentric interpolant built with one of model building
                subroutines.
        T   -   interpolation point

    Result:
        barycentric interpolant F(t)

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> barycentriccalc(const barycentricinterpolant<Precision>& b,
        amp::ampf<Precision> t);

### `barycentriccopy` function

    /*************************************************************************
    Copying of the barycentric interpolant

    INPUT PARAMETERS:
        B   -   barycentric interpolant

    OUTPUT PARAMETERS:
        B2  -   copy(B1)

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentriccopy(const barycentricinterpolant<Precision>& b,
        barycentricinterpolant<Precision>& b2);

### `barycentricdiff1` function

    /*************************************************************************
    Differentiation of barycentric interpolant: first derivative.

    Algorithm used in this subroutine is very robust and should not fail until
    provided with values too close to MaxRealNumber  (usually  MaxRealNumber/N
    or greater will overflow).

    INPUT PARAMETERS:
        B   -   barycentric interpolant built with one of model building
                subroutines.
        T   -   interpolation point

    OUTPUT PARAMETERS:
        F   -   barycentric interpolant at T
        DF  -   first derivative

    NOTE

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricdiff1(const barycentricinterpolant<Precision>& b,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& f,
        amp::ampf<Precision>& df);

### `barycentricdiff2` function

    /*************************************************************************
    Differentiation of barycentric interpolant: first/second derivatives.

    INPUT PARAMETERS:
        B   -   barycentric interpolant built with one of model building
                subroutines.
        T   -   interpolation point

    OUTPUT PARAMETERS:
        F   -   barycentric interpolant at T
        DF  -   first derivative
        D2F -   second derivative

    NOTE: this algorithm may fail due to overflow/underflor if  used  on  data
    whose values are close to MaxRealNumber or MinRealNumber.  Use more robust
    BarycentricDiff1() subroutine in such cases.

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricdiff2(const barycentricinterpolant<Precision>& b,
        amp::ampf<Precision> t,
        amp::ampf<Precision>& f,
        amp::ampf<Precision>& df,
        amp::ampf<Precision>& d2f);

### `barycentricfitfloaterhormann` function

    /*************************************************************************
    Rational least squares fitting, without weights and constraints.

    See BarycentricFitFloaterHormannWC() for more information.

      -- ALGLIB PROJECT --
         Copyright 18.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricfitfloaterhormann(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        int m,
        int& info,
        barycentricinterpolant<Precision>& b,
        barycentricfitreport<Precision>& rep);

Examples: ratint_fit

### `barycentricfitfloaterhormannwc` function

    /*************************************************************************
    Weghted rational least  squares  fitting  using  Floater-Hormann  rational
    functions  with  optimal  D  chosen  from  [0,9],  with  constraints   and
    individual weights.

    Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
    functions. Different values of D are tried, optimal D (least WEIGHTED root
    mean square error) is chosen.  Task  is  linear,  so  linear least squares
    solver  is  used.  Complexity  of  this  computational  scheme is O(N*M^2)
    (mostly dominated by the least squares solver).

    SEE ALSO
    * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual
      weights and constraints.

    INPUT PARAMETERS:
        X   -   points, array[0..N-1].
        Y   -   function values, array[0..N-1].
        W   -   weights, array[0..N-1]
                Each summand in square  sum  of  approximation deviations from
                given  values  is  multiplied  by  the square of corresponding
                weight. Fill it by 1's if you don't  want  to  solve  weighted
                task.
        N   -   number of points, N>0.
        XC  -   points where function values/derivatives are constrained,
                array[0..K-1].
        YC  -   values of constraints, array[0..K-1]
        DC  -   array[0..K-1], types of constraints:
                * DC[i]=0   means that S(XC[i])=YC[i]
                * DC[i]=1   means that S'(XC[i])=YC[i]
                SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
        K   -   number of constraints, 0<=K<M.
                K=0 means no constraints (XC/YC/DC are not used in such cases)
        M   -   number of basis functions ( = number_of_nodes), M>=2.

    OUTPUT PARAMETERS:
        Info-   same format as in LSFitLinearWC() subroutine.
                * Info>0    task is solved
                * Info<=0   an error occured:
                            -4 means inconvergence of internal SVD
                            -3 means inconsistent constraints
                            -1 means another errors in parameters passed
                               (N<=0, for example)
        B   -   barycentric interpolant.
        Rep -   report, same format as in LSFitLinearWC() subroutine.
                Following fields are set:
                * DBest         best value of the D parameter
                * RMSError      rms error on the (X,Y).
                * AvgError      average error on the (X,Y).
                * AvgRelError   average relative error on the non-zero Y
                * MaxError      maximum error
                                NON-WEIGHTED ERRORS ARE CALCULATED

    IMPORTANT:
        this subroitine doesn't calculate task's condition number for K<>0.

    SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:

    Setting constraints can lead  to undesired  results,  like ill-conditioned
    behavior, or inconsistency being detected. From the other side,  it allows
    us to improve quality of the fit. Here we summarize  our  experience  with
    constrained barycentric interpolants:
    * excessive  constraints  can  be  inconsistent.   Floater-Hormann   basis
      functions aren't as flexible as splines (although they are very smooth).
    * the more evenly constraints are spread across [min(x),max(x)],  the more
      chances that they will be consistent
    * the  greater  is  M (given  fixed  constraints),  the  more chances that
      constraints will be consistent
    * in the general case, consistency of constraints IS NOT GUARANTEED.
    * in the several special cases, however, we CAN guarantee consistency.
    * one of this cases is constraints on the function  VALUES at the interval
      boundaries. Note that consustency of the  constraints  on  the  function
      DERIVATIVES is NOT guaranteed (you can use in such cases  cubic  splines
      which are more flexible).
    * another  special  case  is ONE constraint on the function value (OR, but
      not AND, derivative) anywhere in the interval

    Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
    can't solve your task without them. Anything beyond  special  cases  given
    above is not guaranteed and may result in inconsistency.

      -- ALGLIB PROJECT --
         Copyright 18.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricfitfloaterhormannwc(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& xc,
        const ap::template_1d_array< amp::ampf<Precision> >& yc,
        const ap::template_1d_array< int >& dc,
        int k,
        int m,
        int& info,
        barycentricinterpolant<Precision>& b,
        barycentricfitreport<Precision>& rep);

Examples: ratint_fit

### `barycentriclintransx` function

    /*************************************************************************
    This subroutine performs linear transformation of the argument.

    INPUT PARAMETERS:
        B       -   rational interpolant in barycentric form
        CA, CB  -   transformation coefficients: x = CA*t + CB

    OUTPUT PARAMETERS:
        B       -   transformed interpolant with X replaced by T

      -- ALGLIB PROJECT --
         Copyright 19.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentriclintransx(barycentricinterpolant<Precision>& b,
        amp::ampf<Precision> ca,
        amp::ampf<Precision> cb);

### `barycentriclintransy` function

    /*************************************************************************
    This  subroutine   performs   linear  transformation  of  the  barycentric
    interpolant.

    INPUT PARAMETERS:
        B       -   rational interpolant in barycentric form
        CA, CB  -   transformation coefficients: B2(x) = CA*B(x) + CB

    OUTPUT PARAMETERS:
        B       -   transformed interpolant

      -- ALGLIB PROJECT --
         Copyright 19.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentriclintransy(barycentricinterpolant<Precision>& b,
        amp::ampf<Precision> ca,
        amp::ampf<Precision> cb);

### `barycentricserialize` function

    /*************************************************************************
    Serialization of the barycentric interpolant

    INPUT PARAMETERS:
        B   -   barycentric interpolant

    OUTPUT PARAMETERS:
        RA      -   array of real numbers which contains interpolant,
                    array[0..RLen-1]
        RLen    -   RA lenght

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricserialize(const barycentricinterpolant<Precision>& b,
        ap::template_1d_array< amp::ampf<Precision> >& ra,
        int& ralen);

### `barycentricunpack` function

    /*************************************************************************
    Extracts X/Y/W arrays from rational interpolant

    INPUT PARAMETERS:
        B   -   barycentric interpolant

    OUTPUT PARAMETERS:
        N   -   nodes count, N>0
        X   -   interpolation nodes, array[0..N-1]
        F   -   function values, array[0..N-1]
        W   -   barycentric weights, array[0..N-1]

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricunpack(const barycentricinterpolant<Precision>& b,
        int& n,
        ap::template_1d_array< amp::ampf<Precision> >& x,
        ap::template_1d_array< amp::ampf<Precision> >& y,
        ap::template_1d_array< amp::ampf<Precision> >& w);

### `barycentricunserialize` function

    /*************************************************************************
    Unserialization of the barycentric interpolant

    INPUT PARAMETERS:
        RA  -   array of real numbers which contains interpolant,

    OUTPUT PARAMETERS:
        B   -   barycentric interpolant

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void barycentricunserialize(const ap::template_1d_array< amp::ampf<Precision> >& ra,
        barycentricinterpolant<Precision>& b);

### ratint_fit example

        int m;
        int n;
        int d;
        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_1d_array< amp::ampf<Precision> > w;
        ap::template_1d_array< amp::ampf<Precision> > xc;
        ap::template_1d_array< amp::ampf<Precision> > yc;
        ap::template_1d_array< int > dc;
        ratint::barycentricfitreport<Precision> rep;
        int info;
        ratint::barycentricinterpolant<Precision> r;
        int i;
        int j;
        amp::ampf<Precision> a;
        amp::ampf<Precision> b;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;

        printf("\n\nFitting exp(2*x) at [-1,+1] by:\n1. constrained/unconstrained Floater-Hormann functions\n");
        printf("\n");
        printf("Fit type                rms.err max.err    p(0)   dp(0)  DBest\n");

        //
        // Prepare points
        //
        m = 5;
        a = -1;
        b = +1;
        n = 10000;
        x.setlength(n);
        y.setlength(n);
        w.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = a+(b-a)*i/(n-1);
            y(i) = amp::exp<Precision>(2*x(i));
            w(i) = amp::ampf<Precision>("1.0");
        }

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5 Floater-Hormann functions
        // c) without constraints
        //
        ratint::barycentricfitfloaterhormann<Precision>(x, y, n, m, info, r, rep);
        ratint::barycentricdiff1<Precision>(r, amp::ampf<Precision>("0.0"), v, dv);
        printf("Unconstrained FH        %7.4lf %7.4lf %7.4lf %7.4lf      %0ld\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()),
            long(rep.dbest));

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5 Floater-Hormann functions
        // c) constrained: p(0)=1
        //
        xc.setlength(1);
        yc.setlength(1);
        dc.setlength(1);
        xc(0) = 0;
        yc(0) = 1;
        dc(0) = 0;
        ratint::barycentricfitfloaterhormannwc<Precision>(x, y, w, n, xc, yc, dc, 1, m, info, r, rep);
        ratint::barycentricdiff1<Precision>(r, amp::ampf<Precision>("0.0"), v, dv);
        printf("Constrained FH, p(0)=1  %7.4lf %7.4lf %7.4lf %7.4lf      %0ld\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()),
            long(rep.dbest));

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5 Floater-Hormann functions
        // c) constrained: dp(0)=2
        //
        xc.setlength(1);
        yc.setlength(1);
        dc.setlength(1);
        xc(0) = 0;
        yc(0) = 2;
        dc(0) = 1;
        ratint::barycentricfitfloaterhormannwc<Precision>(x, y, w, n, xc, yc, dc, 1, m, info, r, rep);
        ratint::barycentricdiff1<Precision>(r, amp::ampf<Precision>("0.0"), v, dv);
        printf("Constrained FH, dp(0)=2 %7.4lf %7.4lf %7.4lf %7.4lf      %0ld\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()),
            long(rep.dbest));

        //
        // Fitting:
        // a) f(x)=exp(2*x) at [-1,+1]
        // b) by 5 Floater-Hormann functions
        // c) constrained: p(0)=1, dp(0)=2
        //
        xc.setlength(2);
        yc.setlength(2);
        dc.setlength(2);
        xc(0) = 0;
        yc(0) = 1;
        dc(0) = 0;
        xc(1) = 0;
        yc(1) = 2;
        dc(1) = 1;
        ratint::barycentricfitfloaterhormannwc<Precision>(x, y, w, n, xc, yc, dc, 2, m, info, r, rep);
        ratint::barycentricdiff1<Precision>(r, amp::ampf<Precision>("0.0"), v, dv);
        printf("Constrained FH, both    %7.4lf %7.4lf %7.4lf %7.4lf      %0ld\n",
            double(amp::ampf<Precision>(rep.rmserror).toDouble()),
            double(amp::ampf<Precision>(rep.maxerror).toDouble()),
            double(amp::ampf<Precision>(v).toDouble()),
            double(amp::ampf<Precision>(dv).toDouble()),
            long(rep.dbest));
        printf("\n\n");

## `rcond` unit

### Functions

cmatrixlurcond1
cmatrixlurcondinf
cmatrixrcond1
cmatrixrcondinf
cmatrixtrrcond1
cmatrixtrrcondinf
hpdmatrixcholeskyrcond
hpdmatrixrcond
rcondthreshold
rmatrixlurcond1
rmatrixlurcondinf
rmatrixrcond1
rmatrixrcondinf
rmatrixtrrcond1
rmatrixtrrcondinf
spdmatrixcholeskyrcond
spdmatrixrcond

### Examples

rcond_1

### `cmatrixlurcond1` function

    /*************************************************************************
    Estimate of the condition number of a matrix given by its LU decomposition (1-norm)

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        LUA         -   LU decomposition of a matrix in compact form. Output of
                        the CMatrixLU subroutine.
        N           -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> cmatrixlurcond1(const ap::template_2d_array< amp::campf<Precision> >& lua,
        int n);

Examples: rcond_1

### `cmatrixlurcondinf` function

    /*************************************************************************
    Estimate of the condition number of a matrix given by its LU decomposition
    (infinity norm).

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        LUA     -   LU decomposition of a matrix in compact form. Output of
                    the CMatrixLU subroutine.
        N       -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> cmatrixlurcondinf(const ap::template_2d_array< amp::campf<Precision> >& lua,
        int n);

Examples: rcond_1

### `cmatrixrcond1` function

    /*************************************************************************
    Estimate of a matrix condition number (1-norm)

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> cmatrixrcond1(ap::template_2d_array< amp::campf<Precision> > a,
        int n);

Examples: rcond_1

### `cmatrixrcondinf` function

    /*************************************************************************
    Estimate of a matrix condition number (infinity-norm).

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> cmatrixrcondinf(ap::template_2d_array< amp::campf<Precision> > a,
        int n);

Examples: rcond_1

### `cmatrixtrrcond1` function

    /*************************************************************************
    Triangular matrix: estimate of a condition number (1-norm)

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A       -   matrix. Array[0..N-1, 0..N-1].
        N       -   size of A.
        IsUpper -   True, if the matrix is upper triangular.
        IsUnit  -   True, if the matrix has a unit diagonal.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> cmatrixtrrcond1(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        bool isunit);

### `cmatrixtrrcondinf` function

    /*************************************************************************
    Triangular matrix: estimate of a matrix condition number (infinity-norm).

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.
        IsUpper -   True, if the matrix is upper triangular.
        IsUnit  -   True, if the matrix has a unit diagonal.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> cmatrixtrrcondinf(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper,
        bool isunit);

### `hpdmatrixcholeskyrcond` function

    /*************************************************************************
    Condition number estimate of a Hermitian positive definite matrix given by
    Cholesky decomposition.

    The algorithm calculates a lower bound of the condition number. In this
    case, the algorithm does not return a lower bound of the condition number,
    but an inverse number (to avoid an overflow in case of a singular matrix).

    It should be noted that 1-norm and inf-norm condition numbers of symmetric
    matrices are equal, so the algorithm doesn't take into account the
    differences between these types of norms.

    Input parameters:
        CD  - Cholesky decomposition of matrix A,
              output of SMatrixCholesky subroutine.
        N   - size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> hpdmatrixcholeskyrcond(const ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper);

Examples: rcond_1

### `hpdmatrixrcond` function

    /*************************************************************************
    Condition number estimate of a Hermitian positive definite matrix.

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    It should be noted that 1-norm and inf-norm of condition numbers of symmetric
    matrices are equal, so the algorithm doesn't take into account the
    differences between these types of norms.

    Input parameters:
        A       -   Hermitian positive definite matrix which is given by its
                    upper or lower triangle depending on the value of
                    IsUpper. Array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.

    Result:
        1/LowerBound(cond(A)), if matrix A is positive definite,
       -1, if matrix A is not positive definite, and its condition number
        could not be found by this algorithm.

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> hpdmatrixrcond(ap::template_2d_array< amp::campf<Precision> > a,
        int n,
        bool isupper);

Examples: rcond_1

### `rcondthreshold` function

    /*************************************************************************
    Threshold for rcond: matrices with condition number beyond this  threshold
    are considered singular.

    Threshold must be far enough from underflow, at least Sqr(Threshold)  must
    be greater than underflow.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rcondthreshold();

### `rmatrixlurcond1` function

    /*************************************************************************
    Estimate of the condition number of a matrix given by its LU decomposition (1-norm)

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        LUA         -   LU decomposition of a matrix in compact form. Output of
                        the RMatrixLU subroutine.
        N           -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixlurcond1(const ap::template_2d_array< amp::ampf<Precision> >& lua,
        int n);

Examples: rcond_1

### `rmatrixlurcondinf` function

    /*************************************************************************
    Estimate of the condition number of a matrix given by its LU decomposition
    (infinity norm).

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        LUA     -   LU decomposition of a matrix in compact form. Output of
                    the RMatrixLU subroutine.
        N       -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixlurcondinf(const ap::template_2d_array< amp::ampf<Precision> >& lua,
        int n);

Examples: rcond_1

### `rmatrixrcond1` function

    /*************************************************************************
    Estimate of a matrix condition number (1-norm)

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixrcond1(ap::template_2d_array< amp::ampf<Precision> > a,
        int n);

Examples: rcond_1

### `rmatrixrcondinf` function

    /*************************************************************************
    Estimate of a matrix condition number (infinity-norm).

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixrcondinf(ap::template_2d_array< amp::ampf<Precision> > a,
        int n);

Examples: rcond_1

### `rmatrixtrrcond1` function

    /*************************************************************************
    Triangular matrix: estimate of a condition number (1-norm)

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A       -   matrix. Array[0..N-1, 0..N-1].
        N       -   size of A.
        IsUpper -   True, if the matrix is upper triangular.
        IsUnit  -   True, if the matrix has a unit diagonal.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixtrrcond1(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        bool isunit);

### `rmatrixtrrcondinf` function

    /*************************************************************************
    Triangular matrix: estimate of a matrix condition number (infinity-norm).

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    Input parameters:
        A   -   matrix. Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of matrix A.
        IsUpper -   True, if the matrix is upper triangular.
        IsUnit  -   True, if the matrix has a unit diagonal.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> rmatrixtrrcondinf(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper,
        bool isunit);

### `spdmatrixcholeskyrcond` function

    /*************************************************************************
    Condition number estimate of a symmetric positive definite matrix given by
    Cholesky decomposition.

    The algorithm calculates a lower bound of the condition number. In this
    case, the algorithm does not return a lower bound of the condition number,
    but an inverse number (to avoid an overflow in case of a singular matrix).

    It should be noted that 1-norm and inf-norm condition numbers of symmetric
    matrices are equal, so the algorithm doesn't take into account the
    differences between these types of norms.

    Input parameters:
        CD  - Cholesky decomposition of matrix A,
              output of SMatrixCholesky subroutine.
        N   - size of matrix A.

    Result: 1/LowerBound(cond(A))

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spdmatrixcholeskyrcond(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper);

Examples: rcond_1

### `spdmatrixrcond` function

    /*************************************************************************
    Condition number estimate of a symmetric positive definite matrix.

    The algorithm calculates a lower bound of the condition number. In this case,
    the algorithm does not return a lower bound of the condition number, but an
    inverse number (to avoid an overflow in case of a singular matrix).

    It should be noted that 1-norm and inf-norm of condition numbers of symmetric
    matrices are equal, so the algorithm doesn't take into account the
    differences between these types of norms.

    Input parameters:
        A       -   symmetric positive definite matrix which is given by its
                    upper or lower triangle depending on the value of
                    IsUpper. Array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.

    Result:
        1/LowerBound(cond(A)), if matrix A is positive definite,
       -1, if matrix A is not positive definite, and its condition number
        could not be found by this algorithm.

    NOTE:
        if k(A) is very large, then matrix is  assumed  degenerate,  k(A)=INF,
        0.0 is returned in such cases.
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spdmatrixrcond(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        bool isupper);

Examples: rcond_1

### rcond_1 example

        int n;
        int i;
        int j;
        amp::ampf<Precision> c1;
        amp::ampf<Precision> x;
        ap::template_2d_array< amp::ampf<Precision> > a;

        printf("                 CONDITION NUMBERS\n");
        printf("OF VANDERMONDE AND CHEBYSHEV INTERPOLATION MATRICES\n\n");
        printf("    VANDERMONDE   CHEBYSHEV\n");
        printf("  N      1-norm      1-norm\n");
        for(n=2; n<=14; n++)
        {
            a.setlength(n, n);
            printf("%3ld",
                long(n));

            //
            // Vandermone matrix
            //
            for(i=0; i<=n-1; i++)
            {
                x = amp::ampf<Precision>(2*i)/(amp::ampf<Precision>(n-1))-1;
                a(i,0) = 1;
                for(j=1; j<=n-1; j++)
                {
                    a(i,j) = a(i,j-1)*x;
                }
            }
            c1 = 1/rcond::rmatrixrcond1<Precision>(a, n);
            printf(" %11.1lf",
                double(amp::ampf<Precision>(c1).toDouble()));

            //
            // Chebyshev interpolation matrix
            //
            for(i=0; i<=n-1; i++)
            {
                x = amp::ampf<Precision>(2*i)/(amp::ampf<Precision>(n-1))-1;
                a(i,0) = 1;
                if( n>=2 )
                {
                    a(i,1) = x;
                }
                for(j=2; j<=n-1; j++)
                {
                    a(i,j) = 2*x*a(i,j-1)-a(i,j-2);
                }
            }
            c1 = 1/rcond::rmatrixrcond1<Precision>(a, n);
            printf(" %11.1lf\n",
                double(amp::ampf<Precision>(c1).toDouble()));
        }

## `schur` unit

### Functions

rmatrixschur

### `rmatrixschur` function

    /*************************************************************************
    Subroutine performing the Schur decomposition of a general matrix by using
    the QR algorithm with multiple shifts.

    The source matrix A is represented as S'*A*S = T, where S is an orthogonal
    matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of
    sizes 1x1 and 2x2 on the main diagonal).

    Input parameters:
        A   -   matrix to be decomposed.
                Array whose indexes range within [0..N-1, 0..N-1].
        N   -   size of A, N>=0.

    Output parameters:
        A   -   contains matrix T.
                Array whose indexes range within [0..N-1, 0..N-1].
        S   -   contains Schur vectors.
                Array whose indexes range within [0..N-1, 0..N-1].

    Note 1:
        The block structure of matrix T can be easily recognized: since all
        the elements below the blocks are zeros, the elements a[i+1,i] which
        are equal to 0 show the block border.

    Note 2:
        The algorithm performance depends on the value of the internal parameter
        NS of the InternalSchurDecomposition subroutine which defines the number
        of shifts in the QR algorithm (similarly to the block width in block-matrix
        algorithms in linear algebra). If you require maximum performance on
        your machine, it is recommended to adjust this parameter manually.

    Result:
        True,
            if the algorithm has converged and parameters A and S contain the result.
        False,
            if the algorithm has not converged.

    Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library).
    *************************************************************************/
    template<unsigned int Precision>
    bool rmatrixschur(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        ap::template_2d_array< amp::ampf<Precision> >& s);

## `sdet` unit

### Functions

smatrixdet
smatrixldltdet

### `smatrixdet` function

    /*************************************************************************
    Determinant calculation of the symmetric matrix

    Input parameters:
        A       -   matrix. Array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   if IsUpper = True, then symmetric matrix A is given by its
                    upper triangle, and the lower triangle isn’t used by
                    subroutine. Similarly, if IsUpper = False, then A is given
                    by its lower triangle.

    Result:
        determinant of matrix A.

      -- ALGLIB --
         Copyright 2005-2008 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> smatrixdet(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        bool isupper);

### `smatrixldltdet` function

    /*************************************************************************
    Determinant calculation of the matrix given by LDLT decomposition.

    Input parameters:
        A       -   LDLT-decomposition of the matrix,
                    output of subroutine SMatrixLDLT.
        Pivots  -   table of permutations which were made during
                    LDLT decomposition, output of subroutine SMatrixLDLT.
        N       -   size of matrix A.
        IsUpper -   matrix storage format. The value is equal to the input
                    parameter of subroutine SMatrixLDLT.

    Result:
        matrix determinant.

      -- ALGLIB --
         Copyright 2005-2008 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> smatrixldltdet(const ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        int n,
        bool isupper);

## `sinverse` unit

### Functions

smatrixinverse
smatrixldltinverse

### `smatrixinverse` function

    /*************************************************************************
    Inversion of a symmetric indefinite matrix

    Given a lower or upper triangle of matrix A, the algorithm generates
    matrix A^-1 and saves the lower or upper triangle depending on the input.

    Input parameters:
        A       -   matrix to be inverted (upper or lower triangle).
                    Array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format. If IsUpper = True, then the upper
                    triangle of matrix A is given, otherwise the lower
                    triangle is given.

    Output parameters:
        A       -   inverse of matrix A.
                    Array with elements [0..N-1, 0..N-1].
                    If IsUpper = True, then A contains the upper triangle of
                    matrix A^-1, and the elements below the main diagonal are
                    not used nor changed.
                    The same applies if IsUpper = False.

    Result:
        True, if the matrix is not singular.
        False, if the matrix is singular and could not be inverted.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         March 31, 1993
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper);

### `smatrixldltinverse` function

    /*************************************************************************
    Inversion of a symmetric indefinite matrix

    The algorithm gets an LDLT-decomposition as an input, generates matrix A^-1
    and saves the lower or upper triangle of an inverse matrix depending on the
    input (U*D*U' or L*D*L').

    Input parameters:
        A       -   LDLT-decomposition of the matrix,
                    Output of subroutine SMatrixLDLT.
        N       -   size of matrix A.
        IsUpper -   storage format. If IsUpper = True, then the symmetric matrix
                    is given as decomposition A = U*D*U' and this decomposition
                    is stored in the upper triangle of matrix A and on the main
                    diagonal, and the lower triangle of matrix A is not used.
        Pivots  -   a table of permutations, output of subroutine SMatrixLDLT.

    Output parameters:
        A       -   inverse of the matrix, whose LDLT-decomposition was stored
                    in matrix A as a subroutine input.
                    Array with elements [0..N-1, 0..N-1].
                    If IsUpper = True, then A contains the upper triangle of
                    matrix A^-1, and the elements below the main diagonal are
                    not used nor changed. The same applies if IsUpper = False.

    Result:
        True, if the matrix is not singular.
        False, if the matrix is singular and could not be inverted.

      -- LAPACK routine (version 3.0) --
         Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
         Courant Institute, Argonne National Lab, and Rice University
         March 31, 1993
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixldltinverse(ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        int n,
        bool isupper);

## `spdgevd` unit

### Functions

smatrixgevd
smatrixgevdreduce

### `smatrixgevd` function

    /*************************************************************************
    Algorithm for solving the following generalized symmetric positive-definite
    eigenproblem:
        A*x = lambda*B*x (1) or
        A*B*x = lambda*x (2) or
        B*A*x = lambda*x (3).
    where A is a symmetric matrix, B - symmetric positive-definite matrix.
    The problem is solved by reducing it to an ordinary  symmetric  eigenvalue
    problem.

    Input parameters:
        A           -   symmetric matrix which is given by its upper or lower
                        triangular part.
                        Array whose indexes range within [0..N-1, 0..N-1].
        N           -   size of matrices A and B.
        IsUpperA    -   storage format of matrix A.
        B           -   symmetric positive-definite matrix which is given by
                        its upper or lower triangular part.
                        Array whose indexes range within [0..N-1, 0..N-1].
        IsUpperB    -   storage format of matrix B.
        ZNeeded     -   if ZNeeded is equal to:
                         * 0, the eigenvectors are not returned;
                         * 1, the eigenvectors are returned.
        ProblemType -   if ProblemType is equal to:
                         * 1, the following problem is solved: A*x = lambda*B*x;
                         * 2, the following problem is solved: A*B*x = lambda*x;
                         * 3, the following problem is solved: B*A*x = lambda*x.

    Output parameters:
        D           -   eigenvalues in ascending order.
                        Array whose index ranges within [0..N-1].
        Z           -   if ZNeeded is equal to:
                         * 0, Z hasn’t changed;
                         * 1, Z contains eigenvectors.
                        Array whose indexes range within [0..N-1, 0..N-1].
                        The eigenvectors are stored in matrix columns. It should
                        be noted that the eigenvectors in such problems do not
                        form an orthogonal system.

    Result:
        True, if the problem was solved successfully.
        False, if the error occurred during the Cholesky decomposition of matrix
        B (the matrix isn’t positive-definite) or during the work of the iterative
        algorithm for solving the symmetric eigenproblem.

    See also the GeneralizedSymmetricDefiniteEVDReduce subroutine.

      -- ALGLIB --
         Copyright 1.28.2006 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixgevd(ap::template_2d_array< amp::ampf<Precision> > a,
        int n,
        bool isuppera,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        bool isupperb,
        int zneeded,
        int problemtype,
        ap::template_1d_array< amp::ampf<Precision> >& d,
        ap::template_2d_array< amp::ampf<Precision> >& z);

### `smatrixgevdreduce` function

    /*************************************************************************
    Algorithm for reduction of the following generalized symmetric positive-
    definite eigenvalue problem:
        A*x = lambda*B*x (1) or
        A*B*x = lambda*x (2) or
        B*A*x = lambda*x (3)
    to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and
    the given problems are the same, and the eigenvectors of the given problem
    could be obtained by multiplying the obtained eigenvectors by the
    transformation matrix x = R*y).

    Here A is a symmetric matrix, B - symmetric positive-definite matrix.

    Input parameters:
        A           -   symmetric matrix which is given by its upper or lower
                        triangular part.
                        Array whose indexes range within [0..N-1, 0..N-1].
        N           -   size of matrices A and B.
        IsUpperA    -   storage format of matrix A.
        B           -   symmetric positive-definite matrix which is given by
                        its upper or lower triangular part.
                        Array whose indexes range within [0..N-1, 0..N-1].
        IsUpperB    -   storage format of matrix B.
        ProblemType -   if ProblemType is equal to:
                         * 1, the following problem is solved: A*x = lambda*B*x;
                         * 2, the following problem is solved: A*B*x = lambda*x;
                         * 3, the following problem is solved: B*A*x = lambda*x.

    Output parameters:
        A           -   symmetric matrix which is given by its upper or lower
                        triangle depending on IsUpperA. Contains matrix C.
                        Array whose indexes range within [0..N-1, 0..N-1].
        R           -   upper triangular or low triangular transformation matrix
                        which is used to obtain the eigenvectors of a given problem
                        as the product of eigenvectors of C (from the right) and
                        matrix R (from the left). If the matrix is upper
                        triangular, the elements below the main diagonal
                        are equal to 0 (and vice versa). Thus, we can perform
                        the multiplication without taking into account the
                        internal structure (which is an easier though less
                        effective way).
                        Array whose indexes range within [0..N-1, 0..N-1].
        IsUpperR    -   type of matrix R (upper or lower triangular).

    Result:
        True, if the problem was reduced successfully.
        False, if the error occurred during the Cholesky decomposition of
            matrix B (the matrix is not positive-definite).

      -- ALGLIB --
         Copyright 1.28.2006 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixgevdreduce(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isuppera,
        const ap::template_2d_array< amp::ampf<Precision> >& b,
        bool isupperb,
        int problemtype,
        ap::template_2d_array< amp::ampf<Precision> >& r,
        bool& isupperr);

## `spline1d` unit

### Structures

spline1dfitreport
spline1dinterpolant

### Functions

spline1dbuildakima
spline1dbuildcatmullrom
spline1dbuildcubic
spline1dbuildhermite
spline1dbuildlinear
spline1dcalc
spline1dcopy
spline1ddiff
spline1dfitcubic
spline1dfitcubicwc
spline1dfithermite
spline1dfithermitewc
spline1dintegrate
spline1dlintransx
spline1dlintransy
spline1dunpack

### Examples

spline1d_calc
spline1d_cubic
spline1d_fit
spline1d_fitc
spline1d_hermite
spline1d_linear

### `spline1dfitreport` structure

    /*************************************************************************
    Spline fitting report:
        TaskRCond       reciprocal of task's condition number
        RMSError        RMS error
        AvgError        average error
        AvgRelError     average relative error (for non-zero Y[I])
        MaxError        maximum error
    *************************************************************************/
    template<unsigned int Precision>
    class spline1dfitreport
    {
    public:
        amp::ampf<Precision> taskrcond;
        amp::ampf<Precision> rmserror;
        amp::ampf<Precision> avgerror;
        amp::ampf<Precision> avgrelerror;
        amp::ampf<Precision> maxerror;
    };

### `spline1dinterpolant` structure

    /*************************************************************************
    1-dimensional spline inteprolant
    *************************************************************************/
    template<unsigned int Precision>
    class spline1dinterpolant
    {
    public:
        bool periodic;
        int n;
        int k;
        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > c;
    };

### `spline1dbuildakima` function

    /*************************************************************************
    This subroutine builds Akima spline interpolant

    INPUT PARAMETERS:
        X           -   spline nodes, array[0..N-1]
        Y           -   function values, array[0..N-1]
        N           -   points count, N>=5

    OUTPUT PARAMETERS:
        C           -   spline interpolant

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

      -- ALGLIB PROJECT --
         Copyright 24.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dbuildakima(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        int n,
        spline1dinterpolant<Precision>& c);

### `spline1dbuildcatmullrom` function

    /*************************************************************************
    This subroutine builds Catmull-Rom spline interpolant.

    INPUT PARAMETERS:
        X           -   spline nodes, array[0..N-1].
        Y           -   function values, array[0..N-1].
        N           -   points count, N>=2
        BoundType   -   boundary condition type:
                        * -1 for periodic boundary condition
                        *  0 for parabolically terminated spline
        Tension     -   tension parameter:
                        * tension=0   corresponds to classic Catmull-Rom spline
                        * 0<tension<1 corresponds to more general form - cardinal spline

    OUTPUT PARAMETERS:
        C           -   spline interpolant

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

    PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:

    Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    However, this subroutine doesn't require you to specify equal  values  for
    the first and last points - it automatically forces them to be equal.

      -- ALGLIB PROJECT --
         Copyright 23.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dbuildcatmullrom(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        int n,
        int boundtype,
        amp::ampf<Precision> tension,
        spline1dinterpolant<Precision>& c);

### `spline1dbuildcubic` function

    /*************************************************************************
    This subroutine builds cubic spline interpolant.

    INPUT PARAMETERS:
        X           -   spline nodes, array[0..N-1].
        Y           -   function values, array[0..N-1].
        N           -   points count, N>=2
        BoundLType  -   boundary condition type for the left boundary
        BoundL      -   left boundary condition (first or second derivative,
                        depending on the BoundLType)
        BoundRType  -   boundary condition type for the right boundary
        BoundR      -   right boundary condition (first or second derivative,
                        depending on the BoundRType)

    OUTPUT PARAMETERS:
        C           -   spline interpolant

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

    SETTING BOUNDARY VALUES:

    The BoundLType/BoundRType parameters can have the following values:
        * -1, which corresonds to the periodic (cyclic) boundary conditions.
              In this case:
              * both BoundLType and BoundRType must be equal to -1.
              * BoundL/BoundR are ignored
              * Y[last] is ignored (it is assumed to be equal to Y[first]).
        *  0, which  corresponds  to  the  parabolically   terminated  spline
              (BoundL and/or BoundR are ignored).
        *  1, which corresponds to the first derivative boundary condition
        *  2, which corresponds to the second derivative boundary condition

    PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:

    Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    However, this subroutine doesn't require you to specify equal  values  for
    the first and last points - it automatically forces them to be equal.

      -- ALGLIB PROJECT --
         Copyright 23.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dbuildcubic(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        int n,
        int boundltype,
        amp::ampf<Precision> boundl,
        int boundrtype,
        amp::ampf<Precision> boundr,
        spline1dinterpolant<Precision>& c);

Examples: spline1d_calc spline1d_cubic

### `spline1dbuildhermite` function

    /*************************************************************************
    This subroutine builds Hermite spline interpolant.

    INPUT PARAMETERS:
        X           -   spline nodes, array[0..N-1]
        Y           -   function values, array[0..N-1]
        D           -   derivatives, array[0..N-1]
        N           -   points count, N>=2

    OUTPUT PARAMETERS:
        C           -   spline interpolant.

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

      -- ALGLIB PROJECT --
         Copyright 23.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dbuildhermite(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        ap::template_1d_array< amp::ampf<Precision> > d,
        int n,
        spline1dinterpolant<Precision>& c);

Examples: spline1d_hermite

### `spline1dbuildlinear` function

    /*************************************************************************
    This subroutine builds linear spline interpolant

    INPUT PARAMETERS:
        X   -   spline nodes, array[0..N-1]
        Y   -   function values, array[0..N-1]
        N   -   points count, N>=2

    OUTPUT PARAMETERS:
        C   -   spline interpolant

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

      -- ALGLIB PROJECT --
         Copyright 24.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dbuildlinear(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        int n,
        spline1dinterpolant<Precision>& c);

Examples: spline1d_linear

### `spline1dcalc` function

    /*************************************************************************
    This subroutine calculates the value of the spline at the given point X.

    INPUT PARAMETERS:
        C   -   spline interpolant
        X   -   point

    Result:
        S(x)

      -- ALGLIB PROJECT --
         Copyright 23.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spline1dcalc(const spline1dinterpolant<Precision>& c,
        amp::ampf<Precision> x);

Examples: spline1d_calc spline1d_cubic spline1d_hermite spline1d_linear

### `spline1dcopy` function

    /*************************************************************************
    This subroutine makes the copy of the spline.

    INPUT PARAMETERS:
        C   -   spline interpolant.

    Result:
        CC  -   spline copy

      -- ALGLIB PROJECT --
         Copyright 29.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dcopy(const spline1dinterpolant<Precision>& c,
        spline1dinterpolant<Precision>& cc);

### `spline1ddiff` function

    /*************************************************************************
    This subroutine differentiates the spline.

    INPUT PARAMETERS:
        C   -   spline interpolant.
        X   -   point

    Result:
        S   -   S(x)
        DS  -   S'(x)
        D2S -   S''(x)

      -- ALGLIB PROJECT --
         Copyright 24.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1ddiff(const spline1dinterpolant<Precision>& c,
        amp::ampf<Precision> x,
        amp::ampf<Precision>& s,
        amp::ampf<Precision>& ds,
        amp::ampf<Precision>& d2s);

Examples: spline1d_calc

### `spline1dfitcubic` function

    /*************************************************************************
    Least squares fitting by cubic spline.

    This subroutine is "lightweight" alternative for more complex and feature-
    rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
    about subroutine parameters (we don't duplicate it here because of length)

      -- ALGLIB PROJECT --
         Copyright 18.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dfitcubic(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        int m,
        int& info,
        spline1dinterpolant<Precision>& s,
        spline1dfitreport<Precision>& rep);

Examples: spline1d_fit

### `spline1dfitcubicwc` function

    /*************************************************************************
    Weighted fitting by cubic  spline,  with constraints on function values or
    derivatives.

    Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
    basis functions. Basis functions are cubic splines with continuous  second
    derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
    regularizing term is used  when  solving  constrained  tasks  (to  improve
    stability).

    Task is linear, so linear least squares solver is used. Complexity of this
    computational scheme is O(N*M^2), mostly dominated by least squares solver

    SEE ALSO
        Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
                                    less smooth)
        Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
                                    without invididual weights and constraints

    INPUT PARAMETERS:
        X   -   points, array[0..N-1].
        Y   -   function values, array[0..N-1].
        W   -   weights, array[0..N-1]
                Each summand in square  sum  of  approximation deviations from
                given  values  is  multiplied  by  the square of corresponding
                weight. Fill it by 1's if you don't  want  to  solve  weighted
                task.
        N   -   number of points, N>0.
        XC  -   points where spline values/derivatives are constrained,
                array[0..K-1].
        YC  -   values of constraints, array[0..K-1]
        DC  -   array[0..K-1], types of constraints:
                * DC[i]=0   means that S(XC[i])=YC[i]
                * DC[i]=1   means that S'(XC[i])=YC[i]
                SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
        K   -   number of constraints, 0<=K<M.
                K=0 means no constraints (XC/YC/DC are not used in such cases)
        M   -   number of basis functions ( = number_of_nodes+2), M>=4.

    OUTPUT PARAMETERS:
        Info-   same format as in LSFitLinearWC() subroutine.
                * Info>0    task is solved
                * Info<=0   an error occured:
                            -4 means inconvergence of internal SVD
                            -3 means inconsistent constraints
                            -1 means another errors in parameters passed
                               (N<=0, for example)
        S   -   spline interpolant.
        Rep -   report, same format as in LSFitLinearWC() subroutine.
                Following fields are set:
                * RMSError      rms error on the (X,Y).
                * AvgError      average error on the (X,Y).
                * AvgRelError   average relative error on the non-zero Y
                * MaxError      maximum error
                                NON-WEIGHTED ERRORS ARE CALCULATED

    IMPORTANT:
        this subroitine doesn't calculate task's condition number for K<>0.

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

    SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:

    Setting constraints can lead  to undesired  results,  like ill-conditioned
    behavior, or inconsistency being detected. From the other side,  it allows
    us to improve quality of the fit. Here we summarize  our  experience  with
    constrained regression splines:
    * excessive constraints can be inconsistent. Splines are  piecewise  cubic
      functions, and it is easy to create an example, where  large  number  of
      constraints  concentrated  in  small  area will result in inconsistency.
      Just because spline is not flexible enough to satisfy all of  them.  And
      same constraints spread across the  [min(x),max(x)]  will  be  perfectly
      consistent.
    * the more evenly constraints are spread across [min(x),max(x)],  the more
      chances that they will be consistent
    * the  greater  is  M (given  fixed  constraints),  the  more chances that
      constraints will be consistent
    * in the general case, consistency of constraints IS NOT GUARANTEED.
    * in the several special cases, however, we CAN guarantee consistency.
    * one of this cases is constraints  on  the  function  values  AND/OR  its
      derivatives at the interval boundaries.
    * another  special  case  is ONE constraint on the function value (OR, but
      not AND, derivative) anywhere in the interval

    Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
    can't solve your task without them. Anything beyond  special  cases  given
    above is not guaranteed and may result in inconsistency.

      -- ALGLIB PROJECT --
         Copyright 18.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dfitcubicwc(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& xc,
        const ap::template_1d_array< amp::ampf<Precision> >& yc,
        const ap::template_1d_array< int >& dc,
        int k,
        int m,
        int& info,
        spline1dinterpolant<Precision>& s,
        spline1dfitreport<Precision>& rep);

Examples: spline1d_fitc

### `spline1dfithermite` function

    /*************************************************************************
    Least squares fitting by Hermite spline.

    This subroutine is "lightweight" alternative for more complex and feature-
    rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
    more information about subroutine parameters (we don't duplicate  it  here
    because of length).

      -- ALGLIB PROJECT --
         Copyright 18.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dfithermite(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        int n,
        int m,
        int& info,
        spline1dinterpolant<Precision>& s,
        spline1dfitreport<Precision>& rep);

Examples: spline1d_fit

### `spline1dfithermitewc` function

    /*************************************************************************
    Weighted  fitting  by Hermite spline,  with constraints on function values
    or first derivatives.

    Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
    basis functions. Basis functions are Hermite splines.  Small  regularizing
    term is used when solving constrained tasks (to improve stability).

    Task is linear, so linear least squares solver is used. Complexity of this
    computational scheme is O(N*M^2), mostly dominated by least squares solver

    SEE ALSO
        Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
                                    more smooth)
        Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
                                    invididual weights and constraints

    INPUT PARAMETERS:
        X   -   points, array[0..N-1].
        Y   -   function values, array[0..N-1].
        W   -   weights, array[0..N-1]
                Each summand in square  sum  of  approximation deviations from
                given  values  is  multiplied  by  the square of corresponding
                weight. Fill it by 1's if you don't  want  to  solve  weighted
                task.
        N   -   number of points, N>0.
        XC  -   points where spline values/derivatives are constrained,
                array[0..K-1].
        YC  -   values of constraints, array[0..K-1]
        DC  -   array[0..K-1], types of constraints:
                * DC[i]=0   means that S(XC[i])=YC[i]
                * DC[i]=1   means that S'(XC[i])=YC[i]
                SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
        K   -   number of constraints, 0<=K<M.
                K=0 means no constraints (XC/YC/DC are not used in such cases)
        M   -   number of basis functions (= 2 * number of nodes),
                M>=4,
                M IS EVEN!

    OUTPUT PARAMETERS:
        Info-   same format as in LSFitLinearW() subroutine:
                * Info>0    task is solved
                * Info<=0   an error occured:
                            -4 means inconvergence of internal SVD
                            -3 means inconsistent constraints
                            -2 means odd M was passed (which is not supported)
                            -1 means another errors in parameters passed
                               (N<=0, for example)
        S   -   spline interpolant.
        Rep -   report, same format as in LSFitLinearW() subroutine.
                Following fields are set:
                * RMSError      rms error on the (X,Y).
                * AvgError      average error on the (X,Y).
                * AvgRelError   average relative error on the non-zero Y
                * MaxError      maximum error
                                NON-WEIGHTED ERRORS ARE CALCULATED

    IMPORTANT:
        this subroitine doesn't calculate task's condition number for K<>0.

    IMPORTANT:
        this subroitine supports only even M's

    ORDER OF POINTS

    Subroutine automatically sorts points, so caller may pass unsorted array.

    SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:

    Setting constraints can lead  to undesired  results,  like ill-conditioned
    behavior, or inconsistency being detected. From the other side,  it allows
    us to improve quality of the fit. Here we summarize  our  experience  with
    constrained regression splines:
    * excessive constraints can be inconsistent. Splines are  piecewise  cubic
      functions, and it is easy to create an example, where  large  number  of
      constraints  concentrated  in  small  area will result in inconsistency.
      Just because spline is not flexible enough to satisfy all of  them.  And
      same constraints spread across the  [min(x),max(x)]  will  be  perfectly
      consistent.
    * the more evenly constraints are spread across [min(x),max(x)],  the more
      chances that they will be consistent
    * the  greater  is  M (given  fixed  constraints),  the  more chances that
      constraints will be consistent
    * in the general case, consistency of constraints is NOT GUARANTEED.
    * in the several special cases, however, we can guarantee consistency.
    * one of this cases is  M>=4  and   constraints  on   the  function  value
      (AND/OR its derivative) at the interval boundaries.
    * another special case is M>=4  and  ONE  constraint on the function value
      (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]

    Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
    can't solve your task without them. Anything beyond  special  cases  given
    above is not guaranteed and may result in inconsistency.

      -- ALGLIB PROJECT --
         Copyright 18.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dfithermitewc(const ap::template_1d_array< amp::ampf<Precision> >& x,
        const ap::template_1d_array< amp::ampf<Precision> >& y,
        const ap::template_1d_array< amp::ampf<Precision> >& w,
        int n,
        const ap::template_1d_array< amp::ampf<Precision> >& xc,
        const ap::template_1d_array< amp::ampf<Precision> >& yc,
        const ap::template_1d_array< int >& dc,
        int k,
        int m,
        int& info,
        spline1dinterpolant<Precision>& s,
        spline1dfitreport<Precision>& rep);

Examples: spline1d_fitc

### `spline1dintegrate` function

    /*************************************************************************
    This subroutine integrates the spline.

    INPUT PARAMETERS:
        C   -   spline interpolant.
        X   -   right bound of the integration interval [a, x],
                here 'a' denotes min(x[])
    Result:
        integral(S(t)dt,a,x)

      -- ALGLIB PROJECT --
         Copyright 23.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spline1dintegrate(const spline1dinterpolant<Precision>& c,
        amp::ampf<Precision> x);

Examples: spline1d_calc

### `spline1dlintransx` function

    /*************************************************************************
    This subroutine performs linear transformation of the spline argument.

    INPUT PARAMETERS:
        C   -   spline interpolant.
        A, B-   transformation coefficients: x = A*t + B
    Result:
        C   -   transformed spline

      -- ALGLIB PROJECT --
         Copyright 30.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dlintransx(spline1dinterpolant<Precision>& c,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b);

### `spline1dlintransy` function

    /*************************************************************************
    This subroutine performs linear transformation of the spline.

    INPUT PARAMETERS:
        C   -   spline interpolant.
        A, B-   transformation coefficients: S2(x) = A*S(x) + B
    Result:
        C   -   transformed spline

      -- ALGLIB PROJECT --
         Copyright 30.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dlintransy(spline1dinterpolant<Precision>& c,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b);

### `spline1dunpack` function

    /*************************************************************************
    This subroutine unpacks the spline into the coefficients table.

    INPUT PARAMETERS:
        C   -   spline interpolant.
        X   -   point

    Result:
        Tbl -   coefficients table, unpacked format, array[0..N-2, 0..5].
                For I = 0...N-2:
                    Tbl[I,0] = X[i]
                    Tbl[I,1] = X[i+1]
                    Tbl[I,2] = C0
                    Tbl[I,3] = C1
                    Tbl[I,4] = C2
                    Tbl[I,5] = C3
                On [x[i], x[i+1]] spline is equals to:
                    S(x) = C0 + C1*t + C2*t^2 + C3*t^3
                    t = x-x[i]

      -- ALGLIB PROJECT --
         Copyright 29.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline1dunpack(const spline1dinterpolant<Precision>& c,
        int& n,
        ap::template_2d_array< amp::ampf<Precision> >& tbl);

### spline1d_calc example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        spline1d::spline1dinterpolant<Precision> s;
        amp::ampf<Precision> v;
        amp::ampf<Precision> dv;
        amp::ampf<Precision> d2v;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Demonstration of Spline1DCalc(), Spline1DDiff(), Spline1DIntegrate()
        //
        printf("DEMONSTRATION OF Spline1DCalc(), Spline1DDiff(), Spline1DIntegrate()\n\n");
        printf("F(x)=sin(x), [0, pi]\n");
        printf("Natural cubic spline with 3 nodes is used\n\n");

        //
        // Create spline
        //
        n = 3;
        x.setlength(n);
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
        }
        spline1d::spline1dbuildcubic<Precision>(x, y, n, 2, amp::ampf<Precision>("0.0"), 2, amp::ampf<Precision>("0.0"), s);

        //
        // Output results
        //
        spline1d::spline1ddiff<Precision>(s, amp::ampf<Precision>(0), v, dv, d2v);
        printf("                 S(x)    F(x) \n");
        printf("function       %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, amp::ampf<Precision>(0))).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("d/dx(0)        %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(dv).toDouble()),
            double(amp::ampf<Precision>(1).toDouble()));
        printf("d2/dx2(0)      %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(d2v).toDouble()),
            double(amp::ampf<Precision>(0).toDouble()));
        printf("integral(0,pi) %6.3lf  %6.3lf \n",
            double(amp::ampf<Precision>(spline1d::spline1dintegrate<Precision>(s, amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(2).toDouble()));
        printf("\n\n");

### spline1d_cubic example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        spline1d::spline1dinterpolant<Precision> s;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Interpolation by natural Cubic spline.
        //
        printf("INTERPOLATION BY NATURAL CUBIC SPLINE\n\n");
        printf("F(x)=sin(x), [0, pi], 3 nodes\n\n");
        printf("     x   F(x)   S(x)  Error\n");

        //
        // Create spline
        //
        n = 3;
        x.setlength(n);
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
        }
        spline1d::spline1dbuildcubic<Precision>(x, y, n, 1, amp::ampf<Precision>(+1), 1, amp::ampf<Precision>(-1), s);

        //
        // Output results
        //
        t = 0;
        maxerr = 0;
        while( t<amp::ampf<Precision>("0.999999")*amp::pi<Precision>() )
        {
            err = amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t));
            maxerr = amp::maximum<Precision>(err, maxerr);
            printf("%6.3lf %6.3lf %6.3lf %6.3lf\n",
                double(amp::ampf<Precision>(t).toDouble()),
                double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                double(amp::ampf<Precision>(err).toDouble()));
            t = amp::minimum<Precision>(amp::pi<Precision>(), t+amp::ampf<Precision>("0.25"));
        }
        err = amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, amp::pi<Precision>())-amp::sin<Precision>(amp::pi<Precision>()));
        maxerr = amp::maximum<Precision>(err, maxerr);
        printf("%6.3lf %6.3lf %6.3lf %6.3lf\n\n",
            double(amp::ampf<Precision>(amp::pi<Precision>()).toDouble()),
            double(amp::ampf<Precision>(amp::sin<Precision>(amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(err).toDouble()));
        printf("max|error| = %0.3lf\n",
            double(amp::ampf<Precision>(maxerr).toDouble()));
        printf("Try other demos (spline1d_linear, spline1d_hermite) and compare errors...\n\n\n");

### spline1d_fit example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        int info;
        spline1d::spline1dinterpolant<Precision> s;
        amp::ampf<Precision> t;
        spline1d::spline1dfitreport<Precision> rep;

        //
        // Fitting by unconstrained natural cubic spline
        //
        printf("FITTING BY UNCONSTRAINED NATURAL CUBIC SPLINE\n\n");
        printf("F(x)=sin(x)      function being fitted\n");
        printf("[0, pi]          interval\n");
        printf("M=4              number of basis functions to use\n");
        printf("N=100            number of points to fit\n");

        //
        // Create and fit
        //
        n = 100;
        x.setlength(n);
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
        }
        spline1d::spline1dfitcubic<Precision>(x, y, n, 4, info, s, rep);

        //
        // Output results
        //
        if( info>0 )
        {
            printf("\nOK, we have finished\n\n");
            printf("     x   F(x)   S(x)  Error\n");
            t = 0;
            while( t<amp::ampf<Precision>("0.999999")*amp::pi<Precision>() )
            {
                printf("%6.3lf %6.3lf %6.3lf %6.3lf\n",
                    double(amp::ampf<Precision>(t).toDouble()),
                    double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                    double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                    double(amp::ampf<Precision>(amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t))).toDouble()));
                t = amp::minimum<Precision>(amp::pi<Precision>(), t+amp::ampf<Precision>("0.25"));
            }
            printf("%6.3lf %6.3lf %6.3lf %6.3lf\n\n",
                double(amp::ampf<Precision>(t).toDouble()),
                double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                double(amp::ampf<Precision>(amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t))).toDouble()));
            printf("rms error is %6.3lf\n",
                double(amp::ampf<Precision>(rep.rmserror).toDouble()));
            printf("max error is %6.3lf\n",
                double(amp::ampf<Precision>(rep.maxerror).toDouble()));
        }
        else
        {
            printf("\nSomething wrong, Info=%0ld",
                long(info));
        }

### spline1d_fitc example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_1d_array< amp::ampf<Precision> > w;
        ap::template_1d_array< amp::ampf<Precision> > xc;
        ap::template_1d_array< amp::ampf<Precision> > yc;
        ap::template_1d_array< int > dc;
        int n;
        int i;
        int info;
        spline1d::spline1dinterpolant<Precision> s;
        amp::ampf<Precision> t;
        spline1d::spline1dfitreport<Precision> rep;

        //
        // Fitting by constrained Hermite spline
        //
        printf("FITTING BY CONSTRAINED HERMITE SPLINE\n\n");
        printf("F(x)=sin(x)      function being fitted\n");
        printf("[0, pi]          interval\n");
        printf("M=6              number of basis functions to use\n");
        printf("S(0)=0           first constraint\n");
        printf("S(pi)=0          second constraint\n");
        printf("N=100            number of points to fit\n");

        //
        // Create and fit:
        // * X  contains points
        // * Y  contains values
        // * W  contains weights
        // * XC contains constraints locations
        // * YC contains constraints values
        // * DC contains derivative indexes (0 = constrained function value)
        //
        n = 100;
        x.setlength(n);
        y.setlength(n);
        w.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
            w(i) = 1;
        }
        xc.setlength(2);
        yc.setlength(2);
        dc.setlength(2);
        xc(0) = 0;
        yc(0) = 0;
        dc(0) = 0;
        xc(0) = amp::pi<Precision>();
        yc(0) = 0;
        dc(0) = 0;
        spline1d::spline1dfithermitewc<Precision>(x, y, w, n, xc, yc, dc, 2, 6, info, s, rep);

        //
        // Output results
        //
        if( info>0 )
        {
            printf("\nOK, we have finished\n\n");
            printf("     x   F(x)   S(x)  Error\n");
            t = 0;
            while( t<amp::ampf<Precision>("0.999999")*amp::pi<Precision>() )
            {
                printf("%6.3lf %6.3lf %6.3lf %6.3lf\n",
                    double(amp::ampf<Precision>(t).toDouble()),
                    double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                    double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                    double(amp::ampf<Precision>(amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t))).toDouble()));
                t = amp::minimum<Precision>(amp::pi<Precision>(), t+amp::ampf<Precision>("0.25"));
            }
            printf("%6.3lf %6.3lf %6.3lf %6.3lf\n\n",
                double(amp::ampf<Precision>(t).toDouble()),
                double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                double(amp::ampf<Precision>(amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t))).toDouble()));
            printf("rms error is %6.3lf\n",
                double(amp::ampf<Precision>(rep.rmserror).toDouble()));
            printf("max error is %6.3lf\n",
                double(amp::ampf<Precision>(rep.maxerror).toDouble()));
            printf("S(0) = S(pi) = 0 (exactly)\n\n");
        }
        else
        {
            printf("\nSomething wrong, Info=%0ld",
                long(info));
        }

### spline1d_hermite example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        ap::template_1d_array< amp::ampf<Precision> > d;
        int n;
        int i;
        amp::ampf<Precision> t;
        spline1d::spline1dinterpolant<Precision> s;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Interpolation by natural Cubic spline.
        //
        printf("INTERPOLATION BY HERMITE SPLINE\n\n");
        printf("F(x)=sin(x), [0, pi], 3 nodes\n\n");
        printf("     x   F(x)   S(x)  Error\n");

        //
        // Create spline
        //
        n = 3;
        x.setlength(n);
        y.setlength(n);
        d.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
            d(i) = amp::cos<Precision>(x(i));
        }
        spline1d::spline1dbuildhermite<Precision>(x, y, d, n, s);

        //
        // Output results
        //
        t = 0;
        maxerr = 0;
        while( t<amp::ampf<Precision>("0.999999")*amp::pi<Precision>() )
        {
            err = amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t));
            maxerr = amp::maximum<Precision>(err, maxerr);
            printf("%6.3lf %6.3lf %6.3lf %6.3lf\n",
                double(amp::ampf<Precision>(t).toDouble()),
                double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                double(amp::ampf<Precision>(err).toDouble()));
            t = amp::minimum<Precision>(amp::pi<Precision>(), t+amp::ampf<Precision>("0.25"));
        }
        err = amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, amp::pi<Precision>())-amp::sin<Precision>(amp::pi<Precision>()));
        maxerr = amp::maximum<Precision>(err, maxerr);
        printf("%6.3lf %6.3lf %6.3lf %6.3lf\n\n",
            double(amp::ampf<Precision>(amp::pi<Precision>()).toDouble()),
            double(amp::ampf<Precision>(amp::sin<Precision>(amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(err).toDouble()));
        printf("max|error| = %0.3lf\n",
            double(amp::ampf<Precision>(maxerr).toDouble()));
        printf("Try other demos (spline1d_linear, spline1d_cubic) and compare errors...\n\n\n");

### spline1d_linear example

        ap::template_1d_array< amp::ampf<Precision> > x;
        ap::template_1d_array< amp::ampf<Precision> > y;
        int n;
        int i;
        amp::ampf<Precision> t;
        spline1d::spline1dinterpolant<Precision> s;
        amp::ampf<Precision> err;
        amp::ampf<Precision> maxerr;

        //
        // Interpolation by linear spline.
        //
        printf("INTERPOLATION BY LINEAR SPLINE\n\n");
        printf("F(x)=sin(x), [0, pi], 3 nodes\n\n");
        printf("     x   F(x)   S(x)  Error\n");

        //
        // Create spline
        //
        n = 3;
        x.setlength(n);
        y.setlength(n);
        for(i=0; i<=n-1; i++)
        {
            x(i) = amp::pi<Precision>()*i/(n-1);
            y(i) = amp::sin<Precision>(x(i));
        }
        spline1d::spline1dbuildlinear<Precision>(x, y, n, s);

        //
        // Output results
        //
        t = 0;
        maxerr = 0;
        while( t<amp::ampf<Precision>("0.999999")*amp::pi<Precision>() )
        {
            err = amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, t)-amp::sin<Precision>(t));
            maxerr = amp::maximum<Precision>(err, maxerr);
            printf("%6.3lf %6.3lf %6.3lf %6.3lf\n",
                double(amp::ampf<Precision>(t).toDouble()),
                double(amp::ampf<Precision>(amp::sin<Precision>(t)).toDouble()),
                double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, t)).toDouble()),
                double(amp::ampf<Precision>(err).toDouble()));
            t = amp::minimum<Precision>(amp::pi<Precision>(), t+amp::ampf<Precision>("0.25"));
        }
        err = amp::abs<Precision>(spline1d::spline1dcalc<Precision>(s, amp::pi<Precision>())-amp::sin<Precision>(amp::pi<Precision>()));
        maxerr = amp::maximum<Precision>(err, maxerr);
        printf("%6.3lf %6.3lf %6.3lf %6.3lf\n\n",
            double(amp::ampf<Precision>(amp::pi<Precision>()).toDouble()),
            double(amp::ampf<Precision>(amp::sin<Precision>(amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(spline1d::spline1dcalc<Precision>(s, amp::pi<Precision>())).toDouble()),
            double(amp::ampf<Precision>(err).toDouble()));
        printf("max|error| = %0.3lf\n",
            double(amp::ampf<Precision>(maxerr).toDouble()));
        printf("Try other demos (spline1d_hermite, spline1d_cubic) and compare errors...\n\n\n");

## `spline2d` unit

### Structures

spline2dinterpolant

### Functions

spline2dbuildbicubic
spline2dbuildbilinear
spline2dcalc
spline2dcopy
spline2ddiff
spline2dlintransf
spline2dlintransxy
spline2dresamplebicubic
spline2dresamplebilinear
spline2dserialize
spline2dunpack
spline2dunserialize

### `spline2dinterpolant` structure

    /*************************************************************************
    2-dimensional spline inteprolant
    *************************************************************************/
    template<unsigned int Precision>
    class spline2dinterpolant
    {
    public:
        int k;
        ap::template_1d_array< amp::ampf<Precision> > c;
    };

### `spline2dbuildbicubic` function

    /*************************************************************************
    This subroutine builds bicubic spline coefficients table.

    Input parameters:
        X   -   spline abscissas, array[0..N-1]
        Y   -   spline ordinates, array[0..M-1]
        F   -   function values, array[0..M-1,0..N-1]
        M,N -   grid size, M>=2, N>=2

    Output parameters:
        C   -   spline interpolant

      -- ALGLIB PROJECT --
         Copyright 05.07.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dbuildbicubic(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        ap::template_2d_array< amp::ampf<Precision> > f,
        int m,
        int n,
        spline2dinterpolant<Precision>& c);

### `spline2dbuildbilinear` function

    /*************************************************************************
    This subroutine builds bilinear spline coefficients table.

    Input parameters:
        X   -   spline abscissas, array[0..N-1]
        Y   -   spline ordinates, array[0..M-1]
        F   -   function values, array[0..M-1,0..N-1]
        M,N -   grid size, M>=2, N>=2

    Output parameters:
        C   -   spline interpolant

      -- ALGLIB PROJECT --
         Copyright 05.07.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dbuildbilinear(ap::template_1d_array< amp::ampf<Precision> > x,
        ap::template_1d_array< amp::ampf<Precision> > y,
        ap::template_2d_array< amp::ampf<Precision> > f,
        int m,
        int n,
        spline2dinterpolant<Precision>& c);

### `spline2dcalc` function

    /*************************************************************************
    This subroutine calculates the value of the bilinear or bicubic spline  at
    the given point X.

    Input parameters:
        C   -   coefficients table.
                Built by BuildBilinearSpline or BuildBicubicSpline.
        X, Y-   point

    Result:
        S(x,y)

      -- ALGLIB PROJECT --
         Copyright 05.07.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> spline2dcalc(const spline2dinterpolant<Precision>& c,
        amp::ampf<Precision> x,
        amp::ampf<Precision> y);

### `spline2dcopy` function

    /*************************************************************************
    This subroutine makes the copy of the spline model.

    Input parameters:
        C   -   spline interpolant

    Output parameters:
        CC  -   spline copy

      -- ALGLIB PROJECT --
         Copyright 29.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dcopy(const spline2dinterpolant<Precision>& c,
        spline2dinterpolant<Precision>& cc);

### `spline2ddiff` function

    /*************************************************************************
    This subroutine calculates the value of the bilinear or bicubic spline  at
    the given point X and its derivatives.

    Input parameters:
        C   -   spline interpolant.
        X, Y-   point

    Output parameters:
        F   -   S(x,y)
        FX  -   dS(x,y)/dX
        FY  -   dS(x,y)/dY
        FXY -   d2S(x,y)/dXdY

      -- ALGLIB PROJECT --
         Copyright 05.07.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2ddiff(const spline2dinterpolant<Precision>& c,
        amp::ampf<Precision> x,
        amp::ampf<Precision> y,
        amp::ampf<Precision>& f,
        amp::ampf<Precision>& fx,
        amp::ampf<Precision>& fy,
        amp::ampf<Precision>& fxy);

### `spline2dlintransf` function

    /*************************************************************************
    This subroutine performs linear transformation of the spline.

    Input parameters:
        C   -   spline interpolant.
        A, B-   transformation coefficients: S2(x,y) = A*S(x,y) + B

    Output parameters:
        C   -   transformed spline

      -- ALGLIB PROJECT --
         Copyright 30.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dlintransf(spline2dinterpolant<Precision>& c,
        amp::ampf<Precision> a,
        amp::ampf<Precision> b);

### `spline2dlintransxy` function

    /*************************************************************************
    This subroutine performs linear transformation of the spline argument.

    Input parameters:
        C       -   spline interpolant
        AX, BX  -   transformation coefficients: x = A*t + B
        AY, BY  -   transformation coefficients: y = A*u + B
    Result:
        C   -   transformed spline

      -- ALGLIB PROJECT --
         Copyright 30.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dlintransxy(spline2dinterpolant<Precision>& c,
        amp::ampf<Precision> ax,
        amp::ampf<Precision> bx,
        amp::ampf<Precision> ay,
        amp::ampf<Precision> by);

### `spline2dresamplebicubic` function

    /*************************************************************************
    Bicubic spline resampling

    Input parameters:
        A           -   function values at the old grid,
                        array[0..OldHeight-1, 0..OldWidth-1]
        OldHeight   -   old grid height, OldHeight>1
        OldWidth    -   old grid width, OldWidth>1
        NewHeight   -   new grid height, NewHeight>1
        NewWidth    -   new grid width, NewWidth>1

    Output parameters:
        B           -   function values at the new grid,
                        array[0..NewHeight-1, 0..NewWidth-1]

      -- ALGLIB routine --
         15 May, 2007
         Copyright by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dresamplebicubic(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int oldheight,
        int oldwidth,
        ap::template_2d_array< amp::ampf<Precision> >& b,
        int newheight,
        int newwidth);

### `spline2dresamplebilinear` function

    /*************************************************************************
    Bilinear spline resampling

    Input parameters:
        A           -   function values at the old grid,
                        array[0..OldHeight-1, 0..OldWidth-1]
        OldHeight   -   old grid height, OldHeight>1
        OldWidth    -   old grid width, OldWidth>1
        NewHeight   -   new grid height, NewHeight>1
        NewWidth    -   new grid width, NewWidth>1

    Output parameters:
        B           -   function values at the new grid,
                        array[0..NewHeight-1, 0..NewWidth-1]

      -- ALGLIB routine --
         09.07.2007
         Copyright by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dresamplebilinear(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int oldheight,
        int oldwidth,
        ap::template_2d_array< amp::ampf<Precision> >& b,
        int newheight,
        int newwidth);

### `spline2dserialize` function

    /*************************************************************************
    Serialization of the spline interpolant

    INPUT PARAMETERS:
        B   -   spline interpolant

    OUTPUT PARAMETERS:
        RA      -   array of real numbers which contains interpolant,
                    array[0..RLen-1]
        RLen    -   RA lenght

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dserialize(const spline2dinterpolant<Precision>& c,
        ap::template_1d_array< amp::ampf<Precision> >& ra,
        int& ralen);

### `spline2dunpack` function

    /*************************************************************************
    This subroutine unpacks two-dimensional spline into the coefficients table

    Input parameters:
        C   -   spline interpolant.

    Result:
        M, N-   grid size (x-axis and y-axis)
        Tbl -   coefficients table, unpacked format,
                [0..(N-1)*(M-1)-1, 0..19].
                For I = 0...M-2, J=0..N-2:
                    K =  I*(N-1)+J
                    Tbl[K,0] = X[j]
                    Tbl[K,1] = X[j+1]
                    Tbl[K,2] = Y[i]
                    Tbl[K,3] = Y[i+1]
                    Tbl[K,4] = C00
                    Tbl[K,5] = C01
                    Tbl[K,6] = C02
                    Tbl[K,7] = C03
                    Tbl[K,8] = C10
                    Tbl[K,9] = C11
                    ...
                    Tbl[K,19] = C33
                On each grid square spline is equals to:
                    S(x) = SUM(c[i,j]*(x^i)*(y^j), i=0..3, j=0..3)
                    t = x-x[j]
                    u = y-y[i]

      -- ALGLIB PROJECT --
         Copyright 29.06.2007 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dunpack(const spline2dinterpolant<Precision>& c,
        int& m,
        int& n,
        ap::template_2d_array< amp::ampf<Precision> >& tbl);

### `spline2dunserialize` function

    /*************************************************************************
    Unserialization of the spline interpolant

    INPUT PARAMETERS:
        RA  -   array of real numbers which contains interpolant,

    OUTPUT PARAMETERS:
        B   -   spline interpolant

      -- ALGLIB --
         Copyright 17.08.2009 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void spline2dunserialize(const ap::template_1d_array< amp::ampf<Precision> >& ra,
        spline2dinterpolant<Precision>& c);

## `srcond` unit

### Functions

smatrixldltrcond
smatrixrcond

### `smatrixldltrcond` function

    /*************************************************************************
    Condition number estimate of a matrix given by LDLT-decomposition

    The algorithm calculates a lower bound of the condition number. In this
    case, the algorithm does not return a lower bound of the condition number,
    but an inverse number (to avoid an overflow in case of a singular matrix).

    It should be noted that 1-norm and inf-norm condition numbers of symmetric
    matrices are equal, so the algorithm doesn't take into account the
    differences between these types of norms.

    Input parameters:
        L       -   LDLT-decomposition of matrix A given by the upper or lower
                    triangle depending on IsUpper.
                    Output of SMatrixLDLT subroutine.
        Pivots  -   table of permutations which were made during LDLT-decomposition,
                    Output of SMatrixLDLT subroutine.
        N       -   size of matrix A.
        IsUpper -   storage format.

    Result:
        1/LowerBound(cond(A))
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> smatrixldltrcond(const ap::template_2d_array< amp::ampf<Precision> >& l,
        const ap::template_1d_array< int >& pivots,
        int n,
        bool isupper);

### `smatrixrcond` function

    /*************************************************************************
    Condition number estimate of a symmetric matrix

    The algorithm calculates a lower bound of the condition number. In this
    case, the algorithm does not return a lower bound of the condition number,
    but an inverse number (to avoid an overflow in case of a singular matrix).

    It should be noted that 1-norm and inf-norm condition numbers of symmetric
    matrices are equal, so the algorithm doesn't take into account the
    differences between these types of norms.

    Input parameters:
        A       -   symmetric definite matrix which is given by its upper or
                    lower triangle depending on IsUpper.
                    Array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   storage format.

    Result:
        1/LowerBound(cond(A))
    *************************************************************************/
    template<unsigned int Precision>
    amp::ampf<Precision> smatrixrcond(const ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper);

## `ssolve` unit

### Functions

smatrixldltsolve
smatrixsolve

### `smatrixldltsolve` function

    /*************************************************************************
    Solving  a system  of linear equations  with a system matrix  given by its
    LDLT decomposition

    The algorithm solves systems with a square matrix only.

    Input parameters:
        A       -   LDLT decomposition of the matrix (the result of the
                    SMatrixLDLT subroutine).
        Pivots  -   row permutation table (the result of the SMatrixLDLT subroutine).
        B       -   right side of a system.
                    Array whose index ranges within [0..N-1].
        N       -   size of matrix A.
        IsUpper -   points to the triangle of matrix A in which the LDLT
                    decomposition is stored.
                    If IsUpper=True, the decomposition has the form of U*D*U',
                    matrix U is stored in the upper triangle of  matrix A  (in
                    that case, the lower triangle isn't used and isn't changed
                    by the subroutine).
                    Similarly, if IsUpper=False, the decomposition has the form
                    of L*D*L' and the lower triangle stores matrix L.

    Output parameters:
        X       -   solution of a system.
                    Array whose index ranges within [0..N-1].

    Result:
        True, if the matrix is not singular. X contains the solution.
        False, if the matrix is singular (the determinant of matrix D is equal
    to 0). In this case, X doesn't contain a solution.
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixldltsolve(const ap::template_2d_array< amp::ampf<Precision> >& a,
        const ap::template_1d_array< int >& pivots,
        ap::template_1d_array< amp::ampf<Precision> > b,
        int n,
        bool isupper,
        ap::template_1d_array< amp::ampf<Precision> >& x);

### `smatrixsolve` function

    /*************************************************************************
    Solving a system of linear equations with a symmetric system matrix

    Input parameters:
        A       -   system matrix (upper or lower triangle).
                    Array whose indexes range within [0..N-1, 0..N-1].
        B       -   right side of a system.
                    Array whose index ranges within [0..N-1].
        N       -   size of matrix A.
        IsUpper -   If IsUpper = True, A contains the upper triangle,
                    otherwise A contains the lower triangle.

    Output parameters:
        X       -   solution of a system.
                    Array whose index ranges within [0..N-1].

    Result:
        True, if the matrix is not singular. X contains the solution.
        False, if the matrix is singular (the determinant of the matrix is equal
    to 0). In this case, X doesn't contain a solution.

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool smatrixsolve(ap::template_2d_array< amp::ampf<Precision> > a,
        const ap::template_1d_array< amp::ampf<Precision> >& b,
        int n,
        bool isupper,
        ap::template_1d_array< amp::ampf<Precision> >& x);

## `svd` unit

### Functions

rmatrixsvd

### `rmatrixsvd` function

    /*************************************************************************
    Singular value decomposition of a rectangular matrix.

    The algorithm calculates the singular value decomposition of a matrix of
    size MxN: A = U * S * V^T

    The algorithm finds the singular values and, optionally, matrices U and V^T.
    The algorithm can find both first min(M,N) columns of matrix U and rows of
    matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM
    and NxN respectively).

    Take into account that the subroutine does not return matrix V but V^T.

    Input parameters:
        A           -   matrix to be decomposed.
                        Array whose indexes range within [0..M-1, 0..N-1].
        M           -   number of rows in matrix A.
        N           -   number of columns in matrix A.
        UNeeded     -   0, 1 or 2. See the description of the parameter U.
        VTNeeded    -   0, 1 or 2. See the description of the parameter VT.
        AdditionalMemory -
                        If the parameter:
                         * equals 0, the algorithm doesn’t use additional
                           memory (lower requirements, lower performance).
                         * equals 1, the algorithm uses additional
                           memory of size min(M,N)*min(M,N) of real numbers.
                           It often speeds up the algorithm.
                         * equals 2, the algorithm uses additional
                           memory of size M*min(M,N) of real numbers.
                           It allows to get a maximum performance.
                        The recommended value of the parameter is 2.

    Output parameters:
        W           -   contains singular values in descending order.
        U           -   if UNeeded=0, U isn't changed, the left singular vectors
                        are not calculated.
                        if Uneeded=1, U contains left singular vectors (first
                        min(M,N) columns of matrix U). Array whose indexes range
                        within [0..M-1, 0..Min(M,N)-1].
                        if UNeeded=2, U contains matrix U wholly. Array whose
                        indexes range within [0..M-1, 0..M-1].
        VT          -   if VTNeeded=0, VT isn’t changed, the right singular vectors
                        are not calculated.
                        if VTNeeded=1, VT contains right singular vectors (first
                        min(M,N) rows of matrix V^T). Array whose indexes range
                        within [0..min(M,N)-1, 0..N-1].
                        if VTNeeded=2, VT contains matrix V^T wholly. Array whose
                        indexes range within [0..N-1, 0..N-1].

      -- ALGLIB --
         Copyright 2005 by Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool rmatrixsvd(ap::template_2d_array< amp::ampf<Precision> > a,
        int m,
        int n,
        int uneeded,
        int vtneeded,
        int additionalmemory,
        ap::template_1d_array< amp::ampf<Precision> >& w,
        ap::template_2d_array< amp::ampf<Precision> >& u,
        ap::template_2d_array< amp::ampf<Precision> >& vt);

## `trfac` unit

### Functions

cmatrixlu
hpdmatrixcholesky
rmatrixlu
spdmatrixcholesky

### `cmatrixlu` function

    /*************************************************************************
    LU decomposition of a general complex matrix with row pivoting

    A is represented as A = P*L*U, where:
    * L is lower unitriangular matrix
    * U is upper triangular matrix
    * P = P0*P1*...*PK, K=min(M,N)-1,
      Pi - permutation matrix for I and Pivots[I]

    This is cache-oblivous implementation of LU decomposition. It is optimized
    for square matrices. As for rectangular matrices:
    * best case - M>>N
    * worst case - N>>M, small M, large N, matrix does not fit in CPU cache

    INPUT PARAMETERS:
        A       -   array[0..M-1, 0..N-1].
        M       -   number of rows in matrix A.
        N       -   number of columns in matrix A.

    OUTPUT PARAMETERS:
        A       -   matrices L and U in compact form:
                    * L is stored under main diagonal
                    * U is stored on and above main diagonal
        Pivots  -   permutation matrix in compact form.
                    array[0..Min(M-1,N-1)].

      -- ALGLIB routine --
         10.01.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void cmatrixlu(ap::template_2d_array< amp::campf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< int >& pivots);

### `hpdmatrixcholesky` function

    /*************************************************************************
    Cache-oblivious Cholesky decomposition

    The algorithm computes Cholesky decomposition  of  a  Hermitian  positive-
    definite matrix. The result of an algorithm is a representation  of  A  as
    A=U'*U  or A=L*L' (here X' detones conj(X^T)).

    INPUT PARAMETERS:
        A       -   upper or lower triangle of a factorized matrix.
                    array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   if IsUpper=True, then A contains an upper triangle of
                    a symmetric matrix, otherwise A contains a lower one.

    OUTPUT PARAMETERS:
        A       -   the result of factorization. If IsUpper=True, then
                    the upper triangle contains matrix U, so that A = U'*U,
                    and the elements below the main diagonal are not modified.
                    Similarly, if IsUpper = False.

    RESULT:
        If  the  matrix  is  positive-definite,  the  function  returns  True.
        Otherwise, the function returns False. Contents of A is not determined
        in such case.

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool hpdmatrixcholesky(ap::template_2d_array< amp::campf<Precision> >& a,
        int n,
        bool isupper);

### `rmatrixlu` function

    /*************************************************************************
    LU decomposition of a general real matrix with row pivoting

    A is represented as A = P*L*U, where:
    * L is lower unitriangular matrix
    * U is upper triangular matrix
    * P = P0*P1*...*PK, K=min(M,N)-1,
      Pi - permutation matrix for I and Pivots[I]

    This is cache-oblivous implementation of LU decomposition.
    It is optimized for square matrices. As for rectangular matrices:
    * best case - M>>N
    * worst case - N>>M, small M, large N, matrix does not fit in CPU cache

    INPUT PARAMETERS:
        A       -   array[0..M-1, 0..N-1].
        M       -   number of rows in matrix A.
        N       -   number of columns in matrix A.

    OUTPUT PARAMETERS:
        A       -   matrices L and U in compact form:
                    * L is stored under main diagonal
                    * U is stored on and above main diagonal
        Pivots  -   permutation matrix in compact form.
                    array[0..Min(M-1,N-1)].

      -- ALGLIB routine --
         10.01.2010
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    void rmatrixlu(ap::template_2d_array< amp::ampf<Precision> >& a,
        int m,
        int n,
        ap::template_1d_array< int >& pivots);

### `spdmatrixcholesky` function

    /*************************************************************************
    Cache-oblivious Cholesky decomposition

    The algorithm computes Cholesky decomposition  of  a  symmetric  positive-
    definite matrix. The result of an algorithm is a representation  of  A  as
    A=U^T*U  or A=L*L^T

    INPUT PARAMETERS:
        A       -   upper or lower triangle of a factorized matrix.
                    array with elements [0..N-1, 0..N-1].
        N       -   size of matrix A.
        IsUpper -   if IsUpper=True, then A contains an upper triangle of
                    a symmetric matrix, otherwise A contains a lower one.

    OUTPUT PARAMETERS:
        A       -   the result of factorization. If IsUpper=True, then
                    the upper triangle contains matrix U, so that A = U^T*U,
                    and the elements below the main diagonal are not modified.
                    Similarly, if IsUpper = False.

    RESULT:
        If  the  matrix  is  positive-definite,  the  function  returns  True.
        Otherwise, the function returns False. Contents of A is not determined
        in such case.

      -- ALGLIB routine --
         15.12.2009
         Bochkanov Sergey
    *************************************************************************/
    template<unsigned int Precision>
    bool spdmatrixcholesky(ap::template_2d_array< amp::ampf<Precision> >& a,
        int n,
        bool isupper);