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
2
  • Sorry, but it's not clear what's the expected output in the various cases. – egreg Apr 17 at 17:08
  • @egreg I've edited the OP to clarify. – mjc Apr 17 at 17:12
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

7
  • 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 at 17:49
  • Thanks, but it throws a screen full of errors for me :/ – mjc Apr 17 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 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 at 19:34
  • @mjc Start by updating your TeX system. Meanwhile, add \usepackage{xparse}. – egreg Apr 17 at 19:35
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}
5
  • Thanks, it works. Could you point out where I should put the \sqrt? – mjc Apr 17 at 18:05
  • @mjc just around it, \sqrt{\pythagoras{<list>}}. – Skillmon Apr 17 at 18:06
  • You mean in the document? Is it not possible to do it in the command definition? – mjc Apr 17 at 18:08
  • @mjc see my edit. – Skillmon Apr 17 at 18:09
  • Ah, that's got it. Thanks. – mjc Apr 17 at 18:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.