[Before](https://github.com/leanprover/lean4/files/14772220/oi.pdf) and [after](https://github.com/leanprover/lean4/files/14772226/oi2.pdf). This gets `ByteArray`, `String.Extra`, `ToString.Macro` and `RCases` out of the imports of `omega`. I'd hoped to get `Array.Subarray` too, but it's tangled up in the list literal syntax. Further progress could come from make `split` use available `Decidable` instances, so we could pull out `Classical` (and possibly some of `PropLemmas`).
179 lines
6.7 KiB
Text
179 lines
6.7 KiB
Text
/-
|
||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Scott Morrison
|
||
-/
|
||
prelude
|
||
import Init.Omega.Coeffs
|
||
import Init.Data.ToString.Macro
|
||
|
||
/-!
|
||
# Linear combinations
|
||
|
||
We use this data structure while processing hypotheses.
|
||
|
||
-/
|
||
|
||
namespace Lean.Omega
|
||
|
||
/-- Internal representation of a linear combination of atoms, and a constant term. -/
|
||
structure LinearCombo where
|
||
/-- Constant term. -/
|
||
const : Int := 0
|
||
/-- Coefficients of the atoms. -/
|
||
coeffs : Coeffs := []
|
||
deriving DecidableEq, Repr
|
||
|
||
namespace LinearCombo
|
||
|
||
instance : ToString LinearCombo where
|
||
toString lc :=
|
||
s!"{lc.const}{String.join <| lc.coeffs.toList.enum.map fun ⟨i, c⟩ => s!" + {c} * x{i+1}"}"
|
||
|
||
instance : Inhabited LinearCombo := ⟨{const := 1}⟩
|
||
|
||
theorem ext {a b : LinearCombo} (w₁ : a.const = b.const) (w₂ : a.coeffs = b.coeffs) :
|
||
a = b := by
|
||
cases a; cases b
|
||
subst w₁; subst w₂
|
||
congr
|
||
|
||
/--
|
||
Evaluate a linear combination `⟨r, [c_1, …, c_k]⟩` at values `[v_1, …, v_k]` to obtain
|
||
`r + (c_1 * x_1 + (c_2 * x_2 + ... (c_k * x_k + 0))))`.
|
||
-/
|
||
def eval (lc : LinearCombo) (values : Coeffs) : Int :=
|
||
lc.const + lc.coeffs.dot values
|
||
|
||
@[simp] theorem eval_nil : (lc : LinearCombo).eval .nil = lc.const := by
|
||
simp [eval]
|
||
|
||
/-- The `i`-th coordinate function. -/
|
||
def coordinate (i : Nat) : LinearCombo where
|
||
const := 0
|
||
coeffs := Coeffs.set .nil i 1
|
||
|
||
@[simp] theorem coordinate_eval (i : Nat) (v : Coeffs) :
|
||
(coordinate i).eval v = v.get i := by
|
||
simp [eval, coordinate]
|
||
|
||
theorem coordinate_eval_0 : (coordinate 0).eval (.ofList (a0 :: t)) = a0 := by simp
|
||
theorem coordinate_eval_1 : (coordinate 1).eval (.ofList (a0 :: a1 :: t)) = a1 := by simp
|
||
theorem coordinate_eval_2 : (coordinate 2).eval (.ofList (a0 :: a1 :: a2 :: t)) = a2 := by simp
|
||
theorem coordinate_eval_3 :
|
||
(coordinate 3).eval (.ofList (a0 :: a1 :: a2 :: a3 :: t)) = a3 := by simp
|
||
theorem coordinate_eval_4 :
|
||
(coordinate 4).eval (.ofList (a0 :: a1 :: a2 :: a3 :: a4 :: t)) = a4 := by simp
|
||
theorem coordinate_eval_5 :
|
||
(coordinate 5).eval (.ofList (a0 :: a1 :: a2 :: a3 :: a4 :: a5 :: t)) = a5 := by simp
|
||
theorem coordinate_eval_6 :
|
||
(coordinate 6).eval (.ofList (a0 :: a1 :: a2 :: a3 :: a4 :: a5 :: a6 :: t)) = a6 := by simp
|
||
theorem coordinate_eval_7 :
|
||
(coordinate 7).eval
|
||
(.ofList (a0 :: a1 :: a2 :: a3 :: a4 :: a5 :: a6 :: a7 :: t)) = a7 := by simp
|
||
theorem coordinate_eval_8 :
|
||
(coordinate 8).eval
|
||
(.ofList (a0 :: a1 :: a2 :: a3 :: a4 :: a5 :: a6 :: a7 :: a8 :: t)) = a8 := by simp
|
||
theorem coordinate_eval_9 :
|
||
(coordinate 9).eval
|
||
(.ofList (a0 :: a1 :: a2 :: a3 :: a4 :: a5 :: a6 :: a7 :: a8 :: a9 :: t)) = a9 := by simp
|
||
|
||
/-- Implementation of addition on `LinearCombo`. -/
|
||
def add (l₁ l₂ : LinearCombo) : LinearCombo where
|
||
const := l₁.const + l₂.const
|
||
coeffs := l₁.coeffs + l₂.coeffs
|
||
|
||
instance : Add LinearCombo := ⟨add⟩
|
||
|
||
@[simp] theorem add_const {l₁ l₂ : LinearCombo} : (l₁ + l₂).const = l₁.const + l₂.const := rfl
|
||
@[simp] theorem add_coeffs {l₁ l₂ : LinearCombo} : (l₁ + l₂).coeffs = l₁.coeffs + l₂.coeffs := rfl
|
||
|
||
/-- Implementation of subtraction on `LinearCombo`. -/
|
||
def sub (l₁ l₂ : LinearCombo) : LinearCombo where
|
||
const := l₁.const - l₂.const
|
||
coeffs := l₁.coeffs - l₂.coeffs
|
||
|
||
instance : Sub LinearCombo := ⟨sub⟩
|
||
|
||
@[simp] theorem sub_const {l₁ l₂ : LinearCombo} : (l₁ - l₂).const = l₁.const - l₂.const := rfl
|
||
@[simp] theorem sub_coeffs {l₁ l₂ : LinearCombo} : (l₁ - l₂).coeffs = l₁.coeffs - l₂.coeffs := rfl
|
||
|
||
/-- Implementation of negation on `LinearCombo`. -/
|
||
def neg (lc : LinearCombo) : LinearCombo where
|
||
const := -lc.const
|
||
coeffs := -lc.coeffs
|
||
|
||
instance : Neg LinearCombo := ⟨neg⟩
|
||
|
||
@[simp] theorem neg_const {l : LinearCombo} : (-l).const = -l.const := rfl
|
||
@[simp] theorem neg_coeffs {l : LinearCombo} : (-l).coeffs = -l.coeffs := rfl
|
||
|
||
theorem sub_eq_add_neg (l₁ l₂ : LinearCombo) : l₁ - l₂ = l₁ + -l₂ := by
|
||
rcases l₁ with ⟨a₁, c₁⟩; rcases l₂ with ⟨a₂, c₂⟩
|
||
apply ext
|
||
· simp [Int.sub_eq_add_neg]
|
||
· simp [Coeffs.sub_eq_add_neg]
|
||
|
||
/-- Implementation of scalar multiplication of a `LinearCombo` by an `Int`. -/
|
||
def smul (lc : LinearCombo) (i : Int) : LinearCombo where
|
||
const := i * lc.const
|
||
coeffs := lc.coeffs.smul i
|
||
|
||
instance : HMul Int LinearCombo LinearCombo := ⟨fun i lc => lc.smul i⟩
|
||
|
||
@[simp] theorem smul_const {lc : LinearCombo} {i : Int} : (i * lc).const = i * lc.const := rfl
|
||
@[simp] theorem smul_coeffs {lc : LinearCombo} {i : Int} : (i * lc).coeffs = i * lc.coeffs := rfl
|
||
|
||
@[simp] theorem add_eval (l₁ l₂ : LinearCombo) (v : Coeffs) :
|
||
(l₁ + l₂).eval v = l₁.eval v + l₂.eval v := by
|
||
rcases l₁ with ⟨r₁, c₁⟩; rcases l₂ with ⟨r₂, c₂⟩
|
||
simp only [eval, add_const, add_coeffs, Int.add_assoc, Int.add_left_comm]
|
||
congr
|
||
exact Coeffs.dot_distrib_left c₁ c₂ v
|
||
|
||
@[simp] theorem neg_eval (lc : LinearCombo) (v : Coeffs) : (-lc).eval v = - lc.eval v := by
|
||
rcases lc with ⟨a, coeffs⟩
|
||
simp [eval, Int.neg_add]
|
||
|
||
@[simp] theorem sub_eval (l₁ l₂ : LinearCombo) (v : Coeffs) :
|
||
(l₁ - l₂).eval v = l₁.eval v - l₂.eval v := by
|
||
simp [sub_eq_add_neg, Int.sub_eq_add_neg]
|
||
|
||
@[simp] theorem smul_eval (lc : LinearCombo) (i : Int) (v : Coeffs) :
|
||
(i * lc).eval v = i * lc.eval v := by
|
||
rcases lc with ⟨a, coeffs⟩
|
||
simp [eval, Int.mul_add]
|
||
|
||
theorem smul_eval_comm (lc : LinearCombo) (i : Int) (v : Coeffs) :
|
||
(i * lc).eval v = lc.eval v * i := by
|
||
simp [Int.mul_comm]
|
||
|
||
/--
|
||
Multiplication of two linear combinations.
|
||
This is useful only if at least one of the linear combinations is constant,
|
||
and otherwise should be considered as a junk value.
|
||
-/
|
||
def mul (l₁ l₂ : LinearCombo) : LinearCombo :=
|
||
l₂.const * l₁ + l₁.const * l₂ - { const := l₁.const * l₂.const }
|
||
|
||
theorem mul_eval_of_const_left (l₁ l₂ : LinearCombo) (v : Coeffs) (w : l₁.coeffs.isZero) :
|
||
(mul l₁ l₂).eval v = l₁.eval v * l₂.eval v := by
|
||
have : Coeffs.dot l₁.coeffs v = 0 := IntList.dot_of_left_zero w
|
||
simp [mul, eval, this, Coeffs.sub_eq_add_neg, Coeffs.dot_distrib_left, Int.add_mul, Int.mul_add,
|
||
Int.mul_comm]
|
||
|
||
theorem mul_eval_of_const_right (l₁ l₂ : LinearCombo) (v : Coeffs) (w : l₂.coeffs.isZero) :
|
||
(mul l₁ l₂).eval v = l₁.eval v * l₂.eval v := by
|
||
have : Coeffs.dot l₂.coeffs v = 0 := IntList.dot_of_left_zero w
|
||
simp [mul, eval, this, Coeffs.sub_eq_add_neg, Coeffs.dot_distrib_left, Int.add_mul, Int.mul_add,
|
||
Int.mul_comm]
|
||
|
||
theorem mul_eval (l₁ l₂ : LinearCombo) (v : Coeffs) (w : l₁.coeffs.isZero ∨ l₂.coeffs.isZero) :
|
||
(mul l₁ l₂).eval v = l₁.eval v * l₂.eval v := by
|
||
rcases w with w | w
|
||
· rw [mul_eval_of_const_left _ _ _ w]
|
||
· rw [mul_eval_of_const_right _ _ _ w]
|
||
|
||
end LinearCombo
|
||
|
||
end Lean.Omega
|