// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // This file is copied and adapted from the following git repository - // https://github.com/dotnet/corefx // Commit ID: bdd0814360d4c3a58860919f292a306242f27da1 // Path: /src/System.Numerics.Tensors/tests/TensorArithmetic.cs // Original license statement below - // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; namespace Microsoft.ML.OnnxRuntime.Tensors { internal interface ITensorArithmetic { T One { get; } T Zero { get; } void Add(Tensor left, Tensor right, Tensor result); void Add(Tensor tensor, T scalar, Tensor result); void And(Tensor left, Tensor right, Tensor result); void And(Tensor tensor, T scalar, Tensor result); void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result); void Decrement(Tensor tensor, Tensor result); void Divide(Tensor left, Tensor right, Tensor result); void Divide(Tensor tensor, T scalar, Tensor result); void Equals(Tensor left, Tensor right, Tensor result); void GreaterThan(Tensor left, Tensor right, Tensor result); void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result); void Increment(Tensor tensor, Tensor result); void LeftShift(Tensor tensor, int value, Tensor result); void LessThan(Tensor left, Tensor right, Tensor result); void LessThanOrEqual(Tensor left, Tensor right, Tensor result); void Modulo(Tensor left, Tensor right, Tensor result); void Modulo(Tensor tensor, T scalar, Tensor result); void Multiply(Tensor left, Tensor right, Tensor result); void Multiply(Tensor tensor, T scalar, Tensor result); void NotEquals(Tensor left, Tensor right, Tensor result); void Or(Tensor left, Tensor right, Tensor result); void Or(Tensor tensor, T scalar, Tensor result); void RightShift(Tensor tensor, int value, Tensor result); void Subtract(Tensor left, Tensor right, Tensor result); void Subtract(Tensor tensor, T scalar, Tensor result); void UnaryMinus(Tensor tensor, Tensor result); void UnaryPlus(Tensor tensor, Tensor result); void Xor(Tensor left, Tensor right, Tensor result); void Xor(Tensor tensor, T scalar, Tensor result); } internal static class TensorArithmetic { public static ITensorArithmetic Instance => TensorArithmetic.GetArithmetic(); } internal static class TensorArithmetic { public static ITensorArithmetic GetArithmetic() { if (typeof(T) == typeof(bool)) { return (ITensorArithmetic)new BoolArithmetic(); } else if (typeof(T) == typeof(byte)) { return (ITensorArithmetic)new ByteArithmetic(); } else if (typeof(T) == typeof(char)) { return (ITensorArithmetic)new CharArithmetic(); } else if (typeof(T) == typeof(decimal)) { return (ITensorArithmetic)new DecimalArithmetic(); } else if (typeof(T) == typeof(double)) { return (ITensorArithmetic)new DoubleArithmetic(); } else if (typeof(T) == typeof(float)) { return (ITensorArithmetic)new FloatArithmetic(); } else if (typeof(T) == typeof(int)) { return (ITensorArithmetic)new IntArithmetic(); } else if (typeof(T) == typeof(long)) { return (ITensorArithmetic)new LongArithmetic(); } else if (typeof(T) == typeof(sbyte)) { return (ITensorArithmetic)new SByteArithmetic(); } else if (typeof(T) == typeof(short)) { return (ITensorArithmetic)new ShortArithmetic(); } else if (typeof(T) == typeof(uint)) { return (ITensorArithmetic)new UIntArithmetic(); } else if (typeof(T) == typeof(ulong)) { return (ITensorArithmetic)new ULongArithmetic(); } else if (typeof(T) == typeof(ushort)) { return (ITensorArithmetic)new UShortArithmetic(); } return null; } } internal class BoolArithmetic : ITensorArithmetic { public bool One => true; public bool Zero => false; public void Add(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Add(Tensor tensor, bool scalar, Tensor result) { throw new NotSupportedException(); } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (bool)(left[indices] & right[indices]); } } public void And(Tensor tensor, bool scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (bool)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { throw new NotSupportedException(); } public void Decrement(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void Divide(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Divide(Tensor tensor, bool scalar, Tensor result) { throw new NotSupportedException(); } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Increment(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void LeftShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void LessThan(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Modulo(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Modulo(Tensor tensor, bool scalar, Tensor result) { throw new NotSupportedException(); } public void Multiply(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Multiply(Tensor tensor, bool scalar, Tensor result) { throw new NotSupportedException(); } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (bool)(left[indices] | right[indices]); } } public void Or(Tensor tensor, bool scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (bool)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void Subtract(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Subtract(Tensor tensor, bool scalar, Tensor result) { throw new NotSupportedException(); } public void UnaryMinus(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void UnaryPlus(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (bool)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, bool scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (bool)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Add(DenseTensor tensor, bool scalar, DenseTensor result) { throw new NotSupportedException(); } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (bool)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (bool)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, bool scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (bool)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (bool)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { throw new NotSupportedException(); } public void Decrement(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Divide(DenseTensor tensor, bool scalar, DenseTensor result) { throw new NotSupportedException(); } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Increment(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Modulo(DenseTensor tensor, bool scalar, DenseTensor result) { throw new NotSupportedException(); } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Multiply(DenseTensor tensor, bool scalar, DenseTensor result) { throw new NotSupportedException(); } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (bool)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (bool)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, bool scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (bool)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (bool)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Subtract(DenseTensor tensor, bool scalar, DenseTensor result) { throw new NotSupportedException(); } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (bool)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (bool)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, bool scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (bool)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (bool)(tensorSpan[op1Index] ^ scalar); } } } } internal class ByteArithmetic : ITensorArithmetic { public byte One => 1; public byte Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] + right[indices]); } } public void Add(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] & right[indices]); } } public void And(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { byte sum = (byte)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (byte)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] | right[indices]); } } public void Or(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, byte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (byte)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { byte sum = (byte)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (byte)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, byte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (byte)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] ^ scalar); } } } } internal class CharArithmetic : ITensorArithmetic { public char One => (char)1; public char Zero => (char)0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] + right[indices]); } } public void Add(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] & right[indices]); } } public void And(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { char sum = (char)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (char)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] | right[indices]); } } public void Or(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, char scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (char)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { char sum = (char)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (char)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, char scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (char)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (char)(tensorSpan[op1Index] ^ scalar); } } } } internal class DecimalArithmetic : ITensorArithmetic { public decimal One => 1; public decimal Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(left[indices] + right[indices]); } } public void Add(Tensor tensor, decimal scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void And(Tensor tensor, decimal scalar, Tensor result) { throw new NotSupportedException(); } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { decimal sum = (decimal)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (decimal)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, decimal scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, decimal scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, decimal scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Or(Tensor tensor, decimal scalar, Tensor result) { throw new NotSupportedException(); } public void RightShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, decimal scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (decimal)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Xor(Tensor tensor, decimal scalar, Tensor result) { throw new NotSupportedException(); } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, decimal scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void And(DenseTensor tensor, decimal scalar, DenseTensor result) { throw new NotSupportedException(); } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { decimal sum = (decimal)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (decimal)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, decimal scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, decimal scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, decimal scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Or(DenseTensor tensor, decimal scalar, DenseTensor result) { throw new NotSupportedException(); } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, decimal scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (decimal)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (decimal)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Xor(DenseTensor tensor, decimal scalar, DenseTensor result) { throw new NotSupportedException(); } } internal class DoubleArithmetic : ITensorArithmetic { public double One => 1.0; public double Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(left[indices] + right[indices]); } } public void Add(Tensor tensor, double scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void And(Tensor tensor, double scalar, Tensor result) { throw new NotSupportedException(); } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { double sum = (double)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (double)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, double scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, double scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, double scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Or(Tensor tensor, double scalar, Tensor result) { throw new NotSupportedException(); } public void RightShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, double scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (double)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Xor(Tensor tensor, double scalar, Tensor result) { throw new NotSupportedException(); } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, double scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void And(DenseTensor tensor, double scalar, DenseTensor result) { throw new NotSupportedException(); } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { double sum = (double)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (double)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, double scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, double scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, double scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Or(DenseTensor tensor, double scalar, DenseTensor result) { throw new NotSupportedException(); } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, double scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (double)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (double)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Xor(DenseTensor tensor, double scalar, DenseTensor result) { throw new NotSupportedException(); } } internal class FloatArithmetic : ITensorArithmetic { public float One => 1.0f; public float Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(left[indices] + right[indices]); } } public void Add(Tensor tensor, float scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void And(Tensor tensor, float scalar, Tensor result) { throw new NotSupportedException(); } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { float sum = (float)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (float)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, float scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, float scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, float scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Or(Tensor tensor, float scalar, Tensor result) { throw new NotSupportedException(); } public void RightShift(Tensor tensor, int value, Tensor result) { throw new NotSupportedException(); } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, float scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (float)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { throw new NotSupportedException(); } public void Xor(Tensor tensor, float scalar, Tensor result) { throw new NotSupportedException(); } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, float scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void And(DenseTensor tensor, float scalar, DenseTensor result) { throw new NotSupportedException(); } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { float sum = (float)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (float)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, float scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, float scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, float scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Or(DenseTensor tensor, float scalar, DenseTensor result) { throw new NotSupportedException(); } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { throw new NotSupportedException(); } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, float scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (float)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (float)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { throw new NotSupportedException(); } public void Xor(DenseTensor tensor, float scalar, DenseTensor result) { throw new NotSupportedException(); } } internal class IntArithmetic : ITensorArithmetic { public int One => 1; public int Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] + right[indices]); } } public void Add(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] & right[indices]); } } public void And(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { int sum = (int)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (int)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] | right[indices]); } } public void Or(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, int scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (int)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { int sum = (int)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (int)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, int scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (int)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (int)(tensorSpan[op1Index] ^ scalar); } } } } internal class LongArithmetic : ITensorArithmetic { public long One => 1; public long Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] + right[indices]); } } public void Add(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] & right[indices]); } } public void And(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { long sum = (long)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (long)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] | right[indices]); } } public void Or(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, long scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (long)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { long sum = (long)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (long)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, long scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (long)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (long)(tensorSpan[op1Index] ^ scalar); } } } } internal class SByteArithmetic : ITensorArithmetic { public sbyte One => 1; public sbyte Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] + right[indices]); } } public void Add(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] & right[indices]); } } public void And(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { sbyte sum = (sbyte)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (sbyte)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] | right[indices]); } } public void Or(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, sbyte scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (sbyte)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { sbyte sum = (sbyte)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (sbyte)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, sbyte scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (sbyte)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] ^ scalar); } } } } internal class ShortArithmetic : ITensorArithmetic { public short One => 1; public short Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] + right[indices]); } } public void Add(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] & right[indices]); } } public void And(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { short sum = (short)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (short)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] | right[indices]); } } public void Or(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)-tensor[indices]; } } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, short scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (short)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { short sum = (short)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (short)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)-tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)-tensorSpan[op1Index]; } } } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, short scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (short)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (short)(tensorSpan[op1Index] ^ scalar); } } } } internal class UIntArithmetic : ITensorArithmetic { public uint One => 1; public uint Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] + right[indices]); } } public void Add(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] & right[indices]); } } public void And(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { uint sum = (uint)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (uint)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] | right[indices]); } } public void Or(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, uint scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (uint)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { uint sum = (uint)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (uint)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, uint scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (uint)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] ^ scalar); } } } } internal class ULongArithmetic : ITensorArithmetic { public ulong One => 1; public ulong Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] + right[indices]); } } public void Add(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] & right[indices]); } } public void And(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { ulong sum = (ulong)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (ulong)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] | right[indices]); } } public void Or(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, ulong scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ulong)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { ulong sum = (ulong)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (ulong)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, ulong scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ulong)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] ^ scalar); } } } } internal class UShortArithmetic : ITensorArithmetic { public ushort One => 1; public ushort Zero => 0; public void Add(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] + right[indices]); } } public void Add(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] + scalar); } } public void And(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] & right[indices]); } } public void And(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] & scalar); } } public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) { var leftIndices = new int[left.Rank]; var rightIndices = new int[right.Rank]; var resultIndices = new int[result.Rank]; var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) { ushort sum = (ushort)0; ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; // todo, make this more efficient ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); sum += (ushort)(left[leftIndices] * right[rightIndices]); } result[resultIndices] = sum; } } public void Decrement(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]--; } } public void Divide(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] / right[indices]); } } public void Divide(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] / scalar); } } public void Equals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] == right[indices]; } } public void GreaterThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] > right[indices]; } } public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] >= right[indices]; } } public void Increment(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices]++; } } public void LeftShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] << value); } } public void LessThan(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] < right[indices]; } } public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] <= right[indices]; } } public void Modulo(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] % right[indices]); } } public void Modulo(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] % scalar); } } public void Multiply(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] * right[indices]); } } public void Multiply(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] * scalar); } } public void NotEquals(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = left[indices] != right[indices]; } } public void Or(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] | right[indices]); } } public void Or(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] | scalar); } } public void RightShift(Tensor tensor, int value, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] >> value); } } public void Subtract(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] - right[indices]); } } public void Subtract(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] - scalar); } } public void UnaryMinus(Tensor tensor, Tensor result) { throw new NotSupportedException(); } public void UnaryPlus(Tensor tensor, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)+tensor[indices]; } } public void Xor(Tensor left, Tensor right, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(left[indices] ^ right[indices]); } } public void Xor(Tensor tensor, ushort scalar, Tensor result) { Span indices = new Span(new int[result.Rank]); for(int i = 0; i < result.Length; i++) { ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); result[indices] = (ushort)(tensor[indices] ^ scalar); } } public void Add(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] + rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] + rightSpan[op2Index]); } } } public void Add(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] + scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] + scalar); } } } public void And(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] & rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] & rightSpan[op2Index]); } } } public void And(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] & scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] & scalar); } } } public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) { var summingDimensions = new int[leftAxes.Length]; for(int i = 0; i < leftAxes.Length; i++) { summingDimensions[i] = left.dimensions[leftAxes[i]]; } var summingStrides = ArrayUtilities.GetStrides(summingDimensions); int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); var resultStrides = result.strides; // translates from result index to left non-summing dimensions' index portion // since left non-summing dimensions are given precedence in result, the end is zero-padded int[] leftNonSummingStrides = new int[result.Rank]; // translates from summing index to left summing dimensions' index portion int[] leftSummingStrides = new int[leftAxes.Length]; ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); // translates from result index to right non-summing dimensions' index portion int[] rightNonSummingStrides = new int[result.Rank]; // right non-summing dimensions appear after left non-summing dimensions. int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); // translates from summing index to right summing dimensions' index portion int[] rightSummingStrides = new int[rightAxes.Length]; ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) { ushort sum = (ushort)0; int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) { int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); int leftIndex = leftIndexNonSumming + leftIndexSumming; int rightIndex = rightIndexNonSumming + rightIndexSumming; sum += (ushort)(leftSpan[leftIndex] * rightSpan[rightIndex]); } resultSpan[resultIndex] = sum; } } public void Decrement(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]--; } } public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] / rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] / rightSpan[op2Index]); } } } public void Divide(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] / scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] / scalar); } } } public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] == rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; } } } public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] > rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; } } } public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] >= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; } } } public void Increment(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i]++; } } public void LeftShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] << value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] << value); } } } public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] < rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; } } } public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] <= rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; } } } public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] % rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] % rightSpan[op2Index]); } } } public void Modulo(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] % scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] % scalar); } } } public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] * rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] * rightSpan[op2Index]); } } } public void Multiply(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] * scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] * scalar); } } } public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = leftSpan[i] != rightSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; } } } public void Or(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] | rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] | rightSpan[op2Index]); } } } public void Or(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] | scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] | scalar); } } } public void RightShift(DenseTensor tensor, int value, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] >> value); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] >> value); } } } public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] - rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] - rightSpan[op2Index]); } } } public void Subtract(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] - scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] - scalar); } } } public void UnaryMinus(DenseTensor tensor, DenseTensor result) { throw new NotSupportedException(); } public void UnaryPlus(DenseTensor tensor, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)+tensorSpan[i]; } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)+tensorSpan[op1Index]; } } } public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) { var resultSpan = result.Buffer.Span; var leftSpan = left.Buffer.Span; var rightSpan = right.Buffer.Span; if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(leftSpan[i] ^ rightSpan[i]); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : !left.IsReversedStride ? left.strides : right.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : left.IsReversedStride ? left.strides : right.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] ^ rightSpan[op2Index]); } } } public void Xor(DenseTensor tensor, ushort scalar, DenseTensor result) { var resultSpan = result.Buffer.Span; var tensorSpan = tensor.Buffer.Span; if (result.IsReversedStride == tensor.IsReversedStride) { for(int i = 0; i < resultSpan.Length; i++) { resultSpan[i] = (ushort)(tensorSpan[i] ^ scalar); } } else { int rowMajorIndex = 0; int colMajorIndex = 0; ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; var rowMajorStrides = !result.IsReversedStride ? result.strides : tensor.strides; var columnMajorStrides = result.IsReversedStride ? result.strides : tensor.strides; for(;rowMajorIndex < resultSpan.Length; rowMajorIndex++) { colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] ^ scalar); } } } } }