1111# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212# See the License for the specific language governing permissions and
1313# limitations under the License.
14+
1415import numpy as np
1516
1617from pytensor .tensor .random import normal
@@ -171,15 +172,15 @@ def setup_class(self):
171172 r"$\text{mu} \sim \operatorname{Deterministic}(f(\text{beta},~\text{alpha}))$" ,
172173 r"$\text{beta} \sim \operatorname{Normal}(0,~10)$" ,
173174 r"$\text{Z} \sim \operatorname{MultivariateNormal}(f(),~f())$" ,
174- r"$\text{nb_with_p_n } \sim \operatorname{NegativeBinomial}(10,~\text{nbp})$" ,
175+ r"$\text{nb\_with\_p\_n } \sim \operatorname{NegativeBinomial}(10,~\text{nbp})$" ,
175176 r"$\text{zip} \sim \operatorname{MarginalMixture}(f(),~\operatorname{DiracDelta}(0),~\operatorname{Poisson}(5))$" ,
176177 r"$\text{w} \sim \operatorname{Dirichlet}(\text{<constant>})$" ,
177178 (
178- r"$\text{nested_mix } \sim \operatorname{MarginalMixture}(\text{w},"
179+ r"$\text{nested\_mix } \sim \operatorname{MarginalMixture}(\text{w},"
179180 r"~\operatorname{MarginalMixture}(f(),~\operatorname{DiracDelta}(0),~\operatorname{Poisson}(5)),"
180181 r"~\operatorname{Censored}(\operatorname{Bernoulli}(0.5),~-1,~1))$"
181182 ),
182- r"$\text{Y_obs } \sim \operatorname{Normal}(\text{mu},~\text{sigma})$" ,
183+ r"$\text{Y\_obs } \sim \operatorname{Normal}(\text{mu},~\text{sigma})$" ,
183184 r"$\text{pot} \sim \operatorname{Potential}(f(\text{beta},~\text{alpha}))$" ,
184185 r"$\text{pred} \sim \operatorname{Deterministic}(f(\text{<normal>}))" ,
185186 ],
@@ -189,11 +190,11 @@ def setup_class(self):
189190 r"$\text{mu} \sim \operatorname{Deterministic}$" ,
190191 r"$\text{beta} \sim \operatorname{Normal}$" ,
191192 r"$\text{Z} \sim \operatorname{MultivariateNormal}$" ,
192- r"$\text{nb_with_p_n } \sim \operatorname{NegativeBinomial}$" ,
193+ r"$\text{nb\_with\_p\_n } \sim \operatorname{NegativeBinomial}$" ,
193194 r"$\text{zip} \sim \operatorname{MarginalMixture}$" ,
194195 r"$\text{w} \sim \operatorname{Dirichlet}$" ,
195- r"$\text{nested_mix } \sim \operatorname{MarginalMixture}$" ,
196- r"$\text{Y_obs } \sim \operatorname{Normal}$" ,
196+ r"$\text{nested\_mix } \sim \operatorname{MarginalMixture}$" ,
197+ r"$\text{Y\_obs } \sim \operatorname{Normal}$" ,
197198 r"$\text{pot} \sim \operatorname{Potential}$" ,
198199 r"$\text{pred} \sim \operatorname{Deterministic}" ,
199200 ],
@@ -256,7 +257,7 @@ def test_model_latex_repr_three_levels_model():
256257 "$$" ,
257258 "\\ begin{array}{rcl}" ,
258259 "\\ text{mu} &\\ sim & \\ operatorname{Normal}(0,~5)\\ \\ \\ text{sigma} &\\ sim & "
259- "\\ operatorname{HalfCauchy}(0,~2.5)\\ \\ \\ text{censored_normal } &\\ sim & "
260+ "\\ operatorname{HalfCauchy}(0,~2.5)\\ \\ \\ text{censored \\ _normal } &\\ sim & "
260261 "\\ operatorname{Censored}(\\ operatorname{Normal}(\\ text{mu},~\\ text{sigma}),~-2,~2)" ,
261262 "\\ end{array}" ,
262263 "$$" ,
@@ -316,3 +317,22 @@ def random(rng, mu, size):
316317
317318 str_repr = model .str_repr (include_params = False )
318319 assert str_repr == "\n " .join (["x ~ CustomDistNormal" , "y ~ CustomRandomNormal" ])
320+
321+
322+ class TestLatexRepr :
323+ @staticmethod
324+ def simple_model () -> Model :
325+ with Model () as simple_model :
326+ error = HalfNormal ("error" , 0.5 )
327+ alpha_a = Normal ("alpha_a" , 0 , 1 )
328+ Normal ("y" , alpha_a , error )
329+ return simple_model
330+
331+ def test_latex_escaped_underscore (self ):
332+ """
333+ Ensures that all underscores in model variable names are properly escaped for LaTeX representation
334+ """
335+ model = self .simple_model ()
336+ model_str = model .str_repr (formatting = "latex" )
337+ assert "\\ _" in model_str
338+ assert "_" not in model_str .replace ("\\ _" , "" )
0 commit comments