Математика латекс макросы в настройки и Сфинкса


Используя Sphinx и reStructuredText, Можно ли определить математические макросы для выполнения подстановок в Формуле math Latex?

В принципе, я хотел бы иметь что-то вроде

.. |bnabla| replace:: :math:`boldsymbol{nabla}`
.. |vv| replace:: :math:`textbf{v}`

.. math:: rho mbox{D}_t |vv| = - |bnabla| p + rho textbf{g} + eta |bnabla|^2 |vv|,

where |vv| is the velocity and |bnabla| is the nabla operator.

Then follow many other equations with |vv| and |bnabla|...
Но это совсем не работает. Во-первых, флаги не подставляются в математическом режиме, а во-вторых, даже если они были подставлены, оператор :math: не работает в блоке .. math::. Было бы хорошей идеей и не усложнять, чтобы изменить эти два поведения в Сфинкс? Другим решением было бы использовать макросы latex, как в этом вопросе создание макросов LaTeX math в Sphinx, но я думаю, что окончательный код будет проще читать с локальными первыми заменами, как в моем примере. Я хотел бы иметь четкие формулы, которые также можно читать в текстовом режиме.

Кроме того, я использую расширение MathJax, поэтому я не могу использовать переменную pngmath_latex_preamble. Я мог бы использовать это решение для MathJax https://stackoverflow.com/a/19268549/1779806 но это кажется довольно сложным, и снова код был бы более ясным с "локальными" первыми заменами.

Правка:

Я понял, что для многих людей было бы очень удобно и полезно реализовать директиву подстановки mathmacro непосредственно в reStructuredText (т. е. в пакете Python docutils). Новая директива должна работать следующим образом:

Определение:

.. |bnabla| mathmacro:: boldsymbol{nabla}
.. |vv| mathmacro:: textbf{v}

Эти математические макросы могут быть включены непосредственно в тексте, как в

|bnabla| is the nabla operator,

Который должен произвести встроенное уравнение, подобное этому

:math:`boldsymbol{nabla}` is the nabla operator.

Эти макросы также могут быть включены в встроенные уравнения:

This is an inline equation :math:`vv = bnabla f`, 

Который должен быть эквивалентен

:math:`textbf{v} = boldsymbol{nabla}f`

Они также могут быть включены в уравнение блока

.. math:: vv = bnabla f

Который должен быть эквивалентен

.. math:: textbf{v} = boldsymbol{nabla}f.
Однако я действительно не знаком с тем, как docutils работает внутри компании. Я замечаю, в частности, что директива MathBlock (определенная в docutils/parsers/rst/directives/body.py) не вызывает никакого разбора его входных данных, поэтому в математическом режиме нет подстановки. Я не знаю, можно ли изменить поведение директивы подстановки таким образом, чтобы подстановка была кливерной и адаптировалась к контексту, из которого она вызывается, в тексте, В встроенной математике или в блочной математике.

Может ли кто-нибудь подсказать мне, как реализовать эту полезную новую функцию?

1 4

1 ответ:

Поскольку мне действительно нужно было хорошее решение для этой потребности, я разработал его сам... Это помогает мне некоторое время, и решение, возможно, не идеально, но, по крайней мере, оно хорошо работает. Я представляю результат, так как он может быть полезен для других людей.

Я также адаптировал решение как расширение Сфинкса, которое можно найти здесь.

Я должен был определить новую директиву замещения и переопределить директиву и роль математики. Все это делается в файле mathmacro.py:
"""
'Proof of concept' for a new reStructuredText directive *mathmacro*.

Use for example with::

  python mathmacro.py example.rst example.html

"""

import re

from docutils.parsers.rst.directives.misc import Replace

from docutils.parsers.rst.directives.body import MathBlock
from docutils.parsers.rst.roles import math_role

def multiple_replacer(replace_dict):
    """Return a function replacing doing multiple replacements.

    The produced function replace `replace_dict.keys()` by
    `replace_dict.values`, respectively.

    """
    def replacement_function(match):
        s = match.group(0)
        end = s[-1]
        if re.match(r'[\W_]', end):
            return replace_dict[s[:-1]]+end
        else:
            return replace_dict[s]

    pattern = re.compile("|".join([re.escape(k)+r'[\W_\Z]|'+re.escape(k)+r'\Z'
                                   for k in replace_dict.keys()]), 
                         re.M)
    return lambda string: pattern.sub(replacement_function, string)


class MathMacro(Replace):
    """Directive defining a math macro."""
    def run(self):
        if not hasattr(self.state.document, 'math_macros'):
            self.state.document.math_macros = {}

        latex_key = '\\'+self.state.parent.rawsource.split('|')[1]
        self.state.document.math_macros[latex_key] = ''.join(self.content)

        self.state.document.math_macros_replace = \
            multiple_replacer(self.state.document.math_macros)

        self.content[0] = ':math:`'+self.content[0]
        self.content[-1] = self.content[-1]+'`'

        return super(MathMacro, self).run()


class NewMathBlock(MathBlock):
    """New math block directive parsing the latex code."""
    def run(self):
        try:
            multiple_replace = self.state.document.math_macros_replace
        except AttributeError:
            pass
        else:
            if self.state.document.math_macros:
                for i, c in enumerate(self.content):
                    self.content[i] = multiple_replace(c)
        return super(NewMathBlock, self).run()


def new_math_role(role, rawtext, text, lineno, inliner, 
                  options={}, content=[]):
    """New math role parsing the latex code."""
    try:
        multiple_replace = inliner.document.math_macros_replace
    except AttributeError:
        pass
    else:
        if inliner.document.math_macros:
            rawtext = multiple_replace(rawtext)

    return math_role(role, rawtext, text, lineno, inliner,
                     options=options, content=content)


if __name__ == '__main__':

    from docutils.parsers.rst.directives import register_directive
    from docutils.parsers.rst.roles import register_canonical_role

    register_directive('mathmacro', MathMacro)
    register_directive('math', NewMathBlock)
    register_canonical_role('math', new_math_role)



    from docutils.core import publish_cmdline, default_description
    description = ('Generates (X)HTML documents '
                   'from standalone reStructuredText sources. '
                   +default_description)
    publish_cmdline(writer_name='html', description=description)

В содержание примера файла.первый:

Here, I show how to use a new mathmacro substitution directive in
reStructuredText. I think even this small example demonstrates that it
is useful.


First some math without math macros.  Let's take the example of the
incompressible Navier-Stokes equation:

.. math:: \mbox{D}_t \textbf{v} = 
   -\boldsymbol{\nabla} p + \nu \boldsymbol{\nabla} ^2 \textbf{v}.

where :math:`\mbox{D}_t` is the convective derivative,
:math:`\textbf{v}` the velocity, :math:`\boldsymbol{\nabla}` the
nabla operator, :math:`\nu` the viscosity and
:math:`\boldsymbol{\nabla}^2` the Laplacian operator.


.. |Dt| mathmacro:: \mbox{D}_t
.. |bnabla| mathmacro:: \boldsymbol{\nabla}
.. |vv| mathmacro:: \textbf{v}

Now, let's use some math macros and try to get the same result...  The
Navier-Stokes equation can now be written like this:

.. math:: \Dt \vv = - \bnabla p + \nu \bnabla^2 \vv

where |Dt| is the convective derivative, |vv| the velocity, |bnabla|
the nabla operator, :math:`\nu` the viscosity and :math:`\bnabla^2`
the Laplacian operator.