\documentclass[]{article}
\usepackage{amsmath,graphicx,supertabular,hyperref,tabularx,ifthen}
\title{TIP \#420: 'vexpr', a Vector Expression Command}
\date{November 15, 2012}
\author{Sean Woods, Andreas Kupries}
\urlstyle{sf}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0pt}
\def\tipversion$#1${\texttt{\$#1\$}}
\def\tiplangle#1{\ensuremath{<}}
\def\tiprangle#1{\ensuremath{>}}
\def\tipbar#1{\ensuremath{|}}
\def\tipmail#1#2{\(\langle\){\small\expandafter\url{#1@#2}}\(\rangle\)}
\ifx\pdfoutput\undefined
\newcommand{\tipimage}[2]{\typeout{Make sure you download #1.eps}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.eps}}{\includegraphics[width=0.8\textwidth]{#1.eps}}}
\newcommand{\tipxref}[1]{}
\newcommand{\tipxrefend}{}
\else
\newcommand{\tipimage}[2]{\typeout{Make sure you create #1.pdf}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.pdf}}{\includegraphics[width=0.8\textwidth]{#1.pdf}}}
\pdfcatalog{/PageMode /UseOutlines}
\newcommand{\tipxref}[1]{\pdfannotlink attr {/C [0.5 0.5 1.0] /Border [0 0 1]} goto name {#1}}
\newcommand{\tipxrefend}{\pdfendlink}
\fi
\newenvironment{tipabstract}{\begin{abstract}}{\end{abstract}}
\begin{document}\maketitle
\begin{center}\begin{tabularx}{\linewidth}{|r@{: }X|}\hline
\textbf{TIP \#420}&\textbf{'vexpr', a Vector Expression Command}\\\hline
Author&

Sean Woods \tipmail{yoda}{etoyoc.com}
\par
Andreas Kupries \tipmail{andreask}{activestate.com}
\\
Created&Thursday, \(\text{15}^{\text{th}}\) November 2012\\
Type&Project\\
Tcl Version&\(8.7\)\\
State&Draft\\
Vote&Pending\\
Version&\tipversion$Revision: 1.6 $\\
Post History&\\
\hline\end{tabularx}\end{center}
\thispagestyle{empty}\pagestyle{empty}
\begin{tipabstract}

This TIP proposes to add a new command to Tcl for manipulating vectors and related mathematical objects. The command, \textbf{vexpr}, will provide C-optimized implementations of generally useful scalar, 2D, 3D and affine transforms. \textbf{vexpr} is a complement to \textbf{expr}, and expects to take in vector arguments and return vector results.
\end{tipabstract}
\tableofcontents\setcounter{page}{0}\clearpage\pagestyle{plain}

\section{Rationale}

With the interest expressed in the community by \cite{tip363}, I am concerned about the introduction of non-scalar results from \textbf{expr} (and parts of the language the use \textbf{expr}). As the goal of that TIP is to introduce vector math operations, a less ambitious, but arguable equally effective technique could be to introduce a dedicated command. In particular, one designed from the ground up to handle the intricacies of vector operations.

\textbf{vexpr} is a vector expression parser. It operates using reverse-polish notation (like an HP calculator.) Each argument is pushed onto the stack, and when a command is detected, they are popped off the stack. The result of the command is pushed onto the stack in their place.

Why? Well mostly for ease of implementation. Partly because there is no PEMDAS equivalent order of operation for matrices and vectors. Once I go through an example or two, it should be a little clearer.

\section{Examples}

To add \{1 1 1\} and \{2 2 2\} I run the following command:
\begingroup\small\begin{verbatim}
vexpr {2 2 2} {1 1 1} +
> 3.0 3.0 3.0
\end{verbatim}
\endgroup

Remember though, we are working with a stack. Items are popped on the stack in a first-in first-out fashion. While for addition it doesn't matter what order we do things, subtraction does care.
\begingroup\small\begin{verbatim}
vexpr {1 1 1} {2 2 2} -
> 1.0 1.0 1.0
vexpr {2 2 2} {1 1 1} -
> -1.0 -1.0 -1.0
\end{verbatim}
\endgroup

While with 2 arguments and an opcode this seems silly, imagine a complex operation with several steps. Here we are going to model a robot arm with 3 joints. Each ``arm'' is one unit long, and when one joint bends, the rest follow suit.

\textit{unbent}
\begingroup\small\begin{verbatim}
(A) - (B) - (C)
\end{verbatim}
\endgroup

\textit{bent}
\begingroup\small\begin{verbatim}
      (C)
        |
      (B)
     /
(A)
\end{verbatim}
\endgroup

Code:
\begingroup\small\begin{verbatim}
# Positions of the joints
set A_pos {0.0 0.0 0.0}
set B_pos {1.0 0.0 0.0}
set C_pos {2.0 0.0 0.0}

# Rotations of the joints 
set A_rot {0 0 45}
set B_rot {0 0 45}

set b_transform [vexpr \
    $A_pos $B_pos - \
    affine_translate \
    $A_rot radians \
    affine_rotate \
    affine_multiply]
> { 0.707  0.707 0.0  -0.707} 
  {-0.707  0.707 0.0   0.707}
  { 0.0    0.0   1.0   0.0}
  { 0.0    0.0   0.0   1.0}

set b_real [vexpr $B_pos $b_transform vector_transform]

> 0.707106 0.707106 0.0

set c_transform [vexpr \
    $C_pos $B_real - \
    affine_translate \
    load affine_multiply \
    $B_rot radians \
    affine_rotate \
    affine_multiply]
> { 0.0 1.0 0.0 0.707}
  {-1.0 0.0 0.0 2.293}
  {0.0  0.0 1.0 0.0}
  {0.0  0.0 0.0 1.0}

set c_real [vexpr $C_pos $c_transform vector_transform]
> 0.0 2.0 0.0
\end{verbatim}
\endgroup

If you aren't familiar with 3D math and affine transformations, that may look overly complicated, but as you can see each \textbf{vexpr} call is packed with commands. You can plainly see that after 2 45 degree bends, our ``C'' point comes to rest at 0.0,2,0 after completing a 90 degree bend.

\section{Operations}

Note that all arguments that are not one of these operation words are instead treated as values to push onto the evaluation stack.

\subsection{affine\_multiply}

\begin{quote}
AFFINE AFFINE -\tiprangle{} AFFINE
\end{quote}

Multiplies 2 4x4 matrices. Used to combine 2 affine transformations. Note: Some affine transformations need to be performed in a particular order to make sense.

\subsection{affine\_rotate}

\begin{quote}
VECTOR -\tiprangle{} AFFINE
\end{quote}

Converts a ``vector'' of 3 angles (Xrotation Yrotation Zrotation) into an affine transformation. NOTE: the angles should be in radians.

\subsection{affine\_scale}

\begin{quote}
VECTOR -\tiprangle{} AFFINE
\end{quote}

Converts a scale vector (Xscale Yscale Zscale) into an affine transformation. Note: 1.0 1.0 1.0 = No scaling. 2.0 2.0 2.0 = Double the size. 0.5 0.5 0.5 = Half the size.

\subsection{affine\_translate}

\begin{quote}
VECTOR -\tiprangle{} AFFINE
\end{quote}

Converts a displacement vector (X Y Z) into an affine transformation 

\subsection{cart\_to\_cyl}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a cartesian vector to cylindrical coordinates 

\subsection{cart\_to\_sphere}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a cartesian vector to spherical coordinates

\subsection{cross}

\begin{quote}
VECTOR VECTOR -\tiprangle{} VECTOR
\end{quote}

Performs the cross product of two vectors

\subsection{copy}

\begin{quote}
ANY -\tiprangle{} ANY ANY
\end{quote}

Copies the top of the stack, pushing it onto the stack.

\subsection{cyl\_to\_cart}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a vector in cylindrical coordinates to cartesian coordinates 

\subsection{cyl\_to\_degrees}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a cylindrical vector in radians to degrees.

\subsection{cyl\_to\_radians}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a cylindrical vector in degrees to radians.

\subsection{degrees}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a vector or scalar in radians to degrees.

\subsection{dot}

\begin{quote}
VECTOR VECTOR -\tiprangle{} SCALAR
\end{quote}

Produces the dot product of two vectors.

\subsection{dT}

\begin{quote}
(None) -\tiprangle{} SCALAR
\end{quote}

Pushes the value of dT into the stack.

\subsection{identity}

\begin{quote}
(None) -\tiprangle{} AFFINE
\end{quote}

Pushes the identity matrix onto the stack.

\subsection{load}

\begin{quote}
(None) -\tiprangle{} ANY
\end{quote}

Pushes the last value stored by STORE onto the stack. 

\subsection{pi}

\begin{quote}
(None) -\tiprangle{} SCALER
\end{quote}

Pushes the value of PI onto the stack.

\subsection{radians}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a vector or scalar in degrees to radians.

\subsection{setDT}

\begin{quote}
SCALAR -\tiprangle{} (None)
\end{quote}

Pops the current stack value and stores it in the dT variable.

\subsection{sphere\_to\_cart}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a vector in spherical coordinates to cartesian coordinates.

\subsection{sphere\_to\_degrees}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a spherical vector in radians to a spherical vector in degrees.

\subsection{sphere\_to\_radians}

\begin{quote}
VECTOR -\tiprangle{} VECTOR
\end{quote}

Converts a spherical vector in degrees to a spherical vector in radians.

\subsection{store}

\begin{quote}
ANY -\tiprangle{} ANY
\end{quote}

Stores the top of the stack internally for later use. The value stored remains at the top of the stack.

\subsection{vector\_add}

\begin{quote}
VECTOR VECTOR -\tiprangle{} VECTOR
\end{quote}

Adds 2 vectors, which must be of the same length.

\subsection{vector\_length}

\begin{quote}
VECTOR -\tiprangle{} SCALAR
\end{quote}

Produces the length of a vector.

\subsection{vector\_scale}

\begin{quote}
SCALAR VECTOR -\tiprangle{} VECTOR
\end{quote}

Scales a vector by a scalar

\subsection{vector\_subtract}

\begin{quote}
VECTOR VECTOR -\tiprangle{} VECTOR
\end{quote}

Subtracts one vector from another.

\subsection{vector\_transform}

\begin{quote}
AFFINE VECTOR -\tiprangle{} VECTOR
\end{quote}

Transforms a vector using an affine matrix.

\section{Implementation}

A test implementation for \textbf{vexpr} is available as an TEA extension, and can be downloaded [\url{http://www.etoyoc.com/tclmatrix3d}]. At this point in time, the goal is adding \textbf{vexpr} as a standalone command.

\subsection{Limits}

\textbf{vexpr} converts all arguments to an array of 16 double precision elements; only the item left on the top of the stack is converted back into a Tcl list. The ``stack'' itself has a hard-coded limit of 32 elements. (It is implemented as an array.) Exceeding the stack size will cause the command to throw a Tcl error.

\section{Copyright}

This document has been placed in the public domain.

\section{Colophon}

\textit{TIP AutoGenerator --- written by Donal K. Fellows}
\begin{thebibliography}{TIP \#1}
\addcontentsline{toc}{section}{References}
\bibitem[TIP \#363]{tip363}
Karl C. Hansen,
\emph{Vector Math in the Tcl Core},
on-line at \url{http://purl.org/tcl/tip/363.html}
\end{thebibliography}
\end{document}
