应用矩阵运算代码

应用矩阵运算代码

我对 LaTeX 还比较陌生,在使用这个出色的代码时遇到了语法问题这里,它允许在 LaTeX 中进行任意矩阵运算。

我编写了一个宏来生成某些矩阵。例如:

\def\GetRotationMatrixZ#1{
    cos(#1),-sin(#1),0,
    sin(#1), cos(#1),0,
          0,       0,1
}

现在我想将它与链接代码的 \matnew、\matset 命令一起使用。然而,我尝试过的所有方法都失败了。我尝试了宏语法的许多变体,但还是卡住了。

编辑:主要用例看起来像:

\matnew \transformMatrixA
\matset \transformMatrixA {\GetRotationMatrixY\whatever}
% . . .
\matmul \transformMatrix \transformMatrixA \transformMatrixB

我尝试过类似的事情;我不记得具体是哪一个。这个特定示例给出:

Unexpected comma: extra arguments ignored.

答案1

LaTeX3人们会给出更权威的答案(特别是他们知道如何生成变体来\matset扩展其论点)。与此同时,也许这会有所帮助(似乎问题在于您没有使用分号来结束行,并且存在扩展问题)。

TeX是一种宏语言,其中的关键词是扩展。即使你使用更高的抽象级别,例如LaTeX2(它尽力向用户 \emph{hide} 编程可能性)或LaTeX3(相反,它有一个非常深思熟虑和复杂的方案来使编码更容易,同时将程序员的任务与最终用户工具明确分开),你也无法逃避这一点。\matset你链接的代码中的宏似乎没有扩展它的参数。如果你尝试将它用作\matset\MatrixA {\macro{3}},它将收到 \macro{3},而不是它似乎期望的以分号分隔的行。您首先需要告诉TeX扩展\macro{3}到该列表或行。程序员可以立即\LaTeX3生成\matset首先扩展其参数的变体,作为一种解决方法,\expandafter\matset\expandafter\MatrixA \expandafter{\macro{3}}就可以了。请注意,括号{是输入流的一部分,必须通过 跳过\expandafter

%% (to be embedded in the code from [there](https://tex.stackexchange.com/a/112683/34359))

\def\GetRotationMatrix #1{%
    cos(#1), -sin(#1), 0;
    sin(#1),  cos(#1), 0;
          0,        0, 1 }

\expandafter\matset\expandafter\transformMatrixA \expandafter
 {\GetRotationMatrix {3.141592653}}

 \begin{equation}
   \mattypeset \transformMatrixA
 \end{equation}

此处嵌入在布鲁诺·勒·弗洛克法典

% Programming-level functions: \fpm_new:N, \fpm_set:Nn, \fpm_gset:Nn,
% \fpm_add:NNN, \fpm_sub:NNN, \fp_neg:NN, \fp_transpose:NN, \fp_mul:NNN.
%
% Expandable programming-level functions: \fpm_lines:N, \fpm_columns:N,
% \fpm_get:Nnn.
%
% Document-level functions: \matnew, \matset, \matgset, \matadd,
% \matsub, \matmul, \mattypeset.
%
\RequirePackage{expl3}
{
  \ExplSyntaxOn
  %
  % Programming-level code, for adding, multiplying, matrices.  A matrix
  % of size |MxN| is stored as a token list of the form
  %
  % \s__fpm { M } { N } { {a11} ... {a1N} } ... { {aM1} ... {aMN} } ;
  %
  % where |\s__fpm| is a marker used to recognize matrices, |M| and |N|
  % are non-negative integers, and |aij| are floating point numbers.
  %
  % (1) Variables.
  %
  \cs_new_eq:NN \s__fpm \scan_stop: % A marker.
  \tl_const:Nn \c_empty_fpm { \s__fpm { 0 } { 0 } ; }
  \cs_new_eq:NN \l__fpm_tmpa_fpm \c_empty_fpm
  \seq_new:N \l__fpm_lines_seq
  \int_new:N \l__fpm_lines_A_int
  \int_new:N \l__fpm_lines_B_int
  \int_new:N \l__fpm_columns_A_int
  \int_new:N \l__fpm_columns_B_int
  \tl_new:N \l__fpm_matrix_A_tl
  \tl_new:N \l__fpm_matrix_B_tl
  \tl_new:N \l__fpm_matrix_C_tl
  \seq_new:N \l__fpm_matrix_A_seq
  \seq_new:N \l__fpm_matrix_B_seq
  \seq_new:N \l__fpm_one_line_A_seq
  \seq_new:N \l__fpm_one_line_B_seq
  \tl_new:N \l__fpm_one_line_A_tl
  \int_new:N \l__fpm_tmpa_int
  %
  % (2) Variants and generic helpers.
  %
  %
  % (3) Storing matrices.
  %
  \cs_new_protected:Npn \fpm_new:N #1
    { \cs_new_eq:NN #1 \c_empty_fpm }
  \cs_new_protected_nopar:Npn \fpm_set:Nn
    { \__fpm_set:NNn \tl_set:Nx }
  \cs_new_protected_nopar:Npn \fpm_gset:Nn
    { \__fpm_set:NNn \tl_gset:Nx }
  \cs_new_protected:Npn \__fpm_set:NNn #1#2#3
    {
      \seq_set_split:Nnn \l__fpm_lines_seq { ; } {#3}
      \seq_set_filter:NNn \l__fpm_lines_seq \l__fpm_lines_seq
        { ! \tl_if_empty_p:n {##1} }
      %
      % Now all lines are non-empty.
      %
      \tl_clear:N \l__fpm_matrix_A_tl
      \int_zero:N \l__fpm_lines_A_int
      \int_zero:N \l__fpm_columns_A_int
      \seq_map_inline:Nn \l__fpm_lines_seq
        {
          \int_incr:N \l__fpm_lines_A_int
          \seq_set_from_clist:Nn \l__fpm_one_line_A_seq {##1}
          \int_set:Nn \l__fpm_tmpa_int { \seq_count:N \l__fpm_one_line_A_seq }
          \int_compare:nNnT \l__fpm_columns_A_int = \c_zero
            { \int_set_eq:NN \l__fpm_columns_A_int \l__fpm_tmpa_int }
          \int_compare:nNnF \l__fpm_tmpa_int = \l__fpm_columns_A_int
            { \seq_map_break:n { \msg_error:nn { fpm } { invalid-size } } }
          \tl_put_right:Nx \l__fpm_matrix_A_tl
            { { \seq_map_function:NN \l__fpm_one_line_A_seq \__fpm_set_aux:n } }
        }
      #1 #2
        {
          \s__fpm
          { \int_use:N \l__fpm_lines_A_int }
          { \int_use:N \l__fpm_columns_A_int }
          \l__fpm_matrix_A_tl
          ;
        }
    }
  \cs_new:Npn \__fpm_set_aux:n #1 { { \fp_to_tl:n {#1} } }
  %
  % (4) Extracting the size of a matrix, and its contents.
  % |#1| is the matrix, |#2|, |#3| integer variables receiving the
  % number of lines and of columns, and |#4| a token list receiving the
  % contents of the matrix.
  %
  \cs_new_protected:Npn \__fpm_get_parts:NNNN #1#2#3#4
    { \exp_after:wN \__fpm_get_parts:NnnwNNN #1 #2 #3 #4 }
  \cs_new_protected:Npn \__fpm_get_parts:NnnwNNN \s__fpm #1#2#3 ; #4#5#6
    {
      \int_set:Nn #4 {#1}
      \int_set:Nn #5 {#2}
      \tl_set:Nn #6 {#3}
    }
  %
  % (5) Some expandable functions: getting one entry, getting the size.
  %
  \cs_new:Npn \fpm_lines:N #1
    { \exp_after:wN \__fpm_lines:NnnwN #1 \use_i:nn }
  \cs_new:Npn \fpm_columns:N #1
    { \exp_after:wN \__fpm_lines:NnnwN #1 \use_ii:nn }
  \cs_new:Npn \__fpm_lines:NnnwN \s__fpm #1#2#3 ; #4 { #4 {#1} {#2} }
  \cs_new:Npn \fpm_get:Nnn #1#2#3
    { \exp_after:wN \__fpm_get:Nnnwnn #1 #2 #3 }
  \cs_new:Npn \__fpm_get:Nnnwnn \s__fpm #1#2#3 ; #4#5
    { \exp_args:Nf \tl_item:nn { \tl_item:nn {#3} {#4} } {#5} }
  %
  % (6) Summing matrices
  %
  \cs_new_protected_nopar:Npn \fpm_add:NNN { \__fpm_add:NNNN + }
  \cs_new_protected_nopar:Npn \fpm_sub:NNN { \__fpm_add:NNNN - }
  \cs_new_protected:Npn \__fpm_add:NNNN #1#2#3#4
    {
      \tl_set:Nn \l__fpm_sign_tl {#1}
      \__fpm_get_parts:NNNN #3
        \l__fpm_lines_A_int \l__fpm_columns_A_int \l__fpm_matrix_A_tl
      \__fpm_get_parts:NNNN #4
        \l__fpm_lines_B_int \l__fpm_columns_B_int \l__fpm_matrix_B_tl
      \int_compare:nNnTF \l__fpm_lines_A_int = \l__fpm_lines_B_int
        {
          \int_compare:nNnTF \l__fpm_columns_A_int = \l__fpm_columns_B_int
            { \__fpm_add:N #2 }
            { \msg_error:nn { fpm } { invalid-size } }
        }
        { \msg_error:nn { fpm } { invalid-size } }
    }
  \cs_new_protected:Npn \__fpm_add:N #1
    {
      \seq_set_split:NnV \l__fpm_matrix_A_seq { } \l__fpm_matrix_A_tl
      \seq_set_split:NnV \l__fpm_matrix_B_seq { } \l__fpm_matrix_B_tl
      \tl_clear:N \l__fpm_matrix_C_tl
      \seq_mapthread_function:NNN
        \l__fpm_matrix_A_seq
        \l__fpm_matrix_B_seq
        \__fpm_add_lines:nn
      \tl_set:Nx #1
        {
          \s__fpm
          { \int_use:N \l__fpm_lines_A_int }
          { \int_use:N \l__fpm_columns_A_int }
          \l__fpm_matrix_C_tl
          ;
        }
    }
  \cs_new_protected:Npn \__fpm_add_lines:nn #1#2
    {
      \seq_set_split:Nnn \l__fpm_one_line_A_seq { } {#1}
      \seq_set_split:Nnn \l__fpm_one_line_B_seq { } {#2}
      \tl_put_right:Nx \l__fpm_matrix_C_tl
        {
          {
            \seq_mapthread_function:NNN
              \l__fpm_one_line_A_seq
              \l__fpm_one_line_B_seq
              \__fpm_add_entries:nn
          }
        }
    }
  \cs_new:Npn \__fpm_add_entries:nn #1#2
    { { \fp_to_tl:n { #1 \l__fpm_sign_tl #2 } } }
  %
  % (7) Negating all entries.
  %
  \cs_new_protected:Npn \fpm_neg:NN #1#2
    { \tl_set:Nx #1 { \exp_after:wN \__fpm_neg:Nnnw #2 } }
  \cs_new:Npn \__fpm_neg:Nnnw \s__fpm #1#2#3 ;
    { \s__fpm {#1} {#2} \tl_map_function:nN {#3} \__fpm_neg_aux:n ; }
  \cs_new:Npn \__fpm_neg_aux:n #1
    { { \tl_map_function:nN {#1} \__fpm_neg_auxii:n } }
  \cs_new:Npn \__fpm_neg_auxii:n #1
    { { \fp_to_tl:n { - #1 } } }
  %
  % (8) Transposing a matrix.
  %
  \cs_new_protected:Npn \fpm_transpose:NN #1#2
    {
      \__fpm_get_parts:NNNN #2
        \l__fpm_lines_A_int \l__fpm_columns_A_int \l__fpm_matrix_A_tl
      \seq_set_split:NnV \l__fpm_matrix_A_seq { } \l__fpm_matrix_A_tl
      \tl_clear:N \l__fpm_matrix_B_tl
      \prg_replicate:nn { \l__fpm_columns_A_int }
        {
          \tl_put_right:Nx \l__fpm_matrix_B_tl
            { { \seq_map_function:NN \l__fpm_matrix_A_seq \__fpm_wrap_head:n } }
          \seq_set_map:NNn \l__fpm_matrix_A_seq \l__fpm_matrix_A_seq
            { \tl_tail:n {##1} }
        }
      \tl_set:Nx #1
        {
          \s__fpm
          { \int_use:N \l__fpm_columns_A_int }
          { \int_use:N \l__fpm_lines_A_int }
          \l__fpm_matrix_B_tl
          ;
        }
    }
  \cs_new:Npn \__fpm_wrap_head:n #1 { { \tl_head:n {#1} } }
  %
  % (9) Multiplying matrices.
  %
  \cs_new_protected:Npn \fpm_mul:NNN #1#2#3
    {
      \int_compare:nNnTF { \fpm_columns:N #2 } = { \fpm_lines:N #3 }
        {
          \fpm_transpose:NN \l__fpm_tmpa_fpm #3
          \__fpm_get_parts:NNNN #2
            \l__fpm_lines_A_int \l__fpm_columns_A_int \l__fpm_matrix_A_tl
          \__fpm_get_parts:NNNN #3
            \l__fpm_lines_B_int \l__fpm_columns_B_int \l__fpm_matrix_B_tl
          \tl_set:Nx #1
            {
              \s__fpm
              { \int_use:N \l__fpm_lines_A_int }
              { \int_use:N \l__fpm_columns_B_int }
              \tl_map_function:NN \l__fpm_matrix_A_tl \__fpm_mul_line:n
              ;
            }
        }
        { \msg_error:nn { fpm } { invalid-size } }
    }
  \cs_new:Npn \__fpm_mul_line:n #1
    { { \exp_after:wN \__fpm_mul_line:Nnnwn \l__fpm_tmpa_fpm {#1} } }
  \cs_new:Npn \__fpm_mul_line:Nnnwn \s__fpm #1#2#3 ; #4
    { \__fpm_mul_line:nn {#4} #3 \q_recursion_tail \q_recursion_stop }
  \cs_new:Npn \__fpm_mul_line:nn #1#2
    {
      \quark_if_recursion_tail_stop:n {#2}
      {
        \fp_to_tl:n
          {
            \__fpm_mul_one:nwn #1 \use_none_delimit_by_q_stop:w
              \q_mark #2 \q_nil \q_stop
            0
          }
      }
      \__fpm_mul_line:nn {#1}
    }
  \cs_new:Npn \__fpm_mul_one:nwn #1#2 \q_mark #3
    { #1 * #3 + \__fpm_mul_one:nwn #2 \q_mark }
  %
  %
  % Messages.
  %
  \msg_new:nnn { fpm } { invalid-size }
    { Sizes~of~matrices~or~lines~don't~match. }
}
\RequirePackage{amsmath, siunitx}
{
  \ExplSyntaxOn
  %
  % Turning matrices into arrays for display.
  %
  \cs_new_protected:Npn \fpm_to_array:N #1
    {
      \begin{pmatrix}
        \exp_after:wN \__fpm_to_array:Nnnw #1
      \end{pmatrix}
    }
  \cs_new_eq:NN \__fpm_newline: ? % Dummy def.
  \cs_new_protected:Npn \__fpm_to_array:Nnnw \s__fpm #1#2#3 ;
    {
      \cs_gset_nopar:Npn \__fpm_newline:
        { \cs_gset_nopar:Npn \__fpm_newline: { \\ } }
      \tl_map_inline:nn {#3}
        {
          \__fpm_newline:
          \seq_set_split:Nnn \l__fpm_one_line_A_seq { } {##1}
          \seq_set_map:NNn \l__fpm_one_line_A_seq \l__fpm_one_line_A_seq
            { \__fpm_to_array_entry:n {####1} }
          \seq_use:Nnnn \l__fpm_one_line_A_seq { & } { & } { & }
        }
    }
  \cs_new_protected:Npn \__fpm_to_array_entry:n #1
    {
      \str_case:nnn {#1}
        {
          { nan } { \text{nan} }
          { inf } { \infty }
          { -inf } { -\infty }
        }
        { \num{#1} }
    }
}

\RequirePackage{xparse}
\ExplSyntaxOn
%
% Document-level functions.
%
\NewDocumentCommand { \matnew } { m } { \fpm_new:N #1 }
\NewDocumentCommand { \matset } { mm } { \fpm_set:Nn #1 {#2} }
\NewDocumentCommand { \matgset } { mm } { \fpm_gset:Nn #1 {#2} }
\NewDocumentCommand { \matadd } { mmm } { \fpm_add:NNN #1 #2 #3 }
\NewDocumentCommand { \matsub } { mmm } { \fpm_sub:NNN #1 #2 #3 }
\NewDocumentCommand { \matneg } { mm } { \fpm_neg:NN #1 #2 }
\NewDocumentCommand { \mattranspose } { mm } { \fpm_transpose:NN #1 #2 }
\NewDocumentCommand { \matmul } { mmm } { \fpm_mul:NNN #1 #2 #3 }
\NewDocumentCommand { \mattypeset } { m }
  { \fpm_to_array:N #1 }
\ExplSyntaxOff

\documentclass{article}
\begin{document}
  \matnew \X
  \matnew \Y
  \matnew \Z
  \matset \X { 1 , 2 + 3 ; 4 , 3.4e22 }
  \matset \Y { 3 , 4 ; -5 , 6 }
  \begin{align}
    \matadd \Z \X \Y
    \mattypeset \Z & = \mattypeset \X + \mattypeset \Y \\
    \matsub \Z \X \Y
    \mattypeset \Z & = \mattypeset \X - \mattypeset \Y \\
    \matmul \Z \X \Y
    \mattypeset \Z & = \mattypeset \X \times \mattypeset \Y \\
    \matmul \Z \Y \X
    \mattypeset \Z & = \mattypeset \Y \times \mattypeset \X
  \end{align}
\def\GetRotationMatrix #1{%
    cos(#1), -sin(#1), 0;
    sin(#1),  cos(#1), 0;
          0,        0, 1 }

\expandafter\matset\expandafter\transformMatrixA \expandafter
 {\GetRotationMatrix {3.141592653}}

 \begin{equation}
   \mattypeset \transformMatrixA
 \end{equation}
\end{document}

前四个方程来自原始代码

矩阵

相关内容