5.4.20 · D4Scientific Computing (Python)

Exercises — SymPy — symbolic algebra, calculus, ODE solving

2,394 words11 min readBack to topic

Level 1 — Recognition

Recall Solution

WHAT: Opening brackets = multiplying everything out. WHY that tool: expand is the "multiply out" pencil move; factor is its reverse, simplify is a heuristic that might or might not do it.

x = symbols('x')
expand((x + 3)*(x - 3))     # -> x**2 - 9

Result: x**2 - 9.

Recall Solution

WHAT: finding roots. WHY solve: solve(eq, x) treats eq as eq = 0 and returns a list of symbolic roots — not a single number.

x = symbols('x')
solve(x**2 - 7*x + 12, x)    # -> [3, 4]

Result: [3, 4]. Note it is a list, so you would index sol[0] to grab 3.


Level 2 — Application

Recall Solution

WHAT: swap the symbol, keep exactness. WHY .subs then simplify: .subs swaps x for sqrt(3) but leaves the expression un-collapsed; simplify combines it. What it looks like: .

x = symbols('x')
e = (x - 2)**2
simplify(e.subs(x, sqrt(3)))   # -> 7 - 4*sqrt(3)

Result: 7 - 4*sqrt(3). If you wanted a decimal you'd add .evalf()0.0718....

Recall Solution

WHAT: differentiate a product. WHY diff: it applies the known rules (product + power + trig) automatically.

x = symbols('x')
diff(x**3 * sin(x), x)     # -> x**3*cos(x) + 3*x**2*sin(x)

Result: x**3*cos(x) + 3*x**2*sin(x). The two rules: the product rule with (power rule gives ) and (gives ).

Recall Solution

WHAT: area under the curve on . WHY the tuple form (x,a,b): it applies the Fundamental Theorem . By hand: , so .

x = symbols('x')
integrate(3*x**2 + 1, (x, 0, 2))   # -> 10

Result: 10 (an exact integer, not 10.0).


Level 3 — Analysis

Recall Solution

WHAT: expand around up to (but not including) order 7.

x = symbols('x')
cos(x).series(x, 0, 7)
# -> 1 - x**2/2 + x**4/24 - x**6/720 + O(x**7)

Result: 1 - x**2/2 + x**4/24 - x**6/720 + O(x**7). WHY only even powers: the Taylor coefficient of is (see Taylor and Maclaurin Series). For , every odd derivative at is a , so those coefficients vanish. Geometrically, is an even function (mirror-symmetric across the -axis), and even functions have only even-power terms. Look at figure s01: the mirror symmetry is the visual reason.

Figure — SymPy — symbolic algebra, calculus, ODE solving
Recall Solution

WHAT: roots of a quadratic with no real solutions.

x = symbols('x')
solve(x**2 + x + 1, x)
# -> [-1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2]

Result: [-1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2]. WHY this form: the quadratic formula gives . Since (where ), SymPy keeps it exact and complex rather than crashing. This is the same complex-root logic the characteristic equation method uses to turn into oscillations.

Recall Solution

WHAT: compute . WHY the limit and not diff: we want to derive, not assume — this is the definition from Limits and the definition of the derivative.

x, h = symbols('x h')
limit(((x + h)**3 - x**3)/h, h, 0)   # -> 3*x**2
diff(x**3, x)                        # -> 3*x**2  (matches!)

Result: both give 3*x**2. What it looks like: expanding, ; divide by to get ; let and only survives.


Level 4 — Synthesis

Recall Solution

WHAT: three tools chained — series, .removeO(), and lambdify. WHY chain them: series gives a symbolic polynomial; .removeO() strips the bookkeeping so it becomes a real polynomial; lambdify compiles it into a fast numeric function for evaluation.

x = symbols('x')
p = sin(x).series(x, 0, 6).removeO()   # x - x**3/6 + x**5/120
f = lambdify(x, p, 'math')
f(0.5)          # -> 0.4794270833333333
math.sin(0.5)   # -> 0.479425538604203

The polynomial gives 0.47942708..., the true value is 0.47942553... — they agree to 5 decimals because we kept terms through . What it looks like: figure s02 overlays the polynomial (orange) on true (blue); near 0 they hug, far away they peel apart.

Figure — SymPy — symbolic algebra, calculus, ODE solving
Recall Solution

FORECAST: means "growth rate proportional to size" → exponential . General solution ; pins . So predict .

x = symbols('x')
y = Function('y')
sol = dsolve(Eq(y(x).diff(x) - 3*y(x), 0), y(x), ics={y(0): 5})
sol            # -> Eq(y(x), 5*exp(3*x))

Result: Eq(y(x), 5*exp(3*x)) — matches the forecast. Verify: and , so ✓ and ✓.


Level 5 — Mastery

Recall Solution

WHAT: distinguish structural identity from mathematical equality.

x = symbols('x')
(x + 2)**2 == x**2 + 4*x + 4        # -> False  (different trees!)
simplify((x + 2)**2 - (x**2 + 4*x + 4)) == 0   # -> True
((x + 2)**2).equals(x**2 + 4*x + 4)            # -> True

WHY False: == compares the shape of the expression tree. (x+2)**2 is stored as a power node; x**2+4*x+4 is a sum node — different structures, so == is False even though they're equal as functions. Fix: subtract and simplify to 0, or use .equals.

Recall Solution

WHAT: improper integrals (upper limit is oo, SymPy's infinity).

x = symbols('x')
integrate(1/x**2, (x, 1, oo))   # -> 1
integrate(1/x,   (x, 1, oo))    # -> oo

Results: 1 and oo. WHY the split: the antiderivative of is , which approaches as , so the area is bounded: . But the antiderivative of is , which grows without bound, so the area is infinite. Edge lesson: two curves that both shrink toward zero can enclose wildly different total areas — shrinks fast enough, does not.

Recall Solution

WHAT: simplification depends on what SymPy is allowed to assume.

x = symbols('x')
simplify(sqrt(x**2))          # -> sqrt(x**2)  (stays, or Abs(x))
p = symbols('p', positive=True)
simplify(sqrt(p**2))          # -> p

WHY: for a general real , (think : , not ). SymPy refuses to drop the absolute value because it can't prove . Once you declare positive=True, the assumption lets it simplify to just p. Edge lesson: the same expression has two correct answers depending on the sign domain — always tell SymPy your assumptions.

Recall Solution

WHAT: combine solve, list indexing, and .evalf.

x = symbols('x')
roots = solve(x**2 - 2, x)     # -> [-sqrt(2), sqrt(2)]
pos = roots[1]                 # sqrt(2)
pos                            # exact: sqrt(2)
pos.evalf(6)                   # -> 1.41421

Results: exact root sqrt(2), decimal 1.41421. WHY index then evalf: solve returns a list of exact symbolic roots; we pick the positive one, keep it exact for algebra, and only collapse to a float at the very end.


Active Recall

Recall Why does

(x+2)**2 == x**2+4*x+4 return False? == compares expression-tree structure, not mathematical value. Use simplify(a-b)==0 or a.equals(b).

Recall What must you call before

lambdify-ing a series? .removeO(), to strip the O(x**n) order term that isn't numerically evaluable.

Recall Why is

infinite but finite? The antiderivative grows without bound; approaches a finite limit ().

Recall Why doesn't SymPy simplify

sqrt(x**2) to x? Because for general real it equals . Declare positive=True to allow the reduction.

Connections

  • SymPy — symbolic algebra, calculus, ODE solving
  • Limits and the definition of the derivative
  • Taylor and Maclaurin Series
  • Ordinary Differential Equations — characteristic equation method
  • Lambdify — bridging SymPy to NumPy for plotting
  • NumPy — numerical arrays