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

[Demo PR] Format sympy/solvers with yapf #22437

Closed
wants to merge 11 commits into from
Closed

[Demo PR] Format sympy/solvers with yapf #22437

wants to merge 11 commits into from

Conversation

redeboer
Copy link
Contributor

@redeboer redeboer commented Nov 6, 2021

This is a follow-up demo to #22434 (now with yapf) and is not to be merged. See also #17287 (comment).

I played around a bit with the yapf configuration to improve the spacing around arithmetic operators and get it to look a bit more like black (see comparison):

sympy/setup.cfg

Lines 91 to 98 in 2d90dc1

[yapf]
based_on_style = pep8
allow_split_before_dict_value = False
arithmetic_precedence_indication = True
dedent_closing_brackets = True
no_spaces_around_selected_binary_operators = *,/
split_complex_comprehension = True

Release Notes

NO ENTRY

Applied formatting as follows:

```shell
yapf -i -p $(git ls-files | grep -E "sympy/solvers/.*\.py")
```
@sympy-bot
Copy link

sympy-bot commented Nov 6, 2021

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

  • No release notes entry will be added for this pull request.
Click here to see the pull request description that was parsed.
**This is a follow-up demo to #22434 (now with [yapf](https://github.com/google/yapf)) and is not to be merged. See also https://github.com/sympy/sympy/issues/17287#issuecomment-962292806.**

I played around a bit with the yapf configuration to improve the spacing around arithmetic operators and get it to look a bit more like black (see [comparison](https://github.com/redeboer/sympy/compare/17287-apply-yapf-to-solvers...17287-apply-black-to-solvers?expand=1)):

https://github.com/sympy/sympy/blob/2d90dc1d91b1d16679bec2c0f94d49b836b5315b/setup.cfg#L91-L98

#### Release Notes

<!-- BEGIN RELEASE NOTES -->
NO ENTRY
<!-- END RELEASE NOTES -->

@sympy-bot
Copy link

sympy-bot commented Nov 6, 2021

🟠

Hi, I am the SymPy bot (v162). I've noticed that some of your commits add or delete files. Since this is sometimes done unintentionally, I wanted to alert you about it.

This is an experimental feature of SymPy Bot. If you have any feedback on it, please comment at sympy/sympy-bot#75.

The following commits add new files:

If these files were added/deleted on purpose, you can ignore this message.

@redeboer redeboer changed the title 17287 apply yapf to solvers [Demo PR] Apply yapf to sympy/solvers Nov 6, 2021
@redeboer redeboer changed the title [Demo PR] Apply yapf to sympy/solvers [Demo PR] Format sympy/solvers with yapf Nov 6, 2021
I0_num, I0_dem = I0.as_numer_denom()
# collecting coeff of (x**2, x), of the standerd equation.
# substituting (a-b) = s, (a+b) = r
dict_I0 = {x**2:s**2 - 1, x:(2*(1-r)*c + (r+s)*(r-s)), 1:c*(c-2)}
dict_I0 = {x**2: s**2 - 1, x: (2*(1-r)*c + (r+s)*(r-s)), 1: c*(c-2)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is reluctant to make changes in values of the dict; compare this to the addition of space arount the + at line 198 a few lines below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is due to this option:

arithmetic_precedence_indication = True

If you remove that option, it becomes:

    dict_I0 = {
        x**2: s**2 - 1,
        x: (2*(1 - r)*c + (r + s)*(r - s)),
        1: c*(c - 2)
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(line-breaks are just because this didn't fit within 79 anymore)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that looks better

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I switched it off (ba85647), but we have to check if that has undesired consequences elsewhere.

sympy/solvers/ode/riccati.py Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Nov 6, 2021

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
     [907895ac]       [6247eefd]
-      5.56±0.02s          340±4ms     0.06  polygon.PolygonArbitraryPoint.time_bench01

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

Comment on lines -209 to +238
hints = classifier(eq, func, dict=True, ics=ics, xi=xi, eta=eta,
n=terms, x0=x0, hint=hint, prep=prep)
hints = classifier(
eq,
func,
dict=True,
ics=ics,
xi=xi,
eta=eta,
n=terms,
x0=x0,
hint=hint,
prep=prep
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like this change. Maybe I would make a **opts dict or something but I'm not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line breaks are there because of the 79 column limit. If you set it to something like 100, it becomes:

        hints = classifier(
            eq, func, dict=True, ics=ics, xi=xi, eta=eta, n=terms, x0=x0, hint=hint, prep=prep
        )

(I would stick with PEP8's 79, but it illustrates that arguments are put on one line if possible.)

The dedenting is the same effect as you noted here #22437 (comment). But yapf's default profile ("pep8") looks worse imo:

        hints = classifier(eq,
                           func,
                           dict=True,
                           ics=ics,
                           xi=xi,
                           eta=eta,
                           n=terms,
                           x0=x0,
                           hint=hint,
                           prep=prep)

Note that the same happens in function with many arguments:

def _desolve(
eq,
func=None,
hint="default",
ics=None,
simplify=True,
*,
prep=True,
**kwargs
):

For function definitions, this style is quite helpful when type hints are added.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type hints may change it, but I'm not a fan of this either. OK if it re-breaks the lines to have 80 characters, but having a separate line for each argument... (similar to the init-files)

Comment on lines 539 to 559
s = BinaryQuadratic(self.equation, free_symbols=[y, x]).solve(parameters=[t, u])
s = BinaryQuadratic(self.equation,
free_symbols=[y,
x]).solve(parameters=[t, u])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like an odd choice of line breaks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's left -aligning elements at the opening bracket position if there is more than 1. It's kind of nice because you can scan vertically to see what the given brackets args are -- breadth first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh I don't understand the formatting here :S It looks like this also with the default yapf profile... But with split_before_expression_after_opening_paren = True, you get:

                s = BinaryQuadratic(
                    self.equation, free_symbols=[y, x]
                ).solve(parameters=[t, u])

See d864ba2

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is another situation where an intermediate variable with a good name would be better

if (
divisible(sqa*g*z0**2 + D*z0 + sqa*F, _c)
and divisible(e*sqc*g*z0**2 + E*z0 + e*sqc*F, _c)
):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why both black and yapf seem to prefer the unindented reverse smiley ):.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the issue page on which you commented recently at black mentioned about how they tokenize and without looking ahead or back, that is just the simplest thing to do. It also visually marks the range of the if

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why both black and yapf seem to prefer the unindented reverse smiley ):.

Haha reverse smiley. Actually, this is not the default yapf behaviour. It's a consequence of this option, which I added to mimic black:

sympy/setup.cfg

Lines 95 to 96 in 2d90dc1

arithmetic_precedence_indication = True
dedent_closing_brackets = True

If you remove that option, you get:

                        if (divisible(sqa*g*z0**2 + D*z0 + sqa*F, _c) and
                                divisible(e*sqc*g*z0**2 + E*z0 + e*sqc*F, _c)):
                            result.add((solve_x(z0), solve_y(z0)))

Even if the above is more 'concise', I think the split 'black' version is easier to understand at one glance.

Note: I had hoped split_before_logical_operator = True may improve the above a bit, but this seems to have no effect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove that option, you get:

                        if (divisible(sqa*g*z0**2 + D*z0 + sqa*F, _c) and
                                divisible(e*sqc*g*z0**2 + E*z0 + e*sqc*F, _c)):
                            result.add((solve_x(z0), solve_y(z0)))

That looks more like what I would have done when editing the code myself.

Comment on lines 582 to 605
4*A*r*u*v + 4*A*D*(B*v + r*u + r*v - B*u) +
2*A*4*A*E*(u - v) + 4*A*r*4*A*F)
4*A*r*u*v + 4*A*D*(B*v + r*u + r*v - B*u) + 2*A*4*A*E*
(u-v) + 4*A*r*4*A*F
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is odd. I'd rather break on + than *.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted, looks strange indeed... It seems that split_before_arithmetic_operator = True (c9054b1) helps here, and it's also more in line with black style:

                eq = _mexpand(
                    4*A*r*u*v + 4*A*D*(B*v + r*u + r*v - B*u)
                    + 2*A*4*A*E*(u-v) + 4*A*r*4*A*F
                )

Comment on lines 601 to 627
s = BinaryQuadratic(self.equation, free_symbols=var[::-1]).solve(parameters=[t, u]) # Interchange x and y
s = BinaryQuadratic(self.equation,
free_symbols=var[::-1]).solve(
parameters=[t, u]
) # Interchange x and y
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is the kind of situation where an intermediate variable would help.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last time (above) it didn't break on the single argument. I guess it did now because of line length.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is the kind of situation where an intermediate variable would help.

True, although same as #22437 (comment), I don't really get why the formatting looks like this. But split_before_expression_after_opening_paren = True (d864ba2) improves it:

                s = BinaryQuadratic(
                    self.equation, free_symbols=var[::-1]
                ).solve(parameters=[t, u])  # Interchange x and y

Last time (above) it didn't break on the single argument. I guess it did now because of line length.

With black? Could be; black wraps at 88 by default.

@oscarbenjamin
Copy link
Contributor

I haven't been through the whole diff but this looks a lot better than black because it has much better handling of mathematical expressions.

@redeboer
Copy link
Contributor Author

redeboer commented Nov 7, 2021

this looks a lot better than black because it has much better handling of mathematical expressions

I agree. With the recently added commits I'm also more satisfied with the diff.

So I think the current config is quite suitable. The next question is how to apply this formatting. For sure it has to be done by a bot, because this will result in a large amount of line changes ('contributions').

@oscarbenjamin
Copy link
Contributor

The next question is how to apply this formatting

No, I think the next step is to go back to the original issue and ask for the opinions of others. I think that this is better than black but that doesn't mean I'm convinced that we should go with this (or indeed with any automatic formatting). There are many others whose inputs are needed and there needs to be something like consensus before adopting anything as invasive as this across the codebase.

Actually applying the changes is straight-forward once the basic idea is agreed and the details are worked out. We don't need a bot, we just need some people to make a bunch of PRs of manageable size and then others to review and merge those PRs.

@redeboer
Copy link
Contributor Author

redeboer commented Nov 7, 2021

The next question is how to apply this formatting

No, I think the next step is to go back to the original issue

Sounds like a good next step. I think that question about applying formatting by a bot vs individuals will still have to be discussed as well though.

@redeboer redeboer closed this by deleting the head repository Jan 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants