1. Basics of polyrith

1.1. Housekeeping

You should be reading this tutorial simultaneously with scrolling through the associated Lean files. This will let you see the goal state of the Lean code and do the exercises.

Head over to the tutorial’s GitHub repository, https://github.com/hrmacbeth/computations_in_lean, to download the repository to your own computer or to open it in the cloud on Gitpod.

1.2. Basics of the linear_combination tactic

How do you do algebra in Lean? Let’s consider a concrete problem.

Problem

Let \(a\) and \(b\) be complex numbers and suppose that \(a - 5b = 4\) and \(b + 2 = 3\). Show that \(a = 9\).

One way to solve this on paper is by a “calculation block”, and this translates directly, if painstakingly, to Lean.

\[\begin{split}a & = (a - 5 b) + 5 b \\ & = 4 + 5 b \\ & = -6 + 5 (b + 2) \\ & = -6 + 5 \cdot 3 \\ & = 9.\end{split}\]
example {a b : } (h₁ : a - 5 * b = 4) (h₂ : b + 2 = 3) : a = 9 :=
  calc
    a = a - 5 * b + 5 * b := by ring
    _ = 4 + 5 * b := by rw [h₁]
    _ = -6 + 5 * (b + 2) := by ring
    _ = -6 + 5 * 3 := by rw [h₂]
    _ = 9 := by ring

Implicitly, when we write a calculation like this on paper, we tend to alternate “rearrangement steps” (done in Lean with ring) and “substitution steps” (done in Lean with rw).

Another method: You might be familiar with the linarith tactic, for deducing implications among linear inequalities. If we were working over a linear ordered field such as \(\mathbb{R}\) or \(\mathbb{Q}\), this tactic would be a great way to solve this problem.

example {a b : } (h₁ : a - 5 * b = 4) (h₂ : b + 2 = 3) : a = 9 := by linarith

But over \(\mathbb{C}\), which has no order, we could only invoke linarith by first taking real and imaginary parts of both sides – and over a general field this wouldn’t work at all.

In this section we will introduce a tactic, linear_combination, which is well-adapted to algebra over general commutative rings. This tactic was contributed to Mathlib in January 2022 by Brown undergraduate Abby Goldberg. Here is how our example is solved using linear_combination.

example {a b : } (h₁ : a - 5 * b = 4) (h₂ : b + 2 = 3) : a = 9 := by
  linear_combination h₁ + 5 * h₂

The tactic linear_combination works by finding coefficients with which LHS - RHS of the goal is a linear combination of LHS - RHS of the hypotheses. Here LHS - RHS of h₁ is \(a-5b-4\), LHS - RHS of h₂ is \(b-1\), and LHS - RHS of the goal is \(a-9\). It is indeed true that

\[a - 9 = (a - 5b - 4) + 5 (b - 1).\]

linear_combination is a great tactic to use when your intuition for a problem is to “add something to both sides” or “divide both sides by something” or “add two equations”.

Problem

Let \(m\) and \(n\) be integers and suppose that \(m - n = 0\). Show that \(m = n\).

example {m n : } (h : m - n = 0) : m = n := by linear_combination h

Problem

Let \(K\) be a field of characteristic zero, let \(s\in K\), and suppose that \(3s+1 = 4\). Show that \(s = 1\).

example {K : Type*} [Field K] [CharZero K] {s : K} (hs : 3 * s + 1 = 4) : s = 1 := by
  linear_combination 1 / 3 * hs

Problem

Let \(p\) and \(q\) be complex numbers and suppose that \(p+2q=4\) and \(p-2q=2\). Show that \(2p = 6\).

example {p q : } (h₁ : p + 2 * q = 4) (h₂ : p - 2 * q = 2) : 2 * p = 6 := by
  linear_combination h₁ + h₂

Here are a lot of exercises. Do them until you get bored, then go on to the next section.

example {x y : } (h₁ : 2 * x + y = 4) (h₂ : x + y = 1) : x = 3 := by
  sorry

example {r s : } (h₁ : r + 2 * s = -1) (h₂ : s = 3) : r = -7 := by
  sorry

example {c : } (h₁ : 4 * c + 1 = 3 * c - 2) : c = -3 := by
  sorry

example {x y : } (h₁ : x - 3 * y = 5) (h₂ : y = 3) : x = 14 := by
  sorry

example {x y : } (h₁ : 2 * x - y = 4) (h₂ : y - x + 1 = 2) : x = 5 := by
  sorry

example {x y : } (h₁ : x = 3) (h₂ : y = 4 * x - 3) : y = 9 := by
  sorry

example {a b c : } (h₁ : a + 2 * b + 3 * c = 7) (h₂ : b + 2 * c = 3) (h₃ : c = 1) :
    a = 2 := by
  sorry

example {a b : } (h₁ : a + 2 * b = 4) (h₂ : a - b = 1) : a = 2 := by
  sorry

example {u v : } (h₁ : u + 2 * v = 4) (h₂ : u - 2 * v = 6) : u = 5 := by
  sorry

example {u v : } (h₁ : 4 * u + v = 3) (h₂ : v = 2) : u = 1 / 4 := by
  sorry

1.3. linear_combination for nonlinear equations

Despite the name, where linear_combination really comes into its own is in solving nonlinear equations: polynomial equations of degree greater than one. For example, consider the following calculation, which comes up in studying the twisted cubic.

Problem

Let \(x, y, z, w\) be complex numbers and suppose that \(xz=y^2\) and \(yw=z^2\). Show that \(z(xw-yz)=0\).

This can be solved by exhibiting \(z(xw-yz)\) as an element of the ideal generated by \(xz-y^2\) and \(yw-z^2\):

\[z(xw-yz) = w (xz-y^2) + y (yw-z^2).\]
example {x y z w : } (h₁ : x * z = y ^ 2) (h₂ : y * w = z ^ 2) :
    z * (x * w - y * z) = 0 := by
  linear_combination w * h₁ + y * h₂

Even on a problem where your intuition is to use rw, the tactic linear_combination can probably do it.

Problem

Let \(a\) and \(b\) be rational numbers and suppose that \(a = b\). Show that \(a ^ 2 = b ^ 2\).

example {a b : } (h : a = b) : a ^ 2 = b ^ 2 := by linear_combination (a + b) * h

Problem

Let \(a\) and \(b\) be rational numbers and suppose that \(a = b\). Show that \(a ^ 3 = b ^ 3\).

example {a b : } (h : a = b) : a ^ 3 = b ^ 3 := by
  linear_combination (a ^ 2 + a * b + b ^ 2) * h

Do you see the pattern?

Importantly, linear_combination strictly subsumes the tactic ring. In fact, ring amounts to doing a linear_combination of no hypotheses!

Problem

Let \(m\) and \(n\) be integers. Show that

\[(m ^ 2 - n ^ 2) ^ 2 + (2 m n) ^ 2 = (m ^ 2 + n ^ 2) ^ 2.\]
example (m n : ) : (m ^ 2 - n ^ 2) ^ 2 + (2 * m * n) ^ 2 = (m ^ 2 + n ^ 2) ^ 2 := by
  linear_combination

Try the following examples, until you get bored.

example {x y : } (h₁ : x + 3 = 5) (h₂ : 2 * x - y * x = 0) : y = 2 := by
  sorry

example {x y : } (h₁ : x - y = 4) (h₂ : x * y = 1) : (x + y) ^ 2 = 20 := by
  sorry

example {a b c d e f : } (h₁ : a * d = b * c) (h₂ : c * f = d * e) :
    d * (a * f - b * e) = 0 := by
  sorry

example {u v : } (h₁ : u + 1 = v) : u ^ 2 + 3 * u + 1 = v ^ 2 + v - 1 := by
  sorry

example {z : } (h₁ : z ^ 2 + 1 = 0) : z ^ 4 + z ^ 3 + 2 * z ^ 2 + z + 3 = 2 := by
  sorry

example {p q r : } (h₁ : p + q + r = 0) (h₂ : p * q + p * r + q * r = 2) :
    p ^ 2 + q ^ 2 + r ^ 2 = -4 := by
  sorry

1.4. Basics of the polyrith tactic

Surprise! None of the work we did in the last two sections finding the coefficients for linear_combination by hand was necessary. The tactic, polyrith, contributed to Mathlib in July 2022 by Brown undergraduate Dhruv Bhatia, will obtain them from the Sage function MPolynomial_libsingular.lift, so long as you have an internet connection.

(The tactic also requires that your python3 have the requests package installed. This is probably already the case, but if you encounter bugs that look like they might be caused by this, install the package by running python3 -m pip install requests at the command line.)

Here is polyrith being let loose on all the examples from the previous two sections. In each case, click on the blue “Try this” underline, to replace the polyrith invocation (which will query Sage each time) with an automatically-computed linear_combination which stores its result.

example {a b : } (h₁ : a - 5 * b = 4) (h₂ : b + 2 = 3) : a = 9 := by polyrith

example {m n : } (h : m - n = 0) : m = n := by polyrith

example {K : Type*} [Field K] [CharZero K] {s : K} (hs : 3 * s + 1 = 4) : s = 1 := by
  polyrith

example {p q : } (h₁ : p + 2 * q = 4) (h₂ : p - 2 * q = 2) : 2 * p = 6 := by polyrith

example {x y z w : } (h₁ : x * z = y ^ 2) (h₂ : y * w = z ^ 2) :
    z * (x * w - y * z) = 0 := by
  polyrith

example {a b : } (h : a = b) : a ^ 2 = b ^ 2 := by polyrith

example {a b : } (h : a = b) : a ^ 3 = b ^ 3 := by polyrith

example (m n : ) : (m ^ 2 - n ^ 2) ^ 2 + (2 * m * n) ^ 2 = (m ^ 2 + n ^ 2) ^ 2 := by
  polyrith