A Tour of Morfa

Basic operators


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.

Indexing and slicing

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
// ...