/// <summary> /// Evaluates dot operation of vector/matrix lazily. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="x"> [<c>x.Rank == 1 || x.Rank == 2</c>] </param> /// <param name="y"> [<c>y.Rank == 1 || y.Rank == 2</c>] </param> /// <returns> /// <para> The result of dot operation of <paramref name="x"/> and <paramref name="y"/>. </para> /// <para> - If <c>x.Shape == {p} && y.Rank == {p}</c>, then <c>$ReturnValue.Shape == {1}</c>. </para> /// <para> - If <c>x.Shape == {p} && y.Shape == {p, n}</c>, then <c>$ReturnValue.Shape == {n}</c>. </para> /// <para> - If <c>x.Shape == {m, p} && y.Shape == {p}</c>, then <c>$ReturnValue.Shape == {m}</c>. </para> /// <para> - If <c>x.Shape == {m, p} && y.Shape == {p, n}</c>, then <c>$ReturnValue.Shape == {m, n}</c>. </para> /// <para> - If the shape patterns does not match with above patterns, throw <see cref="ShapeMismatchException"/>. </para> /// </returns> /// <exception cref="ShapeMismatchException"></exception> public static NdArray <T> Dot <T>(this NdArray <T> x, NdArray <T> y) { var xEntity = x.GetOrCopyBuffer(); switch (y.Rank) { case 1: var yEntity = y.GetOrCopyBuffer(); switch (x.Rank) { case 1: return(Dot1x1(xEntity, yEntity)); case 2: return(Dot2x1(xEntity, yEntity)); default: break; } break; case 2: var yTEntity = y.Transpose().ToMutable().GetOrCopyBuffer(); switch (x.Rank) { case 1: return(Dot1x2(xEntity, yTEntity)); case 2: return(Dot2x2(xEntity, yTEntity)); default: break; } break; default: break; } Guard.ThrowShapeMismatch($"The ranks of x and y must be 1 or 2. (x.Rank={x.Rank}, y.Rank={y.Rank})"); throw new NotSupportedException(); }
/// <summary> /// Actual implmentation of the matrix multiplication operation. /// </summary> /// <typeparam name="T">The type of data to operate on</typeparam> /// <typeparam name="CADD">The typed add operator</typeparam> /// <typeparam name="CMUL">The typed multiply operator</typeparam> /// <param name="addop">The add operator</param> /// <param name="mulop">The multiply operator</param> /// <param name="in1">The left-hand-side argument</param> /// <param name="in2">The right-hand-side argument</param> /// <param name="out">An optional output argument, use for in-place operations</param> private static void UFunc_Matmul_Inner_Flush <T, CADD, CMUL>(CADD addop, CMUL mulop, NdArray <T> in1, NdArray <T> in2, NdArray <T> @out) where CADD : struct, IBinaryOp <T> where CMUL : struct, IBinaryOp <T> { //Matrix multiplication of two vectors is the dot product if (@out.Shape.Elements == 1) { @out.Value[0] = UFunc_CombineAndAggregate_Inner_Flush <T, CADD, CMUL>(addop, mulop, in1, in2); return; } if (@out.Shape.Dimensions.LongLength != 2) { throw new Exception("Matrix multiplication is only supported for 1 and 2 dimensional arrays"); } long opsOuter = @out.Shape.Dimensions[0].Length; long opsInner = @out.Shape.Dimensions[1].Length; long opsInnerInner = in1.Shape.Dimensions[1].Length; T[] d1 = in1.AsArray(); T[] d2 = in2.AsArray(); T[] d3 = @out.AsArray(); long ix1Base = in1.Shape.Offset; long outerStride1 = in1.Shape.Dimensions[0].Stride; long innerStride1 = in1.Shape.Dimensions[1].Stride; //outerStride1 -= innerStride1 * in1.Shape.Dimensions[1].Length; NdArray <T> rhs = in2.Transpose(); long ix2Base = rhs.Shape.Offset; long outerStride2 = rhs.Shape.Dimensions[0].Stride; long innerStride2 = rhs.Shape.Dimensions[1].Stride; outerStride2 -= innerStride2 * rhs.Shape.Dimensions[1].Length; long ix3 = @out.Shape.Offset; long outerStride3 = @out.Shape.Dimensions[0].Stride; long innerStride3 = @out.Shape.Dimensions[1].Stride; outerStride3 -= innerStride3 * @out.Shape.Dimensions[1].Length; for (long i = 0; i < opsOuter; i++) { long ix2 = ix2Base; for (long j = 0; j < opsInner; j++) { long ix1 = ix1Base; T result = mulop.Op(d1[ix1], d2[ix2]); ix1 += innerStride1; ix2 += innerStride2; for (long k = 1; k < opsInnerInner; k++) { result = addop.Op(result, mulop.Op(d1[ix1], d2[ix2])); ix1 += innerStride1; ix2 += innerStride2; } d3[ix3] = result; ix3 += innerStride3; ix2 += outerStride2; } ix3 += outerStride3; ix1Base += outerStride1; } }
public void TransposeForXDim(int[] axesMap, NdArray <int> from, NdArray <int> to) { Assert.Equal(to, from.Transpose(axesMap), NdArrayComparer <int> .Default); Assert.Equal(to.ToMutable(), from.ToMutable().Transpose(axesMap), NdArrayComparer <int> .Default); }