# How to build macros for vector-matrix operators?

Can anybody build macros for doing the following vector operations? Or are there already such macros? For example,

1) Example data: \def\a{(5,3,0)}
\def\b{(5,1,6)}
\def\A{(1,0,1\\0,2,0\\0,0,3)}
2) Vector addition: $\a+\b$ returns (10,4,6)
3) Vector subtraction: $\a-\b$ returns (0,2,-6)
4) Vector matrix multiplication: $\A*\a$ returns (5,6,0)


Thanks to the David's code, I expanded the followings for 1) vector addition, 2) vector subtraction, 3) vector multiplication, 4) vector division. What I'm going to do is to expand the code to 5) \car and \cdr for list processing. The following is the first step.

\documentclass{article}

\makeatletter

%main macros
\def\rcar#1{\edef\tmp{\noexpand\@rcar#1,\relax}\tmp}
\def\rcdr#1{\edef\tmp{\noexpand\@rcdr#1,\relax}\tmp}

%recursive macros
\the\numexpr#2#1#4\relax
\ifx\@#3\@\expandafter\@gobble
\else\expandafter\@firstofone

\def\@rcar#1,#2\relax{%
#1\relax
\ifx\@#2\@\expandafter\@gobble
\else\expandafter\@firstofone
\fi}

\def\@rcdr#1,#2\relax{%
#2\relax
\ifx\@#2\@\expandafter\@gobble
\else\expandafter\@firstofone
\fi}

\begin{document}
%Data
\def\a{5,3,0,100,1}
\def\b{5,1,6,1000,1}
\def\A{1,0,1\\0,2,0\\0,0,3}
\def\aT{5\\3\\0}

%Test
$(\a) + (\b) = (\rvecadd\a\b)$\par
$(\a) - (\b) = (\rvecsub\a\b)$\par
$(\a) * (\b) = (\rvecmul\a\b)$\par
$(\a) / (\b) = (\rvecdiv\a\b)$

%car test:
\rcar\a

%cdr test
(\rcdr\a)

\end{document}

-
It involves calculations here. Although it's possible to do this by macros, I think it's not very simple. However, this may be simple in LuaLaTeX. – goodluck Aug 21 '12 at 9:59
Is there still an open question here? Otherwise, could you accept one of the answers? – Stephan Lehmke Aug 23 '12 at 9:24

Out of time to do multiplication now, but her are the easy ones vector addition/subtraction.

\documentclass{article}

\def\a{5,3,0}
\def\b{5,1,6}
\def\A{1,0,1\\0,2,0\\0,0,3}
%2) Vector addition: $\a+\b$ returns (10,4,6)
%3) Vector subtraction: $\a-\b$ returns (0,2,-6)
%4) Vector matrix multiplication: $\A*\aT$ returns (5,6,0)

\makeatletter

\the\numexpr#2#1#4\relax
\ifx\@#3\@\expandafter\@gobble
\else\expandafter\@firstofone

\begin{document}

\def\a{5,3,0}
\def\b{5,1,6}
\def\A{1,0,1\\0,2,0\\0,0,3}
\def\aT{5\\3\\0}

$(\a) + (\b) = (\rvecadd\a\b)$

$(\a) - (\b) = (\rvecsub\a\b)$

\end{document}

-
Thanks David for the code. It is very compact but needs a lot of thinking. – gnoejh Aug 23 '12 at 3:40
The use of \gobble and \@firstofone is really great. – gnoejh Aug 23 '12 at 8:30

I changed the syntax a bit, omitting the parentheses you had in your vectors and matrices. With the code below, you can do

\setvector\a{5,3,0}
\setmatrix\A{1,0,1\\0,2,0\\0,0,3}
$$\usematrix\A \cdot \usevvector\a = \matrixtimesvector\result\A\a \usevvector\result$$


to display the matrix \A, the vecor \a (vertically), compute the \result of multiplying \A by \a, and display the \result as a vertical vector.

\documentclass{article}
\usepackage{expl3, xparse}
\usepackage{amsmath}
\ExplSyntaxOn
\seq_new:N \l__mypkg_a_seq
\seq_new:N \l__mypkg_b_seq
\seq_new:N \l__mypkg_result_seq
\int_new:N \l__mypkg_entries_int

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Declaring vectors and matrices
%
\cs_new_protected:Npn \mypkg_set_vector:Nnn #1#2#3
{
\seq_set_split:Nnn #1 {#2} {#3} % Split into entries.
\seq_set_map:NNn #1#1 { \fp_to_tl:n {##1} } % Evaluate each entry.
}
\NewDocumentCommand { \setvector } { m O{,} m }
{
\mypkg_set_vector:Nnn \l__mypkg_result_seq {#2} {#3}
\cs_set_eq:NN #1 \l__mypkg_result_seq
}
\NewDocumentCommand { \setmatrix } { m O{\\} O{,} m }
{
\seq_clear:N \l__mypkg_result_seq
\int_set_eq:NN \l__mypkg_entries_int \c_minus_one
\seq_set_split:Nnn \l__mypkg_a_seq {#2} {#4} % Split into lines.
\seq_map_inline:Nn \l__mypkg_a_seq
{
% Split each line |##1| into entries.  For the first line,
% |\l__mypkg_entries_int| is -1 still; we set it to the
% number of entries in the first line.  Then check that the line
% has the right number of entries: if so, put it in the result
% as a comma-delimited list, otherwise complain loudly and
% ignore the line.
%
\mypkg_set_vector:Nnn \l__mypkg_b_seq {#3} {##1}
\int_compare:nT { \l__mypkg_entries_int = \c_minus_one }
{
\int_set:Nn \l__mypkg_entries_int
{ \seq_count:N \l__mypkg_b_seq }
}
\int_compare:nTF
{ \seq_count:N \l__mypkg_b_seq = \l__mypkg_entries_int }
{
\seq_put_right:Nx \l__mypkg_result_seq
{ \seq_use:Nnnn \l__mypkg_b_seq { & } { & } { & } }
}
{
\msg_error:nnxxx { mypkg } { mismatched-lines }
{ \token_to_str:N #1 }
{ \int_use:N \l__mypkg_entries_int }
{ \seq_count:N \l__mypkg_b_seq }
}
}
\cs_set_eq:NN #1 \l__mypkg_result_seq
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
\tl_new:N \l__mypkg_operation_tl
\NewDocumentCommand { \addvectors } { m m m }
{
\tl_set:Nn \l__mypkg_operation_tl { + }
\cs_set_eq:NN #1 \l__mypkg_result_seq
}
\NewDocumentCommand { \subvectors } { m m m }
{
\tl_set:Nn \l__mypkg_operation_tl { - }
\cs_set_eq:NN #1 \l__mypkg_result_seq
}
{
\int_compare:nNnTF { \seq_count:N #1 } = { \seq_count:N #2 }
{
\seq_clear:N \l__mypkg_result_seq
}
{
\msg_error:nnxxxx { mypkg } { mismatched-vectors }
{ \token_to_str:N #1 } { \seq_count:N #1 }
{ \token_to_str:N #2 } { \seq_count:N #2 }
}
}
{
\seq_put_right:Nx \l__mypkg_result_seq
{ \fp_to_tl:n { #1 \l__mypkg_operation_tl #2 } }
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Scalar product of two vectors
%
\NewDocumentCommand { \scalarproduct } { mmm }
{
\tl_set:Nx #1 { \mypkg_scalar_product:NN #2 #3 }
}
\cs_new:Npn \mypkg_scalar_product:NN #1#2
{
\fp_to_tl:n
{ \seq_mapthread_function:NNN #1 #2 \mypkg_scalar_product_aux:nn }
}
\cs_new:Npn \mypkg_scalar_product_aux:nn #1#2 { + #1 * #2 }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Multiplying matrix times vector
%
\NewDocumentCommand { \matrixtimesvector } { mmm }
{
\seq_clear:N \l__mypkg_result_seq
\seq_map_inline:Nn #2
{
\seq_set_split:Nnn \l__mypkg_a_seq { & } {##1}
\seq_put_right:Nx \l__mypkg_result_seq
{ \mypkg_scalar_product:NN \l__mypkg_a_seq #3 }
}
\cs_set_eq:NN #1 \l__mypkg_result_seq
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Displaying vectors and matrices
%
\NewDocumentCommand { \usehvector } { m }
{
\mode_if_math:F { \msg_warning:nn { mypkg } { text-mode } }
\ensuremath
{
\begin{pmatrix}
\seq_use:Nnnn #1 { , } { , } { , }
\end{pmatrix}
}
}
\NewDocumentCommand { \usevvector } { m }
{
\mode_if_math:F { \msg_warning:nn { mypkg } { text-mode } }
\ensuremath
{
\begin{pmatrix}
\seq_use:Nnnn #1 { \\ } { \\ } { \\ }
\end{pmatrix}
}
}
\NewDocumentCommand { \usematrix } { m }
{
\mode_if_math:F { \msg_warning:nn { mypkg } { text-mode } }
\ensuremath
{
\begin{pmatrix}
\seq_use:Nnnn #1 { \\ } { \\ } { \\ }
\end{pmatrix}
}
}

\msg_new:nnn { mypkg } { mismatched-lines }
{ The~lines~of~#1~should~have~#2~entries,~but~this~one~has~#3. }
\msg_new:nnn { mypkg } { mismatched-vectors }
{ The~vector~#1~has~#2~entries,~but~the~vector~#3~has~#4~entries. }
\msg_new:nnn { mypkg } { text-mode }
{ The~\iow_char:N\\use...~commands~should~only~be~used~in~math~mode. }

\ExplSyntaxOff
\begin{document}
\setvector\a{5,3,0}
\setvector\b{5,1,6}
\setmatrix\A{1,0,1\\0,2,0\\0,0,3}

Vector addition: $\usehvector\a+\usehvector\b$ returns
$\addvectors\result\a\b \usehvector\result$.  Subtraction:
$$\usevvector\a - \usevvector\b = \subvectors\result\a\b \usevvector\result .$$

Scalar product:
$$\usehvector\a \cdot \usevvector\b = \scalarproduct\result\a\b \result$$
Matrix-vector product
$$\usematrix\A \cdot \usevvector\a = \matrixtimesvector\result\A\a \usevvector\result$$

% 2) Vector addition: $\a+\b$ returns (10,4,6)
% 3) Vector subtraction: $\a-\b$ returns (0,2,-6)
% 4) Vector matrix multiplication: $\A*\a$ returns (5,6,0)
\end{document}

-
Thanks Bruno for this powerful code. – gnoejh Aug 23 '12 at 3:42