/// Creates a copy of this two-dimensional array as a DenseTensor<T>
/// </summary>
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam>
/// <param name="array">The array to create a DenseTensor<T> from.</param>
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): row-major. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): column-major.</param>
/// <returns>A 2-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns>
/// Creates a copy of this three-dimensional array as a DenseTensor<T>
/// </summary>
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam>
/// <param name="array">The array to create a DenseTensor<T> from.</param>
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.</param>
/// <returns>A 3-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns>
/// Creates a copy of this four-dimensional array as a DenseTensor<T>
/// </summary>
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam>
/// <param name="array">The array to create a DenseTensor<T> from.</param>
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.</param>
/// <returns>A 4-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns>
/// Creates a copy of this n-dimensional array as a DenseTensor<T>
/// </summary>
/// <typeparam name="T">Type contained in the array to copy to the DenseTensor<T>.</typeparam>
/// <param name="array">The array to create a DenseTensor<T> from.</param>
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.</param>
/// <returns>A n-dimensional DenseTensor<T> with the same dimensions and content as <paramref name="array"/>.</returns>
/// Various methods for creating and manipulating Tensor<T>
/// </summary>
publicstaticpartialclassTensor
{
/// <summary>
/// Creates an identity tensor of the specified size. An identity tensor is a two dimensional tensor with 1s in the diagonal.
/// </summary>
/// <typeparam name="T">type contained within the Tensor. Typically a value type such as int, double, float, etc.</typeparam>
/// <param name="size">Width and height of the identity tensor to create.</param>
/// <returns>a <paramref name="size"/> by <paramref name="size"/> with 1s along the diagonal and zeros elsewhere.</returns>
publicstaticTensor<T>CreateIdentity<T>(intsize)
{
returnCreateIdentity(size,false,Tensor<T>.One);
}
/// <summary>
/// Creates an identity tensor of the specified size and layout (row vs column major). An identity tensor is a two dimensional tensor with 1s in the diagonal.
/// </summary>
/// <typeparam name="T">type contained within the Tensor. Typically a value type such as int, double, float, etc.</typeparam>
/// <param name="size">Width and height of the identity tensor to create.</param>
/// <param name="columMajor">>False to indicate that the first dimension is most minor (closest) and the last dimension is most major (farthest): row-major. True to indicate that the last dimension is most minor (closest together) and the first dimension is most major (farthest apart): column-major.</param>
/// <returns>a <paramref name="size"/> by <paramref name="size"/> with 1s along the diagonal and zeros elsewhere.</returns>
/// Creates an identity tensor of the specified size and layout (row vs column major) using the specified one value. An identity tensor is a two dimensional tensor with 1s in the diagonal. This may be used in case T is a type that doesn't have a known 1 value.
/// </summary>
/// <typeparam name="T">type contained within the Tensor. Typically a value type such as int, double, float, etc.</typeparam>
/// <param name="size">Width and height of the identity tensor to create.</param>
/// <param name="columMajor">>False to indicate that the first dimension is most minor (closest) and the last dimension is most major (farthest): row-major. True to indicate that the last dimension is most minor (closest together) and the first dimension is most major (farthest apart): column-major.</param>
/// <param name="oneValue">Value of <typeparamref name="T"/> that is used along the diagonal.</param>
/// <returns>a <paramref name="size"/> by <paramref name="size"/> with 1s along the diagonal and zeros elsewhere.</returns>
/// Creates a n+1-rank tensor using the specified n-rank diagonal. Values not on the diagonal will be filled with zeros.
/// </summary>
/// <typeparam name="T">type contained within the Tensor. Typically a value type such as int, double, float, etc.</typeparam>
/// <param name="diagonal">Tensor representing the diagonal to build the new tensor from.</param>
/// <returns>A new tensor of the same layout and order as <paramref name="diagonal"/> of one higher rank, with the values of <paramref name="diagonal"/> along the diagonal and zeros elsewhere.</returns>
/// Initialize a 1-dimensional tensor of the specified length
/// </summary>
/// <param name="length">Size of the 1-dimensional tensor</param>
protectedTensor(intlength):base(typeof(T))
{
dimensions=new[]{length};
strides=new[]{1};
isReversedStride=false;
this.length=length;
}
/// <summary>
/// Initialize an n-dimensional tensor with the specified dimensions and layout. ReverseStride=true gives a stride of 1-element width to the first dimension (0). ReverseStride=false gives a stride of 1-element width to the last dimension (n-1).
/// </summary>
/// <param name="dimensions">An span of integers that represent the size of each dimension of the Tensor to create.</param>
/// <param name="reverseStride">False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.</param>
/// True if strides are reversed (AKA Column-major)
/// </summary>
publicboolIsReversedStride=>isReversedStride;
/// <summary>
/// Returns a readonly view of the dimensions of this tensor.
/// </summary>
publicReadOnlySpan<int>Dimensions=>dimensions;
/// <summary>
/// Returns a readonly view of the strides of this tensor.
/// </summary>
publicReadOnlySpan<int>Strides=>strides;
/// <summary>
/// Sets all elements in Tensor to <paramref name="value"/>.
/// </summary>
/// <param name="value">Value to fill</param>
publicvirtualvoidFill(Tvalue)
{
for(inti=0;i<Length;i++)
{
SetValue(i,value);
}
}
/// <summary>
/// Creates a shallow copy of this tensor, with new backing storage.
/// </summary>
/// <returns>A shallow copy of this tensor.</returns>
publicabstractTensor<T>Clone();
/// <summary>
/// Creates a new Tensor with the same layout and dimensions as this tensor with elements initialized to their default value.
/// </summary>
/// <returns>A new Tensor with the same layout and dimensions as this tensor with elements initialized to their default value.</returns>
publicvirtualTensor<T>CloneEmpty()
{
returnCloneEmpty<T>(dimensions);
}
/// <summary>
/// Creates a new Tensor with the specified dimensions and the same layout as this tensor with elements initialized to their default value.
/// </summary>
/// <param name="dimensions">An span of integers that represent the size of each dimension of the DenseTensor to create.</param>
/// <returns>A new Tensor with the same layout as this tensor and specified <paramref name="dimensions"/> with elements initialized to their default value.</returns>
/// Creates a new Tensor of a different type with the same layout and size as this tensor with elements initialized to their default value.
/// </summary>
/// <typeparam name="TResult">Type contained within the new Tensor. Typically a value type such as int, double, float, etc.</typeparam>
/// <returns>A new Tensor with the same layout and dimensions as this tensor with elements of <typeparamref name="TResult"/> type initialized to their default value.</returns>
publicvirtualTensor<TResult>CloneEmpty<TResult>()
{
returnCloneEmpty<TResult>(dimensions);
}
/// <summary>
/// Creates a new Tensor of a different type with the specified dimensions and the same layout as this tensor with elements initialized to their default value.
/// </summary>
/// <typeparam name="TResult">Type contained within the new Tensor. Typically a value type such as int, double, float, etc.</typeparam>
/// <param name="dimensions">An span of integers that represent the size of each dimension of the DenseTensor to create.</param>
/// <returns>A new Tensor with the same layout as this tensor of specified <paramref name="dimensions"/> with elements of <typeparamref name="TResult"/> type initialized to their default value.</returns>
/// Gets the n-1 dimension diagonal from the n dimension tensor.
/// </summary>
/// <returns>An n-1 dimension tensor with the values from the main diagonal of this tensor.</returns>
publicTensor<T>GetDiagonal()
{
returnGetDiagonal(0);
}
/// <summary>
/// Gets the n-1 dimension diagonal from the n dimension tensor at the specified offset from center.
/// </summary>
/// <param name="offset">Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above.</param>
/// <returns>An n-1 dimension tensor with the values from the specified diagonal of this tensor.</returns>
publicTensor<T>GetDiagonal(intoffset)
{
// Get diagonal of first two dimensions for all remaining dimensions
// diagnonal is as follows:
// { 1, 2, 4 }
// { 8, 3, 9 }
// { 0, 7, 5 }
// The diagonal at offset 0 is { 1, 3, 5 }
// The diagonal at offset 1 is { 2, 9 }
// The diagonal at offset -1 is { 8, 7 }
if(Rank<2)
{
thrownewInvalidOperationException($"Cannot compute diagonal of {nameof(Tensor<T>)} with Rank less than 2.");
}
// TODO: allow specification of axis1 and axis2?
varaxisLength0=dimensions[0];
varaxisLength1=dimensions[1];
// the diagonal will be the length of the smaller axis
// if offset it positive, the length will shift along the second axis
// if the offsett is negative, the length will shift along the first axis
/// Gets a tensor representing the elements below and including the diagonal, with the rest of the elements zero-ed.
/// </summary>
/// <returns>A tensor with the values from this tensor at and below the main diagonal and zeros elsewhere.</returns>
publicTensor<T>GetTriangle()
{
returnGetTriangle(0,upper:false);
}
/// <summary>
/// Gets a tensor representing the elements below and including the specified diagonal, with the rest of the elements zero-ed.
/// </summary>
/// <param name="offset">Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above.</param>
/// <returns>A tensor with the values from this tensor at and below the specified diagonal and zeros elsewhere.</returns>
publicTensor<T>GetTriangle(intoffset)
{
returnGetTriangle(offset,upper:false);
}
/// <summary>
/// Gets a tensor representing the elements above and including the diagonal, with the rest of the elements zero-ed.
/// </summary>
/// <returns>A tensor with the values from this tensor at and above the main diagonal and zeros elsewhere.</returns>
publicTensor<T>GetUpperTriangle()
{
returnGetTriangle(0,upper:true);
}
/// <summary>
/// Gets a tensor representing the elements above and including the specified diagonal, with the rest of the elements zero-ed.
/// </summary>
/// <param name="offset">Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above.</param>
/// <returns>A tensor with the values from this tensor at and above the specified diagonal and zeros elsewhere.</returns>
publicTensor<T>GetUpperTriangle(intoffset)
{
returnGetTriangle(offset,upper:true);
}
/// <summary>
/// Implementation method for GetTriangle, GetLowerTriangle, GetUpperTriangle
/// </summary>
/// <param name="offset">Offset of diagonal to set in returned tensor.</param>
/// <param name="upper">true for upper triangular and false otherwise</param>
/// <returns></returns>
publicTensor<T>GetTriangle(intoffset,boolupper)
{
if(Rank<2)
{
thrownewInvalidOperationException($"Cannot compute triangle of {nameof(Tensor<T>)} with Rank less than 2.");
}
// Similar to get diagonal except it gets every element below and including the diagonal.
/// Gets the value at the specied index, where index is a linearized version of n-dimension indices using strides.
/// </summary>
/// <param name="index">An integer index computed as a dot-product of indices.</param>
/// <returns>The value at the specified position in this Tensor.</returns>
publicabstractTGetValue(intindex);
/// <summary>
/// Sets the value at the specied index, where index is a linearized version of n-dimension indices using strides.
/// </summary>
/// <param name="index">An integer index computed as a dot-product of indices.</param>
/// <param name="value">The new value to set at the specified position in this Tensor.</param>
publicabstractvoidSetValue(intindex,Tvalue);
#regionstatics
/// <summary>
/// Performs a value comparison of the content and shape of two tensors. Two tensors are equal if they have the same shape and same value at every set of indices. If not equal a tensor is greater or less than another tensor based on the first non-equal element when enumerating in linear order.
/// Performs a value equality comparison of the content of two tensors. Two tensors are equal if they have the same shape and same value at every set of indices.
thrownewArgumentException("Only single dimensional arrays are supported for the requested action.",nameof(array));
}
if(array.Length<index+Length)
{
thrownewArgumentException("The number of elements in the Tensor is greater than the available space from index to the end of the destination array.",nameof(array));
}
for(inti=0;i<length;i++)
{
array.SetValue(GetValue(i),index+i);
}
}
}
#endregion
#regionIListmembers
objectIList.this[intindex]
{
get
{
returnGetValue(index);
}
set
{
try
{
SetValue(index,(T)value);
}
catch(InvalidCastException)
{
thrownewArgumentException($"The value \"{value}\" is not of type \"{typeof(T)}\" and cannot be used in this generic collection.");
}
}
}
/// <summary>
/// Always fixed size Tensor
/// </summary>
/// <value>always true</value>
publicboolIsFixedSize=>true;
/// <summary>
/// Tensor is not readonly
/// </summary>
/// <value>always false</value>
publicboolIsReadOnly=>false;
intIList.Add(objectvalue)
{
thrownewInvalidOperationException();
}
voidIList.Clear()
{
Fill(default(T));
}
boolIList.Contains(objectvalue)
{
if(IsCompatibleObject(value))
{
returnContains((T)value);
}
returnfalse;
}
intIList.IndexOf(objectvalue)
{
if(IsCompatibleObject(value))
{
returnIndexOf((T)value);
}
return-1;
}
voidIList.Insert(intindex,objectvalue)
{
thrownewInvalidOperationException();
}
voidIList.Remove(objectvalue)
{
thrownewInvalidOperationException();
}
voidIList.RemoveAt(intindex)
{
thrownewInvalidOperationException();
}
#endregion
#regionIEnumerable<T>members
IEnumerator<T>IEnumerable<T>.GetEnumerator()
{
for(inti=0;i<Length;i++)
{
yieldreturnGetValue(i);
}
}
#endregion
#regionICollection<T>members
intICollection<T>.Count=>(int)Length;
voidICollection<T>.Add(Titem)
{
thrownewInvalidOperationException();
}
voidICollection<T>.Clear()
{
Fill(default(T));
}
boolICollection<T>.Contains(Titem)
{
returnContains(item);
}
/// <summary>
/// Determines whether an element is in the Tensor<T>.
/// </summary>
/// <param name="item">
/// The object to locate in the Tensor<T>. The value can be null for reference types.
/// </param>
/// <returns>
/// true if item is found in the Tensor<T>; otherwise, false.
/// </returns>
protectedvirtualboolContains(Titem)
{
returnLength!=0&&IndexOf(item)!=-1;
}
voidICollection<T>.CopyTo(T[]array,intarrayIndex)
{
CopyTo(array,arrayIndex);
}
/// <summary>
/// Copies the elements of the Tensor<T> to an Array, starting at a particular Array index.
/// </summary>
/// <param name="array">
/// The one-dimensional Array that is the destination of the elements copied from Tensor<T>. The Array must have zero-based indexing.
/// </param>
/// <param name="arrayIndex">
/// The zero-based index in array at which copying begins.
thrownewArgumentException("The number of elements in the Tensor is greater than the available space from index to the end of the destination array.",nameof(array));
}
for(inti=0;i<length;i++)
{
array[arrayIndex+i]=GetValue(i);
}
}
boolICollection<T>.Remove(Titem)
{
thrownewInvalidOperationException();
}
#endregion
#regionIReadOnlyCollection<T>members
intIReadOnlyCollection<T>.Count=>(int)Length;
#endregion
#regionIList<T>members
TIList<T>.this[intindex]
{
get{returnGetValue(index);}
set{SetValue(index,value);}
}
intIList<T>.IndexOf(Titem)
{
returnIndexOf(item);
}
/// <summary>
/// Determines the index of a specific item in the Tensor<T>.
/// </summary>
/// <param name="item">The object to locate in the Tensor<T>.</param>
/// <returns>The index of item if found in the tensor; otherwise, -1.</returns>
// this ignores shape, which is fine it just means we'll have hash collisions for things
// with the same content and different shape.
for(inti=0;i<Length;i++)
{
hashCode^=comparer.GetHashCode(GetValue(i));
}
returnhashCode;
}
#endregion
#regionTranslations
/// <summary>
/// Creates a copy of this tensor as a DenseTensor<T>. If this tensor is already a DenseTensor<T> calling this method is equivalent to calling Clone().
/// Runs the loaded model for the given inputs, and fetches the specified outputs in <paramref name="outputNames"/>. Uses the given RunOptions for this run.
/// </summary>
/// <param name="options">Specify <see cref="RunOptions"/> for step.</param>
/// <param name="inputValues">Specify a collection of <see cref="FixedBufferOnnxValue"/> that indicates the input values.</param>
/// <returns>Output Tensors in a Collection of NamedOnnxValue. User must dispose the output.</returns>
Special case .NET Core portable applications. When building a portable .NET Core app,
the PlatformTarget is empty, and you don't know until runtime (i.e. which dotnet.exe)
what processor architecture will be used.
-->
<ErrorCondition="('$(PlatformTarget)' != 'x64' AND '$(PlatformTarget)' != 'arm32' AND '$(PlatformTarget)' != 'arm64' AND '$(PlatformTarget)' != 'x86' AND '$(PlatformTarget)' != 'AnyCPU') AND
('$(OutputType)' == 'Exe' OR '$(OutputType)'=='WinExe') AND
!('$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND '$(PlatformTarget)' == '') AND
('$(TargetFrameworkIdentifier)' != 'Xamarin.iOS' AND
$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'ios') AND