Mathematical Operations

Numerics.NET provides methods for all common operations on tensors. Where applicable, overloaded operator methods are supplied for languages that support them, including element-wise operators in F#. In addition, a series of instance methods have been defined. These provide more efficient use of resources. All instance methods return a reference to the (modified) instance. This enables their use in compound expressions.

Overview of Methods

All standard operations are performed elementwise. In particular, both multiplication and division are performed elementwise and do not perform matrix products or solve natrix equations.

All operations can be performed on any combination of tensor types. The return value is always an instance of type Tensor<T>. The actual return value is of a derived type that is chosen for optimal performance.

Operators

If the corresponding operation on scalars has an operator, then the same operator can be used to perform the operation on corresponding elements of two tensors.

C#
var a = Tensor.CreateFromArray([1, 2, 3]);
var b = Tensor.CreateFromArray([2, 3, 4]);
var c = a + b;
// c -> [ 3, 5, 7 ]
var d = -a;
// d -> [ -1, -2, -3 ]

For binary operations, one of the operands can be a scalar. In this case, the scalar is treated as if it is a tensor with the same value everywhere and of the same shape as the other operand.

C#
var e = a + 4;
// e -> [ 5, 6, 7 ]

Static methods

Every operation has a static method in the Tensor class that names the operation, for example Tensor.Add<T>(Tensor<T>, Tensor<T>, Tensor<T>, Tensor<Boolean>, TensorElementOrder). These methods take the element type of the tensors as a generic type argument. In nearly all cases, the element type can be inferred and the type argument can be omitted.

They take the arguments of the operation as required parameters, which may be followed by a number of optional arguments:

result

A tensor that is to hold the result of the operation. The default is null. If given, the tensor must have compatible dimensions.

mask

A boolean tensor that specifies the locations where the operation should be performed. The shape of this tensor must be compatible with the other arguments and (if present) the result. Only locations where this tensor is true are included in the operation. Otherwise, the result is unchanged.

order

When the result is omitted or null, this argument specifies the desired layout of the result. The default is C-style (row-major) order.

These methods are useful to reuse an existing tensor instance, to avoid unnecessary memory allocation.

C#
Tensor.Add(a, b, d);
// d -> [ 3, 5, 7 ]
var mask = Tensor.CreateFromArray([true, false, true]);
Tensor.Add(a, 4, e, mask: mask);
// e -> [ 5, 2, 7 ]

In-place operations

C# and Visual Basic do not support overloading of compound assignment operators like +=. Instead, an expression like a += b is interpreted as a = a + b. For tensors, this means that a new tensor is created and assigned to the variable in the left-hand side. It is often more efficient to explicitly specify that the operation should be performed in-place.

To this end, most operations have an instance method in the Tensor<T> class that names the operation and has an InPlace suffix, for example Tensor<T>.AddInPlace(T, Tensor<Boolean>). These methods perform the operation in-place, directly on the instance they are called on, and also return the instance. In-place operations support a condition argument.

C#
a.AddInPlace(4);
// a -> [ 5, 6, 7 ]
b.NegateInPlace(mask: mask);
// b -> [ -2, 3, -4 ]

Relational operators

Relational operators require some special attention because their meaning is somewhat ambiguous.

The == and != (or <>) operators retain their usual meaning. Two tensors compare as equal if they have the same shape and all corresponding elements are equal. Otherwise they compare as not equal.

To obtain an elementwise comparison that compares corresponding elements and returns a tensor of boolean values, use the EqualTo or the NotEqualTo method.

Other relational operators (<, <=, >, >=) operate elementwise and return a tensor of boolean values.

C#
a = Tensor.CreateFromArray([5, 6, 7]);
b = Tensor.CreateFromArray([3, 5, 7]);
var x = a == b;
// x -> false
var y = Tensor.EqualTo(a, b);
// y -> [ false, false, true ]
var z = a > b;
// a -> [ true, true, false ]

Mixing operand types

Operations on tensors are generally defined only for tensors with the same element type. In some cases it can be useful to mix operands of different types. For example, you may want to add a tensor of integers to a tensor of floating-point numbers. This can be done by explicitly converting one of the operands to the other type using the As method. This method returns a new tensor of the specified type that shares its storage with the original tensor and converts the elements only as needed.

C#
var t1 = Tensor.CreateFromArray([0.5, 1.5, 2.5]);
a = Tensor.CreateFromArray([1, 2, 3]);
var t2 = t1 + a.As<double>();
// t2 -> [ 1.5, 3.5, 5.5 ]

Supported operations

Besides the usual binary operators, several common compound operations are supported. The following tables list the main methods for addition and subtraction:

Arithmetic Operators

Operators and methods for addition and subtraction

Method

Operator

Description

Add(a, b)

a + b

Adds the elements of the tensors a and b.

Subtract(a, b)

a - b

Subtracts the elements of the tensor b from the elements of the tensor a.

Negate(a)

-a

Negates the elements of the tensor a.

Multiply(a, b)

a * b

Multiplies the elements of the tensors a and b.

Divide(a, b)

a / b

Divides the elements of the tensor a by the elements of the tensor b.

Reciprocal(a)

Divides one by the elements of the tensor a.

Pow(a, b)

a ^ b (VB)
a ** b (F#)

Raises each element of the tensor a to the power specified by the corresponding element in the tensor b. The exponents can be integers or be of the same type as the elements of the tensor a.

Relational operators

The operators in this section are all element-wise. They return a Boolean tensor with the result of comparing the corresponding elements of two tensors, or the corresponding element of a tensor and a fixed scalar. Also listed here are the Max(a, b) and Min(a, b) methods, which follow the same pattern.

Each relational method comes in three flavors: one comparing a tensor to a tensor, one comparing a scalar to a tensor, and one comparing a tensor to a scalar. The table below lists the main functions.

Relational Operators

Method

Operator

Description

EqualTo(a, b)

Tests whether the elements of the tensor a are equal to the corresponding elements of the tensor b.

NotEqualTo(a, b)

Tests whether the elements of the tensor a are not equal to the corresponding elements of the tensor b.

LessThan(a, b)

a < b

Tests whether the elements of the tensor a are less than the corresponding elements of the tensor b.

LessThanOrEqual(a, b)

a <= b

Tests whether the elements of the tensor a are less than or equal to the corresponding elements of the tensor b.

GreaterThan(a, b)

a > b

Tests whether the elements of the tensor a are greater than the corresponding elements of the tensor b.

GreaterThanOrEqual(a, b)

a >= b

Tests whether the elements of the tensor a are greater than or equal to the corresponding elements of the tensor b.

Max(a, b)

Returns the largest of two corresponding elements of the tensors a and b.

Min(a, b)

Returns the smallest of two corresponding elements of the tensors a and b.

Basic functions

The table below lists a number of basic functions that don't qualify as operators but also aren't elementary functions.

Basic Operators

Method

Description

Abs(a)

Returns the absolute value of each element of the tensor a.

Floor(a)

Returns the largest integer less than or equal to each element of the tensor.

Ceiling(a)

Returns the smallest integer less than or equal to each element of the tensor.

Conjugate(a)

Returns the complex conjugate of each element of the tensor.

Elementary functions

The table below lists the elementary functions available for tensors.

Roots

Method

Description

Sqrt(a)

Returns the square root of each element of the tensor.

Hypot(a, b)

Returns the square root of the sum of the squares of corresponding elements in two tensors.

Logarithms and Exponentials

Method

Description

Exp(a)

Returns the exponential function of each element of the tensor.

Exp2(a)

Returns 2 raised to the exponent speciied by each element of the tensor.

Exp10(a)

Returns 10 raised to the exponent speciied by each element of the tensor.

ExpM1(a)

Returns the exponential function minus 1 of each element of the tensor, computed accurately for arguments close to zero.

Log(a)

Returns the natural logarithm of each element of the tensor.

Log2(a)

Returns the base 2 logarithm of each element of the tensor.

Log10(a)

Returns the base 10 logarithm of each element of the tensor.

LogP1(a)

Returns the natural logarithm of one plus each element of the tensor, computed accurately for arguments close to zero.

Trigonometric

Method

Description

Sin(a)

Returns the sine of each element of the tensor.

Cos(a)

Returns the cosine of each element of the tensor.

Tan(a)

Returns the tangent of each element of the tensor.

Asin(a)

Returns the inverse sine of each element of the tensor.

Acos(a)

Returns the inverse cosine of each element of the tensor.

Atan(a)

Returns the inverse tangent of each element of the tensor.

Atan(y, x)

Returns the 4 quadrant inverse tangent of the ratio of corresponding elements in two tensors.

Hyperbolic

Method

Description

Sinh(a)

Returns the hyperbolic sine of each element of the tensor.

Cosh(a)

Returns the hyperbolic cosine of each element of the tensor.

Tanh(a)

Returns the hyperbolic tangent of each element of the tensor.

Asinh(a)

Returns the inverse hyperbolic sine of each element of the tensor.

Acosh(a)

Returns the inverse hyperbolic cosine of each element of the tensor.

Atanh(a)

Returns the inverse hyperbolic tangent of each element of the tensor.