In a recent Mathematica project, $(n \times 0)$- and $(0 \times n)$-dimensional matrices have suddenly become a frustratingly common edge case for me. For instance, consider the following two situations, both common in linear algebra programming:
Suppose we have a matrix $A$, presenting a linear transformation $\newcommand{\R}{\mathbb{R}}\R^n \to \R^m$. The kernel of $A$ is a particular subspace of the source, $\R^n$, and if $A$ has a kernel of dimension $d > 0$, then
NullSpace[A]
produces a new matrix presenting a map $\R^d \to \R^n$ whose image is $\ker A$. This mode of thought is very useful; it lets you, for instance, restrict the action of some other map $B: \R^n \to \R^l$ to the kernel of $A$ by multiplication:B.Transpose[NullSpace[A]]
.Suppose we have a pair of matrices $A$ and $B$, presenting a pair of linear transformations $\R^n \xrightarrow{A} \R^l \xleftarrow{B} \R^m$ with a common target. The pullback or generalized intersection of these two maps is defined to be the collection of pairs of vectors $(x, y) \in \R^n \times \R^m$ with $Ax = By$. This, too, is easy enough to model in Mathematica: the
NullSpace
of the block matrix $\left[\begin{array}{c|c}A & -B\end{array}\right]$ splits into a block matrix itself $\left[\begin{array}{c}P \\ \hline Q \end{array}\right]$. The matrices $P$ and $Q$ present the "largest nontrivial" maps into $\R^n$ and $\R^m$ respectively with the property that $AP = BQ$.
While the mathematics continues to make sense, both of these run into serious difficulties when $0$-dimensional vector spaces get involved. This happens all the time in both situations (and, generally, in any situation where you might be applying NullSpace
to a matrix with trivial kernel): because Mathematica models matrices as lists of lists (with some exceptions, like SparseArray
s, which have to support conversion to lists of lists anyway), it has real trouble modeling an $(n \times 0)$-dimensional matrix. For instance, NullSpace[ IdentityMatrix[n]]
returns {}
, which at first glance is reasonable enough but is totally unsuited for uniformly handling the above procedures. The expression {}
is not $(n \times 0)$-dimensional in any sense, and so matrix multiplication, transposition(, inversion in the case $n = 0$), and so on all balk at using this as input.
This is surmountable, of course, by riddling my Mathematica code with conditionals that check for this failure output and handle it separately. This is uglier than it sounds (and it already sounds ugly); oftentimes this means passing around extra information to keep track of the n
involved, since it's not recoverable from {}
.
My question is: Is there a cleaner solution than a sea of conditionals? Is there an idiomatic way to model $(n \times 0)$- and $(0 \times n)$-dimensional matrices in Mathematica, ideally in a way that's near-seamlessly compatible with standard routines like
Times
,Transpose
,ArrayFlatten
, ...?
(P.S.: I eventually intend to offer this thing I'm writing as a package, and so I'd prefer not to modify the behavior of built-in functions directly.)