Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: more tactics docs and some general refactoring #19

Merged
merged 25 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d4c5e09
doc: `remove_constr` and `remove_trivial_constrs`
ramonfmir Feb 24, 2024
7cb5975
chore: clean up logs in extractor
ramonfmir Feb 27, 2024
1d23224
style: division notation in pre-DCP main example
ramonfmir Feb 27, 2024
afe3b0a
refactor: `equivalence'` -> `equivalence*`
ramonfmir Feb 28, 2024
f0ae187
style: eta reduction in case study
ramonfmir Feb 28, 2024
575a16c
fix: equivalences cannot be lemmas
ramonfmir Feb 28, 2024
4c0b580
chore: proof example in vehicle speed scheduling
ramonfmir Feb 29, 2024
ee9f4b1
doc: add TODO on leaving goals for pre-DCP
ramonfmir Feb 29, 2024
c0923ca
doc: atom library extension
ramonfmir Feb 29, 2024
da1ff24
refactor: `Atoms` -> `AtomCmd`
ramonfmir Feb 29, 2024
37ee436
fix: line breaks in imports from refactor
ramonfmir Feb 29, 2024
a54593e
doc: helpers for `Expr`
ramonfmir Feb 29, 2024
43f5cbe
doc: add TODO to make `vconds` available
ramonfmir Feb 29, 2024
9a05ee4
doc: fix docs for removing constraints
ramonfmir Feb 29, 2024
afb9739
doc: rename constraints
ramonfmir Feb 29, 2024
e5ef756
doc: refine rename constraints
ramonfmir Feb 29, 2024
962b365
doc: rename variables
ramonfmir Feb 29, 2024
be1e4ac
style: use `throwRenameVarsError`
ramonfmir Feb 29, 2024
aa5f495
doc: reorder constraints
ramonfmir Feb 29, 2024
b687e19
feat: cleaner `equivalence_step`, `reduction_step`, and `relaxation_s…
ramonfmir Mar 1, 2024
123a1b6
fix: correct namespace for `Expr` helper functions
ramonfmir Mar 1, 2024
c0e81ff
fix: do not always try to close by `rfl` on manual steps
ramonfmir Mar 1, 2024
cb56a66
refactor: `reduction'` -> `reduction*`
ramonfmir Mar 1, 2024
fce0b00
style: tag definition with `reducible` not `simp`
ramonfmir Mar 1, 2024
e2052f8
refactor: DCP canonization not reduction
ramonfmir Mar 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CvxLean/Command/Equivalence.lean
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ environment:
* `q := r`,
* `eqv : p ≡ q`.

Writing `equivalence'` instead of `equivalence` will also generate a backward solution map at the
Writing `equivalence*` instead of `equivalence` will also generate a backward solution map at the
level of floats.
-/

Expand All @@ -46,7 +46,7 @@ syntax (name := equivalence)

/-- Open an equivalence environment and try to generate a computable backward map. -/
syntax (name := equivalenceAndBwdMap)
"equivalence'" ident "/" ident declSig ":=" Lean.Parser.Term.byTactic : command
"equivalence*" ident "/" ident declSig ":=" Lean.Parser.Term.byTactic : command

/-- Open an equivalence environment with a given left-hand-side problem (`lhsStx`) and perhaps some
parameters (`xs`). From this, an equivalence goal is set to a target problem which is represented by
Expand Down Expand Up @@ -139,7 +139,7 @@ def evalEquivalence : CommandElab := fun stx => match stx with
/-- Same as `equivalence` but also adds the backward map to the environment. -/
@[command_elab «equivalenceAndBwdMap»]
def evalEquivalenceAndBwdMap : CommandElab := fun stx => match stx with
| `(equivalence' $eqvId / $probId $declSig := $proofStx) => do
| `(equivalence* $eqvId / $probId $declSig := $proofStx) => do
liftTermElabM do
let (binders, lhsStx) := expandDeclSig declSig.raw
elabBindersEx binders.getArgs fun xs =>
Expand Down
6 changes: 3 additions & 3 deletions CvxLean/Command/Reduction.lean
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ environment:
* `q := r`,
* `red : p ≼ q`.

Writing `reduction'` instead of `reduction` will also generate a backward solution map at the
Writing `reduction*` instead of `reduction` will also generate a backward solution map at the
level of floats.

It is essentially the same as `CvxLean/Command/Equivalence.lean`, except that the goal is to prove a
Expand All @@ -51,7 +51,7 @@ syntax (name := reduction)

/-- Open a reduction environment and try to generate a computable backward map. -/
syntax (name := reductionAndBwdMap)
"reduction'" ident "/" ident declSig ":=" Lean.Parser.Term.byTactic : command
"reduction*" ident "/" ident declSig ":=" Lean.Parser.Term.byTactic : command

/-- Open a reduction environment with a given left-hand-side problem (`lhsStx`) and perhaps some
parameters (`xs`). From this, a reduction goal is set to a target problem which is represented by a
Expand Down Expand Up @@ -150,7 +150,7 @@ def evalReduction : CommandElab := fun stx => match stx with
/-- Same as `reduction` but also adds the backward map to the environment. -/
@[command_elab «reductionAndBwdMap»]
def evalReductionAndBwdMap : CommandElab := fun stx => match stx with
| `(reduction' $eqvId / $probId $declSig := $proofStx) => do
| `(reduction* $eqvId / $probId $declSig := $proofStx) => do
liftTermElabM do
let (binders, lhsStx) := expandDeclSig declSig.raw
elabBindersEx binders.getArgs fun xs =>
Expand Down
30 changes: 15 additions & 15 deletions CvxLean/Command/Solve.lean
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import CvxLean.Command.Solve.Conic

Given a problem `p : Minimization D R` a user can call `solve p` to call an external solver and
obtain a result. If successful, three new definitions are added to the environment:
* `p.reduced : Minimization (D × E) R` is the problem in conic form.
* `p.conicForm : Minimization (D × E) R` is the problem in conic form.
* `p.status : String` is the status of the solution.
* `p.solution : D` is the solution to the problem.
* `p.value : R` is the value of the solution.
Expand All @@ -32,16 +32,16 @@ def getProblemName (stx : Syntax) : MetaM Name := do

/-- Call DCP and get the problem in conic form as well as `ψ`, the backward map from the
equivalence. -/
def getReducedProblemAndBwdMap (prob : Expr) : MetaM (MinimizationExpr × Expr) := do
def getCanonizedProblemAndBwdMap (prob : Expr) : MetaM (MinimizationExpr × Expr) := do
let ogProb ← MinimizationExpr.fromExpr prob
let (redProb, eqvProof) ← DCP.canonize ogProb
let (canonProb, eqvProof) ← DCP.canonize ogProb
let backwardMap ← mkAppM ``Minimization.Equivalence.psi #[eqvProof]
return (redProb, backwardMap)
return (canonProb, backwardMap)

syntax (name := solve) "solve " term : command

/-- The `solve` command. It works as follows:
1. Reduce optimization problem to conic form.
1. Canonize optimization problem to conic form.
2. Extract problem data using `determineCoeffsFromExpr`.
3. Obtain a solution using `solutionDataFromProblemData`, which calls an external solver.
4. Store the result in the enviroment. -/
Expand All @@ -61,19 +61,19 @@ unsafe def evalSolve : CommandElab := fun stx =>
mvarId.assign mvarVal }
catch _ => pure ()

-- Create prob.reduced.
let (redProb, backwardMap) ← getReducedProblemAndBwdMap probTerm
let redProbExpr := redProb.toExpr
-- Create prob.conicForm.
let (canonProb, backwardMap) ← getCanonizedProblemAndBwdMap probTerm
let canonProbExpr := canonProb.toExpr

let probName ← getProblemName probInstance.raw

simpleAddDefn (probName ++ `reduced) redProbExpr
simpleAddDefn (probName ++ `conicForm) canonProbExpr

-- Call the solver on prob.reduced and get a point in E.
let (coeffsData, sections) ← determineCoeffsFromExpr redProb
-- Call the solver on prob.conicForm and get a point in E.
let (coeffsData, sections) ← determineCoeffsFromExpr canonProb
trace[CvxLean.debug] "Coeffs data:\n{coeffsData}"

let solData ← solutionDataFromProblemData redProb coeffsData sections
let solData ← solutionDataFromProblemData canonProb coeffsData sections
trace[CvxLean.debug] "Solution data:\n{solData}"

-- Add status to the environment.
Expand All @@ -84,8 +84,8 @@ unsafe def evalSolve : CommandElab := fun stx =>
pure ()

-- Solution makes sense, handle the numerical solution.
let solPointExpr ← exprFromSolutionData redProb solData
trace[CvxLean.debug] "Solution point (reduced problem): {solPointExpr}"
let solPointExpr ← exprFromSolutionData canonProb solData
trace[CvxLean.debug] "Solution point (canonized problem): {solPointExpr}"

let backwardMapFloat ← realToFloat <| ← whnf backwardMap
let solPointExprFloat ← realToFloat solPointExpr
Expand All @@ -97,7 +97,7 @@ unsafe def evalSolve : CommandElab := fun stx =>
simpleAddAndCompileDefn (probName ++ `solution) probSolPointFloat

-- Also add value of optimal point.
let probSolValue := mkApp redProb.objFun solPointExpr
let probSolValue := mkApp canonProb.objFun solPointExpr
let probSolValueFloat ← realToFloat probSolValue
check probSolValueFloat

Expand Down
6 changes: 3 additions & 3 deletions CvxLean/Demos/LT2024.lean
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ equivalence eqv₂/q₂ : p₂ := by

solve q₂

#print q₂.reduced
#print q₂.conicForm

#eval q₂.status
#eval q₂.solution
Expand Down Expand Up @@ -73,15 +73,15 @@ def p₃ (Awall Aflr α β γ δ : ℝ) :=

set_option trace.Meta.debug true

equivalence' eqv₃/q₃ : p₃ 100 10 0.5 2 0.5 2 := by
equivalence* eqv₃/q₃ : p₃ 100 10 0.5 2 0.5 2 := by
change_of_variables! (h') (h ↦ exp h')
change_of_variables! (w') (w ↦ exp w')
change_of_variables! (d') (d ↦ exp d')
pre_dcp

solve q₃

#print q₃.reduced
#print q₃.conicForm

#eval q₃.status
#eval q₃.solution
Expand Down
4 changes: 2 additions & 2 deletions CvxLean/Examples/CovarianceEstimation.lean
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ noncomputable def covEstimation (n : ℕ) (N : ℕ) (α : ℝ) (y : Fin N → Fi
c_pos_def : R.PosDef
c_sparse : R⁻¹.abs.sum ≤ α

reduction' red/covEstimationConvex (n : ℕ) (N : ℕ) (α : ℝ) (y : Fin N → Fin n → ℝ) :
reduction* red/covEstimationConvex (n : ℕ) (N : ℕ) (α : ℝ) (y : Fin N → Fin n → ℝ) :
covEstimation n N α y := by
-- Change objective function.
reduction_step =>
Expand Down Expand Up @@ -86,7 +86,7 @@ def yₚ : Fin Nₚ → Fin nₚ → ℝ := ![![0, 2], ![2, 0], ![-2, 0], ![0, -

solve covEstimationConvex nₚ Nₚ αₚ yₚ

#print covEstimationConvex.reduced
#print covEstimationConvex.conicForm
-- minimize
-- -(-(Nₚ • log (sqrt ((2 * π) ^ nₚ)) + Nₚ • (-Vec.sum t.0 / 2)) +
-- -(↑Nₚ * trace ((covarianceMatrix fun i => yₚ i) * Rᵀ) / 2))
Expand Down
4 changes: 2 additions & 2 deletions CvxLean/Examples/FittingSphere.lean
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ instance : ChangeOfVariables fun ((c, t) : (Fin n → ℝ) × ℝ) => (c, sqrt (
condition := fun (_, r) => 0 ≤ r,
property := fun ⟨c, r⟩ h => by simp [sqrt_sq h] }

equivalence' eqv/fittingSphereT (n m : ℕ) (x : Fin m → Fin n → ℝ) : fittingSphere n m x := by
equivalence* eqv/fittingSphereT (n m : ℕ) (x : Fin m → Fin n → ℝ) : fittingSphere n m x := by
-- Change of variables.
equivalence_step =>
apply ChangeOfVariables.toEquivalence
Expand All @@ -106,7 +106,7 @@ equivalence' eqv/fittingSphereT (n m : ℕ) (x : Fin m → Fin n → ℝ) : fitt
dsimp at h₁ ⊢; simp [Vec.sum, Vec.norm, Vec.const]; congr; funext i; congr 1;
rw [norm_sub_sq (𝕜 := ℝ) (E := Fin n → ℝ), sq_sqrt (rpow_two _ ▸ le_of_lt (sqrt_pos.mp h₁))]
simp [mulVec, inner, dotProduct]

#print fittingSphereT
-- optimization (c : Fin n → ℝ) (t : ℝ)
-- minimize Vec.sum ((Vec.norm x ^ 2 - 2 * mulVec x c - Vec.const m t) ^ 2)
Expand Down
8 changes: 4 additions & 4 deletions CvxLean/Examples/HypersonicShapeDesign.lean
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def hypersonicShapeDesign :=
h₂ : Δx ≤ 1
h₃ : a * (1 / Δx) - (1 - b) * sqrt (1 - Δx ^ 2) ≤ 0

equivalence' eqv₁/hypersonicShapeDesignConvex (a b : ℝ) (ha : 0 ≤ a) (hb₁ : 0 ≤ b) (hb₂ : b < 1) :
equivalence* eqv₁/hypersonicShapeDesignConvex (a b : ℝ) (ha : 0 ≤ a) (hb₁ : 0 ≤ b) (hb₂ : b < 1) :
hypersonicShapeDesign a b := by
pre_dcp

Expand Down Expand Up @@ -61,7 +61,7 @@ lemma one_sub_bₚ_nonneg : 0 ≤ 1 - bₚ := by

time_cmd solve hypersonicShapeDesignConvex aₚ bₚ aₚ_nonneg bₚ_nonneg bₚ_lt_one

#print hypersonicShapeDesignConvex.reduced
#print hypersonicShapeDesignConvex.conicForm

-- Final width of wedge.
def wₚ_opt := eqv₁.backward_map aₚ.float bₚ.float hypersonicShapeDesignConvex.solution
Expand All @@ -84,7 +84,7 @@ def ldRatioₚ := 1 / (Float.sqrt ((1 / wₚ_opt ^ 2) - 1))
-- While the above is good enough, we simplify the problem further by performing a change of
-- variables and simplifying appropriately.

equivalence' eqv₂/hypersonicShapeDesignSimpler (a b : ℝ) (ha : 0 ≤ a) (hb₁ : 0 ≤ b)
equivalence* eqv₂/hypersonicShapeDesignSimpler (a b : ℝ) (ha : 0 ≤ a) (hb₁ : 0 ≤ b)
(hb₂ : b < 1) : hypersonicShapeDesignConvex a b ha hb₁ hb₂ := by
change_of_variables (z) (Δx ↦ sqrt z)
conv_constr h₁ =>
Expand Down Expand Up @@ -116,7 +116,7 @@ equivalence' eqv₂/hypersonicShapeDesignSimpler (a b : ℝ) (ha : 0 ≤ a) (hb

time_cmd solve hypersonicShapeDesignSimpler aₚ bₚ aₚ_nonneg bₚ_nonneg bₚ_lt_one

#print hypersonicShapeDesignSimpler.reduced
#print hypersonicShapeDesignSimpler.conicForm

-- Final width of wedge.
def wₚ'_opt :=
Expand Down
4 changes: 2 additions & 2 deletions CvxLean/Examples/TrussDesign.lean
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ instance : ChangeOfVariables
simp; rw [mul_comm _ (R ^ 2 - r ^ 2), ← mul_div, div_self (by positivity), mul_one]
ring_nf; exact sqrt_sq hR }

equivalence' eqv₁/trussDesignGP (hmin hmax wmin wmax Rmax σ F₁ F₂ : ℝ) :
equivalence* eqv₁/trussDesignGP (hmin hmax wmin wmax Rmax σ F₁ F₂ : ℝ) :
trussDesign hmin hmax wmin wmax Rmax σ F₁ F₂ := by
-- Apply key change of variables.
equivalence_step =>
Expand Down Expand Up @@ -114,7 +114,7 @@ instance : ChangeOfVariables
property := fun (h', w', r', A') ⟨hh', hw', hr', hA'⟩ => by
simp [exp_log hh', exp_log hw', exp_log hr', exp_log hA'] }

equivalence' eqv₂/trussDesignConvex (hmin hmax : ℝ) (hmin_pos : 0 < hmin)
equivalence* eqv₂/trussDesignConvex (hmin hmax : ℝ) (hmin_pos : 0 < hmin)
(hmin_le_hmax : hmin ≤ hmax) (wmin wmax : ℝ) (wmin_pos : 0 < wmin) (wmin_le_wmax : wmin ≤ wmax)
(Rmax σ F₁ F₂ : ℝ) : trussDesignGP hmin hmax wmin wmax Rmax σ F₁ F₂ := by
-- Change variables.
Expand Down
16 changes: 8 additions & 8 deletions CvxLean/Examples/VehicleSpeedScheduling.lean
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ private lemma fold_partial_sum [hn : Fact (0 < n)] (t : Fin n → ℝ) (i : Fin
. rfl
. linarith [hn.out]

equivalence' eqv₁/vehSpeedSchedConvex (n : ℕ) (d : Fin n → ℝ)
equivalence* eqv₁/vehSpeedSchedConvex (n : ℕ) (d : Fin n → ℝ)
(τmin τmax smin smax : Fin n → ℝ) (F : ℝ → ℝ) (h_n_pos : 0 < n) (h_d_pos : StrongLT 0 d)
(h_smin_pos : StrongLT 0 smin) : @vehSpeedSched n d τmin τmax smin smax F ⟨h_n_pos⟩ := by
replace h_d_pos : ∀ i, 0 < d i := fun i => h_d_pos i
replace h_smin_pos : ∀ i, 0 < smin i := fun i => h_smin_pos i
replace h_d_pos : ∀ i, 0 < d i := h_d_pos
replace h_smin_pos : ∀ i, 0 < smin i := h_smin_pos
haveI : Fact (0 < n) := ⟨h_n_pos⟩
-- Change variables `s ↦ d / t`.
-- TODO: This can be done by change of variables by detecting that the variable is a vector.
Expand Down Expand Up @@ -93,12 +93,12 @@ equivalence' eqv₁/vehSpeedSchedConvex (n : ℕ) (d : Fin n → ℝ)

-- The problem is technically in DCP form if `F` is DCP convex. The only issue is that we do not
-- have an atom for the perspective function, so the objective function
-- `Vec.sum (t * Vec.map F (d / t))` cannot be reduced directly.
-- `Vec.sum (t * Vec.map F (d / t))` cannot be canonized directly.

-- However, if we fix `F`, we can use other atoms. For example, if `F` is quadratic, the problem can
-- be reduced. Let `F(s) = a * s^2 + b * s + c` with `0 ≤ a`.
-- be canonized. Let `F(s) = a * s^2 + b * s + c` with `0 ≤ a`.

equivalence' eqv₂/vehSpeedSchedQuadratic (n : ℕ) (d : Fin n → ℝ)
equivalence* eqv₂/vehSpeedSchedQuadratic (n : ℕ) (d : Fin n → ℝ)
(τmin τmax smin smax : Fin n → ℝ) (a b c : ℝ) (h_n_pos : 0 < n) (h_d_pos : StrongLT 0 d)
(h_smin_pos : StrongLT 0 smin) :
vehSpeedSchedConvex n d τmin τmax smin smax (fun s => a • s ^ (2 : ℝ) + b • s + c)
Expand Down Expand Up @@ -165,7 +165,7 @@ def τminₚ : Fin nₚ → ℝ :=
def τmaxₚ : Fin nₚ → ℝ :=
![4.6528, 6.5147, 7.5178, 9.7478, 9.0641, 10.3891, 13.1540, 16.0878, 17.4352, 20.9539]

@[optimization_param]
@[optimization_param, reducible]
def sminₚ : Fin nₚ → ℝ :=
![0.7828, 0.6235, 0.7155, 0.5340, 0.6329, 0.4259, 0.7798, 0.9604, 0.7298, 0.8405]

Expand All @@ -174,7 +174,7 @@ def smaxₚ : Fin nₚ → ℝ :=
![1.9624, 1.6036, 1.6439, 1.5641, 1.7194, 1.9090, 1.3193, 1.3366, 1.9470, 2.8803]

lemma sminₚ_pos : StrongLT 0 sminₚ := by
intro i; fin_cases i <;> (simp [sminₚ]; norm_num)
intro i; fin_cases i <;> norm_num

@[simp]
lemma sminₚ_nonneg : 0 ≤ sminₚ := le_of_strongLT sminₚ_pos
Expand Down
3 changes: 3 additions & 0 deletions CvxLean/Meta/Equivalence.lean
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ open Parser Elab Tactic
elab "equivalence_step" _arr:darrow tac:tacticSeqIndentGt : tactic => do
evalTactic <| ← `(tactic| equivalence_trans)
evalTacticSeq1Indented tac.raw
if (← getGoals).length > 1 then
evalTactic <| ← `(tactic| try { equivalence_rfl })
(← getMainGoal).setTag Name.anonymous

end BasicTactics

Expand Down
3 changes: 3 additions & 0 deletions CvxLean/Meta/Reduction.lean
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ open Parser Elab Tactic
elab "reduction_step" _arr:darrow tac:tacticSeqIndentGt : tactic => do
evalTactic <| ← `(tactic| reduction_trans)
evalTacticSeq1Indented tac.raw
if (← getGoals).length > 1 then
evalTactic <| ← `(tactic| try { reduction_rfl })
(← getMainGoal).setTag Name.anonymous

end Meta

Expand Down
3 changes: 3 additions & 0 deletions CvxLean/Meta/Relaxation.lean
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ open Parser Elab Tactic
elab "relaxation_step" _arr:darrow tac:tacticSeqIndentGt : tactic => do
evalTactic <| ← `(tactic| relaxation_trans)
evalTacticSeq1Indented tac.raw
if (← getGoals).length > 1 then
evalTactic <| ← `(tactic| try { relaxation_rfl })
(← getMainGoal).setTag Name.anonymous

end Meta

Expand Down
Loading
Loading