//
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2013 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#if NATIVE
using System;
using System.Security;
using IStation.Numerics.LinearAlgebra.Factorization;
using IStation.Numerics.Providers.Common.Mkl;
using Complex = System.Numerics.Complex;
namespace IStation.Numerics.Providers.LinearAlgebra.Mkl
{
///
/// Intel's Math Kernel Library (MKL) linear algebra provider.
///
internal partial class MklLinearAlgebraProvider
{
///
/// Computes the requested of the matrix.
///
/// The type of norm to compute.
/// The number of rows in the matrix.
/// The number of columns in the matrix.
/// The matrix to compute the norm from.
///
/// The requested of the matrix.
///
[SecuritySafeCritical]
public override double MatrixNorm(Norm norm, int rows, int columns, Complex32[] matrix)
{
if (matrix == null)
{
throw new ArgumentNullException(nameof(matrix));
}
if (rows <= 0)
{
throw new ArgumentException("Value must be positive.", nameof(rows));
}
if (columns <= 0)
{
throw new ArgumentException("Value must be positive.", nameof(columns));
}
if (matrix.Length < rows * columns)
{
throw new ArgumentException($"The given array is too small. It must be at least {rows * columns} long.", nameof(matrix));
}
return SafeNativeMethods.c_matrix_norm((byte)norm, rows, columns, matrix);
}
///
/// Computes the dot product of x and y.
///
/// The vector x.
/// The vector y.
/// The dot product of x and y.
/// This is equivalent to the DOT BLAS routine.
[SecuritySafeCritical]
public override Complex32 DotProduct(Complex32[] x, Complex32[] y)
{
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (x.Length != y.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
return SafeNativeMethods.c_dot_product(x.Length, x, y);
}
///
/// Adds a scaled vector to another: result = y + alpha*x.
///
/// The vector to update.
/// The value to scale by.
/// The vector to add to .
/// The result of the addition.
/// This is similar to the AXPY BLAS routine.
[SecuritySafeCritical]
public override void AddVectorToScaledVector(Complex32[] y, Complex32 alpha, Complex32[] x, Complex32[] result)
{
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (y.Length != x.Length)
{
throw new ArgumentException("All vectors must have the same dimensionality.");
}
if (!ReferenceEquals(y, result))
{
Array.Copy(y, 0, result, 0, y.Length);
}
if (alpha == Complex32.Zero)
{
return;
}
SafeNativeMethods.c_axpy(y.Length, alpha, x, result);
}
///
/// Scales an array. Can be used to scale a vector and a matrix.
///
/// The scalar.
/// The values to scale.
/// This result of the scaling.
/// This is similar to the SCAL BLAS routine.
[SecuritySafeCritical]
public override void ScaleArray(Complex32 alpha, Complex32[] x, Complex32[] result)
{
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (!ReferenceEquals(x, result))
{
Array.Copy(x, 0, result, 0, x.Length);
}
if (alpha == Complex32.One)
{
return;
}
SafeNativeMethods.c_scale(x.Length, alpha, result);
}
///
/// Multiples two matrices. result = x * y
///
/// The x matrix.
/// The number of rows in the x matrix.
/// The number of columns in the x matrix.
/// The y matrix.
/// The number of rows in the y matrix.
/// The number of columns in the y matrix.
/// Where to store the result of the multiplication.
/// This is a simplified version of the BLAS GEMM routine with alpha
/// set to Complex32.One and beta set to Complex32.Zero, and x and y are not transposed.
public override void MatrixMultiply(Complex32[] x, int rowsX, int columnsX, Complex32[] y, int rowsY, int columnsY, Complex32[] result)
{
MatrixMultiplyWithUpdate(Transpose.DontTranspose, Transpose.DontTranspose, Complex32.One, x, rowsX, columnsX, y, rowsY, columnsY, Complex32.Zero, result);
}
///
/// Multiplies two matrices and updates another with the result. c = alpha*op(a)*op(b) + beta*c
///
/// How to transpose the matrix.
/// How to transpose the matrix.
/// The value to scale matrix.
/// The a matrix.
/// The number of rows in the matrix.
/// The number of columns in the matrix.
/// The b matrix
/// The number of rows in the matrix.
/// The number of columns in the matrix.
/// The value to scale the matrix.
/// The c matrix.
[SecuritySafeCritical]
public override void MatrixMultiplyWithUpdate(Transpose transposeA, Transpose transposeB, Complex32 alpha, Complex32[] a, int rowsA, int columnsA, Complex32[] b, int rowsB, int columnsB, Complex32 beta, Complex32[] c)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (b == null)
{
throw new ArgumentNullException(nameof(b));
}
if (c == null)
{
throw new ArgumentNullException(nameof(c));
}
var m = transposeA == Transpose.DontTranspose ? rowsA : columnsA;
var n = transposeB == Transpose.DontTranspose ? columnsB : rowsB;
var k = transposeA == Transpose.DontTranspose ? columnsA : rowsA;
var l = transposeB == Transpose.DontTranspose ? rowsB : columnsB;
if (c.Length != m*n)
{
throw new ArgumentException("Matrix dimensions must agree.");
}
if (k != l)
{
throw new ArgumentException("Matrix dimensions must agree.");
}
SafeNativeMethods.c_matrix_multiply(transposeA, transposeB, m, n, k, alpha, a, b, beta, c);
}
///
/// Computes the LUP factorization of A. P*A = L*U.
///
/// An by matrix. The matrix is overwritten with the
/// the LU factorization on exit. The lower triangular factor L is stored in under the diagonal of (the diagonal is always Complex32.One
/// for the L factor). The upper triangular factor U is stored on and above the diagonal of .
/// The order of the square matrix .
/// On exit, it contains the pivot indices. The size of the array must be .
/// This is equivalent to the GETRF LAPACK routine.
[SecuritySafeCritical]
public override void LUFactor(Complex32[] data, int order, int[] ipiv)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (ipiv == null)
{
throw new ArgumentNullException(nameof(ipiv));
}
if (data.Length != order*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(data));
}
if (ipiv.Length != order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(ipiv));
}
var info = SafeNativeMethods.c_lu_factor(order, data, ipiv);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Computes the inverse of matrix using LU factorization.
///
/// The N by N matrix to invert. Contains the inverse On exit.
/// The order of the square matrix .
/// This is equivalent to the GETRF and GETRI LAPACK routines.
[SecuritySafeCritical]
public override void LUInverse(Complex32[] a, int order)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (a.Length != order*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(a));
}
var info = SafeNativeMethods.c_lu_inverse(order, a);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
if (info > 0)
{
throw new SingularUMatrixException(info);
}
}
///
/// Computes the inverse of a previously factored matrix.
///
/// The LU factored N by N matrix. Contains the inverse On exit.
/// The order of the square matrix .
/// The pivot indices of .
/// This is equivalent to the GETRI LAPACK routine.
[SecuritySafeCritical]
public override void LUInverseFactored(Complex32[] a, int order, int[] ipiv)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (ipiv == null)
{
throw new ArgumentNullException(nameof(ipiv));
}
if (a.Length != order*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(a));
}
if (ipiv.Length != order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(ipiv));
}
var info = SafeNativeMethods.c_lu_inverse_factored(order, a, ipiv);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
if (info > 0)
{
throw new SingularUMatrixException(info);
}
}
///
/// Solves A*X=B for X using LU factorization.
///
/// The number of columns of B.
/// The square matrix A.
/// The order of the square matrix .
/// On entry the B matrix; on exit the X matrix.
/// This is equivalent to the GETRF and GETRS LAPACK routines.
[SecuritySafeCritical]
public override void LUSolve(int columnsOfB, Complex32[] a, int order, Complex32[] b)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (a.Length != order*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(a));
}
if (b.Length != columnsOfB*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
if (ReferenceEquals(a, b))
{
throw new ArgumentException("Arguments must be different objects.");
}
var info = SafeNativeMethods.c_lu_solve(order, columnsOfB, a, b);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Solves A*X=B for X using a previously factored A matrix.
///
/// The number of columns of B.
/// The factored A matrix.
/// The order of the square matrix .
/// The pivot indices of .
/// On entry the B matrix; on exit the X matrix.
/// This is equivalent to the GETRS LAPACK routine.
[SecuritySafeCritical]
public override void LUSolveFactored(int columnsOfB, Complex32[] a, int order, int[] ipiv, Complex32[] b)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (ipiv == null)
{
throw new ArgumentNullException(nameof(ipiv));
}
if (a.Length != order*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(a));
}
if (ipiv.Length != order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(ipiv));
}
if (b.Length != columnsOfB*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
if (ReferenceEquals(a, b))
{
throw new ArgumentException("Arguments must be different objects.");
}
var info = SafeNativeMethods.c_lu_solve_factored(order, columnsOfB, a, ipiv, b);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Computes the Cholesky factorization of A.
///
/// On entry, a square, positive definite matrix. On exit, the matrix is overwritten with the
/// the Cholesky factorization.
/// The number of rows or columns in the matrix.
/// This is equivalent to the POTRF LAPACK routine.
[SecuritySafeCritical]
public override void CholeskyFactor(Complex32[] a, int order)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (order < 1)
{
throw new ArgumentException("Value must be positive.", nameof(order));
}
if (a.Length != order*order)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(a));
}
var info = SafeNativeMethods.c_cholesky_factor(order, a);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
if (info > 0)
{
throw new ArgumentException("Matrix must be positive definite.");
}
}
///
/// Solves A*X=B for X using Cholesky factorization.
///
/// The square, positive definite matrix A.
/// The number of rows and columns in A.
/// On entry the B matrix; on exit the X matrix.
/// The number of columns in the B matrix.
/// This is equivalent to the POTRF add POTRS LAPACK routines.
///
[SecuritySafeCritical]
public override void CholeskySolve(Complex32[] a, int orderA, Complex32[] b, int columnsB)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (b == null)
{
throw new ArgumentNullException(nameof(b));
}
if (b.Length != orderA*columnsB)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
if (ReferenceEquals(a, b))
{
throw new ArgumentException("Arguments must be different objects.");
}
var info = SafeNativeMethods.c_cholesky_solve(orderA, columnsB, a, b);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Solves A*X=B for X using a previously factored A matrix.
///
/// The square, positive definite matrix A.
/// The number of rows and columns in A.
/// On entry the B matrix; on exit the X matrix.
/// The number of columns in the B matrix.
/// This is equivalent to the POTRS LAPACK routine.
[SecuritySafeCritical]
public override void CholeskySolveFactored(Complex32[] a, int orderA, Complex32[] b, int columnsB)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (b == null)
{
throw new ArgumentNullException(nameof(b));
}
if (b.Length != orderA*columnsB)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
if (ReferenceEquals(a, b))
{
throw new ArgumentException("Arguments must be different objects.");
}
var info = SafeNativeMethods.c_cholesky_solve_factored(orderA, columnsB, a, b);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Computes the QR factorization of A.
///
/// On entry, it is the M by N A matrix to factor. On exit,
/// it is overwritten with the R matrix of the QR factorization.
/// The number of rows in the A matrix.
/// The number of columns in the A matrix.
/// On exit, A M by M matrix that holds the Q matrix of the
/// QR factorization.
/// A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.
/// This is similar to the GEQRF and ORGQR LAPACK routines.
[SecuritySafeCritical]
public override void QRFactor(Complex32[] r, int rowsR, int columnsR, Complex32[] q, Complex32[] tau)
{
if (r == null)
{
throw new ArgumentNullException(nameof(r));
}
if (q == null)
{
throw new ArgumentNullException(nameof(q));
}
if (r.Length != rowsR*columnsR)
{
throw new ArgumentException("The given array has the wrong length. Should be rowsR * columnsR.", nameof(r));
}
if (tau.Length < Math.Min(rowsR, columnsR))
{
throw new ArgumentException("The given array is too small. It must be at least min(m,n) long.", nameof(tau));
}
if (q.Length != rowsR*rowsR)
{
throw new ArgumentException("The given array has the wrong length. Should be rowsR * rowsR.", nameof(q));
}
var info = SafeNativeMethods.c_qr_factor(rowsR, columnsR, r, tau, q);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Computes the thin QR factorization of A where M > N.
///
/// On entry, it is the M by N A matrix to factor. On exit,
/// it is overwritten with the Q matrix of the QR factorization.
/// The number of rows in the A matrix.
/// The number of columns in the A matrix.
/// On exit, A N by N matrix that holds the R matrix of the
/// QR factorization.
/// A min(m,n) vector. On exit, contains additional information
/// to be used by the QR solve routine.
/// This is similar to the GEQRF and ORGQR LAPACK routines.
[SecuritySafeCritical]
public override void ThinQRFactor(Complex32[] q, int rowsA, int columnsA, Complex32[] r, Complex32[] tau)
{
if (r == null)
{
throw new ArgumentNullException(nameof(r));
}
if (q == null)
{
throw new ArgumentNullException(nameof(q));
}
if (q.Length != rowsA * columnsA)
{
throw new ArgumentException("The given array has the wrong length. Should be rowsR * columnsR.", nameof(q));
}
if (tau.Length < Math.Min(rowsA, columnsA))
{
throw new ArgumentException("The given array is too small. It must be at least min(m,n) long.", nameof(tau));
}
if (r.Length != columnsA * columnsA)
{
throw new ArgumentException("The given array has the wrong length. Should be columnsA * columnsA.", nameof(r));
}
var info = SafeNativeMethods.c_qr_thin_factor(rowsA, columnsA, q, tau, r);
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
///
/// Solves A*X=B for X using QR factorization of A.
///
/// The A matrix.
/// The number of rows in the A matrix.
/// The number of columns in the A matrix.
/// The B matrix.
/// The number of columns of B.
/// On exit, the solution matrix.
/// The type of QR factorization to perform.
/// Rows must be greater or equal to columns.
[SecuritySafeCritical]
public override void QRSolve(Complex32[] a, int rows, int columns, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (b == null)
{
throw new ArgumentNullException(nameof(b));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (a.Length != rows * columns)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(a));
}
if (b.Length != rows * columnsB)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
if (x.Length != columns * columnsB)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(x));
}
if (rows < columns)
{
throw new ArgumentException("The number of rows must greater than or equal to the number of columns.");
}
var info = SafeNativeMethods.c_qr_solve(rows, columns, columnsB, a, b, x);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
if (info > 0)
{
throw new ArgumentException("Matrix must not be rank deficient.", nameof(a));
}
}
///
/// Solves A*X=B for X using a previously QR factored matrix.
///
/// The Q matrix obtained by calling .
/// The R matrix obtained by calling .
/// The number of rows in the A matrix.
/// The number of columns in the A matrix.
/// Contains additional information on Q. Only used for the native solver
/// and can be null for the managed provider.
/// The B matrix.
/// The number of columns of B.
/// On exit, the solution matrix.
/// The type of QR factorization to perform.
/// Rows must be greater or equal to columns.
[SecuritySafeCritical]
public override void QRSolveFactored(Complex32[] q, Complex32[] r, int rowsA, int columnsA, Complex32[] tau, Complex32[] b, int columnsB, Complex32[] x, QRMethod method = QRMethod.Full)
{
if (r == null)
{
throw new ArgumentNullException(nameof(r));
}
if (q == null)
{
throw new ArgumentNullException(nameof(q));
}
if (b == null)
{
throw new ArgumentNullException(nameof(q));
}
if (x == null)
{
throw new ArgumentNullException(nameof(q));
}
int rowsQ, columnsQ, rowsR, columnsR;
if (method == QRMethod.Full)
{
rowsQ = columnsQ = rowsR = rowsA;
columnsR = columnsA;
}
else
{
rowsQ = rowsA;
columnsQ = rowsR = columnsR = columnsA;
}
if (r.Length != rowsR * columnsR)
{
throw new ArgumentException($"The given array has the wrong length. Should be {rowsR * columnsR}.", nameof(r));
}
if (q.Length != rowsQ * columnsQ)
{
throw new ArgumentException($"The given array has the wrong length. Should be {rowsQ * columnsQ}.", nameof(q));
}
if (b.Length != rowsA * columnsB)
{
throw new ArgumentException($"The given array has the wrong length. Should be {rowsA * columnsB}.", nameof(b));
}
if (x.Length != columnsA * columnsB)
{
throw new ArgumentException($"The given array has the wrong length. Should be {columnsA * columnsB}.", nameof(x));
}
if (method == QRMethod.Full)
{
var info = SafeNativeMethods.c_qr_solve_factored(rowsA, columnsA, columnsB, r, b, tau, x);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
}
else
{
// we don't have access to the raw Q matrix any more(it is stored in R in the full QR), need to think about this.
// let just call the managed version in the meantime. The heavy lifting has already been done. -marcus
base.QRSolveFactored(q, r, rowsA, columnsA, tau, b, columnsB, x, QRMethod.Thin);
}
}
///
/// Solves A*X=B for X using the singular value decomposition of A.
///
/// On entry, the M by N matrix to decompose.
/// The number of rows in the A matrix.
/// The number of columns in the A matrix.
/// The B matrix.
/// The number of columns of B.
/// On exit, the solution matrix.
public override void SvdSolve(Complex32[] a, int rowsA, int columnsA, Complex32[] b, int columnsB, Complex32[] x)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (b == null)
{
throw new ArgumentNullException(nameof(b));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (b.Length != rowsA*columnsB)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
if (x.Length != columnsA*columnsB)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(b));
}
var s = new Complex32[Math.Min(rowsA, columnsA)];
var u = new Complex32[rowsA*rowsA];
var vt = new Complex32[columnsA*columnsA];
var clone = new Complex32[a.Length];
a.Copy(clone);
SingularValueDecomposition(true, clone, rowsA, columnsA, s, u, vt);
SvdSolveFactored(rowsA, columnsA, s, u, vt, b, columnsB, x);
}
///
/// Computes the singular value decomposition of A.
///
/// Compute the singular U and VT vectors or not.
/// On entry, the M by N matrix to decompose. On exit, A may be overwritten.
/// The number of rows in the A matrix.
/// The number of columns in the A matrix.
/// The singular values of A in ascending value.
/// If is true, on exit U contains the left
/// singular vectors.
/// If is true, on exit VT contains the transposed
/// right singular vectors.
/// This is equivalent to the GESVD LAPACK routine.
[SecuritySafeCritical]
public override void SingularValueDecomposition(bool computeVectors, Complex32[] a, int rowsA, int columnsA, Complex32[] s, Complex32[] u, Complex32[] vt)
{
if (a == null)
{
throw new ArgumentNullException(nameof(a));
}
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
if (u == null)
{
throw new ArgumentNullException(nameof(u));
}
if (vt == null)
{
throw new ArgumentNullException(nameof(vt));
}
if (u.Length != rowsA * rowsA)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(u));
}
if (vt.Length != columnsA * columnsA)
{
throw new ArgumentException("The array arguments must have the same length.", nameof(vt));
}
if (s.Length != Math.Min(rowsA, columnsA))
{
throw new ArgumentException("The array arguments must have the same length.", nameof(s));
}
var info = SafeNativeMethods.c_svd_factor(computeVectors, rowsA, columnsA, a, s, u, vt);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
if (info > 0)
{
throw new NonConvergenceException();
}
}
///
/// Does a point wise add of two arrays z = x + y. This can be used
/// to add vectors or matrices.
///
/// The array x.
/// The array y.
/// The result of the addition.
/// There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.
public override void AddArrays(Complex32[] x, Complex32[] y, Complex32[] result)
{
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (x.Length != y.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
if (x.Length != result.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
SafeNativeMethods.c_vector_add(x.Length, x, y, result);
}
///
/// Does a point wise subtraction of two arrays z = x - y. This can be used
/// to subtract vectors or matrices.
///
/// The array x.
/// The array y.
/// The result of the subtraction.
/// There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.
public override void SubtractArrays(Complex32[] x, Complex32[] y, Complex32[] result)
{
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (x.Length != y.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
if (x.Length != result.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
SafeNativeMethods.c_vector_subtract(x.Length, x, y, result);
}
///
/// Does a point wise multiplication of two arrays z = x * y. This can be used
/// to multiple elements of vectors or matrices.
///
/// The array x.
/// The array y.
/// The result of the point wise multiplication.
/// There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.
public override void PointWiseMultiplyArrays(Complex32[] x, Complex32[] y, Complex32[] result)
{
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (x.Length != y.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
if (x.Length != result.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
SafeNativeMethods.c_vector_multiply(x.Length, x, y, result);
}
///
/// Does a point wise division of two arrays z = x / y. This can be used
/// to divide elements of vectors or matrices.
///
/// The array x.
/// The array y.
/// The result of the point wise division.
/// There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.
public override void PointWiseDivideArrays(Complex32[] x, Complex32[] y, Complex32[] result)
{
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (x.Length != y.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
if (x.Length != result.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
SafeNativeMethods.c_vector_divide(x.Length, x, y, result);
}
///
/// Does a point wise power of two arrays z = x ^ y. This can be used
/// to raise elements of vectors or matrices to the powers of another vector or matrix.
///
/// The array x.
/// The array y.
/// The result of the point wise power.
/// There is no equivalent BLAS routine, but many libraries
/// provide optimized (parallel and/or vectorized) versions of this
/// routine.
public override void PointWisePowerArrays(Complex32[] x, Complex32[] y, Complex32[] result)
{
if (_vectorFunctionsMajor != 0 || _vectorFunctionsMinor < 1)
{
base.PointWisePowerArrays(x, y, result);
}
if (y == null)
{
throw new ArgumentNullException(nameof(y));
}
if (x == null)
{
throw new ArgumentNullException(nameof(x));
}
if (x.Length != y.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
if (x.Length != result.Length)
{
throw new ArgumentException("The array arguments must have the same length.");
}
SafeNativeMethods.c_vector_power(x.Length, x, y, result);
}
///
/// Computes the eigenvalues and eigenvectors of a matrix.
///
/// Whether the matrix is symmetric or not.
/// The order of the matrix.
/// The matrix to decompose. The length of the array must be order * order.
/// On output, the matrix contains the eigen vectors. The length of the array must be order * order.
/// On output, the eigen values (λ) of matrix in ascending value. The length of the array must .
/// On output, the block diagonal eigenvalue matrix. The length of the array must be order * order.
public override void EigenDecomp(bool isSymmetric, int order, Complex32[] matrix, Complex32[] matrixEv, Complex[] vectorEv, Complex32[] matrixD)
{
if (matrix == null)
{
throw new ArgumentNullException(nameof(matrix));
}
if (matrix.Length != order * order)
{
throw new ArgumentException($"The given array has the wrong length. Should be {order * order}.", nameof(matrix));
}
if (matrixEv == null)
{
throw new ArgumentNullException(nameof(matrixEv));
}
if (matrixEv.Length != order * order)
{
throw new ArgumentException($"The given array has the wrong length. Should be {order * order}.", nameof(matrixEv));
}
if (vectorEv == null)
{
throw new ArgumentNullException(nameof(vectorEv));
}
if (vectorEv.Length != order)
{
throw new ArgumentException($"The given array has the wrong length. Should be {order}.", nameof(vectorEv));
}
if (matrixD == null)
{
throw new ArgumentNullException(nameof(matrixD));
}
if (matrixD.Length != order * order)
{
throw new ArgumentException($"The given array has the wrong length. Should be {order * order}.", nameof(matrixD));
}
var info = SafeNativeMethods.c_eigen(isSymmetric, order, matrix, matrixEv, vectorEv, matrixD);
if (info == (int)MklError.MemoryAllocation)
{
throw new MemoryAllocationException();
}
if (info < 0)
{
throw new InvalidParameterException(Math.Abs(info));
}
if (info > 0)
{
throw new NonConvergenceException();
}
}
}
}
#endif