solve and solution_dict

157 views
Skip to first unread message

Jason Grout

unread,
Sep 10, 2009, 12:10:12 PM9/10/09
to sage-...@googlegroups.com
I was working on a calculus tutorial/primer on Sage yesterday
(http://sagenb.org/home/pub/791/). I realized how annoyed I get with
always having to specify the solution_dict parameter to solve in order
to substitute values back into another expression. Almost every time I
use solve, I immediately substitute the values back into some other
expression. Having to write solution_dict=True all the time is (a) hard
to remember and (b) inconvenient. Part of the reason for (a) is that I
think "solution_dict" is a long and not very obvious name (I think I
wrote the solution_dict patch, so it's my fault! Sorry for the bad name!).

Somewhere, a while ago, I remember there being a consensus (with small
voter turnout) that solution_dict should default to True (I can't find
the thread on this, though). That is effectively what Mathematica does,
for example. Mathematica returns a list of rules, which print as {x->3,
y->4}, and which are very easy and natural to substitute back into other
expressions.

I wonder if we could either:

(a) make solution_dict default to True (and maybe transition to some
sort of better-named keyword argument?)

* this may break lots of code, so maybe ought to be put off until 5.0.

(b) make .subs() and maybe the __call__ method of a symbolic expression
take the output of solve as-is and try to do something intelligent
(i.e., see if the lhs of each equation is a single variable, and
substitute in the right side)

What do you think?

Thanks,

Jason

Robert Bradshaw

unread,
Sep 10, 2009, 1:56:56 PM9/10/09
to sage-...@googlegroups.com

It would need to be more robust when it can't actually solve things:

sage: solve([x==sin(x)], x, solution_dict=True)
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
File "/Users/robert/sage/sage-4.0/local/lib/python2.6/site-
packages/sage/symbolic/relation.py", line 509, in solve
sol_dict=[dict([[eq.left(),eq.right()] for eq in solution]) for
solution in sol_list]
TypeError: 'sage.symbolic.expression.Expression' object is not iterable


> * this may break lots of code, so maybe ought to be put off
> until 5.0.
>
> (b) make .subs() and maybe the __call__ method of a symbolic
> expression
> take the output of solve as-is and try to do something intelligent
> (i.e., see if the lhs of each equation is a single variable, and
> substitute in the right side)
>
> What do you think?

I say go we should do (b) whether or not we do (a), but perhaps only
if the rhs does not contain the variables of the lhs.

- Robert

kcrisman

unread,
Sep 10, 2009, 3:01:19 PM9/10/09
to sage-devel

I don't think (a) is that good, because many would use solve to
literally solve, not necessarily to use those solutions immediately by
substitution, and the == format seems somehow easier to interpret. If
(b) were well-documented, that would seem to provide for the need that
Jason mentions.

>
> > (a) make solution_dict default to True (and maybe transition to some
> > sort of better-named keyword argument?)
>
> It would need to be more robust when it can't actually solve things:
>
> sage: solve([x==sin(x)], x, solution_dict=True)
> ------------------------------------------------------------
> Traceback (most recent call last):
>    File "<ipython console>", line 1, in <module>
>    File "/Users/robert/sage/sage-4.0/local/lib/python2.6/site-
> packages/sage/symbolic/relation.py", line 509, in solve
>      sol_dict=[dict([[eq.left(),eq.right()] for eq in solution]) for  
> solution in sol_list]
> TypeError: 'sage.symbolic.expression.Expression' object is not iterable
>

However, I think the TypeError Robert points out is a bug in any
case.

sage: solve(sin(x)==cos(x),x,solution_dict=True)
[{sin(x): cos(x)}]

Is that the desired behavior? Or should an informative exception be
raised, or should just sin(x)==cos(x) be returned, or a verbose level
0 message?

This is because the global solve lives in symbolic/relation.py, which
for some reason doesn't do as well with lists.

sage: solve([x==1,y+2==3],x,y)
[[x == 1, y == 1]]
sage: solve([sin(x)=sage: solve([sin(x)==1,y+2==3],x,y)
[]

Anyway, I will try to fix a few of these things while fixing some
other things in solve I am already working on.

- kcrisman

kcrisman

unread,
Sep 10, 2009, 3:06:23 PM9/10/09
to sage-devel

> sage: solve([x==1,y+2==3],x,y)
> [[x == 1, y == 1]]
> sage: solve([sin(x)=sage: solve([sin(x)==1,y+2==3],x,y)
> []
>

Actually, this is a bug in Maxima.

(%i8) solve([x=1,y=1]);
(%o8) [[y = 1, x = 1]]
(%i9) solve(sin(x)=1);

solve: using arc-trig functions to get a solution.
Some solutions will be lost.
%pi
(%o9) [x = ---]
2
(%i10) solve([sin(x)=1,y=1]);
(%o10) []

Stan Schymanski

unread,
Sep 10, 2009, 3:13:12 PM9/10/09
to sage-...@googlegroups.com
I wonder if it would be worthwhile allowing the user to set the defaults
for every function. We had the discussion about the log vs. ln notation,
latex representations and a few others I don't remember any more. Quite
a few of these discussions can't be resolved once and forever, simply
because they are a matter of convention in different fields or user
preference. If we allowed the user to set the defaults for each
function, e.g. set_default(solve, solution_dict = True), some of these
discussions would never have to reappear again. Otherwise, I am sure
that they will reappear again and again, for different functions, or
even for the same ones, when the most recent threads addressing these
issues become too old to be found easily in Google Groups.

I have no idea how hard this would be to implement, though!

Cheers
Stan

kcrisman wrote:
> I don't think (a) is that good, because many would use solve to
> literally solve, not necessarily to use those solutions immediately by
> substitution, and the == format seems somehow easier to interpret. If
> (b) were well-documented, that would seem to provide for the need that
> Jason mentions.
>
>

--


Robert Bradshaw

unread,
Sep 10, 2009, 3:19:02 PM9/10/09
to sage-...@googlegroups.com
On Sep 10, 2009, at 12:13 PM, Stan Schymanski wrote:

> I wonder if it would be worthwhile allowing the user to set the
> defaults
> for every function. We had the discussion about the log vs. ln
> notation,
> latex representations and a few others I don't remember any more.
> Quite
> a few of these discussions can't be resolved once and forever, simply
> because they are a matter of convention in different fields or user
> preference. If we allowed the user to set the defaults for each
> function, e.g. set_default(solve, solution_dict = True), some of these
> discussions would never have to reappear again. Otherwise, I am sure
> that they will reappear again and again, for different functions, or
> even for the same ones, when the most recent threads addressing these
> issues become too old to be found easily in Google Groups.
>
> I have no idea how hard this would be to implement, though!

One problem with too much customization is that it makes debugging
and sharing code a lot harder. I really don't like the idea of having
to use someone else's settings to use someone else's code. Issues
like ln vs log for output aren't as big of a deal, but the same
function returning completely different kinds of output is
potentially incompatible.

- Robert

kcrisman

unread,
Sep 10, 2009, 3:19:46 PM9/10/09
to sage-devel
> sage: solve([x==sin(x)], x, solution_dict=True)
> ------------------------------------------------------------
> Traceback (most recent call last):
>    File "<ipython console>", line 1, in <module>
>    File "/Users/robert/sage/sage-4.0/local/lib/python2.6/site-
> packages/sage/symbolic/relation.py", line 509, in solve
>      sol_dict=[dict([[eq.left(),eq.right()] for eq in solution]) for  
> solution in sol_list]
> TypeError: 'sage.symbolic.expression.Expression' object is not iterable

See if #4786 fixes this. (In the sense that [{sin(x): cos(x)}] would
be better than an error.)

- kcrisman

Stan Schymanski

unread,
Sep 10, 2009, 3:46:04 PM9/10/09
to sage-...@googlegroups.com
To reduce the problem about sharing code, all the custom settings could
be saved in a dictionary and a simple call to your own dictionary would
restore your own custom settings again.

I see your point about reduced compatibility between different people's
code, though. I'd still much more prefer this to a change in the default
behaviour that would break my own code without providing a way of
reverting this change to run my old code.

Stan

Kevin Horton

unread,
Sep 10, 2009, 4:30:02 PM9/10/09
to sage-...@googlegroups.com
On 10 Sep 2009, at 12:10, Jason Grout wrote:

> I wonder if we could either:
>
> (a) make solution_dict default to True (and maybe transition to some
> sort of better-named keyword argument?)
>
> * this may break lots of code, so maybe ought to be put off until
> 5.0.
>

I also find that I consistently want to use the solution_dict, so I
support making it True by default.

--
Kevin Horton
Ottawa, Canada

Robert Bradshaw

unread,
Sep 10, 2009, 4:35:10 PM9/10/09
to sage-...@googlegroups.com

The thing to do here (if we decide to change it) is to make it throw
a deprecation warning for a while when the argument is not specified,
and then eventually switch it.

- Robert

Jason Grout

unread,
Sep 10, 2009, 7:37:42 PM9/10/09
to sage-...@googlegroups.com
Stan Schymanski wrote:
> To reduce the problem about sharing code, all the custom settings could
> be saved in a dictionary and a simple call to your own dictionary would
> restore your own custom settings again.
>
> I see your point about reduced compatibility between different people's
> code, though. I'd still much more prefer this to a change in the default
> behaviour that would break my own code without providing a way of
> reverting this change to run my old code.


Mike Hansen's @options decorator that is used in the graphics provides a
way to set the default options. We use it in the graphics code all the
time. However, I agree with Robert here in this case (where the output
would be different for different defaults).

One could make the case that solve with solution_dict should actually be
a different function.

I think making subs() and the __call__ method accept solve output would
take care of most of the needs for me, and would not be disruptive at all.

Jason

--
Jason Grout

Stan Schymanski

unread,
Sep 11, 2009, 4:44:39 AM9/11/09
to sage-...@googlegroups.com
Thanks, Jason! I appreciate any solution that does not break old code.
Deprecation warnings are useful to tell you why your code is going to be
broken (if informative enough) but they don't take away the necessity to
change all your code, unless you have have been setting the new standard
option anyway.

By the way, I don't see the problem with the current solve output of e.g.
[x == 2*sqrt(y)], as this can be used as a replacement rule either by
.subs() or subs_expr(). Actually, I deleted the solution_dict = True
option in your example code and got the same result. Were you not aware
that the arguments accepted by .subs() have changed?

Cheers
Stan

Reply all
Reply to author
Forward
0 new messages