# Using solve() to find positive real solutions to a complex equation

I need solve() to return only positive real solutions to a symbolic complex equation, but it fails to find a useful solution:

sage: var('x, y', domain='positive')
sage: z = 1/(i*x + 1/(i*y + 1))
sage: Equation = z == 2
sage: solve(Equation, x, y)
([x == (-I*y + 1)/(2*y - 2*I)], )


I want solutions in the form [x == foo, y == bar]. Splitting Equation into real and imaginary components does the trick:

sage: Equation = [z.real() == 2, z.imag() == 0]
sage: solve(Equation, x, y)
[[x == (-1/2), y == -1], [x == (1/2), y == 1]]


But why is that reformulation necessary to produce useful results? Isn't it equivalent to the original Equation?

Also, why does solve() ignore my variables' domain='positive' clause? Solve also ignores positive x and y assumptions:

sage: assume(x>0)
sage: assume(y>0)
sage: solve(Equation, x, y)
[[x == (-1/2), y == -1], [x == (1/2), y == 1]]


And it bugs out when positive x & y clauses are added to Equation:

sage: Equation.append(x>0, y>0)
sage: solve([Equation, x>0], x, y)
[[0 < x, [1/((y^2 + 1)*(1/(y^2 + 1)^2 + (x - y/(y^2 + 1))^2)) == 2, -(x - y/(y^2 + 1))/(1/(y^2 + 1)^2 + (x - y/(y^2 + 1))^2) == 0, x > 0, y > 0]]]

edit retag close merge delete

2

To address one of your questions, but not the main one: Maxima's solve, as is probably mentioned elsewhere on this site, explicitly does not take assumptions into account. The idea is that the variables in solve are like dummy variables in integration, and so should not do this. In Sage we try very weakly to take this into account, but it's a process that has a way to go.

Please clarify the "should not do this" part. What's the _this_?

1

So like when you do the integral from 0 to x of t^2 dt, it didn't really matter what the name of the variable t was, and one shouldn't take any outside info into account because it is just a dummy because I was lazy. I could even do the integral from 0 to x of x^2 dx, though we tell our students not to because of the ambiguity. Similarly, Maxima treats variables in "solve" that way. It's not really a big deal, but at least makes it more clear why it's not a big priority for them to change the behavior. We would like to do more of it in Sage, but there are only limited resources of people who know enough about how Maxima and Sage work in this area, and they are more focused on extending our capabilities to more symbolic ...(more)

Is there any kind of workaround to at least remove automatically the complex solutions from the solutions so the don't mix with real roots? For example i was trying to make a list of real solutions of an equation and half of the list finally came out to be complex numbers.

1

You could postprocess your list of solutions by trying to do float(x) for each of them. If that raised an error, then I guess it wasn't real! We do this for the exclude option for plotting, for instance.

Sort by » oldest newest most voted

Here's a way to see why the explicit split into real and imaginary parts is necessary. If the variables are given to solve as a list,

var('x, y')
z = 1/(i*x + 1/(i*y + 1))
Equation = z == 2
solve(Equation, [x, y])

[[x == (-I*r1 + 1)/(2*r1 - 2*I), y == r1]]


then it's clear that solve is returning a fully complex answer with a dummy variable r1. With references to this dummy variable and the result of solve, one can then find solutions that make the imaginary part of x zero:

var('x, y, r1')
z = 1/(i*x + 1/(i*y + 1))
Equation = z == 2
f = solve(Equation, [x, y])
solve( imaginary(f.rhs()), r1 )

[r1 == -1, r1 == 1]


With an additional reference to this second result, the desired solution form can be achieved with nested lists:

var('x, y, r1')
z = 1/(i*x + 1/(i*y + 1))
Equation = z == 2
f = solve(Equation, [x, y])
g = solve( imaginary(f.rhs()), r1 )
[[f[i].subs(g[j]) for i in (0,1)] for j in (0,1)]

[[x == (-1/2), y == -1], [x == (1/2), y == 1]]


Here's a link to a live example.

more