Пример #1
0
        /// <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} &amp;&amp; y.Rank == {p}</c>, then <c>$ReturnValue.Shape == {1}</c>. </para>
        ///     <para> - If <c>x.Shape == {p} &amp;&amp; y.Shape == {p, n}</c>, then <c>$ReturnValue.Shape == {n}</c>. </para>
        ///     <para> - If <c>x.Shape == {m, p} &amp;&amp; y.Shape == {p}</c>, then <c>$ReturnValue.Shape == {m}</c>. </para>
        ///     <para> - If <c>x.Shape == {m, p} &amp;&amp; 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();
        }
Пример #2
0
        /// <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;
            }
        }
Пример #3
0
 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);
 }