我有一个关于如何回答的想法这个问题并开始把一些东西放在一起。我想把一些东西放在一起,它相当强大,可以处理线性表达式的简化。
首先,我要为这个例子的长度道歉。它很长。但我为缩短它所做的所有尝试要么导致代码编译成功,要么导致代码存在其他问题,这些问题在解决后似乎无法解释这里发生了什么。我可以说,我下面发布的第一部分代码是有效的合理地好吧(虽然不完美,但确实接近我想要的工作)。
关于简化线性表达式,我找到了一个非常有效的方法。这是我为此编写的代码;我将包含此代码的文件命名为减少术语.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}
结果如下: