The module sympy in Python allows you to carry out symbolic manipulations. The short examples included below illustrate some of the more basic capabilities of this module (that are relevant to what we've been covering so far in CFM2103).
We are going to look at expanding brackets, differentiating and integrating functions, as well as solving linear ODEs. You can do much more -- if you are interested check out the link at the end of this document.
from sympy import *
init_session()
# algebraic manipulations:
f1 = (x+1)*(x-2)*(x+6) # this is a symbolic expression
expand(f1)
# another expansion:
f2 = (x+1)**4
expand(f2)
# you can solve algebraic equations (e.g., quadratics)
eqn = x**2-5*x + 6
print('\nThe solutions are:')
solveset(eqn) # this solves eqn == 0
# another quadratic:
eqn = x**2 + 3*x + 7
print('\nThe solutions are:')
solveset(eqn) # this solves eqn == 0
# and here's a cubic:
eqn = x**3 - 2*x + 1
print('\nThe cubic is:')
eqn
print('\nThe solutions are:')
solveset(eqn) # this solves eqn == 0
# 1st order derivative for some function of x:
f3 = (x**2)*exp(-3*x)
print('\nThe function is:')
f3
print('\n...and its derivative is:')
diff(f3, x)
# 3rd order derivative ....
print('\n...its third-order derivative:')
diff(f3, x, 3)
# (indefinite) integration:
f4 = (x**3)*exp(-7*x)
integrate(f4, x)
# another integral:
f5 = sqrt(x**2+1)
integrate(f5, x)
# definite integral:
integrate(f4, (x, 1, 3))
# Maclaurin series:
# f(x) = cosh(x)
cosh(x).series(x, 0, 8)
# another Maclaurin series
# inverse tan function:
atan(x).series(x, 0, 10)
SymPy can provide closed-form solutions for any first or second-order ODE that admits such a solution. Let's start with some simple second-order ODEs with constant coefficients. Such equations are typically of the form:
$$ y'' + ay' + by = F(x)\,, $$
where $a$, $b\in\mathbb{R}$ are some given constants, $y=y(x)$ is the unknown function, and $f(x)$ is a given function (the so-called "forcing term"); here, the dash denotes differentiation with respect to $x$, i.e.
$$ y' = \dfrac{dy}{dx}\,,\qquad\quad y'' = \dfrac{d^2y}{dx^2}\,,\qquad\mbox{etc}. $$
# EX 1:
# example for solving a 2nd order ODE
f = symbols('y', cls=Function)
diffeq = Eq(y(x).diff(x,x)+2*y(x).diff(x)+y(x), sin(x))
print('\nThis is the equation that we are solving:')
diffeq
# solve the above ODE:
print('\nThe solution of this ODE is:')
dsolve(diffeq, y(x))
# EX 2:
# example for solving a 2nd order ODE
f = symbols('y', cls=Function)
diffeq = Eq(y(x).diff(x,x)+4*y(x).diff(x)+20*y(x), sin(x))
print('\nThis is the equation that we are solving:')
diffeq
# solve the above ODE:
print('\nThe solution of this ODE is:')
dsolve(diffeq, y(x))
Next, we look at a couple of examples involving linear first-order ODEs. The solutions of these equations usually require the calculation of the so-called integrating factor. There is a brief handout posted on Brightspace (this topic is supposed to be covered in one of your other modules).

# linear ODEs (the ones that require integrating factors):
f = symbols('y', cls=Function)
P = -1/(x+1)
Q = x/(x+1)
diffeq = Eq(y(x).diff(x) + P*y(x), Q)
print('\nThis is the equation that we are solving:')
diffeq
print('\nThe solution of this ODE is:')
dsolve(diffeq, y(x))
# another example of linear ODE:
#
f = symbols('y', cls=Function)
P = -1
Q = 3*exp(2*x)
diffeq = Eq(y(x).diff(x) + P*y(x), Q)
print('\nThis is the equation that we are solving:')
diffeq
print('\nThe solution of this ODE is:')
dsolve(diffeq, y(x))
You can discover more features of SymPy by visiting the official documentation page: