Exemplo n.º 1
0
        /// <summary>
        /// Actual implmentation of an operation that performs combination of two NdArray values and aggregates the results.
        /// If the aggregation operation is addition, and the combination operation is multiplication, the operation is essentially the dot product,
        /// but the operation aggregation occurs accross all dimensions.
        /// </summary>
        /// <typeparam name="T">The type of data to operate on</typeparam>
        /// <typeparam name="CAGGREGATE">The typed add operator</typeparam>
        /// <typeparam name="CCOMBINE">The typed multiply operator</typeparam>
        /// <param name="aggregate">The add operator</param>
        /// <param name="combine">The multiply operator</param>
        /// <param name="in1">The left-hand-side argument</param>
        /// <param name="in2">The right-hand-side argument</param>
        private static T UFunc_CombineAndAggregate_Inner_Flush <T, CAGGREGATE, CCOMBINE>(CAGGREGATE aggregate, CCOMBINE combine, NdArray <T> in1, NdArray <T> in2)
            where CAGGREGATE : struct, IBinaryOp <T>
            where CCOMBINE : struct, IBinaryOp <T>
        {
            T result;

            T[] d1 = in1.AsArray();
            T[] d2 = in2.AsArray();

            if (in1.Shape.Dimensions.Length == 1)
            {
                long totalOps = in1.Shape.Dimensions[0].Length;
                long ix1      = in1.Shape.Offset;
                long ix2      = in2.Shape.Offset;

                long stride1 = in1.Shape.Dimensions[0].Stride;
                long stride2 = in2.Shape.Dimensions[0].Stride;

                result = combine.Op(d1[ix1], d2[ix2]);
                ix1   += stride1;
                ix2   += stride2;

                for (long i = 1; i < totalOps; i++)
                {
                    result = aggregate.Op(result, combine.Op(d1[ix1], d2[ix2]));
                    ix1   += stride1;
                    ix2   += stride2;
                }
            }
            else if (in1.Shape.Dimensions.Length == 2)
            {
                long opsOuter = in1.Shape.Dimensions[0].Length;
                long opsInner = in1.Shape.Dimensions[1].Length;

                long ix1 = in1.Shape.Offset;
                long ix2 = in2.Shape.Offset;

                long outerStride1 = in1.Shape.Dimensions[0].Stride;
                long outerStride2 = in2.Shape.Dimensions[0].Stride;

                long innerStride1 = in1.Shape.Dimensions[1].Stride;
                long innerStride2 = in2.Shape.Dimensions[1].Stride;

                outerStride1 -= innerStride1 * in1.Shape.Dimensions[1].Length;
                outerStride2 -= innerStride2 * in2.Shape.Dimensions[1].Length;

                result = combine.Op(d1[ix1], d2[ix2]);
                ix1   += innerStride1;
                ix2   += innerStride2;

                for (long i = 0; i < opsOuter; i++)
                {
                    for (long j = (i == 0 ? 1 : 0); j < opsInner; j++)
                    {
                        result = aggregate.Op(result, combine.Op(d1[ix1], d2[ix2]));
                        ix1   += innerStride1;
                        ix2   += innerStride2;
                    }

                    ix1 += outerStride1;
                    ix2 += outerStride2;
                }
            }
            else
            {
                long   n        = in1.Shape.Dimensions.LongLength - 3;
                long[] limits   = in1.Shape.Dimensions.Where(x => n-- > 0).Select(x => x.Length).ToArray();
                long[] counters = new long[limits.LongLength];

                long totalOps = limits.LongLength == 0 ? 1 : limits.Aggregate <long>((a, b) => a * b);

                //This chunck of variables are used to prevent repeated calculations of offsets
                long dimIndex0 = 0 + limits.LongLength;
                long dimIndex1 = 1 + limits.LongLength;
                long dimIndex2 = 2 + limits.LongLength;

                long opsOuter      = in1.Shape.Dimensions[dimIndex0].Length;
                long opsInner      = in1.Shape.Dimensions[dimIndex1].Length;
                long opsInnerInner = in1.Shape.Dimensions[dimIndex2].Length;

                long outerStride1      = in1.Shape.Dimensions[dimIndex0].Stride;
                long innerStride1      = in1.Shape.Dimensions[dimIndex1].Stride;
                long innerInnerStride1 = in1.Shape.Dimensions[dimIndex2].Stride;

                long outerStride2      = in2.Shape.Dimensions[dimIndex0].Stride;
                long innerStride2      = in2.Shape.Dimensions[dimIndex1].Stride;
                long innerInnerStride2 = in2.Shape.Dimensions[dimIndex2].Stride;

                outerStride1 -= innerStride1 * in1.Shape.Dimensions[dimIndex1].Length;
                innerStride1 -= innerInnerStride1 * in1.Shape.Dimensions[dimIndex2].Length;
                outerStride2 -= innerStride2 * in2.Shape.Dimensions[dimIndex1].Length;
                innerStride2 -= innerInnerStride2 * in2.Shape.Dimensions[dimIndex2].Length;

                result = combine.Op(d1[in1.Shape[counters]], d2[in2.Shape[counters]]);
                bool first = true;

                for (long outer = 0; outer < totalOps; outer++)
                {
                    //Get the array offset for the first element in the outer dimension
                    long ix1 = in1.Shape[counters];
                    long ix2 = in2.Shape[counters];
                    if (first)
                    {
                        ix1 += innerInnerStride1;
                        ix2 += innerInnerStride2;
                    }

                    for (long i = 0; i < opsOuter; i++)
                    {
                        for (long j = 0; j < opsInner; j++)
                        {
                            for (long k = (first ? 1 : 0); k < opsInnerInner; k++)
                            {
                                result = aggregate.Op(result, combine.Op(d1[ix1], d2[ix2]));
                                ix1   += innerInnerStride1;
                                ix2   += innerInnerStride2;
                            }
                            first = false;

                            ix1 += innerStride1;
                            ix2 += innerStride2;
                        }

                        ix1 += outerStride1;
                        ix2 += outerStride2;
                    }

                    if (counters.LongLength > 0)
                    {
                        //Basically a ripple carry adder
                        long p = counters.LongLength - 1;
                        while (++counters[p] == limits[p] && p > 0)
                        {
                            counters[p] = 0;
                            p--;
                        }
                    }
                }
            }

            return(result);
        }
Exemplo n.º 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;
            }
        }