% !TeX encoding = UTF-8 % Ce fichier contient le code de l'extension "tuple" % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \def\tplname {tuple} % \def\tplversion {0.2} % % % \def\tpldate {2024/12/20} % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %____________________________________________________________________ % Author : Christian Tellechea | % Status : Maintained | % Email : unbonpetit@netc.fr | % Package URL: https://www.ctan.org/pkg/tuple | % Copyright : Christian Tellechea 2024 | % Licence : Released under the LaTeX Project Public License v1.3c | % or later, see http://www.latex-project.org/lppl.txt | % Files : 1) tuple.tex | % 2) tuple.sty | % 3) README | % 4) tuple-doc-fr.tex | % 5) tuple-doc-fr.pdf | % 6) tuple-doc-en.tex | % 7) tuple-doc-en.pdf | %-------------------------------------------------------------------- \csname tpl_load_once\endcsname \expandafter\let\csname tpl_load_once\endcsname\endinput \expandafter\edef\csname tpl_restorecatcode\endcsname{\catcode\number`\_=\the\catcode`\_\relax } \catcode`\_11 \def\tpl_exec_first\fi\tpl_exec_second#1#2{\fi#1} \def\tpl_exec_second#1#2{#2} \ifdefined\tpl_fromsty\tpl_exec_first\fi\tpl_exec_second {% \def\tpl_error#1{\PackageError\tplname{#1}{Read the \tplname\space manual}}% pour LaTeX } {% \def\tpl_error#1{\errmessage{Package \tplname\space Error: #1^^J}}% pour TeX \immediate\write -1 {Package: \tpldate\space v\tplversion\space Expandable operations for tuples of numbers (CT)}% \input expl3-generic.tex % pour fp }% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Macros diverses %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\tpl_stripsp#1{% \def\tpl_stripsp##1##2{\expanded{\tpl_stripsp_i\_marksp##2\__nil\_marksp#1\_marksp\_nil{##1}}}% \def\tpl_stripsp_i##1\_marksp#1##2\_marksp##3\_nil{\tpl_stripsp_ii##3##1##2\__nil#1\__nil\_nil}% \def\tpl_stripsp_ii##1#1\__nil##2\_nil{\tpl_stripsp_iii##1##2\_nil}% \def\tpl_stripsp_iii##1##2\__nil##3\_nil##4{\unexpanded{##4{##2}}}% } \tpl_stripsp{ } \def\tpl_swaparg#1#2{#2{#1}} \def\tpl_e_second#1#2{\expandafter\tpl_swaparg\expandafter{#2}{#1}} \def\tpl_x_second#1#2{\expandafter\tpl_swaparg\expandafter{\expanded{#2}}{#1}} \def\tpl_swaptwo#1#2{#2#1} \def\tpl_e_after#1#2{\expandafter\tpl_swaptwo\expandafter{#2}{#1}} \def\tpl_x_after#1#2{\expandafter\tpl_swaptwo\expandafter{\expanded{#2}}{#1}} \def\tpl_error_inmethod#1{{\tpl_error{#1}}{-1}} \def\tpl_gobone#1{} \def\tpl_gobtonil#1\_nil{} \def\tpl_firsttonil#1#2\_nil{#1} \def\tpl_antefi#1\fi{\fi#1} \def\tpl_testifx#1{\ifx#1\tpl_exec_first\fi\tpl_exec_second} \def\tpl_testifnum#1{\ifnum#1\tpl_exec_first\fi\tpl_exec_second} \def\tpl_testifcsname#1{\ifcsname#1\endcsname\tpl_exec_first\fi\tpl_exec_second} \def\tpl_cs_enxp#1{\expandafter\noexpand\csname#1\endcsname} \def\tpl_ifempty#1#2#3{\tpl_ifempty_a#1\_YN{#3}\_YN{#2}\_nil} \def\tpl_ifempty_a#1#2\_YN#3#4\_nil{#3} \def\tpl_foreach#1\in#2\do#3{% #1=macro recevant chaque élément #2=liste d'éléments #3=code \def\tpl_foreach_a##1,{% \ifx\tpl_foreach_a##1\else \def#1{##1}% #3% \expandafter\tpl_foreach_a \fi }% \expandafter\tpl_foreach_a#2,\tpl_foreach_a,% 1-développer #2 au cas où... } %--------------- % indexage développable d'un tuple %--------------- \def\tpl_index_tuple#1{\tpl_index_tuple_a0#1,\relax,}% \def\tpl_index_tuple_a#1#2,{% TODO : le faire 8 par 8 ? \ifx\relax#2\else \tpl_antefi #1:#2,\tpl_e_second\tpl_index_tuple_a{\the\numexpr#1+1}% \fi% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Choix options %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\tpl_testifstreq#1#2{% teste si #1=#2 \tpl_stripsp{\def\tpl__tmpa}{#1}% \tpl_stripsp{\def\tpl__tmpb}{#2}% \tpl_testifx{\tpl__tmpa\tpl__tmpb} } \def\tplsetmode#1{% \tpl_testifstreq{#1}{int} {% \tpl_set_mode_a#1:\_nil } {% \tpl_ifddot{#1} {\tpl_set_mode_a#1\_nil} {\tpl_error{":" expected in "\detokenize{#1}"}}% }% } \def\tpl_set_mode_a#1:#2\_nil{% \let\tpl_expr_eval\fpeval \tpl_testifstreq{#1}{int} {% \def\tplfpcompare##1##2##3{\ifnum##1##2##3 \tpl_exec_first\fi\tpl_exec_second}% \def\tpl_item_add##1##2{\the\numexpr##1+##2\relax}% \def\tpl_item_addsq##1##2{\the\numexpr##1+##2*##2\relax}% } {% \tpl_testifstreq{#1}{dec} {% \tpl_testifstreq{#2}{long} {% \tpl_e_after{\let\tplfpcompare}{\csname fp_compare:nNnTF\endcsname}% \def\tpl_item_add##1##2{\fpeval{##1+##2}}% \def\tpl_item_addsq##1##2{\fpeval{##1+##2*##2}}% } {% \tpl_testifstreq{#2}{short} {% \def\tplfpcompare##1##2##3{\ifdim##1pt##2##3pt \tpl_exec_first\fi\tpl_exec_second}% \let\tpl_item_add\tpl_short_short_add \def\tpl_item_addsq##1##2{\tpl_x_second\tpl_short_short_add{\tpl_short_mult{##2}{##2}}{##1}}% }% {% \tpl_error{number 'short' or 'long' expected in '\detokenize{#1:#2}'}% }% }% } {% \tpl_error{number "long" or "dec" expected in "\detokenize{#1:#2}"}% }% }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Moteur rudimentaire de calcul %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Macros développables sur les % décimaux courts "#8.#8" \def\tpl_gob_zeros#1{% \tpl_testifx{0#1} \tpl_gob_zeros {\tpl_testifx{\empty#1}0{#1}}% } \def\tpl_split_iv_iv#1{\tpl_split_iv_iv_a#1{}{}{}{}{}{}{}{}{}\_nil}% coupe le nombre #1 en 2 nombres de 4 chiffres \def\tpl_esplit_iv_iv#1{\expandafter\tpl_split_iv_iv_a#1{}{}{}{}{}{}{}{}{}\_nil}% coupe le nombre #1 en 2 nombres de 4 chiffres \def\tpl_split_iv_iv_a#1#2#3#4#5#6#7#8#9{\tpl_split_iv_iv_b#9#8#7#6#5#4#3#2#1000000000} \def\tpl_split_iv_iv_b#1#2#3#4#5#6#7#8#9{{#9#8#7#6#5}{#4#3#2#1}\tpl_gobtonil} \def\tpl_pack_iv_iv#1{\tpl_pack_iv_iv_a#100000000\_nil} \def\tpl_pack_iv_iv_a#1#2#3#4#5#6#7#8{{#1#2#3#4}{#5#6#7#8}\tpl_gobtonil} %--------------- % multiplication #8.#8 * #8*#8 -> #16.#8 %--------------- \def\tpl_ifdot#1#2#3{\tpl_ifdot_a#1\_YN{#2}\mark_dot.\_YN{#3}\mark_dot\_nil}% #1 contient-il "." ? #2=T #3=F \def\tpl_ifdot_a#1.#2\_YN#3\mark_dot#4\_nil{#3}% \def\tpl_hi#1{\expandafter\tpl_hi_a\the\numexpr#1\relax{}{}{}{}{}{}{}{}{}\_nil} \def\tpl_hi_a#1#2#3#4#5#6#7#8#9{\tpl_hi_b#9#8#7#6#5#4#3#2#1000000000} \def\tpl_hi_b#1#2#3#4#5#6#7#8#9{#9#8#7#6#5\tpl_gobtonil} \def\tpl_pack_hi_unpack_lo#1#2{\expandafter\tpl_pack_hi_unpack_lo_a\the\numexpr#2\relax{}{}{}{}{}{}{}{}{}\_nil{#1}} \def\tpl_pack_hi_unpack_lo_a#1#2#3#4#5#6#7#8#9{\tpl_pack_hi_unpack_lo_b#9#8#7#6#5#4#3#2#1000000000} \def\tpl_pack_hi_unpack_lo_b#1#2#3#4#5#6#7#8#9{\tpl_pack_hi_unpack_lo_c{#9#8#7#6#5}{#4#3#2#1}} \def\tpl_pack_hi_unpack_lo_c#1#2#3\_nil#4{#4{#1}#2} \def\tpl_short_mult#1#2{% #1=a,b #2=c,d (a,b,c,d 8 chiffres max chacun) \tpl_short_mult_a#1\relax#2\relax } \def\tpl_short_mult_a#1#2\relax#3#4\relax{% \tpl_x_after\tpl_short_mult_b{\unless\ifx-#1+\fi#1#2\relax\unless\ifx-#3+\fi#3#4\relax}% } \def\tpl_short_mult_b#1#2\relax#3#4\relax{% \unless\ifx#1#3-\fi \tpl_x_after\tpl_short_mult_c{0#2\tpl_ifdot{#2}{}{.0}\relax0#4\tpl_ifdot{#4}{}{.0}\relax}% } \def\tpl_short_mult_c#1.#2\relax#3.#4\relax{% #1=hi(a) \tpl_x_after\tpl_short_mult_d{\tpl_split_iv_iv{#1}\tpl_pack_iv_iv{#2}\tpl_split_iv_iv{#3}\tpl_pack_iv_iv{#4}}% } \def\tpl_short_mult_d#1#2#3#4#5#6#7#8{% #1=a1 #2=a0 . #3=b1 #4=b0 % * #5=c1 #6=c0 . #7=d1 #8=d0 \tpl_pack_hi_unpack_lo{\tpl_short_mult_e{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}{% #8*#2+#3*#7+#6*#4+\tpl_hi{#8*#3+#7*#4+\tpl_hi{#4*#8}}% d0a0 + d1b1 +c0b0 + hi(d0b1 + d1b0 + hi(b0d0)) }% } \def\tpl_short_mult_e#1#2#3#4#5#6#7#8#9{% #1=a1 #2=a0 . #3=b1 #4=b0 * #5=c1 #6=c0 . #7=d1 #8=d0 #9=retenue pour rang suivan \tpl_pack_hi_unpack_lo{\tpl_short_mult_f{#1}{#2}{#3}{#5}{#6}{#7}}{#9+#8*#1+#7*#2+#6*#3+#5*#4}% d0a1+d1a0+c0b1+c1b0 } \def\tpl_short_mult_f#1#2#3#4#5#6#7{% #1=a1 #2=a0 #3=b1 #4=c1 #5=c0 #6=d1 #7=retenue \tpl_pack_hi_unpack_lo{\tpl_short_mult_g{#1}{#2}{#4}{#5}}{#7+#1*#6+#2*#5+#3*#4}.% d1a1+c0a0+c1b1% } \def\tpl_short_mult_g#1#2#3#4#5{% #1=a1 #2=a0 #3=c1 #4=c0 #5=retenue \tpl_pack_hi_unpack_lo{\tpl_short_mult_h{#1}{#3}}{#5+#1*#4+#2*#3}% } \def\tpl_short_mult_h#1#2#3{\expandafter\tpl_gob_zeros\the\numexpr#1*#2+#3\relax} %--------------- % addition #16.#8 + #16.#8 -> #16.#8 (décimaux non signés) %--------------- \def\tpl_split_viii_viii#1{\tpl_split_viii_viii_a#1{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}\_nil} \def\tpl_split_viii_viii_a#1#2#3#4#5#6#7#8{\tpl_split_viii_viii_b{#8#7#6#5#4#3#2#1}} \def\tpl_split_viii_viii_b#1#2#3#4#5#6#7#8#9{\tpl_split_viii_viii_c#9#8#7#6#5#4#3#2#100000000000000000} \def\tpl_split_viii_viii_c#1#2#3#4#5#6#7#8{\tpl_split_viii_viii_d{#8#7#6#5#4#3#2#1}} \def\tpl_split_viii_viii_d#1#2#3#4#5#6#7#8#9{{#9#8#7#6#5#4#3#2}{#1}\tpl_gobtonil} \def\tpl_decpart_format_viii#1{\tpl_decpart_format_viii_a#100000000\_nil} \def\tpl_decpart_format_viii_a#1#2#3#4#5#6#7#8{#1#2#3#4#5#6#7#8\tpl_gobtonil} \def\tpl_shortadd#1#2{% #1=décimal ou entier ; #2 de la forme 'x.y' \tpl_x_after{\tpl_shortadd_a#1}{\tpl_ifdot{#1}{}{.0}}\relax#2\relax } \def\tpl_shortadd_a#1.#2\relax#3.#4\relax{% a.b + c.d \tpl_x_after\tpl_shortadd_b{\tpl_split_viii_viii{#1}\tpl_split_viii_viii{#3}{\the\numexpr\tpl_decpart_format_viii{#2}+\tpl_decpart_format_viii{#4}\relax}}% } \def\tpl_shortadd_b#1#2#3#4#5{% #1=hi8(a) #2=lo8(a) #3=hi8(c) #4=lo8(c) #5=b+c \tpl_x_after{\tpl_shortadd_c{#1}{#3}}{\the\numexpr#2+#4\tpl_testifnum{#5>99999999 }{+1\relax!.\tpl_gobone}{\relax!.}#5}% } \def\tpl_shortadd_c#1#2#3!{% #1=hi8(a) #2=hi8(c) #3=lo8(a)+lo8(c)+retenue \the\numexpr#1+#2\tpl_testifnum{#3>99999999 }{+1\relax\tpl_gobone}{\relax}#3% } %--------------- % addition entiers signés #8.#8 %--------------- \def\tpl_intpart_format#1{% \tpl_ifempty{#1}{+0}{\tpl_intpart_format_a#1\_nil}% } \def\tpl_intpart_format_a#1#2\_nil{% \ifx#1--\tpl_ifempty{#2}0{}% \else \ifx#1++\tpl_ifempty{#2}0{}% \else+#1% \fi \fi#2% } \def\tpl_short_short_add#1#2{% a.b + c.d \tpl_x_after\tpl_short_short_add_a{#1\tpl_ifdot{#1}{}{.0}\relax#2\tpl_ifdot{#2}{}{.0}\relax}% } \def\tpl_short_short_add_a#1.#2\relax#3.#4\relax{% \tpl_x_after\tpl_short_short_add_b{% \tpl_intpart_format{#1}.\tpl_decpart_format_viii{#2}\relax \tpl_intpart_format{#3}.\tpl_decpart_format_viii{#4}\relax% }% } \def\tpl_short_short_add_b#1#2.#3\relax#4#5.#6\relax{% #1=+/- #2.#3 "+" #4=+/- #5.#6 \tpl_testifx{#1#4}% mêmes signes ? {% \ifx-#1-\fi% afficher le signe - \tpl_e_second\tpl_short_short_add_c{\the\numexpr#3+#6}{#2}{#5}% } {% signes différents \tpl_x_after\tpl_short_short_add_d{\the\numexpr#1#2#4#5\relax.\the\numexpr#1#3#4#6\relax}\_nil }% } \def\tpl_short_short_add_c#1#2#3{% relatifs de mêmes signes : #1=somme (dec part) #2=intpart(a) #3=intpart(b) \the\numexpr#2+#3\ifnum#1>99999999 +1\fi.\tpl_decpart_format{#1}% } \def\tpl_short_short_add_d#1.#2\_nil{% \tpl_x_after\tpl_short_short_add_e{\unless\ifnum#1<0 +\fi#1.\unless\ifnum#2<0 +\fi}#2\_nil } \def\tpl_short_short_add_e#1#2.#3#4\_nil{%résultat : #1=signe #2=intpart #3=signe #4=decpart \ifx#1#3% memes signes \the\numexpr#1#2\relax.\expandafter\tpl_gobone\the\numexpr#4+100000000\relax% \else \ifnum#2=0 #30.\tpl_decpart_format{#4}% prendre le signe de decpart \else \ifnum#4=0 #1#2% \else \tpl_x_after\tpl_short_short_add_f{\the\numexpr#1#2#31\relax.\expandafter\tpl_abs\the\numexpr#3#4#1100000000\relax}\_nil{#1}% \fi \fi \fi } \def\tpl_short_short_add_f#1.#2\_nil#3{% #1=intpart final #2=decpart final #3=signe intpart \ifnum#1=0 #3\fi#1.\tpl_decpart_format{#2}% } \def\tpl_abs#1{\unless\ifx-#1#1\fi} \def\tpl_decpart_format#1{\expandafter\tpl_decpart_format_a\the\numexpr100000000+#1\relax\_nil} \def\tpl_decpart_format_a#1#2#3#4#5#6#7#8#9{\expandafter\tpl_decpart_format_b\the\numexpr#9#8#7#6#5#4#3#2\relax{}{}{}{}{}{}{}{}{}} \def\tpl_decpart_format_b#1#2#3#4#5#6#7#8{#8#7#6#5#4#3#2#1\tpl_gobtonil} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Quicksort développable %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %--------------- % Effectue un quicksort en indexant en % même temps les éléments sous la forme "idx:val" %--------------- \def\tpl_quicksort_and_index#1{\tpl_quicksort_and_index_a0;{#1}?}% #1= tuple finissant par "," \def\tpl_quicksort_and_index_a#1;#2{\tpl_quicksort_and_index_b{#1}#2!,}% #1=index de départ #2= tuple finissant par "," \def\tpl_quicksort_and_index_b#1#2,{% \tpl_testifx{!#2} {\tpl_quicksort_and_index_d{#1}} {\tpl_quicksort_and_index_c{#1}{}{}{#2}}% } \def\tpl_quicksort_and_index_c#1#2#3#4#5,{% #1=index courant #2=part lt #3=part gt #4=pivot #5=élément courant \tpl_testifx{!#5}% partition achevée -> partitionner "part lt" et passer les arguments pour la macro {% \tpl_quicksort_and_index_d lancée à la fin du partitionnement de "part lt" \tpl_quicksort_and_index_a#1;{#2}{#4}{#3}% arg {#4}{#3} lus à la fin par \tpl_quicksort_and_index_d } {% \tplfpcompare{#5}<{#4} {\tpl_quicksort_and_index_c{#1}{#2#5,}{#3}} {\tpl_quicksort_and_index_c{#1}{#2}{#3#5,}}% {#4}% }% } \def\tpl_quicksort_and_index_d#1#2{% #1=index ancien #2=pivot #3=part gt (à suivre, non lu par cette macro) \ifx?#2\else\tpl_antefi#1:#2,\expandafter\tpl_quicksort_and_index_a\the\numexpr#1+1;\fi } %TODO : insertion sort && fusion sort %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Macros pour set, get, split %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\tpl_csdef#1{\expandafter\def\csname#1\endcsname} \def\tpl_csedef#1{\expandafter\edef\csname#1\endcsname} \tpl_foreach\__temp\in{1,2,3,4,5,6,7,8,9}\do{% définition des macros qui parcourent le tuple indexé \tpl_csdef {get_\__temp\expandafter}\expandafter##\expandafter1\__temp:##2,{##2\tpl_gobtonil}% \tpl_csedef{split_\__temp\expandafter}\expandafter\_nil\expandafter##\expandafter1\__temp:##2,{##1\__temp:##2,?}% \tpl_csedef{set_\__temp\expandafter}\expandafter##\expandafter1\expandafter\_nil\expandafter##\expandafter2\__temp:##3,{##2\__temp:##1,}% \tpl_csdef {gobto_\the\numexpr\__temp+1\relax 0\expandafter}\expandafter##\expandafter1\__temp 9:##2,{}% \tpl_csdef {gobto_\the\numexpr\__temp+1\relax 00\expandafter}\expandafter##\expandafter1\__temp 99:##2,{}% \tpl_csdef {gobto_\the\numexpr\__temp+1\relax 000\expandafter}\expandafter##\expandafter1\__temp 999:##2,{}% \tpl_csdef {gobto_\the\numexpr\__temp+1\relax0000\expandafter}\expandafter##\expandafter1\__temp9999:##2,{}% \tpl_csedef{passto_\__temp 0\expandafter}\expandafter##\expandafter1\expandafter\_nil\expandafter##\expandafter2\the\numexpr\__temp 0-1:##3,{##2\the\numexpr\__temp 0-1:##3,##1\noexpand\_nil}% \tpl_csedef{passto_\__temp 00\expandafter}\expandafter##\expandafter1\expandafter\_nil\expandafter##\expandafter2\the\numexpr\__temp 00-1:##3,{##2\the\numexpr\__temp 00-1:##3,##1\noexpand\_nil}% \tpl_csedef{passto_\__temp 000\expandafter}\expandafter##\expandafter1\expandafter\_nil\expandafter##\expandafter2\the\numexpr\__temp 000-1:##3,{##2\the\numexpr\__temp 000-1:##3,##1\noexpand\_nil}% \tpl_csedef{passto_\__temp0000\expandafter}\expandafter##\expandafter1\expandafter\_nil\expandafter##\expandafter2\the\numexpr\__temp0000-1:##3,{##2\the\numexpr\__temp0000-1:##3,##1\noexpand\_nil}% } \tpl_csdef{get_0}#10:#2,{#2\tpl_gobtonil}% \tpl_csdef{split_0}\_nil#10:#2,{#10:#2,?}% \tpl_csdef{set_0}#1\_nil#20:#3,{#20:#1,}% \tpl_csdef{gobto_10}#19:#2,{} \tpl_csdef{gobto_100}#199:#2,{} \tpl_csdef{gobto_1000}#1999:#2,{} \tpl_csdef{gobto_10000}#19999:#2,{} \tpl_csdef{gobto_00}{} \tpl_csdef{gobto_000}{} \tpl_csdef{gobto_0000}{} \tpl_csdef{passto_00}{} \tpl_csdef{passto_000}{} \tpl_csdef{passto_0000}{} \def\tpl_reverse#1{\tpl_reverse_a#1{}{}{}{}{}{}{}{}{}\_nil} \def\tpl_reverse_a#1#2#3#4#5#6#7#8#9{#9#8#7#6#5#4#3#2#1\tpl_gobtonil} %--------------- % getitem (développable) %--------------- \def\tpl_getitem#1#2{% #1=index #2=tuple \tpl_x_after\tpl_getitem_a{\tpl_reverse{#1}}\relax#2\_nil% #2=tuple (finissant par ",") } \def\tpl_getitem_a#1{% #1=chiffre unités \expandafter\tpl_getitem_b\csname get_#1\endcsname{0}% } \def\tpl_getitem_b#1#2#3{% #1=commandes à exécuter #2=nb de 0 #3=chiffre courant \tpl_testifx{\relax#3} {\tpl_getitem_c#1\_nil} {\tpl_e_second\tpl_getitem_b{\csname gobto_#3#2\endcsname#1}{#20}}% } \def\tpl_getitem_c#1#2\_nil{% \tpl_ifempty{#2} {} {\expanded{\unexpanded{\tpl_getitem_c#2\_nil}\expandafter\expandafter\expandafter}}#1% } %--------------- % set item (développable) %-------------- \def\tpl_setitem#1#2#3{% #1=index #2=valeur #3=tuple \tpl_x_after\tpl_setitem_a{{#2}\tpl_reverse{#1}}\relax#3% #3=tuple (finissant par ",") } \def\tpl_setitem_a#1#2{% #1= valeur #2=chiffre unités \tpl_e_second\tpl_setitem_b{\csname set_#2\endcsname#1}{0}% } \def\tpl_setitem_b#1#2#3{% #1=commandes à exécuter #2=nb de 0 #3=chiffre courant \tpl_testifx{\relax#3} {#1\_nil} {\tpl_e_second\tpl_setitem_b{\csname passto_#3#2\endcsname#1}{#20}}% } %--------------- % split at index (développable) %-------------- \def\tpl_split#1#2{% #1=index #2=tuple -> coupe avec "?" le tuple après l'index #1 et renvoie 'tuple1?tuple2' \tpl_x_after\tpl_split_a{\tpl_reverse{#1}}\relax#2% #2=tuple (finissant par ",") } \def\tpl_split_a#1{% #1=chiffre unités \tpl_e_second\tpl_setitem_b{\csname split_#1\endcsname}{0}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Constructeur de tuple %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\newtuple#1{% \tpl_x_after\tpl_newtuple_a{\tpl_stripsp\detokenize{#1}}\_nil } \def\tpl_newtuple_a#1\_nil#2{% \tpl_ifempty{#1} {% \tpl_error{Impossible to define a tuple with an empty name}% } {% \tpl_testifcsname{tpl_tuple(#1)} {\tpl_error{Tuple '#1' already defined}}% {\tpl_csedef{tpl_tuple(#1)}{\tpl_e_second\tpl_newtuple_b{\detokenize\expandafter{\expanded{#2}}}}}% }% } %--------------- % \tpl_newtuple_b est développable et renvoie : % (len,sum,sumsq){tuple indexé}{tuple ordonné indexé} %-------------- \def\tpl_newtuple_b#1{% \tpl_ifempty{#1} {(0,0,0,nan,nan){}{}} {\tpl_newtuple_c(0,0,0){}{}#1,\relax,}% } \def\tpl_newtuple_c(#1,#2,#3)#4#5#6,{% #1=index courant #2=sum #3=sumsq #4=éléments lus indexés #5=éléments lus désindexés #6=élément courant \tpl_testifx{\relax#6}% fin atteinte -> trouver min, max et renvoyer le tout "(len,sum,sum:x^2,min,max){tuple indexé}{tuple ordonné indexé}" {\tpl_x_second{(#1,#2,#3){#4}}{\tpl_e_second\tpl_quicksort_and_index{\tpl_gobone#5,}}}% manger ',' qui commence #5 {\tpl_stripsp\tpl_newtuple_d{#6}(#1,#2,#3){#4}{#5}}% } \def\tpl_newtuple_d#1{% #1=item en cours \tpl_ifempty{#1} {% \tpl_newtuple_c } {% \tpl_ifddot{#1}% si ":" est contenu dans #1, c'est indexé {\tpl_newtuple_f#1\_nil}% traiter ce qui est après ":" {\tpl_newtuple_e{#1}}% }% } \def\tpl_newtuple_e#1(#2,#3,#4)#5#6{% #1=item en cours #2=index courant #3=sum #4=sumsq #5=éléments déjà triés #6=elements non indexés \tpl_x_after\tpl_newtuple_c{(\the\numexpr#2+1,\tpl_item_add{#3}{#1},\tpl_item_addsq{#4}{#1})}{#5#2:#1,}{#6,#1}% } \def\tpl_newtuple_f#1:#2\_nil{% \tpl_ifempty{#2} {\tpl_newtuple_c} {\tpl_newtuple_e{#2}}% } \def\tpl_ifddot#1#2#3{\tpl_ifddot_a#1\_YN{#2}\mark_ddot:\_YN{#3}\mark_ddot\_nil}% #1 contient-il ":" ? #2=T #3=F \def\tpl_ifddot_a#1:#2\_YN#3\mark_ddot#4\_nil{#3}% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Les méthodes %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\tpl_error_only_for_tuples #1{\tpl_error_inmethod{Method '#1' only available for tuples}} \def\tpl_error_no_argument #1#2{\tpl_error_inmethod{Method '#1' does not accept argument '\detokenize{#2}'}} \def\tpl_error_argument_required#1{\tpl_error_inmethod{Method '#1' requires an argument}} \def\tpl_error_empty_tuple#1{\tpl_error_inmethod{Method '#1' not compatible with an empty tuple}} %--------------- % Méthode len (développable) %-------------- \def\tpl_method_len#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{len}} {\tpl_method_len_a#2\_nil}% } {% \tpl_error_no_argument{len}{#1}% }% } \def\tpl_method_len_a(#1,#2\_nil{{#1}{0}}% renvoie un nombre %--------------- % Méthode sum (développable) %-------------- \def\tpl_method_sum#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{sum}} {\tpl_method_sum_a#2\_nil}% } {% \tpl_error_no_argument{sum}{#1}%% }% } \def\tpl_method_sum_a(#1,#2,#3\_nil{{#2}{0}}% renvoie un nombre %--------------- % Méthode min (développable) %--------------- \def\tpl_method_min#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{min}} {\tpl_method_min_a#2\_nil}% } {% \tpl_error_no_argument{min}{#1}%% }% } \def\tpl_method_min_a#1)#2#3\_nil{% \tpl_ifempty{#3} {\tpl_error_empty_tuple{min}} {\tpl_method_min_b#3\_nil}% } \def\tpl_method_min_b0:#1,#2\_nil{{#1}{0}}% renvoie un nombre %--------------- % Méthode max (développable) %--------------- \def\tpl_method_max#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{max}} {\tpl_method_max_a#2\_nil}% } {% \tpl_error_no_argument{max}{#1}% }% } \def\tpl_method_max_a(#1,#2)#3#4\_nil{% \tpl_ifempty{#4} {\tpl_error_empty_tuple{max}} {{\tpl_e_second\tpl_getitem{\the\numexpr#1-1}{#4}}{0}}% renvoie un nombre } %--------------- % Méthode mean (développable) %--------------- \def\tpl_method_mean#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{mean}} {\tpl_method_mean_a#2\_nil}% } {% \tpl_error_no_argument{mean}{#1}%% }% } \def\tpl_method_mean_a(#1,#2,#3\_nil{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_testifnum{#1=0 } {\tpl_error_empty_tuple{mean}} {{\tpl_expr_eval{#2/#1}}{0}}% renvoie un nombre }% %--------------- % Méthode med (développable) %--------------- \def\tpl_method_med#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{med}} {\tpl_method_med_a#2\_nil}% } {% \tpl_error_no_argument{med}{#1}%% }% } \def\tpl_method_med_a(#1,#2)#3#4\_nil{% \tpl_testifnum{#1=0 } {\tpl_error_empty_tuple{med}} {\tpl_method_quantile_a0.5\_nil(#1,#2){#3}{#4}\_nil}% renvoie un nombre } %--------------- % Méthode quantile (développable) %--------------- \def\tpl_method_quantile#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_argument_required{quantile}% }% {% \tpl_testifnum{#3<1 } {% \tpl_error_only_for_tuples{quantile}% } {% \tpl_testifnum{0\ifdim #1pt<0pt \else1\fi\ifdim#1pt<1pt 1\fi=11 }% si #1 dans [0 ; 1[ {\tpl_method_quantile_a#1\_nil#2\_nil}% {\tpl_error_inmethod{Method 'quantile': argument '#1' not in [0;1-]}}% }% }% } \def\tpl_method_quantile_a#1\_nil(#2,#3)#4#5\_nil{% \tpl_testifnum{#2=0 } {\tpl_error_empty_tuple{quantile}} {\tpl_x_after\tpl_method_quantile_b{{\tpl_expr_eval{(#2-1)*#1+1}}{\tpl_expr_eval{trunc((#2-1)*#1+1)}}}{#5}}% renvoie un nombre } \def\tpl_method_quantile_b#1#2#3{% #1=(len-1)*p+1 #2=E(#1) #3=tuple trié {% \tpl_expr_eval{% interpolation linéaire (1-#1+#2)*\tpl_e_second\tpl_getitem{\the\numexpr#2-1\relax}{#3}% +% (#1-#2)*\tpl_getitem{#2}{#3}% }% }% {0}% } %--------------- % Méthode stdev (développable) %--------------- \def\tpl_method_stdev#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{stdev}} {\tpl_method_stdev_a#2\_nil}% } {% \tpl_error_no_argument{stdev}{#1}%% }% } \def\tpl_method_stdev_a(#1,#2,#3)#4\_nil{% \tpl_testifnum{#1=0 } {\tpl_error_empty_tuple{stdev}} {{\tpl_expr_eval{sqrt(#3/#1-(#2/#1)**2)}}{0}}% renvoie un nombre } %--------------- % Méthode get (développable) %--------------- \def\tpl_method_get#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_inmethod{Method 'get': argument required}% } {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{get}}% {\tpl_e_second\tpl_method_get_a{\the\numexpr#1\relax}#2\_nil}% }% } \def\tpl_method_get_a#1(#2,#3)#4#5\_nil{% \tpl_testifnum{#2=0 } {% \tpl_error_empty_tuple{get}% } {% \tpl_testifnum{0\ifnum#1>-1 1\fi\ifnum#1<#2 1\fi=11 }% si index dans [0 ; len -1] {% {\tpl_getitem{#1}{#4}}{0}% } {% \tpl_testifnum{0\ifnum#1<0 1\fi\ifnum\numexpr#1+#2+1>0 1\fi=11 }% si index dans [-len ; -1] {{\tpl_e_second\tpl_getitem{\the\numexpr#1+#2\relax}{#4}}{0}} {\tpl_error_inmethod{Method 'get': invalid index '\detokenize{#1}'}}% }% }% } %--------------- % Méthode set (développable) %--------------- \def\tpl_method_set#1#2#3{% #1=arg méthode ("index1:val1,index2:val2, etc") #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_inmethod{Method 'set': argument required}% } {\tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{set}}% {\tpl_x_after\tpl_method_set_a{#1}\_nil#2\_nil}% xdévelopper #1 et dégrouper #1 et #3 }% } \def\tpl_method_set_a#1\_nil(#2,#3)#4#5\_nil{% #2=len \tpl_testifnum{#2=0 }% si tuple vide, on envoie '0:0,' avec len=1 {\tpl_method_set_b{0:0,}{1}#1,\relax:\relax,\_nil} {\tpl_method_set_b{#4}{#2}#1,\relax:\relax,\_nil}% } \def\tpl_method_set_b#1#2#3:#4,{% #1=tuple #2=len #3=index courant #4=valeur courante \tpl_testifx{\relax#3} {% {\tpl_newtuple_b{#1}}{1}\tpl_gobtonil } {% \tpl_testifnum{0\ifnum#3>-1 1\fi\ifnum#3<#2 1\fi=11 }% si index dans [0 ; len-1] {% \tpl_x_second\tpl_method_set_b{\tpl_setitem{#3}{#4}{#1}}{#2}% }% {% \tpl_testifnum{0\ifnum#3<0 1\fi\ifnum\numexpr#3+#2+1>0 1\fi=11 }% si index dans [-len ; -1] {\tpl_x_second\tpl_method_set_b{\tpl_e_second\tpl_setitem{\the\numexpr#3+#2}{#4}{#1}}{#2}} {\tpl_error_inmethod{Method 'set': invalid index '#3'}\tpl_gobtonil}% }% }% } %--------------- % Méthode sorted (développable) %--------------- \def\tpl_method_sorted#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{sorted}}% {\tpl_method_sorted_a#2\_nil}% } {% \tpl_error_no_argument{sorted}{#1}%% }% } \def\tpl_method_sorted_a(#1)#2#3\_nil{% {(#1){\tpl_ifempty{#3}{#2}{#3}}{}}{1}% } %--------------- % Méthode store (_NON_ développable) %--------------- \def\tpl_ifcs#1{% #1 est-il constitué d'une seule séquence de contrôle ? \tpl_testifnum{\tpl_ifempty{#1}0{\tpl_e_second\tpl_ifempty{\tpl_gobone#1}10}\ifnum\expandafter\expandafter\expandafter`\expandafter\tpl_firsttonil\string#1.\_nil=\escapechar1\fi=11 }% } \def\tpl_method_store#1#2#3{% #1=arg méthode #2=len #3=index courant #4=valeur courante \tpl_ifempty{#1} {% \tpl_error_argument_required{store}% } {% \tpl_testifnum{#3<1 } \tpl_method_store_a \tpl_method_store_b #1\_nil#2\_nil }% } \def\tpl_method_store_a#1\_nil#2\_nil{% #1=arg méthode #2=résultat méthodes précédentes \tpl_ifcs{#1} {\unexpanded{{\def#1{#2}}}{-1}}% bloquer le développement {\tpl_error_inmethod{Method 'store': unexpected argument '\detokenize{#1}'}}% } \def\tpl_method_store_b#1\_nil(#2,#3)#4#5\_nil{% #1=arg méthode #2=arg méthode #3=flag #4=résultat méthodes précédentes \tpl_ifempty{#1} {\tpl_error_inmethod{Method 'store': impossible to define a tuple with an empty name}} {{\noexpand\tpl_csedef{tpl_tuple(\tpl_stripsp\detokenize{#1})}{\tpl_e_second\tpl_newtuple_b{\detokenize\expandafter{\expanded{#4}}}}}{-1}}% bypass \newtuple pour permettre de modifier le tuple initial } %--------------- % Méthode split (_NON_ développable) %--------------- \def\tpl_method_split#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes \tpl_ifempty{#1} {% \tpl_error_inmethod{Method 'split': argument required}% } {% \tpl_testifnum{#3>0 } {\tpl_method_split_a#1\_nil#2\_nil}% dégrouper #1 et #3 {\tpl_error_only_for_tuples{split}}% }% } \def\tpl_method_split_a#1#2#3\_nil(#4,#5)#6#7\_nil{% #1=index de coupure #2=nom tuple 1 #3=nom tuple2 \tpl_testifnum{#4=0 } {% \tpl_error_empty_tuple{split}% } {% \tpl_testifnum{\tpl_ifempty{#2}01\tpl_ifempty{#3}01=11 }% si les deux noms ne sont pas vide {% \tpl_testifnum{0\ifnum#1>-1 1\fi\ifnum#1<\numexpr#4-1\relax1\fi=11 }% si #1 dans [0;len-2] {% \tpl_x_after\tpl_method_split_b{\tpl_split{#1}{#6}}?{#2}{#3}% } {% \tpl_testifnum{0\ifnum#1<-1 1\fi\ifnum\numexpr#1+#4+1>0 1\fi=11 }% si #1 dans [-len ; -2] {\tpl_x_after\tpl_method_split_b{\tpl_e_second\tpl_split{\the\numexpr#1+#4}{#6}}?{#2}{#3}} {\tpl_error_inmethod{Method 'split': invalid index '#1"}}% }% } {% \tpl_error_inmethod{Method 'split': empty name not allowed}% }% }% } \def\tpl_method_split_b#1?#2?#3#4{% {% \noexpand\tpl_csedef{tpl_tuple(\tpl_stripsp\detokenize{#3})}{\tpl_e_second\tpl_newtuple_b{\detokenize\expandafter{\expanded{#1}}}}% \noexpand\tpl_csedef{tpl_tuple(\tpl_stripsp\detokenize{#4})}{\tpl_e_second\tpl_newtuple_b{\detokenize\expandafter{\expanded{#2}}}}% }% {-1}% } %--------------- % Méthode add (développable) %--------------- \def\tpl_method_add#1#2#3{% #1=arg méthode (index1:items,index2:items,...) #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_inmethod{Method 'add': argument required}% } {% \tpl_testifnum{#3>0 } {\tpl_x_after\tpl_method_add_a{#1}\_nil#2\_nil}% xdévelopper # et dégrouper #1 et #3 {\tpl_error_only_for_tuples{add}}% }% } \def\tpl_method_add_a#1\_nil(#2,#3)#4#5\_nil{% #2=len \tpl_method_add_b{#4}{#2}#1,\relax:\relax,\_nil } \def\tpl_method_add_b#1#2#3:#4,{% #1=tuple #2=len #3=index courant #4=item(s) \tpl_testifx{\relax#3} {% {\tpl_newtuple_b{#1}}{1}% \tpl_gobtonil } {% \tpl_testifnum{#3<0 } {% \tpl_testifnum{\numexpr#3+#2+2>0 }% si index dans [-n-1 ; -1] {\tpl_x_second{\tpl_method_add_c{#1}{#2}}{\the\numexpr#3+#2+1}{#4}}% {\tpl_error_inmethod{Method 'add': invalid index '\detokenize{#3:#4}'}\tpl_gobtonil}% } {% \tpl_method_add_c{#1}{#2}{#3}{#4}% }% }% } \def\tpl_method_add_c#1#2#3#4{% #1=tuple #2=len #3=index courant #4=item(s) \tpl_testifnum{#3=0 } {% \tpl_method_add_b{#4,#1}{#2}% si index=0 : ajouter au début } {% \tpl_testifnum{#3=#2 } {% \tpl_method_add_b{#1#4,}{#2}% si index=len : ajouter #4 à la fin } {% \tpl_testifnum{0\ifnum#3>0 1\fi\ifnum#3<#2 1\fi=11 }% si index dans [1 ; len-1] {\tpl_x_after\tpl_method_add_d{\expandafter\tpl_split\expandafter{\the\numexpr#3-1}{#1}}?{#4}{#2}} {\tpl_error_inmethod{Method 'add': invalid index '\detokenize{#3:#4}'}\tpl_gobtonil}% }% }% } \def\tpl_method_add_d#1?#2?#3#4{%#1=tuple 1 #2=tuple 2 #3=items à insérer #4=len \tpl_method_add_b{#1#3,#2}{#4}% } %--------------- % Méthode op (développable) %--------------- \def\tpl_eval_op#1#2{\tpl_subst_idx_a#1\?{\tpl_subst_idx_b#1\_nil{#2}}\_markit idx\?{\tpl_subst_val{#1}}\_markit\_nil} \def\tpl_subst_idx_a#1idx#2\?#3\_markit#4\_nil{#3}% \def\tpl_subst_idx_b#1idx#2\_nil#3{\tpl_eval_op{#1#3#2}{#3}} \def\tpl_subst_val#1#2{\tpl_subst_val_a#1\?{\tpl_subst_val_b#1\_nil{#2}}\_markit val\?{\tpl_expr_eval{#1}}\_markit\_nil} \def\tpl_subst_val_a#1val#2\?#3\_markit#4\_nil{#3}% \def\tpl_subst_val_b#1val#2\_nil#3{\tpl_subst_val{#1#3#2}{#3}} \def\tpl_method_op#1#2#3{% #1=arg méthode f(idx, val) #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_argument_required{op}% } {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{op}} {\tpl_method_op_a#1\_nil#2\_nil}% }% } \def\tpl_method_op_a#1\_nil#2)#3#4\_nil{% {\tpl_x_second\tpl_newtuple_b{\tpl_method_op_b{#1}#3\relax:\relax,}}{1}% } \def\tpl_method_op_b#1#2:#3,{% \tpl_testifx{\relax#2} {} {#2:\tpl_eval_op{#1}{#2}{#3},\tpl_method_op_b{#1}}% } %--------------- % Méthode filter (développable) %--------------- \def\tpl_method_filter#1#2#3{% #1=arg méthode f(idx, val) #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_argument_required{filter}% } {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{filter}} {\tpl_method_filter_a#1\_nil#2\_nil}% }% } \def\tpl_method_filter_a#1\_nil#2)#3#4\_nil{% {\tpl_x_second\tpl_newtuple_b{\tpl_method_filter_b{#1}#3\relax:\relax,}}{1}% } \def\tpl_method_filter_b#1#2:#3,{% \tpl_testifx{\relax#2} {} {% \tpl_testifnum{\tpl_eval_op{#1}{#2}{#3}=1 } {#2:#3,} {}% \tpl_method_filter_b{#1}% }% } %--------------- % Méthode pos (développable) %--------------- \def\tpl_method_pos#1#2#3{% #1=arg méthode {valeur} #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_argument_required{pos}% } {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{pos}} {\tpl_method_pos_a#1[1]\_nil#2\_nil}% }% } \def\tpl_method_pos_a#1[#2]#3\_nil#4)#5#6\_nil{% {\tpl_method_pos_b{1}{#2}{#1}#5\relax:\relax,\_nil}{0}% } \def\tpl_method_pos_b#1#2#3#4:#5,{% #1=occurrence en cours #2=occurrence souhaitée #3=nombre cherché \tpl_testifx{\relax#4} {% -1\tpl_gobtonil% si occurrence non trouvée, renvoyer -1 } {% \tplfpcompare{#3}={#5}% nombres correspondent ? {% \tpl_testifnum{#1=#2 }% occurrence souhaitée ? {#4\tpl_gobtonil} {\tpl_e_second\tpl_method_pos_b{\the\numexpr#1+1}{#2}{#3}}% }% à la première occurrence, renvoyer #2 {% \tpl_method_pos_b{#1}{#2}{#3}% }% }% } %--------------- % Méthode comp (développable) %--------------- \def\tpl_eval_comp#1#2{\tpl_subst_xa_a#1\?{\tpl_subst_xa_b#1\_nil{#2}}\_markit xa\?{\tpl_subst_xb{#1}}\_markit\_nil} \def\tpl_subst_xa_a#1xa#2\?#3\_markit#4\_nil{#3}% \def\tpl_subst_xa_b#1xa#2\_nil#3{\tpl_eval_comp{#1#3#2}{#3}} \def\tpl_subst_xb#1#2{\tpl_subst_xb_a#1\?{\tpl_subst_xb_b#1\_nil{#2}}\_markit xb\?{\tpl_expr_eval{#1}}\_markit\_nil} \def\tpl_subst_xb_a#1xb#2\?#3\_markit#4\_nil{#3}% \def\tpl_subst_xb_b#1xb#2\_nil#3{\tpl_subst_xb{#1#3#2}{#3}} \def\tpl_method_comp#1#2#3{% #1=arg méthode "{op}{nom tuple B}" #2=résultat méthodes précédentes #3=flag \tpl_ifempty{#1} {% \tpl_error_inmethod{Method 'comp' requires arguments}% } {% \tpl_testifnum{#3<1 } {\tpl_error_only_for_tuples{comp}} {\tpl_method_comp_a#1\_nil#2\_nil}% }% } \def\tpl_method_comp_a#1#2\_nil#3\_nil{% \tpl_testifcsname{tpl_tuple(\tpl_stripsp\detokenize{#2})} {\tpl_x_after\tpl_method_comp_b{{#1}\csname tpl_tuple(\tpl_stripsp\detokenize{#2})\endcsname}#3} {\tpl_error_inmethod{Method 'comp': tuple '#2' undefined}}% } \def\tpl_method_comp_b#1(#2,#3)#4#5(#6,#7)#8#9{% \tpl_testifnum{#2=#6 } {{\tpl_x_second\tpl_newtuple_b{\tpl_method_comp_c{#1}#4\relax:\relax,\_nil#8\relax:\relax,\_nil}}{1}} {\tpl_error_inmethod{Method 'comp' requires tuple with same length}}% } \def\tpl_method_comp_c#1#2:#3,#4\_nil#5:#6,#7\_nil{% \tpl_testifx{\relax#3} {} {#2:\tpl_eval_comp{#1}{#6}{#3},\tpl_method_comp_c{#1}#4\_nil#7\_nil}% } %--------------- % Méthode show (développable ou _NON_ développable, dépend des macros \tplformat et \tplsep) %--------------- \def\tpl_method_show#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag \tpl_testifnum{#3=1 } {{\tpl_method_show_a#2}{0}} {\tpl_error_only_for_tuples{show}}% } \def\tpl_method_show_a#1)#2#3{\tpl_unindex\tplformat\tplsep{#2}} \def\tplformat#1#2{#2}% #1=index en cours #2=item en cours \def\tplsep{, } %--------------- % Méthode end_exe (privée et développable) %--------------- \def\tpl_method_end_exe#1#2#3{% #1=arg méthode #2=résultat méthodes précédentes #3=flag {% \tpl_testifnum{#3=1 } {\tpl_method_end_exe_a#2} {\unexpanded{#2}}% diriger vers l'affichage si flag<1 }% {-1}% } \def\tpl_method_end_exe_a#1)#2#3{\tpl_unindex\tpl_method_end_exe_format\tpl_method_end_exe_sep{#2}} \def\tpl_method_end_exe_format#1#2{#2} \def\tpl_method_end_exe_sep{, } %--------------- % macro \tpl_unindex %--------------- \def\tpl_unindex#1#2#3{% #1=macro pour formater un item #2=macro séparateur #3=tuple indexé \tpl_ifempty{#3} {}% {\tpl_unindex_a{#1}{#2}#3\relax:\relax,}% } \def\tpl_unindex_a#1#2#3:#4,#5{% #1=macro pour formater un item #2=macro séparateur #3=index courant #4=item courant #5=prochain index \unexpanded\expandafter{#1{#3}{#4}}% afficher l'item \tpl_testifx{\relax#5} {% \tpl_unindex_b } {% #2% afficher le séparateur \tpl_unindex_a{#1}{#2}#5% }% } \def\tpl_unindex_b#1,{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% La macro utilisateur \tplexe %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\tplexe#1{% \tpl_exea#1.end_exe.\_nil } \def\tpl_exea#1.{% #1=nom du tuple TODO:tester trié ou pas \tpl_testifcsname{tpl_tuple(\tpl_stripsp\detokenize{#1})} {\expandafter\expandafter\expandafter\tpl_exeb\csname tpl_tuple(\tpl_stripsp\detokenize{#1})\endcsname1} {\tpl_error{Tuple '\detokenize{#1}' not defined}\tpl_gobtonil}% } % Flag % -1 : c'est la dernière méthode appelée, les autres sont ignorées % 0 : résultat est un nombre ou est affichable % 1 : résultat est un tuple \def\tpl_exeb(#1)#2#3#4{% #1=flag #2=données du tuple #3=tuple non indexé #4=tuple indexé \tpl_exec{(#1){#2}{#3}}{#4}%{#5}% grouper les argument du tuple } \def\tpl_exec#1#2{% #1=résultat des dernières méthodes (soit le tuple entier (carac){tupleNTR}{tuple TR}, soit un nombre) #2=flag \tpl_testifnum{#2=-1 } {#1\tpl_gobtonil}% renvoie #1 et ignore toutes les autres méthodes {\tpl_exed{#1}{#2}}% } \def\tpl_exed#1#2#3.{% #1=résultat des dernières méthodes (soit le tuple entier (carac){tupleNTR}{tuple TR}, soit un nombre) #2=flag #3=méthode (et arguments) en cours de traitement \tpl_x_after\tpl_exee{\tpl_split_method_args{#3}}{#1}{#2}% } \def\tpl_exee#1#2#3#4{% #1=nom méthode #2=arg méthode #3=argument laissé par les méthodes #4=flag \tpl_testifcsname{tpl_method_#1} {\tpl_x_after\tpl_exec{\csname tpl_method_#1\endcsname{#2}{#3}{#4}}}% 3 arg à chaque méthode 1er=arg méthode #2=résultat précédent #3=flag {\tpl_error{Unknown method "#1"}\tpl_gobtonil}% } \def\tpl_list_methods{len,sum,min,max,mean,med,quantile,stdev,get,set,sorted,store,split,add,op,filter,pos,comp,show,end_exe} \def\tpl_iftrueempty#1{\if\relax\detokenize{#1}\relax\tpl_exec_first\fi\tpl_exec_second} \tpl_foreach\_temp\in\tpl_list_methods\do{% \tpl_csedef{tpl_try_\_temp}##1{% \tpl_cs_enxp{tpl_try_\_temp _a}##1\noexpand\__nil\_temp\noexpand\___nil\noexpand\_nil }% \tpl_csedef{tpl_try_\_temp _a\expandafter}\expandafter##\expandafter1\_temp##2\_nil{% \noexpand\tpl_iftrueempty{##1}% ##1 ne _doit_ pas être ' ' donc la syntaxe ". method" est invalide {{\_temp}{\noexpand\tpl_sanitize_arg##2}\noexpand\tpl_gobtonil}% <- argument Vrai }% } \def\tpl_split_method_args#1{% #1= -> retour {methode}{arg} ou {methode}{{arg1}{arg2}{arg3}...} \tpl_e_after{\tpl_split_method_args_a{#1}}\tpl_list_methods,\relax,\_nil } \def\tpl_split_method_args_a#1#2,{% \tpl_testifx{\relax#2} {% {\detokenize{#1}}{}\tpl_gobtonil } {% \csname tpl_try_#2\endcsname{#1}% %{} <- inclus dans la macro \tpl_try__a {\tpl_split_method_args_a{#1}}% <- argument Faux }% } \def\tpl_sanitize_arg#1\__nil#2\___nil{\tpl_stripsp\unexpanded{#1}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% La macro utilisateur \gentuple %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\tpl_strip_lastcomma#1{\tpl_strip_lastcomma_i#1\empty\tpl_gobtonil, \empty\_nil}% \def\tpl_strip_lastcomma_i#1, \empty{#1} \def\tpl_id#1{#1} \def\tpl_is_while#1{\tpl_stripsp{\expandafter\tpl_is_while_a\tpl_id}{#1}\while\_nil} \def\tpl_is_while_a#1\while#2\_nil{\tpl_ifempty{#1}{\tpl_is_while_b#2\_nil}{\tpl_exec_second}} \def\tpl_is_while_b#1\while#2\_nil{\tpl_ifempty{#1#2}} \def\tpl_is_until#1{\tpl_stripsp{\expandafter\tpl_is_until_a\tpl_id}{#1}\until\_nil} \def\tpl_is_until_a#1\until#2\_nil{\tpl_ifempty{#1}{\tpl_is_until_b#2\_nil}{\tpl_exec_second}} \def\tpl_is_until_b#1\until#2\_nil{\tpl_ifempty{#1#2}} \def\gentuple#1{% \tpl_x_second\tpl_strip_lastcomma{\tpl_gentuple_a#1\_nil}% } \def\tpl_gentuple_a#1\genrule#2;#3\_nil{% #1=amorce #2=expression de génération #3=\while|\until \tpl_stripsp{\expandafter\tpl_gentuple_b\tpl_id}{#3}\_nil#1\genrule#2;% } \def\tpl_gentuple_b#1#2\_nil#3\genrule#4;{% #1=\while|\until #2=condition #3=amorce #4=expression de génération \tpl_is_while{#1} {% \tpl_gentuple_c0{}{}#3\relax,{#4}{#2}\tpl_gentuple_g } {% \tpl_is_until{#1} {\tpl_gentuple_c0{}{}#3\relax,{#4}{#2}\tpl_gentuple_f} {\tpl_error{\string\while\space or \string\until\space expected before condition}}% }% } \def\tpl_gentuple_c#1#2#3#4,{% #1=index en cours #2=n1,n2,n3,... #3={n1}{n2}{n3}... #4=item d'amorce en cours \tpl_testifx{\relax#4} {#2\tpl_gentuple_e{#1}{#1}{#3}}% afficher l'amorce '#2' puis aller à la macro récursive {\tpl_e_second\tpl_gentuple_c{\the\numexpr#1+1}{#2#4,}{#3{#4}}}% } \def\tpl_gentuple_e#1#2#3#4#5#6{% #1=index en cours #2=nb de variables #3=dernières valeurs #4=expression de génération #5=condition arret #6=\tpl_gentuple_g(while) ou \tpl_gentuple_f(until) \tpl_x_second{#6}{\tpl_expr_eval{\tpl_subst_allvalues{#2}{#4}{#3}{#1}}}% <- #1=valeur pour \i (index courant) {#1}{#2}{#3}{#4}{#5}% } \def\tpl_gentuple_f#1#2#3#4#5#6{% #1=item en cours #2=index en cours #3=nb de variables #4=dernières valeurs #5=expression de génération #6=condition arret (until) #1% afficher '#1,' avant de faire le test \ifnum\tpl_x_second\tpl_subst_val{\tpl_subst_i{#6}{#2}}{#1}=0 % tant que condition d'arrêt non vérifiée \tpl_antefi , % séparateur si pas le dernier \tpl_x_after\tpl_gentuple_e{{\the\numexpr#2+1}{#3}{\tpl_gobone#4{#1}}}{#5}{#6}\tpl_gentuple_f% puis recommencer \fi } \def\tpl_gentuple_g#1#2#3#4#5#6{% #1=item en cours #2=index en cours #3=nb de variables #4=dernières valeurs #5=expression de génération #6=condition de poursuite (while) \ifnum\tpl_x_second\tpl_subst_val{\tpl_subst_i{#6}{#2}}{#1}=1 % tant que condition de poursuite en vérifiée \tpl_antefi #1, % séparateur toujours présent, même arès le dernier nombre \expandafter\tpl_gentuple_e\expanded{{\the\numexpr#2+1}{#3}{\tpl_gobone#4{#1}}}{#5}{#6}\tpl_gentuple_g% puis recommencer \fi } %--------------- % macros auxiliaires pour \gentuple %--------------- \tpl_foreach\__temp\in{i,1,2,3,4,5,6,7,8,9}\do{% définition des macros de remplacement \1, \2, etc \tpl_csedef{tpl_subst_\__temp}##1##2{\tpl_cs_enxp{tpl_subst_\__temp _a}##1\noexpand\?{\tpl_cs_enxp{tpl_subst_\__temp _b}##1\noexpand\_nil{##2}}\noexpand\_markit\tpl_cs_enxp{\__temp}\noexpand\?{\noexpand\unexpanded{##1}}\noexpand\_markit\noexpand\_nil}% \tpl_csdef {tpl_subst_\__temp _a\expandafter}\expandafter##\expandafter1\csname\__temp\endcsname##2\?##3\_markit##4\_nil{##3}% \tpl_csedef{tpl_subst_\__temp _b\expandafter}\expandafter##\expandafter1\csname\__temp\endcsname##2\_nil##3{\tpl_cs_enxp{tpl_subst_\__temp}{##1##3##2}{##3}}% } \def\tpl_subst_allvalues#1#2#3{% #1=nombre de variables #2=expression où il y a \1, \2, etc #3=valeurs pour les variables #4=valeur pour \i \tpl_subst_allvalues_a{1}{#1}{#2}#3{}{}{}{}{}{}{}{}{}\_nil%{#4}% <- ajouter l'index courant qui est la valeur pour \i } \def\tpl_subst_allvalues_a#1#2#3#4{% #1=n° de remplacement en cours #2=nb total de remplacements #3=expression #4=valeur de la variable n°#1 \tpl_testifnum{#1>#2 } {\tpl_firsttonil{\tpl_subst_i{#3}}}% <- mange tout jusqu'au \_nil puis lit la valeur pour \i {\tpl_x_after\tpl_subst_allvalues_a{{\the\numexpr#1+1}{#2}{\csname tpl_subst_#1\endcsname{#3}{#4}}}}% } \tpl_restorecatcode \tplsetmode{dec : long} \endinput Versions : _____________________________________________________________________________ | Version | Date | Changements | |-----------------------------------------------------------------------------| | 0.1 | 16/11/2024 | Première version | |-----------------------------------------------------------------------------| | 0.2 | 20/12/2024 | * choix du type de nombres dans le tuple : "int", | | | | "dec:short" ou bien "dec:long" (défaut) | | | | * index négatifs possibles pour les méthodes get, | | | | set, add et split | | | | * ajout d'un moteur de calcul rudimentaire pour les | | | | décimaux #8.#8 avec produit de type #16.#8 | | | | * la méthode 'pos' admet un argument optionnel pour | | | | indiquer l'occurrence cherchée | |-----------------------------------------------------------------------------|