R5 — Equations

Goal: solve equations, inequalities and systems — and understand the one thing solve does that will surprise you.

One equation, one unknown

> solve(2x + 6 = 0, x)
x := -3.0

run this session

Why does that look like an assignment?

Because it is one. Read the echo again — x := -3.0, the exact shape R3 taught. solve does not merely report the root, it stores it, so the next line that mentions x uses it:

> x + 1
-2.0

run this session

That is convenient when you want to carry a result forward into further work, and a trap when you do not: a second solve would substitute the first answer before doing anything at all. This is the stale-binding problem R3 warned about, arriving from a command you did not think of as an assignment.

Clear it between problems:

> unset x
x unset
> solve(x^2 - 4 = 0, x)
x_1 := -2.0
x_2 := 2.0

run this session

Two roots, and notice they bound as x_1 and x_2 rather than x — so x itself is untouched. Proof, rather than assertion:

> unset x
x is not set

run this session

Nothing to clear. The habit to build is simple: when a solve answer looks wrong, check env first.

Symbolic coefficients

> solve(a*x + b = 0, x)
x := ((-1.0 * b) / a)
> unset x
x unset

run this session

That is what makes this a computer algebra system rather than a numerical solver: it rearranged the equation without ever knowing what a and b are.

When there is no closed form

> solve(cos(z) = z, z)
z := 0.73909
> unset z
z unset

run this session

No formula exists for that root, so the answer is numeric — and which kind you got is visible in the answer itself rather than hidden behind a flag.

Naming an equation

An equation is an ordinary value, so you can store one and solve it later:

> eq := x^2 - 5x + 6 = 0
eq := (((x ^ 2.0) + (-1.0 * (5.0 * x))) + 6.0) = 0.0
> solve(eq, x)
x_1 := 2.0
x_2 := 3.0
> unset x_1
x_1 unset
> unset x_2
x_2 unset

run this session

Inequalities

The answer to an inequality is a region, and the language can say so:

> solve(2x + 6 > 0, x)
(x > -3.0)
> solve(x^2 - 4 > 0, x)
((x < -2.0) or (x > 2.0))

run this session

The second is a union, written with or — an ordinary connective here, not a special kind of object. A bounded region comes back as an and, and you can pose a combination directly:

> solve(x^2 - 4 < 0, x)
((x > -2.0) and (x < 2.0))
> solve(2x > 2 and x < 5, x)
((x > 1.0) and (x < 5.0))

run this session

Note there is no := in any of those: a region is not a value to assign, so nothing was stored. Only a definite answer binds.

Systems

solveSystem takes a row of equations, then the unknowns in order:

> solveSystem([[x + y = 3, x - y = 1]], x, y)
[[x = 2.0, y = 1.0]]

run this session

The [[...]] brackets are the matrix literal — one row — which is also the shape the answer comes back in. R6 is about those.

Equations are values too

An equation evaluates as soon as everything in it is known:

> 2 + 2 = 4
true
> sin(pi) = 0
true

run this session

The second is true because equality here is tolerance-based at the display precision. sin(pi) is not exactly zero in floating point — π is not exactly π — and answering false would be technically correct and practically useless. R8 is about getting the exact answer when you want it.

Try it yourself

A rectangle has perimeter 20 and area 24. Find its sides.

Answers The obvious attempt is a system: ```text > solveSystem([[2w + 2h = 20, w * h = 24]], w, h) solveSystem([[((2.0 * w) + (2.0 * h)) = 20.0, (w * h) = 24.0]], w, h) ``` *[run this session](https://lycogrypho.github.io/Leonardo/app/#s=precision%205%0Acolors%20dark%0Apretty%20off%0Alatex%20off%0Anames%20off%0Alogic%20minmax%0Alogic%20symmetric%20off%0Aexact%20precision%2030%0Aexact%20off%0Aeq%20%3A%3D%20(((x%20%5E%202.0)%20%2B%20((-1.0)%20*%20(5.0%20*%20x)))%20%2B%206.0)%20%3D%200.0)* Declined — the unchanged-answer shape from [R4](/Leonardo/lessons/r4.html). **`solveSystem` is linear only**, and `w * h` is not, so it did not guess. Substitute by hand (`h = 10 - w`) and solve the quadratic that remains: ```text > solve(w * (10 - w) = 24, w) w_1 := 4.0 w_2 := 6.0 ``` *[run this session](https://lycogrypho.github.io/Leonardo/app/#s=precision%205%0Acolors%20dark%0Apretty%20off%0Alatex%20off%0Anames%20off%0Alogic%20minmax%0Alogic%20symmetric%20off%0Aexact%20precision%2030%0Aexact%20off%0Aw_1%20%3A%3D%204.0%0Aw_2%20%3A%3D%206.0%0Aeq%20%3A%3D%20(((x%20%5E%202.0)%20%2B%20((-1.0)%20*%20(5.0%20*%20x)))%20%2B%206.0)%20%3D%200.0)* Sides 4 and 6 — the two roots are the same rectangle, seen twice.

What you learned

  • solve binds its answer — one root as the variable, several as x_1, x_2, … Use unset between problems, or the next solve starts from the last one.
  • It handles linear and quadratic exactly, symbolic coefficients included, and falls back to numeric roots when no formula exists.
  • An inequality’s answer is a region, written with and / or in the same language you asked in — and regions do not bind.
  • solveSystem([[...]], x, y) is linear only, and declines rather than guessing.
  • Equality between numbers is tolerant, so sin(pi) = 0 is true.

Previous: R4 — Calculus · Next: R6 — Matrices · All lessons


This site uses Just the Docs, a documentation theme for Jekyll.