% derivative.sty % Copyright 2019-2024 Simon Jensen % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Simon Jensen. % Contributors: Romain Noel \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3}[2023/12/08] \RequirePackage{l3keys2e} \ProvidesExplPackage{derivative}{2024/02/08}{1.4}{Nice and easy derivatives and differentials for LaTeX} \bool_new:N \l__deriv_pkg_italic_bool \bool_new:N \l__deriv_pkg_upright_bool \keys_define:nn { deriv/pkg } { italic .choice:, italic .usage:n = { load }, italic .default:n = { true }, italic / true .code:n = { \bool_set_true:N \l__deriv_pkg_italic_bool \bool_set_false:N \l__deriv_pkg_upright_bool }, italic / false .code:n = { \bool_set_false:N \l__deriv_pkg_italic_bool \bool_set_true:N \l__deriv_pkg_upright_bool }, italic / unknown .code:n = { \msg_error:nnx { deriv } { boolean-values-only } \l_keys_key_str }, upright .choice:, upright .usage:n = { load }, upright .default:n = { true }, upright / true .code:n = { \bool_set_true:N \l__deriv_pkg_upright_bool \bool_set_false:N \l__deriv_pkg_italic_bool }, upright / false .code:n = { \bool_set_false:N \l__deriv_pkg_upright_bool \bool_set_true:N \l__deriv_pkg_italic_bool }, upright / unknown .code:n = { \msg_error:nnx { deriv } { boolean-values-only } \l_keys_key_str }, upright .initial:n = true, } \ProcessKeysPackageOptions{ deriv/pkg } %%%%% Useful conditionals %%%%% \prg_new_conditional:Npnn \__deriv_if_value:n #1 { T, TF } { \tl_if_novalue:nTF {#1} { \prg_return_false: } { \tl_if_blank:nTF {#1} { \prg_return_false: } { \prg_return_true: } } } \prg_new_conditional:Npnn \__deriv_show_order:N #1 { T, TF } { \str_if_eq:NNTF #1 1 { \prg_return_false: } { \prg_return_true: } } \prg_new_protected_conditional:Npnn \__deriv_if_in_two_seq:NNNN #1 #2 #3 #4 { TF } { \int_zero:N \l__deriv_seq_pos_int \seq_map_indexed_inline:Nn #1 { \str_if_eq:VnT #3 {##2} %todo choose correct check { \tl_set:Nf \l__deriv_tmpa_tl { \seq_item:Nn #2 {##1} } \tl_if_eq:NNT #4 \l__deriv_tmpa_tl { \seq_map_break:n { \int_set:Nn \l__deriv_seq_pos_int {##1} } } } } \int_compare:nNnTF \l__deriv_seq_pos_int = 0 { \prg_return_false: } { \prg_return_true: } } %%%%% Variables: derivatives %%%%% \tl_new:N \l__deriv_dv_denom_tl \seq_new:N \l__deriv_dv_var_seq \seq_new:N \l__deriv_dv_order_seq \seq_new:N \l__deriv_dv_variant_seq %%%%% Variables: differential %%%%% \seq_new:N \l__deriv_i_var_seq \seq_new:N \l__deriv_i_order_seq \tl_new:N \l__deriv_i_denom_tl \seq_new:N \l__deriv_i_variant_seq %%%%% Variables: other %%%%% \tl_new:N \l__deriv_cs_name_tl \tl_new:N \l__deriv_derivset_tl \bool_new:N \l__deriv_first_unknown_key_bool \tl_new:N \l__deriv_gcd_result_tl \tl_new:N \l__deriv_gcd_remain_tl \int_new:N \l__deriv_gcd_counter_int \tl_new:N \l__deriv_tmpa_tl \tl_new:N \l__deriv_tmpb_tl \tl_new:N \l__deriv_tmpc_tl \seq_new:N \l__deriv_tmpa_seq \seq_new:N \l__deriv_new_var_seq \seq_new:N \l__deriv_rubber_seq \seq_new:N \l__deriv_add_var_bool_seq \int_new:N \l__deriv_vmo_int \seq_new:N \l__deriv_num_tmpa_seq \seq_new:N \l__deriv_num_tmpb_seq \seq_new:N \l__deriv_sym_tmpa_seq \seq_new:N \l__deriv_sym_tmpb_seq \tl_new:N \l__deriv_sym_tmpa_tl \tl_new:N \l__deriv_num_tmpa_tl \tl_new:N \l__deriv_sym_tmpb_tl \tl_new:N \l__deriv_num_tmpb_tl \tl_new:N \l__deriv_input_tl \seq_new:N \l__deriv_input_seq \seq_new:N \l__deriv_extract_seq \seq_new:N \l__deriv_permutation_seq \seq_new:N \l__deriv_sorted_seq \seq_new:N \l__deriv_symbol_seq \seq_new:N \l__deriv_number_seq \int_new:N \l__deriv_var_count_int \int_new:N \l__deriv_tmpa_int \int_new:N \l__deriv_tmpb_int \tl_new:N \l__deriv_numerical_tl \int_new:N \l__deriv_seq_pos_int \int_new:N \l__deriv_sort_max_int \regex_const:Nn \c__deriv_cs_numbers_regex { \A\-?\d+(?:,\d+){0,2}\Z } \tl_const:Nn \c__deriv_digits_tl {123456789-0} %%%%% default values %%%%% \prop_const_from_keyval:Nn \c__deriv_dv_pkg_keys_prop { style-inf-num = d, style-inf-den = d, style-frac = \frac, style-frac-/ = \slashfrac, style-var = single, style-var-/ = single, style-var-! = multiple, style-var-/! = single, scale-eval = auto, scale-eval-/ = auto, scale-eval-! = auto, scale-fun = auto, scale-var = auto, scale-var-! = auto, scale-frac = auto, scale-frac-/ = auto, delims-eval = .\rvert, delims-eval-/ = .\rvert, delims-eval-! = .\rvert, delims-fun = (), delims-var = (), delims-var-! = (), delims-frac = (), delims-frac-/ = (), sep-inf-ord = 0, sep-inf-fun = 0, sep-ord-fun = 0, sep-frac-fun = 0, sep-inf-var = 0, sep-var-ord = 0, sep-var-inf = \mathop{}\!, sep-ord-inf = \mathop{}\!, sep-ord-ord = {,}, sep-ord-var = 0, sep-var-var = {,}, sep-eval-sb = 0, sep-eval-sp = 0, switch-* = false, switch-/ = false, switch-! = false, switch-sort = true, sort-method = {sign, symbol, abs}, sort-numerical = auto, sort-abs-reverse = false, sort-number-reverse = false, sort-sign-reverse = false, sort-symbol-reverse = false, sort-lexical-reverse = false, fun = false, frac = false, var = none, order = 1, mixed-order = 1 } \prop_const_from_keyval:Nn \c__deriv_i_pkg_keys_prop { style-inf = d, style-var = multiple, style-var-* = single, scale-var = auto, scale-var-* = auto, delims-var = (), delims-var-* = (), sep-begin = \mathop{}\!, sep-inf-ord = 0, sep-inf-var = 0, sep-ord-var = 0, sep-var-inf = \mathop{}\!, sep-var-var = {,}, sep-ord-ord = {,}, sep-end = 0, switch-* = false, var = none, order = 1 } %%%%%% Key-val for all %%%%%% \prop_new:N \l__deriv_all_all_user_keys_prop \prop_const_from_keyval:Nn \c__deriv_all_pkg_keys_prop { scale-auto = leftright } \keys_define:nn { deriv/all/all } { scale-auto .choice:, scale-auto / leftright .code:n = { \cs_set_eq:NN \__deriv_auto_left:n \left \cs_set_eq:NN \__deriv_auto_right:n \right }, scale-auto / mleftmright .code:n = { \cs_set_eq:NN \__deriv_auto_left:n \mleft \cs_set_eq:NN \__deriv_auto_right:n \mright } } %%%%%% Key-val: Derivative %%%%%% % variant \cs_new:Npn \__deriv_dv_define_keys:n #1 { \keys_define:nn { deriv/dv/#1 } { style-inf .meta:n = { style-inf-num={##1}, style-inf-den={##1} }, style-inf-num .tl_set:c = { l__deriv_dv_#1_style_inf_num_tl }, style-inf-den .tl_set:c = { l__deriv_dv_#1_style_inf_den_tl }, style-var .choices:nn = { single, multiple } { \__deriv_dv_set_style_var:nnn {dv_#1} {##1} { } }, style-var-/ .choices:nn = { single, multiple } { \__deriv_dv_set_style_var:nnn {dv_#1} {##1} { _slash } }, style-var-! .choices:nn = { single, multiple, mixed } { \__deriv_i_set_style_var:nnn {dv_#1} {##1} { _compact } }, style-var-/! .choices:nn = { single, multiple, mixed } { \__deriv_i_set_style_var:nnn {dv_#1} {##1} { _slash_compact } }, style-frac .cs_set:cp = { __deriv_dv_#1_style_frac:nn } {##1}, style-frac-/ .cs_set:cp = { __deriv_dv_#1_style_frac_slash:nn } {##1}, scale-eval .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { eval } }, scale-eval-/ .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { eval_slash } }, scale-eval-! .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { eval_compact } }, scale-fun .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { fun } }, scale-var .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { var } }, scale-var-! .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { var_compact } }, scale-frac .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { frac } }, scale-frac-/ .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {dv_#1} {##1} { frac_slash } }, delims-eval .tl_set:c = { l__deriv_dv_#1_delims_eval_tl }, delims-eval-/ .tl_set:c = { l__deriv_dv_#1_delims_eval_slash_tl }, delims-eval-! .tl_set:c = { l__deriv_dv_#1_delims_eval_compact_tl }, delims-fun .tl_set:c = { l__deriv_dv_#1_delims_fun_tl }, delims-var .tl_set:c = { l__deriv_dv_#1_delims_var_tl }, delims-var-! .tl_set:c = { l__deriv_dv_#1_delims_var_compact_tl }, delims-frac .tl_set:c = { l__deriv_dv_#1_delims_frac_tl }, delims-frac-/ .tl_set:c = { l__deriv_dv_#1_delims_frac_slash_tl }, sep-inf-ord .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_inf_ord_tl } {##1} }, sep-inf-fun .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_inf_fun_tl } {##1} }, sep-ord-fun .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_ord_fun_tl } {##1} }, sep-frac-fun .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_frac_fun_tl } {##1} }, sep-inf-var .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_inf_var_tl } {##1} }, sep-var-ord .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_var_ord_tl } {##1} }, sep-var-inf .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_var_inf_tl } {##1} }, sep-ord-inf .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_ord_inf_tl } {##1} }, sep-ord-ord .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_ord_ord_tl } {##1} }, sep-ord-var .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_ord_var_tl } {##1} }, sep-var-var .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_var_var_tl } {##1} }, sep-eval-sb .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_eval_sb_tl } {##1} }, sep-eval-sp .code:n = { \__deriv_set_rubber_length:cn { l__deriv_dv_#1_sep_eval_sp_tl } {##1} }, switch-* .bool_set:c = { l__deriv_dv_#1_switch_star_bool }, switch-/ .bool_set:c = { l__deriv_dv_#1_switch_slash_bool }, switch-! .bool_set:c = { l__deriv_dv_#1_switch_compact_bool }, switch-sort .bool_set:c = { l__deriv_dv_#1_switch_sort_bool }, sort-method .code:n = { \__deriv_set_sort_method:nn {#1} {##1} }, sort-numerical .choices:nn = { auto, first, last, symbolic } { \tl_set:cn { l__deriv_dv_#1_sort_numerical_tl } {##1} }, sort-abs-reverse .bool_set:c = { l__deriv_dv_#1_sort_abs_reverse_bool }, sort-lexical-reverse .bool_set:c = { l__deriv_dv_#1_sort_lexical_reverse_bool }, sort-number-reverse .bool_set:c = { l__deriv_dv_#1_sort_number_reverse_bool }, sort-sign-reverse .bool_set:c = { l__deriv_dv_#1_sort_sign_reverse_bool }, sort-symbol-reverse .bool_set:c = { l__deriv_dv_#1_sort_symbol_reverse_bool }, fun .bool_set:c = { l__deriv_dv_#1_misc_fun_bool }, frac .bool_set:c = { l__deriv_dv_#1_misc_frac_bool }, var .clist_set:c = { l__deriv_dv_#1_misc_var_clist }, var .default:n = { all }, order .clist_set:c = { l__deriv_dv_#1_misc_order_clist }, ord .meta:n = { order={##1} }, mixed-order .tl_set:c = { l__deriv_dv_#1_misc_mixed_order_tl }, mixord .meta:n = { mixed-order={##1} }, unknown .code:n = { \bool_if:NT \l__deriv_first_unknown_key_bool { \clist_clear:c { l__deriv_dv_#1_misc_order_clist } \bool_set_false:N \l__deriv_first_unknown_key_bool } \exp_args:NnnV \tl_set_rescan:Nnn \l__deriv_tmpa_tl { } \l_keys_key_str \clist_put_right:cV { l__deriv_dv_#1_misc_order_clist } \l__deriv_tmpa_tl } } } %%%%%% Key-val: Differential %%%%%% % variant \cs_new:Npn \__deriv_i_define_keys:n #1 { \keys_define:nn { deriv/i/#1 } { style-inf .tl_set:c = { l__deriv_i_#1_style_inf_tl }, style-var .choices:nn = { single, multiple, mixed } { \__deriv_i_set_style_var:nnn {i_#1} {##1} { } }, style-var-* .choices:nn = { single, multiple, mixed } { \__deriv_i_set_style_var:nnn {i_#1} {##1} { _star } }, scale-var .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {i_#1} {##1} { var } }, scale-var-* .choices:nn = { auto, none, big, Big, bigg, Bigg } { \__deriv_set_scale:nnn {i_#1} {##1} { var_star } }, delims-var .tl_set:c = { l__deriv_i_#1_delims_var_tl }, delims-var-* .tl_set:c = { l__deriv_i_#1_delims_var_star_tl }, sep-begin .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_begin_tl } {##1} }, sep-inf-ord .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_inf_ord_tl } {##1} }, sep-inf-var .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_inf_var_tl } {##1} }, sep-ord-var .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_ord_var_tl } {##1} }, sep-var-inf .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_var_inf_tl } {##1} }, sep-var-var .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_var_var_tl } {##1} }, sep-ord-ord .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_ord_ord_tl } {##1} }, sep-end .code:n = { \__deriv_set_rubber_length:cn { l__deriv_i_#1_sep_end_tl } {##1} }, switch-* .bool_set:c = { l__deriv_i_#1_switch_star_bool }, var .clist_set:c = { l__deriv_i_#1_misc_var_clist }, var .default:n = {all}, order .clist_set:c = { l__deriv_i_#1_misc_order_clist }, ord .meta:n = { order={##1} }, unknown .code:n = { \bool_if:NT \l__deriv_first_unknown_key_bool { \clist_clear:c { l__deriv_i_#1_misc_order_clist } \bool_set_false:N \l__deriv_first_unknown_key_bool } \exp_args:NnnV \tl_set_rescan:Nnn \l__deriv_tmpa_tl { } \l_keys_key_str \clist_put_right:cV { l__deriv_i_#1_misc_order_clist } \l__deriv_tmpa_tl } } } % variant, value \cs_new:Npn \__deriv_set_sort_method:nn #1 #2 { \seq_clear:c { l__deriv_dv_#1_sort_method_seq } \seq_set_from_clist:Nn \l__deriv_tmpa_seq {#2} \seq_map_indexed_inline:Nn \l__deriv_tmpa_seq { \str_case:nn {##2} { { sign } { \seq_put_right:cn { l__deriv_dv_#1_sort_method_seq } { \__deriv_sort_sign:n } } { symbol } { \seq_put_right:cn { l__deriv_dv_#1_sort_method_seq } { \__deriv_sort_symbol:n } } { abs } { \seq_put_right:cn { l__deriv_dv_#1_sort_method_seq } { \__deriv_sort_abs:n } } { number } { \seq_put_right:cn { l__deriv_dv_#1_sort_method_seq } { \__deriv_sort_number:n } } { lexical } { \seq_put_right:cn { l__deriv_dv_#1_sort_method_seq } { \__deriv_sort_lexical:n } } } \int_compare:nNnT {##1} = { 3 } { \seq_map_break: } } } % variant, value, name \cs_new:Npn \__deriv_dv_set_style_var:nnn #1 #2 #3 { \exp_args:Nnc \tl_set:cn { l__deriv_#1_style_var#3_tl } { __deriv_dv_build_var_#2:NNNnn } } \cs_new:Npn \__deriv_i_set_style_var:nnn #1 #2 #3 { \exp_args:Nnc \tl_set:cn { l__deriv_#1_style_var#3_tl } { __deriv_i_build_var_#2:NNNnnn } } % dv_variant, scale, name \cs_new:Npn \__deriv_set_scale:nnn #1 #2 #3 { \str_case:nnF {#2} { { auto } { \tl_set:cn { l__deriv_#1_scale_#3_tl } { \__deriv_scale_auto:nnn } } { none } { \tl_set:cn { l__deriv_#1_scale_#3_tl } { \__deriv_scale_none:nnn } } } { \tl_set:cn { l__deriv_#1_scale_#3_tl } { \__deriv_scale_big:nnnn {#2} } } } % muskip, tl \cs_new:Npn \__deriv_set_rubber_length:Nn #1 #2 { \regex_match:NnTF \c__deriv_cs_numbers_regex {#2} { \str_case:nnF {#2} { { 0 } { \tl_clear:N #1 } { 0,0 } { \tl_clear:N #1 } { 0,0,0 } { \tl_clear:N #1 } } { \seq_set_split:Nnn \l__deriv_rubber_seq { , } {#2} \tl_set:Nf #1 { \seq_use:Nnnn \l__deriv_rubber_seq { mu plus } { mu plus } { mu minus } mu } \tl_put_left:Nn #1 { \mskip } } } { \tl_set:Nn #1 {#2} } } %%%%% Setting keys %%%%% \DeclareDocumentCommand{\derivset}{ m o } { \str_if_eq:nnTF {#1} { all } { \__deriv_set_default:nnn { all } {#2} { all } \keys_set:nn { deriv/all/all } { default } } { \tl_set:Nx \l__deriv_derivset_tl { \cs_to_str:N #1 } \deriv_set_keys:Vn \l__deriv_derivset_tl {#2} } } % dv, keyval \cs_new_protected:Npn \deriv_set_keys:nn #1 #2 { \seq_if_in:NnTF \l__deriv_dv_variant_seq {#1} { \__deriv_set_default:nnn {#1} {#2} { dv } } { \seq_if_in:NnTF \l__deriv_i_variant_seq {#1} { \__deriv_set_default:nnn {#1} {#2} { i } } { \msg_error:nnxx { deriv } { derivative-not-defined } { \token_to_str:N #1 } { \token_to_str:N \derivset } } } } % keyval, dv/i, variant \cs_new_protected:Npn \deriv_local_keys:nnn #1 #2 #3 { \bool_set_true:N \l__deriv_first_unknown_key_bool \tl_if_novalue:nTF {#1} { \bool_if:cT { l__deriv_#2_#3_local_keys_bool } { \keys_set:nn { deriv/#2/#3 } { default } \bool_set_false:c { l__deriv_#2_#3_local_keys_bool } } } { \bool_if:cTF { l__deriv_#2_#3_local_keys_bool } { \keys_set:nn { deriv/#2/#3 } { default, #1 } } { \keys_set:nn { deriv/#2/#3 } {#1} } \bool_set_true:c { l__deriv_#2_#3_local_keys_bool } } } %%%%% Declaring variants %%%%% % tl-dv, macro, inf, keyval, dv/i \cs_new_protected:Npn \deriv_preamble:NNnnn #1 #2 #3 #4 #5 { \tl_set:Nx #1 { \cs_to_str:N #2 } \tl_if_novalue:nTF {#4} { \__deriv_preamble_aux:Vnn #1 { style-inf={#3} } {#5} } { \__deriv_preamble_aux:Vnn #1 { style-inf={#3}, #4} {#5} } } % variant, key-value, dv/i \cs_new_protected:Npn \__deriv_preamble_aux:nnn #1 #2 #3 { \seq_if_in:cnF { l__deriv_#3_variant_seq } {#1} { \seq_put_left:cn { l__deriv_#3_variant_seq } {#1} \use:c { __deriv_#3_variables:n } {#1} \use:c { __deriv_#3_define_keys:n } {#1} } \prop_set_eq:cc { l__deriv_#3_#1_user_keys_prop } { c__deriv_#3_pkg_keys_prop } \__deriv_set_default:nnn {#1} {#2} {#3} } % data-type, variant, category, cs-var-list \cs_new:Npn \__deriv_new:nnnnn #1 #2 #3 #4 #5 { \seq_set_from_clist:Nn \l__deriv_new_var_seq {#5} \seq_map_inline:Nn \l__deriv_new_var_seq { \use:c { #1_new:c } { l__deriv_#2_#3_#4_##1_#1 } } } % variant \cs_new_protected:Npn \__deriv_dv_variables:n #1 { \__deriv_new:nnnnn { tl } { dv } {#1} { style } { inf_num, inf_den, var, var_compact, var_slash_compact, frac, frac_slash } \__deriv_new:nnnnn { tl } { dv } {#1} { scale } { eval, eval_slash, eval_compact, fun, var, var_compact, frac, frac_slash } \__deriv_new:nnnnn { tl } { dv } {#1} { delims } { eval, eval_slash, eval_comapct, fun, var, frac, frac_slash } \__deriv_new:nnnnn { tl } { dv } {#1} { sep } { inf_ord, inf_fun, ord_fun, frac_fun, inf_var, var_ord, var_inf, ord_inf, ord_ord, ord_var, var_var, eval_sb, eval_sp } \__deriv_new:nnnnn { bool } { dv } {#1} { switch } { star, slash, compact, sort } \__deriv_new:nnnnn { seq } { dv } {#1} { sort } { method } \__deriv_new:nnnnn { tl } { dv } {#1} { sort } { numerical } \__deriv_new:nnnnn { bool } { dv } {#1} { sort } { abs_reverse, sign_reverse, symbol_reverse, number_reverse, lexical_reverse } \__deriv_new:nnnnn { bool } { dv } {#1} { misc } { fun, frac } \__deriv_new:nnnnn { clist } { dv } {#1} { misc } { var } \__deriv_new:nnnnn { clist } { dv } {#1} { misc } { order } \__deriv_new:nnnnn { tl } { dv } {#1} { misc } { mixed_order } \__deriv_new:nnnnn { prop } { dv } {#1} { user } { keys } \__deriv_new:nnnnn { bool } { dv } {#1} { local } { keys } } % variant \cs_new_protected:Npn \__deriv_i_variables:n #1 { \__deriv_new:nnnnn { tl } { i } {#1} { style } { inf, var, var_star } \__deriv_new:nnnnn { tl } { i } {#1} { scale } { var, var_star } \__deriv_new:nnnnn { tl } { i } {#1} { delims } { var, var_star } \__deriv_new:nnnnn { tl } { i } {#1} { sep } { begin, inf_ord, inf_var, ord_var, var_inf, var_var, ord_ord, end } \__deriv_new:nnnnn { bool } { i } {#1} { switch } { star } \__deriv_new:nnnnn { bool } { i } {#1} { mics } { fun, var, frac } \__deriv_new:nnnnn { clist } { i } {#1} { misc } { order } \__deriv_new:nnnnn { prop } { i } {#1} { user } { keys } \__deriv_new:nnnnn { bool } { i } {#1} { local } { keys } } % variant, keyval, dv/i \cs_new_protected:Npn \__deriv_set_default:nnn #1 #2 #3 { \tl_if_novalue:nTF {#2} { \prop_set_eq:cc { l__deriv_#3_#1_user_keys_prop } { c__deriv_#3_pkg_keys_prop } } { \prop_put_from_keyval:cn { l__deriv_#3_#1_user_keys_prop } {#2} } \__deriv_set_default_auxi:cnn { l__deriv_#3_#1_user_keys_prop } {#1} {#3} \keys_set:nn { deriv/#3/#1 } { default } } % prop-key-val, variant, dv/i \cs_new_protected:Npn \__deriv_set_default_auxi:Nnn #1 #2 #3 { \__deriv_set_default_auxii:fnn { \prop_to_keyval:N #1 } {#2} {#3} } % key-val, variant, dv/i \cs_new_protected:Npn \__deriv_set_default_auxii:nnn #1 #2 #3 { \keys_define:nn { deriv/#3/#2 } { default .meta:n = {#1} } } % new/delare/renew/provide, variant, macro \cs_new_protected:Npn \deriv_dv_define:Nnn #1 #2 #3 { \exp_args:Nne #1 {#3}{ s o m t/ t! m !e{\char_generate:nn {`_}{8}^} } { \group_begin: \deriv_local_keys:nnn {##2} { dv } {#2} \exp_args:Nnc \bool_xor:nnTF {##5} { l__deriv_dv_#2_switch_compact_bool } { \exp_args:Nnc \bool_xor:nnTF {##4} { l__deriv_dv_#2_switch_slash_bool } { \__deriv_dv_slash_compact:nnnnn {dv_#2} {##3} {##6} {##7} {##8} } { \__deriv_dv_compact:nnnnn {dv_#2} {##3} {##6} {##7} {##8} } } { \exp_args:Nnc \bool_xor:nnTF {##4} { l__deriv_dv_#2_switch_slash_bool } { \exp_args:Nnc \bool_xor:nnTF {##1} { l__deriv_dv_#2_switch_star_bool } { \__deriv_dv_star_slash:nnnnn {dv_#2} {##3} {##6} {##7} {##8} } { \__deriv_dv_slash:nnnnn {dv_#2} {##3} {##6} {##7} {##8} } } { \exp_args:Nnc \bool_xor:nnTF {##1} { l__deriv_dv_#2_switch_star_bool } { \__deriv_dv_star:nnnnn {dv_#2} {##3} {##6} {##7} {##8} } { \__deriv_dv_none:nnnnn {dv_#2} {##3} {##6} {##7} {##8} } } } \group_end: } } % new/delare/renew/provide, variant, macro \cs_new_protected:Npn \deriv_i_define:Nnn #1 #2 #3 { #1 {#3}{ s o m } { \group_begin: \deriv_local_keys:nnn {##2} { i } {#2} \exp_args:Nnc \bool_xor:nnTF {##1} { l__deriv_i_#2_switch_star_bool } { \__deriv_inf_star:nn {i_#2} {##3} } { \__deriv_inf_none:nn {i_#2} {##3} } \group_end: } } %%%%% derivative definition %%%%% % variant, function, variable, sb-point, sp-point \cs_new_protected:Npn \__deriv_dv_star_slash:nnnnn #1 #2 #3 #4 #5 { \__deriv_dv_preparation:Nnnn \l__deriv_dv_denom_tl {#1} {#3} { _slash } \__deriv_evaluation_slash:nnnn {#1} {#4} {#5} { \__deriv_fraction_slash:nn {#1} { \use:c { __deriv_#1_style_frac_slash:nn } { \__deriv_dv_numerator_nofun:n {#1} } { \__deriv_dv_denominator:n {#1} } } \__deriv_insert_fun:nnn {#1} {#2} { frac_fun } } } % variant, function, variable, sb-point, sp-point \cs_new_protected:Npn \__deriv_dv_star:nnnnn #1 #2 #3 #4 #5 { \__deriv_dv_preparation:Nnnn \l__deriv_dv_denom_tl {#1} {#3} { } \__deriv_evaluation:nnnn {#1} {#4} {#5} { \__deriv_fraction:nn {#1} { \use:c { __deriv_#1_style_frac:nn } { \__deriv_dv_numerator_nofun:n {#1} } { \__deriv_dv_denominator:n {#1} } } \__deriv_insert_fun:nnn {#1} {#2} { frac_fun } } } % variant, function, variable, sb-point, sp-point \cs_new_protected:Npn \__deriv_dv_slash:nnnnn #1 #2 #3 #4 #5 { \__deriv_dv_preparation:Nnnn \l__deriv_dv_denom_tl {#1} {#3} { _slash } \__deriv_evaluation_slash:nnnn {#1} {#4} {#5} { \__deriv_fraction_slash:nn {#1} { \use:c { __deriv_#1_style_frac_slash:nn } { \__deriv_dv_numerator_fun:nn {#1} {#2} } { \__deriv_dv_denominator:n {#1} } } } } % variant, function, variable, sb-point, sp-point \cs_new_protected:Npn \__deriv_dv_none:nnnnn #1 #2 #3 #4 #5 { \__deriv_dv_preparation:Nnnn \l__deriv_dv_denom_tl {#1} {#3} { } \__deriv_evaluation:nnnn {#1} {#4} {#5} { \__deriv_fraction:nn {#1} { \use:c { __deriv_#1_style_frac:nn } { \__deriv_dv_numerator_fun:nn {#1} {#2} } { \__deriv_dv_denominator:n {#1} } } } } % variant, function, variable, sb-point, sp-point \cs_new_protected:Npn \__deriv_dv_compact:nnnnn #1 #2 #3 #4 #5 { \__deriv_i_preparation:Nnnnn \l__deriv_dv_denom_tl {#1} {#3} { _compact } { _num } \__deriv_evaluation_compact:nnnn {#1} {#4} {#5} { \tl_use:N \l__deriv_dv_denom_tl \__deriv_insert_fun:nnn {#1} {#2} { inf_fun } } } % variant, function, variable, sb-point, sp-point \cs_new_protected:Npn \__deriv_dv_slash_compact:nnnnn #1 #2 #3 #4 #5 { \__deriv_i_preparation:Nnnnn \l__deriv_dv_denom_tl {#1} {#3} { _slash_compact } { _num } \__deriv_evaluation_compact:nnnn {#1} {#4} {#5} { %\__deriv_i_print:Nn \l__deriv_i_denom_tl {#1} \tl_use:N \l__deriv_dv_denom_tl \__deriv_insert_fun:nnn {#1} {#2} { inf_fun } } } % variant, function \cs_new_protected:Npn \__deriv_dv_numerator_fun:nn #1 #2 { \__deriv_insert_numinf:n {#1} \__deriv_show_order:cTF { l__deriv_#1_misc_mixed_order_tl } { \__deriv_insert_ord:cnn { l__deriv_#1_misc_mixed_order_tl } {#1} { inf_ord } \__deriv_insert_fun:nnn {#1} {#2} { ord_fun } } { \__deriv_insert_fun:nnn {#1} {#2} { inf_fun } } } % variant \cs_new_protected:Npn \__deriv_dv_numerator_nofun:n #1 { \__deriv_insert_numinf:n {#1} \__deriv_show_order:cT { l__deriv_#1_misc_mixed_order_tl } { \__deriv_insert_ord:cnn { l__deriv_#1_misc_mixed_order_tl } {#1} { inf_ord } } } % dv \cs_new_protected:Npn \__deriv_dv_denominator:n #1 { \tl_use:N \l__deriv_dv_denom_tl } % denom-tl, variant, variable, if star \cs_new_protected:Npn \__deriv_dv_preparation:Nnnn #1 #2 #3 #4 { \tl_clear:N #1 \seq_set_from_clist:Nn \l__deriv_dv_var_seq {#3} \seq_set_from_clist:Nc \l__deriv_dv_order_seq { l__deriv_#2_misc_order_clist } \tl_use:c { l__deriv_#2_style_var#4_tl } \l__deriv_dv_var_seq \l__deriv_dv_order_seq #1 {#2} {#4} % Legacy development code from when `style-var-/` was not available %\tl_if_eq:nnTF {#4} { _slash } %TODO: Find a better solution %{ \tl_use:c { l__deriv_#2_style_var_tl } \l__deriv_dv_var_seq \l__deriv_dv_order_seq #1 {#2} {#4} } %{ \tl_use:c { l__deriv_#2_style_var#4_tl } \l__deriv_dv_var_seq \l__deriv_dv_order_seq #1 {#2} {#4} } } % var_seq, order_seq, denom-tl, variant, if star \cs_new_protected:Npn \__deriv_dv_build_var_multiple:NNNnn #1 #2 #3 #4 #5 { \int_set:Nn \l__deriv_var_count_int { \seq_count:N #1 } \__deriv_adjust_ord_seq:NN \l__deriv_var_count_int #2 \str_if_eq:cNT { l__deriv_#4_misc_mixed_order_tl } 1 { \__deriv_mixed_order:cNn { l__deriv_#4_misc_mixed_order_tl } #2 {#4} } \__deriv_var_bool_seq:cNN { l__deriv_#4_misc_var_clist } \l__deriv_tmpa_seq \l__deriv_var_count_int \seq_map_indexed_inline:Nn #1 { \seq_pop_left:NN #2 \l__deriv_tmpa_tl \seq_pop_left:NN \l__deriv_tmpa_seq \l__deriv_tmpb_tl \tl_put_right:Nx #3 { \__deriv_insert_deninf:n {#4} \__deriv_insert_mskip:nn {#4} { inf_var } \__deriv_insert_var:Nnn \l__deriv_tmpb_tl {##2} {#4} \__deriv_show_order:NTF \l__deriv_tmpa_tl { \__deriv_insert_ord:Nnn \l__deriv_tmpa_tl {#4} { var_ord } \int_compare:nNnF {##1} = { \l__deriv_var_count_int } { \__deriv_insert_mskip:nn {#4} { ord_inf } } } { \int_compare:nNnF {##1} = { \l__deriv_var_count_int } { \__deriv_insert_mskip:nn {#4} { var_inf } } } } } } % var_seq, order_seq, denom-tl, variant, if star \cs_new_protected:Npn \__deriv_dv_build_var_single:NNNnn #1 #2 #3 #4 #5 { \int_set:Nn \l__deriv_var_count_int { \seq_count:N #1 } \tl_set:Nf \l__deriv_tmpa_tl { \seq_use:Nn #1 { \__deriv_insert_mskip:nn {#4} { var_var } } } \__deriv_var_bool_seq:cNN { l__deriv_#4_misc_var_clist } \l__deriv_tmpa_seq \l__deriv_var_count_int \int_set:Nn \l__deriv_tmpa_int { \seq_count:N #2 } % Temporary store the order argument \tl_set:Nf \l__deriv_tmpb_tl { \seq_use:Nn #2 { \__deriv_insert_mskip:nn {#4} { ord_ord } } } \seq_pop_left:NN \l__deriv_tmpa_seq \l__deriv_tmpc_tl \tl_put_right:Nx #3 { \__deriv_insert_deninf:n {#4} \__deriv_insert_mskip:nn {#4} { inf_var } \__deriv_insert_var:NVn \l__deriv_tmpc_tl \l__deriv_tmpa_tl {#4} \__deriv_show_order:NT \l__deriv_tmpb_tl { \__deriv_insert_ord:Nnn \l__deriv_tmpb_tl {#4} { var_ord } } } \str_if_eq:cNT { l__deriv_#4_misc_mixed_order_tl } 1 { \tl_set_eq:cN { l__deriv_#4_misc_mixed_order_tl } \l__deriv_tmpb_tl } } % var_seq, order_seq \cs_new_protected:Npn \__deriv_adjust_ord_seq:NN #1 #2 { \int_set:Nn \l__deriv_vmo_int { #1 - \seq_count:N #2 } \int_compare:nNnF { \l__deriv_vmo_int } = { 0 } { \int_compare:nNnTF { \l__deriv_vmo_int } < { 0 } { \int_step_inline:nn { -1*\l__deriv_vmo_int } { \seq_pop_right:NN #2 \l__deriv_tmpa_tl } } { \int_step_inline:nn { \l__deriv_vmo_int } { \seq_put_right:Nn #2 { 1 } } } } } % avd-clist, bool-seq, count \cs_new_protected:Npn \__deriv_var_bool_seq:NNN #1 #2 #3 { \seq_clear:N #2 \clist_if_in:NnTF #1 { all } { \exp_args:NNf \seq_set_from_clist:Nn #2 { \prg_replicate:nn {#3} { \c_true_bool , } } } { \clist_if_in:NnTF #1 { none } { \exp_args:NNf \seq_set_from_clist:Nn #2 { \prg_replicate:nn {#3} { \c_false_bool , } } } { \int_step_inline:nn {#3} { \clist_if_in:NnTF #1 {##1} { \seq_put_right:Nn #2 { \c_true_bool } } { \seq_put_right:Nn #2 { \c_false_bool } } } } } } % ord-seq, var-seq \cs_new_protected:Npn \__deriv_adjust_trailing_ord:NN #1 #2 { \int_set:Nn \l__deriv_vmo_int { \seq_count:N #2 - \seq_count:N #1 } \int_compare:nNnT { \l__deriv_vmo_int } < { 0 } { \int_step_inline:nn { -1*\l__deriv_vmo_int } { \seq_pop_right:NN #1 \l__deriv_tmpa_tl } } \int_step_inline:nn { \seq_count:N #1 } { \seq_pop_right:NN #1 \l__deriv_tmpa_tl \str_if_eq:VnF \l__deriv_tmpa_tl { 1 } { \seq_put_right:NV #1 \l__deriv_tmpa_tl \prg_break: } } } %%%%% infinisimal definition %%%%% % variant, variable \cs_new:Npn \__deriv_inf_none:nn #1 #2 { \__deriv_i_preparation:Nnnnn \l__deriv_i_denom_tl {#1} {#2} { } { } \__deriv_i_print:Nn \l__deriv_i_denom_tl {#1} } % variant, variable \cs_new:Npn \__deriv_inf_star:nn #1 #2 { \__deriv_i_preparation:Nnnnn \l__deriv_i_denom_tl {#1} {#2} { _star } { } \__deriv_i_print:Nn \l__deriv_i_denom_tl {#1} } % print-tl, variant \cs_new:Npn \__deriv_i_print:Nn #1 #2 { \__deriv_insert_mskip:nn {#2} { begin } \tl_use:N #1 \__deriv_insert_mskip:nn {#2} { end } } % print-tl, variant, variable, if star, inf_variant \cs_new_protected:Npn \__deriv_i_preparation:Nnnnn #1 #2 #3 #4 #5 { \tl_clear:N #1 \seq_set_from_clist:Nn \l__deriv_i_var_seq {#3} \seq_set_from_clist:Nc \l__deriv_i_order_seq { l__deriv_#2_misc_order_clist } \tl_if_eq:nnTF {#4} { _slash_compact } %TODO: Find a better solution { \tl_use:c { l__deriv_#2_style_var#4_tl } \l__deriv_i_var_seq \l__deriv_i_order_seq #1 {#2} { _compact } {#5} } { \tl_use:c { l__deriv_#2_style_var#4_tl } \l__deriv_i_var_seq \l__deriv_i_order_seq #1 {#2} {#4} {#5} } %\tl_use:c { l__deriv_#2_style_var#4_tl } \l__deriv_i_var_seq \l__deriv_i_order_seq #1 {#2} {#4} {#5} } % var-seq, order-seq, print-tl, variant, if star, inf_variant \cs_new_protected:Npn \__deriv_i_build_var_single:NNNnnn #1 #2 #3 #4 #5 #6 { \int_set:Nn \l__deriv_var_count_int { \seq_count:N #1 } \__deriv_var_bool_seq:cNN { l__deriv_#4_misc_var_clist } \l__deriv_add_var_bool_seq \l__deriv_var_count_int \__deriv_adjust_trailing_ord:NN #2 #1 \int_set:Nn \l__deriv_tmpa_int { \seq_count:N #2 } \seq_map_indexed_inline:Nn #1 { \seq_pop_left:NN \l__deriv_add_var_bool_seq \l__deriv_tmpa_tl \tl_put_right:Nx \l__deriv_tmpb_tl { \__deriv_insert_var:Nnnn \l__deriv_tmpa_tl {##2} {#4} {#5} \int_compare:nNnF {##1} = { \l__deriv_var_count_int } { \__deriv_insert_mskip:nn {#4} { var_var } } } } \seq_map_indexed_inline:Nn #2 { \tl_put_right:Nx \l__deriv_tmpc_tl { \exp_not:n {##2} \int_compare:nNnF {##1} = { \l__deriv_tmpa_int } { \__deriv_insert_mskip:nn {#4} { ord_ord } } } } \tl_put_right:Nx #3 { \__deriv_insert_inf:nn {#4} {#6} \sb { \__deriv_insert_mskip:nn {#4} { inf_var } \exp_not:V \l__deriv_tmpb_tl } \tl_if_blank:VF \l__deriv_tmpc_tl { \sp { \__deriv_insert_mskip:nn {#4} { inf_ord } \exp_not:V \l__deriv_tmpc_tl } } } } % var-seq, order-seq, print-tl, variant, if star, inf_variant \cs_new_protected:Npn \__deriv_i_build_var_multiple:NNNnnn #1 #2 #3 #4 #5 #6 { \int_set:Nn \l__deriv_var_count_int { \seq_count:N #1 } \__deriv_var_bool_seq:cNN { l__deriv_#4_misc_var_clist } \l__deriv_add_var_bool_seq \l__deriv_var_count_int \__deriv_adjust_ord_seq:NN \l__deriv_var_count_int #2 \seq_map_indexed_inline:Nn #1 { \seq_pop_left:NN #2 \l__deriv_tmpa_tl \seq_pop_left:NN \l__deriv_add_var_bool_seq \l__deriv_tmpb_tl \tl_put_right:Nx #3 { \__deriv_insert_inf:nn {#4} {#6} \__deriv_show_order:NTF \l__deriv_tmpa_tl { \__deriv_insert_ord:Nnn \l__deriv_tmpa_tl {#4} { inf_ord } \__deriv_insert_mskip:nn {#4} { ord_var } } { \__deriv_insert_mskip:nn {#4} { inf_var } } \__deriv_insert_var:Nnnn \l__deriv_tmpb_tl {##2} {#4} {#5} \int_compare:nNnF {##1} = { \l__deriv_var_count_int } { \__deriv_insert_mskip:nn {#4} { var_inf } } } } } % var-seq, order-seq, print-tl, variant, if star, inf_variant \cs_new_protected:Npn \__deriv_i_build_var_mixed:NNNnnn #1 #2 #3 #4 #5 #6 { \int_set:Nn \l__deriv_var_count_int { \seq_count:N #1 } \__deriv_var_bool_seq:cNN { l__deriv_#4_misc_var_clist } \l__deriv_add_var_bool_seq \l__deriv_var_count_int \__deriv_adjust_ord_seq:NN \l__deriv_var_count_int #2 \seq_map_indexed_inline:Nn #1 { \seq_pop_left:NN #2 \l__deriv_tmpa_tl \seq_pop_left:NN \l__deriv_add_var_bool_seq \l__deriv_tmpb_tl \tl_put_right:Nx #3 { \__deriv_insert_inf:nn {#4} {#6} \__deriv_show_order:NT \l__deriv_tmpa_tl { \__deriv_insert_ord:Nnn \l__deriv_tmpa_tl {#4} { inf_ord } } \sb { \__deriv_insert_mskip:nn {#4} { inf_var } \__deriv_insert_var:Nnnn \l__deriv_tmpb_tl {##2} {#4} {#5} } \int_compare:nNnF {##1} = { \l__deriv_var_count_int } { \__deriv_insert_mskip:nn {#4} { var_inf } } } } } %%%%% And the rest of the code %%%%% % variant \cs_new:Npn \__deriv_insert_numinf:n #1 { \__deriv_insert_inf:nn {#1} { _num } } % variant \cs_new:Npn \__deriv_insert_deninf:n #1 { \__deriv_insert_inf:nn {#1} { _den } } % variant, name \cs_new:Npn \__deriv_insert_inf:nn #1 #2 { \exp_not:v { l__deriv_#1_style_inf#2_tl } } % dv, function, muskip \cs_new:Npn \__deriv_insert_fun:nnn #1 #2 #3 { \tl_if_blank:nF {#2} { \__deriv_insert_mskip:nn {#1} {#3} \bool_if:cTF { l__deriv_#1_misc_fun_bool } { \__deriv_add_delims:nnn {#1} { fun } {#2} } {#2} } } % if delim, variable, variant, if star \cs_new:Npn \__deriv_insert_var:Nnnn #1 #2 #3 #4 { \bool_if:NTF #1 { \__deriv_add_delims:nnn {#3} { var#4 } {#2} } { \__deriv_handle_double_sp:n {#2} } } % if delim, variable, variant \cs_new:Npn \__deriv_insert_var:Nnn #1 #2 #3 { \bool_if:NTF #1 { \__deriv_add_delims:nnn {#3} { var } {#2} } { \__deriv_handle_double_sp:n {#2} } } % order, variant, name \cs_new:Npn \__deriv_insert_ord:Nnn #1 #2 #3 { \sp { \__deriv_insert_mskip:nn {#2} {#3} \exp_not:V #1 } } % dv, name \cs_new:Npn \__deriv_insert_mskip:nn #1 #2 { \exp_not:v { l__deriv_#1_sep_#2_tl } } %%%%% Scale, delimiters, evaluation %%%%% % variable \cs_new:Npn \__deriv_handle_double_sp:n #1 { \str_case_e:nnF { ^ } { { \tl_item:nn {#1} { -2 } } { \exp_not:n { {#1} } } { \tl_item:nn {#1} { -4 } } { \exp_not:n { {#1} } } } { \exp_not:n {#1} } } % dv, code-for-fraction \cs_new:Npn \__deriv_fraction:nn #1 #2 { \bool_if:cTF { l__deriv_#1_misc_frac_bool } { \__deriv_add_delims:nnn {#1} { frac } {#2} } {#2} } % dv, code-for-fraction \cs_new:Npn \__deriv_fraction_slash:nn #1 #2 { \bool_if:cTF { l__deriv_#1_misc_frac_bool } { \__deriv_add_delims:nnn {#1} { frac_slash } {#2} } {#2} } % dv, sub, sup, code-for-fraction \cs_new:Npn \__deriv_evaluation:nnnn #1 #2 #3 #4 { \__deriv_if_value:nTF {#2} { \__deriv_add_delims:nnn {#1} { eval } {#4} \sb{ \__deriv_insert_mskip:nn {#1} { eval_sb } #2 } \__deriv_if_value:nT {#3} { \sp{ \__deriv_insert_mskip:nn {#1} { eval_sp } #3 } } } { \__deriv_if_value:nTF {#3} { \__deriv_add_delims:nnn {#1} { eval } {#4} \sp{ \__deriv_insert_mskip:nn {#1} { eval_sp } #3 } } {#4} } } % dv, sub, sup, code-for-fraction \cs_new:Npn \__deriv_evaluation_slash:nnnn #1 #2 #3 #4 { \__deriv_if_value:nTF {#2} { \__deriv_add_delims:nnn {#1} { eval_slash } {#4} \sb{ \__deriv_insert_mskip:nn {#1} { eval_sb } #2 } \__deriv_if_value:nT {#3} { \sp{ \__deriv_insert_mskip:nn {#1} { eval_sp } #3 } } } { \__deriv_if_value:nTF {#3} { \__deriv_add_delims:nnn {#1} { eval_slash } {#4} \sp{ \__deriv_insert_mskip:nn {#1} { eval_sp } #3 } } {#4} } } % dv, sub, sup, code-for-fraction \cs_new:Npn \__deriv_evaluation_compact:nnnn #1 #2 #3 #4 { \__deriv_if_value:nTF {#2} { \__deriv_add_delims:nnn {#1} { eval_compact } {#4} \sb{ \__deriv_insert_mskip:nn {#1} { eval_sb } #2 } \__deriv_if_value:nT {#3} { \sp{ \__deriv_insert_mskip:nn {#1} { eval_sp } #3 } } } { \__deriv_if_value:nTF {#3} { \__deriv_add_delims:nnn {#1} { eval_compact } {#4} \sp{ \__deriv_insert_mskip:nn {#1} { eval_sp } #3 } } {#4} } } % dv, name, value \cs_new:Npn \__deriv_add_delims:nnn #1 #2 #3 { \tl_use:c { l__deriv_#1_scale_#2_tl } {#1} {#2} {#3} } % dv, name, code \cs_new:Npn \__deriv_scale_auto:nnn #1 #2 #3 { \__deriv_auto_left:n \tl_item:cn { l__deriv_#1_delims_#2_tl } { 1 } #3 \__deriv_auto_right:n \tl_item:cn { l__deriv_#1_delims_#2_tl } { 2 } } % dv, name, code \cs_new:Npn \__deriv_scale_none:nnn #1 #2 #3 { \__deriv_dont_use_dot:x { \tl_item:cn { l__deriv_#1_delims_#2_tl } { 1 } } #3 \__deriv_dont_use_dot:x { \tl_item:cn { l__deriv_#1_delims_#2_tl } { 2 } } } % item \cs_new:Npn \__deriv_dont_use_dot:n #1 { \str_if_eq:nnF {#1} { . } {#1} } % dv, name, code \cs_new:Npn \__deriv_scale_big:nnnn #1 #2 #3 #4 { \__deriv_scale_big_auxi:ncn {#1} { l__deriv_#2_delims_#3_tl } {#4} } % scaling, delims, code \cs_new:Npn \__deriv_scale_big_auxi:nNn #1 #2 #3 { \tl_use:c { #1 l } { \tl_item:Nn #2 { 1 } } #3 \tl_use:c { #1 r } { \tl_item:Nn #2 { 2 } } } %%%%% Calculation of mixed order %%%%% % mixed-order-tl, order-seq, variant \cs_new:Npn \__deriv_mixed_order:NNn #1 #2 #3 { \__deriv_replace:NN \l__deriv_input_seq #2 \__deriv_seq_counting:NNNn \l__deriv_symbol_seq \l__deriv_number_seq \l__deriv_input_seq {#3} \__deriv_sort:NNNn \l__deriv_permutation_seq \l__deriv_symbol_seq \l__deriv_number_seq {#3} \__deriv_combine_seq:NNNNn \l__deriv_sorted_seq \l__deriv_permutation_seq \l__deriv_symbol_seq \l__deriv_number_seq {#3} \__deriv_output:NNNn #1 \l__deriv_sorted_seq \l__deriv_numerical_tl {#3} } % input-seq, order-seq \cs_new_protected:Npn \__deriv_replace:NN #1 #2 { \tl_set:Nf \l__deriv_input_tl { \seq_use:Nn #2 { , } } \tl_remove_all:Nn \l__deriv_input_tl { ~ } \tl_replace_all:Nnn \l__deriv_input_tl { -- } { , } \tl_replace_all:Nnn \l__deriv_input_tl { - } { ,- } \tl_replace_all:Nnn \l__deriv_input_tl { + } { , } \seq_set_split:NnV #1 { , } \l__deriv_input_tl \seq_remove_all:Nn #1 {} } % symbol-seq, number-seq, input-seq \cs_new_protected:Npn \__deriv_seq_counting:NNNn #1 #2 #3 #4 { \__deriv_seq_counting:NNNNNNNn #1 #2 #3 \l__deriv_sym_tmpa_seq \l__deriv_sym_tmpb_seq \l__deriv_num_tmpa_seq \l__deriv_num_tmpb_seq {#4} } \cs_new_protected:Npn \__deriv_seq_counting:NNNNNNNn #1 #2 #3 #4 #5 #6 #7 #8 { \seq_clear:N #1 \seq_clear:N #2 \seq_clear:N #4 \seq_clear:N #5 \seq_clear:N #6 \seq_clear:N #7 \tl_clear:N \l__deriv_numerical_tl \seq_map_inline:Nn #3 { \str_if_in:nnTF {##1} / { \__deriv_extract_frac:NNNNw \l__deriv_sym_tmpa_tl \l__deriv_sym_tmpb_tl \l__deriv_num_tmpa_tl \l__deriv_num_tmpb_tl ##1 \q_stop } { \__deriv_extract:NNn \l__deriv_sym_tmpa_tl \l__deriv_num_tmpa_tl {##1} \tl_clear:N \l__deriv_sym_tmpb_tl \tl_set:Nn \l__deriv_num_tmpb_tl { 1 } } \__deriv_if_in_two_seq:NNNNTF #4 #5 \l__deriv_sym_tmpa_tl \l__deriv_sym_tmpb_tl { \__deriv_update_seq:NNNNV #6 #7 \l__deriv_num_tmpa_tl \l__deriv_num_tmpb_tl \l__deriv_seq_pos_int } { \__deriv_add_to_seq:NNVV #4 #6 \l__deriv_sym_tmpa_tl \l__deriv_num_tmpa_tl \__deriv_add_to_seq:NNVV #5 #7 \l__deriv_sym_tmpb_tl \l__deriv_num_tmpb_tl } } \__deriv_combine_frac:NNNNNNn #1 #2 #4 #5 #6 #7 {#8} } % sym-tl, num-tl, seq-item \cs_new_protected:Npn \__deriv_extract:NNn #1 #2 #3 { \int_zero:N \l__deriv_tmpa_int \tl_map_inline:nn {#3} { \tl_if_in:NnTF \c__deriv_digits_tl {##1} { \int_incr:N \l__deriv_tmpa_int } { \tl_map_break: } } \tl_set:Nx #2 { \tl_range:nnn {#3} { 1 } \l__deriv_tmpa_int } \int_incr:N \l__deriv_tmpa_int \tl_set:Nx #1 { \tl_range:nnn {#3} \l__deriv_tmpa_int { -1 } } \exp_args:NV \str_case:nn #2 { { } { \tl_set:Nn #2 { 1 } } { - } { \tl_set:Nn #2 { -1 } } } } \cs_new_protected:Npn \__deriv_extract_frac:NNNNw #1 #2 #3 #4 #5 / #6 \q_stop { %TODO: Strip parentheses from denominator (second line) to allow input like '1/(2m)' and would be similar to writing '1/2m'. % However, terms like '1/(m+n)' and '1/(2m+n)' are different and the latter must not be interpreted as '1/(2m+2n)' % Currently '1/2m' is being interpreted as '1/(2m)' but technically 'm/2' is the correct way. And should ideally be changed - but not a must right now. %TODO: Make code to handle the case '(m+n)/xxx' as input correctly with a loop i.e. as 'm/xxx + m/xxx'. Likely has to be done in \deriv_input:nn \__deriv_extract:NNn #1 #3 {#5} %TODO: Temporary solution to: Strip pearentheses from denominator \str_if_in:nnTF {#6} ( { \str_if_in:nnTF {#6} ) { \__deriv_extract_parenthesis:NNw #2 #4 #6 \q_stop } { \__deriv_extract:NNn #2 #4 {#6} } } { \__deriv_extract:NNn #2 #4 {#6} } \tl_if_eq:NNT #1 #2 { \tl_clear:N #1 \tl_clear:N #2 } } \cs_new_protected:Npn \__deriv_extract_parenthesis:NNw #1 #2 ( #3 ) \q_stop { \__deriv_extract:NNn #1 #2 {#3} } \cs_new:Npn \__deriv_combine_frac:NNNNNNn #1 #2 #3 #4 #5 #6 #7 { \int_step_inline:nn { \seq_count:N #3 } { \tl_set:Nx \l__deriv_tmpa_tl { \seq_item:Nn #3 {##1} } \tl_set:Nx \l__deriv_tmpb_tl { \seq_item:Nn #4 {##1} } \int_set:Nn \l__deriv_tmpa_int { \seq_item:Nn #5 {##1} } \int_set:Nn \l__deriv_tmpb_int { \seq_item:Nn #6 {##1} } \int_compare:nNnF \l__deriv_tmpa_int = 0 { \__deriv_adjust_frac_integers:NN \l__deriv_tmpa_int \l__deriv_tmpb_int \__deriv_add_frac_to_seq:NNVVVVn #1 #2 \l__deriv_tmpa_tl \l__deriv_tmpb_tl \l__deriv_tmpa_int \l__deriv_tmpb_int {#7} } } } \cs_new:Npn \__deriv_adjust_frac_integers:NN #1 #2 { \int_compare:nNnTF #1 = #2 { \int_set:Nn #1 { 1 } \int_set:Nn #2 { 1 } } { \int_compare:nNnT \l__deriv_tmpb_int < 0 { \int_set:Nn #1 { -1*#1 } \int_set:Nn #2 { -1*#2 } } \deriv_gcd:NN #1 #2 } } % sym-tl, num-tl \cs_new_protected:Npn \__deriv_add_frac_to_seq:NNnnnnn #1 #2 #3 #4 #5 #6 #7 { \tl_if_empty:nTF {#3} { \tl_if_empty:nTF {#4} { \str_if_eq:vnTF { l__deriv_#7_sort_numerical_tl } { symbolic } { \int_compare:nNnTF {#6} = 1 { \__deriv_add_to_seq:NNnn #1 #2 { } {#5} } { \__deriv_add_to_seq:NNnn #1 #2 { /#6 } {#5} } } { \int_compare:nNnTF {#6} = 1 { \tl_set:Nn \l__deriv_numerical_tl {#5} } { \tl_set:Nn \l__deriv_numerical_tl { #5/#6 } } } } { \int_compare:nNnTF {#6} = 1 { \__deriv_add_to_seq:NNnn #1 #2 { /#4 } {#5} } { \__deriv_add_to_seq:NNnn #1 #2 { /(#6#4) } {#5} } } } { \tl_if_empty:nTF {#4} { \int_compare:nNnTF {#6} = 1 { \__deriv_add_to_seq:NNnn #1 #2 {#3} {#5} } { \__deriv_add_to_seq:NNnn #1 #2 { #3/#6 } {#5} } } { \int_compare:nNnTF {#6} = 1 { \__deriv_add_to_seq:NNnn #1 #2 { #3/#4 } {#5} } { \__deriv_add_to_seq:NNnn #1 #2 { #3/(#6#4) } {#5} } } } } % sym-tl, num-tl \cs_new_protected:Npn \__deriv_add_to_seq:NNnn #1 #2 #3 #4 { \seq_put_right:Nn #1 {#3} \seq_put_right:Nn #2 {#4} } % sym-tl, num-tl \cs_new_protected:Npn \__deriv_update_seq:NNnn #1 #2 #3 #4 { \seq_map_indexed_inline:Nn #1 { \tl_if_eq:nnT {#3} {##2} { \exp_args:NNnx \seq_set_item:Nnn #2 {##1} { \int_eval:n { \seq_item:Nn #2 {##1} + #4 } } \seq_map_break: } } } \cs_new_protected:Npn \__deriv_find_in_seq:NNn #1 #2 #3 { \int_zero:N #2 \seq_map_indexed_inline:Nn #1 { \tl_if_eq:nnT {#3} {##2} { \seq_map_break:n { \int_set:Nn #2 {##1} } } } } \cs_set_eq:NN \__deriv_update_seq:Nnn \seq_set_item:Nnn \cs_generate_variant:Nn \__deriv_update_seq:Nnn { NVV } \cs_new_protected:Npn \__deriv_update_seq:NNNNn #1 #2 #3 #4 #5 { \__deriv_addfrac:NNVVxxn #1 #2 #3 #4 { \seq_item:Nn #1 {#5} } { \seq_item:Nn #2 {#5} } {#5} } \cs_new:Npn \__deriv_addfrac:NNnnnnn #1 #2 #3 #4 #5 #6 #7 { \exp_args:NNnx \seq_set_item:Nnn #1 {#7} { \int_eval:n { #3*#6 + #4*#5 } } \exp_args:NNnx \seq_set_item:Nnn #2 {#7} { \int_eval:n { #4*#6 } } } % sorted-seq, permutation-seq, symbol-seq, number-seq, variant \cs_new:Npn \__deriv_combine_seq:NNNNn #1 #2 #3 #4 #5 { \seq_clear:N #1 \seq_map_inline:Nn #2 { \tl_set:Nx \l__deriv_sym_tmpa_tl { \seq_item:Nn #3 {##1} } \tl_set:Nx \l__deriv_num_tmpa_tl { \seq_item:Nn #4 {##1} } \__deriv_eval_term:NVVn #1 \l__deriv_sym_tmpa_tl \l__deriv_num_tmpa_tl {#5} } } % sorted-seq, sym-tl, num-tl, variant \cs_new_protected:Npn \__deriv_eval_term:Nnnn #1 #2 #3 #4 { \tl_if_empty:nTF {#2} { \seq_put_right:Nn #1 {#3} } { \tl_if_head_eq_charcode:nNTF {#2} / { \seq_put_right:Nn #1 {#3#2} } { \int_compare:nNnTF {#3} = { 1 } { \seq_put_right:Nn #1 {#2} } { \int_compare:nNnTF {#3} = { 0 } { \prg_do_nothing: } { \int_compare:nNnTF {#3} = { -1 } { \seq_put_right:Nn #1 { -#2 } } { \seq_put_right:Nn #1 {#3#2} } } } } } } % permutation-seq, symbol-seq, number-seq, variant \cs_new_protected:Npn \__deriv_sort:NNNn #1 #2 #3 #4 { \seq_clear:N #1 \int_step_inline:nn { \seq_count:N #2 } { \seq_put_right:Nn #1 {##1} } \bool_if:cT { l__deriv_#4_switch_sort_bool } { \int_set:Nn \l__deriv_sort_max_int { \seq_count:c { l__deriv_#4_sort_method_seq } } \seq_sort:Nn #1 { \tl_set:Nx \l__deriv_sym_tmpa_tl { \seq_item:Nn #2 {##1} } \tl_set:Nx \l__deriv_sym_tmpb_tl { \seq_item:Nn #2 {##2} } \tl_set:Nx \l__deriv_num_tmpa_tl { \seq_item:Nn #3 {##1} } \tl_set:Nx \l__deriv_num_tmpb_tl { \seq_item:Nn #3 {##2} } \__deriv_sort_method:cn { l__deriv_#4_sort_method_seq } {#4} } } } % method-seq, dv \cs_new_protected:Npn \__deriv_sort_method:Nn #1 #2 { \seq_map_indexed_inline:Nn #1 { ##2 {#2} \int_compare:nNnT {##1} = { \l__deriv_sort_max_int } { \seq_map_break:n { \sort_return_same: } } } } % dv \cs_new_protected:Npn \__deriv_sort_sign:n #1 { \tl_if_head_eq_charcode:VNTF \l__deriv_num_tmpb_tl - { \tl_if_head_eq_charcode:VNF \l__deriv_num_tmpa_tl - { \__deriv_sort_reverse:Nnn \c_false_bool {#1} { sign } } } { \tl_if_head_eq_charcode:VNT \l__deriv_num_tmpa_tl - { \__deriv_sort_reverse:Nnn \c_true_bool {#1} { sign } } } } % dv \cs_new_protected:Npn \__deriv_sort_symbol:n #1 { \int_set:Nn \l__deriv_tmpa_int { \tl_count:N \l__deriv_sym_tmpa_tl } \int_set:Nn \l__deriv_tmpb_int { \tl_count:N \l__deriv_sym_tmpb_tl } \int_compare:nNnTF \l__deriv_tmpa_int > \l__deriv_tmpb_int { \__deriv_sort_reverse:Nnn \c_false_bool {#1} { symbol } } { \int_compare:nNnT \l__deriv_tmpa_int < \l__deriv_tmpb_int { \__deriv_sort_reverse:Nnn \c_true_bool {#1} { symbol } } } } % dv \cs_new_protected:Npn \__deriv_sort_lexical:n #1 { \__deriv_sort_lexical_auxi:VVn \l__deriv_sym_tmpa_tl \l__deriv_sym_tmpb_tl {#1} } % symbol-str-1, symbol-str-2, dv \cs_new_protected:Npn \__deriv_sort_lexical_auxi:nnn #1 #2 #3 { \str_compare:nNnTF {#1} < {#2} { \__deriv_sort_reverse:Nnn \c_false_bool {#3} { lexical } } { \str_compare:nNnT {#1} > {#2} { \__deriv_sort_reverse:Nnn \c_true_bool {#3} { lexical } } } } % dv \cs_new_protected:Npn \__deriv_sort_abs:n #1 { \int_set:Nn \l__deriv_tmpa_int { \int_abs:n \l__deriv_num_tmpa_tl } \int_set:Nn \l__deriv_tmpb_int { \int_abs:n \l__deriv_num_tmpb_tl } \int_compare:nNnTF \l__deriv_tmpa_int > \l__deriv_tmpb_int { \__deriv_sort_reverse:Nnn \c_false_bool {#1} { abs } } { \int_compare:nNnT \l__deriv_tmpa_int < \l__deriv_tmpb_int { \__deriv_sort_reverse:Nnn \c_true_bool {#1} { abs } } } } % dv \cs_new_protected:Npn \__deriv_sort_number:n #1 { \int_compare:nNnTF \l__deriv_num_tmpa_tl > \l__deriv_num_tmpb_tl { \__deriv_sort_reverse:Nnn \c_false_bool {#1} { number } } { \int_compare:nNnT \l__deriv_num_tmpa_tl < \l__deriv_num_tmpb_tl { \__deriv_sort_reverse:Nnn \c_true_bool {#1} { number } } } } % true/false, dv, sort-method \cs_new_protected:Npn \__deriv_sort_reverse:Nnn #1 #2 #3 { \exp_args:NNc \bool_xor:nnTF #1 { l__deriv_#2_sort_#3_reverse_bool } { \seq_map_break:n { \sort_return_swapped: } } { \seq_map_break:n { \sort_return_same: } } } % mixed-order-tl, sorted-seq, numerical-term, variant \cs_new_protected:Npn \__deriv_output:NNNn #1 #2 #3 #4 { \tl_set:Nf #1 { \seq_use:Nn #2 { + } } \tl_if_empty:NF #3 { \tl_if_empty:NTF #1 { \tl_put_left:NV #1 #3 } { \exp_args:Nv \str_case:nnF { l__deriv_#4_sort_numerical_tl } { { last } { \tl_put_right:Nx #1 { + #3 } } { first } { \tl_put_left:Nx #1 { #3 + } } } { \tl_if_head_eq_charcode:VNTF #1 - { \tl_put_left:NV #1 #3 } { \tl_put_right:Nx #1 { + #3 } } } } } \tl_replace_all:Nnn #1 { +- } { - } \tl_if_empty:NT #1 { \tl_set:Nn #1 { 0 } } } %%%%% GCD (Greatest Common Divisor) %%%%% \cs_new:Npn \deriv_binary_shift_left:Nn #1 #2 { \tl_set:Nx #1 { \tl_range:Nnn #1 { #2+1 } { -1 } \prg_replicate:nn {#2} { 0 } } } \cs_new:Npn \deriv_binary_shift_right:N #1 { \tl_set:Nx #1 { 0 \tl_range:Nnn #1 { 1 } { -2 } } } \prg_new_conditional:Npnn \deriv_binary_if_even:N #1 { p } { \str_if_eq:eeTF { \tl_item:Nn #1 { -1 } } { 0 } { \prg_return_true: } { \prg_return_false: } } \cs_new:Npn \deriv_gcd:NN #1 #2 { % Not needed in my use case but technically correct to include %\int_compare:nNnTF #1 = 0 %{ \int_set:Nn #2 { \int_sign:n {#2} } } %{ \int_compare:nNnTF #2 = 0 { \int_set:Nn #1 { \int_sign:n {#1} } } { \tl_set:Nx \l__deriv_gcd_result_tl { \int_to_bin:n { \int_abs:n #1 } } \tl_set:Nx \l__deriv_gcd_remain_tl { \int_to_bin:n { \int_abs:n #2 } } \__deriv_gcd:NN \l__deriv_gcd_result_tl \l__deriv_gcd_remain_tl \int_set:Nn #1 { #1 / \l__deriv_gcd_result_tl } \int_set:Nn #2 { #2 / \l__deriv_gcd_result_tl } } %} } \cs_new:Npn \__deriv_gcd:NN #1 #2 { \int_zero:N \l__deriv_gcd_counter_int \bool_while_do:nn { \deriv_binary_if_even_p:N #1 && \deriv_binary_if_even_p:N #2 } { \deriv_binary_shift_right:N #1 \deriv_binary_shift_right:N #2 \int_incr:N \l__deriv_gcd_counter_int } \bool_while_do:nn { \deriv_binary_if_even_p:N #1 } { \deriv_binary_shift_right:N #1 } \bool_until_do:nn { \int_compare_p:nNn #2 = 0 } { \bool_while_do:nn { \deriv_binary_if_even_p:N #2 } { \deriv_binary_shift_right:N #2 } \__deriv_gcd_swap_helper:NNff #1 #2 { \exp_args:NV \int_from_bin:n {#1} } { \exp_args:NV \int_from_bin:n {#2} } } \deriv_binary_shift_left:NV #1 \l__deriv_gcd_counter_int \tl_set:Nx #1 { \exp_args:NV \int_from_bin:n {#1} } } \cs_new:Npn \__deriv_gcd_swap_helper:NNnn #1 #2 #3 #4 { \int_compare:nNnTF {#3} > {#4} { \tl_set_eq:NN #1 #2 \tl_set:Nx #2 { \int_to_bin:n { #3 - #4 } } } { \tl_set:Nx #2 { \int_to_bin:n { #4 - #3 } } } } %%%%% Declaring Variant %%%%% \DeclareDocumentCommand{\NewDerivative}{ m m o } { \cs_if_exist:NTF #1 { \msg_error:nnxx { deriv } { command-already-defined } { \token_to_str:N #1 } { \token_to_str:N \NewDerivative } } { \deriv_preamble:NNnnn \l__deriv_cs_name_tl #1 {#2} {#3} { dv } \deriv_dv_define:NVn \NewDocumentCommand \l__deriv_cs_name_tl {#1} } } \DeclareDocumentCommand{\RenewDerivative}{ m m o } { \cs_if_exist:NTF #1 { \deriv_preamble:NNnnn \l__deriv_cs_name_tl #1 {#2} {#3} { dv } \deriv_dv_define:NVn \RenewDocumentCommand \l__deriv_cs_name_tl {#1} } { \msg_error:nnxx { deriv } { command-not-defined } { \token_to_str:N #1 } { \token_to_str:N \RenewDerivative } } } \DeclareDocumentCommand{\ProvideDerivative}{ m m o } { \cs_if_exist:NF #1 { \deriv_preamble:NNnnn \l__deriv_cs_name_tl #1 {#2} {#3} { dv } \deriv_dv_define:NVn \ProvideDocumentCommand \l__deriv_cs_name_tl {#1} } } \DeclareDocumentCommand{\DeclareDerivative}{ m m o } { \deriv_preamble:NNnnn \l__deriv_cs_name_tl #1 {#2} {#3} { dv } \deriv_dv_define:NVn \DeclareDocumentCommand \l__deriv_cs_name_tl {#1} } \DeclareDocumentCommand{\NewDifferential}{ m m o } { \cs_if_exist:NTF #1 { \msg_error:nnxx { deriv } { command-already-defined } { \token_to_str:N #1 } { \token_to_str:N \NewOdvVariant } } { \deriv_preamble:NNnnn \l__deriv_dv_tmp_tl #1 {#2} {#3} { i } \deriv_i_define:NVn \NewDocumentCommand \l__deriv_dv_tmp_tl {#1} } } \DeclareDocumentCommand{\RenewDifferential}{ m m o } { \cs_if_exist:NTF #1 { \deriv_preamble:NNnnn \l__deriv_dv_tmp_tl #1 {#2} {#3} { i } \deriv_i_define:NVn \RenewDocumentCommand \l__deriv_dv_tmp_tl {#1} } { \msg_error:nnxx { deriv } { command-not-defined } { \token_to_str:N #1 } { \token_to_str:N \RenewOdvVariant } } } \DeclareDocumentCommand{\ProvideDifferential}{ m m o } { \cs_if_exist:NF #1 { \deriv_preamble:NNnnn \l__deriv_dv_tmp_tl #1 {#2} {#3} { i } \deriv_i_define:NVn \ProvideDocumentCommand \l__deriv_dv_tmp_tl {#1} } } \DeclareDocumentCommand{\DeclareDifferential}{ m m o } { \deriv_preamble:NNnnn \l__deriv_dv_tmp_tl #1 {#2} {#3} { i } \deriv_i_define:NVn \DeclareDocumentCommand \l__deriv_dv_tmp_tl {#1} } %%%%% slash frac %%%%% \DeclareDocumentCommand{\slashfrac}{ o m m } { \group_begin: \tl_if_novalue:nTF {#1} { \__deriv_slashfrac_auto:nn {#2} {#3} } { \str_case:nnF {#1} { { auto } { \__deriv_slashfrac_auto:nn {#2} {#3} } { none } { \__deriv_slashfrac_none:nn {#2} {#3} } } { \__deriv_slashfrac_scale:nnn {#1} {#2} {#3} } } \group_end: } % numerator, denominator \cs_new_protected:Npn \__deriv_slashfrac_auto:nn #1 #2 { \__deriv_auto_left:n . {#1} \middle/ {#2} \__deriv_auto_right:n . } % numerator, denominator \cs_new_protected:Npn \__deriv_slashfrac_none:nn #1 #2 { {#1} / {#2} } % scale, numerator, denominator \cs_new_protected:Npn \__deriv_slashfrac_scale:nnn #1 #2 #3 { \use:c { #1 l } . {#2} \use:c {#1} / {#3} \use:c { #1 r } . } %%%%% Generate variants %%%%% \prg_generate_conditional_variant:Nnn \__deriv_show_order:N { c } { T, TF } \cs_generate_variant:Nn \__deriv_set_rubber_length:Nn { c } \cs_generate_variant:Nn \deriv_dv_define:Nnn { NV } \cs_generate_variant:Nn \deriv_i_define:Nnn { NV } \cs_generate_variant:Nn \deriv_set_keys:nn { V } \cs_generate_variant:Nn \__deriv_dont_use_dot:n { x } \cs_generate_variant:Nn \__deriv_scale_big_auxi:nNn { nc } \cs_generate_variant:Nn \__deriv_insert_ord:Nnn { c } \cs_generate_variant:Nn \__deriv_insert_var:Nnn { NV } \cs_generate_variant:Nn \__deriv_mixed_order:NNn { c } \cs_generate_variant:Nn \__deriv_sort_method:Nn { c } \cs_generate_variant:Nn \__deriv_eval_term:Nnnn { NVV } \cs_generate_variant:Nn \__deriv_sort_lexical_auxi:nnn { VV } \cs_generate_variant:Nn \__deriv_set_default_auxi:Nnn { c } \cs_generate_variant:Nn \__deriv_set_default_auxii:nnn { f } \cs_generate_variant:Nn \__deriv_preamble_aux:nnn { V } \cs_generate_variant:Nn \__deriv_var_bool_seq:NNN { c } \cs_generate_variant:Nn \deriv_binary_shift_left:Nn { NV } \cs_generate_variant:Nn \__deriv_gcd_swap_helper:NNnn { NNff } \cs_generate_variant:Nn \__deriv_add_frac_to_seq:NNnnnnn { NNVVVV } \cs_generate_variant:Nn \__deriv_add_to_seq:NNnn { NNVV, NNnV } \cs_generate_variant:Nn \__deriv_update_seq:NNnn { NNVV, NNnV } \cs_generate_variant:Nn \__deriv_update_seq:NNNNn { NNNNV } \cs_generate_variant:Nn \__deriv_addfrac:NNnnnnn { NNVVxx } %%%%% Messages %%%%% \msg_new:nnnn { deriv } { command-already-defined } { Command~'#1'~already~defined! } { You~have~used~#2~with~a~command~that~already~has~a~definition. \\ The~existing~definition~of~'#1'~will~not~be~altered. } \msg_new:nnnn { deriv } { derivative-not-defined } { Derivative~'#1'~is~not~defined! } { You~have~used~#2~with~a~derivative~that~was~never~defined. } \msg_new:nnnn { deriv } { command-not-defined } { Command~'#1'~not~yet~defined! } { You~have~used~#2~with~a~command~that~was~never~defined. } \msg_new:nnnn { deriv } { boolean-values-only } { The~key~'#1'~accepts~boolean~values~only. } { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. } \msg_new:nnnn { deriv } { derivative-option-not-defined } { Derivative~option~'#1'~not~yet~defined! } { You~have~used~#2~with~a~derivative~option~that~was~never~defined. } \msg_new:nnnn { deriv } { differential-option-not-defined } { Differential~option~'#1'~not~yet~defined! } { You~have~used~#2~with~a~differential~option~that~was~never~defined. } \msg_new:nnnn { deriv } { differential-options-incompatible } { Differential~options~#1~are~not~compatible! } { You~have~used~#2~options~that~are~incompatible. } %%%%% Declaring derivatives %%%%% \@ifpackageloaded{mleftright} { \derivset{all}[scale-auto = mleftmright] } { \derivset{all}[scale-auto = leftright] } \bool_if:NTF \l__deriv_pkg_italic_bool { \DeclareDerivative{\odv}{\mathnormal{d}} \DeclareDerivative{\mdv}{\mathnormal{D}} \DeclareDifferential{\odif}{\mathnormal{d}} \DeclareDifferential{\mdif}{\mathnormal{D}}[style-var=mixed, style-var-*=multiple] } { \DeclareDerivative{\odv}{\mathrm{d}} \DeclareDerivative{\mdv}{\mathrm{D}} \DeclareDifferential{\odif}{\mathrm{d}} \DeclareDifferential{\mdif}{\mathrm{D}}[style-var=mixed, style-var-*=multiple] } \DeclareDerivative{\fdv}{\delta} \DeclareDerivative{\adv}{\Delta} \DeclareDerivative{\jdv}{\partial}[fun=true, var=1] \DeclareDerivative{\pdv}{\partial}[style-var=multiple, style-var-/=multiple, style-var-!=mixed, style-var-/!=multiple, delims-eval=(), delims-eval-/=(), delims-eval-!=()] \DeclareDifferential{\fdif}{\delta} \DeclareDifferential{\adif}{\Delta} \DeclareDifferential{\pdif}{\partial}[style-var=mixed, style-var-*=multiple] \endinput