Block matrices in LaTeX, part two

Alec Jacobson

August 12, 2010

weblog/

Yesterday I made a first attempt at drawing box-like, block matrices in LaTeX. I achieved this with pure LaTeX. Today I've been able to produce much cool looking results using the vector graphics package tikz. The documentation for this package is not great, but there are a few tutorials and plenty of examples out there. With it I was able to define some new commands that I can call in LaTeX document to make beautiful colored block matrices. First include the necessary packages:
\usepackage{tikz}
\usepackage{ifthen}
Then add these new command definitions. In there are commands to make framed and unframed blocks and a command to make a diagonal (banded) matrix. There is also mumbo-jumbo macros that reduce the clutter for creating block matrix equations. Also a quick version of left and right parentheses. The unfortunate thing about switching to tikz is that for the matrices in an equation to be aligned across their tops you need to encapsulate them in the vertically aligned box command I provide, which then only really works inside a tabular environment.
% master block matrix, should use wrappers instead of calling this
% directly
% This should be called within the tikzpicture environment
% \blockmatrix
%  {width}
%  {height}
%  {text}
%  {block_line_color} (can be none --> no line)
%  {block_fill_color} (can be none --> empty fill)
%  {is_diagonal} (true --> true, otherwise --> false)
%  {diagonal_line_color} (ignored if not diagonal) (can be none --> no line)
%  {diagonal_fill_color} (ignored if not diagonal) (can be noneo --> empty fill)
%  {diagonal_offset} (half diagonal width in tikz units)
% Note: colors here are not rgb, they are defined colors
\newcommand{\blockmatrix}[9]{
  \draw[draw=#4,fill=#5] (0,0) rectangle( #1,#2);
  \ifthenelse{\equal{#6}{true}}
  {
    \draw[draw=#7,fill=#8] (0,#2) -- (#9,#2) -- ( #1,#9) -- ( #1,0) -- ( #1 - #9,0) -- (0,#2 -#9) -- cycle;
  }
  {}
  \draw ( #1/2, #2/2) node { #3};
}

% Quick implementation of a tikz right parenthesis
% \rightparen{width}
\newcommand{\rightparen}[1]{
  \begin{tikzpicture} 
    \draw (0,#1/2) arc (0:30:#1);
    \draw (0,#1/2) arc (0:-30:#1);
  \end{tikzpicture}%this comment is necessary
}

% Quick implementation of a tikz left parenthesis
% \leftparen{width}
\newcommand{\leftparen}[1]{
  \begin{tikzpicture} 
    \draw (0,#1/2) arc (180:150:#1);
    \draw (0,#1/2) arc (180:210:#1);
  \end{tikzpicture}%this comment is necessary
}

% Unframed block matrix, "m" prefix to match fbox, mbox
% \blockmatrix[r,g,b]{width}{height}{text}
\newcommand{\mblockmatrix}[4][none]{
  \begin{tikzpicture} 
  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{none}{none}{false}{none}{none}{0.0}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{none}{fillcolor}{false}{none}{none}{0.0}
  }
  \end{tikzpicture}%this comment is necessary
}

% Framed block matrix
% \fblockmatrix[r,g,b]{width}{height}{text}
\newcommand{\fblockmatrix}[4][none]{
  \begin{tikzpicture} 
  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{black}{none}{false}{none}{none}{0.0}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{black}{fillcolor}{false}{none}{none}{0.0}
  }
  \end{tikzpicture}%this comment is necessary
}

% Diagonal block matrix
% \dblockmatrix[r,g,b]{width}{height}{text}
\newcommand{\dblockmatrix}[4][none]{
  \begin{tikzpicture} 
  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{none}{0.35cm}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{fillcolor}{0.35cm}
  }
  \end{tikzpicture}%this comment is necessary
}


% Diagonal block matrix, but exposes diagonal offset
% \diagonalblockmatrix[r,g,b]{width}{height}{text}
\newcommand{\diagonalblockmatrix}[5][none]{
  \begin{tikzpicture} 

  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{none}{#5}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{fillcolor}{#5}
  }

  \end{tikzpicture}%necessary comment
}

\newcommand{\valignbox}[1]{
  \vtop{\null\hbox{#1}}% necessary comment
}

% a hack so that I don't have to worry about the number of columns or
% spaces between columns in the tabular environment
\newenvironment{blockmatrixtabular}
{% necessary comment
  \begin{tabular}{
  @{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l
  @{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l
  @{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l
  @{}
  }
}
{
  \end{tabular}%necessary comment
}
Then here's the code for a document showing a bunch of uses:
\documentclass[letterpaper,11pt]{article}

\usepackage{tikz}
\usepackage{ifthen}

% master block matrix, should use wrappers instead of calling this
% directly
% This should be called within the tikzpicture environment
% \blockmatrix
%  {width}
%  {height}
%  {text}
%  {block_line_color} (can be none --> no line)
%  {block_fill_color} (can be none --> empty fill)
%  {is_diagonal} (true --> true, otherwise --> false)
%  {diagonal_line_color} (ignored if not diagonal) (can be none --> no line)
%  {diagonal_fill_color} (ignored if not diagonal) (can be noneo --> empty fill)
%  {diagonal_offset} (half diagonal width in tikz units)
% Note: colors here are not rgb, they are defined colors
\newcommand{\blockmatrix}[9]{
  \draw[draw=#4,fill=#5] (0,0) rectangle( #1,#2);
  \ifthenelse{\equal{#6}{true}}
  {
    \draw[draw=#7,fill=#8] (0,#2) -- (#9,#2) -- ( #1,#9) -- ( #1,0) -- ( #1 - #9,0) -- (0,#2 -#9) -- cycle;
  }
  {}
  \draw ( #1/2, #2/2) node { #3};
}

% Quick implementation of a tikz right parenthesis
% \rightparen{width}
\newcommand{\rightparen}[1]{
  \begin{tikzpicture} 
    \draw (0,#1/2) arc (0:30:#1);
    \draw (0,#1/2) arc (0:-30:#1);
  \end{tikzpicture}%this comment is necessary
}

% Quick implementation of a tikz left parenthesis
% \leftparen{width}
\newcommand{\leftparen}[1]{
  \begin{tikzpicture} 
    \draw (0,#1/2) arc (180:150:#1);
    \draw (0,#1/2) arc (180:210:#1);
  \end{tikzpicture}%this comment is necessary
}

% Unframed block matrix, "m" prefix to match fbox, mbox
% \blockmatrix[r,g,b]{width}{height}{text}
\newcommand{\mblockmatrix}[4][none]{
  \begin{tikzpicture} 
  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{none}{none}{false}{none}{none}{0.0}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{none}{fillcolor}{false}{none}{none}{0.0}
  }
  \end{tikzpicture}%this comment is necessary
}

% Framed block matrix
% \fblockmatrix[r,g,b]{width}{height}{text}
\newcommand{\fblockmatrix}[4][none]{
  \begin{tikzpicture} 
  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{black}{none}{false}{none}{none}{0.0}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{black}{fillcolor}{false}{none}{none}{0.0}
  }
  \end{tikzpicture}%this comment is necessary
}

% Diagonal block matrix
% \dblockmatrix[r,g,b]{width}{height}{text}
\newcommand{\dblockmatrix}[4][none]{
  \begin{tikzpicture} 
  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{none}{0.35cm}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{fillcolor}{0.35cm}
  }
  \end{tikzpicture}%this comment is necessary
}


% Diagonal block matrix, but exposes diagonal offset
% \diagonalblockmatrix[r,g,b]{width}{height}{text}
\newcommand{\diagonalblockmatrix}[5][none]{
  \begin{tikzpicture} 

  \ifthenelse{\equal{#1}{none}}
  {
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{none}{#5}
  }
  {
    \definecolor{fillcolor}{rgb}{#1}
    \blockmatrix{#2}{#3}{#4}{black}{none}{true}{black}{fillcolor}{#5}
  }

  \end{tikzpicture}%necessary comment
}

\newcommand{\valignbox}[1]{
  \vtop{\null\hbox{#1}}% necessary comment
}

% a hack so that I don't have to worry about the number of columns or
% spaces between columns in the tabular environment
\newenvironment{blockmatrixtabular}
{% necessary comment
  \begin{tabular}{
  @{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l
  @{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l
  @{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l@{}l
  @{}
  }
}
{
  \end{tabular}%necessary comment
}

\begin{document}

Linear system for solving a biharmonic PDE with boundary
condtions:


\begin{blockmatrixtabular}
\valignbox{\fblockmatrix       [0.8,1.0,0.8]{0.8in}{0.6in}{$L$}}&
\valignbox{\diagonalblockmatrix[1.0,0.8,0.8]{0.8in}{0.8in}{$M^{-1}$}{0.25in}}&
\valignbox{\fblockmatrix       [0.8,1.0,0.8]{0.6in}{0.8in}{$L$}}&
\valignbox{\fblockmatrix                    {0.15in}{0.6in}{$x$}}&
\valignbox{\mblockmatrix                    {0.15in}{0.6in}{$=$}}&
\valignbox{\fblockmatrix       [0.8,1.0,0.8]{0.8in}{0.6in}{$L$}}&
\valignbox{\diagonalblockmatrix[1.0,0.8,0.8]{0.8in}{0.8in}{$M^{-1}$}{0.25in}}&
\valignbox{\fblockmatrix       [0.8,1.0,0.8]{0.25in}{0.8in}{$L$}}&
\valignbox{\fblockmatrix       [0.8,0.8,1.0]{0.15in}{0.25in}{$b$}}\\
\end{blockmatrixtabular}\\

\begin{tabular}{cc}
Simple linear system:&
Linear system with known values susbstituted:\\
\begin{blockmatrixtabular}
\valignbox{\fblockmatrix       [0.8,1.0,0.8]{0.8in}{0.8in}{$A$}}&
\valignbox{\fblockmatrix                    {0.15in}{0.8in}{$x$}}&
\valignbox{\mblockmatrix                    {0.15in}{0.8in}{$=$}}&
\valignbox{\fblockmatrix       [0.8,0.8,1.0]{0.15in}{0.8in}{$b$}}\\
\end{blockmatrixtabular}&

\begin{blockmatrixtabular}
  \valignbox{
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,1.0,0.8]{0.8in}{0.37in}{$A$}\\
  \fblockmatrix     [1.0,0.8,0.8]{0.8in}{0.37in}{$I$}%nc
  \end{blockmatrixtabular}}&
\valignbox{\fblockmatrix{0.15in}{0.8in}{$x$}}&
\valignbox{\mblockmatrix{0.15in}{0.8in}{$=$}}&
  \valignbox{%necessary comment
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,1.0,0.8]{0.15in}{0.37in}{$b$}\\
  \fblockmatrix     [1.0,0.8,0.8]{0.15in}{0.37in}{$\hat{x}$}%nc
  \end{blockmatrixtabular}%necessary comment
  }
\end{blockmatrixtabular}\\
\end{tabular}

Linear system addition expanded in system matrix:

\begin{blockmatrixtabular}
\valignbox{\leftparen{0.8in}}&
  \valignbox{
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,1.0,0.8]{0.8in}{0.37in}{$A$}\\
  \fblockmatrix     [0.8,0.8,1.0]{0.8in}{0.37in}{$0$}%nc
  \end{blockmatrixtabular}}&
\valignbox{\mblockmatrix{0.15in}{0.8in}{$+$}}&
  \valignbox{
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,0.8,1.0]{0.8in}{0.37in}{$0$}\\
  \fblockmatrix     [1.0,0.8,0.8]{0.8in}{0.37in}{$I$}%nc
  \end{blockmatrixtabular}}&
\valignbox{\rightparen{0.8in}}&
\valignbox{\fblockmatrix{0.15in}{0.8in}{$x$}}&
\valignbox{\mblockmatrix{0.15in}{0.8in}{$=$}}&
  \valignbox{%necessary comment
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,1.0,0.8]{0.15in}{0.37in}{$b$}\\
  \fblockmatrix     [1.0,0.8,0.8]{0.15in}{0.37in}{$\hat{x}$}%nc
  \end{blockmatrixtabular}%necessary comment
  }
\end{blockmatrixtabular}\\

Linear system with least squares conditions tacked on to the
bottom: 

\begin{blockmatrixtabular}
  \valignbox{%necessary comment
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,1.0,0.8]{0.8in}{0.8in}{$A$}\\
  \fblockmatrix     [1.0,0.8,0.8]{0.8in}{0.4in}{$G$}%necessary comment
  \end{blockmatrixtabular}%necessary comment
  }&
\valignbox{\fblockmatrix{0.15in}{0.8in}{$x$}}&
\valignbox{\mblockmatrix{0.15in}{0.8in}{$=$}}&%
  \valignbox{%necessary comment
  \begin{blockmatrixtabular}
  \fblockmatrix       [0.8,0.8,1.0]{0.15in}{0.8in}{$b$}\\
  \fblockmatrix       [1.0,0.8,0.8]{0.15in}{0.4in}{$0$}%nc
  \end{blockmatrixtabular}%necessary comment
  }
\end{blockmatrixtabular}\\


Least squares system with a weights applied to the original
matrix:

\begin{blockmatrixtabular}
\valignbox{\diagonalblockmatrix[0.8,1.0,0.8]{0.8in}{0.8in}{$W_A$}{0.25in}}&
  \valignbox{%necessary comment
  \begin{blockmatrixtabular}
  \fblockmatrix     [0.8,1.0,0.8]{0.8in}{0.8in}{$A$}\\
  \fblockmatrix     [1.0,0.8,0.8]{0.8in}{0.4in}{$G$}%nc
  \end{blockmatrixtabular}%necessary comment
  }&%
\valignbox{\fblockmatrix{0.15in}{0.8in}{$x$}}&
\valignbox{\mblockmatrix{0.15in}{0.8in}{$=$}}&
  \valignbox{%necessary comment
  \begin{blockmatrixtabular}
  \fblockmatrix       [0.8,0.8,1.0]{0.15in}{0.8in}{$b$}\\
  \fblockmatrix       [1.0,0.8,0.8]{0.15in}{0.4in}{$0$}%nc
  \end{blockmatrixtabular}%necessary comment
  }
\end{blockmatrixtabular}\\


\end{document}
Which produces this: latex tikz block matrics In conclusion, the disadvantages of the tikz approach is that (1) the command definitions are longer, (2) the code for each block matrix is much more verbose, (3) alignment is not trivial, and (4) it requires an external package. The advantages over the pure LaTeX approach is that (1) alignment is easier, (2) parentheses fit nicely into the vector graphics of the blocks, (3) colors are drop dead easy, (4) diagonal matrices are implemented, and (5) whitespace between rows and columns and above and below symbols is easier to manage. For now, I'm convinced that the tikz way produces better look matrices. Though I imagine myself keeping the pure LaTeX version as a simple back up.