Difference between revisions of "SymPy/Simultaneous Equations"

From PrattWiki
Jump to navigation Jump to search
(Created page with "==Introduction== This page focuses on using SymPy to find both the symbolic and the numeric solutions to equations obtained from electric circuits. == Initialization == To...")
 
Line 121: Line 121:
 
a.subs(zipsub)
 
a.subs(zipsub)
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
There will be times when you want to make the same substitions to several symbolic representations at once.
 
Given that, here is another handy function for making substitutions that takes a list of variables and a list of values:
 
Given that, here is another handy function for making substitutions that takes a list of variables and a list of values:
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
Line 131: Line 132:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
<!--
 
 
==Substituting Values==
 
Now that you have the symbolic answers to the variables ''x'', ''y'', and
 
''z'', you may want to substitute the actual coefficient values to
 
obtain a numerical solution.  One way to do this is to generate a list
 
of the known values, then tell Maple to substitute in the numerical
 
values by using the built-in '''subs''' command.  Add the following
 
lines of code:
 
<source lang=text>
 
Vals := a=-1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10, k=11, l=12
 
subs(Vals, MySoln)
 
</source>
 
Remember if you cut and paste these into a single group you will need to add a semi-colon after the first line or else you will get a parsing error.
 
The list in '''MySoln''' will now be shown with numerical values
 
instead of symbols.  Note that you have ''not'' made any actual
 
changes to any of the variables - you have just asked Maple to show
 
you what they would look like given the particular substitutions
 
presented in '''Vals'''.  This is a very powerful tool, since you can
 
substitute in a variety of values to see how one or more parameters
 
influence a particular variable or variables.
 
 
'''Note:''' unlike MATLAB, Maple defines <math>\sqrt{-1}</math> as an upper-case <code>I</code> instead of lower case <code>i</code>.  You should therefore avoid re-defining <code>I</code> in Maple; using the lower case version as a variable is perfectly fine.
 
 
<!--
 
===Assigning Representations===
 
There will be many times you actually want to assign the solutions
 
found by '''solve''' - that is, you want to take the equations out of
 
the list and have Maple process them as if the = were := so that Maple
 
could use those expressions later.  Maple has a command called '''assign''' that does exactly that.  Add the commands:
 
<source lang=text>
 
assign(MySoln)
 
x
 
y
 
z
 
</source>
 
You will see that while the '''assign''' command does not report
 
anything back to you, when you ask Maple to tell you what ''x'', ''y'',
 
and ''z'' are, it responds with the symbolic representation produced in
 
'''MySoln'''.  This is very useful if, for example, the answer you are
 
looking for is some function of the variables ''x'', ''y'', and ''z''.
 
Assuming that you have determined the variable you are looking for,
 
''alpha'', is
 
<center><math>
 
\begin{align}
 
\alpha&=x+y+z
 
\end{align}
 
</math></center>
 
you can now use the symbolic representations in Maple to generate a
 
symbolic representation for ''alpha'':
 
<source lang=text>
 
alpha:=x+y+z
 
</source>
 
Note, among other things, that Maple represents the variable named
 
'''alpha''' as its symbol, <math>\alpha</math>.  If you want a numerical value,
 
you can again use the '''subs''' command and the value list from
 
before:
 
<source lang=text>
 
subs(Vals, alpha)
 
</source>
 
 
 
 
 
-->
 
<!--
 
 
===Multiple and Dependent Substitution Lists===
 
If you have several sets of equations you want to use for substitution
 
- including some which are dependent on values set in other equations,
 
you can still use <code>subs</code> -- you just need to be careful about the
 
order of the substitutions.  As an example, imagine some variable:
 
<center><math>
 
\begin{align}
 
m&=p+q
 
\end{align}
 
</math></center>
 
where
 
<center><math>
 
\begin{align}
 
p&=r*s\\
 
q&=t-u
 
\end{align}
 
</math></center>
 
and
 
<center><math>
 
\begin{align}
 
r&=1 & t&=3\\
 
s&=2 & u&=4
 
\end{align}
 
</math></center>
 
To get ''m'' in terms of ''r'', ''s'', ''t'', and ''u'', you could write:
 
<source lang=text>
 
MyEqn:=m=p+q;
 
SubsList1:=p=r*s, q=t-u;
 
subs(SubsList1, MyEqn);
 
</source>
 
If you want to get ''m'''s numerical value, you must ''first'' get ''m''
 
in terms of ''r'', ''s'', ''t'', and ''u'', and ''then'' you can substitute
 
in the numbers for those variables.  Specifically:
 
<source lang=text>
 
MyEqn:=m=p+q;
 
SubsList1:=p=r*s, q=t-u;
 
SubsList2:=r=1, s=2, t=3, u=4;
 
subs(SubsList1, SubsList2, MyEqn);
 
</source>
 
 
Putting the equations in the wrong order will end up yielding an
 
answer that is still in terms of  ''r'', ''s'', ''t'', and ''u''.  The reason
 
is that <code>subs</code> ''only'' makes substitutions into the last entry
 
in the argument list.
 
 
Sometimes, you will need to take equations out of a set of brackets to
 
use them.  For example, assume that you have some
 
variable you want to calculate called </code>alpha</code>, which has a formula
 
of:
 
<center><math>
 
\begin{align}
 
\alpha&=x+y+z
 
\end{align}
 
</math></center>
 
You can put in the solutions for ''x'', ''y'', and ''z'' to get <code>alpha</code>
 
in terms of those characters.  What makes
 
this a bit difficult is that <code>MySoln</code> is given as a
 
single-row matrix and <code>subs</code> just wants the equations
 
themselves.  To extract only the equations, you can write:
 
<source lang=text>
 
subs(MySoln[1][], Vals, ThingToSubInFor)
 
</source>
 
Go ahead and add the line
 
<source lang=text>
 
subs(MySoln[1][], Vals, alpha)
 
</source>
 
to the end of your worksheet.
 
 
Again - the order is important - you need to first substitute in the
 
equations for the variables higher in the dependency list, ''then'' give values to the
 
known quantities, then substitute all that into whatever is in the
 
final argument of <code>subs</code>.
 
Run the entire script and make sure that <math>\alpha</math> is
 
<math>\frac{1}{3}</math> when everything gets substituted in.
 
 
==Cleaning Things Up==
 
Many times, Maple will produce an expression that is more complicated
 
than it needs to be.  To get what it considers to be the simplest
 
form, use the '''simplify(expand( ))''' compound function.  The '''expand''' will take the expression and represent it using as many
 
simple terms as necessary while '''simplify''' will recombine them in
 
the most compact form.  Finally, to get a decimal value, use the '''evalf[N]( )''' function, where '''N''' represents the number of
 
decimal digits to use.  For example, 
 
<source lang=text>
 
simplify(expand(alpha))
 
</source>
 
will produce the most symbolically simplified version of <math>\alpha</math> while
 
<source lang=text>
 
evalf[8](subs(Vals, alpha))
 
</source>
 
will produce a floating point result for <math>\alpha</math>.  With practice, you
 
will see how best to combine <code>evalf</code>, <code>simplify</code>, and <code>expand</code> to get the form of answer you want.
 
 
==Memory Issues==
 
A major issue to consider with Maple is its memory.  At the end of the worksheet above,
 
there are several variables that are defined, including ''x'', ''y'', and
 
''z''.  If you go back near the beginning, click in the line where '''eqn1''' is defined, and hit return, you will notice that where ''x'',
 
''y'', and ''z'' were before, their symbolic solutions from much further
 
down the worksheet are being used.  This is why the '''restart'''
 
command is so helpful - if you need to to run a worksheet again, it is
 
best to always start from scratch.  A shortcut for running an entire
 
worksheet is the !!! button at the top of the window.
 
-->
 
 
<!--
 
<!--
 
== Examples ==
 
== Examples ==

Revision as of 20:26, 21 September 2022

Introduction

This page focuses on using SymPy to find both the symbolic and the numeric solutions to equations obtained from electric circuits.

Initialization

To use SymPy, you will need to import the module. The module comes with the Anaconda distribution of Python, but if you have a different installation, you may need to get the module first. Also, you will likely want to use the "pretty printing" capabilities of SymPy, which requires initializing printing. These two steps can be done with:

import sympy as sym

sym.init_printing()

Declaring Symbols

While there are ways to bring in certain "standard" symbols in SymPy, it may be clearest to define them yourself. You need to declare something as a symbol before using it on the right side of an assignment; as usual, if you create a variable as a combination of symbols, Python will duck type it as a symbol too. The sym.var() function accepts a space or comma-separated string of variables and will create symbolic entities based on the code in the string. For instance:

sym.var('x, y')

will create variables x and y

Defining Equations

When it comes to solving things later, there are two different ways to define an equation:

  • If the equation is equal to zero, you do not explicitly have to include the "=0" part; you can simply define a variable to hold on to the expression. If $$x+y=0$$ is one of the equations you are looking to solve, you can use:
eqn1 = x + y

If you have an expression that evaluates to other than zero, you can use sym.Eq(left, right) for that. If the other equations for which you are trying to solve is $$x-y=3$$, you can write that in code as:

eqn2 = sym.Eq(x - y, 3)

Of course, you could also rearrange the expression by moving the right side to the left, in which case:

eqn2 = x - y - 3

would work!


Solving Equations With SymPy

To solve a system of linear algebra equations, you can use the sym.solve(eqns, vars) command. The system of equations should be in a list, set, or tuple as should the list of unknowns. Note that even if you don't specifically "care" about the value of one or more of the unknowns, you must list them; if you want to solve the two equations above to find x, you still need to explicitly list y as a unknown or else SymPy will assume that it is a symbolic, but known, value, thus constraining the system. Here is an example solving the two equations above:

soln = sym.solve((eqn1, eqn2), (x, y))

If you run this in the console, soln will print out pretty. If you put all this in a script, soln will not show up at all... You can put print(soln) in a script, but it will not be pretty. To make it pretty requires a little work since the solution set is a dictionary with the variables as keys. To help, here is a Python function you can add to your code:

def printout(solution, variables, fp=False):
    for var in variables:
        sym.pretty_print(var)
        if fp:
            sym.pretty_print(solution[var].evalf(fp))
        else:
            sym.pretty_print(solution[var])
    print()

This will go through the solutions and print the variable followed by the solution. If you have substituted in numbers, set fp to True to do floating point evaluation on the answers. If you define this function in the console and then type

printout(soln, (x, y))

you will see the variables and their values.

When the solutions are numbers, this does not seem that useful, but imagine that you want to solve:

$$ \begin{align*} ax+by&=c\\ dx+ey&=f \end{align*}$$

symbolically? You will need to add symbols for a through f first, then redefine the equations to include those symbols; here is a sample code:

import sympy as sym

sym.init_printing()

def printout(solution, variables, fp=False):
    for var in variables:
        sym.pretty_print(var)
        if fp:
            sym.pretty_print(solution[var].evalf(fp))
        else:
            sym.pretty_print(solution[var])
    print()

x, y = sym.var('x, y')
a, b, c, d, e, f = sym.var('a, b, c, d, e, f')

eqn1 = a*x + b*y - c # shows moving right to left side
eqn2 = sym.Eq(d*x+e*y, f) # Shows using sym.Eq to give left and right

soln = sym.solve((eqn1, eqn2), (x, y))
print(soln)
printout(soln, (x, y))

The printed version gives:

{x: (-b*f + c*e)/(a*e - b*d), y: (a*f - c*d)/(a*e - b*d)}

which is a bit hard to interpret; the printout version shows the two fractions as mathematical expressions.

Substituting Values

SymPy has a subs method that works on a variable. For instance, if you have:

import sympy as sym

sym.init_printing()

sym.var('a, b, c, d, e, f')
a = b + c * d + e ** f

You have created $$a=b+cd+e^f$$. If you want to know what this would be if $$b=2$$, you could write:

a.subs(b, 2)

to see that - note that this does not change $$a$$. If there are multiple substitutions, you can put them in an interable (i.e. list or tuple) of variable-value pairs; the following two lines will produce the same results:

a.subs( ( (b,2),(c,3) ) )
a.subs( [ [b,2],[c,3] ] )

If you have an iterable of variables to substitute for and an iterable of values, you can use the zip command to create those pairs for you:

varstosub = [b, c]
valstosub = [2, 3]
zipsub = zip(varstosub, valstosub)
a.subs(zipsub)

There will be times when you want to make the same substitions to several symbolic representations at once. Given that, here is another handy function for making substitutions that takes a list of variables and a list of values:

def makesubs(solution, vartosub, valtosub):
    subsol = solution.copy()
    sublist = list(zip(vartosub, valtosub))
    for var in solution:
        subsol[var] = subsol[var].subs(sublist)
    return subsol