难以将格式保存到稍后在代码中调用的序列中

难以将格式保存到稍后在代码中调用的序列中

我有一个关于如何回答的想法这个问题并开始把一些东西放在一起。我想把一些东西放在一起,它相当强大,可以处理线性表达式的简化。

首先,我要为这个例子的长度道歉。它很长。但我为缩短它所做的所有尝试要么导致代码编译成功,要么导致代码存在其他问题,这些问题在解决后似乎无法解释这里发生了什么。我可以说,我下面发布的第一部分代码是有效的合理地好吧(虽然不完美,但确实接近我想要的工作)。

关于简化线性表达式,我找到了一个非常有效的方法。这是我为此编写的代码;我将包含此代码的文件命名为减少术语.tex

\ExplSyntaxOn
%-@-(1)------------------------------------------------------------------------------------
%% some SEVEN commands to help avoid errors in naming the "counters"
\cs_new:Npn \_stirling_var_get:n    #1   { \int_use:c  { l/stirling/var/ #1 /int } }
\cs_new:Npn \_stirling_var_create:n #1   { \int_new:c  { l/stirling/var/ #1 /int } }
\cs_new:Npn \_stirling_var_incr:nn  #1#2 { \int_add:cn { l/stirling/var/ #1 /int } {#2}}
\cs_new:Npn \_stirling_var_decr:nn  #1#2 { \int_sub:cn { l/stirling/var/ #1 /int } {#2}}
\cs_new:Npn \_stirling_var_unset:n  #1   
  { 
    \cs_undefine:c { l/stirling/var/ #1 /int } 
  }
\prg_new_conditional:Npnn \_stirling_var_if_exists:n #1 { T , F , TF }
  { 
    \int_if_exist:cTF { l/stirling/var/ #1 /int } 
      { \prg_return_true: } 
      { \prg_return_false: } 
  }
%%--------------------------------------------------------------------------------
\cs_new:Npn \_stirling_var_advance_counter_according_to_term_sign:nn #1#2
  {
    \bool_if:NTF \l_term_is_positive_bool
      { \_stirling_var_incr:nn { #1 }{ #2 } }
      { \_stirling_var_decr:nn { #1 }{ #2 } }
  }
%%--------------------------------------------------------------------------------
%% a crude attempt to determine whether a token is a digit
\prg_new_conditional:Npnn \is_digit:n #1 { p, T, F , TF }
  { \int_compare:nTF { `0 > `#1 }
                     { \prg_return_false: }
                     { \int_compare:nTF { `#1 > `9 }
                                        { \prg_return_false: }
                                        { \prg_return_true:  }
      }}

%-@-(2)------------------------------------------------------------------------------------
%%--------------------------------------------------------------------------------
\seq_new:N \l_stirling_ordered_list_of_all_variable_names_seq
\seq_new:N \l_stirling_list_of_plus_separated_tokens_seq
\seq_new:N \l_stirling_list_of_minus_separated_tokens_seq
%% boolean to track whether term was preceded by a "+" or "-"
\bool_new:N \l_term_is_positive_bool
%% token list to store the first term from a string of "-" separated items.
\tl_new:N  \l_stirling_lead_tl

%-@-(3)------------------------------------------------------------------------------------
\bool_new:N \l_stirling_have_not_hit_nondigit_token_yet_bool
\tl_new:N   \l_stirling_tmp_a
\tl_new:N   \l_stirling_tmp_b
\tl_new:N   \l_stirling_tmp_c

\cs_new:Npn \_stirling_var_read_coefficient:n #1 
  {
    \bool_set_true:N \l_stirling_have_not_hit_nondigit_token_yet_bool
    \tl_clear:N      \l_stirling_tmp_a
    \tl_clear:N      \l_stirling_tmp_b
    \tl_clear:N      \l_stirling_tmp_c
    \tl_set:Nf       \l_stirling_tmp_a { \tl_trim_spaces:n { #1 }}
    %% if expression starts with a negative sign, you don't want to mistake
    %% there will be an empty token passed.  You want to ignore this term 
    %% otherwise the constant term will be augmented.
    \tl_if_empty:NF \l_stirling_tmp_a
    {
      \tl_map_inline:Nn \l_stirling_tmp_a
        {
          %% collect all the digits to build the numerical coefficient.
          %% As soon as we hit something that is not a digit, stop and
          %% treat all remaining tokens as part of the variable name 
          %% regardless of whether later digits will occur.
          \bool_if:NTF \l_stirling_have_not_hit_nondigit_token_yet_bool
            {
              \is_digit:nTF { ##1 }
                {  \tl_put_right:Nn  \l_stirling_tmp_b { ##1 } }
                {  \bool_set_false:N \l_stirling_have_not_hit_nondigit_token_yet_bool
                   \tl_put_right:Nn  \l_stirling_tmp_c { ##1 } }
            } 
            {
              \tl_put_right:Nn \l_stirling_tmp_c { ##1 }
            } 
        }
      %% The contents of \l_stirling_tmp_b are to be used as a number.  If
      %% no digits were found, then this variable is empty.  If it is empty,
      %% then it should be set to the value of "1".
      \tl_if_empty:NT \l_stirling_tmp_b { \tl_set:Nn \l_stirling_tmp_b { 1 } }
      \_stirling_var_if_exists:nTF { \l_stirling_tmp_c } 
        { 
          \_stirling_var_advance_counter_according_to_term_sign:nn { \l_stirling_tmp_c } { \l_stirling_tmp_b}
        }
        {
          \_stirling_var_create:n { \l_stirling_tmp_c }
          \_stirling_var_advance_counter_according_to_term_sign:nn { \l_stirling_tmp_c } { \l_stirling_tmp_b}
          %% "x" may be stronger than you need.  But you do need to expand so that it's
          %% not the token \l_stirling_tmp_c sitting in the sequence.
          \seq_put_right:Nx \l_stirling_ordered_list_of_all_variable_names_seq { \l_stirling_tmp_c }
        }
    }
  }     

%-@-(4)------------------------------------------------------------------------------------
\cs_new:Npn \_parse_expression:n #1
  { %%\fbox{\ttfamily#1} 
    \__parse_addition:n {#1}
  }

\cs_new:Npn \__parse_addition:n #1
  {
    \seq_set_split:Nnn \l_stirling_list_of_plus_separated_tokens_seq { + } { #1 }
    \seq_map_function:NN \l_stirling_list_of_plus_separated_tokens_seq 
                         \__parse_subtraction:n
  }

\cs_new:Npn \__parse_subtraction:n #1
  {
      \seq_set_split:Nnn \l_stirling_list_of_minus_separated_tokens_seq { - } { #1 }
      \seq_pop_left:NN   \l_stirling_list_of_minus_separated_tokens_seq \l_stirling_lead_tl
      \bool_set_true:N   \l_term_is_positive_bool
      \_stirling_var_read_coefficient:n { \l_stirling_lead_tl }
      \bool_set_false:N  \l_term_is_positive_bool
      \seq_map_function:NN \l_stirling_list_of_minus_separated_tokens_seq
                           \_stirling_var_read_coefficient:n
  }

%-@-(5)------------------------------------------------------------------------------------
\cs_new:Npn \_reset_coefficient_counters:n #1
  {
    \seq_map_function:NN \l_stirling_ordered_list_of_all_variable_names_seq
                         \_stirling_var_unset:n 
  }

%-@-(6)------------------------------------------------------------------------------------
%%--------------------------------------------------------------------------------
\cs_new:Npn \_write_expression:n #1
  {
    \seq_map_function:NN \l_stirling_ordered_list_of_all_variable_names_seq
                         \_stirling_var_set_according_to_coefficient:n 
  }

\tl_new:N        \l_stirling_plus_sign_tl
\bool_new:N      \l_stirling_passed_first_term_bool
\bool_set_true:N \l_stirling_passed_first_term_bool

\cs_generate_variant:Nn \tl_put_right:Nn {Nf}
\cs_new:Npn \_stirling_var_set_according_to_coefficient:n #1
  {
    %% No "+" should precent the lead term
    \bool_if:NTF   \l_stirling_passed_first_term_bool
      { \tl_set:Nn \l_stirling_plus_sign_tl {   } }
      { \tl_set:Nn \l_stirling_plus_sign_tl { + } }
    \int_compare:nNnT { \_stirling_var_get:n { #1 } } > { 0 } { \l_stirling_plus_sign_tl }
    \int_case:nnn { \_stirling_var_get:n { #1 } }
      { {  0 } {     }
        {  1 } { \tl_if_empty:nTF {#1}{ 1 }{#1}  \bool_set_false:N \l_stirling_passed_first_term_bool}
        { -1 } { -#1                             \bool_set_false:N \l_stirling_passed_first_term_bool}
      } { \_stirling_var_get:n { #1 } #1         \bool_set_false:N \l_stirling_passed_first_term_bool}
    %% as soon as you've processed first coefficient, change
    %% the boolean that tracks this.  Otherwise, you may not
    %% have "+" signs where you believe they should be.  Also,
    %% without this boolean, you might have "+" where you'd prefer
    %% not to have them:  such as in front of the first term.
  }

\ExplSyntaxOff

在完成这么多工作并运行后,我认为创建偏导数将是一项简单的任务。但我在分母方面遇到了困难。这是我编写的代码,试图正确格式化分母。我嵌入了几种方法来做到这一点——有些显然是错误的——但我所做的似乎都没有奏效。我很困惑。

这里的想法是,我格式化分母的每个部分,然后店铺格式顺序当我真正想要打印出导数时,这个变量将被调用。

我已经尝试提前发布有关下一部分代码的问题。 我希望自己能将问题缩小到能产生效果的程度。但遗憾的是,即使我成功地缩小了问题范围,我也很难让发布的解决方案配合使用。

我将以下代码保存在名为查找导数.tex

\ExplSyntaxOn
\seq_new:N  \l_stirling_derivative_denominator_raw_seq
\seq_new:N \l_stirling_denominator_pow_seq

\tl_new:N \l_stirling_tmp_d
\cs_generate_variant:Nn \tl_set:Nn {Nx}
\cs_generate_variant:Nn \seq_gput_right:Nn { Nf}
\cs_new:Npn \_parse_derivative:nn #1#2 
  {
    \_parse_expression:n {#2}
    %%---------------------------------------------------------------------------
    %% This next line gets it completely wrong                                   
    \seq_gput_right:Nn \l_stirling_denominator_pow_seq { d#1^{ \_write_expression:n {}  }}
    %%---------------------------------------------------------------------------
    %% Uncommenting this next set of lines will also result in an error.         
    %% This next approach gives me an "inaccessible" error.                      
    %%<2>%% \tl_set:Nx \l_stirling_tmp_d { \_write_expression:n {}}              
    %%<2>%% \seq_gput_right:Nx \l_stirling_denominator_pow_seq { d#1^{ \l_stirling_tmp_d  }}
    %%---------------------------------------------------------------------------
    %% Uncommenting this line, things are a bit better.  But this seems comletely
    %% contrary to what I want to do.                                            
    %%<3>%% \seq_gput_right:Nn \l_stirling_denominator_pow_seq { d#1^{ \_parse_expression:n {#2} \_write_expression:n {}  }}
    %%---------------------------------------------------------------------------
    %% This line shouldn't be here, but it shows the values that should          
    %% be appearing in the exponents, but which aren't.                          
    \fbox{\_write_expression:n{}}\,
    \_reset_coefficient_counters:n {}  
  }

\cs_new:Npn \parse_derivative:nn #1 #2 
  {
    \seq_set_split:Nnn \l_stirling_derivative_denominator_raw_seq { , } { #2 }
    \seq_map_inline:Nn \l_stirling_derivative_denominator_raw_seq
      {
        \group_begin:
        \tl_if_single:nTF { ##1 }
          { \_parse_derivative:nn { ##1 } { 1 } } 
          { \_parse_derivative:nn ##1 } 
        \group_end:
      } 

    \frac{#1}{ \seq_use:Nn \l_stirling_denominator_pow_seq {\,} }
  }    

\NewDocumentCommand{\derivative}{ mm }
    { \parse_derivative:nn {#1}{#2} }

\ExplSyntaxOff

这是主文档:

\documentclass[12pt]{article}
\usepackage{amsmath,amssymb}
\usepackage{xparse}
\input{lib/reduce_terms}
\input{lib/find_derivatives}
\ExplSyntaxOn
%% Not quite overkill.
\cs_new:Npn \simplify_expression:n #1
  {
    \group_begin:
    \_parse_expression:n {#1}
    \_write_expression:n {}
    \_reset_coefficient_counters:n {}
    \group_end:
  }
\NewDocumentCommand{\simplifyExpression}{ m }
    { \simplify_expression:n {#1} }
\ExplSyntaxOff
\pagestyle{empty}
\begin{document}

\begin{align*}
   \simplifyExpression{12-x-3y-k-x-3-y-y-w+4w+10x-w2-7+5} \\
   \simplifyExpression{3a+x-2y-4x}                        \\
   \simplifyExpression{-3+7-x+2y}                         \\
   \simplifyExpression{-3}                                \\
   \simplifyExpression{1+x}                               \\
   \simplifyExpression{1}                                 \\
   \simplifyExpression{x}                                 \\
   \simplifyExpression{x+y-x}                             \\
\end{align*}

\[
  \derivative{x}{{v}{3},{w}{3k+2-k},y,{z}{m+k}}
\]

\end{document}

结果是

在此处输入图片描述

我的问题是如何让分母中的变量具有正确的指数。s 中的表达式fbox应该作为指数出现。

答案1

我知道这是一个非常老套的话题,你可能已经继续前进或用另一种方式解决了这个问题,但我一直在努力扩展expl3自己,发现这是一个有趣的问题。

核心问题是,\_stirling_var_set_according_to_coefficient:n虽然您已使用 声明了它\cs_new:Npn,但 并非完全可扩展,因此当您将 (调用它)放入 x 参数中时,就会遇到问题\write_expression:n。事实上,您的大多数函数都在其中的某个地方使用了不可扩展的函数,这意味着您也可能会在其他地方遇到麻烦。

基本解决方案是,在解析完成后,将完全格式化的系数和变量序列放入标记列表中,然后打印出来,而不是尝试即时组装它。

下面的版本是相当重要的重写。我修复了一些其他错误,并稍微规范了命名法。我还用基于正则表达式的解决方案替换了您的系数检测算法,这大大缩短了代码长度。

\documentclass[12pt]{article}
\usepackage{amsmath,amssymb}
\usepackage{xparse}

\ExplSyntaxOn

\tl_new:N \g_stirling_formatted_expression_tl
\tl_new:N \l_stirling_var_tl
\tl_new:N \l_stirling_coef_tl
\tl_new:N \l_stirling_plus_tl
\tl_const:Nn \c_stirling_minus_tl {-}
\tl_const:Nn \c_stirling_one_tl {1}

\seq_new:N \l_stirling_denominator_raw_seq
\seq_new:N \g_stirling_denominator_pow_seq
\seq_new:N \l_stirling_variable_names_seq
\seq_new:N \l_stirling_coef_and_var_seq

\regex_const:Nn \c_stirling_find_coef_regex { (?|\s*+?\s*)(-?[0-9]*)\s*([^\s+-]*) }

\cs_new:Nn \_stirling_var_get:n { \int_use:c { l/stirling/var/ #1 /int } }
\cs_new_protected:Nn \_stirling_var_create:n { \int_new:c { l/stirling/var/ #1 /int } }
\cs_new_protected:Nn \_stirling_var_unset:n { \cs_undefine:c { l/stirling/var/ #1 /int } }
\cs_new_protected:Nn \_stirling_var_add:nn { \int_add:cn { l/stirling/var/ #1 /int } {#2} }

\prg_new_conditional:Nnn \_stirling_var_if_exists:n {T,F,TF}
{ 
  \int_if_exist:cTF { l/stirling/var/ #1 /int } 
  { \prg_return_true: } 
  { \prg_return_false: } 
}

\cs_new_protected:Nn \_stirling_reset_counters:
{
  \seq_map_function:NN \l_stirling_variable_names_seq
    \_stirling_var_unset:n 
}

\cs_new_protected:Nn \_stirling_format_expression:
{
  \tl_gclear:N \g_stirling_formatted_expression_tl
  \seq_map_function:NN \l_stirling_variable_names_seq
    \_stirling_format_var:n
}

\cs_new_protected:Nn \_stirling_format_var:n
{
  % No "+" should precede the lead term
  \tl_if_empty:NTF \g_stirling_formatted_expression_tl
  {
    \tl_clear:N \l_stirling_plus_tl
  }
  {
    \tl_set:Nn \l_stirling_plus_tl {+}
  }
  \tl_gput_right:Nx \g_stirling_formatted_expression_tl
  {
    \int_case:nnF { \_stirling_var_get:n { #1 } }
    { {  0 } {}
      {  1 } {\l_stirling_plus_tl \tl_if_empty:nTF {#1}{ 1 }{#1} }
      { -1 } {\tl_if_empty:nTF {#1}{ -1 }{-#1} }
    }
    {
      \int_compare:nNnT {\_stirling_var_get:n {#1}} > {0}
        {\l_stirling_plus_tl}
      \_stirling_var_get:n {#1} #1
    }
  }
}

% the regex split creates triplets in the sequence. The first is always blank,
% the second is the coefficient, and the third is the variable.
\cs_new_protected:Nn \_parse_expression:n
{
  \regex_split:NnN \c_stirling_find_coef_regex {#1} \l_stirling_coef_and_var_seq
  % pop triplets from the sequence until we're done
  \bool_until_do:nn {\seq_if_empty_p:N \l_stirling_coef_and_var_seq}
  {
    % the first pop discards an empty item
    \seq_pop_left:NN \l_stirling_coef_and_var_seq \l_stirling_var_tl
    % get the coefficient
    \seq_pop_left:NN \l_stirling_coef_and_var_seq \l_stirling_coef_tl
    % get the variable
    \seq_pop_left:NN \l_stirling_coef_and_var_seq \l_stirling_var_tl
    % create a variable to track cumulative coefficients
    \_stirling_var_if_exists:nF {\l_stirling_var_tl}
    {
      \_stirling_var_create:n {\l_stirling_var_tl}
      \seq_put_right:Nx \l_stirling_variable_names_seq { \l_stirling_var_tl }
    }
    % normalize 1 and -1
    \tl_if_empty:NTF \l_stirling_coef_tl
    {
      \tl_set:Nn \l_stirling_coef_tl {1}
    }
    {
      \tl_if_eq:NNT \l_stirling_coef_tl \c_stirling_minus_tl
      {
        \tl_set:Nn \l_stirling_coef_tl {-1}
      }
    }
    % add coefficient to existing coefficient of same variable
    \_stirling_var_add:nn {\l_stirling_var_tl} {\l_stirling_coef_tl}
  }
  % convert the formatted sequence into a tokenlist
  \_stirling_format_expression:
}

\cs_new_protected:Nn \_parse_derivative:nn
{
  \_parse_expression:n {#2}
  % Skip exponent if it's just 1
  \tl_if_eq:NNTF \g_stirling_formatted_expression_tl \c_stirling_one_tl
  {
    \seq_gput_right:Nx \g_stirling_denominator_pow_seq {d#1}
  }
  {
    \seq_gput_right:Nx \g_stirling_denominator_pow_seq
      {d#1^{ \g_stirling_formatted_expression_tl } }
  }
  \_stirling_reset_counters:
}

\cs_new_protected:Nn \parse_derivative:n
{
  \seq_set_split:Nnn \l_stirling_denominator_raw_seq { , } { #1 }
  \seq_map_inline:Nn \l_stirling_denominator_raw_seq
  {
    \group_begin:
    \tl_if_single:nTF { ##1 }
    { \_parse_derivative:nn { ##1 } { 1 } } 
    { \_parse_derivative:nn ##1 } 
    \group_end:
  } 
}    

\cs_new_protected:Nn \derivative:nn
{
  \parse_derivative:n {#2}
  \frac{#1}{ \seq_use:Nn \g_stirling_denominator_pow_seq {\,} }  
}

\cs_new_protected:Nn \simplify_expression:n
{
  \group_begin:
  \_parse_expression:n {#1}
  \g_stirling_formatted_expression_tl
  \_stirling_reset_counters:
  \group_end:
}

\NewDocumentCommand{\derivative}{ m m }
{
  \derivative:nn {#1}{#2}
}

\NewDocumentCommand{\simplifyExpression}{ m }
{
  \simplify_expression:n {#1}
}

\ExplSyntaxOff

\begin{document}

  \begin{align*}
  \simplifyExpression{12-x-3y-k-x-3-y-y-w+4w+10x-w2-7+5} \\
  \simplifyExpression{3a+x-2y-4x}                        \\
  \simplifyExpression{-3+7-x+2y}                         \\
  \simplifyExpression{-3}                                \\
  \simplifyExpression{1+x}                               \\
  \simplifyExpression{1}                                 \\
  \simplifyExpression{x}                                 \\
  \simplifyExpression{x+y-x}                             \\
  \end{align*}

  \[
  \derivative{x}{{v}{3},{w}{3k+2-k},y,{z}{m+k}}
  \]

\end{document}

结果如下:

在此处输入图片描述

相关内容