Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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\rvecadd#1#2{\edef\tmp{\noexpand\@rvecadd+#1,\relax#2,\relax}\tmp}
\def\rvecsub#1#2{\edef\tmp{\noexpand\@rvecadd-#1,\relax#2,\relax}\tmp}
\def\rvecmul#1#2{\edef\tmp{\noexpand\@rvecadd*#1,\relax#2,\relax}\tmp}
\def\rvecdiv#1#2{\edef\tmp{\noexpand\@rvecadd/#1,\relax#2,\relax}\tmp}
\def\rcar#1{\edef\tmp{\noexpand\@rcar#1,\relax}\tmp}
\def\rcdr#1{\edef\tmp{\noexpand\@rcdr#1,\relax}\tmp}

%recursive macros
\def\@rvecadd#1#2,#3\relax#4,#5\relax{%
\the\numexpr#2#1#4\relax
\ifx\@#3\@\expandafter\@gobble
\else\expandafter\@firstofone
\fi{,\@rvecadd#1#3\relax#5\relax} }

\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}
share|improve this question
    
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
add comment

2 Answers

up vote 7 down vote accepted

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

\def\rvecadd#1#2{\edef\tmp{\noexpand\@rvecadd+#1,\relax#2,\relax}\tmp}
\def\rvecsub#1#2{\edef\tmp{\noexpand\@rvecadd-#1,\relax#2,\relax}\tmp}

\def\@rvecadd#1#2,#3\relax#4,#5\relax{%
\the\numexpr#2#1#4\relax
\ifx\@#3\@\expandafter\@gobble
\else\expandafter\@firstofone
\fi{,\@rvecadd#1#3\relax#5\relax}}

\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}
share|improve this answer
    
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
add comment

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}
\begin{equation}
  \usematrix\A \cdot \usevvector\a
  = \matrixtimesvector\result\A\a  \usevvector\result
\end{equation}

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
  }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Adding two vectors
%
\tl_new:N \l__mypkg_operation_tl
\NewDocumentCommand { \addvectors } { m m m }
  {
    \tl_set:Nn \l__mypkg_operation_tl { + }
    \mypkg_add_vectors:NN #2#3
    \cs_set_eq:NN #1 \l__mypkg_result_seq
  }
\NewDocumentCommand { \subvectors } { m m m }
  {
    \tl_set:Nn \l__mypkg_operation_tl { - }
    \mypkg_add_vectors:NN #2#3
    \cs_set_eq:NN #1 \l__mypkg_result_seq
  }
\cs_new_protected:Npn \mypkg_add_vectors:NN #1#2
  {
    \int_compare:nNnTF { \seq_count:N #1 } = { \seq_count:N #2 }
      {
        \seq_clear:N \l__mypkg_result_seq
        \seq_mapthread_function:NNN #1#2 \mypkg_add_vectors:nn
      }
      {
        \msg_error:nnxxxx { mypkg } { mismatched-vectors }
          { \token_to_str:N #1 } { \seq_count:N #1 }
          { \token_to_str:N #2 } { \seq_count:N #2 }
      }
  }
\cs_new_protected:Npn \mypkg_add_vectors:nn #1#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:
\begin{equation}
  \usevvector\a - \usevvector\b
  = \subvectors\result\a\b \usevvector\result .
\end{equation}

Scalar product:
\begin{equation}
  \usehvector\a \cdot \usevvector\b
  = \scalarproduct\result\a\b \result
\end{equation}
Matrix-vector product
\begin{equation}
  \usematrix\A \cdot \usevvector\a
  = \matrixtimesvector\result\A\a  \usevvector\result
\end{equation}

% 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}
share|improve this answer
    
Thanks Bruno for this powerful code. –  gnoejh Aug 23 '12 at 3:42
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.