summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/numerica/numerica-plus.def
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/numerica/numerica-plus.def')
-rw-r--r--macros/latex/contrib/numerica/numerica-plus.def876
1 files changed, 876 insertions, 0 deletions
diff --git a/macros/latex/contrib/numerica/numerica-plus.def b/macros/latex/contrib/numerica/numerica-plus.def
new file mode 100644
index 0000000000..6301dc9643
--- /dev/null
+++ b/macros/latex/contrib/numerica/numerica-plus.def
@@ -0,0 +1,876 @@
+% This is file `numerica-plus.def',
+% part of the `numerica' package.
+%
+% This work may be distributed and/or modified under the conditions
+% of the LaTeX Project Public License, either version 1.3c of this
+% license or any later version; see
+% http://www.latex-project.org/lppl.txt
+%
+% Andrew Parsloe (ajparsloe@gmail.com)
+%
+\ProvidesExplFile
+ {numerica-plus.def}
+ {2021/02/15}
+ {1.0.0}
+ { Iterate functions, find fixed points, zeros, extrema and recurrence terms }
+%----------------------------------------------------------
+\cs_new_protected:Npn \__nmc_plus_reuse:nNN #1#2#3
+ {
+ \int_case:nnF { #1 }
+ {
+ { 1 }
+ {
+ \seq_pop:NN #2 \l_tmpa_tl
+ \seq_pop:NN #3 \l_tmpb_tl
+ \tl_gset:Nx \g__nmc_reuse_tl { { \l_tmpa_tl , \l_tmpb_tl } }
+ \seq_mapthread_function:NNN #2 #3 \__nmc_plus_reuse_display:nn
+ }
+ { 2 }
+ {
+ \tl_gset:Nx \g__nmc_reuse_tl
+ { \seq_use:Nn #3 { , } }
+ }
+ }
+ { \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl }
+ }
+\cs_new_protected:Npn \__nmc_plus_reuse_display:nn #1#2
+ { \tl_gput_right:Nx \g__nmc_reuse_tl { , { #1 , #2 } } }
+%--------------------------------------
+% \nmcIterate
+\int_new:N \l__nmc_iter_total_int
+\int_new:N \l__nmc_iter_view_int
+\int_new:N \l__nmc_iter_round_int
+\tl_new:N \l__nmc_iter_var_tl
+\fp_new:N \l__nmc_iter_first_fp
+\seq_new:N \l__nmc_iter_result_seq
+\seq_new:N \l__nmc_iter_index_seq
+
+\fp_new:N \l__nmc_iter_fixedpti_fp
+\fp_new:N \l__nmc_iter_fixedptii_fp
+
+\tl_new:N \l__nmc_iter_begin_tl
+\tl_new:N \l__nmc_iter_end_tl
+\tl_new:N \g__nmc_iter_info_tl
+
+\nmc_define:nnN { \nmcIterate } { iter } \iter
+
+\cs_new_protected:Npn \__nmc_iter_settings_digest:
+ {
+ \bool_set_false:N \l__nmc_allow_TF_out_bool
+ \int_set:Nn \l__nmc_iter_total_int
+ { \int_max:nn { \l__nmc_iter_total_int } { 1 } }
+ \int_set:Nn \l__nmc_iter_view_int
+ { \int_min:nn { \int_max:nn { \l__nmc_iter_view_int }
+ { 1 } } { \l__nmc_iter_total_int } }
+ }
+\cs_new_protected:Npn \__nmc_iter_vv_digest:N #1
+ {
+ \tl_if_empty:NTF \l__nmc_iter_var_tl
+ { \__nmc_vv_digest:N #1 }
+ {
+ \clist_push:NV \l__nmc_formula_tl \l__nmc_iter_var_tl
+ \__nmc_vv_digest:N #1
+ \clist_pop:NN \l__nmc_formula_tl \l__nmc_iter_var_tl
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_process:
+ {
+ \int_set:Nn \l__nmc_iter_round_int
+ { \l__nmc_round_int + \l__nmc_iter_extra_int }
+ % first iterate
+ \__nmc_error_where:n { formula }
+ \tl_clear:N \l__nmc_fp_expr_tl
+ \__nmc_fpify:VN \l__nmc_formula_tl \l__nmc_fp_expr_tl
+ \fp_set:Nn \l__nmc_result_fp { \l__nmc_fp_expr_tl }
+ \__nmc_error_fpflag:
+
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \fp_set_eq:NN \l__nmc_iter_first_fp \l__nmc_result_fp
+ \tl_if_empty:NT \l__nmc_iter_var_tl
+ { % get iter. var if unspecified
+ \seq_get:NN \l__nmc_vv_all_seq \l_tmpa_tl
+ \__nmc_vv_split_item:V \l_tmpa_tl
+ \tl_set_eq:NN \l__nmc_iter_var_tl \l__nmc_eq_var_tl
+ }
+ \__nmc_iter_do:
+ \tl_set_eq:NN \l__nmc_fp_expr_tl \l__nmc_fp_exprn_tl
+ }
+ \bool_if:nF { \g__nmc_error_bool || \l__nmc_num_only_bool }
+ {
+ \__nmc_iter_environ:
+ \__nmc_iter_write:
+ }
+ }
+%--------------------------------------
+\cs_new_protected:Npn \__nmc_iter_do:
+ {
+ \bool_if:NTF \l__nmc_num_only_bool
+ {
+ \__nmc_iter_fixed_pt:
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \__nmc_num_format:nNnN { \l__nmc_iter_fixedpti_fp }
+ \l_nmc_result_tl { \l__nmc_round_int }
+ \l__nmc_sci_num_out_bool
+ \int_decr:N \l__nmc_iter_total_int
+ \tl_gset:Nx \g__nmc_iter_info_tl
+ { \int_use:N \l__nmc_iter_total_int }
+ }
+ }
+ { % don't print initial iterations
+ \int_step_function:nnnN { 1 } { 1 }
+ { \l__nmc_iter_total_int - \l__nmc_iter_view_int - 1 }
+ \__nmc_iter_current:n
+ \bool_if:NF \g__nmc_error_bool
+ { % store then print these ones
+ \seq_clear:N \l__nmc_iter_result_seq
+ \int_step_function:nnnN { 1 } { 1 }
+ { \int_min:nn { \l__nmc_iter_view_int }
+ { \l__nmc_iter_total_int - 1 } } \__nmc_iter_current_store:n
+ }
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_current:n #1
+ { % stepping function
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \__nmc_calc_fn_val:VNnN \l__nmc_iter_var_tl \l__nmc_formula_tl
+ { \l__nmc_result_fp } \l__nmc_result_fp
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_current_store:n #1
+ { % stepping function
+ \__nmc_calc_fn_val:VNnN \l__nmc_iter_var_tl \l__nmc_formula_tl
+ { \l__nmc_result_fp } \l__nmc_result_fp
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \__nmc_num_format:nNnN { \l__nmc_result_fp } \l_nmc_result_tl
+ { \l__nmc_round_int } \l__nmc_sci_num_out_bool
+ \seq_put_right:NV \l__nmc_iter_result_seq \l_nmc_result_tl
+ \int_set:Nn \l_tmpa_int
+ { \l__nmc_iter_total_int - \l__nmc_iter_view_int + #1 }
+ \seq_put_right:Nx \l__nmc_iter_index_seq { \int_use:N \l_tmpa_int }
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_fixed_pt:
+ { % already 1 iteration
+ \int_set:Nn \l__nmc_iter_total_int { 1 }
+ \fp_set_eq:NN \l__nmc_iter_fixedpti_fp \l__nmc_iter_first_fp
+ \fp_set:Nn \l__nmc_iter_fixedptii_fp { \l__nmc_iter_fixedpti_fp + 1 }
+ \bool_until_do:nn
+ {
+ \fp_compare_p:nNn { 0 } =
+ { round( \l__nmc_iter_fixedpti_fp - \l__nmc_iter_fixedptii_fp,
+ \l__nmc_iter_round_int ) }
+ || \g__nmc_error_bool
+ }
+ {
+ \int_incr:N \l__nmc_iter_total_int
+ \fp_set_eq:NN \l__nmc_iter_fixedptii_fp \l__nmc_iter_fixedpti_fp
+ \__nmc_calc_fn_val:VNnN \l__nmc_iter_var_tl \l__nmc_formula_tl
+ { \l__nmc_result_fp } \l__nmc_result_fp
+ \fp_set_eq:NN \l__nmc_iter_fixedpti_fp \l__nmc_result_fp
+ \int_compare:nNnF { \l__nmc_iter_total_int } <
+ { \l__nmc_iter_max_int }
+ {
+ \bool_gset_true:N \g__nmc_error_bool
+ \__nmc_error_what:n
+ {
+ No~fixed~point~attained~after~$\int_use:N
+ \l__nmc_iter_total_int$~iterations~of
+ }
+ }
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_environ:
+ {
+ \tl_set:Nx \l__nmc_iter_begin_tl
+ {
+ \mode_if_math:F { \exp_not:o \l__nmc_math_delimi_tl }
+ \exp_not:N \begin{array}{r@{}l}
+ \bool_if:NTF \l__nmc_wraps_math_bool
+ { \exp_not:o \l__nmc_formula_dup_tl &{}= }
+ { &{} }
+ }
+ \tl_set:Nx \l__nmc_iter_end_tl
+ {
+ \exp_not:N \end{array}
+ \mode_if_math:F { \exp_not:o \l__nmc_math_delimii_tl }
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_write:
+ {
+ \__nmc_num_format:nNnN { \l__nmc_iter_first_fp } \l_tmpa_tl
+ { \l__nmc_round_int } \l__nmc_sci_num_out_bool
+ \tl_gset:Nx \g__nmc_iter_info_tl { \int_use:N \l__nmc_iter_total_int }
+ \__nmc_if_mod_zero:nnTF { \l__nmc_debug_int } { 7 }
+ { \seq_get_right:NN \l__nmc_iter_result_seq \l_nmc_result_tl }
+ {
+ \tl_set:Nx \l_nmc_result_tl
+ {
+ \exp_not:o \l__nmc_iter_begin_tl
+ \l_tmpa_tl \l__nmc_vv_display_tl
+ \int_compare:nNnT
+ { \l__nmc_iter_total_int } > { \l__nmc_iter_view_int + 1 }
+ {
+ \\ & \exp_not:N \ldots
+ \ \exp_not:N\mbox{final\
+ \int_use:N \l__nmc_iter_view_int\ of\ \g__nmc_iter_info_tl :}
+ }
+ \int_compare:nNnT { \l__nmc_iter_total_int } > { 1 }
+ { \\ & \exp_not:N \hookrightarrow }
+ \seq_use:Nn \l__nmc_iter_result_seq { \\ & \hookrightarrow }
+ \exp_not:o \l__nmc_iter_end_tl
+ }
+ }
+ }
+\cs_new_protected:Npn \__nmc_iter_display:
+ {
+ \bool_if:NTF \l__nmc_num_only_bool
+ { \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl }
+ {
+ \__nmc_plus_reuse:nNN { \l__nmc_iter_reuse_int }
+ \l__nmc_iter_index_seq \l__nmc_iter_result_seq
+ }
+ \l_nmc_result_tl
+ }
+%--------------------------------------
+%\nmcSolve
+\int_new:N \l__nmc_solve_round_int
+\int_new:N \l__nmc_solve_steps_int
+\int_new:N \l__nmc_solve_slope_int
+\int_new:N \l__nmc_solve_slopei_int
+\int_new:N \l__nmc_solve_signs_int
+\fp_new:N \l__nmc_solvea_fp
+\fp_new:N \l__nmc_solveb_fp
+\fp_new:N \l__nmc_solvec_fp
+\fp_new:N \l__nmc_solved_fp
+
+\fp_new:N \l__nmc_solvefa_fp
+\fp_new:N \l__nmc_solvefb_fp
+\fp_new:N \l__nmc_solvefc_fp
+\bool_new:N \l__nmc_solve_stop_bool
+\tl_new:N \g__nmc_sove_info_tl
+
+\nmc_define:nnN { \nmcSolve } { solve } \solve
+
+\cs_new_protected:Npn \__nmc_solve_settings_digest:
+ {
+ \bool_set_false:N \l__nmc_allow_TF_out_bool
+ \tl_if_empty:NF \l__nmc_solve_step_tl
+ {
+ \__nmc_fpify_set:NN \l__nmc_solve_step_fp \l__nmc_solve_step_tl
+ \fp_compare:nNnT \l__nmc_solve_step_fp = { 0 }
+ { \__nmc_error_what:n { Non-zero~initial~step~required~in } }
+ }
+ }
+\cs_new_protected:Npn \__nmc_solve_vv_digest:N #1
+ {
+ \tl_if_empty:NTF \l__nmc_solve_var_tl
+ { \__nmc_vv_digest:N #1 }
+ {
+ \clist_push:NV \l__nmc_formula_tl \l__nmc_solve_var_tl
+ \__nmc_vv_digest:N #1
+ \clist_pop:NN \l__nmc_formula_tl \l__nmc_solve_var_tl
+ }
+ }
+\cs_new_protected:Npn \__nmc_solve_process:
+ {
+ \int_set:Nn \l__nmc_solve_round_int
+ { \l__nmc_round_int + \l__nmc_solve_extra_int }
+ % get equation var if unspecified
+ \tl_if_empty:NT \l__nmc_solve_var_tl
+ {
+ \seq_get:NN \l__nmc_vv_all_seq \l_tmpa_tl
+ \__nmc_vv_split_item:V \l_tmpa_tl
+ \tl_set_eq:NN \l__nmc_solve_var_tl \l__nmc_eq_var_tl
+ }
+ \bool_if:NF \g__nmc_error_bool
+ { \__nmc_solve_get_trial_vals: }
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \__nmc_error_where:n { function }
+ \__nmc_solve_do:
+ }
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \__nmc_num_format:nNnN { \l__nmc_solvea_fp } \l_nmc_result_tl
+ { \l__nmc_round_int } \l__nmc_sci_num_out_bool
+ \tl_gset:Nx \g__nmc_solve_info_tl
+ { \clist_use:Nn \g__nmc_solve_info_tl { + } }
+ \tl_set_eq:NN \l__nmc_fp_expr_tl \l__nmc_fp_exprn_tl
+ }
+ }
+\cs_new_protected:Npn \__nmc_solve_get_trial_vals:
+ {
+ \prop_get:NVN \g__nmc_subst_var_prop
+ \l__nmc_solve_var_tl \l__nmc_subst_tl
+ % ensure a < b
+ \int_case:nn { \fp_sign:n { \l__nmc_solve_step_fp } }
+ {
+ { 1 }
+ {
+ \fp_set:Nn \l__nmc_solvea_fp { \l__nmc_subst_tl }
+ \fp_set:Nn \l__nmc_solveb_fp
+ { \l__nmc_solvea_fp + \l__nmc_solve_step_fp }
+ }
+ { -1 }
+ {
+ \fp_set:Nn \l__nmc_solveb_fp { \l__nmc_subst_tl }
+ \fp_set:Nn \l__nmc_solvea_fp
+ { \l__nmc_solveb_fp + \l__nmc_solve_step_fp }
+ }
+ }
+ }
+% find opp. signs, zero, or fn min.
+% a b = var vals; fa fb = fn vals
+\cs_new_protected:Npn \__nmc_solve_do:
+ {
+ \__nmc_solve_calc_values:
+ \int_zero:N \l__nmc_solve_steps_int
+ \tl_gclear:N \g__nmc_solve_info_tl
+ \bool_do_until:nn
+ {
+ \g__nmc_error_bool || \l__nmc_solve_stop_bool
+ || \int_compare_p:nNn
+ { \l__nmc_solve_steps_int } > { \l__nmc_solve_max_int }
+ || \fp_compare_p:nNn { 0 } =
+ { round(\l__nmc_solveb_fp - \l__nmc_solvea_fp,
+ \l__nmc_solve_round_int) }
+ }
+ {
+ \int_incr:N \l__nmc_solve_steps_int
+ \int_case:nn { \l__nmc_solve_signs_int }
+ {
+ { 0 } { \__nmc_solve_do_bingo: }
+ { -1 } { \__nmc_solve_do_bisect: }
+ { 1 } { \__nmc_solve_do_slope: }
+ }
+ }
+ \bool_if:nF { \g__nmc_error_bool || \l__nmc_solve_stop_bool }
+ {
+ \__nmc_error_where:n { $\l__nmc_formula_tl$ }
+ \__nmc_error_what:n
+ {
+ No~zero/extremum~found~after~$\int_use:N
+ \l__nmc_solve_max_int$~steps~for~function
+ }
+ }
+ }
+\cs_new_protected:Npn \__nmc_solve_do_bingo:
+ { % fn = 0 to 16 figures
+ \fp_compare:nNnTF { \l__nmc_solvefb_fp } = { 0 }
+ {
+ \fp_set_eq:NN \l__nmc_solvea_fp \l__nmc_solveb_fp
+ \fp_set_eq:NN \l__nmc_solvefa_fp \l__nmc_solvefb_fp
+ }
+ {
+ \fp_set_eq:NN \l__nmc_solveb_fp \l__nmc_solvea_fp
+ \fp_set_eq:NN \l__nmc_solvefb_fp \l__nmc_solvefa_fp
+ }
+ \bool_set_true:N \l__nmc_solve_stop_bool
+ }
+\cs_new_protected:Npn \__nmc_solve_do_bisect:
+ {
+ \tl_gset:Nx \g__nmc_solve_info_tl { \int_use:N \l__nmc_solve_steps_int }
+ \int_zero:N \l__nmc_solve_steps_int
+ \fp_set:Nn \l__nmc_solvec_fp { ( \l__nmc_solvea_fp + \l__nmc_solveb_fp ) / 2 }
+ \__nmc_calc_fn_val:VNnN \l__nmc_solve_var_tl \l__nmc_formula_tl
+ { \l__nmc_solvec_fp } \l__nmc_solvefc_fp
+ \fp_set:Nn \l__nmc_solved_fp { \l__nmc_solvec_fp + 1 }
+ \bool_until_do:nn
+ {
+ \g__nmc_error_bool ||
+ \fp_compare_p:nNn { 0 } =
+ { round( \l__nmc_solvec_fp - \l__nmc_solved_fp ,
+ \l__nmc_solve_round_int ) }
+ }
+ {
+ \int_incr:N \l__nmc_solve_steps_int
+ \fp_set_eq:NN \l__nmc_solved_fp \l__nmc_solvec_fp
+ \fp_compare:nNnTF { 0 } = { \l__nmc_solvefc_fp }
+ {
+ \fp_set_eq:NN \l__nmc_solvea_fp \l__nmc_solvec_fp
+ \fp_set_eq:NN \l__nmc_solvefa_fp \l__nmc_solvefc_fp
+ }
+ {
+ \fp_compare:nNnTF
+ { sign(\l__nmc_solvefa_fp)sign(\l__nmc_solvefc_fp) } = { 1 }
+ {
+ \fp_set_eq:NN \l__nmc_solvea_fp \l__nmc_solvec_fp
+ \fp_set_eq:NN \l__nmc_solvefa_fp \l__nmc_solvefc_fp
+ }
+ {
+ \fp_set_eq:NN \l__nmc_solveb_fp \l__nmc_solvec_fp
+ \fp_set_eq:NN \l__nmc_solvefb_fp \l__nmc_solvefc_fp
+ }
+ \fp_set:Nn \l__nmc_solvec_fp
+ { ( \l__nmc_solvea_fp + \l__nmc_solveb_fp ) / 2 }
+ \__nmc_calc_fn_val:VNnN \l__nmc_solve_var_tl
+ \l__nmc_formula_tl { \l__nmc_solvec_fp } \l__nmc_solvefc_fp
+ }
+ }
+ \bool_set_true:N \l__nmc_solve_stop_bool
+ \clist_gput_right:Nx \g__nmc_solve_info_tl { \int_use:N \l__nmc_solve_steps_int }
+ }
+\cs_new_protected:Npn \__nmc_solve_do_slope:
+ {
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \int_if_zero:nTF { \l__nmc_solve_slope_int }
+ { % contract
+ \fp_add:Nn \l__nmc_solvea_fp
+ { ( \l__nmc_solveb_fp - \l__nmc_solvea_fp ) / 4 }
+ \fp_sub:Nn \l__nmc_solveb_fp
+ { ( \l__nmc_solveb_fp - \l__nmc_solvea_fp ) / 4 }
+ }
+ { % always towards x-axis
+ \fp_compare:nNnTF { 0 } <
+ { \l__nmc_solvefa_fp * \l__nmc_solve_slope_int }
+ { \__nmc_solve_do_slope_left: }
+ { \__nmc_solve_do_slope_right: }
+ }
+ \fp_set_eq:NN \l__nmc_solved_fp \l__nmc_solvea_fp
+ \int_set_eq:NN \l__nmc_solve_slopei_int \l__nmc_solve_slope_int
+ \__nmc_solve_calc_values:
+ }
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \int_compare:nNnF { \l__nmc_solve_slope_int } =
+ { \l__nmc_solve_slopei_int }
+ {
+ \fp_set:Nn \l__nmc_solvec_fp { ( \l__nmc_solvea_fp + \l__nmc_solveb_fp ) / 2 }
+ \int_case:nn { \l__nmc_solve_slopei_int }
+ {
+ { 1 } { \fp_set_eq:NN \l__nmc_solvea_fp \l__nmc_solvec_fp }
+ { -1 } { \fp_set_eq:NN \l__nmc_solveb_fp \l__nmc_solvec_fp }
+ }
+ \__nmc_solve_calc_values:
+ }
+ }
+ \fp_compare:nNnT { 0 } =
+ { round(\l__nmc_solveb_fp - \l__nmc_solvea_fp,
+ \l__nmc_solve_round_int) }
+ { \bool_set_true:N \l__nmc_solve_stop_bool }
+ }
+\cs_new_protected:Npn \__nmc_solve_do_slope_left:
+ {
+ \fp_set:Nn \l__nmc_solvec_fp { 2 \l__nmc_solvea_fp - \l__nmc_solveb_fp }
+ \fp_set_eq:NN \l__nmc_solveb_fp \l__nmc_solvea_fp
+ \fp_set_eq:NN \l__nmc_solvea_fp \l__nmc_solvec_fp
+ }
+\cs_new_protected:Npn \__nmc_solve_do_slope_right:
+ {
+ \fp_set:Nn \l__nmc_solvec_fp { 2 \l__nmc_solveb_fp - \l__nmc_solvea_fp }
+ \fp_set_eq:NN \l__nmc_solvea_fp \l__nmc_solveb_fp
+ \fp_set_eq:NN \l__nmc_solveb_fp \l__nmc_solvec_fp
+ }
+\cs_new_protected:Npn \__nmc_solve_calc_values:
+ {
+ \__nmc_calc_fn_val:VNnN \l__nmc_solve_var_tl \l__nmc_formula_tl
+ { \l__nmc_solvea_fp } \l__nmc_solvefa_fp
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \__nmc_calc_fn_val:VNnN \l__nmc_solve_var_tl \l__nmc_formula_tl
+ { \l__nmc_solveb_fp } \l__nmc_solvefb_fp
+ }
+ \bool_if:NF \g__nmc_error_bool
+ {
+ \int_set:Nn \l__nmc_solve_slope_int
+ { \fp_eval:n { sign(\l__nmc_solvefb_fp - \l__nmc_solvefa_fp) } }
+ \int_set:Nn \l__nmc_solve_signs_int
+ { \fp_eval:n { sign(\l__nmc_solvefa_fp) sign(\l__nmc_solvefb_fp) } }
+ }
+ }
+\cs_new_protected:Npn \__nmc_solve_display:
+ {
+ \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl
+ \bool_if:NF \l__nmc_num_only_bool
+ {
+ \__nmc_num_format:nNnN { \l__nmc_solvefa_fp } \l_tmpa_tl
+ { \l__nmc_round_int } \l__nmc_sci_num_out_bool
+ \tl_set:Nx \l_nmc_result_tl
+ {
+ \exp_not:o \l__nmc_math_delimi_tl
+ \bool_if:NTF \l__nmc_wraps_math_bool
+ {
+ \exp_not:o \l__nmc_formula_tl = \l_tmpa_tl
+ \bool_if:NTF \l__nmc_vv_multline_bool
+ { \exp_not:o \l__nmc_vv_display_tl }
+ {
+ \mathchoice{ \exp_not:o \l__nmc_vv_display_tl }
+ { \exp_not:o \l__nmc_vv_inline_tl }{}{}
+ }
+ \rightarrow \exp_not:N \quad
+ \l__nmc_solve_var_tl = \l_nmc_result_tl
+ }
+ {
+ \l__nmc_solve_var_tl = \l_nmc_result_tl
+ \mathchoice{ \exp_not:o \l__nmc_vv_display_tl }
+ { \exp_not:o \l__nmc_vv_inline_tl }{}{}
+ }
+ \l__nmc_punc_tl
+ \exp_not:o \l__nmc_math_delimii_tl
+ }
+ \int_if_zero:nT { \l__nmc_solve_reuse_int }
+ { \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl }
+ }
+ \l_nmc_result_tl
+ }
+%--------------------------------------
+% \nmcRecur
+\bool_new:N \l__nmc_recur_ellipsis_bool
+\int_new:N \l__nmc_recur_last_int
+\fp_new:N \l__nmc_recur_result_fp
+
+\int_new:N \l__nmc_recur_subscr_ini_int
+\int_new:N \l__nmc_recur_subscr_val_int
+\int_new:N \l__nmc_recur_order_int
+\int_new:N \l__nmc_recur_var_int
+
+\tl_new:N \l__nmc_recurrence_tl
+\tl_new:N \l__nmc_recur_base_var_tl
+\tl_new:N \l__nmc_recur_subscr_var_tl
+
+\seq_new:N \l__nmc_recur_result_seq
+\seq_new:N \l__nmc_recur_index_seq
+\seq_new:N \l__nmc_recur_vars_seq
+
+\nmc_define:nnN { \nmcRecur } { recur } \recur
+
+\cs_new_protected:Npn \__nmc_recur_settings_digest:
+ {
+ \bool_set_false:N \l__nmc_allow_TF_out_bool
+ \int_set:Nn \l__nmc_recur_total_int
+ { \int_max:nn { \l__nmc_recur_total_int } { 1 } }
+ \int_set:Nn \l__nmc_recur_last_int
+ { \int_max:nn { 0 } { \int_min:nn
+ { \l__nmc_recur_last_int } { \l__nmc_recur_total_int } } }
+ \int_set:Nn \l__nmc_recur_first_int
+ { \int_max:nn { 0 } { \int_min:nn { \l__nmc_recur_first_int }
+ { \l__nmc_recur_total_int - \l__nmc_recur_last_int } } }
+ \int_if_zero:nT { \l__nmc_recur_first_int }
+ { \int_decr:N \l__nmc_recur_first_int }
+ }
+\cs_new_protected:Npn \__nmc_recur_vv_digest:N #1
+ { % #1 = reversed vv clist
+ \bool_set_true:N \l__nmc_multitok_bool
+ \__nmc_recur_elements:
+ \__nmc_recur_vars_change:N #1
+ \__nmc_vv_digest:N #1
+ \__nmc_recur_vv_post:
+ \tl_set_eq:NN \l__nmc_formula_tl \l__nmc_recurrence_tl
+ }
+% \l__nmc_recurrence_tl, \l__nmc_recur_base_var_tl,
+% \l__nmc_recur_subscr_var_tl, \l__nmc_recur_subscr_val_int
+\cs_new_protected:Npn \__nmc_recur_elements:
+ {
+ \tl_clear:N \l_tmpa_tl
+ \bool_set_false:N \l_tmpa_bool
+ \tl_map_inline:Nn \l__nmc_formula_tl
+ {
+ \bool_if:NTF \l_tmpa_bool
+ {
+ \tl_set:Nn \l_tmpa_tl { ##1 }
+ \tl_map_break:
+ }
+ {
+ \token_if_math_subscript:NTF ##1
+ {
+ \tl_set:NV \l__nmc_recur_base_var_tl \l_tmpa_tl
+ \bool_set_true:N \l_tmpa_bool
+ }
+ { \tl_put_right:Nn \l_tmpa_tl { ##1 } }
+ }
+ }
+ \__nmc_recur_parse_subscr:N \l_tmpa_tl
+ \exp_last_unbraced:NV\__nmc_split_eq:w \l__nmc_formula_tl \q_stop
+ \tl_set:NV \l__nmc_recurrence_tl \l__nmc_eq_val_tl
+ \tl_set_rescan:Nno \l__nmc_recurrence_tl { \ExplSyntaxOn } \l__nmc_recurrence_tl
+ }
+\cs_new_protected:Npn \__nmc_recur_parse_subscr:N #1
+ {
+ \tl_clear:N \l__nmc_recur_subscr_var_tl
+ \tl_set:Nn \l_tmpb_tl { 0 }
+ \int_zero:N \l__nmc_recur_subscr_val_int
+ \bool_set_false:N \l_tmpa_bool
+ \tl_map_inline:Nn #1
+ {
+ \bool_if:NTF \l_tmpa_bool
+ { \tl_put_right:Nn \l_tmpb_tl { ##1 } }
+ {
+ \tl_if_in:nnTF { +- } { ##1 }
+ {
+ \tl_put_right:Nn \l_tmpb_tl { ##1 }
+ \bool_set_true:N \l_tmpa_bool
+ }
+ { \tl_put_right:Nn \l__nmc_recur_subscr_var_tl { ##1 } }
+ }
+ }
+ \int_set:Nn \l__nmc_recur_subscr_val_int { \l_tmpb_tl }
+ }
+\cs_new_protected:Npn \__nmc_recur_vars_change:N #1
+ { % f_{1} etc ==> f_{n-1} etc in #1 (reverse order vv-list)
+ \clist_reverse:N #1
+ \int_zero:N \l__nmc_recur_order_int
+ \clist_clear:N \l_tmpa_clist % --> \l__nmc_recur_vars_seq
+ \clist_clear:N \l_tmpb_clist % --> #1
+ \int_set:Nn \l_tmpb_int { \l__nmc_recur_subscr_val_int - 1 }
+ \tl_set_rescan:Nno #1 { \ExplSyntaxOn } #1
+ \clist_map_inline:Nn #1
+ {
+ \seq_set_split:Nnn \l_tmpa_seq {_} { ##1 }
+ \seq_pop:NN \l_tmpa_seq \l_tmpa_tl
+ \seq_if_empty:NTF \l_tmpa_seq
+ { \clist_put_left:NV \l_tmpb_clist \l_tmpa_tl }
+ {
+ \tl_if_eq:NNTF \l_tmpa_tl \l__nmc_recur_base_var_tl
+ { % change e.g. f_{1}(x) to f_{n-1}(x)
+ \int_incr:N \l__nmc_recur_order_int
+ \tl_put_right:Nn \l_tmpa_tl { _ }
+ \tl_set_eq:NN \l_tmpb_tl \l__nmc_recur_subscr_var_tl
+ \int_case:nn { \int_sign:n { \l_tmpb_int } }
+ {
+ { -1 }
+ {
+ \tl_put_right:Nx \l_tmpb_tl
+ { \int_use:N \l_tmpb_int }
+ }
+ { 0 } { \prg_do_nothing: }
+ { 1 }
+ {
+ \tl_put_right:Nn \l_tmpb_tl { + }
+ \tl_put_right:Nx \l_tmpb_tl
+ { \int_use:N \l_tmpb_int }
+ }
+ }
+ \tl_put_right:Nx \l_tmpa_tl { { \l_tmpb_tl } }
+ \int_decr:N \l_tmpb_int
+ \seq_pop:NN \l_tmpa_seq \l_tmpb_tl
+ \int_set:Nn \l__nmc_recur_subscr_ini_int
+ { \tl_head:N \l_tmpb_tl }
+ \tl_put_right:Nx \l_tmpa_tl
+ { \tl_range:Nnn \l_tmpb_tl { 2 } { -1 } }
+ \clist_put_left:NV \l_tmpb_clist \l_tmpa_tl
+ \seq_set_split:NnV \l_tmpb_seq { = } \l_tmpa_tl
+ \seq_pop:NN \l_tmpb_seq \l_tmpa_tl
+ \clist_put_left:NV \l_tmpa_clist \l_tmpa_tl
+ }
+ { \clist_put_left:Nn \l_tmpb_clist { ##1 } }
+ }
+ }
+ \int_set:Nn \l__nmc_recur_var_int
+ { \l__nmc_recur_subscr_ini_int + \l__nmc_recur_order_int
+ - \l__nmc_recur_subscr_val_int }
+ \clist_set_eq:NN #1 \l_tmpb_clist
+ \clist_put_left:NV \l_tmpa_clist \l__nmc_recur_subscr_var_tl
+ \clist_concat:NNN \l__nmc_formula_tl \l__nmc_recurrence_tl \l_tmpa_clist
+ }
+\cs_new_protected:Npn \__nmc_recur_vv_post:
+ {
+ \clist_pop:NN \l__nmc_formula_tl \l__nmc_recurrence_tl
+ \clist_pop:NN \l__nmc_formula_tl \l__nmc_recur_subscr_var_tl
+ \tl_set:Nx \l_tmpa_tl { \int_use:N \l__nmc_recur_var_int }
+ \__nmc_vv_record:NVN \l__nmc_recur_subscr_var_tl \l_tmpa_tl \c_empty_prop
+ \tl_set_eq:NN \l_tmpa_tl \l__nmc_recur_subscr_var_tl
+ \tl_put_right:Nn \l_tmpa_tl { =0 } % formal value
+ \seq_put_left:NV \l__nmc_calc_fn_seq \l_tmpa_tl
+ \seq_set_from_clist:NN \l__nmc_recur_vars_seq \l__nmc_formula_tl
+ }
+%%%%%%%%%%%%%%%%%%%
+\cs_new_protected:Npn \__nmc_recur_process:
+ { % store initial vals; generate later vals
+ \__nmc_recur_store_ini:
+ \__nmc_error_where:n { recurrence~formula }
+ \__nmc_recur_generate:
+ \seq_get_right:NN \l__nmc_recur_result_seq \l_nmc_result_tl
+ \tl_set_eq:NN \l__nmc_fp_expr_tl \l__nmc_fp_exprn_tl
+ }
+\cs_new_protected:Npn \__nmc_recur_store_ini:
+ {
+ \seq_set_eq:NN \l_tmpa_seq \l__nmc_recur_vars_seq
+ \int_step_inline:nnnn { 1 } { 1 } { \l__nmc_recur_order_int }
+ {
+ \seq_pop:NN \l_tmpa_seq \l_tmpa_tl
+ \prop_get:NVN \g__nmc_subst_var_prop \l_tmpa_tl \l__nmc_subst_tl
+ \__nmc_num_format:nNnN { \l__nmc_subst_tl } \l_tmpa_tl
+ { \l__nmc_round_int } \l__nmc_sci_num_out_bool
+ \seq_put_right:NV \l__nmc_recur_result_seq \l_tmpa_tl
+ \tl_set:Nx \l_tmpb_tl { \int_eval:n
+ { \l__nmc_recur_subscr_ini_int + ##1 -1 } }
+ \seq_put_right:NV \l__nmc_recur_index_seq \l_tmpb_tl
+ }
+ }
+\cs_new_protected:Npn \__nmc_recur_generate:
+ {
+ \prop_get:NVN \g__nmc_subst_var_prop
+ \l__nmc_recur_subscr_var_tl \l__nmc_subst_tl
+ \int_set:Nn \l__nmc_recur_var_int { \l__nmc_subst_tl }
+ \int_set:Nn \l_tmpa_int { \l__nmc_recur_var_int +
+ \l__nmc_recur_total_int - \l__nmc_recur_order_int - 1 }
+ \__nmc_error_where:n { recurrence~relation }
+ \__nmc_if_mod_zero:nnT { \l__nmc_debug_int } { 7 }
+ { \__nmc_fpify:VN \l__nmc_recurrence_tl \l__nmc_fp_expr_tl }
+ \int_step_function:nnnN { \l__nmc_recur_var_int } { 1 }
+ {\l_tmpa_int } \__nmc_recur_generate_loop:n
+ }
+\cs_new_protected:Npn \__nmc_recur_generate_loop:n #1
+ {
+ \bool_if:NF \g__nmc_error_bool
+ { % calc. the next term
+ \fp_set:Nn \l_tmpa_fp { #1 }
+ \__nmc_calc_fn_val:VNnN \l__nmc_recur_subscr_var_tl
+ \l__nmc_recurrence_tl { \l_tmpa_fp } \l__nmc_recur_result_fp
+ }
+ \bool_if:NF \g__nmc_error_bool
+ { % store the result
+ \__nmc_num_format:nNnN { \l__nmc_recur_result_fp }
+ \l_tmpa_tl { \l__nmc_round_int } \l__nmc_sci_num_out_bool
+ \seq_put_right:NV \l__nmc_recur_result_seq \l_tmpa_tl
+ \seq_put_right:Nn \l__nmc_recur_index_seq { #1 }
+ % shift vals "down variable"; tmpa above, tmpb below
+ \seq_set_eq:NN \l_tmpa_seq \l__nmc_recur_vars_seq
+ \seq_pop:NN \l_tmpa_seq \l_tmpb_tl % low var
+ \int_step_inline:nnnn {2} { 1 } { \l__nmc_recur_order_int }
+ {
+ \seq_pop:NN \l_tmpa_seq \l_tmpa_tl % hi var
+ \prop_get:NVN \g__nmc_subst_var_prop \l_tmpa_tl \l__nmc_subst_tl
+ \prop_put:NVV \g__nmc_subst_var_prop \l_tmpb_tl \l__nmc_subst_tl
+ \prop_put:NVV \l__nmc_vv_change_prop \l_tmpb_tl \l__nmc_subst_tl
+ \tl_set_eq:NN \l_tmpb_tl \l_tmpa_tl
+ }
+ % use tmpb, not tmpa, in case order = 1
+ \prop_put:NVx \g__nmc_subst_var_prop \l_tmpb_tl
+ { \fp_use:N \l__nmc_recur_result_fp }
+ \prop_put:NVx \l__nmc_vv_change_prop \l_tmpb_tl
+ { \fp_use:N \l__nmc_recur_result_fp }
+ }
+ }
+\cs_new_protected:Npn \__nmc_recur_display:
+ {
+ \bool_if:NTF \l__nmc_num_only_bool
+ { \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl }
+ {
+ \seq_clear:N \l_tmpa_seq
+ \seq_clear:N \l_tmpb_seq
+ \seq_clear:N \l_tmpc_seq
+ \__nmc_recur_result:NN \l_tmpa_seq \l_tmpb_seq
+ \tl_set:Nx \l_nmc_result_tl
+ {
+ \exp_not:o \l__nmc_math_delimi_tl
+ \bool_if:NT \l__nmc_wraps_math_bool
+ {
+ \exp_not:o \l__nmc_formula_dup_tl
+ \bool_if:NTF \l__nmc_vv_multline_bool
+ { \exp_not:o \l__nmc_vv_display_tl }
+ {
+ \mathchoice{ \exp_not:o \l__nmc_vv_display_tl }
+ { \exp_not:o \l__nmc_vv_inline_tl }{}{}
+ }
+ \rightarrow \exp_not:N \quad
+ }
+ \seq_use:Nn \l_tmpa_seq { ,\ }
+ \l__nmc_punc_tl
+ \exp_not:o \l__nmc_math_delimii_tl
+ }
+ \__nmc_plus_reuse:nNN { \l__nmc_recur_reuse_int } \l_tmpc_seq \l_tmpb_seq
+ }
+ \l_nmc_result_tl
+ }
+\cs_new_protected:Npn \__nmc_recur_result:NN #1#2
+ {
+ \int_zero:N \l_tmpa_int
+ \seq_map_inline:Nn \l__nmc_recur_result_seq
+ {
+ \seq_pop:NN \l__nmc_recur_index_seq \l__nmc_toss_tl
+ \int_compare:nNnTF { \l_tmpa_int } < { \l__nmc_recur_first_int }
+ { \seq_put_right:Nn #1 { ##1 } }
+ {
+ \int_compare:nTF { \l_tmpa_int = \l__nmc_recur_first_int
+ < \l__nmc_recur_total_int - \l__nmc_recur_last_int }
+ { \seq_put_right:Nn #1 { \ldots } }
+ {
+ \int_compare:nNnT { 1 + \l_tmpa_int } >
+ { \l__nmc_recur_total_int - \l__nmc_recur_last_int }
+ {
+ \seq_put_right:Nn #1 { ##1 }
+ \seq_put_right:Nn #2 { ##1 }
+ \seq_put_right:Nx \l_tmpc_seq { \int_eval:n { \l_tmpa_int + \l__nmc_recur_subscr_val_int } }
+ }
+ }
+ }
+ \int_incr:N \l_tmpa_int
+ }
+ \bool_if:NT \l__nmc_recur_ellipsis_bool
+ { \seq_put_right:Nn #1{ \ldots } }
+ }
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\keys_define:nn { numerica }
+ {
+ iter-do .int_set:N = \l__nmc_iter_total_int,
+ iter-see-last .int_set:N = \l__nmc_iter_view_int,
+ iter-max-iterations .int_set:N = \l__nmc_iter_max_int,
+ iter-extra-rounding .int_set:N = \l__nmc_iter_extra_int,
+ iter-reuse .int_set:N = \l__nmc_iter_reuse_int,
+
+ iter-do .default:n = 5,
+ iter-see-last .default:n = 4,
+ iter-max-iterations .default:n = 100,
+ iter-extra-rounding .default:n = 0,
+ iter-reuse .default:n = 0,
+%
+ solve-max-steps .int_set:N = \l__nmc_solve_max_int,
+ solve-extra-rounding .int_set:N = \l__nmc_solve_extra_int,
+ solve-first-step .tl_set:N = \l__nmc_solve_step_tl,
+ solve-reuse .int_set:N = \l__nmc_solve_reuse_int,
+
+ solve-max-steps .default:n = 100,
+ solve-extra-rounding .default:n = 0,
+ solve-first-step .default:n = 1,
+ solve-reuse .default:n = 0,
+%
+ recur-do .int_set:N = \l__nmc_recur_total_int,
+ recur-see-first .int_set:N = \l__nmc_recur_first_int,
+ recur-see-last .int_set:N = \l__nmc_recur_last_int,
+ recur-reuse .int_set:N = \l__nmc_recur_reuse_int,
+
+ recur-do .default:n = 7,
+ recur-see-first .default:n = 3,
+ recur-see-last .default:n = 2,
+ recur-reuse .default:n = 0
+ }
+\keys_set_known:nn { numerica }
+ {
+ iter-do,iter-see-last,iter-max-iterations,
+ iter-extra-rounding,iter-reuse,
+ solve-variable,solve-first-step,solve-max-steps,
+ solve-extra-rounding,solve-reuse,
+ recur-do,recur-see-first,recur-see-last,recur-reuse
+ }
+\keys_define:nn { numerica/iter }
+ {
+ var .tl_set:N = \l__nmc_iter_var_tl,
+ + .int_set:N = \l__nmc_iter_extra_int,
+ max .int_set:N = \l__nmc_iter_max_int,
+ do .int_set:N = \l__nmc_iter_total_int,
+ see .int_set:N = \l__nmc_iter_view_int,
+ reuse .int_set:N = \l__nmc_iter_reuse_int
+ }
+\keys_define:nn { numerica/solve }
+ {
+ var .tl_set:N = \l__nmc_solve_var_tl,
+ + .int_set:N = \l__nmc_solve_extra_int,
+ max .int_set:N = \l__nmc_solve_max_int,
+ dvar .tl_set:N = \l__nmc_solve_step_tl,
+ reuse .int_set:N = \l__nmc_solve_reuse_int
+ }
+\keys_define:nn { numerica/recur }
+ {
+ do .int_set:N = \l__nmc_recur_total_int,
+ see1 .int_set:N = \l__nmc_recur_first_int,
+ see2 .int_set:N = \l__nmc_recur_last_int,
+ ... .code:n = \bool_set_true:N \l__nmc_recur_ellipsis_bool,
+ reuse .int_set:N = \l__nmc_recur_reuse_int
+ }
+% end of `numerica-plus.def' \ No newline at end of file