Worked Equations and Equations With Units

One of the common refrains in maths, physics and engineering education is to “show your working” and “check your working”.

In a one piece generative production workflow, various tools are available that support the creation of simple worked examples. By using a generative approach, the working is guaranteed to be correct (even if the style of presentation may not be exactly as desired) which provides a great benefit in terms of material production.

In addition, tools are available that also allow dimensions, or units of measurement, to form part of the calculation, as well as providing an important way (through dimensional analysis) of checking that a derived formula does indeed create a quantity of the desired type — with the desired or expected unit of measurement — from the manipulated values.

For the learner, being able to generate a worked example from an arbitrary set-up allows them to check their own working against the worked steps generated automatically / mechanically from an arbitrary set-up.

Once again, sharing the means of production that helps authors create logically correct materials also provides learners with a mechanical tutor at their side to help them check their own work.

handcalcs Equations

The handcalcs package provides a simple way for writing mathematical equations using simple text and then rendering them using LaTeX equation style layout.

If the full power of sympy is not required, handcalcs may provide all the manipulation we need:

import handcalcs.render
from math import pi

We can easily write equations that reference greek letters and subscripted values, expanding on a symbolic equation using some provided magic:

%%render
t = 1
theta = pi / 2
omega_t =  2 * pi / t
\[\begin{split} \begin{aligned} t &= 1 \; \\[10pt] \theta &= \frac{ \pi }{ 2 } = \frac{ 3.142 }{ 2 } &= 1.571 \\[10pt] \omega_{t} &= 2 \cdot \frac{ \pi }{ t } = 2 \cdot \frac{ 3.142 }{ 1 } &= 6.283 \end{aligned} \end{split}\]

We can prevent the magic from evaluating the expression by telling it we want the expression to remian a symbolic one:

%%render symbolic

a = 2
b = 3
c = 2*a + b/3
\[\begin{split} \begin{aligned} a &= 2 \; \\[10pt] b &= 3 \; \\[10pt] c &= 2 \cdot a + \frac{ b }{ 3 } \; \end{aligned} \end{split}\]

If the expression is evaluated, elements will be expanded along a single line, unless we force a “long” format output which splits the output over several lines:

%%render long
a = 2
b = 3
c = 2*a + b/3
\[\begin{split} \begin{aligned} a &= 2 \; \\[10pt] b &= 3 \; \\[10pt] c &= 2 \cdot a + \frac{ b }{ 3 } \\&= 2 \cdot 2 + \frac{ 3 }{ 3 } \\&= 5.0 \\ \end{aligned} \end{split}\]

If the output isn’t to your liking, handcalcs might still help accelerate authoring by providing a draft of some raw laTeX that you could copy and edit by hand and then render by other means.

Note

In single piece generative document workflow terms, the %%tex magic cell could be removed from a rendered version of the notebook and yet still be used to create raw TeX that might be manually copied intom, edited and redered from a %%latex magicked cell with a hidden input.

%%tex long
a = 2
b = 3
c = 2*a + b/3
\[
\begin{aligned}
a &= 2 \; 
\\[10pt]
b &= 3 \; 
\\[10pt]
c &= 2 \cdot a + \frac{ b }{ 3 } \\&= 2 \cdot 2 + \frac{ 3 }{ 3 } \\&= 5.0  \\
\end{aligned}
\]

For example, we might copy the generated LaTeX, edited as required, perhaps with one of the steps omitted, into a %%latex magic cell:

%%latex

\[
\begin{aligned}
a &= 2 \; 
\\[10pt]
b &= 3 \; 
\\[10pt]
c &= 2 \cdot a + \frac{ b }{ 3 } \\&= 5.0  \\
\end{aligned}
\]
\[\begin{split} \begin{aligned} a &= 2 \; \\[10pt] b &= 3 \; \\[10pt] c &= 2 \cdot a + \frac{ b }{ 3 } \\&= 5.0 \\ \end{aligned} \end{split}\]

We can use a decorator rather than magic to expand various expressions contained within a function.

For example, suppose we want to calculate the two roots of a quadratic equation. We can define a function containing an expression for each solution, and decorate it appropriately:

from math import sqrt
from handcalcs import handcalc

@handcalc(override='long', jupyter_display=True)
def quadratic(a, b, c):
    a
    b
    c
    x_1 = (-b + sqrt(b**2 - 4*a*c)) / (2*a)
    x_2 = (-b - sqrt(b**2 - 4*a*c)) / (2*a)

We can now present the worked solution directly:

quadratic(a, b, c)
\[\begin{split} \begin{aligned} a &= 3 \; \\[10pt] b &= 4 \; \\[10pt] c &= -5 \; \\[10pt] x_{1} &= \frac{ \left( - b \right) + \sqrt { \left( b \right) ^{ 2 } - 4 \cdot a \cdot c } }{ 2 \cdot a } \\&= \frac{ \left( - 4 \right) + \sqrt { \left( 4 \right) ^{ 2 } - 4 \cdot 3 \cdot -5 } }{ 2 \cdot 3 } \\&= 7.863 \times 10 ^ {-1 } \\ \\[10pt] x_{2} &= \frac{ \left( - b \right) - \sqrt { \left( b \right) ^{ 2 } - 4 \cdot a \cdot c } }{ 2 \cdot a } \\&= \frac{ \left( - 4 \right) - \sqrt { \left( 4 \right) ^{ 2 } - 4 \cdot 3 \cdot -5 } }{ 2 \cdot 3 } \\&= -2.12 \\ \end{aligned} \end{split}\]

Working with Dimensions

In some situations, such as physics or engineering calculations, it might be important to make use of dimensioned quantities. The forallpeople package is one of several packages that provides dimensional units. Conveniently, it also works with the handcalcs package.

By default, we can load a particular measurement framework, such as the SI units of measurement. (Alternatives inclue things like Imperial measurements.)

import forallpeople as si

si.environment('default') #, top_level=True)
# Describes the SI derived units
# Units are created by compounding the base units (e.g. Newton, Pascal, Celsius, Watt, Joule, etc.)

Calculated quantities have a value and a dimension. An appropriate magnitude prefix is determined automatically:

force = 20000 * si.N
area = 2 * si.m**2
pressure = force / area

pressure
10.000 kPa

Small units are also determined correctly:

2e-6 * si.F
2.000 μF

Dimensional values can be associated with terms in expressions rendered using handcalcs magic, with appropriate units being displayed as part of a rendered calculation:

%%render

# We need to bracket the terms to not expand the units equation
I = (3e-3 * si.A) #  set the current
V = (20 * si.V) # set the voltage

R = V/I
# Incorrect omega, issue: https://github.com/connorferster/handcalcs/issues/76
\[\begin{split} \begin{aligned} I &= 3.000\ \text{mA} \; \;\textrm{(set the current)} \\[10pt] V &= 20.000\ \text{V} \; \;\textrm{(set the voltage)} \\[10pt] R &= \frac{ V }{ I } = \frac{ 20.000\ \text{V} }{ 3.000\ \text{mA} } &= 6.667\ \text{k\Omega} \end{aligned} \end{split}\]