% TODO: % * ALLOW FINE TUNING OF ARROW ETC ARRANGEMENT BY PARAMETERS % (Suggestion by Antonis Tsolomitis) % * BUG: ROWOPMINSIZE AND COLOPMINSIZE DONT WORK IN \swap01 etc. % (MAXIMUM COMPUTATION MISSIG) % * BUG: ARROWHT HAS TWO CONTRADICTING MEANINGS % % \title{\texttt{gauss.sty} -- A Package for Typesetting Matrix Operations} % \author{Manuel Kauers} % \maketitle % % \MakeShortVerb{\|} % % \newenvironment{example} % {\par\goodbreak\medskip % \begin{minipage}[c]{.45\textwidth} % \def\switch{\end{minipage}\begin{minipage}[c]{.45\textwidth}\hfil$} % \obeylines % }{$\hfil\end{minipage}\medskip\goodbreak\par} % % \begin{abstract} % This package provides \LaTeX-macros for typesetting operations on a matrix. % By an ``operation on a matrix'' we understand a \textit{row operation} % or a \textit{column operation}. % % The user interface of the package is very straightforward and easy to understand % while the results look quite pretty. % \end{abstract} % % \tableofcontents % % \section{Usage} % % If you find yourself in search of a package that enables you to easily typeset % constructions like % \[ % \begin{gmatrix}[v] % 1 & 0 & 5 & 7 & 2 \\ % 3 & 1 & 1 & 5 & 1 \\ % 1 & 0 & -7 & 1 & 4 \\ % 4 & 3 & 6 & 5 & 4\\ % 1 & 7 & 9 & 4 & 3 \\ % 0 & 0 & 8 & 0 & -1 % \rowops % \add[-3]01 % \add[-1]02 % \swap34 % \mult5{\cdot 0} % \add[x^2-1]53 % \colops % \swap01 % \mult3{\cdot 1} % \add[0]24 % \end{gmatrix} = \begin{gmatrix}[v] % 0 & 1 & 5 & 7 & 2 \\ % 1 & 0 & -14 & -16 & -5 \\ % 0 & 0 & -12 & -6 & 2 \\ % 7 & 1 & 9 & 4 & 3 \\ % 3 & 4 & 6 & 5 & 4\\ % 0 & 0 & 0 & 0 & 0 % \end{gmatrix}, % \] % then this package is what you need. % It defines a new matrix environment which is extended by comprehensive macros for % typesetting so-called ``operations'' on the matrix. % An operation is either a row operation or a column operation, and may involve one or % two lines. % Examples of such operations arise in the context of Gaussian elimination for solving % systems of linear equations in linear algebra: swaping rows, adding the multiple of one % row to another, and multiply a row by a constant factor. % % \subsection{How to typeset matrix operations} % % \begin{environment}{gmatrix} % The package defines a new matrix environment |gmatrix| which % behaves just like \LaTeX's and \AmS\LaTeX's |matrix|. It takes an optional % parameter \meta{delimtype} to select the matrix delimiters. So, |gmatrix[p]| % corresponds to |pmatrix|, |gmatrix[v]| to |vmatrix|, and so on. % % The |gmatrix| environment can be used exaclty like its brothers and sisters % defined by \LaTeX\ and \AmS\LaTeX, for instance: % \begin{example} % |\begin{gmatrix}[p]| % | a & b \\| % | c & d| % |\end{gmatrix}| % \switch % \begin{gmatrix}[p] a&b\\ c&d\end{gmatrix} % \end{example} % The content of the |gmatrix| environment consists of three parts: matrix, row operations, % and column operations. The latter two are optional parts, and the ordering of them is % arbitrary (i.e.\ row operations may be stated before column operations and vice versa). % The matrix part is required, and it must be the first one. % \end{environment} % % \begin{macro}{\rowops} % \begin{macro}{\colops} % To skip to the next section, there are two comands |\rowops| which swiches to the row % operation section, and |\colops| which switches to the column operation section. % \end{macro} % \end{macro} % % \begin{macro}{\mult} % \begin{macro}{\add} % \begin{macro}{\swap} % Within the operation sections, you have to state the sequence of operations which are to % be typeset. There are the three commands |\mult|, |\add|, and |\swap| to do this. These % commands are specified as follows: % % \begin{enumerate} % \item |\mult{i}{\cdot b}| typesets the operation ``multiply the $i$th row (or column) % by~$b$'', % \item |\swap[a][b]{i}{j}| typesets the operation ``swap the $i$th and the $j$th row % (or column)''. % $a$~and~$b$ are labels to typeset at the end of the arrows, similar to the $\cdot b$ of % the |\mult| command. The command does nothing if $i=j$. % \item |\add[a][b]{i}{j}| typesets the operation ``add the $a$-fold of row (or column)~$i$ to % row (or column)~$j$. $b$~is a label for the $j$th line. The command does nothing if $i=j$. % \end{enumerate} % % In the standard implementation, optional arguments of |\swap| and the second optional % argument of |\add| are ignored. See Section~\ref{ssec:atp} for how to enable them. % % Rows are counted top-down, and columns are counted from left to right. The uppermost row % and the leftmost column have the index~0. There is also the posibility to use |*| as index % which causes the typesetting of several operations where |*| runs over all indices. For % example, |\mult{*}{5}| in the |\rowops| section of a $n\times n$ matrix is equivalent to % state |\mult{0}{5}|,\dots,|\mult{|$n-1$|}{5}|. % \end{macro} % \end{macro} % \end{macro} % % \subsection{Examples} % % \begin{itemize} % \item A matrix with row operations % \begin{example} % |\begin{gmatrix}[p]| % | 1 & 2 & 3 \\| % | 4 & 5 & 6 \\| % | 7 & 8 & 9| % |\rowops| % | \swap{0}{1}| % | \mult{0}{\cdot 7}| % | \add[5]{1}{2}| % |\end{gmatrix}| % \switch % \begin{gmatrix}[p] 1&2&3\\4&5&6\\7&8&9 \rowops % \swap01\mult0{\cdot 7}\add[5]12 % \end{gmatrix} % \end{example} % \item The same operations in an other ordering % \begin{example} % |\begin{gmatrix}[p]| % | 1 & 2 & 3 \\| % | 4 & 5 & 6 \\| % | 7 & 8 & 9| % |\rowops| % | \add[5]{1}{2}| % | \swap{0}{1}| % | \mult{0}{\cdot 7}| % |\end{gmatrix}| % \switch % \begin{gmatrix}[p] 1&2&3\\4&5&6\\7&8&9 \rowops % \add[5]12\swap01\mult0{\cdot 7} % \end{gmatrix} % \end{example} % \item A matrix with column operations % \begin{example} % |\begin{gmatrix}[p]| % | 1 & 2 & 3 \\| % | 4 & 5 & 6 \\| % | 7 & 8 & 9| % |\colops| % | \swap{0}{1}| % | \mult{0}{\cdot 7}| % | \add[5]{1}{2}| % |\end{gmatrix}| % \switch % \begin{gmatrix}[p] 1&2&3\\4&5&6\\7&8&9 \colops % \swap01\mult0{\cdot 7}\add[5]12 % \end{gmatrix} % \end{example} % \item A matrix with both row and column operations % \begin{example} % |\begin{gmatrix}[v]| % | 1 & 2 & 3 \\| % | 4 & 5 & 6 \\| % | 7 & 8 & 9| % |\rowops| % | \swap{1}{2}| % | \mult{2}{\cdot 3}| % | \add[-5]{1}{0}| % | \add[-3]{1}{2}| % |\colops| % | \swap{0}{1}| % | \mult{0}{\cdot 7}| % | \add[5]{1}{2}| % |\end{gmatrix}| % \switch % \begin{gmatrix}[v] 1&2&3\\4&5&6\\7&8&9 \rowops % \swap12\mult2{\cdot 3}\add[-5]10\add[-3]12 \colops % \swap01\mult0{\cdot 7}\add[5]12 % \end{gmatrix} % \end{example} % \item Multiple operations using the |*| index % \begin{example} % |\begin{gmatrix}[p]| % | 1&2&3&4\\| % | 5&6&7&8\\| % | 9&10&11&12\\| % | 13&14&15&16| % |\rowops| % | \add[x]{0}{*}| % |\end{gmatrix}| % \switch % \begin{gmatrix}[p] % 1&2&3&4\\ % 5&6&7&8\\ % 9&10&11&12\\ % 13&14&15&16 % \rowops \add[x]0* % \end{gmatrix} % \end{example} % Note that the first row is not added to itself, because |\add[x]{0}{0}| has no effect. % You can also use two stars: % \begin{example} % |\begin{gmatrix}[p]| % | 1&2&3\\| % | 4&5&6\\| % | 7&8&9| % |\rowops| % | \add{*}{*}| % |\end{gmatrix}| % \switch % \kern-1.5em\begin{gmatrix}[p] % 1&2&3\\ 4&5&6\\ 7&8&9 % \rowops \add** % \end{gmatrix}\kern-2em % \end{example} % \item The package clearly also handels a matrix with larger entries correctly: % \[ % \begin{gmatrix}[p] % a & b & c & d & e \\ % 0 & 0 & \displaystyle\int\limits_a^b f(x)\,dx & 0 & 0 \\ % a & b & c & d & e % \rowops % \mult{1}{:\displaystyle\int\limits_a^b f(x)\,dx}% % \add[-c]10 \add[-1]02 % \end{gmatrix} % \] % Even nested |gmatrix|es are possible: % \[ % \def\littleA#1#2#3#4{\begin{gmatrix}[p]#1\\#3\rowops \add[-#3/#1]01\end{gmatrix}} % \def\littleB#1#2#3#4#5{\begin{gmatrix}[p]#1\\#3\rowops \mult0{\cdot #5}\end{gmatrix}} % \def\littleC#1#2#3#4{\begin{gmatrix}[p]#1\\#3\rowops \swap01\end{gmatrix}} % \kern-1.5em % \begin{gmatrix}[v] % \littleA 2233 & \littleC 1234 & \littleA abcd \\ % \rule[-20pt]{0pt}{45pt}\littleB 0110\pi & \littleC vwxy & \littleC 1xx{x^2} \\ % \littleB 12345 & \littleA \cdot \cdot \cdot \cdot & \littleB 54321 % \rowops % \add[\pi^2/6]01 % \mult1{\cdot 42} % \swap02 % \end{gmatrix} % \kern-1.5em % \] % \end{itemize} % % \subsection{Adapting the package}\label{ssec:atp} % % \subsubsection{Distances and dimensions} % % The appearance of the operation lines and arrows depends strongly on the values of the % dimension parameters described in this section. % % \def\test{\begin{gmatrix}[p]a&b&c\\d&e&f\\g&h&i\rowops % \add[x]01\add[y]12\mult1{\cdot y}\swap02\end{gmatrix}}% % \def\ttest#1=#2.{\[#1=#2\relax\test\]}% % % \begin{macro}{\rowarrowsep} % \begin{macro}{\colarrowsep} % |\rowarrowsep| denotes the distance from the matrix to the operations. % For example, |\rowarrowsep=10pt| yields % \ttest\rowarrowsep=5pt. % and |\rowarrowsep=50pt| yiels % \ttest\rowarrowsep=50pt. % The corresponding dimension for column operations is |\colarrowsep|. % \end{macro} % \end{macro} % \begin{macro}{\opskip} % |\opskip| is the distance between two consecutive operations. % For example, |\opskip=6pt| yields % \ttest\opskip=6pt. % and |\opskip=30pt| yields % \ttest\opskip=25pt. % The |\opskip| length is responsible for both row and column operations. % \end{macro} % \begin{macro}{\labelskip} % |\labelskip| is the distance between an operation arrow and its labels. % For example, |\labelskip=3pt| yields % \ttest\labelskip=3pt. % and |\labelskip=15pt| yields % \ttest\labelskip=15pt. % The |\labelskip| length is responsible for both row and column operations. % \end{macro} % \begin{macro}{\rowopminsize} % \begin{macro}{\colopminsize} % The length |\rowopminsize| is the minimum amount of a horizontal operation % segment to go to the right. % For example, |\rowopminsize=3pt| yields % \ttest\rowopminsize=3pt. % If the horizontal segment ends with an arrow tip and |\rowopminsize| is less than % the width of |\leftarrow|, then the width of |\leftarrow| is taken. In the above % example, this is the case in the |\add[x]{0}{1}| operation. An example for an % exact use of a small value of |\rowopminsize| is the upper horizontal line of % |\add[y]{1}{2}|. % For comparation, |\rowopminsize=30pt| yields % \ttest\rowopminsize=30pt. % The corresponding value for column operations is |\colopminsize|. % \end{macro} % \end{macro} % % \subsubsection{Labels} % % The typesetting of a label can be changed by redefining the macros which are responsible % for label typesetting. Each label parameter of |\mult|, |\add|, and |\swap| is passed to % special ``fontifier'' macros which take one argument and fontify it according to the % semantical requirements. Here is a list of those fontifier macros and their default % definitions: % % \begin{macro}{\rowmultlabel} % |\rowmultlabel| is the label of a |\mult| operation in the |\rowops| section. % Its default definition is \verb?{|\,#1}?. % \end{macro} % \begin{macro}{\colmultlabel} % |\colmultlabel| is the respective macro for the |\colops| section. It is defined % to % \begin{example} % |\underline{\hbox to 1.2em{$\hss\mathstrut{}#1\hss$}}|\kern-20em % \switch % \end{example} % \noindent by default. % \end{macro} % \begin{macro}{\rowswapfromlabel} % |\rowswapfromlabel| is the label of a |\swap| operation in the |\rowops| section % which is to place at the first of the two rows. It is defaultly defined to |{}|, i.e.\ % the label parameter is ignored. % \end{macro} % \begin{macro}{\colswapfromlabel} % |\colswapfromlabel| is the respective macro for the |\colops| section which is % also empty by default. % \end{macro} % \begin{macro}{\rowswaptolabel} % |\rowswaptolabel| is like |\rowswapfromlabel|, but for the other row. It is empy % by default. % \end{macro} % \begin{macro}{\colswaptolabel} % |\colswaptolabel| is |\rowswaptolabel|'s brother for the |\colops| section. % \end{macro} % \begin{macro}{\rowaddfromlabel} % |\rowaddfromlabel| is the macro for the label of the from-line of an |\add| command. % It is defined to |{\scriptstyle#1}| by default. % \end{macro} % \begin{macro}{\coladdfromlabel} % |\coladdfromlabel| is respective macro for the column operations. % \end{macro} % \begin{macro}{\rowaddtolabel} % |\rowaddtolabel| fontifies the label of the to-line of an |\add| command. This macro % is defined to |{\scriptscriptstyle +}| by default, i.e.\ it ignores the parameter. % \end{macro} % \begin{macro}{\coladdtolabel} % |\coladdtolabel| is the respective command for the column operation. It behaves % likewise. % \end{macro} % % For the following example, all of the above labels were defined to |{#1}|, i.e.\ to identity. % % \begin{example} % |\begin{gmatrix}[p]| % | a & b & c \\| % | d & e & f \\| % | g & h & i| % |\colops| % | \mult0{m}| % | \add[af][at]01| % | \swap[sf][st]02| % |\rowops| % | \mult0{m}| % | \add[af][at]01| % | \swap[sf][st]02| % |\end{gmatrix}| % \switch % \def\rowmultlabel#1{#1} % \def\colmultlabel#1{#1} % \def\rowswapfromlabel#1{#1} % \def\colswapfromlabel#1{#1} % \def\rowswaptolabel#1{#1} % \def\colswaptolabel#1{#1} % \def\rowaddfromlabel#1{#1} % \def\coladdfromlabel#1{#1} % \def\rowaddtolabel#1{#1} % \def\coladdtolabel#1{#1} % \begin{gmatrix}[p] % a & b & c \\ % d & e & f \\ % g & h & i % \colops % \mult0{m} % \add[af][at]01 % \swap[sf][st]02 % \rowops % \mult0{m} % \add[af][at]01 % \swap[sf][st]02 % \end{gmatrix} % \end{example} % % \subsubsection{Matrix delimiters} % % \begin{macro}{\newmatrix} % It is possible to define new delimiter specifiers to |gmatrix|, say |gmatrix[X]|, % by defining a matrix environment |Xmatrix|. % A definition of |Xmatrix| which fulfills the requirements needed for compatibility % with |gmatrix| is provided automatically by the call of % % \begin{example} % |\newmatrix{|\meta{left-delim}|}{|\meta{right-delim}|}{X}|,\kern-20em % \switch % \end{example} % % which defines the environment |Xmatrix|. The arguments \meta{left-delim} and % \meta{right-delim} need to be compatible to the |\left|-|\right| mechanism of \TeX. % As soon as |Xmatrix| exists, it is also possible to use |X| as optional argument % to |gmatrix|. % % By convention, the suffix is one single character. If you try to enter |g@| or % the empty string as suffix, nothing is done, otherwise, the definition works % as well. % \end{macro} % % \subsection{Features} % % \begin{itemize} % \item You need not care about the width or height of some macro cells, % operations are always aligned well, i.e. centered to the column or row. % \item Operation elements will not intersect each other, unless you give % some very huge labels. % \item There is no restriction to the order of operation commands, so you can % choose an arbitrary order to achive the best typographic result. % \item If no operations are given, the result is exactly the result of % the \AmS-\TeX\ |matrix| environment. % \item Unlike \AmS's |matrix| environment, there is no limit to the matrix' size % in our reimplementation |gmatrix|. % \item Nested |gmatrix|'s are possible. % \end{itemize} % % \subsection{Trap doors and hints} % % \begin{itemize} % \item The last row \emph{must not} end with an |\\|, but each other line % should end with |\\|. % \item The last row is used internally to measure the column's widths. % Therefore, if you want to point to a column~$i$, then the last row must have % at least $i+1$ entries. % \item In row operations, the package considers the width of labels % (that is, the width of factors in |\mult| and |\add|). But you have to % take care that your labels are not higher than the corresponding line, % otherwise they may intersect with other arrows or labels. % \item analogously for column operations. % \item The package should also run without the |amsmath| package, but if you % use that package (which is assumed to be the usual situation), you have to % load |gauss| after |amsmath|. % \end{itemize} % % \subsection{Bug parade} % % A list of submitted bugs and suggested work-arounds or fixes. % If you face any bug that is not in the list below, feel free to contact me % at |manuel@kauers.de|. % % \begin{itemize} % \item Hans Frederik Nordhaug faced problems with versions of \AmS-\LaTeX\ % that don't define |*matrix| environments as expected (e.g.\ version 2.13). % The current version of |gauss| therefore redefines all those environments % using our |\newmatrix| tool, and requires |amsmath| to be loaded prior to % the |gauss| package. % \item Morten H{\o}gholm suggested the introduction of fontifying macros and % the use of changeable lengths as discussed in Section~\ref{ssec:atp}. % He also suggested some very fine typographic tunings. % \item Herbert Voss found that a |\unitlength=1pt| was missing to make the % behaviour of the package independent of redefinitions of |\unitlength| % outside |gmatrix|. (Fixed.) % \item Michael Hagedorn noticed that signs in entries a treated like % binary relations, i.e., wrong spacing is used. (Fixed.) % \end{itemize} % % \StopEventually % % \section{Implementation} % % \begin{macrocode} \ProvidesPackage{gauss}[2003/01/14] \RequirePackage{amsmath} \makeatletter % \end{macrocode} % % To avoid naming conflicts with other packages, our private control % sequences all start with |\g@|. % Permanently public are only the |gmatrix| environment, the fontifying macros (like % |\rowaddfromlabel|), and the dimensions (like |\opskip|). % % The |amsmath| package is not necessarily needed, but if used, it has to be % loaded prior to the |gauss| package. This is forced by the |\RequirePackage| % command. % % \subsection{Allocation of registers and definition of common macros} % % Boxes,\dots % \begin{macrocode} \newbox\g@trash \newbox\g@matrixbox \newbox\g@eastbox \newbox\g@northbox \newbox\g@label \newbox\g@b@tmp \newbox\g@b@tmpa \newbox\g@b@tmpb % \end{macrocode} % \dots counters,\dots % \begin{macrocode} \newcount\g@maxrow \newcount\g@maxcol \newcount\g@maxrow@old \newcount\g@maxcol@old \newcount\g@c@tmp \newcount\g@c@tmpa % \end{macrocode} % \dots and dimensions \dots % \begin{macrocode} \newdimen\g@axisHeight \newdimen\g@linethickness \newdimen\g@tab \newdimen\g@arrowht \newdimen\g@arrowwd \newdimen\g@d@tmp \newdimen\g@d@tmpa \newdimen\g@d@tmpb \newdimen\g@d@tmpc \newdimen\g@d@tmpd \newdimen\g@d@tmpe % \end{macrocode} % are allocated. % % \begin{macro}{\g@for} % For frequent use, we define a special loop mechanism, which allowes to % iterate over a given interval from a lower bound to a higher one, or % reversely. The code to execute is given as the third argument of |\g@for|, % using |#1| for the iteration variable that is substituted by |\the\loopCount| % for each value in the given bounds. % % Each of the bounds is also visited. Example: The following code prints out % the numbers from 1 to 37, inclusively: % % \begin{example} % |\g@for1\to37\do{#1 }| % \switch % \end{example} % % We first need some more control sequences: |\g@loopContent| is defined to the loop's % body when the loop is entered. % |\g@loopCount| is the variable to increment or decrement with each % iteration. |\g@loopEnd| marks the value at which to stop the loop, % and |\g@loopStep| contains the direction, i.e. $|\g@loopStep|=-1$ iff % $|\g@loopEnd| < \meta{start value}$. % \begin{macrocode} \def\g@loopContent#1{} \newcount\g@loopCount\g@loopCount=0 \newcount\g@loopEnd\g@loopEnd=1 \newcount\g@loopStep\g@loopStep=1 % \end{macrocode} % The |\g@loop| command executes the loop initialized by |\g@for|. % Each iteration is executed in its own group to avoid side effects and % expecially to provide nested loops. % \begin{macrocode} \def\g@loop{% % base case? \ifnum\g@loopCount=\g@loopEnd\else % no: execute loop body {\expandafter\g@loopContent\expandafter{\the\g@loopCount}}% % increment or decrement the loop variable \advance\g@loopCount\g@loopStep % call \g@loop recursivly. \g@loop \fi } % \end{macrocode} % Finally, here is the definition of |\g@for|. Each value in the interval % from |#1| to |#2|, including |#1| and |#2| is visited exactly one time. % \begin{macrocode} \def\g@for#1\to#2\do#3{% \def\g@loopContent##1{#3}% \g@loopCount=#1 \g@loopEnd=#2 \ifnum\g@loopEnd>\g@loopCount% \g@loopStep=1 \else\g@loopStep=-1 \fi \advance\g@loopEnd\g@loopStep % inclusive upper bound \g@loop } % \end{macrocode} % \end{macro} % % \begin{macro}{\g@checkBounds} % The next tool is used by the generic operation commands to check whether or not % a given index is valid. If $|#2|\leq|#3|\leq|#4|$ does not hold, a package % error is thrown that tells the user what happened. % % Parameter |#1| contains `r' or `c' to denote ``rows'' or ``columns'', % respectively. This piece of information is only used within the construction of % the error message. % % \begin{macro}{\ifg@indexCorrect} % The result of |\g@checkBounds| is returned via |\ifg@indexCorrect|. % \begin{macrocode} \newif\ifg@indexCorrect \def\g@checkBounds#1#2#3#4{% \g@indexCorrectfalse \ifnum#2>#3% \PackageError{gauss}{\g@shorterror{#1} #3<#2}{\g@longerror{#1}} \else \ifnum#3>#4% \PackageError{gauss}{\g@shorterror{#1} #3>#4}{\g@longerror{#1}} \else \g@indexCorrecttrue \fi \fi } % \end{macrocode} % We skip the definitions of |\g@shorterror| and |\g@longerror| which serve to % produce error messages. \def\g@shorterror#1{\ifx r#1 Row \else Column \fi index out of bounds: } \def\g@longerror#1{% An index of an operation points to a \ifx r#1 row \else column \fi % that does not exist.\MessageBreak Note that the index of the % \ifx r#1 bottom row \else leftmost column \fi is 0 while the index of the % \ifx r#1 top row \else rightmost column \fi is .% } % \end{macro}\end{macro} % % \begin{macro}{\g@downarrow} % For drawing horizontal arrows of arbitrary length, we use the construction % % \begin{example} % |\hbox to|\meta{width}|{$\leftarrowfill$}|\kern-20em % \switch\end{example} % % \noindent which uses Plain-\TeX's |\leftarrowfill|. Unfortunately, there is no % vertical correspondence to that mechanism and thus, we have construct something % like this by ourselves. We will do so by reimplementing a mechanism that is used % by |\left| and |\right| to construct delimiters of arbitrary height. % % \begin{macrocode} \DeclareMathSymbol{\g@downarrowSymb}{\mathord}{largesymbols}{`\y} \DeclareMathSymbol{\g@vertlineSymb}{\mathord}{largesymbols}{`\?} \def\g@vertline{\hbox{$\g@vertlineSymb$}\kern-\lineskip}% % \end{macrocode} % % After allocating the basic symbols, we define |\g@downarrow| by a recursion % which fills up a vbox with the necessary number of |\g@vertline|'s and a % final |\g@downarrowSymb|. % % The resulting vbox has exactly the height given in |#1| (as \TeX-length), and % no depth. If |#1| is less than a minimum height, then it is set to that minimum % height. % % \begin{macrocode} \def\g@downarrow#1{\vbox{% \vfill \baselineskip\z@\relax \g@d@tmpc=#1\relax \ifdim \g@d@tmpc<\g@arrowht \g@d@tmpc\g@arrowht\relax \fi \g@vlineRec \kern\g@d@tmpc \setbox\g@trash=\hbox{$\g@downarrowSymb$}% \hbox{\raise\dp\g@trash\box\g@trash}% }} \def\g@vlineRec{% \advance\g@d@tmpc-\g@arrowht \ifdim \g@d@tmpc<\z@ \else \g@vertline \g@vlineRec \fi } % \end{macrocode} % % \end{macro} % % \subsection{Converting floasts and lengths to each other} % % \begin{macro}{\g@defdim}% % \begin{macro}{\g@defdouble}% % \begin{macro}{\g@dim}% % \begin{macro}{\g@double}% % The typesetting of matrix operations is done by use of the |picture| % environment of \LaTeX. The macros of that environment require plain % numbers, possibly containing a decimal point. Though it is not clearly % correct, we will call that data format \emph{float} or \emph{double}. % % |picture|'s macros do not work if you give them dimensions as input. % And since the results of measuring a matrix are necessarily dimensions, % we need a mechanism to convert dimensions to floats and vice versa. % % This mechanism is the topic of the current section. % % In fact, we almost provide our own data structure whose values can be shown % as \TeX\ dimensions or as floats. You can ``construct a new instance'' of % that structure either by a dimension (using |\g@defdim|) or by a double % (using |\g@defdouble|). In both cases, a macro is defined to be the % corresponding double value. % % Given an instance of our data structure, i.e.\ given a double, you can get % its double representation using |\g@double| (this just typesets the double % representation), and you can store its value into a \TeX\ dimension using % |\g@dim|. % % Macros for manipulation on floats are defined in the following section. % % \medskip % We first need a macro that cuts away the ``pt''. This is rather tricky because % the ``pt'' that arises in the result of some |\the|\meta{counter} has not the % catcodes as expected. We can redefine them temporarily but we have to note that % constructions like |\g@defdim{|\meta{identifier}|}{12pt}| (i.e.\ giving the length % directly) are no longer possible, since the ``pt'' of a directly given length % has the ``normal'' catcodes. % \begin{macrocode} \edef\redo#1{\catcode`p=#1\catcode`t=#1\relax} \redo{12} \def\g@del#1pt{#1} \redo{11} % \end{macrocode} % Defining a float by a dimension. The first argument expects an idetifier % (identifiers are arbitrary strings), and the second argument expects a % \TeX\ dimension \emph{register}, i.e. some control sequence |\cs| that % evaluates to ``\dots pt'' if you say |\the\cs|. % % It is not possible to specify a double by directly give a length. Use % |\g@defdouble| below in that case. % \begin{macrocode} \def\g@defdim#1#2{% \edef\g@defdim@arg{\the #2}% \edef\g@defdim@arg{\expandafter\g@del\g@defdim@arg}% \g@defdouble{#1}{\g@defdim@arg}% } % \end{macrocode} % And here is |\g@defdouble|. |#1| should be an identifier and |#2| should % be the value to store in float |#1|. To avoid naming conflics with other % macros, |#2| is stored into a macro based on |g@@| and the content of |#1|. % \begin{macrocode} \def\g@defdouble#1#2{% \expandafter\expandafter\expandafter\global \expandafter\edef\csname g@@#1 \endcsname{#2}% } % \end{macrocode} % We now come to the macros for ``reading'' a float. These are |\g@dim| (to % read the dimensional representation) and |\g@double| (for the double % representation). % % An error will occur if you try to read the value of a float that was not % previously defined. (``Missing number, treated as zero.'') % % First |\g@dim|: Let |#1| be the identifier and |#2| the \TeX\ dimension % registern to store the value of |#1| in. % \begin{macrocode} \def\g@dim#1#2{% \edef\g@dim@arg{\g@double{#1}}% #2=\g@dim@arg\p@\relax } % \end{macrocode} % And |\g@double| is even simpler: % \begin{macrocode} \def\g@double#1{% \csname g@@#1 \endcsname } % \end{macrocode} % \end{macro}\end{macro}\end{macro}\end{macro} % % \subsection{Macros for calculus on floats} % % We need some macros that provide simple arithmetic calculation on % floats. Those are defined now. % % \begin{macro}{\g@advance} % Given a float $f_1$, the following macro performs $f_1 := f_1 + f_2$ % where $f_2$ may be either a \TeX\ dimension or a float: % If |\csname|$f_2$|\encsname| does not evaluate to some control sequence, % it is assumed to denote a \TeX\ dimension (e.g. |5pt|, or |\the\something|) % \begin{macrocode} \def\g@advance#1#2{% \g@dim{#1}{\g@d@tmpa}% f_1 := #1 \expandafter\ifx\csname g@@#2 \endcsname\relax \g@d@tmpb=#2% f_2 := #2 (TeX dimension) \else \g@dim{#2}{\g@d@tmpb}% f_2 := #2 (float) \fi \advance\g@d@tmpa\g@d@tmpb\relax% f_1 += f_2 \g@defdim{#1}{\g@d@tmpa}% #1 := f_1 } % \end{macrocode} % \end{macro} % % \begin{macro}{\g@min}\begin{macro}{\g@minD} % Given two floats $f_1, f_2$ and a \TeX\ dimension $d_3$, % the following macro performs $d_3 := \min\{f_1, f_2\}$. % \begin{macrocode} \def\g@min#1#2#3{% \g@dim{#1}{\g@d@tmpa}% f_1 := #1 \g@dim{#2}{\g@d@tmpb}% f_2 := #2 \ifdim \g@d@tmpa<\g@d@tmpb #3=\g@d@tmpa \else #3=\g@d@tmpb \fi \relax } % \end{macrocode} % There is a so called $D$-version of the latter macro. By use of |\g@min|, % this macro also calculates $\min\{f_1,f_2\}$, but its result is translated % into a double representation which is then stored in control sequence |#3|. % \begin{macrocode} \def\g@minD#1#2#3{% \g@min{#1}{#2}{\g@d@tmpc}% \edef\g@minD@arg{\the\g@d@tmpc}% \edef\g@minD@arg{\expandafter\g@del\g@minD@arg}% \edef#3{\g@minD@arg}% } % \end{macrocode} % \end{macro}\end{macro} % \begin{macro}{\g@max}\begin{macro}{\g@maxD} % And here is are the two opposite macros of the preceeding two. % \begin{macrocode} \def\g@max#1#2#3{% \g@dim{#1}{\g@d@tmpa}% \g@dim{#2}{\g@d@tmpb}% \ifdim \g@d@tmpa<\g@d@tmpb #3=\g@d@tmpb \else #3=\g@d@tmpa \fi \relax } \def\g@maxD#1#2#3{% \g@max{#1}{#2}{\g@d@tmpc}% \edef\g@maxD@arg{\the\g@d@tmpc}% \edef\g@maxD@arg{\expandafter\g@del\g@maxD@arg}% \edef#3{\g@maxD@arg}% } % \end{macrocode} % \end{macro}\end{macro} % \begin{macro}{\g@dist}\begin{macro}{\g@distD} % Given two floats $f_1, f_2$ and a \TeX\ dimension $d_3$, the following % macro performs $d_3 := f_1 - f_2$. % \begin{macrocode} \def\g@dist#1#2#3{% \g@dim{#1}{\g@d@tmpa}% f_1 := #1 \g@dim{#2}{\g@d@tmpb}% f_2 := #2 \ifdim \g@d@tmpa<\g@d@tmpb #3=\g@d@tmpb \advance#3 by-\g@d@tmpa \else #3=\g@d@tmpa \advance#3 by-\g@d@tmpb \fi \relax } % \end{macrocode} % Again, we have a $D$-version, where the result is given in double % representation. % \begin{macrocode} \def\g@distD#1#2#3{% \g@dist{#1}{#2}{\g@d@tmpc}% \edef\g@distD@arg{\the\g@d@tmpc}% \edef\g@distD@arg{\expandafter\g@del\g@distD@arg}% \edef#3{\g@distD@arg}% } % \end{macrocode} % \end{macro}\end{macro} % % \begin{macro}{\g@updateArea}\begin{macro}{\g@update} % While the macros that we have seen in this section so far are mainly used % for elementary drawing purposes, we now define a slightly more sophisticated % macro. % It is needed to update the leftmost $x$-values of the so-far matrix operation % set (in terms of row operations). It is invoked after adding a new operation % to the set. % % To update a float $f_1$ with respect to $f_2$ is defined to execute % $f_1 := \max\{f_1, f_2\}$. This is what the following macro does. % \begin{macrocode} \def\g@update#1#2{% \g@dim{#2}{\g@d@tmpe} \g@dim{#1}{\g@d@tmpb} \ifdim \g@d@tmpe>\g@d@tmpb \g@defdim{#1}{\g@d@tmpe}% \fi } % \end{macrocode} % % The matrix dimensions are stored in floats named % $\meta{name} + \meta{index}$ where \meta{name} spcifies the dimension % (e.g. ``cy'' for the current $y$ values of a \emph{c}olumn) and \meta{index} % is the index of the row/column to which the float's value belongs. % % Now, the following macro iterates over $i\in\{|#3|,\dots,|#4|\}$ and updates % all the floats with name $|#2| + i$ with respect to float |#1|. % \begin{macrocode} \def\g@updateArea#1#2#3#4{\g@for#3\to#4\do{\g@update{#2##1}{#1}}} % \end{macrocode} % \end{macro}\end{macro} % % % % \subsection{Macros for measurements} % % The macros defined in this section are used to measure the dimensions % of a given matrix and store the measured values into floats. % % For each row~$i$ of the matrix, the $y$-position of the center of % row~$i$ with respect to the bottom of the matrix is stored in a float % named $|ry| + i$. Another float $|rx| + i$ is initialized to~$0$. This latter % value will always contain the leftmost position at which a new row operation can % start without intersecting previous operations that crossed row~$i$. % % For each row~$j$ of the matrix we similarly define the values % $|cx| + i$ and $|cy| + i$. Note that $|cx| + i$ corresponds to $|ry| + i$ % and $|cy| + i$ corresponds to $|rx| + i$, since column operations grow % vertically whereas row operations grow horizontally. % % \begin{macro}{\g@measureRows} % We first consider row measuring. The following macro assumes that the current % box is a |\vbox| that only contains a copy of the matrix, % i.e. one |\hbox| per row including all the intermediate glues and kerns and % whatever. You can initialize what we assume to have by saying % % \medskip % {\obeylines |\vbox{\halign{|\dots|}}| (typeset the matrix) % |\box0=\lastbox| (save the matrix) % |\vbox{\unhcopy0\g@measureRows}| (measure the row's heights) % |\box0| (restore the matrix)} % \medskip % % \noindent Caution: The following macros will not work if the matrix was not % constructed with an |\halign| because special knowledge about the structure % of |\halign|'s result is used. % % It is assumed that |\g@d@tmp| initially contains the $y$-position of the % matrix's bottom. It is further assumed that |\g@maxrow| contains the total % number of rows. These two counters will be modified during the recursion. % \begin{macrocode} \def\g@measureRows{% \setbox\g@trash\lastbox \ifnum\g@maxrow<0% base case: this box is not part of the matrix \else \ifdim\ht\g@trash=0pt% \advance\g@d@tmp\lastskip\unskip \advance\g@d@tmp\lastkern\unkern \unpenalty \else \advance\g@d@tmp\dp\g@trash \advance\g@d@tmp\g@axisHeight \g@defdim{ry\the\g@maxrow}{\g@d@tmp}% \g@defdim{rx\the\g@maxrow}{\z@}% \advance\g@d@tmp-\g@axisHeight \advance\g@d@tmp\ht\g@trash \advance\g@maxrow-1% \fi \g@measureRows \fi } % \end{macrocode} % \end{macro} % \begin{macro}{\g@measureCols} % In fact, the row measurement is the easier case. The measurement of column % widths is more complicated by two reasons: 1.\ The number of columns is % unknown, and 2.\ we will meet the cells in reverse order. % % This is why column measurement is implemented in two main steps. First the % width of each cell and the distance between two preceeding cells is % measured and stored into temporary floats $|ct| + \meta{index}$ (distance) and % $|cy| + \meta{index}$ (width), where \meta{index} is counted from back to front. % By the way, we count the number of columns. % % In the base case of the recursion we start a second recursion that will % calculate the final results out of the intermediate results and that will % arange the indexing properly. % % What input do we expect? It is assumed that the current box is an |\hbox| % whose first item is an |\hbox| of width 100cm (to detect the base case), % followed by a copy of the last row of the matrix to measure. See the % definition of |g@matrix| to see how such a situation can be constructed. % % We further assume that |g@d@tmp| is initialized to 0.0pt. % % \begin{macrocode} \def\g@measureCols{% \setbox\g@trash\lastbox \ifdim \wd\g@trash=100cm% % base case. Invert the ordering and sum the dimensions. \g@defdouble{ct\the\g@maxcol}{0}% \g@defdouble{cy\the\g@maxcol}{0}% \global\g@maxcol\g@maxcol \g@c@tmp\g@maxcol \advance\g@c@tmp-1% \g@measureColsSucc \global\advance\g@maxcol-1% \else \ifdim \ht\g@trash=0pt% \advance\g@d@tmp\lastskip\unskip \advance\g@d@tmp\lastkern\unkern \unpenalty \else % use ct temporaryly to store the skip between % colnr + 1 and colnr. \g@defdim{ct\the\g@maxcol}{\g@d@tmp}% \g@d@tmp\z@ % use cy temporaryly to store the cell's width. \g@defdim{cy\the\g@maxcol}{\wd\g@trash}% \advance\g@maxcol1% \fi \g@measureCols \fi } % \end{macrocode} % Now, the macro for the second step of the measurement algorithm is defined. % This is easier, since we now already know the total number of columns that % have been measured. Roughly speaking, we sum their width's from left to right % to obtain the $x$-values of the horizontal center of each column. Furthermore, % the $y$-values are now initialized to~$0$, and the order is inverted. % % Knowledge about the implementation of |g@matrix| is used! % % \begin{macrocode} \def\g@measureColsSucc{% \ifnum \g@c@tmp<0\else \g@c@tmpa=\g@maxcol \advance\g@c@tmpa-\g@c@tmp \advance\g@c@tmpa-1 \g@dim{cy\the\g@c@tmp}{\g@d@tmpa}% width of this cell \g@dim{ct\the\g@c@tmp}{\g@d@tmpb}% glue right to this cell \advance\g@d@tmp.5\g@d@tmpa% \g@defdouble{cy\the\g@c@tmp}{0}% \g@defdim{cx\the\g@c@tmpa}{\g@d@tmp}% \advance\g@d@tmp.5\g@d@tmpa \advance\g@d@tmp\g@d@tmpb \ifnum \g@c@tmpa=0% \advance\g@d@tmp.5\g@tab \fi \advance\g@c@tmp-1 \g@measureColsSucc \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\g@measureAxis} % This is an easier macro. It measures and defines some common lengths, % e.g.\ the distance between bottom line and math axis, and the dimensions % of math arrows which are used for drawing arrows in operations. % \begin{macrocode} \def\g@measureAxis{% % 1. Where is the math axis relative to the ground line? \setbox\g@trash=\hbox{$\vcenter{\hbox to 5pt{}}$}% \global\g@axisHeight=\ht\g@trash % 2. What is the minimum width of a horizontal arrow? \setbox\g@trash=\hbox{$\leftarrow$}% \global\g@arrowwd\wd\g@trash % 3. What is the minimum height of a vertical arrow? \setbox\g@trash=\vbox{\g@vertline}% \global\g@arrowht=\ht\g@trash \global\advance\g@arrowht\dp\g@trash \global\advance\g@arrowht\lineskip % 4. What should be the thickness of ordinary lines? \global\g@linethickness=\fboxrule\relax } % \end{macrocode} % \end{macro} % % \begin{macro}{\g@measureArea} % The last marco of this subsection provides the measurement of % a set of floats. (Therefore, it is rather a calculus macro.) % % Assuming that |#4| is a float identifier and for all $i\in I:=\{|#2|,\dots,|#3|\}$ % $|#1|+i$ is a float identifier, the macro does % \[ % |#4| := \max_{i\in I}\{|#1| + i\} % \] % \begin{macrocode} \def\g@measureArea#1#2#3#4{% \g@defdim{#4}{\z@}% \g@for#2\to#3\do{% \g@max{#1##1}{#4}{\g@d@tmpe}% \g@defdim{#4}{\g@d@tmpe}% }% } % \end{macrocode} % \end{macro} % % % % \subsection{Macros for drawing purposes} % % This Section defines low level macros for drawing purposes within a % |picture| environment by use of floats. % % \begin{macro}{\g@vline} % Let $f_1, f_2$ and~$f_3$ be floats. Then, % % \begin{example} % |\g@vline{|$f_1$|}{|$f_2$|}{|$f_3$|}| % \switch\end{example} % % \noindent draws a vertical line from $(f_1,f_2)$ to $(f_2, f_3)$. % \begin{macrocode} \def\g@vline#1#2#3{% \g@minD{#2}{#3}{\min} \g@distD{#2}{#3}{\dist} \put(\g@double{#1},\min){\line(0,1){\dist}} } % \end{macrocode} % \end{macro} % \begin{macro}{\g@vvline} % Let $f_1, f_2$ and~$f_3$ be floats. Then, % % \begin{example} % |\g@vvline{|$f_1$|}{|$f_2$|}{|$f_3$|}| % \switch\end{example} % % \noindent draws a vertical line of length~$|f_3|$, starting at $(f_1,f_2)$, i.e.\ % a line from $(f_1,f_2)$ to $(f_1, f_2+f_3)$. % \begin{macrocode} \def\g@vvline#1#2#3{% \put(\g@double{#1},\g@double{#2}){\line(0,1){\g@double{#3}}} } % \end{macrocode} % \end{macro} % \begin{macro}{\g@varrow} % Let $f_1, f_2$ and~$f_3$ be floats. Then, % % \begin{example} % |\g@varrow{|$f_1$|}{|$f_2$|}{|$f_3$|}| % \switch\end{example} % % \noindent draws an arrow from $(f_1, \max\{f_2,f_3\})$ to $(f_1, \min\{f_2,f_3\})$. % \begin{macrocode} \def\g@varrow#1#2#3{% \g@dim{#2}{\g@d@tmpa}% \g@dim{#3}{\g@d@tmpb}% \advance\g@d@tmpb-\g@d@tmpa \g@cbox{#1}{#2}{\g@downarrow{\g@d@tmpb}}% } % \end{macrocode} % \end{macro} % \begin{macro}{\g@hline} % Let $f_1, f_2$ and~$f_3$ be floats. Then, % % \begin{example} % |\g@hline{|$f_1$|}{|$f_2$|}{|$f_3$|}| % \switch\end{example} % % \noindent draws a horizontal line from $(f_1,f_2)$ to $(f_3,f_2)$. % \begin{macrocode} \def\g@hline#1#2#3{% \g@minD{#1}{#3}{\min}% \g@distD{#1}{#3}{\dist}% \put(\min,\g@double{#2}){\line(1,0){\dist}}% } % \end{macrocode} % \end{macro} % \begin{macro}{\g@hhline} % Let $f_1, f_2$ and~$f_3$ be floats. Then, % % \begin{example} % |\g@hhline{|$f_1$|}{|$f_2$|}{|$f_3$|}| % \switch\end{example} % % \noindent draws a horizontal line of length~$|f_3|$, starting at $(f_1,f_2)$, % i.e.\ a line from $(f_1,f_2)$ to $(f_1+f_3, f_2)$. % \begin{macrocode} \def\g@hhline#1#2#3{% \put(\g@double{#1},\g@double{#2}){\line(1,0){\g@double{#3}}}% } % \end{macrocode} % \end{macro} % \begin{macro}{\g@harrow} % Let $f_1, f_2$ and~$f_3$ be floats. Then, % % \begin{example} % |\g@harrow{|$f_1$|}{|$f_2$|}{|$f_3$|}| % \switch\end{example} % % \noindent draws an arrow from $(\max\{f_1,f_3\},f_2)$ to $(\min\{f_1,f_3\},f_2)$. % \begin{macrocode} \def\g@harrow#1#2#3{% \g@dim{#1}{\g@d@tmpa}% \g@dim{#3}{\g@d@tmpb}% \advance\g@d@tmpb-\g@d@tmpa \advance\g@d@tmpb2\p@ \g@rbox{#1}{#2}{\hbox to\g@d@tmpb{\leftarrowfill}}% } % \end{macrocode} % \end{macro} % % The remaining two macros allow to put arbitrary math material to a % specified position. Those are used for typesetting so called labels within % matrix operations, for example, the factor at an |\add| arrow. % % \begin{macro}{\g@rbox} % The first one is intended to use for row operations. % Assuming that |#1|, |#2| are float identifiers and |#3| is math material, % we put |#3| into an |\hbox| and put that box to point $(|#1|,|#2|)$. % % The box will be vertically aligned to |#2| (i.e., the math axis of |#3| will % be at height |#2|), and horizontally start at |#1|. % % The macro puts the math material of |#3| into |\g@label| and just copies its content when % using, so you can reuse |\g@label| (e.g.\ for measuring purposes). % \begin{macrocode} \def\g@rbox#1#2#3{% \setbox\g@label=\hbox{$\relax#3\relax$}% \ht\g@label\z@\dp\g@label\z@ \setbox\g@label=\hbox{$\mathstrut\box\g@label$}% \put(\g@double{#1},\g@double{#2})% {\makebox(0,0)[l]{\kern-\p@\copy\g@label}}% } % \end{macrocode} % \end{macro} % \begin{macro}{\g@cbox} % The last macro of this section does the corresponding job for columns. % % Here, |#3| will be centered horizontally to |#1|, whereas |#2| denotes the % height of the label's bottom. % % Again, you can reuse the constructed box, it remains in register |\g@label|. % \begin{macrocode} \def\g@cbox#1#2#3{% \setbox\g@label=\hbox{$\relax#3\relax$}% \setbox\g@label=\hbox{\raise\dp\g@label\box\g@label}% \put(\g@double{#1},\g@double{#2})% {\makebox(0,0)[b]{\copy\g@label}}% } % \end{macrocode} % \end{macro} % % % % \subsection{Generic operation commands} % % Before |\halign| begins, the matrix construction macro defines, what to do % if the matrix is finished. This is defined in |\g@endregion| (see the next % section for further information). % % The |\rowops| and |\colops| commands are temporarily set to |\g@east| or % |\g@north|, respectively. Thus, when entering an operation part, the first % thing to do is to invoke |\g@endregion| to do the things that have to be % done when the matrix input finishes. After that, |\g@endregion| has to be % redefined to avoid doing the same process two times. Fortunately, |\g@north| % and |\g@east| can easily reuse |\g@endregion| and store there those things % that have to be done at the end of a region. % % Hence, each switching to another part of the matrix input consists of three % parts: % \begin{enumerate} % \item Invoke |\g@endregion| to finish the current input part. % \item Redefine |\g@endregion| to do the stuff that has to be done at the end % of the region that is now starting. The result of the region is stored into % a special box register which is used in the |gmatrix| environment. % \item Initialize the new region. % \end{enumerate} % You can imagine that it is easy to define further regions (e.g.\ for operations % to the right or below the matrix). % % The two predefined regions |\rowops| and |\colops| are very similar, so we will % show just one of them in this documentation. % % \begin{macro}{\g@north} % The |\g@north| macro is the generic version of |\colops|, its corresponding % part is |\g@east|. % % \begin{macrocode} \def\g@north{% % \end{macrocode} % 1.\ Finish the current region % \begin{macrocode} \g@endregion % \end{macrocode} % 2.\ Redefine |\g@endregion| and prevent |\colops| from being called again. % \begin{macrocode} \gdef\colops{\PackageError{gauss} {Two sets of column operations are specified in % just one matrix. This is not allowed.}}% \gdef\g@endregion{% \end{picture}\egroup \g@measureArea{cy}{0}{\the\g@maxcol}{sum}% \g@dim{sum}{\ht\g@northbox}% \global\setbox\g@northbox=\hbox{% \raise\colarrowsep\box\g@northbox}% }% % \end{macrocode} % 3.\ Initialization of the |\colops| region: Define the operation macros to be % the corresponding private versions of this region (see below), set $|sum|:=0$ % and start the |picture| environment where the operations are painted in. % \begin{macrocode} \def\swap{\g@north@arrow11\colswapfromlabel\colswaptolabel}% \def\add{\g@north@arrow01\coladdfromlabel\coladdtolabel}% \let\mult\g@north@mult \g@defdim{sum}{\z@}% \global\setbox\g@northbox=\hbox\bgroup \begin{picture}(\g@double{w},0)(0,0) \linethickness{\g@linethickness}% } % \end{macrocode} % \end{macro} % \begin{macro}{\g@north@mult} % The multiplication macro is the simplest one because it affects only one single % column. % \begin{macrocode} \def\g@north@mult#1#2{% \ifx *#1 % \end{macrocode} % Reduce |*| to a set of numbers. % \begin{macrocode} \g@for0\to\g@maxcol\do{\g@north@mult{##1}{#2}}% \else % \end{macrocode} % Now |#1| is a number. Is it an index? % \begin{macrocode} \g@checkBounds{c}{0}{#1}{\the\g@maxcol}% \ifg@indexCorrect % \end{macrocode} % Yes, it is. Typeset the operation. % \begin{macrocode} \g@cbox{cx#1}{cy#1}{\colmultlabel{#2}}% \g@dim{cy#1}{\g@d@tmpc}% \advance\g@d@tmpc\ht\g@label \g@defdim{cy#1}{\g@d@tmpc}% \g@advance{cy#1}{\the\opskip}% \g@update{sum}{cx#1}% \fi \fi } % \end{macrocode} % \end{macro} % \begin{macro}{\g@north@arrow} % % The |\g@north@arrow| macro is a generalisation of |\swap| and |\add|. % It takes the following eight parameters: % % \begin{itemize} % \item |#1|: 0 to make the `from' line non-arrowed, 1 to get an arrow tip % \item |#2|: 0 to make the `to' line non-arrowed, 1 to get an arrow tip % \item |#3|: macro for `from' label rendering % \item |#4|: macro for `to' label rendering % \item |#5|: [opt] label of the `from' row % \item |#6|: [opt] label of the `to' row % \item |#7|: index of the `from' row % \item |#8|: index of the `to' row % \end{itemize} % % If only one of the two optional arguments is given, then it is taken as |#5| % and |#6| is taken empty. If both are missing, both are taken empty. % % In |\g@north| above, |\add| is defined to % \begin{example} % |\g@north@arrow01\coladdfromlabel\coladdtolabel|\kern-20em % \switch\end{example} % and |\swap| is defined as % \begin{example} % |\g@north@arrow11\colswapfromlabel\colswaptolabel|\kern-20em % \switch\end{example} % % \begin{macrocode} \def\g@north@arrow#1#2#3#4{% \@ifnextchar[% {\g@north@arrow@a{#1}{#2}{#3}{#4}}% {\g@north@arrow@b{#1}{#2}{#3}{#4}{}[]}% } \def\g@north@arrow@a#1#2#3#4[#5]{% \@ifnextchar[% {\g@north@arrow@b{#1}{#2}{#3}{#4}{#5}}% {\g@north@arrow@b{#1}{#2}{#3}{#4}{#5}[]}% } \def\g@north@arrow@b#1#2#3#4#5[#6]#7#8{% \ifx *#7 % \end{macrocode} % Reduce star indices to loops of number indices. % |**| needs a special handling. % \begin{macrocode} \ifx *#8 \g@for0\to\g@maxcol\do{% \g@north@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{##1}{*}}% \else % \end{macrocode} % Two loops rather than one because going from |#8| down % to 0 looks better than going from 0 to |#8| % \begin{macrocode} \g@for#8\to0\do{% \g@north@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{##1}{#8}}% \g@for#8\to\g@maxcol\do{% \g@north@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{##1}{#8}}% \fi \else \ifx *#8 % \end{macrocode} % Reduce star indices to loops of number indices. % \begin{macrocode} \g@for#7\to0\do{% \g@north@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{#7}{##1}}% \g@for#7\to\g@maxcol\do{% \g@north@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{#7}{##1}}% \else % \end{macrocode} % Now, |#7| and |#8| are numbers. % \begin{macrocode} \ifnum #7=#8\else \g@checkBounds{c}{0}{#7}{\the\g@maxcol}% \ifg@indexCorrect \g@checkBounds{c}{0}{#8}{\the\g@maxcol}% \ifg@indexCorrect % \end{macrocode} % Now, |#7| and |#8| are different from each other, and % both of them are legal indices. % Store the current hights of the operations tower % above column |#7| and |#8| into |tmp1| and |tmp2|, % respectively. % \begin{macrocode} \g@defdouble{tmp1}{\g@double{cy#7}}% \g@defdouble{tmp2}{\g@double{cy#8}}% % \end{macrocode} % Find out the height of the horizontal connection % line. % First increment |#7| and |#8| by the minimum amounts. % \begin{macrocode} \ifx0#1 \g@advance{cy#7}{\the\colopminsize}% \else \g@advance{cy#7}{\the\g@arrowht}% \fi \ifx0#2 \g@advance{cy#8}{\the\colopminsize}% \else \g@advance{cy#8}{\the\g@arrowht}% \fi % \end{macrocode} % Incorporate the columns between |#7| and |#8| into % the height. Then |sum| denotes the level of the % horizontal line. % \begin{macrocode} \g@measureArea{cy}{#7}{#8}{sum}% % \end{macrocode} % Draw arrows and/or vertical lines from |#7|'s and % |#8|'s height up to |sum|. % \begin{macrocode} \ifx0#1 \g@vline{cx#7}{tmp1}{sum}% \else \g@varrow{cx#7}{tmp1}{sum}% \fi \ifx0#2 \g@vline{cx#8}{tmp2}{sum}% \else \g@varrow{cx#8}{tmp2}{sum}% \fi % \end{macrocode} % Draw the horizontal line. % \begin{macrocode} \g@hline{cx#7}{sum}{cx#8}% % \end{macrocode} % Insert space between the horizontal line and % the labels if at least one of the labels |#5| and |#6| is not empty. % Typeset the labels into boxes and measure them. % \begin{macrocode} \setbox\g@b@tmpa=\hbox{$#3{#5}$}% \setbox\g@b@tmpb=\hbox{$#4{#6}$}% \ifdim\ht\g@b@tmpa>\z@ \g@advance{sum}{\the\labelskip}% \else \ifdim\ht\g@b@tmpb>\z@ \g@advance{sum}{\the\labelskip}% \fi \fi % \end{macrocode} % Draw the `from' label if there is one % \begin{macrocode} \g@d@tmpc\z@ \ifdim\ht\g@b@tmpa>\z@ \g@cbox{cx#7}{sum}{\kern-\p@\vcenter{\box\g@b@tmpa}}% \g@d@tmpc=\ht\g@label \fi % \end{macrocode} % Draw the `to' label if there is one % \begin{macrocode} \ifdim\ht\g@b@tmpb>\z@ \g@cbox{cx#8}{sum}{\kern-\p@\vcenter{\box\g@b@tmpb}}% \ifdim \ht\g@label>\g@d@tmpc \g@d@tmpc=\ht\g@label \fi \fi % \end{macrocode} % Advance the sum by the maximum height of the two % labels and the desired space between two consecutive % operations % \begin{macrocode} \g@advance{sum}{\the\g@d@tmpc}% \g@advance{sum}{\the\opskip}% % \end{macrocode} % Update all column tower heights between |#7| and |#8| to % |sum|. % \begin{macrocode} \g@updateArea{sum}{cy}{#7}{#8}% % \end{macrocode} % That's it. % \begin{macrocode} \fi \fi \fi \fi \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\g@east} % \begin{macro}{\g@east@mult} % % The corresponding eastern macros are very similar to the % above defined northern versions. Maybe there is a way % to define generic operation commands once for all regions, % but this would at least lead to less comprehesive definitions. % % We skip the definitions of |\g@east|, |\g@east@mult| and |\g@east@arrow| % in this documentation. % \def\g@east{% \g@endregion \def\swap{\g@east@arrow11\rowswapfromlabel\rowswaptolabel} \def\add{\g@east@arrow01\rowaddfromlabel\rowaddtolabel} \let\mult\g@east@mult \g@defdim{sum}{\z@}% \gdef\rowops{\PackageError{gauss}{Two sets of row operations were specified in % just one matrix. This is not allowed.}} \gdef\g@endregion{% \end{picture}\egroup \g@measureArea{rx}{0}{\the\g@maxrow}{sum}% \g@dim{sum}{\wd\g@eastbox}% }% \global\setbox\g@eastbox=\hbox\bgroup \begin{picture}(0,\g@double{h})(0,0) \linethickness{\g@linethickness}% } \def\g@east@mult#1#2{% \ifx *#1 \g@for0\to\g@maxrow\do{\g@east@mult{##1}{#2}}% \else \g@checkBounds{r}{0}{#1}{\the\g@maxrow}% \ifg@indexCorrect \g@rbox{rx#1}{ry#1}{\rowmultlabel{#2}} \g@dim{rx#1}{\g@d@tmpc}\advance\g@d@tmpc\wd\g@label \g@defdim{rx#1}{\g@d@tmpc}% \g@advance{rx#1}{\the\labelskip}% \g@update{sum}{rx#1}% \fi \fi } % \def\g@east@arrow#1#2#3#4{% \@ifnextchar[% {\g@east@arrow@a{#1}{#2}{#3}{#4}}% {\g@east@arrow@b{#1}{#2}{#3}{#4}{}[]}% } \def\g@east@arrow@a#1#2#3#4[#5]{% \@ifnextchar[% {\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}}% {\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}[]}% } \def\g@east@arrow@b#1#2#3#4#5[#6]#7#8{% \ifx *#7 \ifx *#8 \g@for0\to\g@maxrow\do{\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{##1}{*}}% \else \g@for#8\to0\do{\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{##1}{#8}}% \g@for#8\to\g@maxrow\do{\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{##1}{#8}}% \fi \else \ifx *#8 \g@for#7\to0\do{\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{#7}{##1}}% \g@for#7\to\g@maxrow\do{\g@east@arrow@b{#1}{#2}{#3}{#4}{#5}[#6]{#7}{##1}}% \else \ifnum #7=#8\else \g@checkBounds{r}{0}{#7}{\the\g@maxrow}% \ifg@indexCorrect \g@checkBounds{r}{0}{#8}{\the\g@maxrow}% \ifg@indexCorrect \g@defdouble{tmp1}{\g@double{rx#7}}% \g@defdouble{tmp2}{\g@double{rx#8}}% \ifx0#1 \g@advance{rx#7}{\the\rowopminsize}% \else \g@advance{rx#7}{\the\g@arrowwd}% \fi \ifx0#2 \g@advance{rx#8}{\the\rowopminsize}% \else \g@advance{rx#8}{\the\g@arrowwd}% \fi \g@measureArea{rx}{#7}{#8}{sum}% \ifx0#1 \g@hline{tmp1}{ry#7}{sum}% \else \g@harrow{tmp1}{ry#7}{sum}% \fi \ifx0#2 \g@hline{tmp2}{ry#8}{sum}% \else \g@harrow{tmp2}{ry#8}{sum}% \fi \g@vline{sum}{ry#7}{ry#8}% \setbox\g@b@tmpa=\hbox{$#3{#5}$}% \setbox\g@b@tmpb=\hbox{$#4{#6}$}% \ifdim\wd\g@b@tmpa>\z@ \g@advance{sum}{\the\labelskip}% \else \ifdim\wd\g@b@tmpb>\z@ \g@advance{sum}{\the\labelskip}% \fi \fi \g@d@tmpc\z@ \ifdim\wd\g@b@tmpa>\z@ \g@rbox{sum}{ry#7}{\kern-\p@\vcenter{\box\g@b@tmpa}}% \g@d@tmpc=\wd\g@label \fi \ifdim\wd\g@b@tmpb>\z@ \g@rbox{sum}{ry#8}{\kern-\p@\vcenter{\box\g@b@tmpb}}% \ifdim \wd\g@label>\g@d@tmpc \g@d@tmpc=\wd\g@label \fi \fi \g@advance{sum}{\the\g@d@tmpc}% \g@advance{sum}{\the\opskip}% \g@updateArea{sum}{rx}{#7}{#8}% \fi \fi \fi \fi \fi } % \end{macro}\end{macro} % % % % \subsection{The \texttt{gmatrix} environment} % % |gmatrix| calls |#1matrix| where |matrix| is redefined to |g@matrix|. % |g@matrix| typesets the matrix using |\halign| and stores the % operations into box registers |\g@northbox| and |\g@eastbox|, respectively. % The matrix itself is stored into |\g@matrixbox|. % % The ``real'' typesetting is done at the end of |gmatrix|. % % \begin{environment}{gmatrix} % \dots and here is |gmatrix|: % \begin{macrocode} \newenvironment{gmatrix}[1][] {\unitlength=1pt\def\g@environment{#1matrix}% \begin{g@matrix}% }{% \end{g@matrix}% % \end{macrocode} % Delete temporarily the definition of |matrix|. % \begin{macrocode} \let\matrix\@empty \let\endmatrix\@empty % \end{macrocode} % Find out sizes of the matrix. Set |\g@d@tmp| to the height of the matrix. % \begin{macrocode} \g@d@tmpa\ht\g@matrixbox \advance\g@d@tmpa\p@ \g@d@tmpb\dp\g@matrixbox \advance\g@d@tmpb\p@ \g@d@tmp\ht\g@northbox \ht\g@northbox\z@ \dp\g@northbox\z@ \ifdim \g@d@tmp>\z@ \advance\g@d@tmp-\opskip \fi \advance\g@d@tmp.5\ht\g@matrixbox \advance\g@d@tmp.5\dp\g@matrixbox % \end{macrocode} % Start the matrix environment to get the left delimiter. % \begin{macrocode} \begin{\g@environment}% % \end{macrocode} % Typeset the column operations to the north of the matrix, % and the matrix itself. % \begin{macrocode} \vcenter{\hbox{% \rlap{\raise\ht\g@matrixbox\box\g@northbox}% north % 1 additional pt above and below the matrix \rule\z@\g@d@tmpa\lower\g@d@tmpb\null \box\g@matrixbox% the matrix itself }}% % \end{macrocode} % Close the matrix environment to get now the right delimiter. % \begin{macrocode} \end{\g@environment}% % \end{macrocode} % Finally typeset the eastern operations. % Insert vertical space of |\g@d@tmp| (the height % of the matrix) and horizontal space of |\rowarrowsep| before. % \begin{macrocode} \rule\rowarrowsep\z@ \rule\z@\g@d@tmp \g@dim{d}{\g@d@tmpa}% \vcenter{\hbox{\lower\g@d@tmpa\box\g@eastbox}}% } % \end{macrocode} % \end{environment} % Here is the definition of |\g@endmatrix|. This is the initial |\g@endregion| % which is defined within |\begin{gmatrix}| to finish the matrix input. % \begin{macrocode} \def\g@endmatrix{% \mathstrut\crcr \egroup % end of \halign \egroup % end of \vbox, this contains the matrix % \end{macrocode} % Save the matrix into matrixbox. % \begin{macrocode} \global\setbox\g@matrixbox\lastbox % \end{macrocode} % Measure the matrix' dimensions. % \begin{macrocode} \g@measureAxis \setbox\g@trash=\vbox{% \unvcopy\g@matrixbox % \end{macrocode} % Copy the last row of the matrix into |\g@eastbox| and reinsert it to the vbox. % \begin{macrocode} \global\setbox\g@eastbox=\lastbox \copy\g@eastbox \g@d@tmp\z@ {\g@measureRows}% measure rows }% \setbox\g@trash=\hbox{% % \end{macrocode} % Insert a box of width 100cm to recognize the beginning of the hbox within the % measurement recursion. % \begin{macrocode} \hbox to 100cm{.\hfill.}% \unhbox\g@eastbox \g@d@tmp\z@ {\g@measureCols}% measure columns }% % \end{macrocode} % Determine global dimensions of the matrix (total height, etc.). % \begin{macrocode} \g@d@tmpa=\ht\g@matrixbox\advance\g@d@tmpa\dp\g@matrixbox \g@defdim{h}{\g@d@tmpa}% \g@defdim{w}{\wd\g@matrixbox}% \g@defdim{d}{\dp\g@matrixbox}% }% % \end{macrocode} % \begin{environment}{g@matrix} % Finally, we have the following definition of |g@matrix|: % \begin{macrocode} \edef\g@prae{\hfil\noexpand\mathstrut$\relax} \edef\g@post{\relax$\hfil} \newenvironment{g@matrix} {\setbox\g@trash=\hbox\bgroup \global\g@maxrow@old\g@maxrow \global\g@maxcol@old\g@maxcol \global\g@maxrow0% \global\g@maxcol0% \let\rowops\g@east \let\colops\g@north \vbox\bgroup % count rows while typesetting \def\\{\mathstrut\cr\global\advance\g@maxrow1\relax}% \global\let\g@endregion\g@endmatrix \global\g@tab=2\arraycolsep \ialign\bgroup\g@prae##\g@post&&\kern\g@tab\g@prae##\g@post\cr }{% \g@endregion \egroup % end of \hbox % enable nested gmatrixes (for DniQ :-) \global\g@maxrow\g@maxrow@old \global\g@maxcol\g@maxcol@old \global\let\g@endregion\g@endmatrix \global\let\rowops\g@east \global\let\colops\g@north } % \end{macrocode} % \end{environment} % % % % \subsection{Public tools} % % \begin{macro}{\newmatrix} % The |\newmatrix| command allows to define new matrix environments with % special delimiters as described in Section~1. % % \begin{macrocode} \def\newmatrix#1#2#3{% \ifx g#3 \else \ifx {#3}{g@} \else \expandafter\ifx\csname#3matrix\endcsname\relax \newenvironment{#3matrix}% {\left#1\begin{matrix}}{\end{matrix}\right#2}% \else \renewenvironment{#3matrix}% {\left#1\begin{matrix}}{\end{matrix}\right#2}% \fi \fi \fi } % \end{macrocode} % % For compatibility reasons, we redefine predefined matrix environments such % as |pmatrix|. This is necessary to avoid problems that arise when dealing with % earlier \AmS\TeX\ versions. % % \begin{macrocode} \newmatrix()p \newmatrix[]b \newmatrix\lbrace\rbrace B \newmatrix\lvert\rvert v \newmatrix\lVert\rVert V % \end{macrocode} % \end{macro} % % \begin{macro}{\rowmultlabel}\begin{macro}{\colmultlabel} % \begin{macro}{\rowaddfromlabel}\begin{macro}{\coladdfromlabel} % \begin{macro}{\rowaddtolabel}\begin{macro}{\coladdtolabel} % \begin{macro}{\rowswapfromlabel}\begin{macro}{\colswapfromlabel} % \begin{macro}{\rowswaptolabel}\begin{macro}{\colswaptolabel} % Labels of operations are typeset using the so-called fontifying macros % described in Section~\ref{ssec:atp}. % All of them take exaclty one argument, and they are called within math % mode. The user may redefine them to adjust the appearence of operations % according to his needs. The following is the standard definition: % \begin{macrocode} \def\rowmultlabel#1{|\,#1} \def\rowswapfromlabel#1{} \def\rowswaptolabel#1{} \def\rowaddfromlabel#1{\scriptstyle #1} \def\rowaddtolabel#1{\scriptscriptstyle +} \def\colmultlabel#1{% \underline{\hbox to 1.2em{$\hss\mathstrut{}#1\hss$}}% } \def\colswapfromlabel#1{} \def\colswaptolabel#1{} \def\coladdfromlabel#1{\scriptstyle #1} \def\coladdtolabel#1{\scriptscriptstyle +} % \end{macrocode} % \end{macro}\end{macro} % \end{macro}\end{macro} % \end{macro}\end{macro} % \end{macro}\end{macro} % \end{macro}\end{macro} % % \begin{macro}{\colarrowsep} % \begin{macro}{\rowarrowsep} % \begin{macro}{\labelskip} % \begin{macro}{\opskip} % \begin{macro}{\colopminsize} % \begin{macro}{\rowopminsize} % Finally, we define the public lengths of Section~\ref{ssec:atp}: % \begin{macrocode} \newdimen\colarrowsep\colarrowsep=.5em \newdimen\rowarrowsep\rowarrowsep=.5em \newdimen\opskip\opskip=5pt \newdimen\labelskip\labelskip=4pt \newdimen\colopminsize\colopminsize=3pt \newdimen\rowopminsize\rowopminsize=3pt % \end{macrocode} % \end{macro}\end{macro} % \end{macro}\end{macro} % \end{macro}\end{macro} % % And that's all. % \begin{macrocode} \makeatother % \end{macrocode} % \CheckSum{1188} % \Finale \endinput