Skip to content

Element-wise expressions

Lazy element-wise operations: operators, math functions, masks and pipes.

Nothing is computed until an expression is assigned or made into a tensor.

Concepts

Name Description
left_foldable Whether a chain (a op b) op c of Fn may be stored as one node over a, b, c.
stateless A functor without state: every instance is as good as Fn{}, so none needs to be kept.

Types

Name Description
BitAnd & folded over two or more values: bitwise on integers, logical on bool.
BitNot ~operand: bitwise on integers, logical NOT on bool.
BitOr | folded over two or more values: bitwise on integers, logical on bool.
BitXor ^ folded over two or more values: bitwise on integers, logical on bool.
Clamp value brought into [low, high], as std::clamp does it.
Divides Quotient of two or more values, applied as a left fold: Divides{}(a, b, c) is (a / b) / c.
EqualTo lhs == rhs as a bool.
Ewise An element-wise expression: fn(operands[i...]...) for every index, computed when assigned, not before.
Greater lhs > rhs as a bool.
GreaterEqual lhs >= rhs as a bool.
Less lhs < rhs as a bool.
LessEqual lhs <= rhs as a bool.
LogicalNot !operand as a bool.
Maximum The larger of two values, as std::max chooses: the first of equal ones.
Minimum The smaller of two values, as std::min chooses: the first of equal ones.
Minus Difference of two or more values, applied as a left fold: Minus{}(a, b, c) is (a - b) - c.
Multiplies Product of two or more values, applied as a left fold: Multiplies{}(a, b, c) is (a * b) * c.
Negate Unary minus of a value.
NotEqualTo lhs != rhs as a bool.
Plus Sum of two or more values, applied as a left fold: Plus{}(a, b, c) is (a + b) + c.
Scalar A value used as an operand, as in view * 2 or lengths * Speed{3.0}.
Select Chooses when_true or when_false by condition, which is a bool and nothing that converts to one.
Square operand * operand.

Functions

operator+

template <typename L, typename R>
constexpr auto operator+(L &&lhs, R &&rhs)

Element-wise sum, as a lazy expression.

Either side may be a scalar, but not both. a + b + c is one node over three operands.

Precondition

The tensor operands have equal extents.

operator-

template <typename L, typename R>
constexpr auto operator-(L &&lhs, R &&rhs)

Element-wise difference, as a lazy expression.

Either side may be a scalar, but not both.

Precondition

The tensor operands have equal extents.

template <typename E>
constexpr auto operator-(E &&operand)

Element-wise negation, as a lazy expression.

operator*

template <typename L, typename R>
constexpr auto operator*(L &&lhs, R &&rhs)

Element-wise product, as a lazy expression.

Either side may be a scalar, but not both. Element by element, as in NumPy; the matrix product is a contraction (einsum), not *.

Precondition

The tensor operands have equal extents.

operator/

template <typename L, typename R>
constexpr auto operator/(L &&lhs, R &&rhs)

Element-wise quotient, as a lazy expression.

Either side may be a scalar, but not both.

Precondition

The tensor operands have equal extents.

operator<

template <typename L, typename R>
constexpr auto operator<(L &&lhs, R &&rhs)

Element-wise lhs < rhs, as a mask of bool.

Also <=, > and >=. == and != are not among the element-wise operators: they answer whether two things are equal, in a single bool, as std::equality_comparable, std::ranges::find and every test expect. Use equal and not_equal for masks. Integers of different signedness are compared by value, so -1 < 0u is true.

Precondition

The tensor operands have equal extents.

operator<=

template <typename L, typename R>
constexpr auto operator<=(L &&lhs, R &&rhs)

Element-wise lhs <= rhs, as a mask of bool; see operator<.

operator>

template <typename L, typename R>
constexpr auto operator>(L &&lhs, R &&rhs)

Element-wise lhs > rhs, as a mask of bool; see operator<.

operator>=

template <typename L, typename R>
constexpr auto operator>=(L &&lhs, R &&rhs)

Element-wise lhs >= rhs, as a mask of bool; see operator<.

operator!

template <typename E>
constexpr auto operator!(E &&operand)

Element-wise logical NOT of a mask, as a lazy expression of bool.

&& and || are not overloaded, as overloads they would no longer short-circuit: use & and | on masks.

operator~

template <typename E>
constexpr auto operator~(E &&operand)

Element-wise ~: bitwise on integers, logical NOT on bool.

operator&

template <typename L, typename R>
constexpr auto operator&(L &&lhs, R &&rhs)

Element-wise &: bitwise on integers, logical AND on bool masks.

Chains of one operation are one node, as for +.

Precondition

The tensor operands have equal extents.

operator|

template <typename L, typename R>
constexpr auto operator|(L &&lhs, R &&rhs)

Element-wise |: bitwise on integers, logical OR on bool masks.

Chains of one operation are one node, as for +.

Note

A pipeable on either side makes | a pipe instead (see pipeable); as a scalar operand, bool | abs would be a bitwise OR of whatever | makes of them.

Precondition

The tensor operands have equal extents.

operator^

template <typename L, typename R>
constexpr auto operator^(L &&lhs, R &&rhs)

Element-wise ^: bitwise on integers, logical XOR on bool masks.

Chains of one operation are one node, as for +.

Precondition

The tensor operands have equal extents.

Variables

map

constexpr detail::map_fn map {}

fn(operands[i...]...) for every index: any function of the values, as an expression.

A stateless fn, a lambda without captures, takes no space in the expression. On scalars alone the result is the function's value. Called with fn only, map(fn) waits for its operand and is pipeable: x | map(fn).

const auto shifted = map([offset](int x) { return x + offset; }, view);
const auto mixed = map([](int x, int y, int z) { return (x * y) - z; }, a, b, 1);

Precondition

The tensor operands have equal extents.

equal

constexpr detail::elementwise_fn<EqualTo> equal {}

Element-wise equality, as a mask of bool.

Equality is a function rather than ==, which stays a single bool answer for whether two things are equal. Integers of different signedness are compared by value. Either argument may be a scalar.

not_equal

constexpr detail::elementwise_fn<NotEqualTo> not_equal {}

Element-wise inequality, as a mask of bool.

See equal.

negate

constexpr detail::elementwise_fn<Negate> negate {}

Element-wise negation, as a function object: negate(x), x | negate; the value of -x.

plus

constexpr detail::elementwise_fn<Plus> plus {}

Element-wise sum, as a function object: plus(a, b), x | plus(y); the value of a + b.

minus

constexpr detail::elementwise_fn<Minus> minus {}

Element-wise difference, as a function object: minus(a, b), x | minus(y) is x - y.

multiplies

constexpr detail::elementwise_fn<Multiplies> multiplies {}

Element-wise product, as a function object: multiplies(a, b), x | multiplies(y) is x * y.

divides

constexpr detail::elementwise_fn<Divides> divides {}

Element-wise quotient, as a function object: divides(a, b), x | divides(y) is x / y.

less

constexpr detail::elementwise_fn<Less> less {}

Element-wise <, as a function object and a mask of bool: x | less(y) is x < y.

less_equal

constexpr detail::elementwise_fn<LessEqual> less_equal {}

Element-wise <=, as a function object; see less.

greater

constexpr detail::elementwise_fn<Greater> greater {}

Element-wise >, as a function object; see less.

greater_equal

constexpr detail::elementwise_fn<GreaterEqual> greater_equal {}

Element-wise >=, as a function object; see less.

logical_not

constexpr detail::elementwise_fn<LogicalNot> logical_not {}

Element-wise logical NOT of a mask, as a function object: mask | logical_not is !mask.

bit_not

constexpr detail::elementwise_fn<BitNot> bit_not {}

Element-wise ~, as a function object; see operator~.

bit_and

constexpr detail::elementwise_fn<BitAnd> bit_and {}

Element-wise &, as a function object: mask | bit_and(other) is mask & other.

bit_or

constexpr detail::elementwise_fn<BitOr> bit_or {}

Element-wise |, as a function object: mask | bit_or(other) is mask | other.

bit_xor

constexpr detail::elementwise_fn<BitXor> bit_xor {}

Element-wise ^, as a function object; see bit_and.

where

constexpr detail::elementwise_fn<Select> where {}

Chooses element-wise: where(condition, when_true, when_false).

The condition is a mask of bool, not a number. The branches may be tensors or scalars; the value type is the common type of the two.

const auto relu = where(a > 2, a, 0);
const auto sign = where(a < 3, 1, -1);

Precondition

The tensor operands have equal extents.

abs

constexpr detail::elementwise_fn<Abs> abs {}

Absolute value of each element.

Note

In a constant expression abs is the only portable function here: most of <cmath> is constexpr under GCC, not under Clang.

sqrt

constexpr detail::elementwise_fn<Sqrt> sqrt {}

Square root of each element.

cbrt

constexpr detail::elementwise_fn<Cbrt> cbrt {}

Cube root of each element.

exp

constexpr detail::elementwise_fn<Exp> exp {}

e raised to each element.

exp2

constexpr detail::elementwise_fn<Exp2> exp2 {}

2 raised to each element.

expm1

constexpr detail::elementwise_fn<Expm1> expm1 {}

exp(x) - 1 of each element, accurate for x near zero.

log

constexpr detail::elementwise_fn<Log> log {}

Natural logarithm of each element.

log2

constexpr detail::elementwise_fn<Log2> log2 {}

Base-2 logarithm of each element.

log10

constexpr detail::elementwise_fn<Log10> log10 {}

Base-10 logarithm of each element.

log1p

constexpr detail::elementwise_fn<Log1p> log1p {}

log(1 + x) of each element, accurate for x near zero.

sin

constexpr detail::elementwise_fn<Sin> sin {}

Sine of each element, in radians.

cos

constexpr detail::elementwise_fn<Cos> cos {}

Cosine of each element, in radians.

tan

constexpr detail::elementwise_fn<Tan> tan {}

Tangent of each element, in radians.

asin

constexpr detail::elementwise_fn<Asin> asin {}

Arc sine of each element, in radians.

acos

constexpr detail::elementwise_fn<Acos> acos {}

Arc cosine of each element, in radians.

atan

constexpr detail::elementwise_fn<Atan> atan {}

Arc tangent of each element, in radians.

sinh

constexpr detail::elementwise_fn<Sinh> sinh {}

Hyperbolic sine of each element.

cosh

constexpr detail::elementwise_fn<Cosh> cosh {}

Hyperbolic cosine of each element.

tanh

constexpr detail::elementwise_fn<Tanh> tanh {}

Hyperbolic tangent of each element.

floor

constexpr detail::elementwise_fn<Floor> floor {}

Each element rounded down to an integral value.

ceil

constexpr detail::elementwise_fn<Ceil> ceil {}

Each element rounded up to an integral value.

round

constexpr detail::elementwise_fn<Round> round {}

Each element rounded to the nearest integral value, halfway cases away from zero.

trunc

constexpr detail::elementwise_fn<Trunc> trunc {}

Each element rounded toward zero to an integral value.

isnan

constexpr detail::elementwise_fn<IsNan> isnan {}

Mask of the elements that are NaN.

isinf

constexpr detail::elementwise_fn<IsInf> isinf {}

Mask of the elements that are infinite.

isfinite

constexpr detail::elementwise_fn<IsFinite> isfinite {}

Mask of the elements that are neither infinite nor NaN.

pow

constexpr detail::elementwise_fn<Pow> pow {}

First operand raised to the second, element by element.

atan2

constexpr detail::elementwise_fn<Atan2> atan2 {}

Arc tangent of y / x from the signs of both, in radians: atan2(y, x).

hypot

constexpr detail::elementwise_fn<Hypot> hypot {}

sqrt(x*x + y*y) without undue overflow or underflow, element by element.

fmod

constexpr detail::elementwise_fn<Fmod> fmod {}

Remainder of x / y with the sign of x, element by element.

square

constexpr detail::elementwise_fn<Square> square {}

x * x of each element.

This is what pow(x, 2) should be and is not quite: std::pow(float, int) is a double.

minimum

constexpr detail::elementwise_fn<Minimum> minimum {}

The smaller of two, element by element, as std::min chooses: the first of equal ones.

Named as in NumPy, so as not to be taken for std::min, which compares two values and returns a reference.

maximum

constexpr detail::elementwise_fn<Maximum> maximum {}

The larger of two, element by element, as std::max chooses; see minimum.

clamp

constexpr detail::elementwise_fn<Clamp> clamp {}

clamp(value, low, high): each element brought into [low, high], as std::clamp does it.

With only low and high, clamp(-1.0, 1.0) waits for its operand in a pipe: x | clamp(-1.0, 1.0).

Precondition

low <= high (not checked).

dense_in< Scalar< T >, O >

template <typename T, typename O>
constexpr bool dense_in<Scalar<T>, O> = true

A scalar is dense in every order: it has no memory to walk.

Aliases

Abs

using strata::Abs = detail::math::Abs

Function object of abs.

Sqrt

using strata::Sqrt = detail::math::Sqrt

Function object of sqrt.

Cbrt

using strata::Cbrt = detail::math::Cbrt

Function object of cbrt.

Exp

using strata::Exp = detail::math::Exp

Function object of exp.

Exp2

using strata::Exp2 = detail::math::Exp2

Function object of exp2.

Expm1

using strata::Expm1 = detail::math::Expm1

Function object of expm1.

Log

using strata::Log = detail::math::Log

Function object of log.

Log2

using strata::Log2 = detail::math::Log2

Function object of log2.

Log10

using strata::Log10 = detail::math::Log10

Function object of log10.

Log1p

using strata::Log1p = detail::math::Log1p

Function object of log1p.

Sin

using strata::Sin = detail::math::Sin

Function object of sin.

Cos

using strata::Cos = detail::math::Cos

Function object of cos.

Tan

using strata::Tan = detail::math::Tan

Function object of tan.

Asin

using strata::Asin = detail::math::Asin

Function object of asin.

Acos

using strata::Acos = detail::math::Acos

Function object of acos.

Atan

using strata::Atan = detail::math::Atan

Function object of atan.

Sinh

using strata::Sinh = detail::math::Sinh

Function object of sinh.

Cosh

using strata::Cosh = detail::math::Cosh

Function object of cosh.

Tanh

using strata::Tanh = detail::math::Tanh

Function object of tanh.

Floor

using strata::Floor = detail::math::Floor

Function object of floor.

Ceil

using strata::Ceil = detail::math::Ceil

Function object of ceil.

Round

using strata::Round = detail::math::Round

Function object of round.

Trunc

using strata::Trunc = detail::math::Trunc

Function object of trunc.

IsNan

using strata::IsNan = detail::math::IsNan

Function object of isnan.

IsInf

using strata::IsInf = detail::math::IsInf

Function object of isinf.

IsFinite

using strata::IsFinite = detail::math::IsFinite

Function object of isfinite.

Pow

using strata::Pow = detail::math::Pow

Function object of pow.

Atan2

using strata::Atan2 = detail::math::Atan2

Function object of atan2.

Hypot

using strata::Hypot = detail::math::Hypot

Function object of hypot.

Fmod

using strata::Fmod = detail::math::Fmod

Function object of fmod.