Search code examples
symbolic-mathsage

How can I solve for a single variable by considering multiple equations in SageMath, without manual variable substitution?


I'm trying to use SageMath for taking notes and doing practical calculations. But I'm still unfamiliar with its quirks. From time to time, I find even the simplest problems are sometimes puzzling. Here's one of my questions.

Suppose I have the following simultaneous equations:

# charge in a capacitor
q = cv

# charge transferred by an electric current I in time T
q = it

It's obvious that when an empty capacitor is being charged by an electric current, by charge conservation, these two equations reduce to:

cv == it

In SageMath it's possible to find a solution for v in terms of c, i, and t using the following code:

sage: var("q, c, v, i, t")
(q, c, v, i, t)
sage: solve([c * v == i * t], v)
[v == i*t/c]

Unfortunately I can't convince SageMath to find a solution by automatically considering the first two equations at the same time:

sage: var("q, c, v, i, t")
(q, c, v, i, t)
sage: solve([q == c * v, q == i * t], v)
[]

However, if I ask SageMath to solve for v and i, it produces the following solution, but it's unwanted as each equation is only considered separately:

sage: solve([q == c * v, q == i * t], v, t)
[[v == q/c, t == q/i]]

From this result, it appears that SageMath considers variable q in both equations as a "free parameter" of some kind, so it doesn't know it's expected to treat these two equations as equivalences.

My current workaround (voltage workaround?) is to define two equations separately, then ask SageMath to do a substitution manually.

sage: eq1 = q == c * v
sage: eq2 = q == i * t
sage: solve(eq1.subs(eq2), v)
[v == i*t/c]

But this is rather tedious, especially when there are multiple long and complicated equations instead of my toy problem. Is there a better, "more automated" way to do this, without manual variable substitution?


Solution

  • After reading this thread on SageMath's Q&A forum, I found two new workarounds.

    Pass An Extra Variable to solve() to Consider Both

    A better workaround is pass the variable you want to eliminate along with the unknown variable you want to solve. This way, SageMath no longer treats it as an unknown free parameter, but considers both variables together:

    sage: solve([eq1, eq2], v, q)
    [[v == i*t/c, q == i*t]]
    

    Now the equations are solvable.

    Call Maxima to Eliminate A Variable

    Another workaround is to eliminate a variable directly. As far as I know SageMath doesn't support it natively, but one can still call the underlying Maxima backend from SageMath.

    sage: maxima.eliminate([eq1, eq2], [q])
    [_SAGE_VAR_c*_SAGE_VAR_v-_SAGE_VAR_i*_SAGE_VAR_t]
    
    sage: maxima.eliminate([eq1, eq2], [q]).sage()
    [-i*t + c*v]
    

    Thus, this equation can be solved by eliminating q first:

    sage: solve(maxima.eliminate([eq1, eq2], [q]).sage(), v)
    [v == i*t/c]
    

    One can also save the equation after variable elimination as a temporary variable:

    sage: simp_eq = maxima.eliminate([eq1, eq2], [q]).sage()
    sage: simp_eq
    [-i*t + c*v]