private static void SolveTriangleMatrixRL <T>(bool isUnit, T alpha, INdArray <T> a, MutableNdArray <T> b) { var(m, n) = (b.Shape[0], b.Shape[1]); /* reference Fortran * DO 260, J = N, 1, -1 * IF( ALPHA.NE.ONE )THEN * DO 220, I = 1, M * B( I, J ) = ALPHA*B( I, J ) * 220 CONTINUE * END IF * DO 240, K = J + 1, N * IF( A( K, J ).NE.ZERO )THEN * DO 230, I = 1, M * B( I, J ) = B( I, J ) - A( K, J )*B( I, K ) * 230 CONTINUE * END IF * 240 CONTINUE * IF( NOUNIT )THEN * TEMP = ONE/A( J, J ) * DO 250, I = 1, M * B( I, J ) = TEMP*B( I, J ) * 250 CONTINUE * END IF * 260 CONTINUE */ for (var j = n - 1; j >= 0; --j) { if (ValueTrait.Equals(alpha, One <T>())) { for (var i = 0; i < m; ++i) { b[i, j] = Multiply(alpha, b[i, j]); } } for (var k = j + 1; k < n; ++k) { if (!ValueTrait.Equals(a[k, j], Zero <T>())) { for (var i = 0; i < m; ++i) { b[i, j] = Subtract(b[i, j], Multiply(a[k, j], b[i, k])); } } } if (!isUnit) { var temp = Divide(One <T>(), a[j, j]); for (var i = 0; i < m; ++i) { b[i, j] = Multiply(temp, b[i, j]); } } } }
private static void SolveTriangleMatrixRU <T>(bool isUnit, T alpha, INdArray <T> a, MutableNdArray <T> b) { var(m, n) = (b.Shape[0], b.Shape[1]); /* reference Fortran * DO 210, J = 1, N * IF( ALPHA.NE.ONE )THEN * DO 170, I = 1, M * B( I, J ) = ALPHA*B( I, J ) * 170 CONTINUE * END IF * DO 190, K = 1, J - 1 * IF( A( K, J ).NE.ZERO )THEN * DO 180, I = 1, M * B( I, J ) = B( I, J ) - A( K, J )*B( I, K ) * 180 CONTINUE * END IF * 190 CONTINUE * IF( NOUNIT )THEN * TEMP = ONE/A( J, J ) * DO 200, I = 1, M * B( I, J ) = TEMP*B( I, J ) * 200 CONTINUE * END IF * 210 CONTINUE */ for (var j = 0; j < n; ++j) { if (ValueTrait.Equals(alpha, One <T>())) { for (var i = 0; i < m; ++i) { b[i, j] = Multiply(alpha, b[i, j]); } } for (var k = 0; k < j - 1; ++k) { if (!ValueTrait.Equals(a[k, j], Zero <T>())) { for (var i = 0; i < m; ++i) { b[i, j] = Subtract(b[i, j], Multiply(a[k, j], b[i, k])); } } } if (!isUnit) { var temp = Divide(One <T>(), a[j, j]); for (var i = 0; i < m; ++i) { b[i, j] = Multiply(temp, b[i, j]); } } } }
/// <summary> /// Gets the identity matrix which has the specified dimension. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="n"></param> /// <returns></returns> public static NdArray <T> Identity <T>(int n) { var array = NdArray.CreateMutable(new T[n, n]); for (var i = 0; i < n; ++i) { array[i, i] = ValueTrait.One <T>(); } return(array.MoveToImmutable()); }
/// <summary> /// Computes sum from all elements of the <paramref name="ndArray"/>. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ndArray"></param> /// <returns></returns> public static T Sum <T>(this INdArray <T> ndArray) { var value = ValueTrait.Zero <T>(); var len = ndArray.Shape.TotalLength; for (var i = 0; i < len; ++i) { value = ValueTrait.Add(value, ndArray.GetItem(i)); } return(value); }
/// <summary> /// Computes unbiased variance from all elements of the <paramref name="ndArray"/>. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ndArray"></param> /// <returns></returns> public static T UnbiasedVar <T>(this INdArray <T> ndArray) { var value = ValueTrait.Zero <T>(); var mean = ndArray.Mean(); var len = ndArray.Shape.TotalLength; for (var i = 0; i < len; ++i) { var temp = ValueTrait.Subtract(ndArray.GetItem(i), mean); value = ValueTrait.Multiply(temp, temp); } return(ValueTrait.Divide(value, ValueTrait.FromLong <T>(len - 1))); }
public static Vector <T> GetVector <T>() where T : unmanaged { Span <T> span = stackalloc T[Vector <T> .Count]; var x = ValueTrait.UnaryNegate(ValueTrait.One <T>()); for (var i = 0; i < Vector <T> .Count; ++i) { span[i] = x; x = ValueTrait.Increment(x); } return(new Vector <T>(span)); }
/// <summary> /// [Pure] Returns the 2-D norm of all elements of <paramref name="ndArray"/>. /// </summary> /// <param name="ndArray"></param> /// <returns></returns> public static T Norm2 <T>(this INdArray <T> ndArray) { var len = ndArray.Shape.TotalLength; Guard.AssertOperation(len > 0, "ndArray has no elements."); var norm = ValueTrait.Zero <T>(); for (var i = 0; i < len; ++i) { var element = ndArray.GetItem(i); norm = ValueTrait.Add(norm, ValueTrait.Multiply(element, element)); } return(NdMath.Sqrt(norm)); }
private static void SolveTriangleMatrixLU <T>(bool isUnit, T alpha, INdArray <T> a, MutableNdArray <T> b) { var(m, n) = (b.Shape[0], b.Shape[1]); /* reference Fortran * DO 60, J = 1, N * IF( ALPHA.NE.ONE )THEN * DO 30, I = 1, M * B( I, J ) = ALPHA*B( I, J ) * 30 CONTINUE * END IF * DO 50, K = M, 1, -1 * IF( B( K, J ).NE.ZERO )THEN * IF( NOUNIT ) * $ B( K, J ) = B( K, J )/A( K, K ) * DO 40, I = 1, K - 1 * B( I, J ) = B( I, J ) - B( K, J )*A( I, K ) * 40 CONTINUE * END IF * 50 CONTINUE * 60 CONTINUE */ for (var j = 0; j < n; ++j) { if (!ValueTrait.Equals(alpha, One <T>())) { for (var i = 0; i < m; ++i) { b[i, j] = Multiply(alpha, b[i, j]); } } for (var k = m - 1; k >= 0; --k) { if (!ValueTrait.Equals(b[k, j], Zero <T>())) { if (!isUnit) { b[k, j] = Divide(b[k, j], a[k, k]); } for (var i = 0; i < k - 1; ++i) { b[i, j] = Subtract(b[i, j], Multiply(b[k, j], a[i, k])); } } } } }
private static void SolveTriangleMatrixLL <T>(bool isUnit, T alpha, INdArray <T> a, MutableNdArray <T> b) { var(m, n) = (b.Shape[0], b.Shape[1]); /* reference Fortran * DO 100, J = 1, N * IF( ALPHA.NE.ONE )THEN * DO 70, I = 1, M * B( I, J ) = ALPHA*B( I, J ) * 70 CONTINUE * END IF * DO 90 K = 1, M * IF( B( K, J ).NE.ZERO )THEN * IF( NOUNIT ) * $ B( K, J ) = B( K, J )/A( K, K ) * DO 80, I = K + 1, M * B( I, J ) = B( I, J ) - B( K, J )*A( I, K ) * 80 CONTINUE * END IF * 90 CONTINUE * 100 CONTINUE */ for (var j = 0; j < n; ++j) { if (!ValueTrait.Equals(alpha, One <T>())) { for (var i = 0; i < m; ++i) { b[i, j] = Multiply(alpha, b[i, j]); } } for (var k = 0; k < m; ++k) { if (!ValueTrait.Equals(b[k, j], Zero <T>())) { if (!isUnit) { b[k, j] = Divide(b[k, j], b[k, k]); } for (var i = k; i < m; ++i) { b[i, j] = Subtract(b[i, j], Divide(b[k, j], a[i, k])); } } } } }
/// <summary> /// Returns the largest value of the <paramref name="ndArray"/>. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ndArray"></param> /// <returns></returns> public static T Max <T>(this INdArray <T> ndArray) { var len = ndArray.Shape.TotalLength; Guard.AssertOperation(len > 0, "ndArray has no elements."); var max = ndArray.GetItem(0); for (var i = 1; i < len; ++i) { var current = ndArray.GetItem(i); if (ValueTrait.GreaterThan(current, max)) { max = current; } } return(max); }
/// <summary> /// Returns the index of the smallest value of the <paramref name="ndArray"/>. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ndArray"></param> /// <returns></returns> public static IndexArray ArgMin <T>(this INdArray <T> ndArray) { var len = ndArray.Shape.TotalLength; Guard.AssertOperation(len > 0, "ndArray has no elements."); var argmin = 0; var min = ndArray.GetItem(0); for (var i = 1; i < len; ++i) { var current = ndArray.GetItem(i); if (ValueTrait.LessThan(current, min)) { argmin = i; min = current; } } return(ndArray.ToShapedIndices(argmin)); }
// reference: // https://github.com/xianyi/OpenBLAS/blob/develop/reference/dtrsmf.f /// <summary> /// [dtrsm] Solves one of the matrix equations: /// <list type="bullet"> /// <item> /// <term><c>(side, transa) = (Left, None)</c></term> /// <description><c>A * X = alpha * B</c></description> /// </item> /// <item> /// <term><c>(side, transa) = (Right, None)</c></term> /// <description><c>X * A = alpha * B</c></description> /// </item> /// </list> /// </summary> /// <typeparam name="T"></typeparam> /// <param name="side"></param> /// <param name="uplo"></param> /// <param name="diag"> <c>true</c> if <paramref name="a"/> is a unit triangular; otherwise, <c>false</c>. </param> /// <param name="alpha"></param> /// <param name="a"></param> /// <param name="b"></param> public static void SolveTriangleMatrix <T>(OperandSide side, TriangleKind uplo, bool diag, T alpha, INdArray <T> a, MutableNdArray <T> b) { if (ValueTrait.Equals(alpha, Zero <T>())) { VectorOperation.Identity(NdArray.Zeros <T>(b.Shape), b); return; } switch ((side, uplo)) { case (OperandSide.Left, TriangleKind.Upper): SolveTriangleMatrixLU(diag, alpha, a, b); break; case (OperandSide.Left, TriangleKind.Lower): SolveTriangleMatrixLL(diag, alpha, a, b); break; case (OperandSide.Right, TriangleKind.Upper): SolveTriangleMatrixRU(diag, alpha, a, b); break; case (OperandSide.Right, TriangleKind.Lower): SolveTriangleMatrixRL(diag, alpha, a, b); break; default: Guard.ThrowArgumentError("Invalid configs."); break; } }
/// <summary> /// Calculates dot product of the two specified sequences. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="lhs"></param> /// <param name="rhs"></param> /// <returns></returns> public static T Dot <T>(ReadOnlyMemory <T> lhs, ReadOnlyMemory <T> rhs) { Guard.AssertArgument(lhs.Length == rhs.Length, "lhs.Length == rhs.Length"); if (typeof(T) == typeof(byte)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <byte> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <byte> >(ref rhs) ); return(Unsafe.As <byte, T>(ref result)); } if (typeof(T) == typeof(ushort)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <ushort> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <ushort> >(ref rhs) ); return(Unsafe.As <ushort, T>(ref result)); } if (typeof(T) == typeof(uint)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <uint> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <uint> >(ref rhs) ); return(Unsafe.As <uint, T>(ref result)); } if (typeof(T) == typeof(ulong)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <ulong> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <ulong> >(ref rhs) ); return(Unsafe.As <ulong, T>(ref result)); } if (typeof(T) == typeof(sbyte)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <sbyte> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <sbyte> >(ref rhs) ); return(Unsafe.As <sbyte, T>(ref result)); } if (typeof(T) == typeof(short)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <short> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <short> >(ref rhs) ); return(Unsafe.As <short, T>(ref result)); } if (typeof(T) == typeof(int)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <int> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <int> >(ref rhs) ); return(Unsafe.As <int, T>(ref result)); } if (typeof(T) == typeof(long)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <long> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <long> >(ref rhs) ); return(Unsafe.As <long, T>(ref result)); } if (typeof(T) == typeof(float)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <float> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <float> >(ref rhs) ); return(Unsafe.As <float, T>(ref result)); } if (typeof(T) == typeof(double)) { var result = DotOptimized( Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <double> >(ref lhs), Unsafe.As <ReadOnlyMemory <T>, ReadOnlyMemory <double> >(ref rhs) ); return(Unsafe.As <double, T>(ref result)); } { var result = ValueTrait.Zero <T>(); for (var i = 0; i < lhs.Length; ++i) { result = ValueTrait.Add(result, ValueTrait.Multiply(lhs.Span[i], rhs.Span[i])); } return(result); } }
/// <summary> /// Calculates dot product of the two specified sequences. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="lhs"></param> /// <param name="rhs"></param> /// <returns></returns> private static T DotOptimized <T>(ReadOnlyMemory <T> lhs, ReadOnlyMemory <T> rhs) where T : unmanaged { var lhsVSpan = MemoryMarshal.Cast <T, Vector <T> >(lhs.Span); var rhsVSpan = MemoryMarshal.Cast <T, Vector <T> >(rhs.Span); var retval = ValueTrait.Zero <T>(); var i = 0; for (var len = lhsVSpan.Length & ~0b1111; i < len; i += 16) { retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i], rhsVSpan[i])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x1], rhsVSpan[i + 0x1])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x2], rhsVSpan[i + 0x2])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x3], rhsVSpan[i + 0x3])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x4], rhsVSpan[i + 0x4])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x5], rhsVSpan[i + 0x5])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x6], rhsVSpan[i + 0x6])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x7], rhsVSpan[i + 0x7])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x8], rhsVSpan[i + 0x8])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x9], rhsVSpan[i + 0x9])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0xA], rhsVSpan[i + 0xA])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0xB], rhsVSpan[i + 0xB])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0xC], rhsVSpan[i + 0xC])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0xD], rhsVSpan[i + 0xD])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0xE], rhsVSpan[i + 0xE])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0xF], rhsVSpan[i + 0xF])); } if (i < (lhsVSpan.Length & ~0b111)) { retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i], rhsVSpan[i])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x1], rhsVSpan[i + 0x1])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x2], rhsVSpan[i + 0x2])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x3], rhsVSpan[i + 0x3])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x4], rhsVSpan[i + 0x4])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x5], rhsVSpan[i + 0x5])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x6], rhsVSpan[i + 0x6])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x7], rhsVSpan[i + 0x7])); i += 8; } if (i < (lhsVSpan.Length & ~0b11)) { retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i], rhsVSpan[i])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x1], rhsVSpan[i + 0x1])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x2], rhsVSpan[i + 0x2])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x3], rhsVSpan[i + 0x3])); i += 4; } if (i < (lhsVSpan.Length & ~0b1)) { retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i], rhsVSpan[i])); retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i + 0x1], rhsVSpan[i + 0x1])); i += 2; } if (i < lhsVSpan.Length) { retval = ValueTrait.Add(retval, Vector.Dot(lhsVSpan[i], rhsVSpan[i])); ++i; } var lhsRemainSpan = lhs.Span.Slice(Vector <T> .Count * i); var rhsRemainSpan = rhs.Span.Slice(Vector <T> .Count * i); var resultRemainSpan = lhs.Span.Slice(Vector <T> .Count * i); for (var j = 0; j < resultRemainSpan.Length; ++j) { retval = ValueTrait.Add(retval, ValueTrait.Multiply(lhsRemainSpan[j], rhsRemainSpan[j])); } return(retval); }
/// <summary> /// Computes mean from all elements of the <paramref name="ndArray"/>. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ndArray"></param> /// <returns></returns> public static T Mean <T>(this INdArray <T> ndArray) => ValueTrait.Divide(ndArray.Sum(), ValueTrait.FromLong <T>(ndArray.Shape.TotalLength));