1

Motivation

I'd like a \pythagoras command that takes a list of expressions, with a second, optional list of bracket shapes, and returns a pythagorean expression.

Desired result

For instance,

\pythagoras{a,b,c}

should return something equivalent to

\sqrt{a^2+b^2+c^2}

while

\pythagoras{a,\frac{b}{2},c}[.,r,.]

should return something equivalent to

\sqrt{a^2+\left(\frac{b}{2}\right)^2+c^2}

Current code

\documentclass{article}
\usepackage{xparse,amsmath}

\ExplSyntaxOn

% count list \NewDocumentCommand{\countlist}{m}{ \clist_count:n { #1 } }

% repeat command \cs_new_eq:NN \Repeat \prg_replicate:nn

% brackets; my notation of r for round, s for square, c for curly \NewDocumentCommand{\br}{O{r} O{#1} m}{ \left \str_case:nnF { #1 } { {r}{(} {s}{[} {c}{{} {v}{|} {V}{|} {.}{.} } {.} #3 \right \str_case:nnF { #2 } { {r}{)} {s}{]} {c}{}} {v}{|} {V}{|} {.}{.} } {.} }

% pythagoras \NewDocumentCommand{\pythagoras}{m O{.\Repeat{\countlist{#1}-1}{,.}}}{ \seq_set_from_clist:Nn \l_tmpa_seq {#1} \seq_set_from_clist:Nn \l_tmpb_seq {#2} \cs_set:Npn __mapper ##1##2 {__sep \tl_if_empty:nTF { ##2 }{##1}{\br[##2]{##1}}^2} \cs_set:Npn __sep {\cs_set:Npn __sep {+}} \seq_mapthread_function:NNN \l_tmpa_seq \l_tmpb_seq __mapper }

\ExplSyntaxOff

Problems

My current attempt to create a default list of bracket shapes using \Repeat in the optional argument of \pythagoras doesn't seem to be working.

\begin{document}
    \begin{align*}
        & \pythagoras{x,y}[.,.] \\           % pass the bracket parameters explicitly; works as desired
        & .\Repeat{\countlist{x,y}-1}{,.} \\ % the expression used in the definition; in the document, it works as desired
        & \pythagoras{x,y}                   % rely on the \Repeat command in the optional argument in the definition; 
                                             % should return x^2+y^2; 
                                             % actually returns x^2
    \end{align*}
\end{document}

I'm also not sure how to wrap the sum in a \sqrt. Wrapping the relevant line of the \pythagoras command returns an error.

Credits

  • \countlist is taken from egreg's answer to this question
  • \Repeat is taken from Joseph Wright's answer to this question
  • \br is taken from egreg's answer to this question
  • \pythagoras is adapted from Don Hosek's answer to this question
mjc
  • 745

2 Answers2

1

It's simpler. ;-) As specifier for the fences I use the amsmath convention:

  • p for (round) parentheses
  • b for (square) brackets
  • B for braces
  • v for a vertical line (absolute value)
  • V for a double vertical line (norm)

You can add to the list or modify it, but I don't recommend using different abbreviations that can be confusing.

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\pythagoras}{mo} { \IfNoValueTF{#2} { \sqrt { \mjc_pythagoras:n { #1 } } } { \sqrt{ \mjc_pythagoras:nn { #1 } { #2 } } } }

\bool_new:N \l__mjc_pythagoras_delims_bool \seq_new:N \l__mjc_pythagoras_items_seq \seq_new:N \l__mjc_pythagoras_delims_seq \seq_new:N \l__mjc_pythagoras_output_seq

\cs_new_protected:Nn \mjc_pythagoras:n {% no optional argument \seq_set_split:Nnn \l__mjc_pythagoras_items_seq { , } { #1 } \bool_set_false:N \l__mjc_pythagoras_delims_bool __mjc_pythagoras: } \cs_new_protected:Nn \mjc_pythagoras:nn { \seq_set_split:Nnn \l__mjc_pythagoras_items_seq { , } { #1 } \seq_set_split:Nnn \l__mjc_pythagoras_delims_seq { , } { #2 } \bool_set_true:N \l__mjc_pythagoras_delims_bool __mjc_pythagoras: }

\cs_new_protected:Nn __mjc_pythagoras: { \seq_clear:N \l__mjc_pythagoras_output_seq \seq_map_indexed_inline:Nn \l__mjc_pythagoras_items_seq { \seq_put_right:Nx \l__mjc_pythagoras_output_seq { \bool_if:NTF \l__mjc_pythagoras_delims_bool { __mjc_pythagoras_left:n { ##1 } ##2 __mjc_pythagoras_right:n { ##1 } } { ##2 } ^{2} } } \seq_use:Nn \l__mjc_pythagoras_output_seq { + } }

\cs_new:Nn __mjc_pythagoras_left:n { \str_case_e:nn { \seq_item:Nn \l__mjc_pythagoras_delims_seq { #1 } } { {p}{\left(} {b}{\left[} {B}{\left{} {v}{\left|} {V}{\left|} } } \cs_new:Nn __mjc_pythagoras_right:n { \str_case_e:nn { \seq_item:Nn \l__mjc_pythagoras_delims_seq { #1 } } { {p}{\right)} {b}{\right]} {B}{\right}} {v}{\right|} {V}{\right|} } }

\ExplSyntaxOff

\begin{document}

\begin{gather} \pythagoras{a} \ \pythagoras{a,b} \ \pythagoras{a,b,c} \ \pythagoras{a,\frac{1}{2},c}[.,p,.] \end{gather}

\end{document}

enter image description here

egreg
  • 1,121,712
  • Strangely similar to my answer :) Just a minor point: You should use \seq_set_from_clist:Nn instead of \seq_set_split:Nnn. – Skillmon Apr 17 '21 at 17:49
  • Thanks, but it throws a screen full of errors for me :/ – mjc Apr 17 '21 at 18:03
  • Actually, you shouldn't, \seq_set_split:Nnn is faster than \seq_set_from_clist:Nn (if the clist is at least 4 elements or longer). – Skillmon Apr 17 '21 at 18:06
  • @Skillmon The two are different: \seq_set_split:Nnn honors empty items, whereas \seq_set_from_clist:Nn removes them. In this case the former is better. – egreg Apr 17 '21 at 19:34
  • @mjc Start by updating your TeX system. Meanwhile, add \usepackage{xparse}. – egreg Apr 17 '21 at 19:35
  • @egreg yes, you're right, the from_clist one removes blank items (but not empty items formed by a set of braces), \seq_set_split:Nnn is indeed the better choice for this. – Skillmon Apr 17 '21 at 20:36
  • @egreg Ah, my Overleaf environment was set to 2019. Along with xparse, the 2020 version runs the code OK. Thanks. – mjc Apr 17 '21 at 21:06
1

The following uses two different output routines depending on whether the optional argument was used or not. In both cases it uses the \clist_use:Nn function.

\documentclass[]{article}

\ExplSyntaxOn \clist_new:N \l_mjc_pythagoras_elements_clist \clist_new:N \l_mjc_pythagoras_brackets_clist \tl_new:N \l_mjc_pythagoras_element_tl \msg_new:nnn { mjc-pythagoras } { unmatched-braces } { The~ bracket~ specification~ and~ the~ number~ of~ elements~ don't~ match.\ Elements:~ #1\ Brackets:~ #2 } \NewDocumentCommand \pythagoras { m o } { \sqrt { \group_begin: \clist_set:Nn \l_mjc_pythagoras_elements_clist {#1} \IfNoValueTF {#2} { \clist_use:Nn \l_mjc_pythagoras_elements_clist { \sp{2} + } \sp{2} } { \clist_set:Nn \l_mjc_pythagoras_brackets_clist {#2} \int_compare:nNnTF { \clist_count:N \l_mjc_pythagoras_elements_clist } = { \clist_count:N \l_mjc_pythagoras_brackets_clist } { __mjc_delimiter_left: \clist_use:Nn \l_mjc_pythagoras_elements_clist { __mjc_delimiter_right: + __mjc_delimiter_left: } __mjc_delimiter_right: } { \msg_error:nnxx { mjc-pythagoras } { unmatched-braces } { \clist_count:N \l_mjc_pythagoras_elements_clist } { \clist_count:N \l_mjc_pythagoras_brackets_clist } } } \group_end: } } \cs_new_protected:Npn __mjc_delimiter_left: { \clist_pop:NN \l_mjc_pythagoras_brackets_clist \l_mjc_pythagoras_bracket_tl \str_case_e:nn \l_mjc_pythagoras_bracket_tl { { r } { \left( } { s } { \left[ } { c } { \left{ } { v } { \left| } { V } { \left| } } } \cs_new_protected:Npn __mjc_delimiter_right: { \str_case_e:nn \l_mjc_pythagoras_bracket_tl { { r } { \right) } { s } { \right] } { c } { \right} } { v } { \right| } { V } { \right| } } \sp {2} } \ExplSyntaxOff

\begin{document} $\pythagoras{a,b,c}$

$\pythagoras{a,b,c}[.,r,.]$

$\pythagoras{a,b,c}[.,r]$ % throws an error \end{document}

Skillmon
  • 60,462