Skip to content

Conversation

@smichr
Copy link
Member

@smichr smichr commented Jul 10, 2017

fixes #10258

Copy link
Member Author

Choose a reason for hiding this comment

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

note to self: perhaps better to return None (if possible) keep old code but instead of return when_multiple, return None (and keep the Expr header test).

@smichr smichr changed the title [wip] piecewise_fold correction and Piecewise assumptions fix fix Piecewise assumptions Jul 11, 2017
@asmeurer
Copy link
Member

Yeah, I've wondered about that commutative thing before. Do tests break if you change that (I vaguely remember something depends on it)?

Maybe it would be helpful at the very least to fix that after #6494, so that people can easily write Function('f', commutative=False).

Copy link
Member

Choose a reason for hiding this comment

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

What is this? You shouldn't be able to put lists in SymPy objects.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was surprised, too, but this is necessary as long as anything in SymPy can emit a list, e.g. solve. A Piecewise is an appropriate container for handling any objects (Basic or otherwise) whose selection depends on some condition. The only way to represent a solution to an equation with piecewise conditions is with a Piecewise of lists (or dicts).

For a univariate Piecewise we can give this:

>> solve(Piecewise((x**2-4,x>-4),(x+6,True)), x)
[-6, -2, 2]

But for a multivariate one we need to give a piecewise result:

>> solve(Piecewise((x**2-4,y>0),(x+6,True)),x)
Piecewise(([-2, 2], y > 0), (-6, True))

Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't be allowed. The result should be a list of Piecewise, not the other way around. No SymPy object should have args that is a list, since list isn't Basic (and it's mutable, which is double bad).

Copy link
Member Author

Choose a reason for hiding this comment

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

I was puzzled by this when I encountered it. What object will you return so that when you substitute y=1 you get the list [-2. 2]? The syntax is solve(function) -> list of solutions not [list of solutions], so [-2, 2] not [[-2, 2]] Piecewise allows us to say "this list under this condition otherwise this list."

Copy link
Member Author

Choose a reason for hiding this comment

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

We could just hack around this by making Piecewise return its solve results in a Tuple when necessary and documenting accordingly.

Copy link
Member Author

Choose a reason for hiding this comment

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

So we yield a number of items equal to the longest solution and accept that there will be repeats?

Copy link
Member

Choose a reason for hiding this comment

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

There are only repeats for y < 0. I see this as similar to solve(x**2 - a, x) -> [sqrt(a), -sqrt(a)], which contains the same solution twice for a=0.

Copy link
Member Author

Choose a reason for hiding this comment

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

Leave a comment

I see this as similar to

hmm. That makes sense -- when not given enough information to filter the results, duplicates may be returned.

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed the mods to Function.is_commutative (sans typo). I vaguely recall that the case with a non-Expr arg will now fail because assumptions are worked out based on commutativity being False instead of None. We'll see.

Copy link
Member

Choose a reason for hiding this comment

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

You could be right about that. Might end up being a harder thing to fix than expected.

Copy link
Member

Choose a reason for hiding this comment

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

How does removing this flag fix the issue?

Copy link
Member Author

Choose a reason for hiding this comment

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

when_multiple was used to make it emit something other than None when a multivalued expressions existed, e.g. Piecewise((0, x< 0), (1, True)).is_zero -> False but it should give None: the conditions do not allow us to say definitievely that the piecewise is zero. When we have Piecewise((2, x< 0), (1, True)).is_zero then we can say False.

Copy link
Member

Choose a reason for hiding this comment

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

Is it doing anything smart enough to check if x.is_negative, or is that outside the scope of this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

One would only inspect the condition if the expression were a function of a common variable. And no, that is not included and cannot be until I get to the point of having the robust condition checking in place -- it is currently very easy to trip up the condition checking. Once that is in place, any condition sharing a single variable with the expression could be solved and substituted into the expression when doing the checking so Piecewise arg

(a + b - 3, a + b < 2)` -> solve cond for a and subst using positive symbol `pos` to indicate that we are using "<"
(2 - b - pos) + b - 3 ->
-1 - pos -> a negative

could be inferred.

@smichr
Copy link
Member Author

smichr commented Jul 11, 2017

Leave a comment

Do tests break if you change that

I modified the function to return None if there is a mix of commutative and noncommutative args. Nothing broke (which is not too surprising). What did you have in mind to change, returning None if any arg is noncommutative?

@asmeurer
Copy link
Member

I went ahead and implemented undefined function assumptions #12945. So I think with that PR we should definitely make Function('f')(x).is_commutative unrelated to x.is_commutative, since you can easily set Function('f', commutative=False).

@asmeurer
Copy link
Member

Can the is_commutative stuff be moved to a separate PR?

@smichr
Copy link
Member Author

smichr commented Jul 11, 2017

moved to a separate PR?

yes -- done.

When there is a disagreement between expressions in the
Piecewise, None should be returned as no answer can be
given regarding the assumption.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Relational involving Piecewise evaluates incorrectly as True

2 participants