Variant limits

Variants for superior, inferior, projective, and injective limits are an interesting challenge for typesetting engines with mathematical capabilities.

They have both a subscript expression and a stretchy symbol (an arrow or a bar) that indicates the direction and nature of the limit.

The symbol is stacked below or above the limit.

In display mode, the expression is below the limit.

In inline mode, the expression is on the right of the limit, but the symbol remains above or below the limit. So the symbol is not moveable, while the expression is, depending on the context.

sile
varlimits-sile.sil
\begin[papersize=a7]{document}
\nofolios
\neverindent
\use[module=packages.math]
\font[size=12pt]
\set[parameter=math.font.family,value=Libertinus Math]
\set[parameter=math.font.size,value=12]

\begin[mode=display]{math}
  \projlim_{i \in I} A_i = \varprojlim_{i \in I} A_i
\end{math}

Inline: \math{\projlim_{i \in I} A_i = \varprojlim_{i \in I} A_i}

\begin[mode=display]{math}
  \injlim_{i \in I} A_i = \varinjlim_{i \in I} A_i
\end{math}

Inline: \math{\injlim_{i \in I} A_i = \varinjlim_{i \in I} A_i}

\begin[mode=display]{math}
  \limsup_{n \to \infty} a_n = \varlimsup_{n \to \infty} a_n
\end{math}

Inline: \math{\limsup_{n \to \infty} a_n = \varlimsup_{n \to \infty} a_n}

\begin[mode=display]{math}
  \liminf_{n \to \infty} a_n = \varliminf_{n \to \infty} a_n
\end{math}

Inline: \math{\liminf_{n \to \infty} a_n = \varliminf_{n \to \infty} a_n}
\end{document}
Command
$ sile -o varlimits-sile.pdf varlimits-sile.sil
Preview
lualatex
varlimits-lualatex.tex
\documentclass[12pt]{article}
\usepackage[paperheight=105mm,paperwidth=74mm,margin=4mm]{geometry}
\pagenumbering{gobble}
\setlength{\parindent}{0pt}
\usepackage{libertinus}
\usepackage{fontspec}
\usepackage{unicode-math}
\begin{document}

$$
  \projlim_{i \in I} A_i = \varprojlim_{i \in I} A_i
$$

Inline: $\projlim_{i \in I} A_i = \varprojlim_{i \in I} A_i$


$$
  \injlim_{i \in I} A_i = \varinjlim_{i \in I} A_i
$$

Inline: $\injlim_{i \in I} A_i = \varinjlim_{i \in I} A_i$

$$
  \limsup_{n \to \infty} a_n = \varlimsup_{n \to \infty} a_n
$$

Inline: $\limsup_{n \to \infty} a_n = \varlimsup_{n \to \infty} a_n$

$$
  \liminf_{n \to \infty} a_n = \varliminf_{n \to \infty} a_n
$$

Inline: $\liminf_{n \to \infty} a_n = \varliminf_{n \to \infty} a_n$
\end{document}
Command
$ lualatex --interaction=batchmode --halt-on-error --jobname=data/varlimits-lualatex varlimits-lualatex.tex
Preview
typst
varlimits-typst.typ
// 2025, Didier Willis
// License: MIT.
// Typst does not have these extended limits out of the box:
//   projlim, injlim, varprojlim, varinjlim,
//   varlimsup, varliminf.
// So here is a possible implementation...
// Total newbie, so it's maybe not idiomatic
#let varlim(arrow) = context {
  let lim = "lim"
  let lim-width = measure(lim).width
  let arrow-height = measure(arrow).height
  let varlimop = box(
    width: lim-width,
    baseline: arrow-height,
    box(
      width: 0pt,
      baseline: arrow-height,
      [#math.stretch(arrow, size: lim-width)],
    )
      + box(
        baseline: 0pt,
        width: 0pt,
        lim,
      ),
  )
  return varlimop
}
// Helpers
#let strut = context {
  // Weird way to do a small adjustment for varliminf
  // so that the limit expression is a bit lower
  block(height: measure("").height, width: 0pt)
}
#let varprojlim = math.limits(varlim(sym.arrow.l), inline: false)
#let projlim = math.limits("proj\u{2009}lim", inline: false)
#let varinjlim = math.limits(varlim(sym.arrow.r), inline: false)
#let injlim = math.limits("inj\u{2009}lim", inline: false)
#let varliminf = math.limits(underline("lim" + strut), inline: false)
#let varlimsup = math.limits(overline("lim"), inline: false)

// --- Now the intended document ---

#set page(
  paper: "a7",
  margin: 4mm,
)
#set text(
  font: "Libertinus Serif",
  size: 12pt,
)

$ projlim_(i in I) A_i = varprojlim_(i in I) A_i $
Inline: $projlim_(i in I) A_i = varprojlim_(i in I) A_i$

$ injlim_(i in I) A_i = varinjlim_(i in I) A_i $
Inline: $injlim_(i in I) A_i = varinjlim_(i in I) A_i$

$ limsup_(n -> oo) a_n = varlimsup_(n -> oo) a_n $

Inline: $limsup_(n -> oo) a_n = varlimsup_(n -> oo) a_n$

$ liminf_(n -> oo) a_n = varliminf_(n -> oo) a_n $

Inline: $liminf_(n -> oo) a_n = varliminf_(n -> oo) a_n$
Command
$ typst compile varlimits-typst.typ varlimits-typst.pdf
Preview
glu
varlimits-glu.html
<html>
<head>
<style>
@page { size: A7; margin: 4mm; }
body { font-family: "Libertinus Serif"; font-size: 11pt; }
math { font-family: "Libertinus Math"; }
p { margin: 0.4em 0; }
</style>
</head>
<body>

<p><math display="block"><mrow>
  <munder><mrow><mi>proj&#x2009;lim</mi></mrow><mrow><mi>i</mi><mo>&#x2208;</mo><mi>I</mi></mrow></munder>
  <msub><mi>A</mi><mi>i</mi></msub>
  <mo>=</mo>
  <munder>
    <munder><mi>lim</mi><mo stretchy="true">&#x2190;</mo></munder>
    <mrow><mi>i</mi><mo>&#x2208;</mo><mi>I</mi></mrow>
  </munder>
  <msub><mi>A</mi><mi>i</mi></msub>
</mrow></math></p>

<p>Inline: <math><mrow>
  <msub><mrow><mi>proj&#x2009;lim</mi></mrow><mrow><mi>i</mi><mo>&#x2208;</mo><mi>I</mi></mrow></msub>
  <msub><mi>A</mi><mi>i</mi></msub>
  <mo>=</mo>
  <msub>
    <munder><mi>lim</mi><mo stretchy="true">&#x2190;</mo></munder>
    <mrow><mi>i</mi><mo>&#x2208;</mo><mi>I</mi></mrow>
  </msub>
  <msub><mi>A</mi><mi>i</mi></msub>
</mrow></math>, the arrow stays under the limit while the
expression moves to the side.</p>

<p><math display="block"><mrow>
  <munder><mrow><mi>inj&#x2009;lim</mi></mrow><mrow><mi>i</mi><mo>&#x2208;</mo><mi>I</mi></mrow></munder>
  <msub><mi>A</mi><mi>i</mi></msub>
  <mo>=</mo>
  <munder>
    <munder><mi>lim</mi><mo stretchy="true">&#x2192;</mo></munder>
    <mrow><mi>i</mi><mo>&#x2208;</mo><mi>I</mi></mrow>
  </munder>
  <msub><mi>A</mi><mi>i</mi></msub>
</mrow></math></p>

<p><math display="block"><mrow>
  <munder><mrow><mi>lim&#x2009;inf</mi></mrow><mrow><mi>n</mi><mo>&#x2192;</mo><mi>&#x221E;</mi></mrow></munder>
  <msub><mi>a</mi><mi>n</mi></msub>
  <mo>=</mo>
  <munder>
    <munder><mi>lim</mi><mo stretchy="true">&#x0332;</mo></munder>
    <mrow><mi>n</mi><mo>&#x2192;</mo><mi>&#x221E;</mi></mrow>
  </munder>
  <msub><mi>a</mi><mi>n</mi></msub>
</mrow></math></p>

<p>varlimsup (lim with an overline) is omitted: Glu stretches the
overline to the right width but does not yet place it tight above
its base.</p>

</body>
</html>
Command
$ glu --css all-system-fonts.css -o varlimits-glu.pdf varlimits-glu.html
Preview