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

TODO: rebase Addressing Piecewise issues #1009

Closed
wants to merge 13 commits into
base: master
from

Conversation

Projects
None yet
6 participants
@flacjacket
Member

flacjacket commented Jan 22, 2012

This push is to address a couple open issues with Piecewise and its syntax, notably changing the otherwise syntax. Other major changes with this commit are getting rid of the ExprCondPair class and changing how evaluation is handled. The use of True as the condition to specify otherwise conditions is deprecated. Additionally, the use of numbers as conditions is deprecated and the use of Interval's as conditions is dropped entirely. To implement the same functionality, either the '.as_relational()' or '.contains()' methods of Interval can be used.

As before, evaluation strips any bools out of the args by dropping expressions with False, but now expressions with condition=True are promoted to the otherwise statement by evaluation. Evaluation is not performed by default, but it is called when subs is called to allow for evaluation in that case. When bools end up in the args and evaluate is the default value of False, a deprecation warning is raised and evaluate is set to True to get clear the args of the bool.

The properties '.exprcondpairs' and '.otherwise' are implemented to easily access the expr/cond pairs and otherwise statement, respectively.

TODO:

This addresses the following issues:

#5200 (closed) latex printing with piecewise function : reversed expr and cond

#5666 (now doesn't raise an error but perhaps could be better than Piecewise()) Piecewise does not work when not given an "otherwise" condition

#5725 Piecewise should use a different syntax for "otherwise"

#5809 (closed) Cannot simplify Piecewise

#5825 (closed) Piecewise((1,Interval(0,1,False,True)),(0,True)) syntax should not be allowed

Also, the following also seems like it has been handled, but not closed:

#4315 (no error but discussion about what the result should be) series expansion of piecewise fails

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 22, 2012

Member

Thanks for working on this. I started to work on this a while back, but I ran into problems with _eval_leading_term. Did you encounter those issues?

Member

asmeurer commented Jan 22, 2012

Thanks for working on this. I started to work on this a while back, but I ran into problems with _eval_leading_term. Did you encounter those issues?

@asmeurer

View changes

Show outdated Hide outdated sympy/functions/elementary/piecewise.py
@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 22, 2012

Member

You've made things awfully complicated here? Why don't you just do what was suggested in issue 2626? Namely, use the syntax, Piecewise((expr1, cond1), ..., (exprn, condn), [otherwise]) (where the square brackets indicate that the argument is optional).

Member

asmeurer commented Jan 22, 2012

You've made things awfully complicated here? Why don't you just do what was suggested in issue 2626? Namely, use the syntax, Piecewise((expr1, cond1), ..., (exprn, condn), [otherwise]) (where the square brackets indicate that the argument is optional).

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 22, 2012

Member

Ah, well I see that that syntax does work in your branch. I suppose the complicated .args is necessary to support the old syntax as well (?) I think that .args should just use the new syntax, and all other supported syntaxes should be canonicalized to it for .args (similar to what Integral does).

By the way, I also think we ought to deprecate the old syntax, as it's very confusing.

Member

asmeurer commented Jan 22, 2012

Ah, well I see that that syntax does work in your branch. I suppose the complicated .args is necessary to support the old syntax as well (?) I think that .args should just use the new syntax, and all other supported syntaxes should be canonicalized to it for .args (similar to what Integral does).

By the way, I also think we ought to deprecate the old syntax, as it's very confusing.

@asmeurer

View changes

Show outdated Hide outdated sympy/functions/elementary/piecewise.py
@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 22, 2012

Member

The first commit I don't think makes things terribly complicated, it mostly just adds the ability to have the otherwise expression in addition to adding the .ecs and .otherwise properties to easily get out the expr/cond pairs and otherwise statements, since the args can no longer be iterated as 'e, c in args'.

The second commit makes things more complicated as it changes the canonical args to allow evaluate to be maintained between things like subs. The more I think about it, the more I think this might not be necessary, as the only use is when you want to do something like Piecewise((x,x>0), evaluate=False).subs(x,1) and want it to return a Piecewise rather than just returning 1.

As for the old syntax, I'm not sure that can really be deprecated. or at least we can't really raise warnings, as there shouldn't be anything wrong with having True as a condition, especially since there's no way to tell a condition 1>0 or (x>0).subs(x,1) apart from True. I changed all the instances in the code to use the new otherwise syntax and changed the documentation to reflect this.

In the same vein, in issue 2626, you noted allowing a 1-tuple for an otherwise statement, I'm not entirely sure if this is necessary, but I included it as a possibility, that may be leading to an increased mess in some of the code.

I had the same problem with _eval_leading_term. Function tried to do _eval_leading_term on args[0], but since for a Piecewise that's a Tuple, it fails. What I implemented was to add all the expressions, including otherwise, together and return _eval_leading_term of that. I'm not sure if that would be the desired behavior for a Piecewise function or if it should take the expression when the variable goes to 0, but it works in as much as the old tests still pass.

Member

flacjacket commented Jan 22, 2012

The first commit I don't think makes things terribly complicated, it mostly just adds the ability to have the otherwise expression in addition to adding the .ecs and .otherwise properties to easily get out the expr/cond pairs and otherwise statements, since the args can no longer be iterated as 'e, c in args'.

The second commit makes things more complicated as it changes the canonical args to allow evaluate to be maintained between things like subs. The more I think about it, the more I think this might not be necessary, as the only use is when you want to do something like Piecewise((x,x>0), evaluate=False).subs(x,1) and want it to return a Piecewise rather than just returning 1.

As for the old syntax, I'm not sure that can really be deprecated. or at least we can't really raise warnings, as there shouldn't be anything wrong with having True as a condition, especially since there's no way to tell a condition 1>0 or (x>0).subs(x,1) apart from True. I changed all the instances in the code to use the new otherwise syntax and changed the documentation to reflect this.

In the same vein, in issue 2626, you noted allowing a 1-tuple for an otherwise statement, I'm not entirely sure if this is necessary, but I included it as a possibility, that may be leading to an increased mess in some of the code.

I had the same problem with _eval_leading_term. Function tried to do _eval_leading_term on args[0], but since for a Piecewise that's a Tuple, it fails. What I implemented was to add all the expressions, including otherwise, together and return _eval_leading_term of that. I'm not sure if that would be the desired behavior for a Piecewise function or if it should take the expression when the variable goes to 0, but it works in as much as the old tests still pass.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 22, 2012

Member

This needs to be merged or rebased with master. The issue is most likely the branch I recently pushed in that refactors the inequality classes.

Member

asmeurer commented Jan 22, 2012

This needs to be merged or rebased with master. The issue is most likely the branch I recently pushed in that refactors the inequality classes.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 22, 2012

Member

Right. To be more clear, the complication is specifically in .args, and as a result in anything that parses .args, and the code that builds it. .args should just be ((expr, cond), ..., otherwise).

The more I think about it, the more I think this might not be necessary, as the only use is when you want to do something like Piecewise((x,x>0), evaluate=False).subs(x,1) and want it to return a Piecewise rather than just returning 1.

I think the solution here is to keep 1 > 0 from being evaluated. You will need to implement the evaluate keyword in the new inequality classes. Then Piecewise can just pass the evaluate flag to that (or do you think it would be cleaner to not do that automatically and require the user to do it?).

In the same vein, in issue 2626, you noted allowing a 1-tuple for an otherwise statement, I'm not entirely sure if this is necessary, but I included it as a possibility, that may be leading to an increased mess in some of the code.

This is an added source of complication. It is not necessary to support this syntax. We decided against it.

I had the same problem with _eval_leading_term. Function tried to do _eval_leading_term on args[0], but since for a Piecewise that's a Tuple, it fails. What I implemented was to add all the expressions, including otherwise, together and return _eval_leading_term of that. I'm not sure if that would be the desired behavior for a Piecewise function or if it should take the expression when the variable goes to 0, but it works in as much as the old tests still pass.

@ness01 or someone who knows more about what that does will have to comment. Is it OK for _eval_leading_term to "overestimate", so to speak? Getting the term at 0 may not be so easy, as the conditions could be more than one dimensional, and hence be symbolic after you substitute 0.

As for the old syntax, I'm not sure that can really be deprecated. or at least we can't really raise warnings, as there shouldn't be anything wrong with having True as a condition, especially since there's no way to tell a condition 1>0 or (x>0).subs(x,1) apart from True. I changed all the instances in the code to use the new otherwise syntax and changed the documentation to reflect this.

I do think the old syntax should be removed, as this is another source of complication in the code. Just trying to understand the bulleted list of what happens with the args in the docstring was making my head spin, and I already have a good idea of what it would do.

I don't see how to avoid all ambiguities without completely dropping the old syntax (this is why the syntax needed to be changed in the first place). However, if we do that without a deprecation cycle, then any user of Piecewise will have his Piecewise objects automatically evaluated at the otherwise condition, which may be surprising.

So I think we should try to raise a warning. Just do it whenever True is interpreted as the otherwise condition. If the user got True not because he wanted otherwise but because he wanted it to evaluate to that point, then he will need to be warned anyway. We can direct the users to avoid ambiguity during the deprecation period by adding nan as a manual otherwise condition. Then, interpret all True conditions before the otherwise as evaluation (I thought you were already doing this, but Piecewise((x,x>0), (y, 0 < 1), nan) is giving me the same thing as Piecewise((x,x>0), y)).

Do you see any problems with that plan?

Member

asmeurer commented Jan 22, 2012

Right. To be more clear, the complication is specifically in .args, and as a result in anything that parses .args, and the code that builds it. .args should just be ((expr, cond), ..., otherwise).

The more I think about it, the more I think this might not be necessary, as the only use is when you want to do something like Piecewise((x,x>0), evaluate=False).subs(x,1) and want it to return a Piecewise rather than just returning 1.

I think the solution here is to keep 1 > 0 from being evaluated. You will need to implement the evaluate keyword in the new inequality classes. Then Piecewise can just pass the evaluate flag to that (or do you think it would be cleaner to not do that automatically and require the user to do it?).

In the same vein, in issue 2626, you noted allowing a 1-tuple for an otherwise statement, I'm not entirely sure if this is necessary, but I included it as a possibility, that may be leading to an increased mess in some of the code.

This is an added source of complication. It is not necessary to support this syntax. We decided against it.

I had the same problem with _eval_leading_term. Function tried to do _eval_leading_term on args[0], but since for a Piecewise that's a Tuple, it fails. What I implemented was to add all the expressions, including otherwise, together and return _eval_leading_term of that. I'm not sure if that would be the desired behavior for a Piecewise function or if it should take the expression when the variable goes to 0, but it works in as much as the old tests still pass.

@ness01 or someone who knows more about what that does will have to comment. Is it OK for _eval_leading_term to "overestimate", so to speak? Getting the term at 0 may not be so easy, as the conditions could be more than one dimensional, and hence be symbolic after you substitute 0.

As for the old syntax, I'm not sure that can really be deprecated. or at least we can't really raise warnings, as there shouldn't be anything wrong with having True as a condition, especially since there's no way to tell a condition 1>0 or (x>0).subs(x,1) apart from True. I changed all the instances in the code to use the new otherwise syntax and changed the documentation to reflect this.

I do think the old syntax should be removed, as this is another source of complication in the code. Just trying to understand the bulleted list of what happens with the args in the docstring was making my head spin, and I already have a good idea of what it would do.

I don't see how to avoid all ambiguities without completely dropping the old syntax (this is why the syntax needed to be changed in the first place). However, if we do that without a deprecation cycle, then any user of Piecewise will have his Piecewise objects automatically evaluated at the otherwise condition, which may be surprising.

So I think we should try to raise a warning. Just do it whenever True is interpreted as the otherwise condition. If the user got True not because he wanted otherwise but because he wanted it to evaluate to that point, then he will need to be warned anyway. We can direct the users to avoid ambiguity during the deprecation period by adding nan as a manual otherwise condition. Then, interpret all True conditions before the otherwise as evaluation (I thought you were already doing this, but Piecewise((x,x>0), (y, 0 < 1), nan) is giving me the same thing as Piecewise((x,x>0), y)).

Do you see any problems with that plan?

@ness01

This comment has been minimized.

Show comment
Hide comment
@ness01

ness01 Jan 22, 2012

Contributor

As I have said elsewhere, I'm not quite certain why so many functions implement _eval_as_leading_term. According to the docstring (and the implementation!), as_leading_term may only be used on a result returned by Basic.series. Now, conceivably, this could return a piecewise. I think that the right thing for piecewise to do is to pass eval_leading_term through to its components.

But really I don't know for sure, and I am not even aware of any code that returns Piecewise in series, except for Piecewise itself. And, moreover, I don't think gruntz can handle piecewise anyway.

So in summary, my suggestion is to make as_leading_term behave just like series - simply return a piecewise with the same conditions and the inner functions replaced by their leading terms. But I am not at all confident this is right (since I know no use cases) and certainly did not write the code. Maybe @certik knows better.

Contributor

ness01 commented Jan 22, 2012

As I have said elsewhere, I'm not quite certain why so many functions implement _eval_as_leading_term. According to the docstring (and the implementation!), as_leading_term may only be used on a result returned by Basic.series. Now, conceivably, this could return a piecewise. I think that the right thing for piecewise to do is to pass eval_leading_term through to its components.

But really I don't know for sure, and I am not even aware of any code that returns Piecewise in series, except for Piecewise itself. And, moreover, I don't think gruntz can handle piecewise anyway.

So in summary, my suggestion is to make as_leading_term behave just like series - simply return a piecewise with the same conditions and the inner functions replaced by their leading terms. But I am not at all confident this is right (since I know no use cases) and certainly did not write the code. Maybe @certik knows better.

@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 22, 2012

Member

It's currently rebased, but there are some test failures with the printing.

Do you see any problems with that plan?

That sounds good. I'll see what I can do to get that going.

As for the _eval_leading_term, I'll try making it a Piecewise and seeing that it doesn't fail until I hear otherwise.

Member

flacjacket commented Jan 22, 2012

It's currently rebased, but there are some test failures with the printing.

Do you see any problems with that plan?

That sounds good. I'll see what I can do to get that going.

As for the _eval_leading_term, I'll try making it a Piecewise and seeing that it doesn't fail until I hear otherwise.

@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 24, 2012

Member

@asmeurer So there is currently some test error in nseries that originates from somewhere in gruntz.py that I don't fully understand, but other than that, I've tried to fix this up, tho I'm not totally sure what exactly you were trying to say at some points, so please note if something is off.

I haven't changed any of the docstring for this, but here's the gist of it:

By default, evaluate isn't called and if there are any bool conds, it raises a warning and sets evaluate to True. eval then gets rid of any bools by discarding when False and promoting expressions to otherwise if their condition is True before otherwise. If subs is called, it is taken as an evaluation and eval is called to clear any bools.

With this Piecewise((x,x>0), (y, 0 < 1), nan) (which would be legal post-deprecation as Piecewise((x,x>0), (y, 0 < 1), nan, evaluate=True)) reduces to Piecewise((x,x>0), y), but only because evaluate is called. I'm not sure what you mean by:

Then, interpret all True conditions before the otherwise as evaluation

if not something like that. Do you mean the 0 < 1 is not trying to be called as an otherwise statement and thus should trigger evaluation, or because it is a True condition and not otherwise it should be kept as a expression/condition rather than evaluating to the otherwise statement? Should this use of a bool then warrant a deprecation warning?

I also put in deprecation for numbers as a condition, I see no reason why you'd want to use a number as a condition, but I could be wrong.

Member

flacjacket commented Jan 24, 2012

@asmeurer So there is currently some test error in nseries that originates from somewhere in gruntz.py that I don't fully understand, but other than that, I've tried to fix this up, tho I'm not totally sure what exactly you were trying to say at some points, so please note if something is off.

I haven't changed any of the docstring for this, but here's the gist of it:

By default, evaluate isn't called and if there are any bool conds, it raises a warning and sets evaluate to True. eval then gets rid of any bools by discarding when False and promoting expressions to otherwise if their condition is True before otherwise. If subs is called, it is taken as an evaluation and eval is called to clear any bools.

With this Piecewise((x,x>0), (y, 0 < 1), nan) (which would be legal post-deprecation as Piecewise((x,x>0), (y, 0 < 1), nan, evaluate=True)) reduces to Piecewise((x,x>0), y), but only because evaluate is called. I'm not sure what you mean by:

Then, interpret all True conditions before the otherwise as evaluation

if not something like that. Do you mean the 0 < 1 is not trying to be called as an otherwise statement and thus should trigger evaluation, or because it is a True condition and not otherwise it should be kept as a expression/condition rather than evaluating to the otherwise statement? Should this use of a bool then warrant a deprecation warning?

I also put in deprecation for numbers as a condition, I see no reason why you'd want to use a number as a condition, but I could be wrong.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 24, 2012

Member

Please clean up your commit history.

Member

asmeurer commented Jan 24, 2012

Please clean up your commit history.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 24, 2012

Member

Do you mean the 0 < 1 is not trying to be called as an otherwise statement and thus should trigger evaluation

Yes. If you just write Piecewise((x,x>0), (y, 0 < 1)), the y will be interpreted as otherwise. The workaround for users should be to add nan as the otherwise condition manually (this effectively shouldn't change anything, since conditions outside the range evaluate to nan by default when no otherwise is given).

I would give the warning for Piecewise((x,x>0), (y, 0 < 1)) but not Piecewise((x,x>0), (y, 0 < 1), nan), since the latter follows the new syntax, and is actually what we will recommend to people to avoid the warning (and make things correct).

Member

asmeurer commented Jan 24, 2012

Do you mean the 0 < 1 is not trying to be called as an otherwise statement and thus should trigger evaluation

Yes. If you just write Piecewise((x,x>0), (y, 0 < 1)), the y will be interpreted as otherwise. The workaround for users should be to add nan as the otherwise condition manually (this effectively shouldn't change anything, since conditions outside the range evaluate to nan by default when no otherwise is given).

I would give the warning for Piecewise((x,x>0), (y, 0 < 1)) but not Piecewise((x,x>0), (y, 0 < 1), nan), since the latter follows the new syntax, and is actually what we will recommend to people to avoid the warning (and make things correct).

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 24, 2012

Member

Are numbers currently allowed as conditions? I think this shouldn't be allowed, for the same reason that intervals can't be used (they're not Booleans). Unless I'm misunderstanding what this means.

Member

asmeurer commented Jan 24, 2012

Are numbers currently allowed as conditions? I think this shouldn't be allowed, for the same reason that intervals can't be used (they're not Booleans). Unless I'm misunderstanding what this means.

@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 24, 2012

Member

Alright, I think I get it.

And yes, numbers are currently allowed conditions, I can remove that as well.

Member

flacjacket commented Jan 24, 2012

Alright, I think I get it.

And yes, numbers are currently allowed conditions, I can remove that as well.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 24, 2012

Member

From what I can see, they are just evaluated as booleans, i.e., nonzero means True and zero means False. Is that right?

Yeah, let's just remove that. I wouldn't even bother deprecating it.

Member

asmeurer commented Jan 24, 2012

From what I can see, they are just evaluated as booleans, i.e., nonzero means True and zero means False. Is that right?

Yeah, let's just remove that. I wouldn't even bother deprecating it.

@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 24, 2012

Member

Alright, I've finished cleaning up documentation, number conditions are removed and the deprecation warning is correctly implemented.

Also, the error that I was getting earlier was due to the as_leading_term. Doing abs(x - a).nseries(x, 1) adds a Piecewise with an Order. This ends up creating a new Order based off the leading term of the Piecewise, and thus it needs to be a normal function of the Symbol in question. To fix the test, I changed as_leading_term back to adding the expressions and taking the leading term of the sum.

Member

flacjacket commented Jan 24, 2012

Alright, I've finished cleaning up documentation, number conditions are removed and the deprecation warning is correctly implemented.

Also, the error that I was getting earlier was due to the as_leading_term. Doing abs(x - a).nseries(x, 1) adds a Piecewise with an Order. This ends up creating a new Order based off the leading term of the Piecewise, and thus it needs to be a normal function of the Symbol in question. To fix the test, I changed as_leading_term back to adding the expressions and taking the leading term of the sum.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 24, 2012

Member

SymPy Bot Summary: There were test failures.

@flacjacket: Please fix the test failures.

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY7ZgKDA

Interpreter: /Library/Frameworks/Python.framework/Versions/3.2/bin/python3 (3.2.2-final-0)
Architecture: Darwin (64-bit)
Cache: yes
Test command: setup.py test
master hash: 9258bb9
branch hash: 97cc38361bdf20cce1f895ec88df7a11e523e915

Automatic review by SymPy Bot.

Member

asmeurer commented Jan 24, 2012

SymPy Bot Summary: There were test failures.

@flacjacket: Please fix the test failures.

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY7ZgKDA

Interpreter: /Library/Frameworks/Python.framework/Versions/3.2/bin/python3 (3.2.2-final-0)
Architecture: Darwin (64-bit)
Cache: yes
Test command: setup.py test
master hash: 9258bb9
branch hash: 97cc38361bdf20cce1f895ec88df7a11e523e915

Automatic review by SymPy Bot.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

You can ignore that test failure. There aren't any in Python 2 either, but there seems to be some problem with the bot. It just hangs with

============================== txt doctests start ==============================

bot-tmpjf8lh2/sympy/doc/src/gotchas.txt [100]                               [OK]
bot-tmpjf8lh2/sympy/doc/src/guide.txt [46]                                  [OK]
bot-tmpjf8lh2/sympy/doc/src/install.txt [10]                                [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/assumptions/index.txt [80]              [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/concrete.txt [22]                       [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/core.txt [13]                           [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/evalf.txt [69]                          [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/functions/elementary.txt [24]           [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'latex_ex.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/geometry.txt [58]                       [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/integrals/integrals.txt [7]             [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/logic.txt [15]                          [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/matrices.txt [99]                       [OK]
*** DocTestRunner.merge: 'ntheory.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'matrices.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/advanced.txt [24]     [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/examples.txt [183]    [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/kane.txt [46]         [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/kinematics.txt [62]   [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/masses.txt [23]       [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/vectors.txt [58]      [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/physics/units.txt [9]                   [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/polys/basics.txt [54]                   [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'reference.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/polys/wester.txt [59]                   [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/printing.txt [30]                       [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/rewriting.txt [15]                      [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/series.txt [7]                          [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/solvers/solvers.txt [4]                 [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/statistics.txt [25]                     [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/utilities/autowrap.txt [8]              [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/utilities/codegen.txt [1]               [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/utilities/iterables.txt [5]             [OK]
bot-tmpjf8lh2/sympy/doc/src/tutorial.ru.txt [189]                           [OK]
bot-tmpjf8lh2/sympy/doc/src/tutorial.txt [195]                              [OK]

Does anyone else get this?

Member

asmeurer commented Jan 25, 2012

You can ignore that test failure. There aren't any in Python 2 either, but there seems to be some problem with the bot. It just hangs with

============================== txt doctests start ==============================

bot-tmpjf8lh2/sympy/doc/src/gotchas.txt [100]                               [OK]
bot-tmpjf8lh2/sympy/doc/src/guide.txt [46]                                  [OK]
bot-tmpjf8lh2/sympy/doc/src/install.txt [10]                                [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/assumptions/index.txt [80]              [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/concrete.txt [22]                       [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/core.txt [13]                           [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/evalf.txt [69]                          [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/functions/elementary.txt [24]           [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'latex_ex.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/geometry.txt [58]                       [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/integrals/integrals.txt [7]             [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/logic.txt [15]                          [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/matrices.txt [99]                       [OK]
*** DocTestRunner.merge: 'ntheory.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'matrices.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/advanced.txt [24]     [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/examples.txt [183]    [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/kane.txt [46]         [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/kinematics.txt [62]   [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/masses.txt [23]       [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/physics/mechanics/vectors.txt [58]      [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/physics/units.txt [9]                   [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/polys/basics.txt [54]                   [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
*** DocTestRunner.merge: 'reference.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/polys/wester.txt [59]                   [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/printing.txt [30]                       [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/rewriting.txt [15]                      [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/series.txt [7]                          [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/solvers/solvers.txt [4]                 [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/statistics.txt [25]                     [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/utilities/autowrap.txt [8]              [OK]
bot-tmpjf8lh2/sympy/doc/src/modules/utilities/codegen.txt [1]               [OK]
*** DocTestRunner.merge: 'index.txt' in both testers; summing outcomes.
bot-tmpjf8lh2/sympy/doc/src/modules/utilities/iterables.txt [5]             [OK]
bot-tmpjf8lh2/sympy/doc/src/tutorial.ru.txt [189]                           [OK]
bot-tmpjf8lh2/sympy/doc/src/tutorial.txt [195]                              [OK]

Does anyone else get this?

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

That's in Python 2.5 by the way. That might be important.

Member

asmeurer commented Jan 25, 2012

That's in Python 2.5 by the way. That might be important.

@asmeurer

View changes

Show outdated Hide outdated sympy/functions/elementary/piecewise.py
@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

It appears that the evaluate keyword does not work at all. I guess this would actually rely on http://code.google.com/p/sympy/issues/detail?id=2531 to do correctly. Perhaps a new issue could be opened.

Member

asmeurer commented Jan 25, 2012

It appears that the evaluate keyword does not work at all. I guess this would actually rely on http://code.google.com/p/sympy/issues/detail?id=2531 to do correctly. Perhaps a new issue could be opened.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

Well, I didn't necessarily want all the commits squashed into one. I was mostly concerned with the one letter commit messages :)

But don't worry, it's fine. Please do mention in the message what you did to fix the leading_term issue, though.

Member

asmeurer commented Jan 25, 2012

Well, I didn't necessarily want all the commits squashed into one. I was mostly concerned with the one letter commit messages :)

But don't worry, it's fine. Please do mention in the message what you did to fix the leading_term issue, though.

@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 25, 2012

Member

Yes, in any instance where there is something you could keep unevaluated, it is forced. For now, that could be changed for nested Piecewise statements, but not evaluating with bools would require that issue.

Member

flacjacket commented Jan 25, 2012

Yes, in any instance where there is something you could keep unevaluated, it is forced. For now, that could be changed for nested Piecewise statements, but not evaluating with bools would require that issue.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

I like how nan is automatically included (but not printed). That makes things very clear.

Member

asmeurer commented Jan 25, 2012

I like how nan is automatically included (but not printed). That makes things very clear.

@asmeurer

View changes

Show outdated Hide outdated sympy/functions/elementary/piecewise.py
@asmeurer

View changes

Show outdated Hide outdated sympy/functions/elementary/piecewise.py
@flacjacket

This comment has been minimized.

Show comment
Hide comment
@flacjacket

flacjacket Jan 25, 2012

Member

SymPy Bot Summary: All tests have passed.

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY0_kJDA

Interpreter: /opt/python-2.5.6-32bit/bin/python (2.5.6-final-0)
Architecture: Linux (32-bit)
Cache: yes
Test command: setup.py test
master hash: 9258bb9
branch hash: e82666140d59c8908b7e2724a48989e7ce1bd92f

Automatic review by SymPy Bot.

Member

flacjacket commented Jan 25, 2012

SymPy Bot Summary: All tests have passed.

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY0_kJDA

Interpreter: /opt/python-2.5.6-32bit/bin/python (2.5.6-final-0)
Architecture: Linux (32-bit)
Cache: yes
Test command: setup.py test
master hash: 9258bb9
branch hash: e82666140d59c8908b7e2724a48989e7ce1bd92f

Automatic review by SymPy Bot.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

Have all the things we discussed been well tested (in particular the subtitles with the syntax change)?

Member

asmeurer commented Jan 25, 2012

Have all the things we discussed been well tested (in particular the subtitles with the syntax change)?

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jan 25, 2012

Member

My final comment (for now at least) is to make it clear in the docstring that the old way is deprecated.

Speaking of which, what do you think would be a good deprecation cycle length for this?

Member

asmeurer commented Jan 25, 2012

My final comment (for now at least) is to make it clear in the docstring that the old way is deprecated.

Speaking of which, what do you think would be a good deprecation cycle length for this?

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Feb 26, 2012

Member

The syntax now is a little more complicated, but that's just because of the backwards compatibility. Once we break that, it will become cleaner in my opinion.

Member

asmeurer commented Feb 26, 2012

The syntax now is a little more complicated, but that's just because of the backwards compatibility. Once we break that, it will become cleaner in my opinion.

@rlamy

This comment has been minimized.

Show comment
Hide comment
@rlamy

rlamy Feb 27, 2012

Member

No, this actually makes the implementation more complicated: currently, something like for expr, cond in self.args is enough to handle all the arguments, but this forces us to deal with the "otherwise" value in addition.

A real simplification would be to replace Piecewise with nested IfElse(condition, true_expr, false_expr) objects.

Member

rlamy commented Feb 27, 2012

No, this actually makes the implementation more complicated: currently, something like for expr, cond in self.args is enough to handle all the arguments, but this forces us to deal with the "otherwise" value in addition.

A real simplification would be to replace Piecewise with nested IfElse(condition, true_expr, false_expr) objects.

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Feb 27, 2012

Member

I disagree with that. Flat is better than nested.

expr, cond doesn't work because not every expression has a condition.

Member

asmeurer commented Feb 27, 2012

I disagree with that. Flat is better than nested.

expr, cond doesn't work because not every expression has a condition.

flacjacket added some commits Jan 15, 2012

New Piecewise syntax and fix Piecewise issues
Piecewise syntax is changed to allow for a more sensible definition of
the otherwise condition. Before, an expr/cond pair was specified where
cond was given as True. Now, otherwise can either be passed as the final
argument after a sequence of expr/cond 2-tuples. The old otherwise
syntax using (otherwise, True) raises a deprecation warning.

The ExprCondPair class is removed in favor of Tuples to store the
expr/cond pairs.

The '.as_leading_term()' function is changed so that it takes the sum of
all the expressions and, if it is not NaN, the otherwise statement, and
returns the leading term of the sum. Ideally, '.as_leading_term()' would
return a Piecewise function, but doing this breaks the evaluation of
'abs(x-a).nseries(x, 1)'.

Piecewise no longer accepts an Interval as a condition. To implement the
same functionality, either the '.as_relational()' or '.contains()'
methods of Interval can be used. Piecewise also no longer accepts
numbers as conditions.

The properties '.exprcondpairs' and '.otherwise' are implemented to
easily access the expr/cond pairs and otherwise statement, respectively.

Addresses issues: 2101, 2567, 2626, 2710, 2726
Additional Piecewise testing
Changes allowing evaluate keyword to override default behavior of
clearing nested Piecewise expressions. More testing of new Piecewise
evaluate keyword behavior, including an XFAIL test related to Issue
3025, where evaluate=False does not override behavior when bools are in
the conditions.

Includes new tests and doctests for '.exprcondpairs' and '.otherwise'
properties.

Re-enables testing for expressions in expr/cond pairs and the otherwise
statement to be Expr or GeometryEntity. GeometryEntity is needed due to
the use of Piecewise in the geometry module for '.arbitrary_point()'.
Change Piecewise evaluation behavior
Piecewise evaluation now returns the first expression which is
explicitly True. If no conditions are True, the otherwise expression is
returned. Evaluation can be triggered by setting the 'evaluate' keyword
to True. When a boolean is given as a condition, evaluation is enabled
unless specifically disabled by setting 'evaluate' to False. In this
case, any explicitly False conditions are removed and any explicitly
True conditions are given as the otherwise statement. This is done so
bools are kept out of args, see Issue 3025. The collapsing of nested
Piecewise functions is moved from eval to the __new__ method. This is
performed by default, but setting 'evaluate' to False will disable it.
Add Piecewise .doit() to perform evaluation
Added a .doit() method to Piecewise functions. This allows for
forced evaluation of the Piecewise function. If you want to call doit()
to evaluate args but not evaluate the Piecewise function itself,
evaluate=False can be added to the hints.
Fix other code to work with new Piecewise evaluation
Change '.doit()' keyword for evaluating Piecewise objects from
'evaluate' to 'piecewise' and set other functions to use this to
avoid evaluation of Piecewise when required. Having no expr/cond pairs
is treated like having bools in the conditions.
Fix up documentation of Piecewise objects
Improve documentation of Piecewise objects, specifying how the new
evaluation functionality works, how it is overridden and the limitations
posed by not being able to have bools in the args.
Piecewise raises error with bool args and evaluate=False
Change behavior of Piecewise so if bools are given as args and it is
given the keyword evaluate=False, it raises a NotImplementedError. This
can be changed once classes implementing boolean logic that subclass
Basic are implemented. Changes are made in meijerint to parse the args
of a Piecewise function used in that module which may have bool
conditions, but should not be evaluated. This can be changed to use
evaluate=False when the Basic boolean classes are implemented.
Fix type checking in Piecewise
Change checking in Piecewise to take expr/cond pairs only in tuples,
Tuples or lists, all other expressions go to otherwise. Drop the type
checking for the exprs and otherwise statement.
assert Piecewise((x, True)) == x
raises(TypeError,"Piecewise(x)")
assert Piecewise((x, x > 1)) == Piecewise((x, x > 1), S.NaN)
assert Piecewise((x, x > 1), (0, True), S.NaN) == 0

This comment has been minimized.

@rlamy

rlamy Feb 27, 2012

Member

Huh?? This should be Piecewise((x, x > 1), 0).

@rlamy

rlamy Feb 27, 2012

Member

Huh?? This should be Piecewise((x, x > 1), 0).

This comment has been minimized.

@asmeurer

asmeurer Feb 27, 2012

Member

No, this is right. NaN is the otherwise condition. See the prior discussion, both here and on the mailing list. During the deprecation cycle, you can force (expr, cond) pairs to be viewed as that (rather than (expr_otherwise, True)) by manually adding nan as the otherwise condition (this is the default otherwise condition, so this changes nothing).

@asmeurer

asmeurer Feb 27, 2012

Member

No, this is right. NaN is the otherwise condition. See the prior discussion, both here and on the mailing list. During the deprecation cycle, you can force (expr, cond) pairs to be viewed as that (rather than (expr_otherwise, True)) by manually adding nan as the otherwise condition (this is the default otherwise condition, so this changes nothing).

This comment has been minimized.

@rlamy

rlamy Feb 27, 2012

Member

But the (x, x > 1) part has disappeared! That is the problem, not whether the "otherwise" should be 0 or NaN.

@rlamy

rlamy Feb 27, 2012

Member

But the (x, x > 1) part has disappeared! That is the problem, not whether the "otherwise" should be 0 or NaN.

This comment has been minimized.

@asmeurer

asmeurer Feb 28, 2012

Member

That's because the piecewise evaluated to 0, which had a True condition.

@asmeurer

asmeurer Feb 28, 2012

Member

That's because the piecewise evaluated to 0, which had a True condition.

This comment has been minimized.

@rlamy

rlamy Feb 28, 2012

Member

Translated to Python code, Piecewise((x, x>1), (0, True), S.NaN) means

if x > 1:
    return x
elif True:
    return 0
else:
    return S.NaN

which is clearly equivalent to

if x > 1:
    return x
else:
    return 0

but not to simply return 0.

@rlamy

rlamy Feb 28, 2012

Member

Translated to Python code, Piecewise((x, x>1), (0, True), S.NaN) means

if x > 1:
    return x
elif True:
    return 0
else:
    return S.NaN

which is clearly equivalent to

if x > 1:
    return x
else:
    return 0

but not to simply return 0.

This comment has been minimized.

@asmeurer

asmeurer Feb 28, 2012

Member

OK, I see what you're getting at. This is exactly why we need Piecewise(evaluate=False).

@asmeurer

asmeurer Feb 28, 2012

Member

OK, I see what you're getting at. This is exactly why we need Piecewise(evaluate=False).

This comment has been minimized.

@rlamy

rlamy Feb 28, 2012

Member

Let's move the discussion to issue 3025, so that it doesn't disappear when this review is done, OK?

@rlamy

rlamy Feb 28, 2012

Member

Let's move the discussion to issue 3025, so that it doesn't disappear when this review is done, OK?

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Feb 27, 2012

Member

By the way, I do think that it actually would be useful to have some method of Piecewise that would return some kind of IFElse representation. That is exactly what the lambda printer uses, as I remember, so it would essentially move the logic from there into Piecewise, where it might be useful to others as well. But the .args should be expr, cond pairs with otherwise at the end as discussed in issue 2626.

Member

asmeurer commented Feb 27, 2012

By the way, I do think that it actually would be useful to have some method of Piecewise that would return some kind of IFElse representation. That is exactly what the lambda printer uses, as I remember, so it would essentially move the logic from there into Piecewise, where it might be useful to others as well. But the .args should be expr, cond pairs with otherwise at the end as discussed in issue 2626.

@rlamy rlamy referenced this pull request Feb 29, 2012

Merged

Refactor ExprCondPair #1095

flacjacket added some commits Mar 16, 2012

Merge branch 'master' into piecewise_fixes
Conflicts:
	sympy/functions/elementary/piecewise.py
	sympy/printing/tests/test_str.py
Merge branch 'master' into piecewise_fixes
Conflicts:
	sympy/solvers/tests/test_ode.py
Merge branch 'master' into piecewise_fixes
Conflicts:
	sympy/printing/tests/test_str.py
	sympy/stats/crv_types.py
@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer Jun 2, 2012

Member

SymPy Bot Summary: ❗️ There were merge conflicts; could not test the branch.

@flacjacket: Please rebase or merge your branch with master. See the report for a list of the merge conflicts.

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY7N0aDA

Interpreter: /Library/Frameworks/Python.framework/Versions/3.2/bin/python3 (3.2.2-final-0)
Architecture: Darwin (64-bit)
Cache: yes
Test command: ./bin/test && ./bin/doctest
master hash: 53af081
branch hash: 972d8fe

Automatic review by SymPy Bot.

Member

asmeurer commented Jun 2, 2012

SymPy Bot Summary: ❗️ There were merge conflicts; could not test the branch.

@flacjacket: Please rebase or merge your branch with master. See the report for a list of the merge conflicts.

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY7N0aDA

Interpreter: /Library/Frameworks/Python.framework/Versions/3.2/bin/python3 (3.2.2-final-0)
Architecture: Darwin (64-bit)
Cache: yes
Test command: ./bin/test && ./bin/doctest
master hash: 53af081
branch hash: 972d8fe

Automatic review by SymPy Bot.

@jrioux

This comment has been minimized.

Show comment
Hide comment
@jrioux

jrioux Oct 22, 2012

Member

SymPy Bot Summary: ❗️ There were merge conflicts (could not merge flacjacket/piecewise_fixes (972d8fe) into master (57e94e4)); could not test the branch.
@flacjacket: Please rebase or merge your branch with master. See the report for a list of the merge conflicts.

Member

jrioux commented Oct 22, 2012

SymPy Bot Summary: ❗️ There were merge conflicts (could not merge flacjacket/piecewise_fixes (972d8fe) into master (57e94e4)); could not test the branch.
@flacjacket: Please rebase or merge your branch with master. See the report for a list of the merge conflicts.

@smichr

This comment has been minimized.

Show comment
Hide comment
@smichr

smichr May 18, 2017

Member

I happened across this after working rather intensely on getting more Piecewise issues to work. These are concerning to me. But they are old and maybe the understanding has changed. But let me tell you what it looks like to me.

expr, cond doesn't work because not every expression has a condition.

If there is no condition, then it shouldn't be in a Piecewise. The only exception that I can think of is the condition "not any of the preceding" which is what is meant by (cond, True).

In [2]: Piecewise((1, x < 0), (2, 1 > 0), (3, True), nan)
Out[2]:
⎧1 for x < 0

⎩2 otherwise

I think these are wrong. They should both evaluate to 2.

I believe this is fundamentally the wrong way to view Piecewise. The expr,cond pairs are prioritized by their position in the arg list (as I understand it). Stepping through these args we have an enevaluated condition followed by a True condition at which point -- and current behavior supports this -- anything past that is ignored because the True means "not any previous condition." So the current print out is correct: the expression is 1 (if x < 0 happens to evaluate) otherwise it is 2.

I tend to agree that there is no need to change the internal representation of the Piecewise args. One can allow an alternate input syntax without too much harm, though. And the printer could be made to show it this way. On the other hand, having a keyword to extract the Expr,Cond pairs and one to extract the default value would be fine -- one ends up having to watch for the True, anyway, so it might as well be stored as a separate value.

How seriously do we want to pursue the changes of this PR?

Member

smichr commented May 18, 2017

I happened across this after working rather intensely on getting more Piecewise issues to work. These are concerning to me. But they are old and maybe the understanding has changed. But let me tell you what it looks like to me.

expr, cond doesn't work because not every expression has a condition.

If there is no condition, then it shouldn't be in a Piecewise. The only exception that I can think of is the condition "not any of the preceding" which is what is meant by (cond, True).

In [2]: Piecewise((1, x < 0), (2, 1 > 0), (3, True), nan)
Out[2]:
⎧1 for x < 0

⎩2 otherwise

I think these are wrong. They should both evaluate to 2.

I believe this is fundamentally the wrong way to view Piecewise. The expr,cond pairs are prioritized by their position in the arg list (as I understand it). Stepping through these args we have an enevaluated condition followed by a True condition at which point -- and current behavior supports this -- anything past that is ignored because the True means "not any previous condition." So the current print out is correct: the expression is 1 (if x < 0 happens to evaluate) otherwise it is 2.

I tend to agree that there is no need to change the internal representation of the Piecewise args. One can allow an alternate input syntax without too much harm, though. And the printer could be made to show it this way. On the other hand, having a keyword to extract the Expr,Cond pairs and one to extract the default value would be fine -- one ends up having to watch for the True, anyway, so it might as well be stored as a separate value.

How seriously do we want to pursue the changes of this PR?

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer May 19, 2017

Member

FWIW, I now think that Piecewise is correct. It should be thought of as an if-then-else chain. This works well for things like code generation, and also with the basic fact that it's impossible in general to ensure that two (expr, cond) pairs agree with each other where both conditions are true.

Member

asmeurer commented May 19, 2017

FWIW, I now think that Piecewise is correct. It should be thought of as an if-then-else chain. This works well for things like code generation, and also with the basic fact that it's impossible in general to ensure that two (expr, cond) pairs agree with each other where both conditions are true.

@smichr

This comment has been minimized.

Show comment
Hide comment
@smichr

smichr May 19, 2017

Member

@asmeurer , do you still favor the True-less printing and entry for Piecewise? I have some modest mods that allow for the following:

>>> p = Piecewise
>>> p()
Piecewise()
>>> p(2)
2
>>> p(default=2)
2
>>> p((1, x< 0), 2)
Piecewise((1, x < 0), 2)
>>> p((1, x< 0), default=2)
Piecewise((1, x < 0), 2)
>>> p((1, x< 0), (2, True))
Piecewise((1, x < 0), 2)
>>> p((1, x< 0), (2, True), default=3)  # or should this raise an error?
Piecewise((1, x < 0), 3)
>>> p((1, x< 0), (2, True), (3, True))
Piecewise((1, x < 0), 2)
>>> _.ec, _.default  # or similar names
(((1, x < 0),), 2)

See #12654

Member

smichr commented May 19, 2017

@asmeurer , do you still favor the True-less printing and entry for Piecewise? I have some modest mods that allow for the following:

>>> p = Piecewise
>>> p()
Piecewise()
>>> p(2)
2
>>> p(default=2)
2
>>> p((1, x< 0), 2)
Piecewise((1, x < 0), 2)
>>> p((1, x< 0), default=2)
Piecewise((1, x < 0), 2)
>>> p((1, x< 0), (2, True))
Piecewise((1, x < 0), 2)
>>> p((1, x< 0), (2, True), default=3)  # or should this raise an error?
Piecewise((1, x < 0), 3)
>>> p((1, x< 0), (2, True), (3, True))
Piecewise((1, x < 0), 2)
>>> _.ec, _.default  # or similar names
(((1, x < 0),), 2)

See #12654

@asmeurer

This comment has been minimized.

Show comment
Hide comment
@asmeurer

asmeurer May 19, 2017

Member

It could be useful, but on the other hand, it leads to some ambiguity. Also, what would Piecewise() with no arguments mean?

Member

asmeurer commented May 19, 2017

It could be useful, but on the other hand, it leads to some ambiguity. Also, what would Piecewise() with no arguments mean?

@smichr

This comment has been minimized.

Show comment
Hide comment
@smichr

smichr May 22, 2017

Member

It could be useful, but on the other hand, it leads to some ambiguity.

I'm going to close this. I can't see a compelling reason to not use the (otherwise, True) condition as the default arg. The pretty printing looks good, so all we would be doing is simplifying the output of str. And that can be done without changing the internals. #12654 does this by allowing a default arg go be given.

Also, what would Piecewise() with no arguments mean?

It means that there is no definition for the expression. It is Piecewise's way of saying "undefined".

If anyone desires to comment on this, please do so on #12654 after reopening it.

Member

smichr commented May 22, 2017

It could be useful, but on the other hand, it leads to some ambiguity.

I'm going to close this. I can't see a compelling reason to not use the (otherwise, True) condition as the default arg. The pretty printing looks good, so all we would be doing is simplifying the output of str. And that can be done without changing the internals. #12654 does this by allowing a default arg go be given.

Also, what would Piecewise() with no arguments mean?

It means that there is no definition for the expression. It is Piecewise's way of saying "undefined".

If anyone desires to comment on this, please do so on #12654 after reopening it.

@smichr smichr closed this May 22, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment