Skip to content

Commit 6b5b142

Browse files
committed
Remove Forward definitions where possible.
pyparsing.Forward only needs to be used for mutually recursive mathtext elements; others can be defined directly (using `=` instead of `<<=`). This speeds up ``` MPLBACKEND=agg python -c 'import time; from pylab import *; from matplotlib.tests.test_mathtext import math_tests; fig = figure(figsize=(3, 10)); fig.text(0, 0, "\n".join(filter(None, math_tests)), size=6); start = time.perf_counter(); [fig.canvas.draw() for _ in range(10)]; print((time.perf_counter() - start) / 10)' ``` by around 6%.
1 parent 709fba8 commit 6b5b142

File tree

1 file changed

+49
-59
lines changed

1 file changed

+49
-59
lines changed

lib/matplotlib/_mathtext.py

Lines changed: 49 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313

1414
import numpy as np
1515
from pyparsing import (
16-
Empty, Forward, NotAny, oneOf, OneOrMore, Optional, ParseBaseException,
17-
ParseFatalException, ParserElement, ParseResults, QuotedString, Regex,
18-
StringEnd, ZeroOrMore, pyparsing_common)
16+
Empty, Forward, Literal, NotAny, oneOf, OneOrMore, Optional,
17+
ParseBaseException, ParseFatalException, ParserElement, ParseResults,
18+
QuotedString, Regex, StringEnd, ZeroOrMore, pyparsing_common)
1919

2020
import matplotlib as mpl
2121
from . import cbook
@@ -1697,70 +1697,72 @@ class _MathStyle(enum.Enum):
16971697

16981698
def __init__(self):
16991699
p = types.SimpleNamespace()
1700-
# All forward declarations are here
1700+
1701+
def set_names_and_parse_actions():
1702+
for key, val in vars(p).items():
1703+
if not key.startswith('_'):
1704+
# Set names on everything -- very useful for debugging
1705+
val.setName(key)
1706+
# Set actions
1707+
if hasattr(self, key):
1708+
val.setParseAction(getattr(self, key))
1709+
1710+
# Root definitions.
1711+
1712+
p.float_literal = Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)")
1713+
p.space = oneOf(self._space_widths)("space")
1714+
1715+
p.single_symbol = Regex(
1716+
r"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" %
1717+
"\U00000080-\U0001ffff" # unicode range
1718+
)("sym")
1719+
p.accentprefixed = "\\" + oneOf(self._accentprefixed)("sym")
1720+
p.symbol_name = (
1721+
oneOf([rf"\{sym}" for sym in tex2uni])("sym")
1722+
+ Regex("(?=[^A-Za-z]|$)").leaveWhitespace())
1723+
p.symbol = (p.single_symbol | p.symbol_name).leaveWhitespace()
1724+
p.unknown_symbol = Regex(r"\\[A-Za-z]*")("name")
1725+
1726+
p.font = "\\" + oneOf(self._fontnames)("font")
1727+
p.start_group = (
1728+
Optional(r"\math" + oneOf(self._fontnames)("font")) + "{")
1729+
p.end_group = Literal("}")
1730+
1731+
p.ambi_delim = oneOf(self._ambi_delim)
1732+
p.left_delim = oneOf(self._left_delim)
1733+
p.right_delim = oneOf(self._right_delim)
1734+
1735+
set_names_and_parse_actions() # for root definitions.
1736+
1737+
# Mutually recursive definitions. (Minimizing the number of Forward
1738+
# elements is important for speed.)
17011739
p.accent = Forward()
1702-
p.ambi_delim = Forward()
17031740
p.auto_delim = Forward()
17041741
p.binom = Forward()
17051742
p.customspace = Forward()
1706-
p.end_group = Forward()
1707-
p.float_literal = Forward()
1708-
p.font = Forward()
17091743
p.frac = Forward()
17101744
p.dfrac = Forward()
17111745
p.function = Forward()
17121746
p.genfrac = Forward()
17131747
p.group = Forward()
1714-
p.left_delim = Forward()
1715-
p.main = Forward()
1716-
p.math = Forward()
1717-
p.math_string = Forward()
1718-
p.non_math = Forward()
17191748
p.operatorname = Forward()
17201749
p.overline = Forward()
17211750
p.overset = Forward()
17221751
p.placeable = Forward()
17231752
p.required_group = Forward()
1724-
p.right_delim = Forward()
17251753
p.simple = Forward()
17261754
p.simple_group = Forward()
1727-
p.single_symbol = Forward()
1728-
p.accentprefixed = Forward()
1729-
p.space = Forward()
17301755
p.sqrt = Forward()
1731-
p.start_group = Forward()
17321756
p.subsuper = Forward()
1733-
p.symbol = Forward()
1734-
p.symbol_name = Forward()
17351757
p.token = Forward()
17361758
p.underset = Forward()
1737-
p.unknown_symbol = Forward()
17381759

1739-
for key, val in vars(p).items():
1740-
if not key.startswith('_'):
1741-
# Set names on everything -- very useful for debugging
1742-
val.setName(key)
1743-
# Set actions
1744-
if hasattr(self, key):
1745-
val.setParseAction(getattr(self, key))
1760+
set_names_and_parse_actions() # for mutually recursive definitions.
17461761

1747-
p.float_literal <<= Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)")
1748-
1749-
p.space <<= oneOf(self._space_widths)("space")
17501762
p.customspace <<= r"\hspace" - (
17511763
"{" + p.float_literal("space") + "}"
17521764
| Error(r"Expected \hspace{n}"))
17531765

1754-
p.single_symbol <<= Regex(
1755-
r"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" %
1756-
"\U00000080-\U0001ffff" # unicode range
1757-
)("sym")
1758-
p.accentprefixed <<= "\\" + oneOf(self._accentprefixed)("sym")
1759-
p.symbol_name <<= (
1760-
oneOf([rf"\{sym}" for sym in tex2uni])("sym")
1761-
+ Regex("(?=[^A-Za-z]|$)").leaveWhitespace())
1762-
p.symbol <<= (p.single_symbol | p.symbol_name).leaveWhitespace()
1763-
17641766
p.accent <<= (
17651767
"\\"
17661768
+ oneOf([*self._accent_map, *self._wide_accents])("accent")
@@ -1771,14 +1773,9 @@ def __init__(self):
17711773
"{" + ZeroOrMore(p.simple | p.unknown_symbol)("name") + "}"
17721774
| Error(r"Expected \operatorname{name}"))
17731775

1774-
p.start_group <<= (
1775-
Optional(r"\math" + oneOf(self._fontnames)("font")) + "{")
1776-
p.end_group <<= "}"
17771776
p.group <<= (
17781777
p.start_group + ZeroOrMore(p.token)("group") + p.end_group)
17791778

1780-
p.font <<= "\\" + oneOf(self._fontnames)("font")
1781-
17821779
p.simple_group <<= "{" + ZeroOrMore(p.token)("group") + "}"
17831780
p.required_group <<= "{" + OneOrMore(p.token)("group") + "}"
17841781

@@ -1792,10 +1789,6 @@ def __init__(self):
17921789
p.required_group("num") + p.required_group("den")
17931790
| Error(r"Expected \binom{num}{den}"))
17941791

1795-
p.ambi_delim <<= oneOf(self._ambi_delim)
1796-
p.left_delim <<= oneOf(self._left_delim)
1797-
p.right_delim <<= oneOf(self._right_delim)
1798-
17991792
p.genfrac <<= r"\genfrac" - (
18001793
"{" + Optional(p.ambi_delim | p.left_delim)("ldelim") + "}"
18011794
+ "{" + Optional(p.ambi_delim | p.right_delim)("rdelim") + "}"
@@ -1822,8 +1815,6 @@ def __init__(self):
18221815
p.simple_group("annotation") + p.simple_group("body")
18231816
| Error(r"Expected \underset{annotation}{body}"))
18241817

1825-
p.unknown_symbol <<= Regex(r"\\[A-Za-z]*")("name")
1826-
18271818
p.placeable <<= (
18281819
p.accentprefixed # Must be before accent so named symbols that are
18291820
# prefixed with an accent name work
@@ -1874,15 +1865,14 @@ def __init__(self):
18741865
| Error("Expected a delimiter"))
18751866
)
18761867

1877-
p.math <<= OneOrMore(p.token)
1878-
1879-
p.math_string <<= QuotedString('$', '\\', unquoteResults=False)
1880-
1881-
p.non_math <<= Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace()
1882-
1883-
p.main <<= (
1868+
# Leaf definitions.
1869+
p.math = OneOrMore(p.token)
1870+
p.math_string = QuotedString('$', '\\', unquoteResults=False)
1871+
p.non_math = Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace()
1872+
p.main = (
18841873
p.non_math + ZeroOrMore(p.math_string + p.non_math) + StringEnd()
18851874
)
1875+
set_names_and_parse_actions() # for leaf definitions.
18861876

18871877
self._expression = p.main
18881878
self._math_expression = p.math

0 commit comments

Comments
 (0)