Accessing Tensor Elements in C# QuickStart Sample

Illustrates different ways of accessing elements of a tensor and sub-tensors using classes in the Numerics.NET.Tensors namespace in C#.

View this sample in: Visual Basic F#

using System;

// Tensor classes reside in the Numerics.NET.Tensors
// namespace.
using Numerics.NET.Tensors;

namespace Numerics.NET.QuickStart.CSharp
{
    /// <summary>
    /// Illustrates different ways of getting and setting 
    /// elements of a tensor.
    /// </summary>
    class AccessingTensorElements
    {
        static void Main(string[] args)
        {
            // The license is verified at runtime. We're using
            // a 30 day trial key here. For more information, see
            //     https://numerics.net/trial-key
            Numerics.NET.License.Verify("64542-18980-57619-62268");

            //
            // Accessing tensor elements
            //

            // Let's create a few tensors to work with:
            var t = Tensor.CreateFromFunction((3, 4), (i, j) => 11 + 10 * i + j);
            // t -> [ [ 11, 12, 13, 14 ],
            //        [ 21, 22, 23, 24 ],
            //        [ 31, 32, 33, 34 ] ]

            // Actually, let's use something a little bigger:
            t = Tensor.CreateFromFunction((3, 4, 5), (i, j, k) => 100 * i + 10 * j + k);

            // Tensors have indexer properties which get or set all or part
            // of a tensor, including individual values.

            // Important: All indexers return Tensor<T> objects,
            // even if it contains just a single element!
            var t123 = t[1, 2, 3];
            // t123 -> [ 123 ]
            Console.WriteLine($"Type of t[1, 2, 3] -> {t123.GetType()}");

            // As of C# 8.0, you can use the caret (^) operator to
            // specify that the index should be counted from the end
            // of the dimension:
            var t_2_2_2 = t[^2, ^2, ^2];
            // t_2_2_2 -> [ 123 ]

            // Single values can be set using the indexer, but you
            // have to assign a scalar tensor:
            t[1, 2, 3] = Tensor.CreateScalar(999);
            t123 = t[1, 2, 3];
            // t123 -> [ 999 ]

            // To get an element's value, and not a scalar tensor,
            // use the GetValue method:
            var tValue = t.GetValue(1, 2, 3);
            // tValue -> [ 999 ]
            // A corresponding SetValue method lets you set the value:
            t.SetValue(99, 1, 2, 3);
            tValue = t.GetValue(1, 2, 3);
            // tValue -> [ 99 ]

            // When you leave out dimensions, the entire dimensions
            // are returned:
            var t12x = t[1, 2];
            // t12x -> [ 120, 121, 122, 999, 124 ]

            // You can use ranges and slices to get or set sub-tensors.
            // You can use either Numerics.NET.Range or System.Range:
            var r12 = new Numerics.NET.Range(1, 2);
            var trrr = t[r12, r12, r12];
            // trrr -> [[[ 111, 112], [121, 122]], [211, 212], [221, 222]]]
            trrr = t[1..3, 1..3, 1..3];

            // You can mix and match:
            var s = Tensor.CreateFromFunction((3, 3), (i, j) => 11 + 10 * i + j);
            // s -> [[ 11 12 13 ]
            //       [ 21 22 23 ]
            //       [ 31 32 33 ]]
            var row1 = s[0, ..];
            // row1 -> [ 11 12 13 ]
            var column1 = s[.., ^2];
            // column1 -> [ 12 22 32 ]
            var row2 = s[1, 1..];
            // row2 -> [ 22 23 ]

            // C#'s ranges do not support strides. For that, you have to use
            // either Numerics.NET.Range or Numerics.NET.Slice:
            var row3 = s[1, new Numerics.NET.Range(0, 2, 2)];
            // row3 -> [ 21 23 ]
            row3 = s[1, new Numerics.NET.Slice(2, 0, 2)];
            // row3 -> [ 21 23 ]

            // You can even have ranges with negative strides:
            var x = Tensor.CreateRange(3);
            // x -> [ 0 1 2 ]
            var reverse = x[new Numerics.NET.Range(2, 0, -1)];
            // reverse -> [ 2 1 0 ]
            reverse = x[new Numerics.NET.Slice(2, 2, -1)];
            // reverse -> [ 2 1 0 ]

            // You can set values using ranges and slices:
            s[1, 1..3] = Tensor.CreateFromArray(new[] { 88, 99 });
            // s -> [[ 11 12 13 ]
            //       [ 21 88 99 ]
            //       [ 31 32 33 ]]
            s[..^1, ^2] = Tensor.CreateFromArray(new[] { 1, 2 });
            // s -> [[ 11  1 13 ]
            //       [ 21  2 99 ]
            //       [ 31 32 33 ]]

            // TODO: s[1, new Range(0, 2, 2)] = Tensor.CreateFromArray(new[] { 77, 66 });
            // s -> [[ 11  1 13 ]
            //       [ 77  2 66 ]
            //       [ 31 32 33 ]]

            //
            // Advanced indexes:
            //

            // You can use sets of integers to specify only those elements:
            int[] indexes = { 0, 3 };
            var t1 = t[1, indexes, 3..5];
            // t1 -> [[ 103 133 ]
            //        [ 104 134 ]]

            // You can also use a mask, an array of booleans, that are true
            // for the elements you want to select:
            bool[] mask = { true, false, false, true };
            var t2 = t[1, mask, 3..5];
            // t2 -> [[ 103 133 ]
            //        [ 104 134 ]]


            //
            // Copying and cloning tensors
            //

            // A shallow copy of a tensor constructs a tensor
            // that shares the component storage with the original.
            // This is done using an indexer:
            Console.WriteLine("Shallow copy vs. clone:");
            var t10 = t2[TensorIndex.All];
            // The Copy method creates a full copy.
            var t11 = t2.Copy();
            // When we change t2, t10 changes, but t11 is left
            // unchanged:
            Console.WriteLine($"t2[1,1] = {t2[1, 1]}");
            t2.SetValue(-2, 1, 1);
            Console.WriteLine($"t10[1,1] = {t10[1, 1]}");
            Console.WriteLine($"t11[1,1] = {t11[1, 1]}");
if 


            Console.Write("Press Enter key to exit...");
            Console.ReadLine();
        }
    }
}