Math Formulas (MathJax and Mathoid)
LCOJ renders math with MathJax right in the browser, with no extra service to install. This page explains how it works, the formula syntax, and why you shouldn't enable Mathoid.
⏱ ~10 min · 👤 Operators, problem setters · 🔑 Just a browser; SSH + docker if you need to fix static files
Do you need this?
This page explains how LCOJ renders math in problem statements, blog posts, and comments, and why you don't need to install Mathoid.
- LCOJ renders formulas out of the box with MathJax running in the browser. No extra service is required.
- Mathoid is DMOJ's server-side formula renderer. LCOJ currently doesn't use it when rendering Markdown, and enabling it can actually make formulas stop rendering (see below).
If you are a problem setter, you only need the Formula syntax section.
Status in LCOJ
| Component | Status in the shipped config (dmoj/config/local_settings.py) |
|---|---|
| MathJax 3.2.0 (in the browser) | Enabled, static files served from /static/vnoj/mathjax/3.2.0/ |
Mathoid (MATHOID_URL) | Disabled: not set, so the False default from dmoj/settings.py applies |
Mathoid service in docker-compose.yml | Not present |
How LCOJ renders formulas
- The server uses
markdown2(VNOI's fork) with thelatexextra. It recognizes~...~and$$...$$and protects the formula so Markdown doesn't mangle characters such as_,*, and\. - The HTML is sent to the browser with the original formula text.
- MathJax (configured in
resources/mathjax_config.js) renders the formulas in the browser.
Formula syntax
| Type | Syntax | Notes |
|---|---|---|
| Inline math | ~...~ | The primary syntax; use this |
| Display math | $$...$$ | Centered, on its own line |
| Inline (alternative) | \(...\) | Supported by MathJax, but Markdown may eat the \, so prefer ~...~ |
A single $ is NOT math
$a+b$ is displayed literally as $a+b$. Use ~a+b~ for inline math and $$...$$ for display math.
Inline math
Given two integers ~a~ and ~b~ ~(1 \le a, b \le 10^9)~.Display math
The Fibonacci sequence is defined as:
$$F(n) = \begin{cases}
0, & n = 0 \\
1, & n = 1 \\
F(n-1) + F(n-2), & n \ge 2
\end{cases}$$Full example
Given an integer ~N~ ~(1 \le N \le 10^{18})~, find the ~N~-th Fibonacci number
modulo ~10^9 + 7~.
$$F(n) = F(n-1) + F(n-2)$$
**Note:** For ~30\%~ of the points, ~N \le 10^6~.Common symbols
| Meaning | Write | Meaning | Write |
|---|---|---|---|
| Less than or equal | ~a \le b~ | Fraction | ~\frac{a}{b}~ |
| Greater than or equal | ~a \ge b~ | Power, subscript | ~a^{10}~, ~a_{i,j}~ |
| Not equal | ~a \ne b~ | Sum | ~\sum_{i=1}^{n} a_i~ |
| Multiply | ~a \times b~ | Product | ~\prod_{i=1}^{n} a_i~ |
| Congruence | ~a \equiv b \pmod{m}~ | Root | ~\sqrt{x}~, ~\sqrt[3]{x}~ |
| Floor / ceiling | ~\lfloor x \rfloor~, ~\lceil x \rceil~ | Logarithm | ~\log n~ |
Colors
LCOJ's MathJax config loads the color package, so you can write ~\color{red}{x}~.
Mathoid in LCOJ today
Mathoid (upstream source, formerly github.com/wikimedia/mathoid) is a Wikimedia Node.js service that renders TeX to SVG/MathML. DMOJ used it for server-side math rendering.
LCOJ currently doesn't use Mathoid when rendering Markdown. Setting MATHOID_URL only affects two things:
- It shows the Math engine option on the edit-profile page.
- When a user's engine is
auto(the default) and the browser supports MathML, the engine becomesmml. The page then does not load MathJax, and the server doesn't render the formula either. Result: formulas show up as raw~...~.
Do not enable Mathoid
For now, setting MATHOID_URL does not improve formulas and can make them disappear for many browsers. Keep the default configuration.
If you are re-implementing this feature (optional, for developers)
Only do this on a development machine, after wiring the MathoidMathParser class (in judge/utils/mathoid.py in dmoj/repo) into the Markdown renderer.
Build a Mathoid image yourself from the upstream source following its README. Mathoid listens on port 10044 according to its
config.dev.yaml. LCOJ does not ship this image.Add the service to
dmoj/docker-compose.override.yml(Compose merges this file withdocker-compose.ymlautomatically when run fromdmoj/) and attach it to thesitenetwork so thesitecontainer can reach it:yamlservices: mathoid: image: my-mathoid:latest # the image you built restart: unless-stopped networks: [site]Set these in your settings file (see Environment and configuration):
pythonMATHOID_URL = 'http://mathoid:10044/' MATHOID_CACHE_ROOT = '/cache/mathoid/' # a directory the site can write to MATHOID_CACHE_URL = '/mathoid/' # public URL for that directory (needs an nginx location)Run
docker compose up -d mathoid, thendocker compose restart site.
Other settings and their defaults (in dmoj/settings.py): MATHOID_GZIP = False, MATHOID_MML_CACHE = None, MATHOID_CSS_CACHE = 'default', MATHOID_DEFAULT_TYPE = 'auto', MATHOID_MML_CACHE_TTL = 86400.
Verify
- Open a problem statement with a formula written as
~...~or$$...$$: it renders as math, with no raw~characters left. - Open DevTools (Network tab) and reload:
/static/vnoj/mathjax/3.2.0/es5/tex-chtml.min.jsreturns status 200. dmoj/config/local_settings.pyhas noMATHOID_URLline (the defaultFalsestays in effect).
Troubleshooting
| Symptom | Common cause | Fix |
|---|---|---|
$a+b$ is shown literally | Single $ delimiters | Change to ~a+b~ |
~a+b~ is shown literally on every page | MathJax failed to load | Open DevTools and check /static/vnoj/mathjax/3.2.0/es5/tex-chtml.min.js; if it returns 404, run ./scripts/copy_static, then docker compose restart nginx |
~a+b~ is shown literally after setting MATHOID_URL | Engine switched to mml, so MathJax isn't loaded | Remove MATHOID_URL, then docker compose restart site |
| A formula shows a red error | Invalid LaTeX | Try the formula in an online LaTeX editor |
| Old statements look unchanged after a config change | Statement HTML is cached for up to 1 day | Save the problem again (saving clears the cache), or wait for it to expire |
Next steps
- Problem format: write a complete statement, formulas included.
- TikZ diagrams (Texoid): the server-side renderer for TikZ/LaTeX diagrams.
- Helper scripts:
copy_staticwhen MathJax static files return 404.
Need help?
Open an issue at github.com/luyencode/lcoj-docker/issues, find more at behitek.com, or contact us via luyencode.net/about/#lien-he.
