# Correct syntax for "solve(f.derivative(x1,x2)==(0,0))"

I am trying to create simple code to identify critical points of a multivariate function. For pedagogical reasons, I want to do this completely manually. That is, I first want to compute the gradient, and then I want to solve for points where the gradient is zero. Here is my code:

var('x1 x2')
f(x1,x2) = x1^2 + x2^2
Df=f.derivative()
solve(Df(x1,x2)==(0,0),(x1,x2))


The third step returns what I want. If I evaluate Df(x1,x2), Sage returns (2*x1, 2*x2) as expected. However the final step returns the following error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-33-bc76a33e3a15> in <module>
----> 1 solve(Df(x1,x2)==(Integer(0),Integer(0)),(x1,x2))

/var/tmp/sage-jc4b6yulaujayb9sr94ia88eourzeqip0oidmas3/local/lib/python3.8/site-packages/sage/symbolic/relation.py in solve(f, *args, **kwds)
1045
1046     if not isinstance(f, (list, tuple)):
-> 1047         raise TypeError("The first argument must be a symbolic expression or a list of symbolic expressions.")
1048
1049     # f is a list of such expressions or equations

TypeError: The first argument must be a symbolic expression or a list of symbolic expressions.

edit retag close merge delete

Sort by » oldest newest most voted

The result of Df(x1,x2) is a vector with symbolic entries, and testing equality with the tuple (0, 0) returns False, hence the error.

If you want to use solve then you need either a list of equations or a list of left-hand sides of equations which will be set equal to zero. For equalities of vectors, a trick is to subtract right-hand sides from left-hand sides to obtain a single vector, and convert that to a list of entries:

sage: solve(list(Df(x1,x2) - vector([0,0])), (x1,x2))
[[x1 == 0, x2 == 0]]


In this specific case where right-hand sides of equations are already zero, the step of subtracting the right-hand side can of course be omitted.

more

If you want to generalize a bit, you may try :

sage: solve(list(df(dict(zip(f.variables(), f.variables())))), f.variables())
[[x1 == 0, x2 == 0]]

( 2022-06-15 21:21:43 +0200 )edit

As an alternative, once defined $f$ and $Df$, a code which works with any number of variables is

xx = f.args()
eqs = list(Df(*xx))
solve(eqs, *xx)

( 2022-06-16 01:33:28 +0200 )edit
1

To define Df, I would use f.gradient() instead of f.derivative(). The latter can fail if some variable is missing in the definition of f, returning an scalar instead of a vector. The former always returns a vector, as expected. For example,

sage: f(x,y) = y^2
sage: f.derivative()
(x, y) |--> 2*y
(x, y) |--> (0, 2*y)

( 2022-06-16 01:37:20 +0200 )edit

Brilliant! I have learned a lot. Thank you so much!

( 2022-06-16 16:12:54 +0200 )edit