3

This is a follow up question of Smart parentheses?


In the above mention question, the parentheses are smart so that they change they form depending on the nesting level. I wonder if it would be possible to make the parenthesis a bit more smarter. I want to see an output like that

(one level)
[outer (inner level) level]

I.e. the outer level should change to braces if an inner level is present. To make a starting point here’s the MWE from Przemysław Scherwentl’s answer to the original question.

\documentclass{article}

\newcount\smcount
\def\smart#1{\ifcase\smcount(\or[\or\{\else TOO DEEP!\fi%
\advance\smcount by1 #1\ifcase\smcount\or)\or]\or\}\else TOO DEEP!\fi%
\advance\smcount by-1 }

\begin{document}

\smart{Ala \smart{ma \smart {kota}}}

\end{document}

This one implements three levels with the “wrong” order of paranthesis.

I need two levels, as described above, and only in math mode but the latter should make a difference for the general implementation.

Tobi
  • 56,353
  • There's a package which I don't remember that provides a \br{…\br{…\br{…}…}…} intelligent parenthesis. – Manuel Oct 08 '14 at 15:19
  • maybe the commath package could be helpful? – barbara beeton Oct 08 '14 at 16:16
  • @barbarabeeton: No, I can’t find anything on nested parenthesis in the manual … – Tobi Oct 08 '14 at 16:19
  • @Manuel: This one? http://www.latex-community.org/forum/viewtopic.php?f=46&t=4747 Unfortunately this is not fully automated … – Tobi Oct 08 '14 at 16:23
  • @Tobi No. May be I'm wrong, but I think there's a package which implements those nested changing parenthesis with a \br command. But I don't remember… or may be I'm wrong. – Manuel Oct 08 '14 at 16:40
  • 3
    Transform the expression into Polish notation and you won't need any parenthesis. – egreg Oct 08 '14 at 19:24

3 Answers3

6

Automating the over-use of \left, \right is so wrong, but...

enter image description here

\documentclass{article}

\newcount\smcount
\delimitershortfall-1sp
\def\smart#1{\left\ifodd\smcount[\else(\fi
\advance\smcount by1 #1\right\ifodd\smcount)\else]\fi}

\begin{document}

$\smart{aaa\smart{Ala \smart{ma \smart {kota}}}}$

\end{document}

or after clarification in comments, perhaps you want

\documentclass{article}


\delimitershortfall-1sp
\def\xsmart#1{\left(#1\right)}
\def\smarttest#1\smart#2#3\endsmarttest#4{%
\ifx\valign#2%
\left(\let\smart\xsmart#4\right)%
\else
\left[\let\smart\xsmart#4\right]%
\fi}

\def\smart#1{\smarttest#1\smart\valign\endsmarttest{#1}}%


\begin{document}

$\smart{aaa\smart{Ala \smart{ma \smart {kota}}}}$

$\smart{aaa}$

\end{document}

but that seems stranger still:-)

David Carlisle
  • 757,742
  • Thanks, but this doesn’t answer the question ;-) To add the delimiters isn’t the problem, but changing the appearance of the outer level depending on the inner level … – Tobi Oct 08 '14 at 16:03
  • And can you please explain what’s “wrong” with using the delimiter? – Tobi Oct 08 '14 at 16:04
  • 1
    @Tobi \left\right add extra horizontal space which is often unfortunate, and even without the negative delimitershortfall often make brackets that are too big http://tex.stackexchange.com/questions/173717/is-it-ever-bad-to-use-left-and-right/173740#173740 – David Carlisle Oct 08 '14 at 18:48
  • OK … thank you but do you have an idea how to implement the outer-inner-dependence, which is the main part of my question? ;-) – Tobi Oct 09 '14 at 19:29
  • At the moment the will be only the cases (a), (a (b)), which should come out as [a (b)], or ((a) (b)), i.e. [(a) (b)]. I’ll take care of the number of nesting levels and I’d implement \innerparens{b} -> (b) and \outerparens{a} -> [a] to make the more complex equations manually. – Tobi Oct 09 '14 at 19:54
  • For cases with more nesting levels, all inner ones can have round parens and only the outermost gets brackets. E.g (( (a) ((b (c))) )) would be [( (a) ((b (c))) )]. – Tobi Oct 09 '14 at 19:54
  • @Tobi Oh I'd never have guessed that:-) can the first nested occurrence of \smart be assumed to be at the top level not inside a {} group (if so it's easy, if not it's harder requiring a multi pass system, probably) – David Carlisle Oct 09 '14 at 20:03
  • Hm … at the moment I assume that it will live alway outside a group (except the one created by the math environments). – Tobi Oct 09 '14 at 20:19
  • @Tobi updated answer – David Carlisle Oct 09 '14 at 20:47
  • Thanks. It works with your example but not with $\sum_n \paren{z_{\text{m}\,n} \cdot \cos\paren{\omega_n t + \phi_n}}$ so I guess I was wrong claiming that theres no grouping? (PS: May you explain, why you didn’t understand my question so I can improve my english skills ;-)) – Tobi Oct 11 '14 at 14:04
  • @Tobi before the edit (and even after to a certain extent) I would have expected that "so that they change they form depending on the nesting level." meant that the form changed (alternated) at all levels not just that the outer level was [ and all inner levels were ( (incidentally why do you want this, it seems very weird, and actually easiest just to code directly with [ then ( by hand. – David Carlisle Oct 11 '14 at 14:15
  • I like automated solutions and didm’† think it will be that complicated. I guess doing it manually is much easier anI’ll go with that, but I do alway claim, that LaTeX is able to do every thing, and won’t be wrong here ;-) – Tobi Oct 11 '14 at 14:26
3

You can try this:

\def\smart#1{\let\smartA=\empty
  \setbox0=\hbox{\def\smart{\global\let\smartA=\relax}$#1$}%
  \begingroup\def\smart##1{(##1)}\ifx\smartA\relax [#1]\else (#1)\fi\endgroup
}

\smart{abc\smart{d\smart{ef}g}h}  % ->  [abc(d(ef)g)h]
\smart{pq{\smart{ru}v}w}          % ->  [pq(ru)vw]
\smart{xyz}                       % ->  (xyz)

\end

I didn't solve more than two levels. All inner levels have rounded (brackets). Inner level hidden in group doesn't bother.

wipet
  • 74,238
  • Thanks. The problem here is that you explicitly (must) use $…$ so this my corrupts the display styles (e.g. fractions etc.) … furthermore I doesn’t work with $\sum_n \paren{z_{\text{m}\,n} \cdot \cos\paren{\omega_n t + \phi_n}}$ (like Davids answer) – Tobi Oct 11 '14 at 14:06
  • Sorry, I don't understand your comment. User cannot use $...$. And I don't understand what you say about \sum_n \paren{...}. – wipet Oct 12 '14 at 14:56
  • I mean, that the sue of $…$ is part of your definition for the \hbox an thus al formulas (or parts of) inside of \smart{…} are treaded as inline math, i.e. factions or the limits of \sum etc. are typeset wrong (to small) when I use \smart in a display math environment like {equation}. The equation in my comment is an example where \smart seems to fail. I get round parens for both levels. – Tobi Oct 12 '14 at 15:09
  • This is misunderstanding. The \hbox{$...$} is not used for printing but only for calculating the level of parentheses. It is not printed. The printing version respects the math-mode. See more about this in implementation notes of my new answer which implements arbitrary number of nested levels. – wipet Oct 12 '14 at 15:23
3

The problem seems to be very interesting especially when arbitrary number of levels of brackets is expected. I tried to solve this. Arbitrary number of levels can be used and the types of brackets for each level can be declared.

The formula enclosed by brackets are typed by \brk{formula} (\brk is abbreviation for "brackets"). The formula can include another \brk{...} (nesting at arbitrary number of levels). For example:

\brk{a\brk{b\brk{c\brk{d}e}f}g\brk{h}i\brk{jk\brk{l}pq}r}
this means:
(a(b(c(d)e)f)g(h)i(jk(l)pq)r)

My solution implements two pass algorithm. The whole parameter of most outer \brk is processed in first pass in order to decide the number of nested brackets. After first pass is done, each bracket knows the number of nested levels in its subformula. It means, for our example:

brk1

The second pass of \brk macro prints desired brackets. You have to declare the shape of these brackets by the \brkDecl macro:

\brkDecl <left0><right0><left1><right1><left2><right2>etc<left-n><right-n><dot><dot>

Examles:

\brkDecl ()[]..

\brk{a\brk{b\brk{c\brk{d}e}f}g\brk{h}i\brk{jk\brk{l}pq}r}

brk2

\brkDecl ()[]\{\}\langle\rangle..

$\brk{a\brk{b\brk{c\brk{d}e}f}g\brk{h}i\brk{jk\brk{l}pq}r}$

brk3

\brkDecl (){\bigl(}{\bigr)}{\Bigl(}{\Bigr)}{\biggl(}{\biggr)}{\Biggl(}{\Biggr)}..

$\brk{a\brk{b\brk{c\brk{d}e}f}g\brk{h}i\brk{jk\brk{l}pq}r}$

brk4

You can use \ensurebalanced macro from here and math-active character setting in order to user can simply type only rounded brackets:

\def\brkX#1){\ensurebalanced()\brk{#1}}
{\catcode`\(=13 \global\let(=\brkX}
\def\brkActive{\mathcode`\(="8000 }

\brkDecl {\mathopen{\mathchar`(}}{)}{\bigl(}{\bigr)}{\Bigl(}{\Bigr)}{\biggl(}{\biggr)}{\Biggl(}{\Biggr)}..
\brkActive

$(a(b(c(d)e)f)g(h)i(jk(l)pq)r)$

brk4

Note, that the <left0> declaration in \brkDecl is somewhat more complicated here, becuase the character ( is declared as active character in math.

The implementation of the \brk macro follows:

\newcount\brkN  \newcount\brkL  
\def\brk#1{\def\brkS{0}\global\brkN=0 \let\brk=\brkA
   \ifmmode \setbox0=\hbox{$#1$}\else \setbox0=\hbox{#1}\fi
   \sxdef{brk.0}{\the\brkL}%
   \global\brkN=0 \let\brk=\brkB
   \brkE L0#1\brkE R0\let\brk=\brkC
}
\def\brkA#1{{\global\brkL=0 \global\advance\brkN by1
   \def\brkS{0}\edef\brkM{\the\brkN}%
   #1%
   \sxdef{brk.\brkM}{\the\brkL}\global\advance\brkL by1}%
   \ifnum\brkS>\brkL \global\brkL=\brkS\relax \else \edef\brkS{\the\brkL}\fi
}
\def\brkB{\global\advance\brkN by1 \expandafter\brkD\expandafter{\the\brkN}}
\let\brkC=\brk
\def\brkD#1#2{\brkE L{#1}#2\brkE R{#1}}
\def\brkE #1#2{\csname brk.#1.%
   \ifnum\csname brk.#2\endcsname>\brkF\space \brkF \else \csname brk.#2\endcsname \fi
   \endcsname 
}
\def\brkDecl{\brkL=0 \brkG}
\def\brkG#1#2{\ifx#1.\advance\brkL by-1 \edef\brkF{\the\brkL}\else 
  \sdef{brk.L.\the\brkL}{#1}\sdef{brk.R.\the\brkL}{#2}%
  \advance\brkL by1 \expandafter\brkG \fi
}
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\sxdef#1{\global\expandafter\edef\csname#1\endcsname}

The implementation notes. In the first pass, the \brk macros inside the parameter are processed like \brkA. In the second pass, they are processed like \brkB. The normal
meaning of \brk is returned by \brkC.

The first pass is processed inside box0, i. e. the material is fully processed but not printed. The left brackets are numbered from zero from left to right (by \brkN counter) and the number of levels is calculated by \brkL counter. The macro \csname brk.\the\brkN\endcsname includes the number of sub-brackets for each left bracket after first pass is done.

The macros \csname brk.L.\the\brkL\endcsname include the type of left bracket for \bkrL level. The right bracket is stored in \csname brk.R.\the\brkL\endcsname. These macros are initialized by \brkDecl.

wipet
  • 74,238