Skip to content
This repository was archived by the owner on Apr 18, 2026. It is now read-only.

Commit 8eefbbe

Browse files
authored
Merge branch 'main' into integration
2 parents fd2ddee + ff947f7 commit 8eefbbe

14 files changed

Lines changed: 929 additions & 372 deletions

src/integration_tests/algorithmic_style_test.py

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,9 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, Callable
5+
import textwrap
66

7-
from latexify import frontend
8-
9-
10-
def check_algorithm(
11-
fn: Callable[..., Any],
12-
latex: str,
13-
**kwargs,
14-
) -> None:
15-
"""Helper to check if the obtained function has the expected LaTeX form.
16-
17-
Args:
18-
fn: Function to check.
19-
latex: LaTeX form of `fn`.
20-
**kwargs: Arguments passed to `frontend.get_latex`.
21-
"""
22-
# Checks the syntax:
23-
# def fn(...):
24-
# ...
25-
# latexified = get_latex(fn, style=ALGORITHM, **kwargs)
26-
latexified = frontend.get_latex(fn, style=frontend.Style.ALGORITHMIC, **kwargs)
27-
assert latexified == latex
7+
from integration_tests import integration_utils
288

299

3010
def test_factorial() -> None:
@@ -34,18 +14,33 @@ def fact(n):
3414
else:
3515
return n * fact(n - 1)
3616

37-
latex = (
38-
r"\begin{algorithmic}"
39-
r" \Function{fact}{$n$}"
40-
r" \If{$n = 0$}"
41-
r" \State \Return $1$"
42-
r" \Else"
43-
r" \State \Return $n \mathrm{fact} \mathopen{}\left( n - 1 \mathclose{}\right)$"
44-
r" \EndIf"
45-
r" \EndFunction"
46-
r" \end{algorithmic}"
17+
latex = textwrap.dedent(
18+
r"""
19+
\begin{algorithmic}
20+
\Function{fact}{$n$}
21+
\If{$n = 0$}
22+
\State \Return $1$
23+
\Else
24+
\State \Return $n \cdot \mathrm{fact} \mathopen{}\left( n - 1 \mathclose{}\right)$
25+
\EndIf
26+
\EndFunction
27+
\end{algorithmic}
28+
""" # noqa: E501
29+
).strip()
30+
ipython_latex = (
31+
r"\begin{array}{l}"
32+
r" \mathbf{function} \ \mathrm{fact}(n) \\"
33+
r" \hspace{1em} \mathbf{if} \ n = 0 \\"
34+
r" \hspace{2em} \mathbf{return} \ 1 \\"
35+
r" \hspace{1em} \mathbf{else} \\"
36+
r" \hspace{2em}"
37+
r" \mathbf{return} \ n \cdot"
38+
r" \mathrm{fact} \mathopen{}\left( n - 1 \mathclose{}\right) \\"
39+
r" \hspace{1em} \mathbf{end \ if} \\"
40+
r" \mathbf{end \ function}"
41+
r" \end{array}"
4742
)
48-
check_algorithm(fact, latex)
43+
integration_utils.check_algorithm(fact, latex, ipython_latex)
4944

5045

5146
def test_collatz() -> None:
@@ -59,19 +54,39 @@ def collatz(n):
5954
iterations = iterations + 1
6055
return iterations
6156

62-
latex = (
63-
r"\begin{algorithmic}"
64-
r" \Function{collatz}{$n$}"
65-
r" \State $\mathrm{iterations} \gets 0$"
66-
r" \While{$n > 1$}"
67-
r" \If{$n \mathbin{\%} 2 = 0$}"
68-
r" \State $n \gets \left\lfloor\frac{n}{2}\right\rfloor$"
69-
r" \Else \State $n \gets 3 n + 1$"
70-
r" \EndIf"
71-
r" \State $\mathrm{iterations} \gets \mathrm{iterations} + 1$"
72-
r" \EndWhile"
73-
r" \State \Return $\mathrm{iterations}$"
74-
r" \EndFunction"
75-
r" \end{algorithmic}"
57+
latex = textwrap.dedent(
58+
r"""
59+
\begin{algorithmic}
60+
\Function{collatz}{$n$}
61+
\State $\mathrm{iterations} \gets 0$
62+
\While{$n > 1$}
63+
\If{$n \mathbin{\%} 2 = 0$}
64+
\State $n \gets \left\lfloor\frac{n}{2}\right\rfloor$
65+
\Else
66+
\State $n \gets 3 \cdot n + 1$
67+
\EndIf
68+
\State $\mathrm{iterations} \gets \mathrm{iterations} + 1$
69+
\EndWhile
70+
\State \Return $\mathrm{iterations}$
71+
\EndFunction
72+
\end{algorithmic}
73+
"""
74+
).strip()
75+
ipython_latex = (
76+
r"\begin{array}{l}"
77+
r" \mathbf{function} \ \mathrm{collatz}(n) \\"
78+
r" \hspace{1em} \mathrm{iterations} \gets 0 \\"
79+
r" \hspace{1em} \mathbf{while} \ n > 1 \\"
80+
r" \hspace{2em} \mathbf{if} \ n \mathbin{\%} 2 = 0 \\"
81+
r" \hspace{3em} n \gets \left\lfloor\frac{n}{2}\right\rfloor \\"
82+
r" \hspace{2em} \mathbf{else} \\"
83+
r" \hspace{3em} n \gets 3 \cdot n + 1 \\"
84+
r" \hspace{2em} \mathbf{end \ if} \\"
85+
r" \hspace{2em}"
86+
r" \mathrm{iterations} \gets \mathrm{iterations} + 1 \\"
87+
r" \hspace{1em} \mathbf{end \ while} \\"
88+
r" \hspace{1em} \mathbf{return} \ \mathrm{iterations} \\"
89+
r" \mathbf{end \ function}"
90+
r" \end{array}"
7691
)
77-
check_algorithm(collatz, latex)
92+
integration_utils.check_algorithm(collatz, latex, ipython_latex)

src/integration_tests/integration_utils.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,43 @@ def check_function(
4343
latexified = frontend.function(fn, **kwargs)
4444
assert str(latexified) == latex
4545
assert latexified._repr_latex_() == rf"$$ \displaystyle {latex} $$"
46+
47+
48+
def check_algorithm(
49+
fn: Callable[..., Any],
50+
latex: str,
51+
ipython_latex: str,
52+
**kwargs,
53+
) -> None:
54+
"""Helper to check if the obtained function has the expected LaTeX form.
55+
56+
Args:
57+
fn: Function to check.
58+
latex: LaTeX form of `fn`.
59+
ipython_latex: IPython LaTeX form of `fn`
60+
**kwargs: Arguments passed to `frontend.get_latex`.
61+
"""
62+
# Checks the syntax:
63+
# @algorithmic
64+
# def fn(...):
65+
# ...
66+
if not kwargs:
67+
latexified = frontend.algorithmic(fn)
68+
assert str(latexified) == latex
69+
assert latexified._repr_latex_() == f"$ {ipython_latex} $"
70+
71+
# Checks the syntax:
72+
# @algorithmic(**kwargs)
73+
# def fn(...):
74+
# ...
75+
latexified = frontend.algorithmic(**kwargs)(fn)
76+
assert str(latexified) == latex
77+
assert latexified._repr_latex_() == f"$ {ipython_latex} $"
78+
79+
# Checks the syntax:
80+
# def fn(...):
81+
# ...
82+
# latexified = algorithmic(fn, **kwargs)
83+
latexified = frontend.algorithmic(fn, **kwargs)
84+
assert str(latexified) == latex
85+
assert latexified._repr_latex_() == f"$ {ipython_latex} $"

src/integration_tests/regression_test.py

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ def test_quadratic_solution() -> None:
1111
def solve(a, b, c):
1212
return (-b + math.sqrt(b**2 - 4 * a * c)) / (2 * a)
1313

14-
latex = r"\mathrm{solve}(a, b, c) = \frac{-b + \sqrt{ b^{2} - 4 a c }}{2 a}"
14+
latex = (
15+
r"\mathrm{solve}(a, b, c) ="
16+
r" \frac{-b + \sqrt{ b^{2} - 4 \cdot a \cdot c }}{2 \cdot a}"
17+
)
1518
integration_utils.check_function(solve, latex)
1619

1720

@@ -36,13 +39,15 @@ def test_x_times_beta() -> None:
3639
def xtimesbeta(x, beta):
3740
return x * beta
3841

39-
latex_without_symbols = r"\mathrm{xtimesbeta}(x, \mathrm{beta}) = x \mathrm{beta}"
42+
latex_without_symbols = (
43+
r"\mathrm{xtimesbeta}(x, \mathrm{beta}) = x \cdot \mathrm{beta}"
44+
)
4045
integration_utils.check_function(xtimesbeta, latex_without_symbols)
4146
integration_utils.check_function(
4247
xtimesbeta, latex_without_symbols, use_math_symbols=False
4348
)
4449

45-
latex_with_symbols = r"\mathrm{xtimesbeta}(x, \beta) = x \beta"
50+
latex_with_symbols = r"\mathrm{xtimesbeta}(x, \beta) = x \cdot \beta"
4651
integration_utils.check_function(
4752
xtimesbeta, latex_with_symbols, use_math_symbols=True
4853
)
@@ -64,8 +69,8 @@ def sum_with_limit(a, n):
6469
return sum(i**2 for i in range(a, n))
6570

6671
latex = (
67-
r"\mathrm{sum\_with\_limit}(a, n) = \sum_{i = a}^{n - 1} "
68-
r"\mathopen{}\left({i^{2}}\mathclose{}\right)"
72+
r"\mathrm{sum\_with\_limit}(a, n) = \sum_{i = a}^{n - 1}"
73+
r" \mathopen{}\left({i^{2}}\mathclose{}\right)"
6974
)
7075
integration_utils.check_function(sum_with_limit, latex)
7176

@@ -75,8 +80,8 @@ def sum_with_limit(n):
7580
return sum(i for i in range(n + 1))
7681

7782
latex = (
78-
r"\mathrm{sum\_with\_limit}(n) = \sum_{i = 0}^{n} "
79-
r"\mathopen{}\left({i}\mathclose{}\right)"
83+
r"\mathrm{sum\_with\_limit}(n) = \sum_{i = 0}^{n}"
84+
r" \mathopen{}\left({i}\mathclose{}\right)"
8085
)
8186
integration_utils.check_function(sum_with_limit, latex)
8287

@@ -86,8 +91,8 @@ def sum_with_limit(n):
8691
return sum(i for i in range(n * 3))
8792

8893
latex = (
89-
r"\mathrm{sum\_with\_limit}(n) = \sum_{i = 0}^{n 3 - 1} "
90-
r"\mathopen{}\left({i}\mathclose{}\right)"
94+
r"\mathrm{sum\_with\_limit}(n) = \sum_{i = 0}^{n \cdot 3 - 1}"
95+
r" \mathopen{}\left({i}\mathclose{}\right)"
9196
)
9297
integration_utils.check_function(sum_with_limit, latex)
9398

@@ -97,8 +102,8 @@ def prod_with_limit(n):
97102
return math.prod(i**2 for i in range(n))
98103

99104
latex = (
100-
r"\mathrm{prod\_with\_limit}(n) = "
101-
r"\prod_{i = 0}^{n - 1} \mathopen{}\left({i^{2}}\mathclose{}\right)"
105+
r"\mathrm{prod\_with\_limit}(n) ="
106+
r" \prod_{i = 0}^{n - 1} \mathopen{}\left({i^{2}}\mathclose{}\right)"
102107
)
103108
integration_utils.check_function(prod_with_limit, latex)
104109

@@ -108,8 +113,8 @@ def prod_with_limit(a, n):
108113
return math.prod(i**2 for i in range(a, n))
109114

110115
latex = (
111-
r"\mathrm{prod\_with\_limit}(a, n) = "
112-
r"\prod_{i = a}^{n - 1} \mathopen{}\left({i^{2}}\mathclose{}\right)"
116+
r"\mathrm{prod\_with\_limit}(a, n) ="
117+
r" \prod_{i = a}^{n - 1} \mathopen{}\left({i^{2}}\mathclose{}\right)"
113118
)
114119
integration_utils.check_function(prod_with_limit, latex)
115120

@@ -119,8 +124,8 @@ def prod_with_limit(n):
119124
return math.prod(i for i in range(n - 1))
120125

121126
latex = (
122-
r"\mathrm{prod\_with\_limit}(n) = "
123-
r"\prod_{i = 0}^{n - 2} \mathopen{}\left({i}\mathclose{}\right)"
127+
r"\mathrm{prod\_with\_limit}(n) ="
128+
r" \prod_{i = 0}^{n - 2} \mathopen{}\left({i}\mathclose{}\right)"
124129
)
125130
integration_utils.check_function(prod_with_limit, latex)
126131

@@ -131,7 +136,7 @@ def prod_with_limit(n):
131136

132137
latex = (
133138
r"\mathrm{prod\_with\_limit}(n) = "
134-
r"\prod_{i = 0}^{n 3 - 1} \mathopen{}\left({i}\mathclose{}\right)"
139+
r"\prod_{i = 0}^{n \cdot 3 - 1} \mathopen{}\left({i}\mathclose{}\right)"
135140
)
136141
integration_utils.check_function(prod_with_limit, latex)
137142

@@ -140,7 +145,7 @@ def test_nested_function() -> None:
140145
def nested(x):
141146
return 3 * x
142147

143-
integration_utils.check_function(nested, r"\mathrm{nested}(x) = 3 x")
148+
integration_utils.check_function(nested, r"\mathrm{nested}(x) = 3 \cdot x")
144149

145150

146151
def test_double_nested_function() -> None:
@@ -150,7 +155,7 @@ def inner(y):
150155

151156
return inner
152157

153-
integration_utils.check_function(nested(3), r"\mathrm{inner}(y) = x y")
158+
integration_utils.check_function(nested(3), r"\mathrm{inner}(y) = x \cdot y")
154159

155160

156161
def test_reduce_assignments() -> None:
@@ -160,11 +165,11 @@ def f(x):
160165

161166
integration_utils.check_function(
162167
f,
163-
r"\begin{array}{l} a = x + x \\ f(x) = 3 a \end{array}",
168+
r"\begin{array}{l} a = x + x \\ f(x) = 3 \cdot a \end{array}",
164169
)
165170
integration_utils.check_function(
166171
f,
167-
r"f(x) = 3 \mathopen{}\left( x + x \mathclose{}\right)",
172+
r"f(x) = 3 \cdot \mathopen{}\left( x + x \mathclose{}\right)",
168173
reduce_assignments=True,
169174
)
170175

@@ -176,18 +181,18 @@ def f(x):
176181
return 3 * b
177182

178183
latex_without_option = (
179-
r"\begin{array}{l} "
180-
r"a = x^{2} \\ "
181-
r"b = a + a \\ "
182-
r"f(x) = 3 b "
183-
r"\end{array}"
184+
r"\begin{array}{l}"
185+
r" a = x^{2} \\"
186+
r" b = a + a \\"
187+
r" f(x) = 3 \cdot b"
188+
r" \end{array}"
184189
)
185190

186191
integration_utils.check_function(f, latex_without_option)
187192
integration_utils.check_function(f, latex_without_option, reduce_assignments=False)
188193
integration_utils.check_function(
189194
f,
190-
r"f(x) = 3 \mathopen{}\left( x^{2} + x^{2} \mathclose{}\right)",
195+
r"f(x) = 3 \cdot \mathopen{}\left( x^{2} + x^{2} \mathclose{}\right)",
191196
reduce_assignments=True,
192197
)
193198

@@ -204,12 +209,12 @@ def sigmoid(x):
204209
integration_utils.check_function(
205210
sigmoid,
206211
(
207-
r"\mathrm{sigmoid}(x) = \left\{ \begin{array}{ll} "
208-
r"\frac{1}{1 + \exp \mathopen{}\left( -x \mathclose{}\right)}, & "
209-
r"\mathrm{if} \ x > 0 \\ "
210-
r"\frac{\exp x}{\exp x + 1}, & "
211-
r"\mathrm{otherwise} "
212-
r"\end{array} \right."
212+
r"\mathrm{sigmoid}(x) = \left\{ \begin{array}{ll}"
213+
r" \frac{1}{1 + \exp \mathopen{}\left( -x \mathclose{}\right)}, &"
214+
r" \mathrm{if} \ x > 0 \\"
215+
r" \frac{\exp x}{\exp x + 1}, &"
216+
r" \mathrm{otherwise}"
217+
r" \end{array} \right."
213218
),
214219
reduce_assignments=True,
215220
)
@@ -220,10 +225,10 @@ def solve(a, b):
220225
return ((a + b) - b) / (a - b) - (a + b) - (a - b) - (a * b)
221226

222227
latex = (
223-
r"\mathrm{solve}(a, b) = "
224-
r"\frac{a + b - b}{a - b} - \mathopen{}\left( "
225-
r"a + b \mathclose{}\right) - \mathopen{}\left( "
226-
r"a - b \mathclose{}\right) - a b"
228+
r"\mathrm{solve}(a, b) ="
229+
r" \frac{a + b - b}{a - b} - \mathopen{}\left("
230+
r" a + b \mathclose{}\right) - \mathopen{}\left("
231+
r" a - b \mathclose{}\right) - a \cdot b"
227232
)
228233
integration_utils.check_function(solve, latex)
229234

src/latexify/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
except Exception:
88
__version__ = ""
99

10-
from latexify import frontend
10+
from latexify import frontend, generate_latex
1111

12-
Style = frontend.Style
12+
Style = generate_latex.Style
1313

14-
get_latex = frontend.get_latex
14+
get_latex = generate_latex.get_latex
1515

16-
function = frontend.function
16+
algorithmic = frontend.algorithmic
1717
expression = frontend.expression
18+
function = frontend.function

src/latexify/codegen/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
AlgorithmicCodegen = algorithmic_codegen.AlgorithmicCodegen
66
ExpressionCodegen = expression_codegen.ExpressionCodegen
77
FunctionCodegen = function_codegen.FunctionCodegen
8+
IPythonAlgorithmicCodegen = algorithmic_codegen.IPythonAlgorithmicCodegen

0 commit comments

Comments
 (0)