public static Array <Real> Mul(this Array <Real> a, Array <Real> b, Array <Real> result = null) { return(Array_.ElementwiseOp(a, b, result, (n, x, offsetx, incx, y, offsety, incy, z, offsetz, incz) => { if (incx == 1 && incy == 1 && incz == 1) { Blas.vmul(n, x, offsetx, y, offsety, z, offsetz); } else if (incx == 0) // x[offsetx] is broadcast: y[:] * x[offsetx] { Blas.gemv(Order.RowMajor, Transpose.NoTrans, n, 1, 1, y, offsety, incy, x, offsetx, 1, 0, z, offsetz, incz); } //else if (incy == 0) // y[offsety] is broadcast: x[:] * y[offsety] // Blas.gemv(Order.RowMajor, Transpose.NoTrans, n, 1, 1, x, offsetx, incx, y, offsety, 1, 0, z, offsetz, incz); else // when everything else fails, fallback to slow version { for (int i = 0; i < n; i++) { z[offsetz] = x[offsetx] * y[offsety]; offsetx += incx; offsety += incy; offsetz += incz; } } })); }
private static void _EinsteinSum(int n, Einstein[] einstein, Array <float> x, int offX, Array <float> y, int offY, Array <float> z, int offZ ) { if (n == einstein.Length) { z.Values[offZ] += x.Values[offX] * y.Values[offY]; return; } var e = einstein[n]; if (n == einstein.Length - 1) { switch (e.mode) { case EinsteinMode.ELEMENTWISE: int axisX = (int)e.axisX, axisY = (int)e.axisY, axisZ = (int)e.axisZ; if (x.Stride[axisX] == 1 && y.Stride[axisY] == 1 && z.Stride[axisZ] == 1) { Blas.vmul(x.Shape[axisX], x.Values, offX, y.Values, offY, z.Values, offZ); return; } break; case EinsteinMode.OUTERX: var axis = (int)e.axisX; Blas.axpy(x.Shape[axis], y.Values[offY], x.Values, offX, x.Stride[axis], z.Values, offZ, z.Stride[(int)e.axisZ]); return; case EinsteinMode.OUTERY: axis = (int)e.axisY; Blas.axpy(y.Shape[axis], x.Values[offX], y.Values, offY, y.Stride[axis], z.Values, offZ, z.Stride[(int)e.axisZ]); return; } } switch (e.mode) { case EinsteinMode.INNER: for (int i = 0; i < x.Shape[(int)e.axisX]; ++i) { _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); offX += x.Stride[(int)e.axisX]; offY += y.Stride[(int)e.axisY]; } return; case EinsteinMode.ELEMENTWISE: for (int i = 0; i < x.Shape[(int)e.axisX]; ++i) { _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); offX += x.Stride[(int)e.axisX]; offY += y.Stride[(int)e.axisY]; offZ += z.Stride[(int)e.axisZ]; } return; case EinsteinMode.OUTERX: var axis = (int)e.axisX; for (int i = 0; i < x.Shape[axis]; ++i) { _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); offX += x.Stride[axis]; offZ += z.Stride[(int)e.axisZ]; } return; case EinsteinMode.OUTERY: axis = (int)e.axisY; for (int i = 0; i < y.Shape[axis]; ++i) { _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); offY += y.Stride[axis]; offZ += z.Stride[(int)e.axisZ]; } return; case EinsteinMode.SUMX: axis = (int)e.axisX; for (int i = 0; i < x.Shape[axis]; ++i) { _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); offX += x.Stride[axis]; } return; case EinsteinMode.SUMY: axis = (int)e.axisY; for (int i = 0; i < y.Shape[axis]; ++i) { _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); offY += y.Stride[axis]; } return; } }