The most obvious operators which serve in the matrix
DSL are the arithmetic operators like +
, -
and alike.
*
denotes matrix product, element-wise multiplication being less frequently used in matrix setting.
Such operator overloads are declared as ordinary functions:
public func *(m1: Matrix, m2: Matrix): Matrix;
allows us to write A * B
.
Another batch of operators are the indexing and slicing operators. These are also done using operator overloads, only with one twist.
First, to have A[1]
and B[1,2]
we do simple indexing by overloads:
public func $[] (m: Matrix, arg: int): Matrix;
public func $[] (m: Matrix, arg1: int, arg2: int): Matrix;
Then, having a ..
operator from morfa.base
which creates Range
object:
import morfa.base;
public func $[] (m: Matrix, arg: Range): Matrix;
public func $[] (m: Matrix, arg1: Range, arg2: Range): Matrix;
and A[0..4]
, B[0..2, 10..0 by -2]
, C[1..$,4]
slices become available, and are in line with standard morfa.base
slicing of arrays.
To have an option of doing A[0, ..]
, which is a common way of denoting taking the first (zero-th) row of A
we must do:
public func $[] (m: Matrix, func(int,Offset): Range, arg: Range): Matrix;
Here func(int,Offset): Range
is the type of the ..
.
The idea is not to use whatever is passed as this argument (note it is given no variable in the function body), just to denote its type.
Depending on the properties of the Matrix
class implementation, these $[]
may be templated and also user conversions can be employed to define all this more concisely.
In the end, $[]
may look like this:
public template <RangeTypes...>
public func $[](m: Matrix, RangeTypes): Matrix;
or this:
public func convert(r: Range): SomeGenericRangeType;
// ...
public func $[](m: Matrix, range1: SomeGenericRangeType,
range2: SomeGenericRangeType): Matrix;
The slice-assign operation is defined very much alike, substituting $[]
with $[]=
.
Then assignments as this: A[3, ..] = B[$..-1 by -1]
become fully available.
Other common matrix operations can be introduced by defining our own new operators like this:
// Transposition
public operator ᵀ
{
kind = postfix,
precedence = not
}
public alias $ᵀ = trans;
// Conjugate transpose
public operator ᴴ
{
kind = postfix,
precedence = not
}
public alias $ᴴ = ctrans;
(assuming trans
and ctrans
are appropriate functions).
Now we can write the common expression Aᵀ
to denote transpose of matrix A
.
One does not necessarily have to use a Unicode character ᵀ
, '
will work exactly the same.
It is worth noting that the power operator ^
needs similar measures, as it is not built-in in Morfa:
public operator ^
{
kind = infix,
precedence = not,
associativity = left
}
// ...