% This is file `diffcoeffx.sty'. % % This program is free software; you can redistribute it and/or modify it % under the terms of the GNU General Public License as published by the % Free Software Foundation; either version 2 of the License, or (at your % option) any later version. % % Andrew Parsloe aparsloe@clear.net.nz % \RequirePackage{expl3} \RequirePackage{xparse} \ProvidesExplPackage{diffcoeffx} {2015/06/27} {1.0} {Write differential coefficients easily.} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_generate_variant:Nn \tl_if_eq:nnF { no } \cs_generate_variant:Nn \tl_if_eq:nnT { no } \cs_generate_variant:Nn \tl_if_in:NnTF { NV } \cs_generate_variant:Nn \prop_pop:NnNT { NV } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % variables \tl_new:N \g_diffco_d_ldelim_tl \tl_new:N \g_diffco_d_rdelim_tl \tl_new:N \g_diffco_p_ldelim_tl \tl_new:N \g_diffco_p_rdelim_tl \tl_new:N \l__diffco_entiand_tl \tl_new:N \l__diffco_phantom_tl \tl_new:N \g_diffco_dop_tl \tl_new:N \l__diffco_denom_tl \tl_new:N \l__diffco_coeff_tl \clist_new:N \l__diffco_order_clist \tl_new:N \l__diffco_order_spec_tl \tl_new:N \l__diffco_nudge_tl \bool_new:N \g__diffco_erent_shape_bool \bool_new:N \l__diffco_no_parens_bool \bool_new:N \l__diffco_override_bool \bool_new:N \l__diffco_ordinary_bool \bool_new:N \l__diffco_fp_bool \bool_new:N \l__diffco_vars_noted_bool \tl_new:N \l__diffco_orders_in_tl \tl_new:N \l__diffco_order_tl \tl_new:N \l__diffco_curr_tok_tl \tl_new:N \l__diffco_curr_term_tl \int_new:N \l__diffco_curr_tok_int \int_new:N \l__diffco_curr_state_int \int_new:N \l__diffco_prev_state_int \prop_new:N \l__diffco_vars_prop \tl_new:N \l__diffco_vars_tl \clist_new:N \l__diffco_vars_clist \tl_new:N \l__diffco_curr_var_tl \tl_new:N \l__diffco_curr_qvar_tl \tl_new:N \l__diffco_nos_tl \tl_new:N \l__diffco_nos_aux_tl \tl_new:N \l__diffco_alg_tl \tl_new:N \l__diffco_alg_aux_tl \tl_new:N \l__diffco_alg_expr_tl \tl_const:Nn \c__diffco_digits_tl { 1234567890 } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \keys_define:nn { diffcoeffx } { roman .bool_gset:N = \g_diffco_roman_bool, roman .default:n = { false }, d-delims .code:n = { \tl_gset:Nx \g_diffco_d_ldelim_tl { \left \use_i:nn #1 } \tl_gset:Nx \g_diffco_d_rdelim_tl { \right \use_ii:nn #1 } }, d-delims .default:n = { .| }, p-delims .code:n = { \tl_gset:Nx \g_diffco_p_ldelim_tl { \left \use_i:nn #1 } \tl_gset:Nx \g_diffco_p_rdelim_tl { \right \use_ii:nn #1 } }, p-delims .default:n = { () }, d-nudge .code:n = { \tl_gset:Nn \g_diffco_d_nudge_tl { \mskip #1 mu } }, d-nudge .default:n = { 0 }, p-nudge .code:n = { \tl_gset:Nn \g_diffco_p_nudge_tl { \mskip #1 mu } }, p-nudge .default:n = { -6 }, sep .code:n = { \tl_gset:Nn \g_diffco_sep_tl { \mskip #1 mu } }, sep .default:n = { 2 }, d-sep .code:n = { \tl_gset:Nn \g_diffco_d_sep_tl { \mskip #1 mu } }, d-sep .default:n = { 1 }, p-sep .code:n = { \tl_gset:Nn \g_diffco_p_sep_tl { \mskip #1 mu } }, p-sep .default:n = { 1 } } \DeclareDocumentCommand \diffset { o } { \IfValueTF { #1 } { \clist_if_empty:nTF { #1 } { \keys_set:nn { diffcoeffx } { roman,d-delims,p-delims, d-nudge,p-nudge,sep,d-sep,p-sep } } { \keys_set:nn { diffcoeffx } { #1 } } } { \keys_set:nn { diffcoeffx } { roman,d-delims,p-delims, d-nudge,p-nudge,sep,d-sep,p-sep } } } % now set the defaults \diffset %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Derivatives % Ordinary differential coefficient. #1 (star) is the append boolean; % #2 is the order; #3 the differentiand; #4 slash / boolean; % #5 the variable of differentiation; #6 the point of evaluation. \NewDocumentCommand \diff{ s o m t/ m g } { \group_begin: % roman or italic? \bool_if:NF \g__diffco_erent_shape_bool { \__diffco_shape:N d } \IfValueTF { #2 } { \tl_set:Nn \l__diffco_order_tl { \g_diffco_d_sep_tl ^{ #2 } } \int_compare:nNnTF { \tl_count:n { #5 } } > { \c_one } { \tl_set:Nn \l__diffco_denom_tl { (#5)^{ #2 } } } { \tl_set:Nn \l__diffco_denom_tl { #5^{ #2 } } } } { \tl_set:Nn \l__diffco_order_tl { } \tl_if_in:nnTF { #5 } { ^ } { \tl_set:Nn \l__diffco_denom_tl { (#5) } } { \tl_set:Nn \l__diffco_denom_tl { #5 } } } % differentiand appended (star) or numerator (no star); % slash or fraction? \IfBooleanTF { #1 } { % differentiand follows diff coeff \__diffco_phantom:n { #3 } \tl_set:Nn \l__diffco_coeff_tl { \IfBooleanTF { #4 } { % slash (therefore no phantom) (\g_diffco_dop_tl \l__diffco_order_tl / \g_diffco_dop_tl \l__diffco_denom_tl ) \l__diffco_entiand_tl } { % frac \frac { \g_diffco_dop_tl \l__diffco_order_tl \l__diffco_phantom_tl } { \g_diffco_dop_tl \l__diffco_denom_tl } \l__diffco_entiand_tl } } } { % differentiand in numerator \tl_set:Nn \l__diffco_coeff_tl { \IfBooleanTF { #4 } { % slash \g_diffco_dop_tl \l__diffco_order_tl #3 / \g_diffco_dop_tl \l__diffco_denom_tl } { % frac \frac { \g_diffco_dop_tl \l__diffco_order_tl #3 } { \g_diffco_dop_tl \l__diffco_denom_tl } } } } % point of eval? \IfNoValueTF { #6 } { % no \l__diffco_coeff_tl } { % yes \bool_set_true:N \l__diffco_ordinary_bool \__diffco_delims:nnnnN #6;;;;\q_stop \l__diffco_ordinary_bool } \group_end: } \NewDocumentCommand \Diff { o m m g } { \group_begin: \__diffco_shape:N D \bool_gset_true:N \g__diffco_erent_shape_bool \diff[#1]{#2}{#3}{#4} \bool_gset_false:N \g__diffco_erent_shape_bool \group_end: } \NewDocumentCommand \diffdelta { o m m g } { \group_begin: \__diffco_shape:N \delta \bool_gset_true:N \g__diffco_erent_shape_bool \diff[#1]{#2}{#3}{#4} \bool_gset_false:N \g__diffco_erent_shape_bool \group_end: } \NewDocumentCommand \Diffdelta { o m m g } { \group_begin: \__diffco_shape:N \Delta \bool_gset_true:N \g__diffco_erent_shape_bool \diff[#1]{#2}{#3}{#4} \bool_gset_false:N \g__diffco_erent_shape_bool \group_end: } \cs_new_nopar:Npn \__diffco_shape:N #1 { \bool_if:NTF \g_diffco_roman_bool { \tl_gset:Nn \g_diffco_dop_tl { \mathrm{ #1} } } { \tl_gset:Nn \g_diffco_dop_tl { #1 } } } %%%%% \cs_new:Npn \__diffco_phantom:n #1 { \bool_if:nTF { \tl_if_head_eq_meaning_p:nN { #1 } \hfill || \tl_if_head_eq_meaning_p:nN { #1 } \hfil } { \l__diffco_phantom_aux:nn #1\q_stop } { \bool_if:nTF { \tl_if_head_eq_meaning_p:nN { #1 } \hspace || \tl_if_head_eq_meaning_p:nN { #1 } \hphantom } { \l__diffco_phantom_aux:nnn #1\q_stop } { \tl_set:Nn \l__diffco_entiand_tl { #1 } } } } \cs_new:Npn \l__diffco_phantom_aux:nn #1#2\q_stop { \tl_set:Nn \l__diffco_phantom_tl { #1 } \tl_set:Nn \l__diffco_entiand_tl { #2 } } \cs_new:Npn \l__diffco_phantom_aux:nnn #1#2#3\q_stop { \tl_set:Nn \l__diffco_phantom_tl { #1 { #2 } } \tl_set:Nn \l__diffco_entiand_tl { #3 } } %%%%%%%%%%%%%%%%%%%% % Partial differential coefficient. #1 (star) = append differentiand % to diff. coeff.(displace from numerator); #2 = comma list of the % orders of diff. in each var.; #3 = order override for the % numerator; #4 = differentiand; #5 = clist of vars of diff. in % order; #6 = list of vars held constant \NewDocumentCommand \diffp{ s o o t/ m m g } { \group_begin: % diff. order list \tl_clear:N \l__diffco_order_clist \IfValueT { #2 } { \clist_set:Nn \l__diffco_order_clist { #2 } \tl_set:Nx \l__diffco_order_spec_tl { [\clist_use:Nn \l__diffco_order_clist { , }]} } % order list override \IfValueT { #3 } { \bool_set_true:N \l__diffco_override_bool \tl_set:Nn \l__diffco_order_tl { #3 } } \__diffco_orders:Nn \l__diffco_order_clist { #6 } % position of differentiand \IfBooleanTF { #1 } { % appended \__diffco_phantom:n { #5 } \tl_set:Nn \l__diffco_coeff_tl { \frac { \partial \__diffco_omit_order_if_i:N \l__diffco_order_tl \l__diffco_phantom_tl } { \l__diffco_denom_tl } \l__diffco_entiand_tl } } { % in numerator \tl_set:Nn \l__diffco_coeff_tl { \frac { \partial \__diffco_omit_order_if_i:N \l__diffco_order_tl #5 } { \l__diffco_denom_tl } } } \IfNoValueTF { #7 } { \l__diffco_coeff_tl } { % hold some vars const./ pt of eval. \bool_set_false:N \l__diffco_ordinary_bool \__diffco_delims:nnnnN #7;;;;\q_stop \l__diffco_ordinary_bool } \group_end: } % end of \diffp \NewDocumentCommand \jacob { m m } { % need extra braces in denom for clist manipulations \diffp{ (#1) }{ { {{(#2)}} } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % #1 subscript; #2 superscript; #3 delims; #4 nudge override % #5 detritus; #6 boolean (true = ordinary deriv.; false = partial deriv.) \cs_new:Npn \__diffco_delims:nnnnN #1;#2;#3;#4;#5\q_stop#6 { \tl_set:Nn \l__diffco_sub_tl { #1 } \tl_set:Nn \l__diffco_super_tl { #2 } \tl_if_empty:nTF { #3 } { % default delims \bool_if:NTF #6 { % ordinary \tl_set_eq:NN \l__diffco_ldelim_tl \g_diffco_d_ldelim_tl \tl_set_eq:NN \l__diffco_rdelim_tl \g_diffco_d_rdelim_tl \tl_if_empty:nTF { #4 } { \tl_set_eq:NN \l__diffco_nudge_tl \g_diffco_d_nudge_tl } { \tl_set:Nn \l__diffco_nudge_tl { \mskip #4 mu } } } { % partial \tl_set_eq:NN \l__diffco_ldelim_tl \g_diffco_p_ldelim_tl \tl_set_eq:NN \l__diffco_rdelim_tl \g_diffco_p_rdelim_tl \tl_if_empty:nTF { #4 } { \tl_set_eq:NN \l__diffco_nudge_tl \g_diffco_p_nudge_tl } { \tl_set:Nn \l__diffco_nudge_tl { \mskip #4 mu } } } } { % delims specified \tl_set:Nn \l__diffco_ldelim_tl { \left \use_i:nn #3 } \tl_set:Nn \l__diffco_rdelim_tl { \right \use_ii:nn #3 } \tl_if_empty:nTF { #4 } { \tl_set:NV \l_tmpa_tl { \use_ii:nn #3 } \__diffco_get_nudge:N \l_tmpa_tl } { \tl_set:Nx \l__diffco_nudge_tl { \mskip #4 mu } } } \l__diffco_ldelim_tl \l__diffco_coeff_tl \l__diffco_rdelim_tl \tl_if_empty:NF \l__diffco_sub_tl { \c_math_subscript_token { \l__diffco_nudge_tl \l__diffco_sub_tl } } \tl_if_empty:NF \l__diffco_super_tl { \c_math_superscript_token { \l__diffco_nudge_tl \l__diffco_super_tl } } } \cs_new:Npn \__diffco_get_nudge:N #1 { \exp_args:NV\tl_case:NnF #1 { ) { \tl_set:Nn \l__diffco_nudge_tl { \mskip -6mu } } > { \tl_set:Nn \l__diffco_nudge_tl { \mskip -6mu } } \} { \tl_set:Nn \l__diffco_nudge_tl { \mskip -4mu } } \rangle { \tl_set:Nn \l__diffco_nudge_tl { \mskip -6mu } } } { \tl_set:Nn \l__diffco_nudge_tl { \mskip 0mu } } } % #1 is the clist of diff. orders % #2 is the clist of variables \cs_new:Npn \__diffco_orders:Nn #1#2 { \int_zero:N \l_tmpa_int \tl_clear:N \l_tmpb_tl \clist_clear:N \l_tmpa_clist \clist_clear:N \l_tmpb_clist \clist_clear:N \l__diffco_vars_clist \clist_set:Nn \l__diffco_vars_clist { #2 } \clist_map_inline:Nn \l__diffco_vars_clist { \bool_set_false:N \l__diffco_no_parens_bool % get order of each variable \clist_pop:NNF #1 \l_tmpa_tl { \tl_set:Nn \l_tmpa_tl { 1 } } \tl_if_eq:noT { 1 } \l_tmpa_tl { \bool_set_true:N \l__diffco_no_parens_bool } \clist_put_right:NV \l_tmpa_clist \l_tmpa_tl % create the denominator \tl_clear:N \l_tmpb_tl \bool_if:nTF { \int_compare_p:nNn { \tl_count:n { ##1 } } = { \c_one } || \l__diffco_no_parens_bool } { \tl_put_right:Nn \l_tmpb_tl { \partial ##1 } } { \tl_put_right:Nn \l_tmpb_tl { \partial (##1) } } \tl_if_eq:noF { 1 } \l_tmpa_tl { \tl_put_right:Nn \l_tmpb_tl { ^ } \tl_put_right:Nx \l_tmpb_tl { { \l_tmpa_tl } } } \clist_put_right:No \l_tmpb_clist \l_tmpb_tl } % end of inline map % numerator order \bool_if:NF \l__diffco_override_bool { \tl_set:Nx \l__diffco_orders_in_tl { \clist_use:Nn \l_tmpa_clist {+} } \diff_simplify_orders:NN \l__diffco_orders_in_tl \l__diffco_order_tl } % denominator \tl_set:Nx \l__diffco_denom_tl { \clist_use:Nn \l_tmpb_clist { \g_diffco_sep_tl } } } % don't display order 1 superscript \cs_new:Npn \__diffco_omit_order_if_i:N #1 { \tl_if_eq:noF { 1 } #1 { ^{ \g_diffco_p_sep_tl \l__diffco_order_tl } } } %%%%%%%%%%%%%%%%%%%%%% % #1 is expr. in; #2 is expr. out \cs_new:Npn \diff_simplify_orders:NN #1 #2 { \tl_clear:N \l__diffco_nos_tl \__diffco_digest_expr:NNNN #1 \l__diffco_nos_tl \l__diffco_alg_tl \l__diffco_vars_prop \__diffco_eval_nos:N \l__diffco_nos_tl \tl_if_empty:NF \l__diffco_alg_tl { \__diffco_eval_vars:NN \l__diffco_alg_tl \l__diffco_vars_prop } \__diffco_manicure_result:NNN \l__diffco_nos_tl \l__diffco_alg_tl #2 } % #1 is the expression; #2 (tl) receives the numerical part; % #3 (tl) receives the algebraic part; #4 (prop) receives the vars \cs_new:Npn \__diffco_digest_expr:NNNN #1#2#3#4 { \tl_put_right:Nn #1 { + } \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set:Nn \l__diffco_curr_state_int { \c_zero } \int_set:Nn \l__diffco_prev_state_int { \c_zero } \int_set:Nn \l__diffco_curr_tok_int { \c_zero } \tl_clear:N #3 \prop_clear:N #4 \tl_map_inline:Nn #1 { \tl_set:Nn \l__diffco_curr_tok_tl { ##1 } \__diffco_get_curr_index:NN ##1 \l__diffco_curr_tok_int \__diffco_compare_states:NNNNN \l__diffco_curr_state_int \l__diffco_curr_tok_int #2#3#4 } \tl_if_empty:NT #2 { \tl_set:Nn #2 { 0 } } } % #1 contains current token (tl); #2 receives current token index (int) \cs_new:Npn \__diffco_get_curr_index:NN #1#2 { \tl_if_in:NnTF \c__diffco_digits_tl { #1 } { % digit \int_set:Nn #2 { \c_one } } { \tl_case:NnF #1 { + { \int_set_eq:NN #2 \c_zero } - { \int_set_eq:NN #2 \c_zero } ^ { \int_set_eq:NN #2 \c_three } * { \int_set_eq:NN #2 \c_five } \times { \int_set_eq:NN #2 \c_five \tl_set:Nn \l__diffco_curr_tok_tl { * } } ( { \int_set_eq:NN #2 \c_six } ) { \int_set_eq:NN #2 \c_seven } } { \token_if_math_subscript:NTF #1 { \int_set_eq:NN #2 { \c_four } } { \int_set_eq:NN #2 \c_two } % var } } } % #1 (int) is curr. state; #2 (int) is curr token index; % #3 (tl) receives the numerical part; % #4 (tl) receives the algebraic part; % #5 (prop) receives the vars \cs_new:Npn \__diffco_compare_states:NNNNN #1#2#3#4#5 { \int_case:nn { #1 } { { \c_zero } % sgn { \__diffco_sgn_transitions:NNNN #1#2#3#4 } { \c_one } % num { \__diffco_num_transitions:NNNN #1#2#3#4 } { \c_two } % alg { \__diffco_alg_transitions:NNNNN #1#2#3#4#5 } { \c_three } % exp { \__diffco_exp_transitions:NN #1#2 } { \c_four } % sub (_) { \__diffco_sub_transitions:NN #1#2 } { \c_five } % mul (*,X) { \__diffco_mul_transitions:NNNN #1#2#3#4 } } } % transitions from the signed state % #1 = 0, current state; #2 current token index % #3 store num. part; #4 store alg. part \cs_new:Npn \__diffco_sgn_transitions:NNNN #1#2#3#4 { \int_case:nnF { #2 } { { \c_zero } % tok = s { \tl_if_eq:NNTF \l__diffco_curr_term_tl \l__diffco_curr_tok_tl { \tl_set:Nn \l__diffco_curr_term_tl { + } } { \tl_set:Nn \l__diffco_curr_term_tl { - } } \int_set_eq:NN \l__diffco_prev_state_int #1 % \int_set:Nn #1 { \c_zero } } { \c_one } % tok = d { \__diffco_term_qvar_append:NN #1 #2 } { \c_two } % tok = v { \tl_put_right:Nn \l__diffco_curr_term_tl { 1 } \__diffco_term_var_append:NN #1 #2 } { \c_six } % tok = ( { \tl_put_right:Nn \l__diffco_curr_term_tl { 1*( } \tl_put_right:NV #3 \l__diffco_curr_term_tl \tl_put_right:NV #4 \l__diffco_curr_term_tl \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set:Nn #1 { \c_zero } } { \c_seven } % tok = ) { \tl_put_right:Nn #3 { ) } \tl_put_right:Nn #4 { ) } \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set:Nn #1 { \c_zero } } } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { sign } } } % transitions from the numeric state % #1 = 1, current state; #2 current token index % #3 store num. part; #4 store alg. part \cs_new:Npn \__diffco_num_transitions:NNNN #1#2#3#4 { \int_case:nnF { #2 } { { \c_zero } % tok = s { \tl_put_right:NV #3 \l__diffco_curr_term_tl \tl_clear:N \l__diffco_curr_qvar_tl \tl_clear:N \l__diffco_curr_term_tl \__diffco_term_append:NN #1#2 } { \c_one } % tok = d { \__diffco_term_qvar_append:NN #1 #2 } { \c_two } % tok = v { \tl_clear:N \l__diffco_curr_qvar_tl \__diffco_term_var_append:NN #1#2 } { \c_three } % tok = ^ { \__diffco_term_qvar_append:NN #1#2 } { \c_five } % tok = * { \tl_clear:N \l__diffco_curr_qvar_tl \__diffco_term_append:NN #1#2 } { \c_six } % tok = ( { \tl_put_right:Nn \l__diffco_curr_term_tl { *( } \tl_put_right:NV #3 \l__diffco_curr_term_tl \tl_put_right:NV #4 \l__diffco_curr_term_tl \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set:Nn #1 { \c_zero } } { \c_seven } % tok = ) { \tl_put_right:Nn \l__diffco_curr_term_tl { ) } \tl_put_right:NV #3 \l__diffco_curr_term_tl \tl_put_right:Nn #4 { +0) } \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set:Nn #1 { \c_zero } } } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { number } } } % transitions from the algebraic state % #1 = 2, current state; #2 current token index % #3 store num. part; #4 store alg. part; #5 var store \cs_new:Npn \__diffco_alg_transitions:NNNNN #1#2#3#4#5 { \int_case:nnF { #2 } { { \c_zero } % tok = s { \bool_if:NF \l__diffco_vars_noted_bool { \__diffco_store_var:NN #5 \l__diffco_curr_var_tl } \tl_clear:N \l__diffco_curr_var_tl \tl_put_right:NV #4 \l__diffco_curr_term_tl \tl_clear:N \l__diffco_curr_term_tl \__diffco_term_append:NN #1 #2 } { \c_one } % tok = d { \int_compare:nNnTF { \l__diffco_prev_state_int } = { \c_three } { \__diffco_term_var_append:NN #1 \c_two } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { variable } } } { \c_two } % tok = v { \__diffco_term_var_append:NN #1 #2 } { \c_three } % tok = ^ { \__diffco_term_var_append:NN #1#2 } { \c_four } % tok = _ { \__diffco_term_var_append:NN #1#2 } { \c_seven } % tok = ) { \bool_if:NF \l__diffco_vars_noted_bool { \__diffco_store_var:NN #5 \l__diffco_curr_var_tl } \tl_clear:N \l__diffco_curr_var_tl \tl_put_right:Nn \l__diffco_curr_term_tl { ) } \tl_put_right:Nn #3 { +0) } \tl_put_right:NV #4 \l__diffco_curr_term_tl \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set:Nn #1 { \c_zero } } } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { variable } } } % transitions from the exponent state % #1 = 3, current state; #2 current token index \cs_new:Npn \__diffco_exp_transitions:NN #1#2 { \int_case:nn { \l__diffco_prev_state_int } { { \c_one } % prev = num { \int_case:nnF { #2 } { { \c_one } % tok = d { \tl_clear:N \l__diffco_curr_qvar_tl \tl_put_right:Nn \l__diffco_curr_tok_tl { * } \__diffco_term_append:NN #1 \c_five \bool_set_true:N \l__diffco_fp_bool } { \c_two } % tok = v { \__diffco_term_qvar_append:NN #1 \c_two \tl_set_eq:NN \l__diffco_curr_var_tl \l__diffco_curr_qvar_tl \tl_clear:N \l__diffco_curr_qvar_tl } } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { ^ } } } { \c_two } % prev = alg { \int_compare:nNnTF { #2 } < { \c_three } { \__diffco_term_var_append:NN #1 \c_two } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { ^ } } } } } % transitions from the subscript state % #1 = 4, current state; #2 current token index \cs_new:Npn \__diffco_sub_transitions:NN #1#2 { \bool_if:nTF {( \int_compare_p:nNn { \l__diffco_prev_state_int } = { \c_two } && \int_compare_p:nNn { #2 } < { \c_three } )} { \__diffco_term_var_append:NN #1 \c_two } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { _ } } } % transitions from the multiplicative state % #1 = 5, current state; #2 current token index % #3 store num. part; #4 store alg. part \cs_new:Npn \__diffco_mul_transitions:NNNN #1#2#3#4 { \int_case:nnF { #2 } { { \c_zero } % tok = s { \int_compare:nNnTF {\l__diffco_prev_state_int } = { \c_three } { \tl_put_right:Nn \l__diffco_curr_term_tl { 1 } \tl_put_right:NV #3 \l__diffco_curr_term_tl \tl_clear:N \l__diffco_curr_term_tl \__diffco_term_append:NN #1 #2 } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { multiplicative~token } } } { \c_one } % tok = d { \__diffco_term_qvar_append:NN #1 #2 } { \c_two } % tok = v { \tl_put_right:Nn \l__diffco_curr_term_tl {1 } \__diffco_term_var_append:NN #1#2 } { \c_five } % tok = * { \prg_do_nothing: } { \c_six } % tok = ( { \tl_put_right:Nn \l__diffco_curr_term_tl { ( } \tl_put_right:NV #3 \l__diffco_curr_term_tl \tl_put_right:NV #4 \l__diffco_curr_term_tl \tl_set:Nn \l__diffco_curr_term_tl { + } \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set:Nn #1 { \c_zero } } } { \msg_error:nnxxx { diffcoeffx } { order_spec_construct } { \l__diffco_order_spec_tl } { \l__diffco_curr_tok_tl } { multiplicative~token } } } %%%%%%%%%%%%%%%%%%% % term/var/qvar appending routines % #1 current state; #2 current token index \cs_new:Npn \__diffco_term_var_append:NN #1#2 { \tl_put_right:NV \l__diffco_curr_term_tl \l__diffco_curr_tok_tl \tl_put_right:NV \l__diffco_curr_var_tl \l__diffco_curr_tok_tl \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set_eq:NN #1 #2 } % #1 current state; #2 current token index \cs_new:Npn \__diffco_term_qvar_append:NN #1#2 { \tl_put_right:NV \l__diffco_curr_term_tl \l__diffco_curr_tok_tl \tl_put_right:NV \l__diffco_curr_qvar_tl \l__diffco_curr_tok_tl \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set_eq:NN #1 #2 } % #1 current state; #2 current token index \cs_new:Npn \__diffco_term_append:NN #1#2 { \tl_put_right:NV \l__diffco_curr_term_tl \l__diffco_curr_tok_tl \int_set_eq:NN \l__diffco_prev_state_int #1 \int_set_eq:NN #1 #2 } % #1 is prop list; #2 is tl containing var \cs_new:Npn \__diffco_store_var:NN #1 #2 { \int_set:Nn \l_tmpa_int { \exp_args:NV \tl_count_tokens:n #2 } \prop_get:NVNTF #1 \l_tmpa_int \l_tmpa_tl { \tl_put_right:Nn \l_tmpa_tl { , } \tl_put_right:NV \l_tmpa_tl #2 \prop_put:NVV #1 \l_tmpa_int \l_tmpa_tl } { \prop_put:NVV #1 \l_tmpa_int #2 } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % evals numerical expr. in #1, which receives the % evaluated expr. \cs_new:Npn \__diffco_eval_nos:N #1 { \bool_if:NTF \l__diffco_fp_bool { % exponent; use l3fp \fp_set:Nn \l_tmpa_fp { #1 } \int_set:Nn \l_tmpa_int { \fp_use:N \l_tmpa_fp } \bool_set_false:N \l__diffco_fp_bool } { % normal mode; use l3int \int_set:Nn \l_tmpa_int { #1 } } \tl_set:Nx #1 { \int_use:N \l_tmpa_int } \int_compare:nNnT { \l_tmpa_int } > { \c_zero } { \tl_put_left:Nn #1 { + } } } % #1 (tl) has algebraic part & receives eval. expression % #2 (prop) contains the variables % The idea is to remove each var but leave coeffs, split into % num & alg parts, eval. the num part for the net coeff of var \cs_new:Npn \__diffco_eval_vars:NN #1#2 { \bool_set_true:N \l__diffco_vars_noted_bool \prop_set_eq:NN \l_tmpa_prop #2 \int_set_eq:NN \l_tmpa_int \c_one \bool_until_do:nn { \prop_if_empty_p:N #2 } { \prop_pop:NVNT #2 \l_tmpa_int \l_tmpa_tl { \tl_put_left:Nn \l_tmpa_tl { , } \tl_put_left:NV \l__diffco_vars_tl \l_tmpa_tl } \int_incr:N \l_tmpa_int } \clist_set:NV \l__diffco_vars_clist \l__diffco_vars_tl \clist_remove_duplicates:N \l__diffco_vars_clist \bool_if:NF \l__diffco_override_bool { \clist_map_inline:Nn \l__diffco_vars_clist { \tl_replace_all:Nnn #1 { ##1 } { } \__diffco_digest_expr:NNNN #1 \l__diffco_nos_aux_tl \l__diffco_alg_aux_tl \l_tmpa_prop \__diffco_eval_nos:N \l__diffco_nos_aux_tl \__diffco_cumulate_expr:NnN \l__diffco_nos_aux_tl { ##1 } \l__diffco_alg_expr_tl \tl_set_eq:NN #1 \l__diffco_alg_aux_tl \tl_clear:N \l__diffco_nos_aux_tl \tl_clear:N \l__diffco_alg_aux_tl } } \tl_set_eq:NN #1 \l__diffco_alg_expr_tl } % #1 is num coeff; #2 is var; #3 is cumulating expr. (All tl.) \cs_new:Npn \__diffco_cumulate_expr:NnN #1#2#3 { \int_case:nnF { #1 } { { 0 } { \prg_do_nothing: } { +1 } { \tl_put_right:Nn #3 { + #2 } } { -1 } { \tl_put_right:Nn #3 { - #2 } } } { \tl_put_right:NV #3 { #1 } \exp_args:NNx \tl_if_in:NnT \c__diffco_digits_tl { \tl_head:n { #2 } } { \tl_put_right:Nn #3 { \times} } \tl_put_right:Nn #3 { #2 } } } % alg. part precedes num. part unless alg. starts % with - and nums > 0. #1 nums, #2 alg, #3 output \cs_new:Npn \__diffco_manicure_result:NNN #1#2#3 { % alg < 0 ? \exp_args:NV \tl_if_head_eq_charcode:nNTF #2 - { \int_compare:nNnTF { #1 } > { \c_zero } { % nums > 0 \tl_concat:NNN #3 #1 #2 } { % nums =< 0 \seq_set_split:NnV \l_tmpa_seq { + } #2 \seq_pop:NN \l_tmpa_seq \l_tmpa_tl \tl_set:Nx \l_tmpb_tl { \seq_use:Nn \l_tmpa_seq { + } } \int_compare:nNnF { #1 } = { \c_zero } { \tl_concat:NNN \l_tmpa_tl \l_tmpa_tl #1 } \tl_concat:NNN #3 \l_tmpb_tl \l_tmpa_tl } } { % alg >= 0 \int_compare:nNnTF { #1 } = { \c_zero } { \tl_set_eq:NN #3 #2 } { \tl_concat:NNN #3 #2 #1 } } % if everything cancels, output 0 \tl_if_empty:NTF #3 { \tl_set:Nn #3 { 0 } } { % trim initial + sign \exp_args:NV \tl_if_head_eq_charcode:nNT #3 + { \tl_set:Nx #3 { \tl_tail:N #3 } } } } %%%%%%%%%%%%%%%%%%%% % messages \cs_gset:Npn \msg_error_text:n #1 { #1.sty.~Is~this~construction~intended } \cs_gset:Npn \msg_info_text:n #1 { If~intended~then~use~the~order-override~option~to~specify~the~overall~ order~of~differentiation. } \msg_new:nnnn { diffcoeffx } { order_spec_construct } { \msg_error_text:n { diffcoeffx }:~#3~followed~by~#2~in~the~order~ specification~#1~\msg_line_context:? } { \msg_info_text:n { diffcoeffx } }