Saturday, 24 August 2013

Difficulty saving formatting to a sequence to be called later in my code

Difficulty saving formatting to a sequence to be called later in my code

I had an idea about how to answer this question and started putting some
things together. I wanted to put something together that was fairly
powerful and could handle simplification of linear expressions.
I should start by apologizing for the length of this example. It is quite
long. But all my attempts at reducing it have either resulted in code that
compiles, or results in code that has other issues which, when resolved
seem to shed no light on what's happening here. I can say that the first
portion of code I post below works reasonably well (it's not perfect, but
it does get close to the job I want).
Regarding simplifying linear expressions, I got something that worked
pretty well. Here's the code I put together to do that; I called the file
containing this code *reduce_terms.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
After getting this much up and running, I thought it would be a simple
task to create the partial derivatives. But I got stuck with the
denominators. Here's the code that I wrote trying to get the denominator
formatted correctly. I've embedded several of my approaches to get this
right--some are clearly wrong--but nothing I do seems to work. I'm quite
mystified.
The idea here is that I format each part of the denominator and then store
the formatting in a sequence variable which will be called later on when I
actually want to print out the derivative.
I've already tried posting a question early regarding this next portion of
code. I was hoping I'd narrowed it down to something that would prove
fruit. But alas, even if I managed to narrow it down correctly, I'm having
difficulty getting the posted solutions to cooperate.
This following code I saved in a file I called *find_derivatives.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
Here's the master document:
\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}
which results in

My question is about how to get the variables in the denominator to have
the correct exponents. The expressions in the fboxs are what should be
appearing as the exponents.

No comments:

Post a Comment