Difference between revisions of "SymPy/Simultaneous Equations"
(→Complete Example Extended, with Helpers) |
|||
Line 161: | Line 161: | ||
=== Complete Example Extended, with Helpers === | === Complete Example Extended, with Helpers === | ||
By carefully setting up your symbolic variables and by using the helper functions above, you can organize your code in a way that will be much more flexible for future assignments. First, instead of creating all of your symbolic variables at once, you can divide them into a collection of unknowns and a collection of knowns -- that will make it easier when you want Python to solve your symbolic equations. Second, you can create a list of the substitution values that you will be using later. | By carefully setting up your symbolic variables and by using the helper functions above, you can organize your code in a way that will be much more flexible for future assignments. First, instead of creating all of your symbolic variables at once, you can divide them into a collection of unknowns and a collection of knowns -- that will make it easier when you want Python to solve your symbolic equations. Second, you can create a list of the substitution values that you will be using later. | ||
+ | |||
+ | '''Note:''' the code below assumes that <code>sym_helper.py</code> is accessible. If you are using Google Colab, please see the section below on how to get that to work. | ||
<syntaxhighlight lang=python> | <syntaxhighlight lang=python> | ||
# Imports | # Imports |
Revision as of 23:39, 16 January 2023
Introduction
This page focuses on using SymPy to find both the symbolic and the numeric solutions to equations obtained from electric circuits.
Very Basic Example
The example code below assumes you are either running code in a notebook of some kind or typing it into a console. There is a finished example at the end of this section which also includes the commands to display different variables if you are using a script. Imagine you have the equation $$ax=d$$ and you want to solve for $$x$$. You can do this in SymPy as follows:
Initialization
You will need to import sympy
to use symbolic calculations. Pratt Pundit will general give that module the nickname sym
:
import sympy as sym
Declare Variables
You will need to let Python know what your variables are. There are several ways to do this; the easiest is to use the sym.var()
command with a string containing the variables you want separated by spaces:
sym.var('a x d')
Define Equations
When it comes to solving things later, there are two different ways to define an equation:
- If you have an expression that evaluates to other than zero, you can use sym.Eq(left, right) for that. Given that we are trying to solve $$ax=d$$, you can write that in code as:
eqn1 = sym.Eq(a * x, d)
- 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. For instance, in this case, we can re-write the equation we are trying to solve as $$ax-d=0$$ and just define a variable to hold on to the left side:
eqn1 = a * x - d
Solve Equations
There are two fundamentally different ways to solve one equation. If you give the solver the equation, it will return a list with the solution in it:
soln1 = sym.solve(eqn1, x)
soln1
will produce a list that contains $$d/a$$. On the other hand, if you give the solver a list with an equation in it, it will return a dictionary with the solution defined in it:
soln2 = sym.solve([eqn1], x)
soln2
will produce the dictionary $$\left\{x: \frac{d}{a}\right\}$$. Whenever you have more than one equation, you will need to collect the equations in a list or a tuple and the solver will return a dictionary. Given that, it is generally a good idea to always give the solver a list for the equations and a list for the unknowns, even if there is only one of each.
soln = sym.solve([eqn1], [x])
soln
Make Substitutions
Now that you have symbolic answers, you can make numerical substitutions for those symbols using the subs
command. You will need to pull the appropriate definition out of the dictionary and then apply the substitutions to it. For example, to see what $$x$$ is when $$d$$ is 10, you can write:
soln[x].subs(d, 10)
If you want to see multiple substitutions, you can put the substitution pairs in tuples or lists that are contained in a tuple or list:
soln[x].subs([[a, 3], [d, 10]])
Complete Example
The code below has an additional piece, which is importing IPython.display as disp. This will allow you to display symbols in a formatted fashion within a script.
# Import sympy
import sympy as sym
# Print pretty
sym.init_printing()
# Use disp.display to use formatted printing
import IPython.display as disp
show = disp.display
# Declare symbols
sym.var('a x d')
# Equations
eqn1 = sym.Eq(a * x, d)
# Solve
soln1 = sym.solve(eqn1, x)
show(soln1)
soln2 = sym.solve([eqn1], x)
show(soln2)
soln = sym.solve([eqn1], [x])
show(soln)
show(soln[x].subs(d, 10))
show(soln[x].subs([[a, 3], [d, 10]]))
Helper Functions
As you can see in the example above, there are some processes that look like they might get a little complicated as the number of equations increases. Given that, here is a set of helper functions that you may want to import into your script or notebook. Note: if you are using Google Colab, accessing secondary files takes a bit of work - this will be explained later. These functions are all in a file called sym_helper.py
.
Imports
The sym_helper.py
will need to import the sympy module. It will also attempt to import the IPython.display module. in order to make sym_helper.py
compatible with applications like Trinket (which does not use IPython.display), sym_helper.py
will see if it can import the module and then, based on that, decide how it will show things:
import sympy as sym
try:
import IPython.display as disp
show = disp.display
except:
show = sym.pretty_print
Printing Out Solution Dictionary
Next, we may want help printing out the solutions to a set of equations. As long as you give solve
a list of equations, you will get back a dictionary.
If you are running your code in a notebook or in the console, typing soln
by itself and hitting return will let you see a pretty version of the solution. If you put all this in a script, however, 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 called printout
you can use:
def printout(solution, variables=None, fp=False):
# Default case: print all variables
if variables==None:
variables = tuple(solution.keys())
# Fixes issue if solving for a single item
if not isinstance(variables, (list, tuple)):
variables = [variables]
for var in variables:
show(var)
if fp:
show(solution[var].evalf(fp))
else:
show(solution[var])
print()
This will go through the dictionary and print the variable followed by the solution for that variable. If you have substituted in numbers, set fp
to an integer to do floating point evaluation on the answers. While a function like this may not seem necessary at the moment (with only one unknown variable, this feels like a lot of overhead), as you start solving problems with more and more unknowns it will be nice to have!
Making Substitutions
As you start working with more equations, you may end up having more and more symbols that you will want to be able to replace with numerical values later. Having to create a list of lists with the substitutions every time can certainly get old! Here is a function that will take a solution dictionary, a list of variables for which to substitute, and a list of the values to use for those variables. It returns a dictionary with the substitutions in place. Note that if it gets a list of equations rather than a dictionary, it will convert the list to a dictionary first. This is not something that is needed for linear algebra but will be something that is needed when setting up and solving simultaneous differential equations.
def makesubs(solution, vartosub, valtosub):
subsol = solution.copy()
sublist = list(zip(vartosub, valtosub))
if type(subsol)==list:
subsol = makedict(subsol)
for var in subsol:
subsol[var] = subsol[var].subs(sublist)
return subsol
def makedict(sollist):
d = {}
for eqn in sollist:
d[eqn.lhs] = eqn.rhs
return d
Complete Example Extended, with Helpers
By carefully setting up your symbolic variables and by using the helper functions above, you can organize your code in a way that will be much more flexible for future assignments. First, instead of creating all of your symbolic variables at once, you can divide them into a collection of unknowns and a collection of knowns -- that will make it easier when you want Python to solve your symbolic equations. Second, you can create a list of the substitution values that you will be using later.
Note: the code below assumes that sym_helper.py
is accessible. If you are using Google Colab, please see the section below on how to get that to work.
# Imports
import sympy as sym
from sym_helper import *
# Print pretty
sym.init_printing()
# Declare symbols (unknowns in first group, knowns in second)
# Create a list of future numerical values for knowns
unks = sym.var('x')
knowns = sym.var('a d')
subval = [10, 3]
# Equations
eqn1 = sym.Eq(a * x, d)
# Collect equations
eqns = [eqn1]
# Solve and display
sol = sym.solve(eqns, unks)
printout(sol)
# Perform substitutions
subsol = makesubs(sol, knowns, subval)
printout(subsol)
Google Colab and Helper Files
Google Colab runs your files in the cloud; you will need to tell Google Colab to access your Google Drive files if you have a helper file that you need to load. There are several steps to this:
- Decide where all your files are going to go. Typically, Google Colab will create a folder called "Colab Notebooks" on your Google Drive. Best bet is to put everything there in some organized way.
- Decide if you want to have a common folder for help files. For EGR 224 in Spring of 2023, I have a folder called "Helpers" inside my "Colab Notebooks" folder, and I am planning to store all helper files there.
- Copy the helper files you need into that folder. The sym_help.py file will be available on Sakai in the Resources section. You can download it to your computer and then upload it to your Google Colab/Helpers folder using the web interface or you can install the Google Drive application for you computer so that you have direct access to your Google Drive files from Explorer / Finder.
- Decide where your notebook is going to be. The examples on this page are all in a folder I called "BasicLinalg" that is inside the "Colab Notebooks" folder. Note that whenever Colab creates a new notebook, it puts it in "Colab Notebooks" - you can move it wherever you want it to be later.
- In your notebook, you will need to do three things to get access to your Helper folder, to import functions from the helper file, and to have the notebook save things in the folder for the notebook:
- Connect the drive:Note that you will generally need to give Google permission to access your drive.
from google.colab import drive drive.mount('/content/drive')
- Change directories and get helper functions:Note that the % in front of a command issues the command to your operating system; cd means "change directory." Your Google Drive is mounted at /context/drive/MyDrive, so this changes the directory to the Helpers folder inside of the Colab Notebooks folder.
%cd /content/drive/MyDrive/Colab\ Notebooks/Helpers from sym_helper import *
- Change directories to where your notebook will live:Among other things, this will ensure that any files your notebook creates (graphs, for instance) will get saved to the right place in your Google Drive and not to the cloud.
%cd /content/drive/MyDrive/Colab\ Notebooks/BasicLinalg
- Connect the drive: