I am working on a library for automatic theorem numbering when I encountered some “layout did not converge within 5 attempts” issue. The minimal reproducing example is this:
#let section(loc) = (counter(heading).at(loc).at(0, default: 0), )
#let create-theorem(thm-name, heading-provider, thm-counter, last-heading-state) = body => block[
#context {
let curr-heading = heading-provider(here())
if (last-heading-state.get() != curr-heading) {
thm-counter.update(0)
last-heading-state.update(curr-heading)
}
}
#thm-counter.step()
#context strong[#thm-name #numbering("1.", ..(heading-provider(here()) + thm-counter.get()))]
#body
]
#let theorem = create-theorem("Theorem", section, counter("theorem"), state("last-heading-thm"))
#let corollary = create-theorem("Corollary", loc => section(loc) + counter("theorem").at(loc), counter("corollary"), state("last-heading-cor"))
#set heading(numbering: "1.")
=
#theorem[]
#theorem[]
#corollary[]
#corollary[]
Here, each theorem-like environment uses a heading function, a counter to number the theorems, and a state to track whether we should reset this counter.
For example, we would expect theorems to be numbered absolutely and reset at each section as ., and corollaries to be attached to theorems, numbered as ...
However, once I add 2 theorems and 2 corollaries, as in this example, the layout does not converge.
I have completely no idea why this example would diverge, but here’s a few observations:
- If we change the definition of #theorem and #corollary to:
#let theorem = create-theorem("Theorem", loc => (), counter("theorem"), state("last-heading-thm"))
#let corollary = create-theorem("Corollary", loc => counter("theorem").at(loc), counter("corollary"), state("last-heading-cor"))
The example will then converge, so the heading counter somehow plays a role here. (But it is constant throughout the layout. How?)
- If we change the definition of #corollary to:
#let corollary = create-theorem("Corollary", section, counter("corollary"), state("last-heading-cor"))
to not depend on counter(“theorem”), then it would also converge. So counter(“theorem”) somehow also plays a role here.
- If you only have 1 theorem and 2 corollaries, or 2 theorems and 1 corollary, everything converges. Only when you increase to 2 theorems and 2 corollaries does the layout diverge.
I’d like to know why this behavior happens and how to fix it.