Accessing Tensor Elements in Visual Basic QuickStart Sample

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

This sample is also available in: C#, F#.

Overview

This QuickStart sample demonstrates the various ways to access and manipulate elements within tensors using Numerics.NET. It covers both basic and advanced indexing techniques that are essential for working with multidimensional data structures.

The sample illustrates:

  • Basic indexing to access individual elements and slices of tensors
  • Using C# 8.0’s caret (^) operator for end-relative indexing
  • Working with ranges and slices to access sub-tensors
  • Advanced indexing techniques using integer arrays and boolean masks
  • Understanding the difference between shallow copies and deep copies of tensors
  • Setting values in tensors using various indexing methods
  • Using strides for more complex slice operations
  • Working with multi-dimensional tensors

The code provides practical examples of each technique, making it easy to understand how to effectively work with tensor data structures in your applications. Each operation is demonstrated with clear examples showing both the syntax and the resulting tensor structure.

The code

Imports Numerics.NET.Tensors

' Illustrates different ways of getting and setting
' elements of a tensor.
Module AccessingTensorElements

    Sub Main()
        ' The license is verified at runtime. We're Imports
        ' 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:
        Dim t = Tensor.CreateFromFunction((3, 4), Function (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), Function (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!
        Dim t123 = t(1, 2, 3)
        ' t123 -> ( 123 )
        Console.WriteLine($"Type of t(1, 2, 3) -> {t123.GetType()}")

        ' Single values can be set Imports 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:
        Dim 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:
        Dim 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:
        Dim r12 = new Numerics.NET.Range(1, 2)
        Dim trrr = t(r12, r12, r12)
        ' trrr -> ((( 111, 112), (121, 122)), (211, 212), (221, 222)))
        Dim r13 = New Range(1, 3)
        trrr = t(r13, r13, r13)

        ' You can mix and match:
        Dim s = Tensor.CreateFromFunction((3, 3), Function (i, j) 11 + 10 * i + j)
        ' s -> (( 11 12 13 )
        '       ( 21 22 23 )
        '       ( 31 32 33 ))
        Dim row1 = s(0, Range.All)
        ' row1 -> ( 11 12 13 )
        Dim column1 = s(Range.All, New Index(2, True))
        ' column1 -> ( 12 22 32 )
        Dim row2 = s(1, New System.Range(1, New Index(0, True)))
        ' row2 -> ( 22 23 )

        ' C#'s ranges do not support strides. For that, you have to use
        ' either Numerics.NET.Range or Numerics.NET.Slice:
        Dim 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:
        Dim x = Tensor.CreateRange(3)
        ' x -> ( 0 1 2 )
        Dim 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 Imports ranges and slices:
        s(1, New System.Range(1, 3)) = Tensor.CreateFromArray({ 88, 99 })
        ' s -> (( 11 12 13 )
        '       ( 21 88 99 )
        '       ( 31 32 33 ))
        s(New System.Range(0, New Index(1, True)), New Index(2, True)) = Tensor.CreateFromArray({ 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:
        Dim indexes = { 0, 3 }
        Dim t1 = t(1, indexes, New Range(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:
        Dim mask = { True, False, False, True }
        Dim t2 = t(1, mask, New Range(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 Imports an indexer:
        Console.WriteLine("Shallow copy vs. clone:")
        Dim t10 = t2(TensorIndex.All)
        ' The Copy method creates a full copy.
        Dim 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 CLONEDATA
#End If

        ' We can give a tensor its own component storage
        ' by calling the CloneData method:
        Console.WriteLine("CloneData:")
        ' TODO: t11.CloneData()
        ' Now, changing the original v2 no longer changes v7:
        ' t2(1, 1) = 4
        Console.WriteLine($"t11(1,1) = {t11(1, 1)}")
        Console.Write("Press Enter key to exit...")
        Console.ReadLine()
    End Sub
End Module