// // 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