Is there a way to remove automatic scaling of nested braces/brackets/parentheses in math mode?

I’m pretty sure I’ve seen something like this before, but I can’t remember anything. I’m not even sure this is possible. Is it? If so, then how would I do it?

$((...((x - 2)^2 - 2)^2... - 2)^2)$

image

Basically, I want to have all the parentheses to have the same standard size. I’ve looked at lr as my immediate guess, but it looks like that you should use it explicitly, and it doesn’t affect symbols that were inserted without its use.

Isn’t that a set rule on lr?

#set math.lr(size: 1em)
$ ((...((x - 2)^2 - 2)^2... - 2)^2) $

image

1 Like

Oh, I think it didn’t work because I used #set math.lr(size: 100%). Not sure I would call 1em an obvious value for size, but now I know. Thanks.

The accent superscript position looks like a bug though, right? They should ideally all be at the same height.

2 Likes

You mean the superscript numbers? Yeah, I suppose it is, unless there is “a more correct” solution. I didn’t even notice until now.

I think the correct way is to escape the brackets, i.e. writing \( and \). That way, the superscript positions are also correct.

3 Likes

Hmmm seems like superscripts (and probably subscripts) positions are computed at some point before the set rule is in effect? It does seem inefficient, if the computations happen all the same despite identical lr size.

Yes, my experience so far has been the same. The difference between relative and length is usually very fine. In this case, looks like em works!

That’s fine, but this is not an automated solution like I imagined (set/show rule) and it does make the code less readable. Cool that at least superscript position is correct.

Let’s see how it goes:

There’s quite a bit happening “behind the scenes”, and so I think explaining what’s actually happening in the code might make things clearer.


When delimiters are automatically matched, what this really means is that an implicit math.lr function call is created, with the size set to auto. e.g.

$((...((x - 2)^2 - 2)^2... - 2)^2)$

gets turned into

$lr((lr((...lr((lr((x - 2), size: #auto)^2 - 2), size: #auto)^2... - 2), size: #auto)^2), size: #auto)$

(technically these aren’t equivalent, but that doesn’t matter here).

Now the size of auto means that the compiler stretches the delimiters to the total height of the contents in the lr function call’s body. When you use a relative size, like 100%, this is relative to the aforementioned auto size calculated. So the set rule #set math.lr(size: 100%) won’t do anything, as you’re telling it to set the size to be 100% of the automatic size!


Regarding the incorrect looking superscript position when using #set math.lr(size: 1em), this isn’t really a bug. Like with the automatic delimiter matching, when you write the superscript ...^2 an implicit math.attach function call is created. The expression preceding the ^2 is wrapped into the base of the attach function call. e.g.

$lr((lr((...lr((lr((x - 2), size: #auto)^2 - 2), size: #auto)^2... - 2), size: #auto)^2), size: #auto)$

becomes

$lr((attach(lr((...attach(lr((attach(lr((x - 2), size: #auto), tr: 2) - 2), size: #auto), tr: 2)... - 2), size: #auto), tr: 2)), size: #auto)$

The position of the scripts is calculated based on the total height of the base in the attach function call. So when using #set math.lr(size: 1em), the height of the body in the attach calls isn’t changing, despite the brackets no longer scaling. Thus, the superscript positions don’t change and end up looking incorrect.

I wouldn’t consider this a bug because the intended output is unclear. Consider the example below:

#set math.lr(size: 1em)
$ ((x - 2)^2 - 2)^2 $
$ (-2 + (x - 2)^2)^2 $

Rendering of the above Typst code.

The outer attach’s base in each equation have the same height. But while in the first equation it would make sense for the superscript to be lower, in the second it isn’t so clear. How should the compiler infer the height relative to which the superscript positioning is done? At what distance from the superscript should it decide to no longer include that element’s height in the positioning? More on this at the end.

As @ludwig said, the correct way to do this is to escape the brackets, ensuring the implicit lr isn’t created. By escaping the brackets, this also means the body of the attach function call is just the bracket itself. So you end up getting the correct superscript positions.


The original behaviour desired, not wanting the delimiters to get larger, is part of https://github.com/typst/typst/issues/360 in my opinion. The crux of that issue is solving how the interactions between delimiters and the rest of math (attachments, etc.) should work when we prefer the height of the delimiters over the height of the body within it (and when this should even happen!). Implementing this is quite tricky, as well as figuring out clear rules for the behaviour. It’s a tough problem to solve, but doable I think.

3 Likes

I think lining up all superscripts makes sense in both cases. Visually, superscript has to attach near the top of a parenthesis. Since all parentheses have the same height, all the superscripts next to them must be typeset at the same height.

The way I see it, the linked issue is about changing the default parentheses scaling in certain scenarios. The question in the topic, however, is to be able to disable the scaling completely. But it’s true that they both share the same domain, i.e., something that has to do with parentheses scaling.

We probably should wait for @laurmaedje to respond (here on in the issue).

I took the Smarter parentheses sizing issue to mean adding an option for that behaviour, as an alternative to the current default of scaling to match the height. So in this regard, I think being able to disable scaling completely can also fall under the scope of that issue.

I see what you mean, but attach is intended to place scripts with regards to its entire base. If you want it to only be placed with regard to the parenthesis, it alone should be the base then in the attach function call. I think changing it to behave as you describe would be fickle, and probably cause undesirable behaviour sometimes.