@@ -12,6 +12,8 @@ open CvxLean Minimization Real BigOperators Matrix Finset
1212
1313section LeastSquares
1414
15+ /- We first need some preliminaries on least squares. -/
16+
1517def leastSquares {n : ℕ} (a : Fin n → ℝ) :=
1618 optimization (x : ℝ)
1719 minimize (∑ i, ((a i - x) ^ 2 ) : ℝ)
@@ -84,64 +86,81 @@ def fittingSphere :=
8486 optimization (c : Fin n → ℝ) (r : ℝ)
8587 minimize (∑ i, (‖(x i) - c‖ ^ 2 - r ^ 2 ) ^ 2 : ℝ)
8688 subject to
87- h₁ : 0 < r
88-
89- instance : ChangeOfVariables fun ((c, t) : (Fin n → ℝ) × ℝ) => (c, sqrt (t + ‖c‖ ^ 2 )) :=
90- { inv := fun (c, r) => (c, r ^ 2 - ‖c‖ ^ 2 ),
91- condition := fun (_, r) => 0 ≤ r,
92- property := fun ⟨c, r⟩ h => by simp [sqrt_sq h] }
89+ h₁ : 0 ≤ r
90+
91+ -- Changes of variables ensuring bijection, which must also add the condition on `E` in the
92+ -- equivalence. TODO: Move to `CvxLean` core.
93+
94+ structure ChangeOfVariablesBij {D E} (c : E → D) where
95+ c_inv : D → E
96+ cond_D : D → Prop
97+ cond_E : E → Prop
98+ prop_D : ∀ x, cond_D x → c (c_inv x) = x
99+ prop_E : ∀ y, cond_E y → c_inv (c y) = y
100+
101+ @[equiv]
102+ def ChangeOfVariablesBij.toEquivalence {D E R} [Preorder R] {f : D → R} {cs : D → Prop } (c : E → D)
103+ (cov : ChangeOfVariablesBij c)
104+ (hD : ∀ x, cs x → cov.cond_D x)
105+ (hE : ∀ x, cs x → cov.cond_E (cov.c_inv x)) :
106+ ⟨f, cs⟩ ≡ ⟨fun y => f (c y), fun y => cs (c y) ∧ cov.cond_E y⟩ :=
107+ Equivalence.ofStrongEquivalence <|
108+ { phi := fun x => cov.c_inv x
109+ psi := fun y => c y
110+ phi_feasibility := fun x hx => by simp [feasible, cov.prop_D x (hD x hx)]; exact ⟨hx, hE x hx⟩
111+ psi_feasibility := fun y ⟨hy, _⟩ => hy
112+ phi_optimality := fun x hx => by simp [cov.prop_D x (hD x hx)]
113+ psi_optimality := fun y _ => by simp }
114+
115+ def covBij {n} : ChangeOfVariablesBij
116+ (fun ((c, t) : (Fin n → ℝ) × ℝ) => (c, sqrt (t + ‖c‖ ^ 2 ))) :=
117+ { c_inv := fun (c, r) => (c, r ^ 2 - ‖c‖ ^ 2 ),
118+ cond_D := fun (_, r) => 0 ≤ r,
119+ cond_E := fun (c, t) => 0 ≤ t + ‖c‖ ^ 2 ,
120+ prop_D := fun (c, r) h => by simp [sqrt_sq h],
121+ prop_E := fun (c, t) h => by simp at h; simp [sq_sqrt h] }
93122
94123equivalence* eqv/fittingSphereT (n m : ℕ) (x : Fin m → Fin n → ℝ) : fittingSphere n m x := by
95- -- Change of variables.
124+ -- Change of variables (bijective) + some clean up.
125+ -- TODO: Do this with `change_of_variables` (or a new command `change_of_variables_bij`).
96126 equivalence_step =>
97- apply ChangeOfVariables.toEquivalence
98- (fun (ct : (Fin n → ℝ) × ℝ) => (ct.1 , sqrt (ct.2 + ‖ct.1 ‖ ^ 2 )))
99- · rintro _ h; exact le_of_lt h
127+ apply ChangeOfVariablesBij.toEquivalence
128+ (fun (ct : (Fin n → ℝ) × ℝ) => (ct.1 , sqrt (ct.2 + ‖ct.1 ‖ ^ 2 ))) covBij
129+ · rintro cr h; exact h
130+ . rintro ct _; simp [covBij, sq_nonneg]
100131 rename_vars [c, t]
101- -- Clean up.
132+ rename_constrs [h₁, h₂]
102133 conv_constr h₁ => dsimp
103- conv_obj => dsimp
134+ conv_constr h₂ => dsimp [covBij]
104135 -- Rewrite objective.
105136 rw_obj into (Vec.sum (((Vec.norm x) ^ 2 - 2 * (Matrix.mulVec x c) - Vec.const m t) ^ 2 )) =>
106- dsimp at h₁ ⊢; simp [Vec.sum, Vec.norm, Vec.const]; congr; funext i; congr 1 ;
107- rw [norm_sub_sq (𝕜 := ℝ) (E := Fin n → ℝ), sq_sqrt (rpow_two _ ▸ le_of_lt (sqrt_pos.mp h₁) )]
137+ simp [Vec.sum, Vec.norm, Vec.const]; congr; funext i; congr 1 ;
138+ rw [norm_sub_sq (𝕜 := ℝ) (E := Fin n → ℝ), sq_sqrt (rpow_two _ ▸ h₂ )]
108139 simp [mulVec, inner, dotProduct]
140+ -- Remove redundant h₁.
141+ remove_constr h₁ => exact sqrt_nonneg _
109142
110143#print fittingSphereT
111144-- optimization (c : Fin n → ℝ) (t : ℝ)
112145-- minimize Vec.sum ((Vec.norm x ^ 2 - 2 * mulVec x c - Vec.const m t) ^ 2)
113146-- subject to
114- -- h₁ : 0 < sqrt ( t + ‖c‖ ^ 2)
147+ -- h₂ : 0 ≤ t + ‖c‖ ^ 2
115148
116- -- Next, we proceed to remove the non-convex constraint by arguing that any (non-trivial) point that
117- -- minimizes the objective function without the constraint, also satisfies the constraint. We define
118- -- the problem directly, but note that we could also remove the constraint using the `relaxation`
119- -- command.
149+ -- Next, we proceed to remove the non-convex constraint by arguing that any point that minimizes the
150+ -- objective function without the constraint, also satisfies the constraint. We define the problem
151+ -- directly, but note that we could also remove the constraint using the `reduction` command.
120152
121153def fittingSphereConvex (n m : ℕ) (x : Fin m → Fin n → ℝ) :=
122154 optimization (c : Fin n → ℝ) (t : ℝ)
123155 minimize (Vec.sum ((Vec.norm x ^ 2 - 2 * mulVec x c - Vec.const m t) ^ 2 ) : ℝ)
124156
125- /-- If the squared error is zero, then `aᵢ = x`. -/
126- lemma vec_squared_norm_error_eq_zero_iff {n m : ℕ} (a : Fin m → Fin n → ℝ) (x : Fin n → ℝ) :
127- ∑ i, ‖a i - x‖ ^ 2 = 0 ↔ ∀ i, a i = x := by
128- simp [rpow_two]
129- rw [sum_eq_zero_iff_of_nonneg (fun _ _ => sq_nonneg _)]
130- constructor
131- · intros h i
132- have hi := h i (by simp)
133- rwa [sq_eq_zero_iff, norm_eq_zero, sub_eq_zero] at hi
134- · intros h i _
135- rw [sq_eq_zero_iff, norm_eq_zero, sub_eq_zero]
136- exact h i
137-
138- /-- This tells us that solving the relaxed problem is sufficient for optimal points if the solution
139- is non-trivial. -/
157+ /-- This tells us that solving the relaxed problem is sufficient (i.e., it is a valid reduction). -/
140158lemma optimal_convex_implies_optimal_t (hm : 0 < m) (c : Fin n → ℝ) (t : ℝ)
141- (h_nontrivial : x ≠ Vec.const m c) ( h_opt : (fittingSphereConvex n m x).optimal (c, t)) :
159+ (h_opt : (fittingSphereConvex n m x).optimal (c, t)) :
142160 (fittingSphereT n m x).optimal (c, t) := by
143161 simp [fittingSphereT, fittingSphereConvex, optimal, feasible] at h_opt ⊢
144162 constructor
163+ -- Feasibility.
145164 · let a := Vec.norm x ^ 2 - 2 * mulVec x c
146165 have h_ls : optimal (leastSquaresVec a) t := by
147166 refine ⟨trivial, ?_⟩
@@ -161,47 +180,20 @@ lemma optimal_convex_implies_optimal_t (hm : 0 < m) (c : Fin n → ℝ) (t : ℝ
161180 rw [norm_sub_sq (𝕜 := ℝ) (E := Fin n → ℝ)]
162181 congr
163182 -- We use the result to establish that `t + ‖c‖ ^ 2` is non-negative.
164- have h_t_add_c2_nonneg : 0 ≤ t + ‖c‖ ^ 2 := by
165- rw [h_t_add_c2_eq]
166- apply mul_nonneg (by norm_num)
167- apply sum_nonneg
168- intros i _
169- rw [rpow_two]
170- exact sq_nonneg _
171- cases (lt_or_eq_of_le h_t_add_c2_nonneg) with
172- | inl h_t_add_c2_lt_zero =>
173- -- If it is positive, we are done.
174- convert h_t_add_c2_lt_zero; simp
175- | inr h_t_add_c2_eq_zero =>
176- -- Otherwise, it contradicts the non-triviality assumption.
177- exfalso
178- rw [h_t_add_c2_eq, zero_eq_mul] at h_t_add_c2_eq_zero
179- rcases h_t_add_c2_eq_zero with (hc | h_sum_eq_zero)
180- · simp at hc; linarith
181- rw [vec_squared_norm_error_eq_zero_iff] at h_sum_eq_zero
182- apply h_nontrivial
183- funext i
184- exact h_sum_eq_zero i
183+ rw [← rpow_two, h_t_add_c2_eq]
184+ apply mul_nonneg (by norm_num)
185+ apply sum_nonneg
186+ intros i _
187+ rw [rpow_two]
188+ exact sq_nonneg _
189+ -- Optimality.
185190 · intros c' x' _
186191 exact h_opt c' x'
187192
188- /-- We express the nontriviality condition only in terms of `x` so that it can be checked. -/
189- lemma non_triviality_condition (c : Fin n → ℝ) (hx : ∃ i j, x i ≠ x j) : x ≠ Vec.const m c := by
190- intros h
191- conv at hx => congr; ext i; rw [← not_forall]
192- rw [← not_forall] at hx
193- apply hx
194- intros i j
195- rw [congr_fun h i, congr_fun h j]
196- simp [Vec.const]
197-
198193/-- We show that we have a reduction via the identity map. -/
199- def red (hm : 0 < m) (hx : ∃ i j, x i ≠ x j) :
200- (fittingSphereT n m x) ≼ (fittingSphereConvex n m x) :=
194+ def red (hm : 0 < m) : (fittingSphereT n m x) ≼ (fittingSphereConvex n m x) :=
201195 { psi := id,
202- psi_optimality := fun (c, t) h_opt => by
203- have h_nontrivial := non_triviality_condition n m x c hx
204- exact optimal_convex_implies_optimal_t n m x hm c t h_nontrivial h_opt }
196+ psi_optimality := fun (c, t) h_opt => optimal_convex_implies_optimal_t n m x hm c t h_opt }
205197
206198#print fittingSphereConvex
207199-- optimization (c : Fin n → ℝ) (t : ℝ)
0 commit comments