ring-like tactics #
The core normalization procedure for ring-like tactics that solve equations in commutative (semi)rings where the exponents can also contain variables. Based on http://www.cs.ru.nl/~freek/courses/tt-2014/read/10.1.1.61.3041.pdf .
More precisely, expressions of the following form are supported:
- constants (non-negative integers)
- variables
- coefficients (living in
BaseType; forringthis is a rational embedded into the semiring) - addition of expressions
- multiplication of expressions (
a * b) - scalar multiplication of expressions (
r • a) - exponentiation of expressions (the exponent must have type
ℕ) - subtraction and negation of expressions (if the base is a full ring)
The extension to exponents means that something like 2 * 2^n * b = b * 2^(n+1) can be proved,
even though it is not strictly speaking an equation in the language of commutative rings.
Implementation notes #
The basic approach to prove equalities is to normalise both sides and check for equality.
The normalisation is guided by building a value in the type ExSum at the meta level,
together with a proof (at the base level) that the original value is equal to
the normalised version.
The outline of the file:
- Define a mutual inductive family of types
ExSum,ExProd,ExBase, which can represent expressions with+,*,^and some parametricBaseType. The mutual induction ensures that associativity and distributivity are applied, by restricting which kinds of subexpressions appear as arguments to the various operators. - Represent addition, multiplication and exponentiation in the
ExSumtype, thus allowing us to map expressions toExSum(theevalfunction drives this). We apply associativity and distributivity of the operators here (helped byEx*types) and commutativity as well (by sorting the subterms; unfortunately not helped by anything). Any expression not of the above formats is treated as an atom (the same as a variable).
There are some details we glossed over which make the plan more complicated:
- The order on atoms is not initially obvious. We construct a list containing them in order of initial appearance in the expression, then use the index into the list as a key to order on.
- For
pow, the exponent must be a natural number, while the base can be any semiringα. We swap out operations for the base ringαwith those for the exponent ringℕas soon as we deal with exponents. Unfortunately this has to be done with a separate inductive type due to universe issues outlined later in this file.
Caveats and future work #
The normalized form of an expression is the one that is useful for the tactic,
but not as nice to read. To remedy this, the user-facing normalization calls ringNFCore.
Subtraction cancels out identical terms, but division does not.
That is: a - a = 0 := by ring solves the goal,
but a / a := 1 by ring doesn't.
Note that 0 / 0 is generally defined to be 0,
so division cancelling out is not true in general.
Multiplication of powers can be simplified a little bit further:
2 ^ n * 2 ^ n = 4 ^ n := by ring could be implemented
in a similar way that 2 * a + 2 * a = 4 * a := by ring already works.
This feature wasn't needed yet, so it's not implemented yet.
Tags #
ring, semiring, exponent, power
A typed expression of type CommSemiring ℕ used when we are working on
ring subexpressions of type ℕ.
Equations
Instances For
The data used by ring to represent coefficients. e is a raw rat cast.
We include e as a parameter even though it is unused in this definition because it lets us use
Qq type annotations in the RingCompute structure, and so that it can be used with the Result
type defined below.
- value : ℚ
The value represented by
e. Should not be zero.
Instances For
Equations
Instances For
The data used to represent coefficients in exponents. This is the same data that ring uses.
Equations
Instances For
The ExNat types #
The Ex{Base,Prod,Sum}Nat types are equivalent to Ex{Base,Prod,Sum} btℕ sℕ. ExProdNat is only
used to represent exponents in ExProds. We cannot use ExProd btℕ sℕ in the mul constructor
of ExProd because BaseType is a parameter and not an index. Making BaseType an index
(i.e. moving it to the right of the colon) would require including it as an argument to each
constructor, raising the universe level of ExProd from Type to Type 1; that is:
inductive ExProd : ∀ {u : Lean.Level} {α : Q(Type u)} (BaseType : Q($α) → Type)
(sα : Q(CommSemiring $α)) (e : Q($α)), Type
| const {u : Lean.Level} {α : Q(Type u)} {BaseType} {sα} {e : Q($α)} (value : BaseType e) :
ExProd BaseType sα e
| mul {u : Lean.Level} {α : Q(Type u)} {BaseType} {sα} {x : Q($α)} {e : Q(ℕ)} {b : Q($α)} :
ExBase BaseType sα x → ExProd btℕ sℕ e → ExProd BaseType sα b →
ExProd BaseType sα q($x ^ $e * $b)
would fail to compile because ExProd lives in Type 1.
Lean does not support monadic computation in Type 1 in its core monad types,
so we cannot tolerate this universe bump.
ExBaseNat e stores the structure of a normalized expression e : Q(ℕ), which appears
as the base of an exponent expression e^n. The sum constructor is only used when the exponent
n is not a constant.
Used to represent normalized natural number expressions in exponents.
ExBaseNat q($e) is equivalent to ExBase btℕ sℕ q($e), and one can cast between the two.
- atom
{e : Q(ℕ)}
(id : ℕ)
: ExBaseNat e
An atomic expression
ewith idid.Atomic expressions are those which
ringcannot parse any further. For instance,a + (a % b)hasaand(a % b)as atoms. Thering1tactic does not normalize the subexpressions in atoms, butring_nfdoes.Atoms in fact represent equivalence classes of expressions, modulo definitional equality. The field
index : ℕshould be a unique number for each class, whilee : Q($α)contains a representative of this class. - sum
{e : Q(ℕ)}
: ExSumNat e → ExBaseNat e
A sum of monomials.
Instances For
ExProdNat e stores the structure of a normalized monomial expression e : Q(ℕ).
A monomial here is a product of powers of ExBaseNat expressions, terminated by a (nonzero)
constant coefficient.
Used to represent normalized natural number expressions in exponents.
ExProdNat q($e) is equivalent to ExProd btℕ sℕ q($e), and one can cast between the two.
- const
{e : Q(ℕ)}
(value : btℕ e)
: ExProdNat e
A coefficient
value, holding the data thatringuses to represent rational coefficients. In this case these happen to always be natural numbers. - mul {x e b : Q(ℕ)} : ExBaseNat x → ExProdNat e → ExProdNat b → ExProdNat q(«$x» ^ «$e» * «$b»)
Instances For
ExSumNat e stores the structure of a normalized polynomial expression e : Q(ℕ), which is
a sum of monomials.
Used to represent normalized natural number expressions in exponents.
ExSumNat q($e) is equivalent to ExSum btℕ sℕ q($e), and one can cast between the two.
- zero : ExSumNat q(0)
Zero is a polynomial.
eis the expression0. - add
{a b : Q(ℕ)}
: ExProdNat a → ExSumNat b → ExSumNat q(«$a» + «$b»)
A sum
a + bis a polynomial ifais a monomial andbis another polynomial.
Instances For
The BaseType parameter is used to specify how constant coefficients are stored. In the ring
tactic we need only to store coefficients as normalizations to rational numbers, but in a future
algebra tactic the base type may itself be a normalized ring expression.
ExBase BaseType sα e stores the structure of a normalized expression e, which appears
as the base of an exponent expression e^n. The sum constructor is only used when the exponent
n is not a constant.
- atom
{u : Lean.Level}
{α : Q(Type u)}
{BaseType : Q(«$α») → Type}
{sα : Q(CommSemiring «$α»)}
{e : Q(«$α»)}
(id : ℕ)
: ExBase BaseType sα e
An atomic expression
ewith idid.Atomic expressions are those which a
ring-like tactic cannot parse any further. For instance,a + (a % b)hasaand(a % b)as atoms. Thering1tactic does not normalize the subexpressions in atoms, butring_nfdoes.Atoms in fact represent equivalence classes of expressions, modulo definitional equality. The field
index : ℕshould be a unique number for each class, whilee : Q($α)contains a representative of this class. - sum
{u : Lean.Level}
{α : Q(Type u)}
{BaseType : Q(«$α») → Type}
{sα : Q(CommSemiring «$α»)}
{e : Q(«$α»)}
: ExSum BaseType sα e → ExBase BaseType sα e
A sum of monomials.
Instances For
ExProd BaseType sα e stores the structure of a normalized monomial expression e.
A monomial here is a product of powers of ExBase expressions, terminated by a (nonzero) constant
coefficient. The data of the constant coefficient is stored in the BaseType.
- const {u : Lean.Level} {α : Q(Type u)} {BaseType : Q(«$α») → Type} {sα : Q(CommSemiring «$α»)} {e : Q(«$α»)} (value : BaseType e) : ExProd BaseType sα e
- mul {u : Lean.Level} {α : Q(Type u)} {BaseType : Q(«$α») → Type} {sα : Q(CommSemiring «$α»)} {x : Q(«$α»)} {e : Q(ℕ)} {b : Q(«$α»)} : ExBase BaseType sα x → ExProdNat e → ExProd BaseType sα b → ExProd BaseType sα q(«$x» ^ «$e» * «$b»)
Instances For
ExSum BaseType sα e stores the structure of a normalized polynomial expression e, which is
a sum of monomials.
- zero
{u : Lean.Level}
{α : Q(Type u)}
{BaseType : Q(«$α») → Type}
{sα : Q(CommSemiring «$α»)}
: ExSum BaseType sα q(0)
Zero is a polynomial.
eis the expression0. - add
{u : Lean.Level}
{α : Q(Type u)}
{BaseType : Q(«$α») → Type}
{sα : Q(CommSemiring «$α»)}
{a b : Q(«$α»)}
: ExProd BaseType sα a → ExSum BaseType sα b → ExSum BaseType sα q(«$a» + «$b»)
A sum
a + bis a polynomial ifais a monomial andbis another polynomial.
Instances For
The result of evaluating an (unnormalized) expression e into the type family E
(typically one of ExSum, ExProd, ExBase or BaseType) is a (normalized) element e'
and a representation E e' for it, and a proof of e = e'.
- expr : Q(«$α»)
The normalized result.
- val : E self.expr
The data associated to the normalization.
- proof : Q(«$e» = unknown_1)
A proof that the original expression is equal to the normalized result.
Instances For
Defines how comparisons and binary equality are computed in the base type. These are seperated from RingCompute because they can often be defined without using instance caches.
- eq {x y : Q(«$α»)} : BaseType x → BaseType y → Bool
Returns whether two coefficients are equal
- compare {x y : Q(«$α»)} : BaseType x → BaseType y → Ordering
Returns whether
xis less than, equal to or greater thany. Can be any total order.
Instances For
Stores all of the normalization procedures on the coefficient type.
ring implements these using norm_num
algebra will implement these using ring
- add {x y : Q(«$α»)} : BaseType x → BaseType y → Lean.MetaM (Result BaseType q(«$x» + «$y») × Option Q(Meta.NormNum.IsNat («$x» + «$y») 0))
Evaluate the sum of two coefficents.
If the result is zero returns a proof of this fact, which is used to remove zero terms.
- mul {x y : Q(«$α»)} : BaseType x → BaseType y → Lean.MetaM (Result BaseType q(«$x» * «$y»))
Evaluate the product of two coefficents.
- cast (v : Lean.Level) (β : Q(Type v)) : Q(CommSemiring «$β») → (x✝ : Q(SMul «$β» «$α»)) → (x : Q(«$β»)) → AtomM ((y : Q(«$α»)) × ExSum BaseType sα q(«$y») × Q(∀ (a : «$α»), «$x» • a = «$y» * a))
Given a commutative ring
βwith a scalar multiplication action onαand ax : β, castxtoαsuch that the scalar multiplication turns into normal multiplication. Typically one can think ofαas being an algebra overβ, but this file does not know aboutAlgebras. Evaluate the negation of a coefficient.
- pow {x : Q(«$α»)} {b : Q(ℕ)} : BaseType x → (vb : ExProdNat q(«$b»)) → OptionT Lean.MetaM (Result BaseType q(«$x» ^ «$b»))
Raise a coefficient to some natural power.
The exponent is not necessarily a natural literal. If the tactic can only raise coefficients to the power of a literal (e.g.
ring), it should check for this and returnnoneotherwise. - inv {x : Q(«$α»)} (czα : Option Q(CharZero «$α»)) (fα : Q(Semifield «$α»)) : BaseType x → AtomM (Option (Result BaseType q(«$x»⁻¹)))
Evaluate the inverse of a coefficient.
- derive (x : Q(«$α»)) : Lean.MetaM (Result (ExSum BaseType sα) q(«$x»))
Evaluate an expression as a potential coefficient.
- isOne {x : Q(«$α»)} : BaseType x → Option Q(Meta.NormNum.IsNat «$x» 1)
Decides whether a coefficient is 1 and returns a proof if so.
- one : Result BaseType q(Nat.rawCast 1)
The number 1 represented as a BaseType.
Instances For
Equations
- Mathlib.Tactic.Ring.Common.instCoeOutRingComputeRingCompare BaseType sα = { coe := fun (x : Mathlib.Tactic.Ring.Common.RingCompute BaseType sα) => x.toRingCompare }
Equations
Equations
Embed an exponent (an ExBase, ExProd pair) as an ExProd by multiplying by 1.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Embed ExProd in ExSum by adding 0.
Instances For
Equality test for expressions. This is not a BEq instance because it is heterogeneous.
Equality test for expressions. This is not a BEq instance because it is heterogeneous.
Equality test for expressions. This is not a BEq instance because it is heterogeneous.
A total order on normalized expressions.
This is not an Ord instance because it is heterogeneous.
A total order on normalized expressions.
This is not an Ord instance because it is heterogeneous.
A total order on normalized expressions.
This is not an Ord instance because it is heterogeneous.
Get the leading coefficient of an ExProd.
Equations
- (Mathlib.Tactic.Ring.Common.ExProd.const q).coeff = ⟨e, q⟩
- (Mathlib.Tactic.Ring.Common.ExProd.mul a a_1 v).coeff = v.coeff
Instances For
Two monomials are said to "overlap" if they differ by a constant factor, in which case the constants just add. When this happens, the constant may be either zero (if the monomials cancel) or nonzero (if they add up); the zero case is handled specially.
- zero
{u : Lean.Level}
{α : Q(Type u)}
{bt : Q(«$α») → Type}
{sα : Q(CommSemiring «$α»)}
{e : Q(«$α»)}
: Q(Meta.NormNum.IsNat «$e» 0) → Overlap bt sα e
The expression
e(the sum of monomials) is equal to0. - nonzero
{u : Lean.Level}
{α : Q(Type u)}
{bt : Q(«$α») → Type}
{sα : Q(CommSemiring «$α»)}
{e : Q(«$α»)}
: Result (ExProd bt sα) e → Overlap bt sα e
The expression
e(the sum of monomials) is equal to another monomial (with nonzero leading coefficient).
Instances For
Addition #
Given monomials va, vb, attempts to add them together to get another monomial.
If the monomials are not compatible, returns none.
For example, xy + 2xy = 3xy is a .nonzero overlap, while xy + xz returns none
and xy + -xy = 0 is a .zero overlap.
Equations
- One or more equations did not get rendered due to their size.
- Mathlib.Tactic.Ring.Common.evalAddOverlap rc rcℕ va vb = do liftM (Lean.checkSystem `Mathlib.Tactic.Ring.Common.evalAddOverlap.toString) OptionT.fail
Instances For
Adds two polynomials va, vb together to get a normalized result polynomial.
0 + b = ba + 0 = aa * x + a * y = a * (x + y)(forx,ycoefficients; usesevalAddOverlap)(a₁ + a₂) + (b₁ + b₂) = a₁ + (a₂ + (b₁ + b₂))(ifa₁.lt b₁)(a₁ + a₂) + (b₁ + b₂) = b₁ + ((a₁ + a₂) + b₂)(if nota₁.lt b₁)
Multiplication #
Multiplies two monomials va, vb together to get a normalized result monomial.
x * y = (x * y)(forx,ycoefficients)x * (b₁ * b₂) = b₁ * (b₂ * x)(forxcoefficient)(a₁ * a₂) * y = a₁ * (a₂ * y)(forycoefficient)(x ^ ea * a₂) * (x ^ eb * b₂) = x ^ (ea + eb) * (a₂ * b₂)(ifeaandebare identical except coefficient)(a₁ * a₂) * (b₁ * b₂) = a₁ * (a₂ * (b₁ * b₂))(ifa₁.lt b₁)(a₁ * a₂) * (b₁ * b₂) = b₁ * ((a₁ * a₂) * b₂)(if nota₁.lt b₁)
Multiplies a monomial va to a polynomial vb to get a normalized result polynomial.
a * 0 = 0a * (b₁ + b₂) = (a * b₁) + (a * b₂)
Equations
- One or more equations did not get rendered due to their size.
- Mathlib.Tactic.Ring.Common.evalMul₁ rc rcℕ va Mathlib.Tactic.Ring.Common.ExSum.zero = pure { expr := q(0), val := Mathlib.Tactic.Ring.Common.ExSum.zero, proof := q(⋯) }
Instances For
Multiplies two polynomials va, vb together to get a normalized result polynomial.
0 * b = 0(a₁ + a₂) * b = (a₁ * b) + (a₂ * b)
Equations
- One or more equations did not get rendered due to their size.
- Mathlib.Tactic.Ring.Common.evalMul rc rcℕ Mathlib.Tactic.Ring.Common.ExSum.zero vb = pure { expr := q(0), val := Mathlib.Tactic.Ring.Common.ExSum.zero, proof := q(⋯) }
Instances For
Negation #
Negates a monomial va to get another monomial.
-c = (-c)(forccoefficient)-(a₁ * a₂) = a₁ * -a₂
Equations
- One or more equations did not get rendered due to their size.
Instances For
Negates a polynomial va to get another polynomial.
-0 = 0(forccoefficient)-(a₁ + a₂) = -a₁ + -a₂
Equations
- One or more equations did not get rendered due to their size.
- Mathlib.Tactic.Ring.Common.evalNeg rc rα Mathlib.Tactic.Ring.Common.ExSum.zero = pure { expr := q(0), val := Mathlib.Tactic.Ring.Common.ExSum.zero, proof := q(⋯) }
Instances For
Subtraction #
Subtracts two polynomials va, vb to get a normalized result polynomial.
a - b = a + -b
Equations
- One or more equations did not get rendered due to their size.
Instances For
Exponentiation #
The fallback case for exponentiating polynomials is to use ExBase.toProd to just build an
exponent expression. (This has a slightly different normalization than evalPowAtom because
the input types are different.)
x ^ e = (x + 0) ^ e * 1
Equations
- One or more equations did not get rendered due to their size.
Instances For
The fallback case for exponentiating polynomials is to use ExBase.toProd to just build an
exponent expression.
x ^ e = x ^ e * 1 + 0
Equations
- One or more equations did not get rendered due to their size.
Instances For
The main case of exponentiation of ring expressions is when va is a polynomial and n is a
nonzero literal expression, like (x + y)^5. In this case we work out the polynomial completely
into a sum of monomials.
x ^ 1 = xx ^ (2*n) = x ^ n * x ^ nx ^ (2*n+1) = x ^ n * x ^ n * x
There are several special cases when exponentiating monomials:
1 ^ n = 1x ^ y = (x ^ y)whenxis a constant (Note this may fail if e.g.yis not a constant)(a * b) ^ e = a ^ e * b ^ e
In all other cases we use evalPowProdAtom.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The result of extractCoeff is a numeral and a proof that the original expression
factors by this numeral.
- k : Q(ℕ)
A raw natural number literal.
- e' : Q(ℕ)
The result of extracting the coefficient is a monic monomial.
e'is a monomial.
Instances For
Given a monomial expression va, splits off the leading coefficient k and the remainder
e', stored in the ExtractCoeff structure.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Exponentiates a polynomial va by a monomial vb, including several special cases.
a ^ 1 = a0 ^ e = 0if0 < e(a + 0) ^ b = a ^ bcomputed usingevalPowProda ^ b = (a ^ b') ^ kifb = b' * kandk > 1
Otherwise a ^ b is just encoded as a ^ b * 1 + 0 using evalPowAtom.
Exponentiates two polynomials va, vb.
a ^ 0 = 1a ^ (b₁ + b₂) = a ^ b₁ * a ^ b₂
Equations
- One or more equations did not get rendered due to their size.
Instances For
This cache contains data required by the ring tactic during execution.
A ring instance on
α, if available.A division semiring instance on
α, if available.A characteristic zero ring instance on
α, if available.
Instances For
Create a new cache for α by doing the necessary instance searches.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Evaluates an atom, an expression where ring can find no additional structure.
a = a ^ 1 * 1 + 0
Equations
- One or more equations did not get rendered due to their size.
Instances For
Applies ⁻¹ to a polynomial to get an atom.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Inverts a polynomial va to get a normalized result polynomial.
c⁻¹ = (c⁻¹)ifcis a constant(a ^ b * c)⁻¹ = a⁻¹ ^ b * c⁻¹
Equations
- One or more equations did not get rendered due to their size.
Instances For
Inverts a polynomial va to get a normalized result polynomial.
0⁻¹ = 0a⁻¹ = (a⁻¹)ifais a nontrivial sum
Equations
- One or more equations did not get rendered due to their size.
- Mathlib.Tactic.Ring.Common.ExSum.evalInv rc rcℕ dsα czα Mathlib.Tactic.Ring.Common.ExSum.zero = pure { expr := q(0), val := Mathlib.Tactic.Ring.Common.ExSum.zero, proof := q(⋯) }
Instances For
Divides two polynomials va, vb to get a normalized result polynomial.
a / b = a * b⁻¹
Equations
- One or more equations did not get rendered due to their size.
Instances For
Checks whether e would be processed by eval as a ring expression,
or otherwise if it is an atom or something simplifiable via norm_num.
We use this in ring_nf to avoid rewriting atoms unnecessarily.
Returns:
noneifevalwould processeas an algebraic ring expressionsome noneifevalwould treateas an atom.some (some r)ifevalwould not processeas an algebraic ring expression, butNormNum.derivecan nevertheless simplifye, with resultr.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Evaluates expression e of type α into a normalized representation as a polynomial.
This is the main driver of ring, which calls out to evalAdd, evalMul etc.
rctells us how to normalize constants inα.rcℕtells us how to normalize constants in exponents.