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

Fix unevaluated printing of negative sum in numerator #24111

Merged
merged 1 commit into from Oct 6, 2022

Conversation

oscargus
Copy link
Contributor

@oscargus oscargus commented Oct 5, 2022

References to other Issues or PRs

Fixes #24108

Brief description of what is fixed or changed

Other comments

Release Notes

  • printing
    • Fix str of numerator consisting of a sum where a minus signs can be extracted.

@oscargus oscargus added printing unevaluated Issues related to unevaluated expressions labels Oct 5, 2022
@sympy-bot
Copy link

sympy-bot commented Oct 5, 2022

Hi, I am the SymPy bot (v167). I'm here to help you write a release notes entry. Please read the guide on how to write release notes.

Your release notes are in good order.

Here is what the release notes will look like:

  • printing
    • Fix str of numerator consisting of a sum where a minus signs can be extracted. (#24111 by @oscargus)

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.12.

Click here to see the pull request description that was parsed.
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->

Fixes #24108 

#### Brief description of what is fixed or changed


#### Other comments


#### Release Notes

<!-- Write the release notes for this release below between the BEGIN and END
statements. The basic format is a bulleted list with the name of the subpackage
and the release note for this PR. For example:

* solvers
  * Added a new solver for logarithmic equations.

* functions
  * Fixed a bug with log of integers.

or if no release note(s) should be included use:

NO ENTRY

See https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more
information on how to write release notes. The bot will check your release
notes automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
* printing
   * Fix str of numerator consisting of a sum where a minus signs can be extracted.
<!-- END RELEASE NOTES -->

Update

The release notes on the wiki have been updated.

@oscargus
Copy link
Contributor Author

oscargus commented Oct 5, 2022

Test program

from sympy import * 
from sympy.parsing.latex import parse_latex
expr = parse_latex('\\frac {-1 - 1}{2}')
expr2 = parse_latex('\\frac {-\\sin(x)}{2}')
expr3 = parse_latex('\\frac {-a - b}{2}')
expr4 = parse_latex('\\frac {-1 - 1*3}{2}')
expr5 = parse_latex('\\frac {-1 - 1*1}{2}')
print(expr)
print(expr2)
print(expr3)
print(expr4)
print(expr5)

With this PR:

(-1 - 1*1)/2
-sin(x)/2
(-a - b)/2
(-3 - 1)/2
(-1 - 1)/2

With master:

-1 - 1*1/2
-sin(x)/2
-a - b/2
-3 - 1/2
-1 - 1/2

@github-actions
Copy link

github-actions bot commented Oct 5, 2022

Benchmark results from GitHub Actions

Lower numbers are good, higher numbers are bad. A ratio less than 1
means a speed up and greater than 1 means a slowdown. Green lines
beginning with + are slowdowns (the PR is slower then master or
master is slower than the previous release). Red lines beginning
with - are speedups.

Significantly changed benchmark results (PR vs master)

Significantly changed benchmark results (master vs previous release)

       before           after         ratio
     [41d90958]       [a2400344]
     <sympy-1.11.1^0>                 
-         956±2μs          612±2μs     0.64  solve.TimeSparseSystem.time_linear_eq_to_matrix(10)
-     2.77±0.01ms         1.15±0ms     0.41  solve.TimeSparseSystem.time_linear_eq_to_matrix(20)
-     5.55±0.01ms         1.69±0ms     0.30  solve.TimeSparseSystem.time_linear_eq_to_matrix(30)

Full benchmark results can be found as artifacts in GitHub Actions
(click on checks at the top of the PR).

@oscarbenjamin
Copy link
Contributor

Looks good.

@smichr
Copy link
Member

smichr commented Oct 5, 2022

see also #24022 and #24111

@oscarbenjamin
Copy link
Contributor

Looks like the added tests fail.

@oscargus oscargus force-pushed the anotherunevaluatedprintingbug branch from fdf52ca to 9cbb351 Compare October 6, 2022 07:14
@oscargus
Copy link
Contributor Author

oscargus commented Oct 6, 2022

Fixed the tests and replaced str with self._print as @asmeurer correctly pointed out in #24108 (comment)

As @smichr points out, there are related issues. The test here must be updated when the -1*1 print issue is fixed.

@oscargus oscargus force-pushed the anotherunevaluatedprintingbug branch from 9cbb351 to 30ed997 Compare October 6, 2022 07:25
@oscarbenjamin
Copy link
Contributor

the -1*1 print issue

Is that an issue with printing or with parsing?

To me this looks correct for the printing code:

In [7]: Mul(-1, 1, evaluate=False)
Out[7]: -11

That printed output is a correct representation of the expression that is being printed.

The question coming back from there is why do you have a -1*1 expression in the first place? If that expression comes from e.g. parse_latex then maybe parse_latex should be fixed i.e. this is the bug:

In [10]: srepr(parse_expr('1-1', evaluate=False))
Out[10]: 'Add(Integer(1), Mul(Integer(-1), Integer(1)))'

That could be Add(Integer(1), Integer(-1)) although I'm not 100% sure what is best.

@oscarbenjamin oscarbenjamin merged commit ebde7f2 into sympy:master Oct 6, 2022
@oscargus
Copy link
Contributor Author

oscargus commented Oct 7, 2022

Not sure. The "ironic" thing is that parse_latex('\\frac {-1 - 1*1}{2}') is printed as (-1 - 1)/2 but parse_latex('\\frac {-1 - 1}{2}') is printed as (-1 - 1*1)/2.

The question coming back from there is why do you have a -1*1 expression in the first place?

I'm inclined to ask why anyone would like unevaluated printing at all...

@oscargus oscargus deleted the anotherunevaluatedprintingbug branch October 7, 2022 10:20
@oscargus
Copy link
Contributor Author

oscargus commented Oct 7, 2022

I think it was a parsing bug and should be fixed by #24096

@oscarbenjamin
Copy link
Contributor

I'm inclined to ask why anyone would like unevaluated printing at all...

I think what is really wanted is to be able to control how expressions are printed. In other words for some uses it should be possible to define an expression that is to be printed in a certain way and then have it printed in exactly that way.

This is sometimes for prettiness purposes e.g. if you aren't really doing much heavy computing with SymPy but you want it to produce displayed equations. Then this kind of thing ruins your equations:

In [6]: pdf = 1/(sigma*sqrt(2*pi))*exp(-((x - mu)/sigma)**2)

In [7]: pdf
Out[7]: 
             2 
    -(-μ + x)  
    ───────────
          2    
         σ     
√2⋅ℯ           
───────────────
     2⋅√π⋅σ

In that context someone might use evaluate=False to stop evaluation from messing up their expressions but then they still have to contend with the printer not printing their expressions in the intended way.

The other context is things related to code generation e.g. in floating point you might need to care about the distinction between (x + y) + z and x + (y + z).

The problem is that SymPy just hasn't been designed with these uses in mind and evaluate=False is essentially a bolt on that never completely works.

@oscarbenjamin
Copy link
Contributor

I think it was a parsing bug and should be fixed by #24096

Yes, looks like it:

In [2]: from sympy.parsing.latex import parse_latex

In [3]: parse_latex('\\frac {-1 - 1*1}{2}')
Out[3]: 
-1 - 11
────────
   2    

In [4]: parse_latex('\\frac {-1 - 1}{2}')
Out[4]: 
-1 - 1
──────
  2  

@asmeurer
Copy link
Member

asmeurer commented Oct 7, 2022

In that context someone might use evaluate=False to stop evaluation from messing up their expressions but then they still have to contend with the printer not printing their expressions in the intended way.

That seems fine, albeit annoying. But many of the annoyances are due to things we shouldn't be doing in the printers anyway (like sorting). Again, if the printers could actually tell if an expression was "unevaluated" it would make this easier.

The other context is things related to code generation e.g. in floating point you might need to care about the distinction between (x + y) + z and x + (y + z).

I don't like this as a use-case. If you want this sort of thing for code generation you should use special codegen nodes. evaluate=False is much more fragile for code generation because you're more likely to actually do computation with expressions that are used for codegen, but you never want to do computation on unevaluated expressions. That's where things break and you can get all sorts of bugs, because no other part of the codebase is designed around them. I know the original issue author mentioned code generation, but I don't see why you'd need -1 - 1 to be unevaluated for codegen purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
printing unevaluated Issues related to unevaluated expressions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrect printing of parse_latex('\\frac {-1 - 1}{2}')
5 participants