Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML and LaTeX/PDF generation require incompatible uses of DeclareMathOperator* #11611

Open
tepperly opened this issue Aug 17, 2023 · 6 comments
Assignees
Labels
awaiting:response Waiting for a response from the author of this issue builder:html builder:latex

Comments

@tepperly
Copy link

Describe the bug

For Sphinx LaTeX/PDF generation to work correctly, I need to the following in my conf.py file:

# Additional stuff for the LaTeX preamble.
'preamble': """\\DeclareMathOperator*{\\argmin}{argmin}
\\DeclareMathOperator*{\\argmax}{argmax}
\\sphinxDUC{2610}{$\square$}
"""

For Sphinx HTML generation to work correctly, I need to put the \DeclareMathOperator inside the individual .. math:: pieces. For example,

.. math::
   \DeclareMathOperator*{\argmin}{argmin}
   {\bf p}^\ast &= \argmin_{{\bf p} \in \mathbb{R}^n} \; c({\bf p}) \\
   \text{such that} \; 0 &\leq v({\bf p}) \leq V \\
                       0 &\leq p_i \leq 1, \; i = 1, \ldots n

If I generate LaTeX using sphinx-build using the HTML configuration (i.e., with \DeclareMathOperator inside the individual .. math:: pieces, I see errors like this when I run latex via make.

$ make
latexmk -pdf -dvi- -ps-  'LiDO.tex'
Rc files read:
  /etc/latexmkrc
  latexmkrc
Latexmk: This is Latexmk, John Collins, 4 Apr. 2023. Version 4.80.
No existing .aux file, so I'll make a simple one, and require run of *latex.
Latexmk: applying rule 'pdflatex'...
Rule 'pdflatex':  Reasons for rerun
Category 'other':
  Rerun of 'pdflatex' forced or previously required

------------
Run number 1 of rule 'pdflatex'
------------
------------
Running 'pdflatex   -recorder  "LiDO.tex"'
------------
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/CVE-2023-32700 patched) (preloaded format=pdflatex)
 restricted \write18 enabled.
... numerous lines deleted...
! LaTeX Error: Can be used only in preamble.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              
                                                  
l.887 ...        &l_n \leq p_n \leq u_n\end{split}
                                                  
? x

The key line is the !LaTeX Error: Can be used only in preamble.

The generated LaTeX behind this error looks like this:

Consider a generic optimization problem of this sort:
\begin{equation*}
\begin{split}\DeclareMathOperator*{\argmin}{argmin}
{\bf p}^\ast = \argmin_{{\bf p} \, \in \, \mathbb{R}^n} \quad &f({\bf p}) \\
\mathrm{such that} \quad &L_1 \leq g_1({\bf p}) \leq U_1 \\
                    &\cdots \\
                    &L_m \leq g_m({\bf p}) \leq U_m \\
                    &l_1 \leq p_1 \leq u_1 \\
                    &\cdots \\
                    &l_n \leq p_n \leq u_n\end{split}
\end{equation*}

I think LaTeX requires \DeclareMathOperator* to be in the preamble.

The command to invoke sphinx looks like

$ sphinx-build -q -b latex -d ${HOME}/lido/build/clang-build/src/docs/sphinx/_doctrees ${HOME}/lido/src/docs/sphinx ${HOME}/lido/build/clang-build/src/docs/sphinx/html
$ sphinx-build --version
sphinx-build 5.0.2

Ideally, I would like a single set of Sphinx inputs to be able to generate both HTML and LaTeX documentation.

How to Reproduce

Here is index.rst for a simple reproducer:

.. LiDO documentation master file, created by
   sphinx-quickstart on Thu Aug 17 08:19:29 2023.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to LiDO's documentation!
================================

.. math::
   \DeclareMathOperator*{\argmin}{argmin}
   {\bf p}^\ast &= \argmin_{{\bf p} \in \mathbb{R}^n} \; c({\bf p}) \\
   \text{such that} \; 0 &\leq v({\bf p}) \leq V \\
                       0 &\leq p_i \leq 1, \; i = 1, \ldots n

Here is a corresponding conf.py:

# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'LiDO'
copyright = '2023, Watts'
author = 'Watts'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = []

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']



# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'alabaster'
html_static_path = ['_static']

latex_elements = {
'preamble': """\\DeclareMathOperator*{\\argmin}{argmin}
"""
}

Environment Information

Platform:              linux; (Linux-6.4.6-100.fc37.x86_64-x86_64-with-glibc2.36)
Python version:        3.10.10 (main, Jul  7 2023, 14:09:08) [Clang 15.0.7 (Fedora 15.0.7-2.fc37)])
Python implementation: CPython
Sphinx version:        7.0.0
Docutils version:      0.19
Jinja2 version:        3.1.2
Pygments version:      2.13.0

Sphinx extensions

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 
    'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.graphviz']

Additional context

No response

@tepperly
Copy link
Author

As a sphinx user, I can imagine a solution might involve defining a mathpreamble in conf.py that would define things that need to go into the LaTeX preamble as well as being inserted at the front of every math element or some better way of doing it in MathJax.

@jfbu
Copy link
Contributor

jfbu commented Aug 19, 2023

edit please skip to #11611 (comment)

As work-around this should work (untested attow):

latex_elements = {
    'preamble': """\\DeclareMathOperator*{\\argmin}{argmin}
.... put here all other \\DeclareMathOperator declarations which occur in any math directive...
% (this % is to comment out this line) and then make \DeclareMathOperator a no-op for LaTeX:
\\makeatletter\\let\\DeclareMathOperator\\@gobbletwo\\makeatother
"""
}

A better way would for MathJaX to provide an analog of the LaTeX preamble so that you can put the DeclareMathOperator there.

Finally, perhaps using \operatorname{argmin} eveywhere in your equations in place of \argmin could be a mark-up working both in LaTeX and in MathJaX (as a short internet search seemed to indicate but I lost the link, but I checked LaTeX).

@jfbu
Copy link
Contributor

jfbu commented Aug 19, 2023

edit please skip to #11611 (comment)

Arrgh you use the starred form so it should be

latex_elements = {
    'preamble': """\\DeclareMathOperator*{\\argmin}{argmin}
.... put here all other \\DeclareMathOperator declarations which occur in any math directive...
% (this % is to comment out this line) and then make \DeclareMathOperator a no-op for LaTeX:
\\def\\DeclareMathOperator#1#2#3{}
"""
}

If you use both starred and nonstarred form then this possible, but I will post this for now.

@jfbu
Copy link
Contributor

jfbu commented Aug 19, 2023

edit please skip to #11611 (comment)

This should work with both usages of starred and non-starred \DeclareMathOperator

latex_elements = {
    'preamble': """\\DeclareMathOperator*{\\argmin}{argmin}
.... put here all other \\DeclareMathOperator declarations which occur in any math directive...
% (this % is to comment out this line) and then make \DeclareMathOperator a no-op for LaTeX:
\\makeatletter\\def\\DeclareMathOperator{\\@ifstar\\@gobbletwo\\@gobbletwo}\\makeatother
"""
}

@jfbu
Copy link
Contributor

jfbu commented Aug 19, 2023

I am sorry. Here is a working solution. I should have tested. I naturally should have delayed the redefinition of \DeclareMathOperator, this was my mistake. But, surprisingly \AtBeginDocument does not work the user definition is over-ruled nevertheless because the "only preamble" restrictions are executed after.

So to get rid of this silently and efficiently simply do

latex_elements = {
    'preamble': """\\DeclareMathOperator*{\\argmin}{argmin}
.... put here all other \\DeclareMathOperator declarations which occur in any math directive...
% (this % is to comment out this line) and then make \DeclareMathOperator a no-op for LaTeX:
\\makeatletter\\def\\DeclareMathOperator{\\@ifstar\\@gobbletwo\\@gobbletwo}\\makeatother
\\makeatletter\\let\\@preamblecmds\\@empty\\makeatother
"""
}

This will inhibit the LaTeX dictatorship. I will perhaps post a less radical solution later, if I don't get too much irritated by LaTeX internals. At least I did test the above;

Update: with modern LaTeX (October 2020 release or later) one can do this in the LaTeX preamble (escape suitably or use a raw string when transferring to conf.py):

\makeatletter
\AddToHook{begindocument/end}{\def\DeclareMathOperator{\@ifstar\@gobbletwo\@gobbletwo}}
\makeatother

and the effect is to make \DeclareMathOperator a no-op without touching configuration of other commands. (there does not seem to be any official interface to do that, this is the simplest way).

With older LaTeX one would have to hack some TeX code to "prune" \DeclareMathOperator from the list of commands declared preamble-only. This is not difficult but why the effort. Simply use \let\@preamblecmds\@empty as above. The redefinition of \DeclareMathOperator as a no-op is still needed except if the \argmin etc... are never defined in preamble: else each new usage of \DeclareMathOperator*{\argmin}{argmin} will complain about the command being already defined.

@jfbu
Copy link
Contributor

jfbu commented Aug 27, 2023

My thoughts on this:

  • adding LaTeX-preamble only commands such as \DeclareMathOperator inside each math directive sounds wrong; (one can try to argue with LaTeX team that \DeclareMathOperator should not have been made preamble-only, but this is fact of life; and once one has used it in preamble one can not use it again in equations because it will complain the command such as \argming is already defined, which is another very irritating fact of life which one can also try to argue in vain about with LaTeX team, but result of such requests is known in advance),
  • even if one does not need to generate PDF output via LaTeX, the extra \DeclareMathOperator in math directive contents makes it impossible to generate HTML with math rendered via images, as those images go via a build process using LaTeX.

So the cleanest way would be to configure properly MathJaX: from quick search on internet it appears to be possible but I did not invest time into checking. If this holds, this issue is not one of Sphinx proper. Please advise.

Alternative at Sphinx level would be to provide a new configuration variable mathjax_preamble which would get copied over into each equation for HTML output, and this would make for cleaner sources which can compile via Sphinx both to PDF via LaTeX and HTML with no problem.

As long as it is not argued conclusively that MathJaX does not provide the means to solve this already via a suitable configuration of it, there is no reason to add the burden at Sphinx upstream.

My earlier comment provides a work-around to allow the extra explicit \DeclareMathOperator to be physically added to each math directive contents and still be compatible with PDF via LaTeX production. Please confirm if it works and whether this issue needs to be kept open.

@jfbu jfbu added the awaiting:response Waiting for a response from the author of this issue label Aug 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting:response Waiting for a response from the author of this issue builder:html builder:latex
Projects
None yet
Development

No branches or pull requests

2 participants