├── .gitignore ├── Misc ├── Supplementary Information.zip ├── SDP_relaxation_from_QCQP.jl ├── zetaeta.jl └── stpszs.jl ├── README.md ├── 2_Acceleration_without_momentum ├── code_to_compute_pivoted_cholesky.jl ├── test_code.jl └── BnB_PEP_reducing_function_value_AWM.jl ├── 3_Gradient_reduction_in_smooth_nonconvex_problems ├── code_to_compute_pivoted_cholesky.jl └── test_code.jl ├── 4_Potential_function_optimizing_in_weakly_convex_problems ├── code_to_compute_pivoted_cholesky.jl └── test_code.jl └── 1_Gradient_reduction_in_strongly_convex_smooth_problems ├── code_to_compute_pivoted_cholesky.jl └── test_code.jl /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /Misc/Supplementary Information.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shuvomoy/BnB-PEP-code/HEAD/Misc/Supplementary Information.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BnB-PEP 2 | 3 | This code can be used to reproduce and verify the results from the paper 4 | 5 | > [Shuvomoy Das Gupta, Bart P.G. Van Parys, Ernest K. Ryu, "Branch-and-Bound Performance Estimation Programming: A Unified Methodology for Constructing Optimal Optimization Methods", Mathematical Programming 204.1 (2024): 567-639.](https://link.springer.com/article/10.1007/s10107-023-01973-1) 6 | 7 | A preprint of the work is available on arXiv [here](https://arxiv.org/abs/2203.07305). 8 | 9 | If you find the code helpful in you project, we kindly request that you cite the following paper: 10 | 11 | ``` 12 | @article{dasgupta2022BnBPEP, 13 | title={Branch-and-bound performance estimation programming: A unified methodology for constructing optimal optimization methods}, 14 | author={Das Gupta, Shuvomoy and Van Parys, Bart PG and Ryu, Ernest K}, 15 | journal={Mathematical Programming}, 16 | volume={204}, 17 | number={1}, 18 | pages={567--639}, 19 | year={2024}, 20 | publisher={Springer} 21 | } 22 | ``` 23 | 24 | **Please use Gurobi 12.0 or later.** Please use `Gurobi 12.0` or later when implementing stage 3 of the BnB-PEP algorithm: several issues in the spatial branch-and-bound algorithm in `Gurobi 10.0` that cause numerical instabilities have recently been fixed; see the list of bug fixes [here](https://docs.gurobi.com/projects/optimizer/en/12.0/reference/releasenotes/fixedbugs.html) and [here](https://docs.gurobi.com/projects/optimizer/en/11.0/reference/releasenotes/fixedbugs.html). 25 | 26 | ## Reporting issues 27 | 28 | Please report any issues via the [Github issue tracker](https://github.com/Shuvomoy/BnB-PEP-code/issues). All types of issues are welcome including bug reports, feature requests, and so on. 29 | 30 | ## Contact 31 | Please feel free to send an email :email: to [sd158@rice.edu](sd158@rice.edu) regarding any subject including but not limited to comments about this paper, performance estimation problems in general, implementation for a specific research problem, or just to say hi 😃! -------------------------------------------------------------------------------- /2_Acceleration_without_momentum/code_to_compute_pivoted_cholesky.jl: -------------------------------------------------------------------------------- 1 | ## code to compute projection onto a psd cone 2 | 3 | # The following part is taken from ProximalOperators.jl 4 | 5 | # ProximalOperators.jl code start 6 | 7 | const RealOrComplex{R <: Real} = Union{R, Complex{R}} 8 | const HermOrSym{T, S} = Union{Hermitian{T, S}, Symmetric{T, S}} 9 | 10 | abstract type ProximableFunction end 11 | 12 | 13 | struct IndPSD <: ProximableFunction 14 | scaling::Bool 15 | end 16 | 17 | IndPSD(; scaling=false) = IndPSD(scaling) 18 | 19 | function (f::IndPSD)(X::HermOrSym{T}) where {R <: Real, T <: RealOrComplex{R}} 20 | F = eigen(X) 21 | for i in eachindex(F.values) 22 | # Do we allow for some tolerance here? 23 | if F.values[i] <= -100 * eps(R) 24 | return R(Inf) 25 | end 26 | end 27 | return R(0) 28 | end 29 | 30 | 31 | function (f::IndPSD)(X::AbstractMatrix{R}) where R <: Real 32 | f(Symmetric(X)) 33 | end 34 | 35 | function (f::IndPSD)(X::AbstractMatrix{C}) where C <: Complex 36 | f(Hermitian(X)) 37 | end 38 | 39 | is_convex(f::IndPSD) = true 40 | is_cone(f::IndPSD) = true 41 | 42 | fun_name(f::IndPSD) = "indicator of positive semidefinite cone" 43 | fun_dom(f::IndPSD) = "Symmetric, Hermitian, AbstractArray{Float64}" 44 | fun_expr(f::IndPSD) = "x ↦ 0 if A ⪰ 0, +∞ otherwise" 45 | fun_params(f::IndPSD) = "none" 46 | 47 | function projection_on_psdcone!(Y, f::IndPSD, X; gamma=1.0, ϵ_min_pos_eig_val = 1e-10) 48 | n = size(X, 1) 49 | F = eigen(X) 50 | for i in eachindex(F.values) 51 | F.values[i] = max.(ϵ_min_pos_eig_val, F.values[i]) 52 | end 53 | for i = 1:n, j = i:n 54 | Y[i, j] = 0.0 55 | for k = 1:n 56 | Y[i, j] += F.vectors[i, k] * F.values[k] * conj(F.vectors[j, k]) 57 | end 58 | Y[j, i] = conj(Y[i, j]) 59 | end 60 | return 0.0 61 | end 62 | 63 | # ProximalOperators.jl code end 64 | 65 | ## function to compute the pivoted choleksy decomposition of a positive semidefinite matrix 66 | 67 | function compute_pivoted_cholesky_L_mat(A; ϵ_tol = 1e-4) 68 | # ensure that A is positive semidefinite 69 | Y = zeros(size(A)) 70 | n = size(A, 1) 71 | # Find the psd projection of A 72 | projection_on_psdcone!(Y, IndPSD(), A) 73 | if norm(Y-A) >= 1e-6 74 | @warn "the given matrix is not positive semidefinite (no need to panic if you are computing a lower bound)" 75 | end 76 | F = cholesky(Y; check=false) 77 | F_L_actual = F.L 78 | for i in 1:n 79 | for j in 1:n 80 | if i >= j 81 | if abs(F_L_actual[i,j]) <= ϵ_tol 82 | F_L_actual[i,j] = 0.0 83 | end 84 | end 85 | end 86 | end 87 | # F = cholesky(Y, Val(true); check=false) 88 | # F_L = F.L 89 | # F_P = F.P # permutation matrix 90 | # F_L_actual = F_P*F_L # because we have A = (F.P*F.L)*(F.P*F.L)' 91 | # for i in 1:n 92 | # for j in 1:n 93 | # if i < j 94 | # F_L_actual[i,j] = 0.0 95 | # end 96 | # end 97 | # end 98 | return F_L_actual 99 | end 100 | -------------------------------------------------------------------------------- /3_Gradient_reduction_in_smooth_nonconvex_problems/code_to_compute_pivoted_cholesky.jl: -------------------------------------------------------------------------------- 1 | ## code to compute projection onto a psd cone 2 | 3 | # The following part is taken from ProximalOperators.jl 4 | 5 | # ProximalOperators.jl code start 6 | 7 | const RealOrComplex{R <: Real} = Union{R, Complex{R}} 8 | const HermOrSym{T, S} = Union{Hermitian{T, S}, Symmetric{T, S}} 9 | 10 | abstract type ProximableFunction end 11 | 12 | 13 | struct IndPSD <: ProximableFunction 14 | scaling::Bool 15 | end 16 | 17 | IndPSD(; scaling=false) = IndPSD(scaling) 18 | 19 | function (f::IndPSD)(X::HermOrSym{T}) where {R <: Real, T <: RealOrComplex{R}} 20 | F = eigen(X) 21 | for i in eachindex(F.values) 22 | # Do we allow for some tolerance here? 23 | if F.values[i] <= -100 * eps(R) 24 | return R(Inf) 25 | end 26 | end 27 | return R(0) 28 | end 29 | 30 | 31 | function (f::IndPSD)(X::AbstractMatrix{R}) where R <: Real 32 | f(Symmetric(X)) 33 | end 34 | 35 | function (f::IndPSD)(X::AbstractMatrix{C}) where C <: Complex 36 | f(Hermitian(X)) 37 | end 38 | 39 | is_convex(f::IndPSD) = true 40 | is_cone(f::IndPSD) = true 41 | 42 | fun_name(f::IndPSD) = "indicator of positive semidefinite cone" 43 | fun_dom(f::IndPSD) = "Symmetric, Hermitian, AbstractArray{Float64}" 44 | fun_expr(f::IndPSD) = "x ↦ 0 if A ⪰ 0, +∞ otherwise" 45 | fun_params(f::IndPSD) = "none" 46 | 47 | function projection_on_psdcone!(Y, f::IndPSD, X; gamma=1.0, ϵ_min_pos_eig_val = 1e-10) 48 | n = size(X, 1) 49 | F = eigen(X) 50 | for i in eachindex(F.values) 51 | F.values[i] = max.(ϵ_min_pos_eig_val, F.values[i]) 52 | end 53 | for i = 1:n, j = i:n 54 | Y[i, j] = 0.0 55 | for k = 1:n 56 | Y[i, j] += F.vectors[i, k] * F.values[k] * conj(F.vectors[j, k]) 57 | end 58 | Y[j, i] = conj(Y[i, j]) 59 | end 60 | return 0.0 61 | end 62 | 63 | # ProximalOperators.jl code end 64 | 65 | ## function to compute the pivoted choleksy decomposition of a positive semidefinite matrix 66 | 67 | function compute_pivoted_cholesky_L_mat(A; ϵ_tol = 1e-4) 68 | # ensure that A is positive semidefinite 69 | Y = zeros(size(A)) 70 | n = size(A, 1) 71 | # Find the psd projection of A 72 | projection_on_psdcone!(Y, IndPSD(), A) 73 | if norm(Y-A) >= 1e-6 74 | @warn "the given matrix is not positive semidefinite (no need to panic if you are computing a lower bound)" 75 | end 76 | F = cholesky(Y; check=false) 77 | F_L_actual = F.L 78 | for i in 1:n 79 | for j in 1:n 80 | if i >= j 81 | if abs(F_L_actual[i,j]) <= ϵ_tol 82 | F_L_actual[i,j] = 0.0 83 | end 84 | end 85 | end 86 | end 87 | # F = cholesky(Y, Val(true); check=false) 88 | # F_L = F.L 89 | # F_P = F.P # permutation matrix 90 | # F_L_actual = F_P*F_L # because we have A = (F.P*F.L)*(F.P*F.L)' 91 | # for i in 1:n 92 | # for j in 1:n 93 | # if i < j 94 | # F_L_actual[i,j] = 0.0 95 | # end 96 | # end 97 | # end 98 | return F_L_actual 99 | end 100 | -------------------------------------------------------------------------------- /4_Potential_function_optimizing_in_weakly_convex_problems/code_to_compute_pivoted_cholesky.jl: -------------------------------------------------------------------------------- 1 | ## code to compute projection onto a psd cone 2 | 3 | # The following part is taken from ProximalOperators.jl 4 | 5 | # ProximalOperators.jl code start 6 | 7 | const RealOrComplex{R <: Real} = Union{R, Complex{R}} 8 | const HermOrSym{T, S} = Union{Hermitian{T, S}, Symmetric{T, S}} 9 | 10 | abstract type ProximableFunction end 11 | 12 | 13 | struct IndPSD <: ProximableFunction 14 | scaling::Bool 15 | end 16 | 17 | IndPSD(; scaling=false) = IndPSD(scaling) 18 | 19 | function (f::IndPSD)(X::HermOrSym{T}) where {R <: Real, T <: RealOrComplex{R}} 20 | F = eigen(X) 21 | for i in eachindex(F.values) 22 | # Do we allow for some tolerance here? 23 | if F.values[i] <= -100 * eps(R) 24 | return R(Inf) 25 | end 26 | end 27 | return R(0) 28 | end 29 | 30 | 31 | function (f::IndPSD)(X::AbstractMatrix{R}) where R <: Real 32 | f(Symmetric(X)) 33 | end 34 | 35 | function (f::IndPSD)(X::AbstractMatrix{C}) where C <: Complex 36 | f(Hermitian(X)) 37 | end 38 | 39 | is_convex(f::IndPSD) = true 40 | is_cone(f::IndPSD) = true 41 | 42 | fun_name(f::IndPSD) = "indicator of positive semidefinite cone" 43 | fun_dom(f::IndPSD) = "Symmetric, Hermitian, AbstractArray{Float64}" 44 | fun_expr(f::IndPSD) = "x ↦ 0 if A ⪰ 0, +∞ otherwise" 45 | fun_params(f::IndPSD) = "none" 46 | 47 | function projection_on_psdcone!(Y, f::IndPSD, X; gamma=1.0, ϵ_min_pos_eig_val = 1e-10) 48 | n = size(X, 1) 49 | F = eigen(X) 50 | for i in eachindex(F.values) 51 | F.values[i] = max.(ϵ_min_pos_eig_val, F.values[i]) 52 | end 53 | for i = 1:n, j = i:n 54 | Y[i, j] = 0.0 55 | for k = 1:n 56 | Y[i, j] += F.vectors[i, k] * F.values[k] * conj(F.vectors[j, k]) 57 | end 58 | Y[j, i] = conj(Y[i, j]) 59 | end 60 | return 0.0 61 | end 62 | 63 | # ProximalOperators.jl code end 64 | 65 | ## function to compute the pivoted choleksy decomposition of a positive semidefinite matrix 66 | 67 | function compute_pivoted_cholesky_L_mat(A; ϵ_tol = 1e-4) 68 | # ensure that A is positive semidefinite 69 | Y = zeros(size(A)) 70 | n = size(A, 1) 71 | # Find the psd projection of A 72 | projection_on_psdcone!(Y, IndPSD(), A) 73 | if norm(Y-A) >= 1e-6 74 | @warn "the given matrix is not positive semidefinite (no need to panic if you are computing a lower bound)" 75 | end 76 | F = cholesky(Y; check=false) 77 | F_L_actual = F.L 78 | for i in 1:n 79 | for j in 1:n 80 | if i >= j 81 | if abs(F_L_actual[i,j]) <= ϵ_tol 82 | F_L_actual[i,j] = 0.0 83 | end 84 | end 85 | end 86 | end 87 | # F = cholesky(Y, Val(true); check=false) 88 | # F_L = F.L 89 | # F_P = F.P # permutation matrix 90 | # F_L_actual = F_P*F_L # because we have A = (F.P*F.L)*(F.P*F.L)' 91 | # for i in 1:n 92 | # for j in 1:n 93 | # if i < j 94 | # F_L_actual[i,j] = 0.0 95 | # end 96 | # end 97 | # end 98 | return F_L_actual 99 | end 100 | -------------------------------------------------------------------------------- /1_Gradient_reduction_in_strongly_convex_smooth_problems/code_to_compute_pivoted_cholesky.jl: -------------------------------------------------------------------------------- 1 | ## code to compute projection onto a psd cone 2 | 3 | # The following part is taken from ProximalOperators.jl 4 | 5 | # ProximalOperators.jl code start 6 | 7 | const RealOrComplex{R <: Real} = Union{R, Complex{R}} 8 | const HermOrSym{T, S} = Union{Hermitian{T, S}, Symmetric{T, S}} 9 | 10 | abstract type ProximableFunction end 11 | 12 | 13 | struct IndPSD <: ProximableFunction 14 | scaling::Bool 15 | end 16 | 17 | IndPSD(; scaling=false) = IndPSD(scaling) 18 | 19 | function (f::IndPSD)(X::HermOrSym{T}) where {R <: Real, T <: RealOrComplex{R}} 20 | F = eigen(X) 21 | for i in eachindex(F.values) 22 | # Do we allow for some tolerance here? 23 | if F.values[i] <= -100 * eps(R) 24 | return R(Inf) 25 | end 26 | end 27 | return R(0) 28 | end 29 | 30 | 31 | function (f::IndPSD)(X::AbstractMatrix{R}) where R <: Real 32 | f(Symmetric(X)) 33 | end 34 | 35 | function (f::IndPSD)(X::AbstractMatrix{C}) where C <: Complex 36 | f(Hermitian(X)) 37 | end 38 | 39 | is_convex(f::IndPSD) = true 40 | is_cone(f::IndPSD) = true 41 | 42 | fun_name(f::IndPSD) = "indicator of positive semidefinite cone" 43 | fun_dom(f::IndPSD) = "Symmetric, Hermitian, AbstractArray{Float64}" 44 | fun_expr(f::IndPSD) = "x ↦ 0 if A ⪰ 0, +∞ otherwise" 45 | fun_params(f::IndPSD) = "none" 46 | 47 | function projection_on_psdcone!(Y, f::IndPSD, X; gamma=1.0, ϵ_min_pos_eig_val = 1e-10) 48 | n = size(X, 1) 49 | F = eigen(X) 50 | for i in eachindex(F.values) 51 | F.values[i] = max.(ϵ_min_pos_eig_val, F.values[i]) 52 | end 53 | for i = 1:n, j = i:n 54 | Y[i, j] = 0.0 55 | for k = 1:n 56 | Y[i, j] += F.vectors[i, k] * F.values[k] * conj(F.vectors[j, k]) 57 | end 58 | Y[j, i] = conj(Y[i, j]) 59 | end 60 | return 0.0 61 | end 62 | 63 | # ProximalOperators.jl code end 64 | 65 | ## function to compute the pivoted choleksy decomposition of a positive semidefinite matrix 66 | 67 | function compute_pivoted_cholesky_L_mat(A; ϵ_tol = 1e-4) 68 | # ensure that A is positive semidefinite 69 | Y = zeros(size(A)) 70 | n = size(A, 1) 71 | # Find the psd projection of A 72 | projection_on_psdcone!(Y, IndPSD(), A) 73 | if norm(Y-A) >= 1e-6 74 | @warn "the given matrix is not PSD given the tolerance (this warning does not matter if you are computing a lower bound, because we are not modelling the PSD-ness directly in that case)" 75 | end 76 | F = cholesky(Y; check=false) 77 | F_L_actual = F.L 78 | for i in 1:n 79 | for j in 1:n 80 | if i >= j 81 | if abs(F_L_actual[i,j]) <= ϵ_tol 82 | F_L_actual[i,j] = 0.0 83 | end 84 | end 85 | end 86 | end 87 | # F = cholesky(Y, Val(true); check=false) 88 | # F_L = F.L 89 | # F_P = F.P # permutation matrix 90 | # F_L_actual = F_P*F_L # because we have A = (F.P*F.L)*(F.P*F.L)' 91 | # for i in 1:n 92 | # for j in 1:n 93 | # if i < j 94 | # F_L_actual[i,j] = 0.0 95 | # end 96 | # end 97 | # end 98 | return F_L_actual 99 | end 100 | -------------------------------------------------------------------------------- /1_Gradient_reduction_in_strongly_convex_smooth_problems/test_code.jl: -------------------------------------------------------------------------------- 1 | ## Test code 2 | 3 | ## Load the code 4 | 5 | include("BnB-PEP-gradient-reduction-scvx-smooth.jl") 6 | 7 | 8 | ## Input parameters and feasible stepsize generation 9 | 10 | μ = 0.1 11 | L = 1 12 | N = 2 13 | R = 1 14 | default_obj_val_upper_bound = 1e6 15 | 16 | 17 | h_test, α_test = feasible_h_α_generator(N, μ, L; step_size_type = :Default) 18 | 19 | ## Solve primal with feasible stepsize 20 | 21 | p_feas_1, G_feas_1, Ft_feas_1 = solve_primal_with_known_stepsizes(N, μ, L, α_test, R; show_output = :on) 22 | 23 | # ------------------------------------------------------- 24 | ## Stage 1 of the BnB-PEP Algorithm: solve the dual for the warm-starting stepsize 25 | # ------------------------------------------------------- 26 | 27 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, μ, L, α_test, R; show_output = :off, 28 | ϵ_tol_feas = 1e-6, 29 | objective_type = :default, 30 | obj_val_upper_bound = default_obj_val_upper_bound) 31 | 32 | 33 | ## Compute bound based on SDP relaxation of the BnB-PEP, uncomment if you prefer this method (and comment the heuristic one) 34 | 35 | # M_λ, M_α, M_Z, M_L_cholesky, M_ν = bound_generator_through_SDP_relaxation(N, μ, L, R, ν_feas_1; show_output = :off, obj_val_upper_bound = d_feas_1) 36 | 37 | ## Compute bound based on heuristic method 38 | 39 | M_tilde = 50 40 | 41 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, μ, L, α_feas_1, R; show_output = :off, 42 | ϵ_tol_feas = 1e-6, 43 | objective_type = :find_M_λ, 44 | obj_val_upper_bound = 1.001*p_feas_1) 45 | 46 | M_λ =M_tilde*maximum(λ_feas_1) 47 | 48 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, μ, L, α_feas_1, R; show_output = :off, 49 | ϵ_tol_feas = 1e-6, 50 | objective_type = :find_M_Z, 51 | obj_val_upper_bound = 1.001*p_feas_1) 52 | 53 | M_Z = M_tilde*maximum(Z_feas_1[i,i] for i in 1:N+2) 54 | 55 | M_L_cholesky = sqrt(M_Z) 56 | 57 | M_α = (5*M_tilde)/L 58 | 59 | M_ν = ν_feas_1 60 | 61 | @show [M_λ M_α M_Z M_L_cholesky M_ν] 62 | 63 | ## Sparsify the solution 64 | 65 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, μ, L, α_feas_1, R; show_output = :off, 66 | ϵ_tol_feas = 1e-6, 67 | objective_type = :find_sparse_sol, 68 | obj_val_upper_bound = 1.001*p_feas_1) 69 | 70 | 71 | ## Store the warm start point for computing locally optimal solution 72 | 73 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective = d_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective 74 | 75 | 76 | # --------------------------------------------------- 77 | ## Stage 2 of the BnB-PEP Algorithm: compute the locally optimal point 78 | # ---------------------------------------------------- 79 | 80 | obj_val_loc_opt, λ_loc_opt, ν_loc_opt, Z_loc_opt, L_cholesky_loc_opt, α_loc_opt, idx_set_λ_loc_opt_effective = BnB_PEP_solver( 81 | # different parameters to be used 82 | # ------------------------------ 83 | N, μ, L, R, 84 | # solution to warm-start 85 | # ---------------------- 86 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective, 87 | # bounds on the variables 88 | # ---------------------- 89 | M_λ, M_α, M_Z, M_L_cholesky, M_ν; 90 | # options 91 | # ------- 92 | solution_type = :find_locally_optimal, # other option :find_globally_optimal 93 | show_output = :on, # other option :on 94 | local_solver = :ipopt, # other option :knitro 95 | reduce_index_set_for_λ = :for_warm_start_only, 96 | # options for reduce_index_set_for_λ 97 | # (i) :on (making it :on will make force λ[i,j] = 0, if (i,j) ∉ idx_set_λ_feas_effective, and will turn the BnB-PEP solver into a heuristic), 98 | # (ii) :off , this will define λ and warm-start over the full index set 99 | # (iii) :for_warm_start_only , this option is the same as the :off option, however in this case we will define λ over the full index set, but warm-start from a λ_ws that has reduced index set 100 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation 101 | quadratic_equality_modeling = :exact, 102 | cholesky_modeling = :definition, 103 | ϵ_tol_feas = 1e-6, # tolerance for feasibility 104 | polish_solution = :on # wheather to polish the solution to get better precision, the other option is :off 105 | ) 106 | 107 | ## Store the solution to be warm-started for a next step 108 | 109 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective = obj_val_loc_opt, λ_loc_opt, ν_loc_opt, Z_loc_opt, L_cholesky_loc_opt, α_loc_opt, idx_set_λ_loc_opt_effective 110 | 111 | ## Update the entries of the bounds 112 | 113 | # Based on the SDP relaxation of the BnB-PEP (uncomment if you prefer this method, and the comment the heuristic method below) 114 | # M_λ, M_α, M_Z, M_L_cholesky, M_ν = bound_generator_through_SDP_relaxation(N, μ, L, R, ν_ws; show_output = :off, obj_val_upper_bound = d_star_ws) 115 | 116 | 117 | # Bounds based on the heuristic 118 | 119 | M_tilde = 1.01 120 | 121 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, μ, L, α_ws, R; show_output = :off, 122 | ϵ_tol_feas = 1e-6, 123 | objective_type = :find_M_Z, 124 | obj_val_upper_bound = 1.001*d_star_ws) 125 | 126 | M_Z = M_tilde*maximum(Z_feas_1[i,i] for i in 1:N+2) 127 | 128 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, α_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, μ, L, α_ws, R; show_output = :off, 129 | ϵ_tol_feas = 1e-6, 130 | objective_type = :find_M_λ, 131 | obj_val_upper_bound = 1.001*d_star_ws) 132 | 133 | M_λ = M_tilde* maximum(λ_feas_1) 134 | 135 | M_L_cholesky = sqrt(M_Z) 136 | 137 | M_α = 5*M_tilde*maximum(abs.(α_loc_opt)) 138 | 139 | M_ν = ν_ws# ν_feas_1 140 | 141 | @show [M_λ M_α M_Z M_L_cholesky M_ν] 142 | 143 | 144 | ## Compute the global lower bound via the lazy callback procedure 145 | 146 | obj_val_glb_lbd, λ_glb_lbd, ν_glb_lbd, Z_glb_lbd, L_cholesky_glb_lbd, α_glb_lbd, idx_set_λ_glb_lbd_effective = BnB_PEP_solver( 147 | # different parameters to be used 148 | # ------------------------------- 149 | N, μ, L, R, 150 | # solution to warm-start 151 | # ---------------------- 152 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective, 153 | # bounds on the variables 154 | # ---------------------- 155 | M_λ, M_α, M_Z, M_L_cholesky, M_ν; 156 | # options 157 | # ------- 158 | solution_type = :find_globally_optimal, # other option :find_globally_optimal 159 | show_output = :on, # other option :on 160 | reduce_index_set_for_λ = :on, # :for_warm_start_only, 161 | # options for reduce_index_set_for_λ 162 | # (i) :on (making it :on will make force λ[i,j] = 0, if (i,j) ∉ idx_set_λ_feas_effective, and will turn the BnB-PEP solver into a heuristic), 163 | # (ii) :off , this will define λ and warm-start over the full index set 164 | # (iii) :for_warm_start_only , this option is the same as the :off option, however in this case we will define λ over the full index set, but warm-start from a λ_ws that has reduced index set 165 | positive_step_size = :off, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 166 | find_global_lower_bound_via_cholesky_lazy_constraint = :on, # if this on, then we model Z = L_cholesky*L_cholesky^T via lazy constraint (the goal is to find a lower bound to BnB PEP) 167 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation 168 | quadratic_equality_modeling = :exact, #:through_ϵ, 169 | cholesky_modeling = :definition, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 170 | ϵ_tol_feas = 1e-4, # tolerance for feasibility 171 | maxCutCount=1e6, # this is the number of cuts to be added if the lazy constraint callback is activated 172 | global_lower_bound_given = :off, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 173 | global_lower_bound = 0.0, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 174 | heuristic_solution_submit = :off, # other option is :on, turning it on means that at the node of the spatial branch and bound tree we will take a look at the relaxed solution and if it satisfies certain condition, we will submit a heuristic solution 175 | polish_solution = :on # wheather to polish the solution to get better precision, the other option is :off 176 | ) 177 | 178 | # ---------------------------------------------------- 179 | ## Stage 3 of the BnB-PEP Algorithm: find the globally optimal solution to the BnB-PEP-QCQP 180 | # ---------------------------------------------------- 181 | 182 | 183 | obj_val_glb_opt, λ_glb_opt, ν_glb_opt, Z_glb_opt, L_cholesky_glb_opt, α_glb_opt, idx_set_λ_glb_opt_effective = BnB_PEP_solver( 184 | # different parameters to be used 185 | # ------------------------------- 186 | N, μ, L, R, 187 | # solution to warm-start 188 | # ---------------------- 189 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective, 190 | # bounds on the variables 191 | # ---------------------- 192 | M_λ, M_α, M_Z, M_L_cholesky, M_ν; 193 | # options 194 | # ------- 195 | solution_type = :find_globally_optimal, #:find_locally_optimal, # other option :find_globally_optimal 196 | show_output = :on, # other option :on 197 | reduce_index_set_for_λ = :on, #:for_warm_start_only, #:on,#:for_warm_start_only, # other option :on (making it :on will make force λ[i,j] = 0, if (i,j) ∉ idx_set_λ_feas_effective, and will turn the BnB-PEP solver into a heuristic), 198 | reduce_index_set_for_L_cholesky = :on, #other option is :off, 199 | bound_impose = :on, # if this is :from_warm_start_sol, then from the warm_start solution we compute lower and upper bounds for the decision variables, 200 | quadratic_equality_modeling = :exact, #other option is :through_ϵ, 201 | cholesky_modeling = :formula, #other option is :definition, 202 | ϵ_tol_feas = 1e-4, # tolerance for cholesky feasibility 203 | global_lower_bound_given = :on, # wheather is a global lower bound is given, other option is :off 204 | global_lower_bound = obj_val_glb_lbd, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 205 | polish_solution = :on # wheather to polish the solution to get better precision, the other option is :off 206 | ) 207 | 208 | ## Optimal stepsize 209 | 210 | h_glb_opt = compute_h_from_α(α_glb_opt, N, μ, L) 211 | -------------------------------------------------------------------------------- /2_Acceleration_without_momentum/test_code.jl: -------------------------------------------------------------------------------- 1 | ## Test code 2 | 3 | ## Include the main Julia file 4 | 5 | include("BnB_PEP_reducing_function_value_AWM.jl") 6 | 7 | ## Parameters to use 8 | 9 | L = 1 10 | N = 2 11 | R = 1 12 | default_obj_val_upper_bound = 1e6 13 | 14 | ## Feasible stepsize generation 15 | 16 | h_test = feasible_h_generator(N, L; step_size_type = :Default) 17 | 18 | ## Solve primal with feasible stepsizes 19 | 20 | p_feas_1, G_feas_1, Ft_feas_1 = solve_primal_with_known_stepsizes(N, L, h_test, R; show_output = :on) 21 | 22 | ## ------------------------------------------------------- 23 | # Stage 1 of the BnB-PEP Algorithm: solve the dual for the warm-starting stepsize 24 | ## ------------------------------------------------------- 25 | 26 | 27 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_test, R; show_output = :off, 28 | ϵ_tol_feas = 1e-6, 29 | objective_type = :default, 30 | obj_val_upper_bound = default_obj_val_upper_bound) 31 | 32 | ## Computing the bounds for computing locally optimal solution to BnB-PEP 33 | 34 | ## Using SDP relaxation based bound, comment the block out if using heuristic based bound 35 | 36 | # M_λ, M_h, M_Z, M_L_cholesky, M_ν = bound_generator_through_SDP_relaxation(N, L, R, ν_feas_1; show_output = :off, obj_val_upper_bound = d_feas_1) 37 | 38 | 39 | ## Using Heuristic bound, comment the block out if using bound based on SDP relaxation 40 | # ------------------------------------------------------------------------- 41 | 42 | M_tilde = 50 43 | 44 | # Compute M_λ 45 | 46 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_feas_1, R; show_output = :off, 47 | ϵ_tol_feas = 1e-6, 48 | objective_type = :find_M_λ, 49 | obj_val_upper_bound = 1.001*p_feas_1) 50 | 51 | M_λ = M_tilde*maximum(λ_feas_1) 52 | 53 | # Compute M_Z 54 | 55 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_feas_1, R; show_output = :off, 56 | ϵ_tol_feas = 1e-6, 57 | objective_type = :find_M_Z, 58 | obj_val_upper_bound = 1.001*p_feas_1) 59 | 60 | M_Z = M_tilde*maximum(Z_feas_1[i,i] for i in 1:N+2) 61 | 62 | # Compute M_L_cholesky 63 | 64 | M_L_cholesky = sqrt(M_Z) 65 | 66 | # Compute M_h 67 | 68 | M_h = (500*M_tilde)/L 69 | 70 | # Compute M_ν 71 | 72 | M_ν = ν_feas_1 73 | 74 | @show [M_λ M_h M_Z M_L_cholesky M_ν] 75 | 76 | ## Sparsify the solution for warm-starting locally optimal solver 77 | 78 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_feas_1, R; show_output = :off, 79 | ϵ_tol_feas = 1e-8, 80 | objective_type = :find_sparse_sol, 81 | obj_val_upper_bound = 1.001*p_feas_1) 82 | 83 | ## Store the warm start point for computing locally optimal solution 84 | 85 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, h_ws, idx_set_λ_ws_effective = d_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective 86 | 87 | # --------------------------------------------------- 88 | ## Stage 2 of the BnB-PEP Algorithm: compute the locally optimal point 89 | # ---------------------------------------------------- 90 | 91 | 92 | obj_val_loc_opt, λ_loc_opt, ν_loc_opt, Z_loc_opt, L_cholesky_loc_opt, h_loc_opt, idx_set_λ_loc_opt_effective = BnB_PEP_solver( 93 | # different parameters to be used 94 | # ------------------------------ 95 | N, L, R, 96 | # solution to warm-start 97 | # ---------------------- 98 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, h_ws, idx_set_λ_ws_effective, 99 | # bounds on the variables 100 | # ---------------------- 101 | M_λ, M_h, M_Z, M_L_cholesky, M_ν; 102 | # options 103 | # ------- 104 | solution_type = :find_locally_optimal, # other option :find_globally_optimal 105 | show_output = :on, # other option :on 106 | local_solver = :knitro, #:ipopt, # other option :knitro 107 | knitro_multistart = :off, 108 | knitro_multi_algorithm = :off, 109 | reduce_index_set_for_λ = :for_warm_start_only, 110 | # options for reduce_index_set_for_λ 111 | # (i) :on (making it :on will make force λ[i,j] = 0, if (i,j) ∉ idx_set_λ_feas_effective, and will turn the BnB-PEP solver into a heuristic), 112 | # (ii) :off , this will define λ and warm-start over the full index set 113 | # (iii) :for_warm_start_only , this option is the same as the :off option, however in this case we will define λ over the full index set, but warm-start from a λ_ws that has reduced index set 114 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation 115 | quadratic_equality_modeling = :exact, 116 | cholesky_modeling = :definition, 117 | ϵ_tol_feas = 1e-6, # tolerance for Cholesky decomposition, 118 | polish_solution = :off # wheather to polish the solution to get better precision, the other option is :off 119 | ) 120 | 121 | 122 | ## Values for the tables 123 | 124 | using LatexPrint 125 | 126 | @show round(obj_val_loc_opt, digits = 6) 127 | 128 | h_matlab_format = round.(OffsetArrays.no_offset_view(h_loc_opt),digits = 6) 129 | h_latex = lap(h_matlab_format) 130 | 131 | obj_val_loc_opt_refined, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_loc_opt, R; show_output = :on, 132 | ϵ_tol_feas = 1e-6, 133 | objective_type = :default, 134 | obj_val_upper_bound = default_obj_val_upper_bound) 135 | 136 | @show h_latex 137 | 138 | println(h_matlab_format) 139 | 140 | 141 | ## Store the solution to be warm-started for a next step 142 | 143 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, h_ws, idx_set_λ_ws_effective = obj_val_loc_opt, λ_loc_opt, ν_loc_opt, Z_loc_opt, L_cholesky_loc_opt, h_loc_opt, idx_set_λ_loc_opt_effective 144 | 145 | 146 | ## Update the variable bounds 147 | 148 | ## Update the variable bounds based on SDP relaxation, comment out the block if using heuristic based variable bound 149 | 150 | # M_λ, M_h, M_Z, M_P, M_ν = bound_generator_through_SDP_relaxation(N, L, R, ν_feas_1; show_output = :off, obj_val_upper_bound = d_star_ws) 151 | 152 | ## Update the variable bounds based on SDP relaxation, comment out the block if using SDP relaxation based bound 153 | 154 | M_tilde = 1.01 155 | 156 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_ws, R; show_output = :off, 157 | ϵ_tol_feas = 1e-6, 158 | objective_type = :find_M_Z, 159 | obj_val_upper_bound = 1.001*d_star_ws) 160 | 161 | M_Z = M_tilde*maximum(Z_feas_1[i,i] for i in 1:N+2) 162 | 163 | d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_ws, R; show_output = :off, 164 | ϵ_tol_feas = 1e-6, 165 | objective_type = :find_M_λ, 166 | obj_val_upper_bound = 1.001*d_star_ws) 167 | 168 | M_λ = M_tilde* maximum(λ_feas_1) 169 | 170 | M_L_cholesky = sqrt(M_Z) 171 | 172 | M_h = 5*M_tilde*maximum(abs.(h_loc_opt)) 173 | 174 | M_ν = ν_ws# ν_feas_1 175 | 176 | @show [M_λ M_h M_Z M_L_cholesky M_ν] 177 | 178 | ## Compute global lower bound via lazy callback 179 | 180 | obj_val_glb_lbd, λ_glb_lbd, ν_glb_lbd, Z_glb_lbd, L_cholesky_glb_lbd, h_glb_lbd, idx_set_λ_glb_lbd_effective = BnB_PEP_solver( 181 | # different parameters to be used 182 | # ------------------------------- 183 | N, L, R, 184 | # solution to warm-start 185 | # ---------------------- 186 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, h_ws, idx_set_λ_ws_effective, 187 | # bounds on the variables 188 | # ---------------------- 189 | M_λ, M_h, M_Z, M_L_cholesky, M_ν; 190 | # options 191 | # ------- 192 | solution_type = :find_globally_optimal, # other option :find_globally_optimal 193 | show_output = :on, # other option :on 194 | reduce_index_set_for_λ = :on, #:off, # :for_warm_start_only, 195 | # options for reduce_index_set_for_λ 196 | # (i) :on (making it :on will make force λ[i,j] = 0, if (i,j) ∉ idx_set_λ_feas_effective, and will turn the BnB-PEP solver into a heuristic), 197 | # (ii) :off , this will define λ and warm-start over the full index set 198 | # (iii) :for_warm_start_only , this option is the same as the :off option, however in this case we will define λ over the full index set, but warm-start from a λ_ws that has reduced index set 199 | positive_step_size = :off, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 200 | find_global_lower_bound_via_cholesky_lazy_constraint = :on, # if this on, then we model Z = L_cholesky*L_cholesky^T via lazy constraint (the goal is to find a lower bound to BnB PEP) 201 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation 202 | quadratic_equality_modeling = :exact, #:through_ϵ, 203 | cholesky_modeling = :definition, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 204 | ϵ_tol_feas = 1e-6, # tolerance for cholesky feasibility 205 | maxCutCount=1e6, # this is the number of cuts to be added if the lazy constraint callback is activated 206 | global_lower_bound_given = :off, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 207 | global_lower_bound = 0.0, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 208 | polish_solution = :on # wheather to polish the solution to get better precision, the other option is :off 209 | ) 210 | 211 | ## Time to compute the globally optimal solution 212 | 213 | obj_val_glb_opt, λ_glb_opt, ν_glb_opt, Z_glb_opt, L_cholesky_glb_opt, h_glb_opt, idx_set_λ_glb_opt_effective = BnB_PEP_solver( 214 | # different parameters to be used 215 | # ------------------------------- 216 | N, L, R, 217 | # solution to warm-start 218 | # ---------------------- 219 | d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, h_ws, idx_set_λ_ws_effective, 220 | # bounds on the variables 221 | # ---------------------- 222 | M_λ, M_h, M_Z, M_L_cholesky, M_ν; 223 | # options 224 | # ------- 225 | solution_type = :find_globally_optimal, #:find_locally_optimal, # other option :find_globally_optimal 226 | show_output = :on, # other option :on 227 | reduce_index_set_for_λ = :on, # other option :on (making it :on will make force λ[i,j] = 0, if (i,j) ∉ idx_set_λ_feas_effective, and will turn the BnB-PEP solver into a heuristic), 228 | reduce_index_set_for_L_cholesky = :on, #other option is :on, 229 | bound_impose = :on, # if this is :from_warm_start_sol, then from the warm_start solution we compute lower and upper bounds for the decision variables, 230 | quadratic_equality_modeling = :exact, #:through_ϵ, 231 | cholesky_modeling = :definition, #:formula, #:definition, 232 | ϵ_tol_feas = 1e-6, # tolerance for cholesky feasibility 233 | global_lower_bound_given = :on, # wheather is a global lower bound is given 234 | global_lower_bound = obj_val_glb_lbd, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 235 | polish_solution = :off # wheather to polish the solution to get better precision, the other option is :off 236 | ) 237 | 238 | ## Print the globally optimal stepsize 239 | 240 | @show round(obj_val_glb_opt, digits = 6) 241 | 242 | 243 | h_matlab_format = round.(OffsetArrays.no_offset_view(h_glb_opt),digits = 6) 244 | h_glb_opt_latex = lap(h_matlab_format) 245 | 246 | @show h_glb_opt_latex 247 | -------------------------------------------------------------------------------- /Misc/SDP_relaxation_from_QCQP.jl: -------------------------------------------------------------------------------- 1 | # Automated SDP relaxation of QCQPs in JuMP+Julia 2 | 3 | # Here, we show how to construct automatic SDP relaxation of a nonconvex QCQP in `Julia+JuMP` 4 | # The code was written based on the tips from Benoît Legat (https://blegat.github.io/) 5 | 6 | ## Example QCQP 7 | 8 | # Consider the following QCQP as an example: 9 | # $$ 10 | # p^{\star}=\left(\begin{array}{ll} 11 | # \textrm{minimize} & c_{1}^{\top}x+c_{2}^{\top}y+c_{3}\mathbf{tr}(Z)\\ 12 | # \textrm{subject to} & a_{1}xy^{\top}+A_{1}\left(\begin{bmatrix}x\\ 13 | # y 14 | # \end{bmatrix}\right)=Z,\\ 15 | # & xy^{\top}+A_{2}\left(\begin{bmatrix}x\\ 16 | # y 17 | # \end{bmatrix}\right)\leq0,\\ 18 | # & Z=PP^{\top}, 19 | # \end{array}\right)\quad(1) 20 | # $$ 21 | # where the decision variables are: $x,y\in\mathbf{R}^{2},\; P,Z\in\mathbf{S}^{2}$. We have the bound information that the optimal value lies between $[-400,-200]$. Here $A_1, A_2$ are linear operators from $\mathbf{R}^4$ to $\mathbf{S}^2$. First, let us solve the problem to global optimality using `Gurobi+JuMP`. 22 | 23 | 24 | # Load the packages 25 | using JuMP, Gurobi, MosekTools, Mosek, LinearAlgebra, DiffOpt 26 | 27 | # Problem data: 28 | c_1 = [-3; -5] 29 | c_2 = [2; -5] 30 | c_3 = -1 31 | a_1 = 4 32 | A_1_op(x,y) = [3*x[1]+2*y[2] -x[2]+y[1]; -x[2]+y[1] -4*x[2]+y[2]] 33 | A_2_op(x,y) = [2*x[1]-5*y[2] -3*x[2]+2*y[1]; -3*x[2]+2*y[1] 4*x[2]-7*y[2]] 34 | x_lb = 0 35 | x_ub = 5 36 | y_lb = 0 37 | y_ub = 10 38 | 39 | ## Solving the QCQP to global optimality 40 | 41 | function QCQP_solver(c_1, c_2, c_3, a_1, x_lb, x_ub, y_lb, y_ub) 42 | 43 | nonlinear_model = Model(Gurobi.Optimizer) 44 | 45 | set_optimizer_attribute(nonlinear_model, "NonConvex", 2) 46 | 47 | @variable(nonlinear_model, x_lb <= x[1:2] <= x_ub) 48 | 49 | @variable(nonlinear_model, y_lb <= y[1:2] <= y_ub) 50 | 51 | @variable(nonlinear_model, Z[1:2, 1:2], Symmetric) 52 | 53 | @variable(nonlinear_model, P[1:2, 1:2]) 54 | 55 | @objective( nonlinear_model, Min, c_1'*x + c_2'*y + c_3*tr(Z) ) 56 | 57 | con_shape = SymmetricMatrixShape(2) 58 | 59 | QuadCon1 = @constraint(nonlinear_model, vectorize(a_1*x*transpose(y) + A_1_op(x,y) - Z, con_shape) .== 0 ) 60 | 61 | QuadCon2 = @constraint(nonlinear_model, vectorize(x*transpose(y) + A_2_op(x,y), con_shape) .<= 0 ) 62 | 63 | SDPCon3 = @constraint(nonlinear_model, vectorize(Z - P*P', con_shape) .== 0 ) 64 | 65 | @constraint(nonlinear_model, c_1'*x + c_2'*y + c_3*tr(Z) >= -400 ) 66 | 67 | @constraint(nonlinear_model, c_1'*x + c_2'*y + c_3*tr(Z) <= -200 ) 68 | 69 | optimize!(nonlinear_model) 70 | 71 | p_star = objective_value(nonlinear_model) 72 | 73 | x_star = value.(x) 74 | 75 | y_star = value.(y) 76 | 77 | Z_star = value.(Z) 78 | 79 | @show x_star 80 | 81 | @show y_star 82 | 83 | @show Z_star 84 | 85 | @show p_star 86 | 87 | return x_star, y_star, Z_star, p_star 88 | 89 | end 90 | 91 | 92 | 93 | # Let us run the function. 94 | 95 | 96 | # x_star, y_star, Z_star, p_star = QCQP_solver(c_1, c_2, c_3, a_1, x_lb, x_ub, y_lb, y_ub) 97 | 98 | 99 | ## Extracting the data to construct SDP relaxation 100 | 101 | # We have three quadratic constraint arrays in (1). The third one is just $Z\succeq0$, so we can just model that. For the first and second, we want to convert them into standard form quadratic constraints. 102 | 103 | # Defining $w=\textrm{vec}(x,y)$ we want to write the first quadratic constraint 104 | # $$ 105 | # a_{1}xy^{\top}+A_{1}\left(\begin{bmatrix}x\\ 106 | # y 107 | # \end{bmatrix}\right)=Z 108 | # $$ 109 | # as 110 | # $$ 111 | # w^{\top}P_{1}^{(k,\ell)}w+q_{1}^{(k,\ell)\top}w+r_{1}^{(k,\ell)}=Z_{k,\ell}\quad k\in[1:2],\;\ell\in[1:k], 112 | # $$ 113 | 114 | # and we want to write the second quadratic constraint 115 | # $$ 116 | # xy^{\top}+A_{2}\left(\begin{bmatrix}x\\ 117 | # y 118 | # \end{bmatrix}\right) \leq 0 119 | # $$ 120 | # as 121 | # $$ 122 | # w^{\top}P_{2}^{(k,\ell)}w+q_{2}^{(k,\ell)\top}w+r_{2}^{(k,\ell)} \leq 0, \quad k\in[1:2],\;\ell\in[1:k], 123 | # $$ 124 | # where $P_{i}^{(k,\ell)},q_{i}^{(k,\ell)},r_{i}^{(k,\ell)}$ are problemdata that we are going to extract from the original problem. 125 | 126 | # Let us create a `struct` that will help in providing the quadratic form data $P,q,r$. 127 | 128 | 129 | using DiffOpt 130 | 131 | struct Form 132 | P 133 | q 134 | r 135 | end 136 | 137 | using LinearAlgebra 138 | 139 | LinearAlgebra.symmetric_type(::Type{Form}) = Form 140 | LinearAlgebra.symmetric(f::Form, ::Symbol) = f 141 | LinearAlgebra.transpose(f::Form) = f 142 | 143 | 144 | # The following function creates the data to construct the SDP relaxation. 145 | 146 | 147 | function standard_form_data_constructor(c_1, c_2, c_3, a_1, x_lb, x_ub, y_lb, y_ub) 148 | 149 | data_model = Model() 150 | 151 | @variable(data_model, x_lb <= x[1:2] <= x_ub) 152 | 153 | @variable(data_model, y_lb <= y[1:2] <= y_ub) 154 | 155 | @variable(data_model, Z[1:2, 1:2], Symmetric) 156 | 157 | w = Vector{VariableRef}[] 158 | 159 | push!(w, x) 160 | 161 | push!(w, y) 162 | 163 | # create the vectorized w 164 | 165 | w_vec = reduce(vcat, w) 166 | 167 | # Add the qcqp constraints that we want to take to standard form 168 | 169 | con_shape = SymmetricMatrixShape(2) 170 | 171 | QuadCon1 = @constraint(data_model, vectorize(a_1*x*transpose(y) + A_1_op(x,y) - Z, con_shape) .== 0 ) 172 | 173 | QuadCon2 = @constraint(data_model, vectorize(x*transpose(y) + A_2_op(x,y), con_shape) .<= 0 ) 174 | 175 | # create index map that will contain the indices of the original decision variables 176 | 177 | index_map = MOI.Utilities.IndexMap() 178 | 179 | for (i, var_ref) in enumerate(w_vec) 180 | index_map[JuMP.index(var_ref)] = MOI.VariableIndex(i) 181 | end 182 | 183 | n = length(index_map.var_map) 184 | 185 | remove = JuMP.index.(JuMP.vectorize(Z, con_shape)) # we have to ensure that we are not considering Z in w 186 | 187 | # The function `standard_form(con_ref::JuMP.ConstraintRef)` will take a `JuMP` quadratic function and convert it into a standard form quadratic constraint of the form $w^\top P w + q^\top w + r$ form. 188 | function standard_form_data(con_ref::JuMP.ConstraintRef) 189 | object = JuMP.constraint_object(con_ref) 190 | quad_func = JuMP.moi_function(object) 191 | quad_func = MOI.Utilities.substitute_variables(quad_func) do var 192 | F = MOI.ScalarAffineFunction{Float64} 193 | if var in remove 194 | return zero(F) 195 | else 196 | return convert(F, var) 197 | end 198 | end 199 | matrix = DiffOpt.sparse_array_representation(quad_func, n, index_map) 200 | r = matrix.constant - MOI.constant(JuMP.moi_set(object)) 201 | P, q = Matrix(0.5*matrix.quadratic_terms), Vector(matrix.affine_terms) 202 | # P, q = 0.5*matrix.quadratic_terms, matrix.affine_terms 203 | return Form(P, q, r) 204 | end 205 | 206 | QuadCon1StdTerms = JuMP.reshape_vector(standard_form_data.(QuadCon1), con_shape) 207 | # For example, 208 | # QuadCon1StdTerms[1,1].P will give us corresponding P 209 | # QuadCon1StdTerms[1,1].q will give us corresponding q 210 | # QuadCon1StdTerms[1,1].r will give us corresponding r 211 | 212 | # QuadCon2StdTerms = map(QuadCon2) do con_refs 213 | # JuMP.reshape_vector(standard_form_data.(QuadCon2), con_shape) 214 | # end 215 | 216 | QuadCon2StdTerms = JuMP.reshape_vector(standard_form_data.(QuadCon2), con_shape) 217 | 218 | return QuadCon1StdTerms, QuadCon2StdTerms 219 | 220 | end 221 | 222 | 223 | 224 | # Test the function. 225 | 226 | 227 | QuadCon1StdTerms, QuadCon2StdTerms = standard_form_data_constructor(c_1, c_2, c_3, a_1, x_lb, x_ub, y_lb, y_ub) 228 | 229 | # For example, 230 | # QuadCon1StdTerms[1,1].P will give us corresponding P 231 | # QuadCon1StdTerms[1,1].q will give us corresponding q 232 | # QuadCon1StdTerms[1,1].r will give us corresponding r 233 | 234 | 235 | ## SDP relaxation model 236 | 237 | # So, we have the following SDP relaxation of (2): 238 | # $$ 239 | # p_{\textrm{SDP}}^{\star}=\left(\begin{array}{ll} 240 | # \textrm{minimize} & c_{1}^{\top}x+c_{2}^{\top}y+c_{3}\mathbf{tr}(Z)\\ 241 | # \textrm{subject to} & \mathbf{tr}(P_{1}^{(k,\ell)}W)+q_{1}^{(k,\ell)\top}w+r_{1}^{(k,\ell)}=Z_{k,\ell},\quad k\in[1:2],\;\ell\in[1:k],\\ 242 | # & \mathbf{tr}(P_{2}^{(k,\ell)}W)+q_{2}^{(k,\ell)\top}w+r_{2}^{(k,\ell)}\leq0,\quad k\in[1:2],\;\ell\in[1:k],\\ 243 | # & Z\succeq0,\\ 244 | # & \begin{bmatrix}W & w\\ 245 | # w^{\top} & 1 246 | # \end{bmatrix}\succeq0,\\ 247 | # & w=\textrm{vec}(x,y),\\ 248 | # & W-l_{w}w^{\top}-wl_{w}^{\top}\geq-l_{w}l_{w}^{\top},\\ 249 | # & W-l_{w}w{}^{\top}-wl_{w}^{\top}\geq-u_{w}u_{w}^{\top},\\ 250 | # & W-l_{w}w^{\top}-wu_{w}^{\top}\geq-l_{w}u_{w}^{\top},\\ 251 | # & l_{w}\leq w\leq u_{w}, 252 | # \end{array}\right) 253 | # $$ 254 | 255 | # where the decision variables are $x,y\in\mathbf{R}^{2},\; Z\in\mathbf{S}^{2},\; W\in\mathbf{S}^{4}$. The last four constraints are called RLT cuts that are valid inequalities for $W=w w^\top$. For more details about the RLT cut and how the SDP relaxation is constructed in general, see 256 | 257 | # > Anstreicher, Kurt M. "Semidefinite programming versus the reformulation-linearization technique for nonconvex quadratically constrained quadratic programming." *Journal of Global Optimization* 43.2 (2009): 471-484. 258 | # > 259 | # > (Link: [http://www.optimization-online.org/DB_FILE/2007/05/1655.pdf](http://www.optimization-online.org/DB_FILE/2007/05/1655.pdf)) 260 | 261 | # Let us solve the SDP model step by step. 262 | 263 | 264 | using Mosek, MosekTools 265 | 266 | function SDP_relaxation_solver(c_1, c_2, c_3, a_1, x_lb, x_ub, y_lb, y_ub, QuadCon1StdTerms, QuadCon2StdTerms; big_M = 100, RLT_cut = :on) 267 | 268 | # Define the SDP model 269 | 270 | SDP_model = Model(optimizer_with_attributes(Mosek.Optimizer)) 271 | 272 | @variable(SDP_model, x_lb <= x[1:2] <= x_ub) 273 | 274 | @variable(SDP_model, y_lb <= y[1:2] <= y_ub) 275 | 276 | @variable(SDP_model, Z[1:2, 1:2], PSD) 277 | 278 | w = Vector{VariableRef}[] 279 | 280 | push!(w, x) 281 | 282 | push!(w, y) 283 | 284 | # create the vectorized w 285 | 286 | w_vec = reduce(vcat, w) 287 | 288 | len_w = length(w_vec) 289 | 290 | 291 | @variable(SDP_model, W[1:len_w, 1:len_w], Symmetric) 292 | 293 | @objective(SDP_model, Min, c_1'*x + c_2'*y + c_3*tr(Z) ) 294 | 295 | dim_Z = 2 296 | 297 | # SDP relaxation of qudratic constraint 1 298 | # --------------------------------------- 299 | 300 | for k in 1:dim_Z 301 | for ℓ in 1:k 302 | @constraint(SDP_model, tr(QuadCon1StdTerms[k,ℓ].P * W) + (QuadCon1StdTerms[k,ℓ].q)'*w_vec + (QuadCon1StdTerms[k,ℓ].r) == Z[k,ℓ] ) 303 | end 304 | end 305 | 306 | # SDP relaxation of qudratic constraint 2 307 | # --------------------------------------- 308 | 309 | for k in 1:dim_Z 310 | for ℓ in 1:k 311 | @constraint(SDP_model, tr(QuadCon2StdTerms[k,ℓ].P * W) + (QuadCon2StdTerms[k,ℓ].q)'*w_vec + (QuadCon2StdTerms[k,ℓ].r) <= 0 ) 312 | end 313 | end 314 | 315 | # Schur complement constraint 316 | # --------------------------- 317 | 318 | @constraint(SDP_model, schurCon, [W w_vec; w_vec' 1] in PSDCone()) 319 | 320 | @constraint(SDP_model, c_1'*x + c_2'*y + c_3*tr(Z) >= -400 ) 321 | 322 | @constraint(SDP_model, c_1'*x + c_2'*y + c_3*tr(Z) <= -200 ) 323 | 324 | # Add RLT cuts 325 | # ------------ 326 | 327 | if RLT_cut == :on 328 | 329 | # construct lower and upper bound vector for w_vec 330 | 331 | l_w = zeros(len_w) 332 | u_w = zeros(len_w) 333 | 334 | for i in 1:len_w 335 | 336 | if has_upper_bound(w_vec[i]) == true 337 | u_w[i] = upper_bound(w_vec[i]) 338 | else 339 | u_w[i] = big_M 340 | end 341 | 342 | if has_lower_bound(w_vec[i]) == true 343 | l_w[i] = lower_bound(w_vec[i]) 344 | else 345 | l_w[i] = -big_M 346 | end 347 | 348 | end 349 | 350 | # Add RLT cuts 351 | # ------------ 352 | 353 | con_shape = SymmetricMatrixShape(2) 354 | 355 | @info "[🎠 ] Adding RLT cuts" 356 | 357 | @constraint(SDP_model, RLT_cut_1, vectorize( W - l_w*w_vec' - w_vec*l_w' + l_w*l_w', con_shape) .>= 0) 358 | 359 | @constraint(SDP_model, RLT_cut_2, vectorize(W - l_w*w_vec' - w_vec*l_w' + u_w*u_w', con_shape) .>= 0) 360 | 361 | @constraint(SDP_model, RLT_cut_3, vectorize(W - l_w*w_vec' - w_vec*u_w' + l_w*u_w', con_shape) .>= 0) 362 | 363 | @constraint(SDP_model, RLT_cut_4, l_w .<= w_vec) 364 | 365 | @constraint(SDP_model, RLT_cut_5, w_vec .<= u_w ) 366 | 367 | end 368 | 369 | # Solve the optimization problem 370 | 371 | optimize!(SDP_model) 372 | 373 | objective_value(SDP_model) 374 | 375 | if termination_status(SDP_model) != MOI.OPTIMAL 376 | @info "[💀]" 377 | @error "model_dual_PEP_with_known_stepsizes solving did not reach optimality; termination status = " termination_status(SDP_model) 378 | end 379 | 380 | x_star = value.(x) 381 | 382 | y_star = value.(y) 383 | 384 | Z_star = value.(Z) 385 | 386 | W_star = value.(W) 387 | 388 | p_star = objective_value(SDP_model) 389 | 390 | return x_star, y_star, Z_star, W_star, p_star 391 | 392 | end 393 | 394 | # Test the function. 395 | 396 | 397 | # x_star_SDP, y_star_SDP, Z_star_SDP, W_star_SDP, p_star_SDP = SDP_relaxation_solver(c_1, c_2, c_3, a_1, x_lb, x_ub, y_lb, y_ub, QuadCon1StdTerms, QuadCon2StdTerms; big_M = 100, RLT_cut = :on) 398 | 399 | -------------------------------------------------------------------------------- /3_Gradient_reduction_in_smooth_nonconvex_problems/test_code.jl: -------------------------------------------------------------------------------- 1 | ## Test code 2 | 3 | ## Include the main Julia file 4 | 5 | include("BnB_PEP_gradient_reduction_smooth_ncvx.jl") 6 | 7 | ## Parameters to use 8 | 9 | L = 1 10 | N = 3 11 | R = 1 12 | default_obj_val_upper_bound = 1e6 13 | 14 | ## Feasible stepsize generation 15 | 16 | h_test, α_test = feasible_h_α_generator(N, L; step_size_type = :Default) 17 | ## Solve primal with feasible stepsize 18 | 19 | p_feas_1, G_feas_1, Ft_feas_1 = solve_primal_with_known_stepsizes(N, R, L, α_test; show_output = :off) 20 | 21 | 22 | # ------------------------------------------------------- 23 | ## Stage 1 of the BnB-PEP Algorithm: solve the dual for the warm-starting stepsize 24 | # ------------------------------------------------------- 25 | 26 | 27 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_test; 28 | show_output = :off, 29 | ϵ_tol_feas = 1e-6, 30 | objective_type = :default, 31 | obj_val_upper_bound = default_obj_val_upper_bound) 32 | 33 | @info "primal-dual gap = $(p_feas_1-d_feas_1)" 34 | 35 | 36 | ## Computing the bounds for computing locally optimal solution to BnB-PEP 37 | 38 | M_tilde = 50 39 | 40 | # compute M_λ 41 | 42 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_feas_1; show_output = :off, 43 | ϵ_tol_feas = 1e-6, 44 | objective_type = :find_M_λ, 45 | obj_val_upper_bound = 1.001*p_feas_1) 46 | 47 | M_λ =M_tilde*maximum(λ_feas_1) 48 | 49 | # compute M_τ 50 | 51 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_feas_1; show_output = :off, 52 | ϵ_tol_feas = 1e-6, 53 | objective_type = :find_M_τ, 54 | obj_val_upper_bound = 1.001*p_feas_1) 55 | 56 | M_τ = M_tilde*maximum(τ_feas_1) 57 | 58 | # compute M_η 59 | 60 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_feas_1; show_output = :off, 61 | ϵ_tol_feas = 1e-6, 62 | objective_type = :find_M_η, 63 | obj_val_upper_bound = 1.001*p_feas_1) 64 | 65 | M_η = M_tilde*maximum(η_feas_1) 66 | 67 | # compute M_Z 68 | 69 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_feas_1; show_output = :off, 70 | ϵ_tol_feas = 1e-6, 71 | objective_type = :find_M_Z, 72 | obj_val_upper_bound = 1.001*p_feas_1) 73 | 74 | 75 | M_Z = M_tilde*max(1,maximum(Z_feas_1[i,i] for i in 1:N+2)) 76 | 77 | # compute M_L_cholesky 78 | 79 | M_L_cholesky = sqrt(M_Z) 80 | 81 | # compute M_α 82 | 83 | M_α = (5*M_tilde)/L 84 | 85 | # compute M_ν 86 | 87 | M_ν = ν_feas_1 88 | 89 | @show [M_λ M_τ M_η M_α M_Z M_L_cholesky M_ν] 90 | 91 | ## sparsify the solution for warm-starting locally optimal solver 92 | 93 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_feas_1; 94 | show_output = :on, 95 | ϵ_tol_feas = 1e-6, 96 | objective_type = :find_sparse_sol, 97 | obj_val_upper_bound = p_feas_1) 98 | 99 | 100 | ## store the warm start point for computing locally optimal solution 101 | 102 | 103 | d_star_ws, λ_ws, τ_ws, η_ws, ν_ws, Z_ws, L_cholesky_ws, Θ_ws, α_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective, idx_set_η_ws_effective = d_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective 104 | 105 | 106 | # --------------------------------------------------- 107 | ## Stage 2 of the BnB-PEP Algorithm: compute the locally optimal point 108 | # ---------------------------------------------------- 109 | 110 | 111 | obj_val_loc_opt, λ_loc_opt, τ_loc_opt, η_loc_opt, ν_loc_opt, Z_loc_opt, L_cholesky_loc_opt, Θ_loc_opt, α_loc_opt, idx_set_λ_loc_opt_effective, idx_set_τ_loc_opt_effective, idx_set_η_loc_opt_effective = BnB_PEP_solver( 112 | # different parameters to be used 113 | # ------------------------------ 114 | N, L, R, 115 | # solution to warm-start (Θ is warm-started internally) 116 | # ----------------------------------------------------- 117 | d_star_ws, λ_ws, τ_ws, η_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective, idx_set_η_ws_effective, 118 | # bounds on the variables (M_Θ is computed internally) 119 | # ---------------------------------------------------- 120 | M_λ, M_τ, M_η, M_α, M_Z, M_L_cholesky, M_ν; 121 | # options 122 | # ------- 123 | solution_type = :find_locally_optimal, # other option :find_globally_optimal 124 | show_output = :on, # other option :on 125 | local_solver = :ipopt, # other option :knitro 126 | reduce_index_set_for_dual_variables = :off, #other option is :for_warm_start_only, 127 | positive_step_size = :on, # other option is :off 128 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation 129 | quadratic_equality_modeling = :exact, #:through_ϵ, # :exact, 130 | cholesky_modeling = :definition, 131 | ϵ_tol_feas = 1e-6, # tolerance for Cholesky feasibility 132 | polish_solution = :on, # wheather to polish the solution to get better precision, the other option is :off 133 | M_Θ_factor = M_tilde, # upper bound factor for Θ 134 | impose_pattern = :off # wheather to impose the pattern found by solving smaller BnB-PEPs to global optimality 135 | ) 136 | 137 | # Store the solution to be warm-started for a next step 138 | 139 | 140 | ## values for the tables 141 | 142 | using LatexPrint 143 | 144 | @show round(obj_val_loc_opt, digits = 7) 145 | 146 | h_loc_opt = compute_h_from_α(α_loc_opt, N, L) 147 | 148 | h_matlab_format = round.(OffsetArrays.no_offset_view(h_loc_opt),digits = 6) 149 | h_latex = lap(h_matlab_format) 150 | 151 | @show h_latex 152 | 153 | 154 | 155 | ## Store the solution to be warm-started for a next step 156 | 157 | d_star_ws, λ_ws, τ_ws, η_ws, ν_ws, Z_ws, L_cholesky_ws, Θ_ws, α_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective, idx_set_η_ws_effective = obj_val_loc_opt, λ_loc_opt, τ_loc_opt, η_loc_opt, ν_loc_opt, Z_loc_opt, L_cholesky_loc_opt, Θ_loc_opt, α_loc_opt, idx_set_λ_loc_opt_effective, idx_set_τ_loc_opt_effective, idx_set_η_loc_opt_effective 158 | 159 | ## Update the entries of the bounds based on the heuristic 160 | 161 | ## Computing the bounds for computing locally optimal solution to BnB-PEP 162 | 163 | M_tilde = 1.01 164 | 165 | # compute M_λ 166 | 167 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_ws; show_output = :off, 168 | ϵ_tol_feas = 1e-6, 169 | objective_type = :find_M_λ, 170 | obj_val_upper_bound = 1.001*d_star_ws) 171 | 172 | M_λ = M_tilde*maximum(λ_feas_1) 173 | 174 | # compute M_τ 175 | 176 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_ws; show_output = :off, 177 | ϵ_tol_feas = 1e-6, 178 | objective_type = :find_M_τ, 179 | obj_val_upper_bound = 1.001*d_star_ws) 180 | 181 | M_τ = M_tilde*maximum(τ_feas_1) 182 | 183 | # compute M_η 184 | 185 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_ws; show_output = :off, 186 | ϵ_tol_feas = 1e-6, 187 | objective_type = :find_M_η, 188 | obj_val_upper_bound = 1.001*d_star_ws) 189 | 190 | M_η = M_tilde*maximum(η_feas_1) 191 | 192 | # compute M_Z 193 | 194 | d_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, ℓ_1_norm_η_feas_1, tr_Z_feas_1, λ_feas_1, τ_feas_1, η_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, Θ_feas_1, α_feas_1, idx_set_λ_feas_1_effective, idx_set_τ_feas_1_effective, idx_set_η_1_feas_effective = solve_dual_PEP_with_known_stepsizes(N, R, L, α_ws; show_output = :off, 195 | ϵ_tol_feas = 1e-6, 196 | objective_type = :find_M_Z, 197 | obj_val_upper_bound = 1.001*d_star_ws) 198 | 199 | 200 | M_Z = M_tilde*max(1,maximum(Z_feas_1[i,i] for i in 1:N+2)) 201 | 202 | # compute M_L_cholesky 203 | 204 | M_L_cholesky = sqrt(M_Z) 205 | 206 | # compute M_α 207 | 208 | M_α = (5*M_tilde)/L 209 | 210 | # compute M_ν 211 | 212 | M_ν = ν_feas_1 213 | 214 | @show [M_λ M_τ M_η M_α M_Z M_L_cholesky M_ν] 215 | 216 | 217 | 218 | ## Compute global lower bound via lazy callback 219 | 220 | obj_val_glb_lbd, λ_glb_lbd, τ_glb_lbd, η_glb_lbd, ν_glb_lbd, Z_glb_lbd, L_cholesky_glb_lbd, Θ_glb_lbd, α_glb_lbd, idx_set_λ_glb_lbd_effective, idx_set_τ_glb_lbd_effective, idx_set_η_glb_lbd_effective = BnB_PEP_solver( 221 | # different parameters to be used 222 | # ------------------------------ 223 | N, L, R, 224 | # solution to warm-start (Θ is warm-started internally) 225 | # ----------------------------------------------------- 226 | d_star_ws, λ_ws, τ_ws, η_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective, idx_set_η_ws_effective, 227 | # bounds on the variables (M_Θ is computed internally) 228 | # ---------------------------------------------------- 229 | M_λ, M_τ, M_η, M_α, M_Z, M_L_cholesky, M_ν; 230 | # options 231 | # ------- 232 | solution_type = :find_globally_optimal, # other option :find_globally_optimal 233 | show_output = :on, # other option :on 234 | reduce_index_set_for_dual_variables = :on, # :for_warm_start_only, 235 | positive_step_size = :on, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 236 | find_global_lower_bound_via_cholesky_lazy_constraint = :on, # if this on, then we model Z = L_cholesky*L_cholesky^T via lazy constraint (the goal is to find a lower bound to BnB PEP) 237 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation 238 | quadratic_equality_modeling = :exact, #:through_ϵ, 239 | cholesky_modeling = :definition, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 240 | ϵ_tol_feas = 1e-6, # tolerance for Cholesky feasibility 241 | maxCutCount=1e6, # this is the number of cuts to be added if the lazy constraint callback is activated 242 | global_lower_bound_given = :off, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 243 | global_lower_bound = 0.0, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 244 | polish_solution = :on, # wheather to polish the solution to get better precision, the other option is :off 245 | M_Θ_factor = M_tilde, # upper bound factor for Θ 246 | impose_pattern = :off # wheather to impose the pattern found by solving smaller BnB-PEPs to global optimality 247 | ) 248 | 249 | 250 | # ---------------------------------------------------- 251 | ## Stage 3 of the BnB-PEP Algorithm: find the globally optimal solution to the BnB-PEP-QCQP 252 | # ---------------------------------------------------- 253 | 254 | 255 | obj_val_glb_opt, λ_glb_opt, τ_glb_opt, η_glb_opt, ν_glb_opt, Z_glb_opt, L_cholesky_glb_opt, Θ_glb_opt, α_glb_opt, idx_set_λ_glb_opt_effective, idx_set_τ_glb_opt_effective, idx_set_η_glb_opt_effective= BnB_PEP_solver( 256 | # different parameters to be used 257 | # ------------------------------ 258 | N, L, R, 259 | # solution to warm-start (Θ is warm-started internally) 260 | # ----------------------------------------------------- 261 | d_star_ws, λ_ws, τ_ws, η_ws, ν_ws, Z_ws, L_cholesky_ws, α_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective, idx_set_η_ws_effective, 262 | # bounds on the variables (M_Θ is computed internally) 263 | # ---------------------------------------------------- 264 | M_λ, M_τ, M_η, M_α, M_Z, M_L_cholesky, M_ν; 265 | # options 266 | # ------- 267 | solution_type = :find_globally_optimal, #:find_locally_optimal, # other option :find_globally_optimal 268 | show_output = :on, # other option :on 269 | reduce_index_set_for_dual_variables = :off, #:on, 270 | reduce_index_set_for_L_cholesky = :off, #:on, 271 | positive_step_size = :on, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 272 | bound_impose = :on, # if this is :from_warm_start_sol, then from the warm_start solution we compute lower and upper bounds for the decision variables, [💀 : TODO] if this is :uniform_bound, then we impose a user specified bound on the variables 273 | quadratic_equality_modeling = :exact, #:through_ϵ, # :exact, #:through_ϵ, 274 | cholesky_modeling = :formula, #:definition, 275 | ϵ_tol_feas = 1e-4, # tolerance for Cholesky feasibility 276 | global_lower_bound_given = :on, # wheather is a global lower bound is given 277 | global_lower_bound = obj_val_glb_lbd, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 278 | polish_solution = :on, # wheather to polish the solution to get better precision, the other option is :off 279 | M_Θ_factor = 5*M_tilde, 280 | impose_pattern = :on 281 | ) 282 | 283 | ## Values for the tables 284 | 285 | @show round(obj_val_glb_opt, digits = 7) 286 | 287 | h_glb_opt = compute_h_from_α(α_glb_opt, N, L) 288 | 289 | h_matlab_format = round.(OffsetArrays.no_offset_view(h_glb_opt),digits = 6) 290 | 291 | h_glb_opt_latex = lap(h_matlab_format) 292 | 293 | @show h_glb_opt_latex 294 | -------------------------------------------------------------------------------- /Misc/zetaeta.jl: -------------------------------------------------------------------------------- 1 | # List of ζ and η 2 | 3 | # ------------------------ 4 | # Value of ζ and η for N=6 5 | # ------------------------ 6 | 7 | ζ_star = [1.0587901252766914e-16, 0.1496264953236793, 0.14947572771315815, 0.1494433376014367, 0.14939538104320496, 0.14669589069824765] 8 | 9 | η_star = [0.15761974578618743, -1.595115651108022e-5, -6.01668066885403e-6, 2.3848933315195266e-5, 3.7595337582835704e-5, 2.0949675843617817e-5] 10 | 11 | 12 | # ------------------------ 13 | # Value of ζ and η for N=7 14 | # ------------------------ 15 | 16 | ζ_star = [1.588185187915037e-16, 0.1496610983645615, 0.14948816516209543, 0.14939428136795657, 0.14934265594460203, 0.14931187143245128, 0.14665341549614128] 17 | 18 | η_star = [0.15761775420723367, -5.4313164391444874e-5, -2.429882285018153e-5, 6.619419012930244e-5, 0.00011731708975059024, 0.00011528727919545087, 5.9705915017058906e-5] 19 | 20 | 21 | # ------------------------ 22 | # Value of ζ and η for N=8 23 | # ------------------------ 24 | 25 | ζ_star = [5.293950626383457e-17, 0.1496371020097476, 0.14948048394854666, 0.14942843237988826, 0.14939322110795616, 0.14938358868049822, 0.14936109326009542, 0.14668266387945147] 26 | 27 | η_star = [0.15761904988196784, -2.784070327628467e-5, -1.2756450951842552e-5, 3.655413496088017e-5, 7.138236971045348e-5, 8.089041551716976e-5, 6.994490416018815e-5, 3.3024686195423184e-5] 28 | 29 | 30 | # ------------------------ 31 | # Value of ζ and η for N=9 32 | # ------------------------ 33 | 34 | ζ_star = [1.0587901252766914e-16, 0.14968804080535372, 0.14949778326536728, 0.14935901352327313, 0.14927850462248743, 0.14925095068124292, 0.14925069490107412, 0.14924886920346306, 0.14662538855877025] 35 | 36 | η_star = [0.15761436078649793, -8.627243853273084e-5, -4.082483562212887e-5, 9.316989596783352e-5, 0.00017236369077489204, 0.00020002797285720083, 0.0002012423724109121, 0.00017198283297256868, 8.363475534564658e-5] 37 | 38 | 39 | # ------------------------ 40 | # Value of ζ and η for N=10 41 | # ------------------------ 42 | 43 | ζ_star = [0.0, 0.14970271456957604, 0.14950178115954785, 0.14933923800272356, 0.14924373747229014, 0.1492063182592372, 0.14919726052668103, 0.14920962623430334, 0.14921807791359185, 0.1466116655957435] 44 | 45 | η_star = [0.15761176284957415, -0.00010455912466494315, -4.9566808439841546e-5, 0.0001073975647304034, 0.0002010517717851933, 0.00023805446125082328, 0.00024789267340270246, 0.00023720533144490921, 0.00019867744857776372, 9.464309368023868e-5] 46 | 47 | 48 | # ------------------------ 49 | # Value of ζ and η for N=11 50 | # ------------------------ 51 | 52 | ζ_star = [0.0, 0.14971793353429957, 0.1495050740272908, 0.14931771913254172, 0.14920721530358205, 0.14915953626690528, 0.14914210666704059, 0.14914604292814673, 0.1491689505432677, 0.14918721265177037, 0.14659814197116672] 53 | 54 | η_star = [0.15760842580209516, -0.00012428257751411853, -5.865977774480318e-5, 0.00012222066100687115, 0.00023024672844252194, 0.0002770467354149164, 0.00029473377315854813, 0.0002923078248497431, 0.00027187982684146665, 0.00022470853378740434, 0.00010494375276581371] 55 | 56 | 57 | # ------------------------ 58 | # Value of ζ and η for N=12 59 | # ------------------------ 60 | 61 | ζ_star = [0.0, 0.1497336546462447, 0.1495073783341136, 0.14929440237485403, 0.1491680881504394, 0.1491104027547666, 0.1490840008561252, 0.1490805434969642, 0.14909474468951966, 0.14912809607817992, 0.14915590232522596, 0.14658499075576734] 62 | 63 | η_star = [0.15760423346526214, -0.00014554406023672967, -6.797898492958606e-5, 0.0001374828447615935, 0.0002606061673984489, 0.0003168488265729927, 0.0003430771200642813, 0.0003475110652705449, 0.0003356398094982504, 0.00030571383153826646, 0.00025035468331188873, 0.00011430504109354015] 64 | 65 | 66 | # ------------------------ 67 | # Value of ζ and η for N=13 68 | # ------------------------ 69 | 70 | ζ_star = [5.293950626383457e-17, 0.14974963045321818, 0.14950842230187, 0.14926868158431447, 0.1491259208823917, 0.1490574495265277, 0.14902250196615108, 0.14901087583983913, 0.14901810129902163, 0.14904233239555656, 0.14908617165098023, 0.14912397536431007, 0.14657217708360856] 71 | 72 | η_star = [0.15759907042044066, -0.000168237465592305, -7.741472025943716e-5, 0.0001535972147596665, 0.0002923277165473157, 0.0003586979757626738, 0.0003929561883891188, 0.00040512846146796084, 0.0003997041105222827, 0.00037876342564123824, 0.0003394907437311507, 0.00027569758749968967, 0.0001227117938572886] 73 | 74 | 75 | 76 | # Value of ζ and η for N=14 77 | # ------------------------ 78 | 79 | ζ_star = [1.0587901252766914e-16, 0.14967716228383832, 0.1494872515664367, 0.14935724986914134, 0.14926941328810686, 0.14922701388078757, 0.14920427250131937, 0.149194079637073, 0.1491933860948389, 0.14920136711621185, 0.14921789466044413, 0.1492449118286266, 0.14925932159532018, 0.1466410034015014] 80 | 81 | η_star = [0.15761128755134912, -7.878179422303915e-5, -3.379681828873855e-5, 9.093005895541208e-5, 0.0001766143981121715, 0.0002177830254273847, 0.00023998300236585616, 0.00025015176772799755, 0.00025131502458084235, 0.0002443546880084965, 0.00022951893591022647, 0.00020470798664035602, 0.00016001876959347009, 6.713305400096593e-5] 82 | 83 | 84 | # ------------------------ 85 | # Value of ζ and η for N=15 86 | # ------------------------ 87 | 88 | ζ_star = [0.0, 0.14978154680064734, 0.14950521555708485, 0.14920823780472695, 0.14902907453380895, 0.14893685400954929, 0.14888245258239954, 0.1488549254350521, 0.14884710175989013, 0.14885684364128415, 0.14888472853066131, 0.14892959748386533, 0.14899715935348157, 0.14905717511876607, 0.14654770693544236] 89 | 90 | η_star = [0.15758530712751267, -0.00021773962921283634, -9.587444510995279e-5, 0.00018931626898289556, 0.00036224846316790054, 0.00045061179324950353, 0.0005029806133192502, 0.000529924701079513, 0.0005386764699703801, 0.0005312807629224459, 0.0005073619129022385, 0.0004683206223921082, 0.00040828088272772866, 0.00032618822717975227, 0.0001362791564945898] 91 | 92 | 93 | # ------------------------ 94 | # Value of ζ and η for N=16 95 | # ------------------------ 96 | 97 | ζ_star = [0.0, 0.149691316126875, 0.14948425388514042, 0.14932326568135834, 0.149215500822491, 0.1491604891113151, 0.14912804839782567, 0.14910973024117843, 0.14910198971150057, 0.1491026739200127, 0.1491116781862459, 0.14912928373369116, 0.14915602949007215, 0.1491949057350239, 0.14922219810932794, 0.14662710446554925] 98 | 99 | η_star = [0.15760566443540452, -0.00010025396227663543, -3.9873982397868555e-5, 0.00011447356136499348, 0.00021912437305631513, 0.0002721161464750962, 0.0003034177088668195, 0.00032121558556606696, 0.000329025411462782, 0.0003290186443312425, 0.0003212725115405641, 0.0003056372476284859, 0.000281679364762756, 0.0002463187976769454, 0.0001904330155507763, 7.663085828822604e-5] 100 | 101 | 102 | # ------------------------ 103 | # Value of ζ and η for N=17 104 | # ------------------------ 105 | 106 | ζ_star = [0.0, 0.1498117177780186, 0.14949203568538924, 0.14913144644219078, 0.14890984541918637, 0.14878865961205098, 0.1487106829580541, 0.14866379644581076, 0.14863944915307437, 0.1486347213502868, 0.14864821787430196, 0.14867946883595365, 0.14873051612562213, 0.1488004622537489, 0.14889719689503186, 0.14898463990838198, 0.146524638608541] 107 | 108 | η_star = [0.15756603550599277, -0.0002721636748208443, -0.00011218992917721926, 0.00023247307583697304, 0.0004447384714823115, 0.0005595002375442115, 0.0006334129122467075, 0.0006780567140435954, 0.000702031620032827, 0.0007080867644331443, 0.0006977773310570024, 0.0006714957038732671, 0.0006275270530007444, 0.0005669747939717624, 0.0004819003474755159, 0.000377550315645836, 0.00014526335669368584] 109 | 110 | 111 | # ------------------------ 112 | # Value of ζ and η for N=18 113 | # ------------------------ 114 | 115 | ζ_star = [0.0, 0.14970456458811468, 0.14947655728607856, 0.14928159616780598, 0.14915163886023497, 0.14908192468174036, 0.1490380752650697, 0.14901031651754928, 0.14899464727219436, 0.1489881970059353, 0.14899059446660068, 0.14900100188634216, 0.14902008900973812, 0.14904857166494634, 0.14908743535354418, 0.14914044856491693, 0.14918259105477608, 0.1466134415695752] 116 | 117 | η_star = [0.157597855534426, -0.00012347059194457133, -4.4349905799295946e-5, 0.0001421931942755465, 0.0002677331666000704, 0.00033432667740008597, 0.0003761622987259337, 0.0004026718619502946, 0.0004178390896091095, 0.00042451184115826547, 0.0004230177483421203, 0.0004142561211916018, 0.00039753811935158316, 0.00037235388243719625, 0.00033777565289241766, 0.0002900261109457918, 0.00022144668997376576, 8.466656824086947e-5] 118 | 119 | 120 | # ------------------------ 121 | # Value of ζ and η for N=19 122 | # ------------------------ 123 | 124 | ζ_star = [1.0587901252766914e-16, 0.14983777463086057, 0.1494646656096721, 0.1490322996254661, 0.14876016883482476, 0.1486026203536655, 0.1484947962494657, 0.14842251263440953, 0.14837735222890153, 0.14835444164820852, 0.1483524294181294, 0.1483702581072063, 0.14840740058706586, 0.1484651985591103, 0.14854520794674012, 0.14864745962606768, 0.14878130804557152, 0.14890384143349958, 0.14650263276985798] 125 | 126 | η_star = [0.1575400402227479, -0.0003306278490456603, -0.00012388852693135855, 0.0002870304708039566, 0.0005455434555346594, 0.0006929929030763072, 0.0007937599511815365, 0.0008612905315719734, 0.0009040338177207319, 0.000926712782218479, 0.000930686466152011, 0.0009169890365618878, 0.0008863042198071387, 0.0008372254686096136, 0.0007686880714870793, 0.0006807214460705955, 0.0005641757339329437, 0.0004314473247320031, 0.00014949816174805608] 127 | 128 | 129 | # ------------------------ 130 | # Value of ζ and η for N=20 131 | # ------------------------ 132 | 133 | ζ_star = [5.293950626383456e-17, 0.14984837894061587, 0.1494441226916134, 0.14897214424246089, 0.14867100364681823, 0.1484918270545569, 0.14836593409096518, 0.1482780520460223, 0.14821997560349792, 0.1481856711801243, 0.14817456437802246, 0.14818395211824728, 0.1482148771717615, 0.1482660850356506, 0.1483399313610816, 0.14843760421854693, 0.1485594700665636, 0.14871568113660766, 0.14885943742571314, 0.1464918313016711] 134 | 135 | η_star = [0.1575241111060072, -0.00036099555704169827, -0.00012706333190352185, 0.00032009438690594027, 0.0006049387073612656, 0.0007716682876090451, 0.0008885603672140623, 0.0009700082015911743, 0.0010242927677727124, 0.0010572465917057527, 0.0010694422338899138, 0.0010635880212526657, 0.001038617261330902, 0.0009960048205899638, 0.0009332702504017946, 0.0008498428210269312, 0.0007453084481393604, 0.0006098886884736041, 0.0004599686159600226, 0.00014986647639038115] 136 | 137 | 138 | # ------------------------ 139 | # Value of ζ and η for N=21 140 | # ------------------------ 141 | 142 | ζ_star = [5.293950626383456e-17, 0.14985685857405248, 0.1494181128882494, 0.148903612349604, 0.14857065021857394, 0.14836701126425356, 0.14822071432889758, 0.14811475032187318, 0.14804169796765562, 0.14799423498605704, 0.14797198839171236, 0.14797244691866712, 0.14799502586441238, 0.1480406450852506, 0.148107935497058, 0.1482003440946506, 0.1483180728142233, 0.14846248424134853, 0.14864397334267815, 0.148811856706656, 0.14648117876370792] 143 | 144 | η_star = [0.1575059959277633, -0.0003918994407194752, -0.0001278952857818313, 0.0003579434527465486, 0.0006715196568961071, 0.0008599758782317078, 0.0009949623908938015, 0.0010925021203639581, 0.0011600632652134268, 0.0012048173024420828, 0.001227028976396294, 0.0012292841595410123, 0.0012121000995037328, 0.0011746396323862574, 0.0011184399559556483, 0.0010399491310428366, 0.000939680629161375, 0.000816097260335845, 0.0006593978315095545, 0.0004898786389664667, 0.00014895396439404548] 145 | 146 | 147 | # ------------------------ 148 | # Value of ζ and η for N=22 149 | # ------------------------ 150 | 151 | ζ_star = [0.0, 0.1497243414619556, 0.1494404246816254, 0.14916602888064096, 0.1489818141942083, 0.14887303121526546, 0.14879815707320487, 0.14874370334230066, 0.14870574693896052, 0.1486800204705395, 0.14866550536662307, 0.14866140745727055, 0.14866685467528412, 0.14868199771587115, 0.14870700714094748, 0.1487417888868936, 0.14878829747172917, 0.14884665712276002, 0.14891951081494292, 0.14901099226628764, 0.14909239751242193, 0.14658658947222902] 152 | 153 | η_star = [0.15757379906727528, -0.0001734313027615391, -4.4566462518415514e-5, 0.00021615311552448434, 0.00039188215585888426, 0.0004939779555706416, 0.0005638302712453993, 0.0006144759926501076, 0.000649759051245862, 0.0006739663603379082, 0.0006880081924668529, 0.0006926794705522437, 0.0006888689993185825, 0.0006763946075910665, 0.000655140282388293, 0.0006252637274895448, 0.0005848080261746544, 0.0005339769384882729, 0.00047003875398957736, 0.0003891405372468875, 0.0002874772222831603, 9.582726649451758e-5] 154 | 155 | 156 | # ------------------------ 157 | # Value of ζ and η for N=23 158 | # ------------------------ 159 | 160 | ζ_star = [1.0587901252766914e-16, 0.14986566777980526, 0.1493466936489042, 0.1487371212903346, 0.148330749361415, 0.14806861373140137, 0.14787281772499555, 0.14772245966964911, 0.1476116544707255, 0.14753096583283248, 0.1474803839173391, 0.14745679025747763, 0.14745969266155817, 0.14748874785421304, 0.1475433123966594, 0.14762509839485274, 0.1477325244315745, 0.1478703631234134, 0.1480373540942682, 0.1482366103285218, 0.14847880446278866, 0.14870540497270207, 0.14645896392004643] 161 | 162 | η_star = [0.15746247170582056, -0.0004544414353737822, -0.00012060683954410613, 0.0004510565870126916, 0.000830449868046721, 0.001070596512380298, 0.0012492256405906605, 0.001386024491926864, 0.0014869053248978631, 0.0015611603309949949, 0.0016086320557541394, 0.001632507522133178, 0.001633166229160344, 0.0016110703252163578, 0.0015668032578393493, 0.001498781271035844, 0.0014087553534373732, 0.001291858540118805, 0.0011502372050375903, 0.0009803705850436465, 0.0007726506826077274, 0.0005551657361028083, 0.0001444173203409784] 163 | 164 | 165 | # ------------------------ 166 | # Value of ζ and η for N=24 167 | # ------------------------ 168 | 169 | ζ_star = [1.0587901252766914e-16, 0.14972848790361318, 0.14940805889290756, 0.14908655910670798, 0.1488685451753615, 0.14873360236764388, 0.14863731394813562, 0.1485638684603783, 0.14850964097170063, 0.14846966494662608, 0.14844275609022467, 0.14842802936245222, 0.14842434458803536, 0.14843186854893292, 0.14845007560072263, 0.14847930835254503, 0.14851996721915062, 0.14857202834904468, 0.14863800220641918, 0.14871740389069757, 0.14881405511573245, 0.14893170177224932, 0.14903956217755052, 0.1465729797068339] 170 | 171 | η_star = [0.15755651229921624, -0.00019906690663665805, -3.789256855732294e-5, 0.0002661884033042434, 0.00047269746804242866, 0.000598243687006881, 0.0006871411230522849, 0.0007547070997447148, 0.000804444020754567, 0.0008413652489123437, 0.0008665075060932291, 0.0008807733003140664, 0.0008852910764144152, 0.0008798627328777988, 0.0008650527842016316, 0.0008404891950590232, 0.000805865297340173, 0.0007612473994778241, 0.0007041414458380644, 0.0006354223956818684, 0.0005510807075470737, 0.00044785903245039946, 0.00032402291392208784, 9.896823350862398e-5] 172 | 173 | 174 | # ------------------------ 175 | # Value of ζ and η for N=25 176 | # ------------------------ 177 | 178 | ζ_star = [1.0587901252766914e-16, 0.14972853710250625, 0.14938732676343427, 0.1490400031165334, 0.14880302187187094, 0.14865288997803736, 0.14854401397410583, 0.1484592496811998, 0.1483951453023005, 0.14834652808527757, 0.14831190371072978, 0.1482905862025982, 0.14828123674501745, 0.1482838135148424, 0.14829817840756426, 0.14832393230364702, 0.1483617268998418, 0.14841176668096992, 0.1484742540284238, 0.14855185470053728, 0.14864373683547372, 0.14875446456029376, 0.14888734695384462, 0.14901063420020294, 0.1465659904839631] 179 | 180 | η_star = [0.15754630788726884, -0.00021176382927566546, -3.2247245396194425e-5, 0.000295444459673587, 0.0005191029417027073, 0.0006581946497774748, 0.000758217975850467, 0.0008358153095853658, 0.0008942814759672195, 0.0009388522089824162, 0.0009708670473792013, 0.0009910095700419411, 0.001000630937740123, 0.0009997212647658998, 0.0009884318264310535, 0.0009671912021171294, 0.0009353201942758453, 0.0008927263459835074, 0.0008392332534078748, 0.0007722156630584487, 0.0006929110621257704, 0.0005965213363533516, 0.0004803472461368837, 0.00034358519964350435, 9.997381467175912e-5] 181 | -------------------------------------------------------------------------------- /4_Potential_function_optimizing_in_weakly_convex_problems/test_code.jl: -------------------------------------------------------------------------------- 1 | ## Test code 2 | 3 | ## Include the main Julia file 4 | 5 | include("BnB-PEP-potential-minimization-weakly-convex-problems.jl") 6 | 7 | ## ## Parameters to use 8 | 9 | N = 3 10 | R = .1 11 | M = 1 12 | default_obj_val_upper_bound = 1e6 13 | ϵ_tol_feas = 1e-6 14 | ϵ_tol_Cholesky = 1e-4 15 | 16 | ## Feasible stepsize generation 17 | 18 | h_feas = feasible_h_generator(N, M, R; step_size_type = :Default) 19 | 20 | # ------------------------------------------------------- 21 | ## Stage 1 of the BnB-PEP Algorithm: solve the dual for the warm-starting stepsize 22 | # ------------------------------------------------------- 23 | 24 | 25 | d_star_feas, ℓ_1_norm_λ_feas, ℓ_1_norm_τ_feas, tr_Z_sum_feas, λ_feas, τ_feas, Z_feas, L_cholesky_feas, b_feas, c_feas, idx_set_λ_effective_feas, idx_set_τ_effective_feas = solve_dual_with_known_stepsizes(N, M, h_feas; show_output = :on, ϵ_tol_feas = 1e-6, 26 | objective_type = :default, obj_val_upper_bound = default_obj_val_upper_bound) 27 | 28 | ## store the warm start point for computing locally optimal solution 29 | 30 | d_star_ws, λ_ws, τ_ws, Z_ws, L_cholesky_ws, h_ws, b_ws, c_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective = d_star_feas, λ_feas, τ_feas, Z_feas, L_cholesky_feas, h_feas, b_feas, c_feas, idx_set_λ_effective_feas, idx_set_τ_effective_feas 31 | 32 | ## Computing the bounds for computing locally optimal solution to BnB-PEP 33 | 34 | M_tilde = 10 35 | 36 | # Compute M_λ 37 | 38 | d_star_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, tr_Z_sum_feas_1, λ_feas_1, τ_feas_1, Z_feas_1, L_cholesky_feas_1, b_feas_1, c_feas_1, idx_set_λ_effective_feas_1, idx_set_τ_effective_feas_1 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 39 | objective_type = :find_M_λ, obj_val_upper_bound = 1.001*d_star_ws) 40 | 41 | M_λ = M_tilde*maximum(λ_feas_1) 42 | 43 | ## Compute M_τ 44 | 45 | d_star_feas_2, ℓ_1_norm_λ_feas_2, ℓ_1_norm_τ_feas_2, tr_Z_sum_feas_2, λ_feas_2, τ_feas_2, Z_feas_2, L_cholesky_feas_2, b_feas_2, c_feas_2, idx_set_λ_effective_feas_2, idx_set_τ_effective_feas_2 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 46 | objective_type = :find_M_τ, obj_val_upper_bound = 1.001*d_star_ws) 47 | 48 | M_τ = M_tilde*maximum(τ_feas_2) 49 | 50 | ## Compute M_Z 51 | 52 | d_star_feas_3, ℓ_1_norm_λ_feas_3, ℓ_1_norm_τ_feas_3, tr_Z_sum_feas_3, λ_feas_3, τ_feas_3, Z_feas_3, L_cholesky_feas_3, b_feas_3, c_feas_3, idx_set_λ_effective_feas_3, idx_set_τ_effective_feas_3 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 53 | objective_type = :find_M_Z, obj_val_upper_bound = 1.001*d_star_ws) 54 | 55 | max_elm_Z_ws = [] 56 | 57 | for k in 0:N 58 | push!(max_elm_Z_ws, maximum(abs.(Z_feas_3[k]))) 59 | end 60 | 61 | M_Z = M_tilde*maximum(abs.(max_elm_Z_ws)) 62 | 63 | 64 | ## Compute M_cholesky 65 | 66 | M_L_cholesky = sqrt(M_Z) 67 | 68 | ## Compute M_h 69 | 70 | M_h = 5*M_tilde*maximum(abs.(h_ws)) 71 | 72 | ## compute M_b 73 | 74 | d_star_feas_4, ℓ_1_norm_λ_feas_4, ℓ_1_norm_τ_feas_4, tr_Z_sum_feas_4, λ_feas_4, τ_feas_4, Z_feas_4, L_cholesky_feas_4, b_feas_4, c_feas_4, idx_set_λ_effective_feas_4, idx_set_τ_effective_feas_4 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 75 | objective_type = :find_M_b, obj_val_upper_bound = 1.001*d_star_ws) 76 | 77 | M_b = M_tilde*maximum(b_feas_4) 78 | 79 | ## compute M_c 80 | 81 | d_star_feas_5, ℓ_1_norm_λ_feas_5, ℓ_1_norm_τ_feas_5, tr_Z_sum_feas_5, λ_feas_5, τ_feas_5, Z_feas_5, L_cholesky_feas_5, b_feas_5, c_feas_5, idx_set_λ_effective_feas_5, idx_set_τ_effective_feas_5 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 82 | objective_type = :find_M_c, obj_val_upper_bound = 1.001*d_star_ws) 83 | 84 | M_c = M_tilde*max(1,2*maximum(c_feas_5)) #2*max(1,maximum(c_feas_5)) 85 | 86 | @show [M_λ M_τ M_h M_Z M_L_cholesky M_b M_c] 87 | 88 | ## sparsify the solution for warm-starting locally optimal solver 89 | 90 | d_star_feas, ℓ_1_norm_λ_feas, ℓ_1_norm_τ_feas, tr_Z_sum_feas, λ_feas, τ_feas, Z_feas, L_cholesky_feas, b_feas, c_feas, idx_set_λ_effective_feas, idx_set_τ_effective_feas = solve_dual_with_known_stepsizes(N, M, h_ws; 91 | show_output = :on, 92 | ϵ_tol_feas = 1e-6, 93 | objective_type = :find_sparse_sol, 94 | obj_val_upper_bound = d_star_ws) 95 | 96 | # --------------------------------------------------- 97 | ## Stage 2 of the BnB-PEP Algorithm: compute the locally optimal point 98 | # ---------------------------------------------------- 99 | 100 | 101 | obj_val_loc_opt, 102 | λ_loc_opt, 103 | τ_loc_opt, 104 | Z_loc_opt, 105 | L_cholesky_loc_opt, 106 | b_loc_opt, 107 | c_loc_opt, 108 | Θ_loc_opt, 109 | h_loc_opt, 110 | idx_set_λ_loc_opt_effective, 111 | idx_set_τ_loc_opt_effective = BnB_PEP_solver( 112 | # different parameters to be used 113 | # ------------------------------ 114 | N, 115 | M, 116 | R, 117 | # solution to warm-start (Θ is warm-started internally) 118 | # ----------------------------------------------------- 119 | d_star_ws, 120 | λ_ws, 121 | τ_ws, 122 | Z_ws, 123 | L_cholesky_ws, 124 | h_ws, 125 | b_ws, 126 | c_ws, 127 | idx_set_λ_ws_effective, 128 | idx_set_τ_ws_effective, 129 | # bounds on the variables (M_Θ is computed internally) 130 | # ---------------------------------------------------- 131 | M_λ, 132 | M_τ, 133 | M_h, 134 | M_Z, 135 | M_L_cholesky, 136 | M_b, 137 | M_c; 138 | # options 139 | # ------- 140 | solution_type = :find_locally_optimal, # other option :find_globally_optimal 141 | show_output = :on, # other option :on 142 | local_solver = :knitro, #:ipopt, # :ipopt, # other option :knitro 143 | knitro_multistart = :off, # other option :on (only if :knitro solver is used) 144 | knitro_multi_algorithm = :off, # other option on (only if :knitro solver is used) 145 | reduce_index_set_for_dual_variables = :for_warm_start_only, 146 | reduce_index_set_for_L_cholesky = :off, # the other option is :on 147 | positive_step_size = :on, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 148 | find_global_lower_bound_via_cholesky_lazy_constraint = :off, # if this on, then we model Z = L_cholesky*L_cholesky^T via lazy constraint (the goal is to find a lower bound to BnB PEP) 149 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation, 150 | quadratic_equality_modeling = :exact, #:through_ϵ, # other option is :exact 151 | cholesky_modeling = :definition, #:formula, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 152 | ϵ_tol_feas = 1e-6, # tolerance for feasibility 153 | ϵ_tol_Cholesky = 0.0005, # tolerance for determining which elements of L_cholesky_ws is zero 154 | maxCutCount = 1e4, # this is the number of cuts to be added if the lazy constraint callback is activated 155 | global_lower_bound_given = :off, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 156 | global_lower_bound = 0.0, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 157 | polish_solution = :off, # wheather to polish the solution to get better precision, the other option is :off, 158 | M_Θ_factor = M_tilde, # factor by which to magnify the internal M_Θ 159 | impose_pattern = :on 160 | ) 161 | 162 | ## Test the linear constraint 163 | # 164 | # k = 0 165 | # 166 | # 𝐰, 𝐠, 𝐟 = data_generator_potential_pep(h_loc_opt,k; input_type = :stepsize_constant) 167 | # 168 | # term_1 = -(b_loc_opt[k+1]*a_vec(-1,3,𝐟) - b_loc_opt[k]*a_vec(-1,2,𝐟)) 169 | # 170 | # term_2 = sum(τ_loc_opt[i_k_idx(i,k)]*a_vec(i,-1,𝐟) for i in 0:3) 171 | # 172 | # term_3 = sum(λ_loc_opt[i_j_k_λ]*a_vec(i_j_k_λ.i,i_j_k_λ.j,𝐟) for i_j_k_λ in λ_loc_opt.axes[1] if i_j_k_λ.k == k) 173 | 174 | # Test the relationship between b and λ (comment out later) 175 | 176 | # k = 2 177 | # 178 | # b_loc_opt[k] - (4-λ_loc_opt[i_j_k_idx(2,0,k)] + b_loc_opt[k+1]) 179 | # 180 | # b_loc_opt[k+1] - λ_loc_opt[i_j_k_idx(2,3,k)] 181 | # 182 | # (2*h_loc_opt[k]*λ_loc_opt[i_j_k_idx(2,3,k)])-(λ_loc_opt[i_j_k_idx(2,0,k)]) 183 | # 184 | # c_loc_opt[k] - (h_loc_opt[k]^2*b_loc_opt[k+1]) 185 | # 186 | # b_loc_opt[k] - (4+((1-(2*h_loc_opt[k]))*b_loc_opt[k+1])) 187 | # 188 | # τ_loc_opt[i_k_idx(2,k)] - (b_loc_opt[k]-b_loc_opt[k+1]) 189 | # 190 | # bFlippedAnalytic(k,h) = (2/h)*(1-(1-2h)^k) 191 | # 192 | # bAnalytic(k,h) = (2/h)*(1-(1-2h)^(N+1-k)) 193 | # 194 | # b_loc_opt 195 | # 196 | # bAnalytic(N+1,h_loc_opt[k]) 197 | # 198 | # bAnalyticArray = [bAnalytic(i,h_loc_opt[0]) for i in 0:N+1] 199 | # 200 | # [b_loc_opt[i] for i in 0:N+1] - bAnalyticArray 201 | 202 | ## Store the solution to be warm-started for a next step 203 | 204 | d_star_ws, λ_ws, τ_ws, Z_ws, L_cholesky_ws, h_ws, b_ws, c_ws, idx_set_λ_ws_effective, idx_set_τ_ws_effective = obj_val_loc_opt, λ_loc_opt, τ_loc_opt, Z_loc_opt, L_cholesky_loc_opt, h_loc_opt, b_loc_opt, c_loc_opt, idx_set_λ_loc_opt_effective, idx_set_τ_loc_opt_effective 205 | 206 | h_ws = h_loc_opt 207 | 208 | ## update the entries of the bounds based on the heuristic 209 | 210 | ## Computing the bounds for computing locally optimal solution to BnB-PEP 211 | 212 | M_tilde = 1.01 213 | 214 | ## compute M_λ 215 | 216 | d_star_feas_1, ℓ_1_norm_λ_feas_1, ℓ_1_norm_τ_feas_1, tr_Z_sum_feas_1, λ_feas_1, τ_feas_1, Z_feas_1, L_cholesky_feas_1, b_feas_1, c_feas_1, idx_set_λ_effective_feas_1, idx_set_τ_effective_feas_1 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 217 | objective_type = :find_M_λ, obj_val_upper_bound = 1.001*d_star_ws) 218 | 219 | M_λ = M_tilde*maximum(λ_feas_1) 220 | 221 | ## Compute M_τ 222 | 223 | d_star_feas_2, ℓ_1_norm_λ_feas_2, ℓ_1_norm_τ_feas_2, tr_Z_sum_feas_2, λ_feas_2, τ_feas_2, Z_feas_2, L_cholesky_feas_2, b_feas_2, c_feas_2, idx_set_λ_effective_feas_2, idx_set_τ_effective_feas_2 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 224 | objective_type = :find_M_τ, obj_val_upper_bound = 1.001*d_star_ws) 225 | 226 | M_τ = M_tilde*maximum(τ_feas_2) 227 | 228 | ## Compute M_Z 229 | 230 | d_star_feas_3, ℓ_1_norm_λ_feas_3, ℓ_1_norm_τ_feas_3, tr_Z_sum_feas_3, λ_feas_3, τ_feas_3, Z_feas_3, L_cholesky_feas_3, b_feas_3, c_feas_3, idx_set_λ_effective_feas_3, idx_set_τ_effective_feas_3 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 231 | objective_type = :find_M_Z, obj_val_upper_bound = 1.001*d_star_ws) 232 | 233 | max_elm_Z_ws = [] 234 | 235 | for k in 0:N 236 | push!(max_elm_Z_ws, maximum(abs.(Z_feas_3[k]))) 237 | end 238 | 239 | M_Z = M_tilde*maximum(abs.(max_elm_Z_ws)) 240 | 241 | 242 | ## Compute M_cholesky 243 | 244 | M_L_cholesky = sqrt(M_Z) 245 | 246 | ## Compute M_h 247 | 248 | M_h = 5*M_tilde*maximum(abs.(h_ws)) 249 | 250 | ## compute M_b 251 | 252 | d_star_feas_4, ℓ_1_norm_λ_feas_4, ℓ_1_norm_τ_feas_4, tr_Z_sum_feas_4, λ_feas_4, τ_feas_4, Z_feas_4, L_cholesky_feas_4, b_feas_4, c_feas_4, idx_set_λ_effective_feas_4, idx_set_τ_effective_feas_4 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 253 | objective_type = :find_M_b, obj_val_upper_bound = 1.001*d_star_ws) 254 | 255 | M_b = M_tilde *maximum(b_feas_4) 256 | 257 | ## compute M_c 258 | 259 | d_star_feas_5, ℓ_1_norm_λ_feas_5, ℓ_1_norm_τ_feas_5, tr_Z_sum_feas_5, λ_feas_5, τ_feas_5, Z_feas_5, L_cholesky_feas_5, b_feas_5, c_feas_5, idx_set_λ_effective_feas_5, idx_set_τ_effective_feas_5 = solve_dual_with_known_stepsizes(N, M, h_ws; show_output = :off, ϵ_tol_feas = 1e-6, 260 | objective_type = :find_M_c, obj_val_upper_bound = 1.001*d_star_ws) 261 | 262 | M_c = M_tilde*max(1,2*maximum(c_feas_5)) #2*max(1,maximum(c_feas_5)) 263 | 264 | 265 | 266 | ## Compute global lower bound via lazy callback 267 | 268 | obj_val_glb_lbd, 269 | λ_glb_lbd, 270 | τ_glb_lbd, 271 | Z_glb_lbd, 272 | L_cholesky_glb_lbd, 273 | b_glb_lbd, 274 | c_glb_lbd, 275 | Θ_glb_lbd, 276 | h_glb_lbd, 277 | idx_set_λ_glb_lbd_effective, 278 | idx_set_τ_glb_lbd_effective = BnB_PEP_solver( 279 | # different parameters to be used 280 | # ------------------------------ 281 | N, 282 | M, 283 | R, 284 | # solution to warm-start (Θ is warm-started internally) 285 | # ----------------------------------------------------- 286 | d_star_ws, 287 | λ_ws, 288 | τ_ws, 289 | Z_ws, 290 | L_cholesky_ws, 291 | h_ws, 292 | b_ws, 293 | c_ws, 294 | idx_set_λ_ws_effective, 295 | idx_set_τ_ws_effective, 296 | # bounds on the variables (M_Θ is computed internally) 297 | # ---------------------------------------------------- 298 | M_λ, 299 | M_τ, 300 | M_h, 301 | M_Z, 302 | M_L_cholesky, 303 | M_b, 304 | M_c; 305 | # options 306 | # ------- 307 | solution_type = :find_globally_optimal, # other option :find_globally_optimal 308 | show_output = :on, # other option :on 309 | local_solver = :ipopt, # :ipopt, # other option :knitro 310 | knitro_multistart = :off, # other option :on (only if :knitro solver is used) 311 | knitro_multi_algorithm = :off, # other option on (only if :knitro solver is used) 312 | reduce_index_set_for_dual_variables = :for_warm_start_only, # other options are :on and :off 313 | reduce_index_set_for_L_cholesky = :off, # the other option is :on 314 | positive_step_size = :on, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 315 | find_global_lower_bound_via_cholesky_lazy_constraint = :on, # if this on, then we model Z = L_cholesky*L_cholesky^T via lazy constraint (the goal is to find a lower bound to BnB PEP) 316 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation, 317 | quadratic_equality_modeling = :exact, #:through_ϵ, #:through_ϵ, # other option is :exact 318 | cholesky_modeling = :formula, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 319 | ϵ_tol_feas = 1e-6, # tolerance for feasibility 320 | ϵ_tol_Cholesky = 0.0005, # tolerance for determining which elements of L_cholesky_ws is zero 321 | maxCutCount = 1e3, # this is the number of cuts to be added if the lazy constraint callback is activated 322 | global_lower_bound_given = :off, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 323 | global_lower_bound = 0.0, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 324 | polish_solution = :off, # wheather to polish the solution to get better precision, the other option is :off, 325 | M_Θ_factor = 1.1, # factor by which to magnify the internal M_Θ 326 | impose_pattern = :on 327 | ) 328 | 329 | 330 | # ---------------------------------------------------- 331 | ## Stage 3 of the BnB-PEP Algorithm: find the globally optimal solution to the BnB-PEP-QCQP 332 | # ---------------------------------------------------- 333 | 334 | 335 | obj_val_glb_opt, 336 | λ_glb_opt, 337 | τ_glb_opt, 338 | Z_glb_opt, 339 | L_cholesky_glb_opt, 340 | b_glb_opt, 341 | c_glb_opt, 342 | Θ_glb_opt, 343 | h_glb_opt, 344 | idx_set_λ_glb_opt_effective, 345 | idx_set_τ_glb_opt_effective = BnB_PEP_solver( 346 | # different parameters to be used 347 | # ------------------------------ 348 | N, 349 | M, 350 | R, 351 | # solution to warm-start (Θ is warm-started internally) 352 | # ----------------------------------------------------- 353 | d_star_ws, 354 | λ_ws, 355 | τ_ws, 356 | Z_ws, 357 | L_cholesky_ws, 358 | h_ws, 359 | b_ws, 360 | c_ws, 361 | idx_set_λ_ws_effective, 362 | idx_set_τ_ws_effective, 363 | # bounds on the variables (M_Θ is computed internally) 364 | # ---------------------------------------------------- 365 | M_λ, 366 | M_τ, 367 | M_h, 368 | M_Z, 369 | M_L_cholesky, 370 | M_b, 371 | M_c; 372 | # options 373 | # ------- 374 | solution_type = :find_globally_optimal, # other option :find_globally_optimal 375 | show_output = :on, # other option :on 376 | local_solver = :ipopt, # :ipopt, # other option :knitro 377 | knitro_multistart = :off, # other option :on (only if :knitro solver is used) 378 | knitro_multi_algorithm = :off, # other option on (only if :knitro solver is used) 379 | reduce_index_set_for_dual_variables = :off, # :for_warm_start_only, 380 | reduce_index_set_for_L_cholesky = :off, # the other option is :on 381 | positive_step_size = :on, # other option is :on (i.e., making it :on will enforce the stepsize to be non-negative, which will turn BnB-PEP solver into a heuristic), 💀 turning it :on is not recommended 382 | find_global_lower_bound_via_cholesky_lazy_constraint = :off, # if this on, then we model Z = L_cholesky*L_cholesky^T via lazy constraint (the goal is to find a lower bound to BnB PEP) 383 | bound_impose = :on, # if this is :on, then from the warm_start solution we compute lower and upper bounds for the decision variables using the semidefinite relaxation, 384 | quadratic_equality_modeling = :exact, #:through_ϵ, # other option is :exact 385 | cholesky_modeling = :formula, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 386 | ϵ_tol_feas = 1e-6, # tolerance for feasibility 387 | ϵ_tol_Cholesky = 0.0005, # tolerance for determining which elements of L_cholesky_ws is zero 388 | maxCutCount = 1e3, # this is the number of cuts to be added if the lazy constraint callback is activated 389 | global_lower_bound_given = :on, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 390 | global_lower_bound = obj_val_glb_lbd, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 391 | polish_solution = :off, # wheather to polish the solution to get better precision, the other option is :off, 392 | M_Θ_factor = 1.1, # factor by which to magnify the internal M_Θ 393 | impose_pattern = :on # Caution if impose_pattern == :on, keep reduce_index_set_for_dual_variables = :off and reduce_index_set_for_L_cholesky = :off, and vice versa 394 | ) 395 | 396 | 397 | 398 | ## 399 | -------------------------------------------------------------------------------- /Misc/stpszs.jl: -------------------------------------------------------------------------------- 1 | ## Locally optimal stepsize vector for N=1; 2 | 3 | ##------------------------------; 4 | 5 | h_1 = [1.4999999210629629]; 6 | 7 | ## Locally optimal stepsize vector for N=2; 8 | 9 | ##------------------------------; 10 | 11 | h_2 = [1.4142136527967577, 1.8767680682248675]; 12 | 13 | ## Locally optimal stepsize vector for N=3; 14 | 15 | ##------------------------------; 16 | 17 | h_3 = [1.4142144091492264, 2.414208339844569, 1.500000462437766]; 18 | 19 | ## Locally optimal stepsize vector for N=4; 20 | 21 | ##------------------------------; 22 | 23 | h_4 = [1.414214, 1.601232, 3.005144, 1.5]; 24 | 25 | ## Locally optimal stepsize vector for N=5; 26 | 27 | ##------------------------------; 28 | 29 | h_5 = [1.414214, 2.0, 1.414214, 3.557647, 1.5]; 30 | 31 | ## Locally optimal stepsize vector for N=6; 32 | 33 | ##------------------------------; 34 | 35 | h_6 = [1.6012300929266492, 1.4142176845862175, 3.7191663034855567, 1.4142216029725352, 1.6012255538809508, 2.1888255519960196]; 36 | 37 | ## Locally optimal stepsize vector for N=7; 38 | 39 | ##------------------------------; 40 | 41 | h_7 = [1.6012326607370193, 1.4142183813382985, 2.2605675429124905, 1.414214577958452, 4.826920575623034, 1.4142155048032368, 1.8767663274138684]; 42 | 43 | ## Locally optimal stepsize vector for N=8; 44 | 45 | ##------------------------------; 46 | 47 | h_8 = [1.4142260345941442, 1.9999954569447265, 1.4142163917732418, 2.9794039151459266, 1.6012212088909783, 1.4142245477733064, 4.964412117876488, 1.500000626975218]; 48 | 49 | ## Locally optimal stepsize vector for N=9; 50 | 51 | ##------------------------------; 52 | 53 | h_9 = [1.6012311339283445, 1.4142333308691475, 2.2605410405082544, 1.4142179185808277, 5.7845675259464, 1.4142207838755536, 2.674512700022901, 1.4142204599558477, 1.8767665285664457]; 54 | 55 | ## Locally optimal stepsize vector for N=10; 56 | 57 | ##------------------------------; 58 | 59 | h_10 = [1.601224406823249, 1.4142269348335696, 2.979419832958444, 1.4142230479383013, 1.9999917508781457, 1.4142137339937706, 6.883591307839643, 1.4142187397712072, 2.414191543331326, 1.5000031521379187]; 60 | 61 | ## Locally optimal stepsize vector for N=11; 62 | 63 | ##------------------------------; 64 | 65 | h_11 = [1.6012184627647943, 1.4142334847876532, 3.4141294418919994, 1.4142265800546767, 2.000033158544334, 1.414216217183766, 2.4514394713763346, 1.4142167219250152, 7.149044294761066, 1.4142182104810823, 1.8767634603482573]; 66 | 67 | ## Locally optimal stepsize vector for N=12; 68 | 69 | ##------------------------------; 70 | 71 | h_12 = [1.4142353094718887, 2.4513612181900983, 1.4142471995391792, 2.000008642812234, 1.4142158600696018, 7.445135389235387, 1.414240663346553, 1.999968065656365, 1.4142179518967448, 4.172814857799279, 1.4142288857867302, 1.8767571735764537]; 72 | 73 | ## Locally optimal stepsize vector for N=13; 74 | 75 | ##------------------------------; 76 | 77 | h_13 = [1.6012552008209224, 1.414282536387252, 2.2604336645261767, 1.4142257616569167, 4.885327245969352, 1.6012247244556845, 1.414258243630367, 2.9792595146138576, 1.4143147344439224, 1.999920202248278, 1.414196389834401, 6.9126910644978175, 1.500006878193675]; 78 | 79 | ## Locally optimal stepsize vector for N=14; 80 | 81 | ##------------------------------; 82 | 83 | h_14 = [1.6011830618674123, 1.414301105213751, 2.979292728889659, 1.4142624396201617, 1.9999608093632555, 1.414216748754149, 8.697629733780435, 1.4143756997617771, 1.6010940635230428, 2.2610188881412596, 1.4142275765489727, 2.5872820438083184, 1.4142249152323982, 3.180434175827493]; 84 | 85 | ## Locally optimal stepsize vector for N=15; 86 | 87 | ##------------------------------; 88 | 89 | h_15 = [1.6011452849329992, 1.4143559802274681, 2.9793080608422597, 1.4142869805528666, 1.9999293134495792, 1.414217703680261, 5.41819064627181, 1.414251559999807, 2.4509305132269055, 1.414343529592472, 2.0001297240770506, 1.4142016052755357, 9.19808906765696, 1.4142360705932655, 1.8767455202310255]; 90 | 91 | ## Locally optimal stepsize vector for N=16; 92 | 93 | ##------------------------------; 94 | 95 | h_16 = [1.6012780958122796, 1.4143314565697052, 2.260298658520155, 1.4142350693299588, 5.6095179947294005, 1.6011989855365694, 1.4143043860157416, 3.5760432828297812, 1.4143057252378808, 2.000004167183858, 1.4142175106778454, 2.9803282809368197, 1.6007498305756025, 1.4145646012913373, 7.8995258645030315, 1.5000145128521007]; 96 | 97 | ## Locally optimal stepsize vector for N=17; 98 | 99 | ##------------------------------; 100 | 101 | h_17 = [1.601090959821508, 1.4144352847301846, 2.9791528143681716, 1.414317261346118, 1.9999083412295158, 1.4142125315122054, 6.669376714546105, 1.6011531762658755, 1.414379449397543, 2.663991404562482, 1.4147645470276546, 1.6005555604060866, 3.4124572877482646, 1.6004710422448782, 1.4147341717932223, 8.256849185774536, 1.5000190568256546]; 102 | 103 | ## Locally optimal stepsize vector for N=18; 104 | 105 | ##------------------------------; 106 | 107 | h_18 = [1.6011893859171968, 1.4142843529646747, 2.9792813939451506, 1.4142460076205512, 1.9999686201924212, 1.41421900234158, 9.799607124508029, 1.4142332041091843, 2.451345595422608, 1.4142516655783877, 2.000023033658437, 1.4142129514771555, 7.0291189206458755, 1.4142479633022167, 2.2606008358664944, 1.4142436749519474, 1.6012097714875895, 2.7266067054635705]; 108 | 109 | ## Locally optimal stepsize vector for N=19; 110 | 111 | ##------------------------------; 112 | 113 | h_19 = [1.6010423501019335, 1.4145196300484633, 2.979044996164088, 1.4143553898645498, 1.9998598516384003, 1.4142192133242881, 6.667872717162003, 1.4143377465205942, 2.000890428701081, 1.414245497602413, 2.450419103152237, 1.4142491151450531, 3.4128668087789262, 1.4152041067051473, 1.5999089003301372, 12.28066434838983, 1.4143455654164023, 1.6011311948350766, 2.188741337646666]; 114 | 115 | ## Locally optimal stepsize vector for N=20; 116 | 117 | ##------------------------------; 118 | 119 | h_20 = [1.6009116761102526, 1.4146114976696553, 3.413305795634835, 1.4143855093101274, 2.0006489057132075, 1.4142510838773608, 2.4505198897660274, 1.4142227765930024, 7.190649742614982, 1.414323405472593, 2.2608183100312558, 1.4152309452410137, 1.600027719473019, 3.2161984144991616, 1.5998060634093048, 1.415192204128364, 12.798950809514734, 1.4143565088331467, 1.6011240492928513, 2.1887253346679634]; 120 | 121 | ## Locally optimal stepsize vector for N=21; 122 | 123 | ##------------------------------; 124 | 125 | h_21 = [1.6008936066412038, 1.4145953588234756, 3.4132399973728904, 1.4143043995512696, 2.450854566411019, 1.4143934401593792, 2.000095534724163, 1.4142320390305645, 12.480371831423259, 1.6012619016433214, 1.4144224030430421, 2.2622483515946676, 1.4142726790081224, 2.58510875933713, 1.4142599119655737, 7.896345612998376, 1.4143466310886157, 2.260818558130245, 1.4143725054901288, 1.6010846109257393, 2.725915419258379]; 126 | 127 | ## Locally optimal stepsize vector for N=22; 128 | 129 | ##------------------------------; 130 | 131 | h_22 = [1.601096412274911, 1.4143723731186688, 3.4137866670199313, 1.4142535259813818, 2.4512741949541446, 1.4142844543417532, 2.0000112439328195, 1.4142282560219772, 12.766387052511593, 1.4142668481311924, 1.9999985522296777, 1.414226127341901, 3.413833337962595, 1.4143144556439147, 1.9998825329478767, 1.414204796622049, 8.853044348575066, 1.4142699817327227, 2.2606098863858115, 1.4142613577306569, 1.6011987753482781, 2.7265037132283663]; 132 | 133 | ## Locally optimal stepsize vector for N=23; 134 | 135 | ##------------------------------; 136 | 137 | h_23 = [1.601100645756741, 1.4143824610164948, 3.4136615797286196, 1.4142811871589154, 2.000232005728548, 1.4142339915284245, 2.4511256293363237, 1.4142233260844315, 13.005445614891139, 1.6012744074363086, 1.414313220711643, 2.260436199731083, 1.4142388304369593, 4.558792714236304, 1.4143168842286593, 2.000550406152943, 1.4142202986118377, 2.450493687219217, 1.414231613921239, 9.44439636982949, 1.4142978226816678, 1.6011738758563925, 2.1887798645602365]; 138 | 139 | ## Locally optimal stepsize vector for N=24; 140 | 141 | ##------------------------------; 142 | 143 | h_24 = [1.6012547782230548, 1.4143680559595941, 2.2602955951875403, 1.414243765381817, 5.171325931703084, 1.414288642499394, 1.9999843515188434, 1.4142260897168477, 3.4138282992236935, 1.4143925289248378, 1.9997575839616901, 1.4142057858553114, 17.05782649223543, 1.4144025206830748, 1.6015407920057165, 1.7017368298617106, 3.3907534707672657, 1.4143409281563557, 1.9998527165320235, 1.4141912979382152, 7.508433144045916, 1.4143147358498585, 1.6011528935748691, 2.1887759255372483]; 144 | 145 | ## Locally optimal stepsize vector for N=25; 146 | 147 | ##------------------------------; 148 | 149 | h_25 = [1.6007515116515938, 1.4149407281723974, 2.9782435307510005, 1.4145238371137783, 1.9995909398399123, 1.4142216140426431, 7.8616206481004465, 1.6012009537764098, 1.4148041921328138, 2.2595928425116134, 1.414318232283614, 5.167333630841824, 1.4145447841144176, 1.9998029861163944, 1.414318004341104, 3.411608550219099, 1.4157268846762319, 1.9976250887324316, 1.4143152195851727, 17.932913507569996, 1.414383472626355, 1.9998260444134914, 1.4142374871812793, 3.5567547347326642, 1.5000517123909558]; 150 | 151 | ## Locally optimal stepsize vector for N=26; 152 | 153 | ##------------------------------; 154 | 155 | h_26 = [1.600710881607143, 1.4150093233713295, 2.978122647071361, 1.414545147018181, 1.9995254152132305, 1.4142426987001477, 8.096216448223721, 1.4145138261087902, 2.000015697907071, 1.4142595774330875, 3.412833433012788, 1.4151395866912706, 1.9984510347737345, 1.4142307898563962, 5.773790057388543, 1.4149291802257888, 2.006127476583084, 1.4145028644709376, 2.439729243813605, 1.4143283379628218, 18.295160340650877, 1.4143393355627145, 2.827263294923399, 1.6011741838545834, 1.4143940693263126, 2.188924751886103]; 156 | 157 | ## Locally optimal stepsize vector for N=27; 158 | 159 | ##------------------------------; 160 | 161 | h_27 = [1.6009890982742996, 1.4145337922285035, 2.9796797191088795, 1.4143138674212052, 1.9998676831017252, 1.4142409389766932, 4.288709914594402, 1.4143435231529853, 1.999719649188748, 1.414239414502185, 16.234073530553943, 1.4143030672580887, 2.0000009068577103, 1.414236283081719, 3.4135182847099013, 1.4143940546046647, 1.9997736815622862, 1.4142022232465605, 10.219237168116248, 1.4143012173634417, 1.999914109116094, 1.4142268239620508, 4.888940935239365, 1.4143230784225511, 2.0000692387276007, 1.4142164009576257, 2.4749842353418576]; 162 | 163 | ## Locally optimal stepsize vector for N=28; 164 | 165 | ##------------------------------; 166 | 167 | h_28 = [1.6005375210524635, 1.4152251314338193, 2.9777769707546002, 1.4145879963549752, 1.9994639414170716, 1.4142647564570017, 8.090309638556207, 1.4144553036507446, 2.203439694018971, 1.4143197331192112, 2.210250880719624, 1.4143119413220981, 5.764811867433829, 1.4146368106978717, 1.999538870376065, 1.414374980692087, 3.408979771546222, 1.4163565463222167, 1.9966642752611787, 1.4143755718996587, 21.226410833713082, 1.4144500139912715, 1.9997180657214289, 1.414246376249571, 4.578642362502237, 1.601160634971309, 1.4144502991848988, 2.1887460552555686]; 168 | 169 | ## Locally optimal stepsize vector for N=29; 170 | 171 | ##------------------------------; 172 | 173 | h_29 = [1.6002927586808298, 1.415525651370906, 2.978712753272001, 1.4146483873338824, 1.9993191237553913, 1.4142947235732442, 5.889926503311145, 1.4146409622395584, 2.000172363789169, 1.414283511675743, 2.9729190568386348, 1.5008591830824594, 1.499296575406973, 8.921933099484614, 1.4147316595899222, 1.9995709976477156, 1.4143174118051058, 3.4071452294748665, 1.4166281882335146, 1.9960997366954825, 1.4144349780169319, 22.087592098611406, 1.4148959848491875, 1.6006809049779425, 2.659932119387521, 1.5038925744302711, 1.4961833858252167, 4.508612436337461, 1.5000137463448708]; 174 | 175 | ## Locally optimal stepsize vector for N=30; 176 | 177 | ##------------------------------; 178 | 179 | h_30 = [1.6003654170632955, 1.415412937398086, 2.9783432517185524, 1.4146131985550692, 1.9992959016362932, 1.4143398224977368, 6.319380651155119, 1.4145881822391186, 1.9997921288944214, 1.4143449089369788, 3.4096895584855575, 1.4158810644596762, 1.9971170825470583, 1.4144288889740995, 21.275005564392014, 1.4145490233016664, 2.260194119522961, 1.4153694634949203, 1.60008363735125, 4.1813506884524765, 1.414412507899433, 2.259849143572253, 1.5946347024649916, 1.4188554824409338, 10.474765395944672, 1.4145085555575794, 2.261260887414666, 1.5019980981369183, 1.4981104943953742, 2.7197676435574483]; 180 | 181 | ## Locally optimal stepsize vector for N=31; 182 | 183 | ##------------------------------; 184 | 185 | h_31 = [1.6009012767622817, 1.4147234871567058, 2.9787995552662503, 1.4143870880225942, 1.999696704001685, 1.4142513035514515, 7.328860103820718, 1.4143838897158825, 2.001211641417877, 1.4142665477271397, 2.4496013435103925, 1.4142341112172974, 4.553957904836446, 1.4143474703788648, 2.258065036449293, 1.4975526778628745, 1.5026603506063485, 10.75324274121008, 1.4144255286090968, 1.9998161571966548, 1.4142188479749676, 3.7507947439676665, 1.4177050547920576, 1.5973554134045371, 2.260003840742824, 1.4141277354779866, 19.958849844665774, 1.4143135488459455, 2.0000080184804006, 1.4142253317709903, 2.4750161044880885]; 186 | 187 | ## Locally optimal stepsize vector for N=32; 188 | 189 | ##------------------------------; 190 | 191 | h_32 = [1.5998648806704898, 1.4159103518613492, 2.980901875031469, 1.4147004874157703, 1.99919979933615, 1.4143224531352712, 4.280786079037718, 1.4151882728564518, 1.9977551812705419, 1.414323583969701, 17.220707295291188, 1.41462126240323, 2.0027042730130953, 1.4143377280860787, 2.446904932326078, 1.4143272698240925, 5.7687555993211435, 1.4149285150157755, 1.999721183345221, 1.414284505786265, 3.4071753538041363, 1.4174297689410846, 1.9946854401843364, 1.414425303264432, 15.628155849240517, 1.4146410329286407, 2.0025817268269464, 1.414302455423245, 2.4469543357049055, 1.4143159409840016, 4.511773095814449, 1.500120716248855]; 192 | 193 | ## Locally optimal stepsize vector for N=33; 194 | 195 | ##------------------------------; 196 | 197 | h_33 = [1.5997766274842133, 1.4161764537038088, 2.9789426611728733, 1.414799112039579, 1.999054808384089, 1.4143141303243114, 5.410172879202292, 1.4145221055930162, 2.4399737540240967, 1.4159500053949285, 2.003526314565949, 1.4143915121124566, 12.648284551209473, 1.4145391287008235, 2.4463053551938785, 1.41577027265032, 2.000446309187309, 1.4146214560677577, 4.047289403020011, 1.416447582629537, 1.991573439856216, 1.4151753773639664, 5.586439928740523, 1.5176780746836187, 1.4854663520997813, 2.253909368628828, 1.4135277156353798, 22.790819182294367, 1.6010515463304964, 1.414634611427034, 3.44049810403578, 1.4143813706769115, 1.8768416160383037]; 198 | 199 | ## Locally optimal stepsize vector for N=34; 200 | 201 | ##------------------------------; 202 | 203 | h_34 = [1.6008430923354466, 1.4147891665421979, 2.978796819272509, 1.4143872925369763, 1.9997652200105829, 1.4142550974743404, 6.953400165019456, 1.4142920892078152, 2.7898478190485747, 1.4143265417426372, 2.46126388245335, 1.4144417239469067, 1.999273202604643, 1.4144126539059414, 2.734827249978152, 1.4142784185099557, 24.42600656424854, 1.4144017494879677, 2.0001720315248237, 1.414272445210797, 2.9743418739602125, 1.50045258592433, 1.4996255067178146, 5.890463885428819, 1.6010167328258618, 1.414509675427336, 2.977387825860003, 1.4151477895111195, 1.999049996000295, 1.4141341873575843, 11.213704785790922, 1.6012127795045126, 1.414344893439503, 2.1887177690210633]; 204 | 205 | ## Locally optimal stepsize vector for N=35; 206 | 207 | ##------------------------------; 208 | 209 | h_35 = [1.6007862140215436, 1.4148577223714744, 2.9785858278379567, 1.4144082557753213, 1.9997794745595157, 1.4142402622065617, 8.02600475041799, 1.4143165530007553, 2.7975706465681225, 1.4143566732293982, 2.467122857124626, 1.414489008308242, 1.9991675314429624, 1.4144414619753634, 2.720777423722706, 1.4142814236450503, 4.798874961858089, 1.415265315169822, 1.9978590614933192, 1.4143009998055376, 27.436134182456108, 1.6043805291826405, 1.414562825285957, 1.698673445918, 2.9630859910567233, 1.4152307632851306, 1.599965160557248, 4.274124309027505, 1.414792645696098, 1.999111791608517, 1.4140820713213729, 9.403691550635742, 1.6012014988183731, 1.4143584340561772, 2.1887155774412803]; 210 | 211 | ## Locally optimal stepsize vector for N=36; 212 | 213 | ##------------------------------; 214 | 215 | h_36 = [1.5993567621591407, 1.4166808984690136, 2.976815421418033, 1.4149409848655763, 1.998439819244633, 1.41448795736843, 7.0303952078205585, 1.4148233855338874, 1.9996333134202804, 1.414342002752839, 4.028589059657193, 1.4148119577473395, 2.167106003504827, 1.414375413506481, 2.2476719340222533, 1.414579755471762, 8.630085787712558, 1.415269074969654, 1.9971632182116559, 1.4152588033681148, 2.9666332421516977, 1.5061059268112498, 1.4939563307704675, 29.207705790513312, 1.4147424846947512, 2.258864088065915, 1.4977602130663232, 1.5028050987918349, 3.7460154760532807, 1.416130961507448, 1.9969213584179242, 1.4138146449632507, 8.17883202117262, 1.4150498531438183, 1.600528178477736, 2.1884932207706855]; 216 | 217 | ## Locally optimal stepsize vector for N=37; 218 | 219 | ##------------------------------; 220 | 221 | h_37 = [1.5997692403150428, 1.4161659460283151, 2.977408664110061, 1.4147863879027809, 1.9988969659752296, 1.4143952017426986, 6.680781146636308, 1.4147111490859454, 1.9996820185146817, 1.4143193702673618, 3.748625487497692, 1.4147102539077236, 2.257591176318092, 1.4245265027467178, 1.588785403388544, 24.055854637298978, 0.00038118319243192776, 0.00021876237453662337, 1.4155071939518507, 1.9975323508713063, 1.414289199752659, 4.0347192640315, 1.5084436266740897, 1.4921566013697591, 2.6591949193993436, 1.5825481445352907, 1.427294212292109, 6.325802538932765, 1.5095756463230876, 1.4908190742115182, 2.6570746883456398, 1.5719481702607452, 1.43544050317854, 12.259628596074716, 1.4148276608825583, 1.600784641477842, 2.1885196395827764]; 222 | 223 | ## Locally optimal stepsize vector for N=38; 224 | 225 | ##------------------------------; 226 | 227 | h_38 = [1.4155002425369236, 1.9989936512592401, 1.4145330843309538, 3.408590829069846, 1.4151047432919643, 1.9973187063841917, 1.4145242086975205, 9.609349513546082, 1.4149591510626216, 1.9994617340500331, 1.4143687114225911, 4.028797253759505, 1.4149108863549944, 2.165687223009185, 1.4143162502958033, 2.2501946039070453, 1.4145223164486027, 7.002920073055802, 1.4154079942780464, 1.9947620747389838, 1.4160460412128741, 2.964264531411844, 1.5067644073105697, 1.4931818183959376, 31.196455409151977, 1.6007326256486116, 1.4155464689190997, 2.661909050785873, 1.5037266729610206, 1.4964203001033847, 4.029914426911501, 1.4178134637420061, 1.9937544134846648, 1.4136239469795377, 8.805268586872314, 1.415162136787419, 1.6004402286568131, 2.188439862703244]; 228 | 229 | ## Locally optimal stepsize vector for N=39; 230 | 231 | ##------------------------------; 232 | 233 | h_39 = [1.600595973564461, 1.4150982019926557, 2.9786078947052808, 1.4144507815783804, 1.9996381217293184, 1.4142967607745143, 6.950070868424125, 1.414329485544287, 2.813168593487037, 1.4143527665871687, 2.5253687675462757, 1.4145359605875392, 1.9987451271848051, 1.414487821475068, 2.640743245587536, 1.4142821112400983, 26.154176864376776, 1.4144530724045226, 1.999798583447871, 1.4142621201931742, 4.274072516872105, 1.4144059314588067, 2.382801746366226, 1.5006480520357728, 1.4994371334021166, 2.499677338871729, 1.3939424701515712, 14.569141844796198, 1.6009227067559546, 1.414757815276279, 3.272518349392588, 1.414556535532682, 1.9992422061472503, 1.414367462485523, 3.241683158343338, 1.503457246895429, 1.4965963311268198, 6.138721732488466, 1.5000581407225893]; 234 | 235 | ## Locally optimal stepsize vector for N=40; 236 | 237 | ##------------------------------; 238 | 239 | h_40 = [1.41543744756978, 1.9990380390131512, 1.4145130851455807, 3.4097512435832047, 1.4149333499412857, 1.997998967926543, 1.4144672122658863, 8.824260788488223, 1.414544107898623, 2.811226536512002, 1.4146308361361917, 2.5509503419568156, 1.4153711124237134, 1.9948673055615684, 1.4155946148883898, 2.6125686834466886, 1.4143899469600663, 4.788567313051487, 1.420876831800345, 1.9861232660063364, 1.4147423599756304, 29.93273115280763, 0.0004681578473879134, 0.0002661227278550633, 1.4157125835641602, 1.9980515360953757, 1.4144095981217644, 2.974380827352609, 1.421073452669013, 1.5924305964281138, 5.403549889395542, 1.414614339777705, 2.4085547623509647, 1.4186133349039414, 2.0203558691689905, 1.414437314333217, 10.616560542556414, 1.6010944513618097, 1.4147610813870655, 2.188422919113617]; 240 | 241 | ## Locally optimal stepsize vector for N=41; 242 | 243 | ##------------------------------; 244 | 245 | h_41 = [1.5988164707582782, 1.417362899608668, 2.9750176479892128, 1.4151209235971427, 1.997838485930838, 1.4146479652597816, 8.235389895749567, 1.415022099482422, 1.9993721160226712, 1.4144310108954075, 4.0658265014515385, 1.4148686105433859, 2.415911239188622, 1.4182442825581767, 2.0094637320795212, 1.4163213587221024, 5.583251499658983, 1.4146909601323627, 2.254327207516568, 1.4966728159377576, 1.5049368906311031, 31.788114208347498, 1.6013286496578212, 1.416285770792525, 2.2578178663628536, 1.4144584843772212, 4.193396585417043, 1.4148595437938698, 2.2538141886769414, 1.4955330827163553, 1.5061103137940488, 5.571351098824316, 1.525389196944872, 1.479939022179087, 2.2496353972820966, 1.4134144795784342, 13.064031525403617, 1.4148849711424565, 2.0015381167386974, 1.414231419894712, 2.4709820112168925]; 246 | 247 | ## Locally optimal stepsize vector for N=42; 248 | 249 | ##------------------------------; 250 | 251 | h_42 = [1.5985331618624563, 1.4176529024834976, 2.9742965727217925, 1.4151800473512037, 1.997664286231081, 1.4147025573619258, 8.594375314586879, 1.4150451064837055, 1.9990222256523151, 1.4144671536842552, 4.911612291489882, 1.6011508351955612, 1.415226586293632, 3.378419520261731, 1.4155460310499446, 2.045990062358746, 1.4152716641097074, 2.400958774638821, 1.4151159416927792, 4.901117702195977, 1.4213335026356624, 1.9879297164977574, 1.4131376371337925, 33.35949855106227, 1.6010876106306111, 1.416655807744716, 2.2583002287812484, 1.414425591105634, 3.7484617078823415, 1.4183415811635265, 1.9911502858106034, 1.4141296901414595, 6.0150723770576935, 1.414585316702246, 2.4212207638599677, 1.5271169318661788, 1.4756040168480584, 1.7068655025625743, 11.689443743781446, 1.6010929462944523, 1.414849072202828, 2.1882844610260017]; 252 | 253 | ## Locally optimal stepsize vector for N=43; 254 | 255 | ##------------------------------; 256 | 257 | h_43 = [1.5972196900636433, 1.419197101838935, 2.9857945857200976, 1.4153916182355992, 1.9980171481883475, 1.414512464652121, 4.269147830034994, 1.4159667610334703, 1.9930316230800256, 1.4150003237436035, 9.624095433067907, 1.511094133486185, 1.4902809367619174, 2.6589495844034805, 1.5047196362919575, 1.4952879448055687, 4.521998245314546, 1.5282630109883355, 1.4775884573067495, 2.2484716517001977, 1.4137102247514408, 17.65389106545459, 1.4152075985894583, 1.9979273426810262, 1.4145952773003896, 4.013584978216514, 1.4152667107361572, 2.13949992463803, 1.4140566729616508, 2.280319047032558, 1.4157707037390115, 6.287134850549526, 1.4153994492620863, 2.1424064574519055, 1.4138665994591832, 2.2649508849461815, 1.414841818145644, 28.38302196839053, 1.4148317885088566, 1.9994589052806793, 1.4143064107270136, 3.5543532178625195, 1.5002550290764005]; 258 | 259 | ## Locally optimal stepsize vector for N=44; 260 | 261 | ##------------------------------; 262 | 263 | h_44 = [1.4160611259084073, 1.9982296861023758, 1.4147623287520685, 3.406898333479773, 1.4154030742061625, 1.9958400821292852, 1.4149194893842787, 8.855346790015448, 1.4151331964296765, 1.9988672867561796, 1.4145612939576102, 4.388919472954342, 1.4158237262196405, 2.022467754001419, 1.4147135207418784, 2.4093477292913623, 1.4145173286028092, 4.423000685021294, 1.4218740247489894, 1.9873708922304087, 1.412802240830457, 33.201066723215774, 1.4151267419124265, 1.9993100647970299, 1.4143824762423796, 4.023928254756794, 1.415214831771194, 2.164879715640403, 1.414055185934533, 2.2498885061772134, 1.4145692994348815, 13.746924477668317, 1.5988825226543717, 1.4173707584433666, 2.986576879698875, 1.4182773271131175, 1.9900815616963967, 1.414630973186174, 4.2579709843066365, 1.4270056962505384, 1.97616587068593, 1.4133499045082942, 6.5204206505181865, 1.5002299095372922]; 264 | 265 | ## Locally optimal stepsize vector for N=45; 266 | 267 | ##------------------------------; 268 | 269 | h_45 = [1.4161972739555593, 1.998367406866847, 1.4147260338525682, 3.406015803947939, 1.4154375125934848, 1.9954971194764362, 1.414938618470103, 9.305287508586206, 1.4152339952109552, 1.998704560274911, 1.414521576434053, 4.719344906182089, 1.4149658736168835, 2.587981668854004, 1.4161959377313253, 1.9992711727854005, 1.416463631965115, 2.530387267508789, 1.414691213216659, 4.733936620580937, 1.5460887010404956, 1.4656720482982641, 1.6882281841869402, 35.13739692473029, 1.601289416338826, 1.4160533378997624, 2.6593439056728423, 1.587210077794041, 1.424334280660946, 6.552457682878794, 1.637272083114244, 1.4162995784838117, 1.6599858295620002, 4.216521384626508, 1.5151711290340475, 1.4856347860283354, 2.956554675318282, 1.4330804141181048, 1.9716404576617494, 1.4158538198894033, 14.271582936670148, 1.4151392179038045, 2.002874024911339, 1.4142268297928948, 2.4682915002682684]; 270 | 271 | ## Locally optimal stepsize vector for N=46; 272 | 273 | ##------------------------------; 274 | 275 | h_46 = [1.6015429425914232, 1.4175326928990566, 2.2551277742286366, 1.4147712431662254, 4.86439051978118, 1.510697965079035, 1.490676737190435, 2.9623971021023974, 1.419283917588936, 1.9904578839014009, 1.415147482263413, 13.460523124760812, 1.5987153114723682, 1.4174327851557815, 3.177824523077203, 1.5249703512963495, 1.4792659429972659, 2.2714691638130393, 1.4142327282401406, 7.904104385426405, 1.4149513192824839, 2.1935393242145, 1.4142672177692273, 2.2085749540850337, 1.4172073361294393, 4.503100409604037, 1.5402496703017037, 1.471431257297709, 2.2499278543142225, 1.4127605627031403, 39.10857854743178, 1.4154869361677151, 1.9993507074321433, 1.4145172161775919, 3.415685794298011, 1.4187739625984614, 1.9872955425471772, 1.4146498757233847, 5.139477745363656, 1.4151102877652486, 2.251151931452901, 1.4963792527378377, 1.5057371665744763, 9.103211456335499, 1.731013650651186, 1.5011176273870548]; 276 | 277 | ## Locally optimal stepsize vector for N=47; 278 | 279 | ##------------------------------; 280 | 281 | h_47 = [1.5970634100266545, 1.4193324284174809, 2.9731276147989414, 1.4155380082702063, 1.9961981010450436, 1.4150165100145473, 7.802268467212787, 1.597519037577431, 1.4194210475484224, 2.255016635465564, 1.4147668237868074, 5.1282199908665165, 1.5118928716946813, 1.4891128912735507, 3.125067607133881, 1.5309208938061691, 1.4742835591307246, 2.3010153706876766, 1.4140944871817376, 32.26356192325056, 1.4156090691758343, 2.2571778578405652, 1.4968723512017374, 1.5046269267824037, 4.535459765938803, 1.4157393144088903, 2.1656506019383133, 1.4139808428064586, 2.245733642804837, 1.4148322585192936, 9.070719548143632, 1.4149330573917287, 2.1901795659357624, 1.4143070118565668, 2.2139110462924707, 1.4168840202173714, 3.9935489878444286, 1.444174793550274, 1.9404687144459578, 1.4165674198802651, 20.01104563330288, 1.601285354334758, 1.4161527482608625, 2.2578296544263154, 1.4145634938187404, 4.0398827247084865, 1.5002803391437551]; 282 | 283 | ## Locally optimal stepsize vector for N=48; 284 | 285 | ##------------------------------; 286 | 287 | h_48 = [1.5956440058364711, 1.4208305499354321, 2.978771069871827, 1.415771930677078, 1.9967344831157892, 1.4146526050985244, 5.3783865024216695, 1.4155428330225648, 2.178740852949944, 1.414436754737676, 2.228266956275092, 1.4147463973369132, 17.011898232997876, 1.5980615598370451, 1.418579000026285, 2.967914499608419, 1.419825801688591, 1.9924004389923546, 1.4143420257053414, 7.548672227975246, 1.4158046048612147, 1.9981928338506527, 1.4146961902504551, 3.839122251772535, 1.416073077884366, 1.9768090394085989, 1.4197415387407653, 3.969190822155726, 1.4429745635292637, 1.9277467045755816, 1.4185453273073114, 11.77080943828107, 1.4150012143528106, 2.1957790213156394, 1.4147846694160189, 2.194140310209627, 1.4200467859118509, 3.976378491456916, 1.456492357931007, 1.9163929680062204, 1.417764223239567, 32.88276725033982, 1.4150724847506488, 1.9990249230166857, 1.4143187465073446, 4.166606046217121, 1.414585086124617, 1.8768520363821057]; 288 | 289 | ## Locally optimal stepsize vector for N=49; 290 | 291 | ##------------------------------; 292 | 293 | h_49 = [1.5952780901570869, 1.4210227835168772, 2.975474639063835, 1.4157724201856479, 1.9949475077581673, 1.4153532202226558, 6.312759848701846, 1.415620217234369, 1.998056052422589, 1.4151043309075266, 3.38827230964731, 1.4298878356606748, 1.9636701642842846, 1.4171606875711011, 9.097392290632127, 1.4158670153895625, 1.9912977007816883, 1.4168670720848302, 3.359766686120749, 1.4380519203059825, 1.9584159671740642, 1.416933490472856, 36.560004127628204, 1.4150182688999275, 2.437230191606516, 1.41739748858828, 2.0038477057371473, 1.4137197685477534, 6.311940832634879, 1.5236268003849827, 1.4810343204987997, 2.2533767393780866, 1.4140486017052931, 4.116910890318551, 1.5412674507990374, 1.469897149767861, 2.2561435190957218, 1.413374943905227, 19.517256781208594, 1.5993646599207159, 1.419212985283726, 2.2560423840328396, 1.4144313087093048, 3.732228610874682, 1.4345562367243945, 1.9642914565953367, 1.4125544217006611, 5.76056030590457, 1.5003092153686197]; 294 | 295 | ## Locally optimal stepsize vector for N=50; 296 | 297 | ##------------------------------; 298 | 299 | h_50 = [1.5958743518790774, 1.4203770234563378, 2.971211184884086, 1.4157274281846162, 1.995741454373446, 1.4152169068658134, 8.549741557142763, 1.4154688479452724, 1.9983336889867038, 1.4147088064618587, 4.888232118878028, 1.6005594184145655, 1.4161180326078795, 3.3605483314412066, 1.4158245523573785, 2.1171962361361203, 1.4145676908196327, 2.320338004765043, 1.4160303079882408, 4.907259290717155, 1.4329242645055837, 1.964171439142215, 1.4130061410783987, 36.96886074199298, 1.415489557404075, 1.9996059863093698, 1.4145244241336101, 3.7268306084082283, 1.5268410248149245, 1.4782602939339355, 2.2558071881603117, 1.414347161790353, 13.474201968821102, 1.5976750370133366, 1.4188627098610425, 2.9643322594240185, 1.4230920853398292, 1.9895190521714607, 1.4128709461202384, 6.6622453348451005, 1.514751947716923, 1.4865992890480064, 3.279911713894502, 1.4161590010827143, 2.055739999107617, 1.4168372776764715, 2.4219460576308194, 1.4147756009008488, 8.175336727653681, 1.500403734613415]; 300 | -------------------------------------------------------------------------------- /2_Acceleration_without_momentum/BnB_PEP_reducing_function_value_AWM.jl: -------------------------------------------------------------------------------- 1 | ## Load the packages: 2 | # ------------------- 3 | using JuMP, MosekTools, Mosek, LinearAlgebra, OffsetArrays, Gurobi, Ipopt, JLD2, Distributions, OrderedCollections, BenchmarkTools, KNITRO 4 | 5 | ## Load the pivoted Cholesky finder 6 | # --------------------------------- 7 | include("code_to_compute_pivoted_cholesky.jl") 8 | 9 | 10 | ## Some helper functions 11 | 12 | # construct e_i in R^n 13 | function e_i(n, i) 14 | e_i_vec = zeros(n, 1) 15 | e_i_vec[i] = 1 16 | return e_i_vec 17 | end 18 | 19 | # this symmetric outer product is used when a is constant, b is a JuMP variable 20 | function ⊙(a,b) 21 | return ((a*b') .+ transpose(a*b')) ./ 2 22 | end 23 | 24 | # this symmetric outer product is for computing ⊙(a,a) where a is a JuMP variable 25 | function ⊙(a) 26 | return a*transpose(a) 27 | end 28 | 29 | # function to compute cardinality of a vector 30 | function compute_cardinality(x, ϵ_sparsity) 31 | n = length(x) 32 | card_x = 0 33 | for i in 1:n 34 | if abs(x[i]) >= ϵ_sparsity 35 | card_x = card_x + 1 36 | end 37 | end 38 | return card_x 39 | end 40 | 41 | # function to compute rank of a matrix 42 | function compute_rank(X, ϵ_sparsity) 43 | eigval_array_X = eigvals(X) 44 | rnk_X = 0 45 | n = length(eigval_array_X) 46 | for i in 1:n 47 | if abs(eigval_array_X[i]) >= ϵ_sparsity 48 | rnk_X = rnk_X + 1 49 | end 50 | end 51 | return rnk_X 52 | end 53 | 54 | 55 | # Options for these function are 56 | # step_size_type = :Default => will create a last step of 1/(L) rest will be zero 57 | # step_size_type = :Random => will create a random stepsize 58 | 59 | function feasible_h_generator(N, L; step_size_type = :Default) 60 | 61 | # construct h 62 | # ----------- 63 | h = OffsetArray(zeros(N), 0:N-1) 64 | 65 | if step_size_type == :Default 66 | for i in 0:N-1 67 | h[i]= 1 # because we have defined h[i]/L in the FSFOM, h[i]=1 will correspond to a stepsize of 1/L 68 | end 69 | elseif step_size_type == :Random 70 | for i in 0:N-1 71 | h[i] = Uniform(0, 1) # same 72 | end 73 | end 74 | 75 | return h 76 | 77 | end 78 | 79 | 80 | function data_generator_function(N, L, h; input_type = :stepsize_constant) 81 | 82 | # define all the bold vectors 83 | # -------------------------- 84 | 85 | # define 𝐱_0 and 𝐱_star 86 | 87 | 𝐱_0 = e_i(N+2, 1) 88 | 89 | 𝐱_star = zeros(N+2, 1) 90 | 91 | # define 𝐠_0, 𝐠_1, …, 𝐠_N 92 | 93 | # first we define the 𝐠 vectors, 94 | # index -1 corresponds to ⋆, i.e., 𝐟[:,-1] = 𝐟_⋆ = 0 95 | 96 | # 𝐠= [𝐠_⋆ 𝐠_0 𝐠_1 𝐠_2 ... 𝐠_N] 97 | 𝐠 = OffsetArray(zeros(N+2, N+2), 1:N+2, -1:N) 98 | for i in 0:N 99 | 𝐠[:,i] = e_i(N+2, i+2) 100 | end 101 | 102 | # time to define the 𝐟 vectors 103 | 104 | # 𝐟 = [𝐟_⋆ 𝐟_0, 𝐟_1, …, 𝐟_N] 105 | 106 | 𝐟 = OffsetArray(zeros(N+1, N+2), 1:N+1, -1:N) 107 | 108 | for i in 0:N 109 | 𝐟[:,i] = e_i(N+1, i+1) 110 | end 111 | 112 | if input_type == :stepsize_constant 113 | 114 | # 𝐱 = [𝐱_{-1}=𝐱_⋆ ∣ 𝐱_{0} ∣ 𝐱_{1} ∣ … 𝐱_{N}] ∈ 𝐑^(N+2 × N+2) 115 | 𝐱 = OffsetArray(zeros(N+2, N+2), 1:N+2, -1:N) 116 | 117 | # assign values next using our formula for 𝐱_k 118 | 𝐱[:,0] = 𝐱_0 119 | 120 | for k in 1:N 121 | 𝐱[:,k] = 𝐱[:,0] - (1/L) .* ( sum( h[i] .* 𝐠[:,i] for i in 0:k-1) ) 122 | end 123 | 124 | elseif input_type == :stepsize_variable 125 | 126 | 𝐱 = [𝐱_star 𝐱_0] 127 | 128 | # assign values next using our formula for 𝐱_k 129 | for k in 1:N 130 | 𝐱_k = 𝐱_0 - (1/L)*( sum( h[i] .* 𝐠[:,i] for i in 0:k-1) ) 131 | 𝐱 = [𝐱 𝐱_k] 132 | end 133 | 134 | # make 𝐱 an offset array to make our life comfortable 135 | 𝐱 = OffsetArray(𝐱, 1:N+2, -1:N) 136 | 137 | end 138 | 139 | return 𝐱, 𝐠, 𝐟 140 | 141 | end 142 | 143 | 144 | # Index set creator function for the dual variables λ 145 | 146 | struct i_j_idx # correspond to (i,j) pair, where i,j ∈ I_N_⋆ 147 | i::Int64 # corresponds to index i 148 | j::Int64 # corresponds to index j 149 | end 150 | 151 | # We have dual variable λ={λ_ij}_{i,j} where i,j ∈ I_N_star 152 | # The following function creates the maximal index set for λ 153 | 154 | function index_set_constructor_for_dual_vars_full(I_N_star) 155 | 156 | # construct the index set for λ 157 | idx_set_λ = i_j_idx[] 158 | for i in I_N_star 159 | for j in I_N_star 160 | if i!=j 161 | push!(idx_set_λ, i_j_idx(i,j)) 162 | end 163 | end 164 | end 165 | 166 | return idx_set_λ 167 | 168 | end 169 | 170 | # The following function will return the effective index set of a known λ i.e., those indices of that are λ that are non-zero. 171 | 172 | function effective_index_set_finder(λ ; ϵ_tol = 0.0005) 173 | 174 | # the variables λ are of the type DenseAxisArray whose index set can be accessed using _.axes and data via _.data syntax 175 | 176 | idx_set_λ_current = (λ.axes)[1] 177 | 178 | idx_set_λ_effective = i_j_idx[] 179 | 180 | # construct idx_set_λ_effective 181 | 182 | for i_j_λ in idx_set_λ_current 183 | if abs(λ[i_j_λ]) >= ϵ_tol # if λ[i,j] >= ϵ, where ϵ is our cut off for accepting nonzero 184 | push!(idx_set_λ_effective, i_j_λ) 185 | end 186 | end 187 | 188 | return idx_set_λ_effective 189 | 190 | end 191 | 192 | # The following function will return the zero index set of a known L_cholesky i.e., those indices of that are L that are zero. 💀 Note that for λ we are doing the opposite. 193 | 194 | function zero_index_set_finder_L_cholesky(L_cholesky; ϵ_tol = 1e-4) 195 | n_L_cholesky, _ = size(L_cholesky) 196 | zero_idx_set_L_cholesky = [] 197 | for i in 1:n_L_cholesky 198 | for j in 1:n_L_cholesky 199 | if i >= j # because i= -ϵ_tol_feas, 548 | # where ϵ_tol_feas is our tolerance for feasibility. This is recommended while solving using Gurobi 549 | cholesky_modeling = :formula, # : formula impelements the equivalent representation of Z = L_cholesky*L_cholesky^T via formulas, the other option is :definition, that directly model Z = L_cholesky*L_cholesky^T 550 | ϵ_tol_feas = 1e-6, # tolerance for feasibility 551 | ϵ_tol_Cholesky = 0.0005, # tolerance for determining which elements of L_cholesky_ws is zero 552 | maxCutCount=1e3, # this is the number of cuts to be added if the lazy constraint callback is activated 553 | global_lower_bound_given = :off, # wheather is a global lower bound is given, providing this would make the branch-and-bound faster 554 | global_lower_bound = 0.0, # value of the global lower bound (if nothing is given then 0 is a valid lower bound) 555 | polish_solution = :on, # wheather to polish the solution to get better precision, the other option is :off 556 | ) 557 | 558 | # Number of points 559 | # ---------------- 560 | 561 | I_N_star = -1:N 562 | dim_Z = N+2 563 | 564 | # ************* 565 | # declare model 566 | # ------------- 567 | # ************* 568 | 569 | if solution_type == :find_globally_optimal 570 | 571 | @info "[🐌 ] globally optimal solution finder activated, solution method: spatial branch and bound" 572 | 573 | BnB_PEP_model = Model(Gurobi.Optimizer) 574 | # using direct_model results in smaller memory allocation 575 | # we could also use 576 | # Model(Gurobi.Optimizer) 577 | # but this requires more memory 578 | 579 | set_optimizer_attribute(BnB_PEP_model, "NonConvex", 2) 580 | # "NonConvex" => 2 tells Gurobi to use its nonconvex algorithm 581 | 582 | set_optimizer_attribute(BnB_PEP_model, "MIPFocus", 3) 583 | # If you are more interested in good quality feasible solutions, you can select MIPFocus=1. 584 | # If you believe the solver is having no trouble finding the optimal solution, and wish to focus more 585 | # attention on proving optimality, select MIPFocus=2. 586 | # If the best objective bound is moving very slowly (or not at all), you may want to try MIPFocus=3 to focus on the bound. 587 | 588 | # 🐑: other Gurobi options one can play with 589 | # ------------------------------------------ 590 | 591 | # turn off all the heuristics 592 | # set_optimizer_attribute(BnB_PEP_model, "Heuristics", 0) 593 | # set_optimizer_attribute(BnB_PEP_model, "RINS", 0) 594 | 595 | # other termination epsilons for Gurobi 596 | # set_optimizer_attribute(BnB_PEP_model, "MIPGapAbs", 1e-4) 597 | 598 | set_optimizer_attribute(BnB_PEP_model, "MIPGap", 1e-2) # 99% optimal solution, because Gurobi will provide a result associated with a global lower bound within this tolerance, by polishing the result, we can find the exact optimal solution by solving a convex SDP 599 | 600 | # set_optimizer_attribute(BnB_PEP_model, "FuncPieceRatio", 0) # setting "FuncPieceRatio" to 0, will ensure that the piecewise linear approximation of the nonconvex constraints lies below the original function 601 | 602 | # set_optimizer_attribute(BnB_PEP_model, "Threads", 64) # how many threads to use at maximum 603 | # 604 | set_optimizer_attribute(BnB_PEP_model, "FeasibilityTol", 1e-4) 605 | # 606 | # set_optimizer_attribute(BnB_PEP_model, "OptimalityTol", 1e-4) 607 | 608 | elseif solution_type == :find_locally_optimal 609 | 610 | @info "[🐙 ] locally optimal solution finder activated, solution method: interior point method" 611 | 612 | if local_solver == :knitro 613 | 614 | @info "[🚀 ] activating KNITRO" 615 | 616 | # BnB_PEP_model = Model(optimizer_with_attributes(KNITRO.Optimizer, "convex" => 0, "strat_warm_start" => 1)) 617 | 618 | BnB_PEP_model = Model( 619 | optimizer_with_attributes( 620 | KNITRO.Optimizer, 621 | "convex" => 0, 622 | "strat_warm_start" => 1, 623 | # the last settings below are for larger N 624 | # you can comment them out if preferred but not recommended 625 | "honorbnds" => 1, 626 | # "bar_feasmodetol" => 1e-3, 627 | #"feastol" => 1e-4, 628 | #"infeastol" => 1e-12, 629 | #"opttol" => 1e-4 630 | ) 631 | ) 632 | 633 | if knitro_multistart == :on 634 | set_optimizer_attribute(BnB_PEP_model, "ms_enable", 1) 635 | set_optimizer_attribute(BnB_PEP_model, "par_numthreads", 8) 636 | set_optimizer_attribute(BnB_PEP_model, "par_msnumthreads", 8) 637 | set_optimizer_attribute(BnB_PEP_model, "ms_maxsolves", 8) 638 | end 639 | 640 | if knitro_multi_algorithm == :on 641 | set_optimizer_attribute(BnB_PEP_model, "algorithm", 5) 642 | set_optimizer_attribute(BnB_PEP_model, "ma_terminate", 0) 643 | end 644 | 645 | elseif local_solver == :ipopt 646 | 647 | @info "[🎃 ] activating IPOPT" 648 | 649 | BnB_PEP_model = Model(Ipopt.Optimizer) 650 | 651 | # very high precision solution in IPOPT can be obtained via the following code, comment them out if high precision is not required 652 | 653 | set_optimizer_attribute(BnB_PEP_model, "constr_viol_tol", 1e-6) 654 | 655 | set_optimizer_attribute(BnB_PEP_model, "dual_inf_tol", 1e-6) 656 | 657 | set_optimizer_attribute(BnB_PEP_model, "compl_inf_tol", 1e-6) 658 | 659 | set_optimizer_attribute(BnB_PEP_model, "tol", 1e-10) 660 | 661 | set_optimizer_attribute(BnB_PEP_model, "max_iter", 5000) 662 | 663 | end 664 | end 665 | 666 | # ************************ 667 | # define all the variables 668 | # ------------------------ 669 | # ************************ 670 | 671 | @info "[🎉 ] defining the variables" 672 | 673 | # define λ 674 | # -------- 675 | 676 | if reduce_index_set_for_λ == :off 677 | # define λ over the full index set 678 | idx_set_λ = index_set_constructor_for_dual_vars_full(I_N_star) 679 | @variable(BnB_PEP_model, λ[idx_set_λ] >= 0) 680 | elseif reduce_index_set_for_λ == :on 681 | # define λ over a reduced index set, idx_set_λ_ws_effective, which is the effective index set of λ_ws 682 | idx_set_λ = idx_set_λ_ws_effective 683 | @variable(BnB_PEP_model, λ[idx_set_λ] >= 0) 684 | elseif reduce_index_set_for_λ == :for_warm_start_only 685 | # this :for_warm_start_only option is same as the :off option, however in this case we will define λ over the full index set, but warm-start from a λ_ws that has reduced index set 686 | idx_set_λ = index_set_constructor_for_dual_vars_full(I_N_star) 687 | idx_set_λ_ws = idx_set_λ_ws_effective 688 | @variable(BnB_PEP_model, λ[idx_set_λ] >= 0) 689 | end 690 | 691 | # define ν 692 | # -------- 693 | 694 | @variable(BnB_PEP_model, ν >= 0) 695 | 696 | # define Z 697 | # -------- 698 | 699 | @variable(BnB_PEP_model, Z[1:dim_Z, 1:dim_Z], Symmetric) 700 | 701 | if find_global_lower_bound_via_cholesky_lazy_constraint == :off 702 | 703 | # define the cholesky matrix of Z: L_cholesky 704 | # ------------------------------------------- 705 | @variable(BnB_PEP_model, L_cholesky[1:dim_Z, 1:dim_Z]) 706 | 707 | end 708 | 709 | # define the stepsize matrix h 710 | # ---------------------------- 711 | if positive_step_size == :off 712 | @variable(BnB_PEP_model, h[0:N-1]) 713 | elseif positive_step_size == :on 714 | @variable(BnB_PEP_model, h[0:N-1] >= 0) 715 | end 716 | 717 | # [👲 ] insert warm-start values for all the variables 718 | # ---------------------------------------------------- 719 | 720 | @info "[👲 ] warm-start values for all the variables" 721 | 722 | # warm start for λ 723 | # ---------------- 724 | if reduce_index_set_for_λ == :for_warm_start_only 725 | for i_j_λ in idx_set_λ_ws 726 | set_start_value(λ[i_j_λ], λ_ws[i_j_λ]) 727 | end 728 | for i_j_λ in setdiff(idx_set_λ, idx_set_λ_ws) 729 | set_start_value(λ[i_j_λ], 0.0) 730 | end 731 | else 732 | for i_j_λ in idx_set_λ 733 | set_start_value(λ[i_j_λ], λ_ws[i_j_λ]) 734 | end 735 | end 736 | 737 | # warm start for ν 738 | # ---------------- 739 | 740 | set_start_value(ν, ν_ws) 741 | 742 | # warm start for Z 743 | # ---------------- 744 | 745 | for i in 1:dim_Z 746 | for j in 1:dim_Z 747 | set_start_value(Z[i,j], Z_ws[i,j]) 748 | end 749 | end 750 | 751 | # warm start for L_cholesky 752 | # ------------------------ 753 | 754 | if find_global_lower_bound_via_cholesky_lazy_constraint == :off 755 | for i in 1:dim_Z 756 | for j in 1:dim_Z 757 | set_start_value(L_cholesky[i,j], L_cholesky_ws[i,j]) 758 | end 759 | end 760 | end 761 | 762 | # warm start for h 763 | # ---------------- 764 | 765 | for i in 0:N-1 766 | set_start_value(h[i], h_ws[i]) 767 | end 768 | 769 | 770 | # ************ 771 | # [🎇 ] add objective 772 | # ------------- 773 | # ************* 774 | 775 | @info "[🎇 ] adding objective" 776 | 777 | @objective(BnB_PEP_model, Min, ν*R^2) 778 | 779 | # Adding an upper bound for the objective function 780 | 781 | @constraint(BnB_PEP_model, ν*R^2 <= 1.001*d_star_ws) # this 1.001 factor gives some slack 782 | 783 | # Adding a lower bound for the objective function (if given) 784 | if global_lower_bound_given == :on 785 | @constraint(BnB_PEP_model, ν*R^2 >= global_lower_bound) 786 | end 787 | 788 | # ****************************** 789 | # [🎍 ] add the data generator function 790 | # ******************************* 791 | 792 | @info "[🎍 ] adding the data generator function to create 𝐱, 𝐠, 𝐟" 793 | 794 | dim_𝐱 = N+2 795 | 796 | 𝐱_0 = e_i(dim_𝐱, 1) 797 | 798 | 𝐱_star = zeros(dim_𝐱, 1) 799 | 800 | 𝐱, 𝐠, 𝐟 = data_generator_function(N, L, h; input_type = :stepsize_variable) 801 | 802 | B_mat_0_minus1 = ⊙(𝐱_0-𝐱_star, 𝐱_0-𝐱_star) 803 | 804 | # ******************* 805 | # add the constraints 806 | # ******************* 807 | 808 | 809 | # add the linear constraint 810 | # ------------------------- 811 | 812 | @info "[🎋 ] adding linear constraint" 813 | 814 | 815 | # note that in the code i_j_λ = (i,j), i_j_λ.i = i, i_j_λ.j = j 816 | @constraint(BnB_PEP_model, sum(λ[i_j_λ]*a_vec(i_j_λ.i,i_j_λ.j,𝐟) for i_j_λ in idx_set_λ) - a_vec(-1,N,𝐟) .== 0) 817 | 818 | # add the LMI constraint 819 | # ---------------------- 820 | 821 | @info "[🎢 ] adding LMI constraint" 822 | 823 | if quadratic_equality_modeling == :exact 824 | 825 | 826 | # modeling of the LMI constraint through vectorization (works same) 827 | # ------------------------------------ 828 | @constraint(BnB_PEP_model, 829 | vectorize( 830 | ν*B_mat_0_minus1 + sum(λ[i_j_λ]*A_mat(i_j_λ.i,i_j_λ.j,h,𝐠,𝐱) for i_j_λ in idx_set_λ) + 831 | (1/(2*(L)))*sum(λ[i_j_λ]*C_mat(i_j_λ.i,i_j_λ.j,𝐠) for i_j_λ in idx_set_λ) 832 | - Z, 833 | SymmetricMatrixShape(dim_Z) 834 | ) .== 0 835 | ) 836 | 837 | elseif quadratic_equality_modeling == :through_ϵ 838 | 839 | # modeling of the LMI constraint through vectorization and ϵ_tol_feas 840 | # --------------------------------------- 841 | 842 | # part 1: models 843 | # (dual related terms) - Z <= ϵ_tol_feas*ones(dim_Z,dim_z) 844 | @constraint(BnB_PEP_model, 845 | vectorize( 846 | ν*B_mat_0_minus1 + sum(λ[i_j_λ]*A_mat(i_j_λ.i,i_j_λ.j,h,𝐠,𝐱) for i_j_λ in idx_set_λ) + 847 | (1/(2*(L)))*sum(λ[i_j_λ]*C_mat(i_j_λ.i,i_j_λ.j,𝐠) for i_j_λ in idx_set_λ) 848 | - Z - ϵ_tol_feas*ones(dim_Z,dim_Z), 849 | SymmetricMatrixShape(dim_Z) 850 | ) .<= 0 851 | ) 852 | 853 | # part 2: models 854 | # (dual related terms) - Z >= -ϵ_tol_feas*ones(dim_Z,dim_z) 855 | @constraint(BnB_PEP_model, 856 | vectorize( 857 | ν*B_mat_0_minus1 + sum(λ[i_j_λ]*A_mat(i_j_λ.i,i_j_λ.j,h,𝐠,𝐱) for i_j_λ in idx_set_λ) + 858 | (1/(2*(L)))*sum(λ[i_j_λ]*C_mat(i_j_λ.i,i_j_λ.j,𝐠) for i_j_λ in idx_set_λ) 859 | - Z + ϵ_tol_feas*ones(dim_Z,dim_Z), 860 | SymmetricMatrixShape(dim_Z) 861 | ) .>= 0 862 | ) 863 | 864 | else 865 | 866 | @error "something is not right in LMI modeling" 867 | 868 | return 869 | 870 | end 871 | 872 | 873 | # implementation through ϵ_tol_feas 874 | 875 | # add valid constraints for Z ⪰ 0 876 | # ------------------------------- 877 | 878 | @info "[🎩 ] adding valid constraints for Z" 879 | 880 | # diagonal components of Z are non-negative 881 | for i in 1:dim_Z 882 | @constraint(BnB_PEP_model, Z[i,i] >= 0) 883 | end 884 | 885 | # the off-diagonal components satisfy: 886 | # (∀i,j ∈ dim_Z: i != j) -(0.5*(Z[i,i] + Z[j,j])) <= Z[i,j] <= (0.5*(Z[i,i] + Z[j,j])) 887 | 888 | for i in 1:dim_Z 889 | for j in 1:dim_Z 890 | if i != j 891 | @constraint(BnB_PEP_model, Z[i,j] <= (0.5*(Z[i,i] + Z[j,j])) ) 892 | @constraint(BnB_PEP_model, -(0.5*(Z[i,i] + Z[j,j])) <= Z[i,j] ) 893 | end 894 | end 895 | end 896 | 897 | # add cholesky related constraints 898 | # -------------------------------- 899 | 900 | if find_global_lower_bound_via_cholesky_lazy_constraint == :off 901 | 902 | @info "[🎭 ] adding cholesky matrix related constraints" 903 | 904 | # Two constraints to define the matrix L_cholesky to be a lower triangular matrix 905 | # ------------------------------------------------- 906 | 907 | # upper off-diagonal terms of L_cholesky are zero 908 | 909 | for i in 1:dim_Z 910 | for j in 1:dim_Z 911 | if i < j 912 | # @constraint(BnB_PEP_model, L_cholesky[i,j] .== 0) 913 | fix(L_cholesky[i,j], 0; force = true) 914 | end 915 | end 916 | end 917 | 918 | # diagonal components of L_cholesky are non-negative 919 | 920 | for i in 1:dim_Z 921 | @constraint(BnB_PEP_model, L_cholesky[i,i] >= 0) 922 | end 923 | 924 | end 925 | 926 | # time to implement Z = L*L^T constraint 927 | # -------------------------------------- 928 | 929 | if cholesky_modeling == :definition && find_global_lower_bound_via_cholesky_lazy_constraint == :off 930 | 931 | if quadratic_equality_modeling == :exact 932 | 933 | # direct modeling through definition and vectorization 934 | # --------------------------------------------------- 935 | @constraint(BnB_PEP_model, vectorize(Z - (L_cholesky * L_cholesky'), SymmetricMatrixShape(dim_Z)) .== 0) 936 | 937 | elseif quadratic_equality_modeling == :through_ϵ 938 | 939 | # definition modeling through vectorization and ϵ_tol_feas 940 | 941 | # part 1: models Z-L_cholesky*L_cholesky <= ϵ_tol_feas*ones(dim_Z,dim_Z) 942 | @constraint(BnB_PEP_model, vectorize(Z - (L_cholesky * L_cholesky') - ϵ_tol_feas*ones(dim_Z,dim_Z), SymmetricMatrixShape(dim_Z)) .<= 0) 943 | 944 | # part 2: models Z-L_cholesky*L_cholesky >= -ϵ_tol_feas*ones(dim_Z,dim_Z) 945 | 946 | @constraint(BnB_PEP_model, vectorize(Z - (L_cholesky * L_cholesky') + ϵ_tol_feas*ones(dim_Z,dim_Z), SymmetricMatrixShape(dim_Z)) .>= 0) 947 | 948 | else 949 | 950 | @error "something is not right in Cholesky modeling" 951 | 952 | return 953 | 954 | end 955 | 956 | 957 | elseif cholesky_modeling == :formula && find_global_lower_bound_via_cholesky_lazy_constraint == :off 958 | 959 | # Cholesky constraint 1 960 | # (∀ j ∈ dim_Z) L_cholesky[j,j]^2 + ∑_{k∈[1:j-1]} L_cholesky[j,k]^2 == Z[j,j] 961 | 962 | for j in 1:dim_Z 963 | if j == 1 964 | @constraint(BnB_PEP_model, L_cholesky[j,j]^2 == Z[j,j]) 965 | elseif j > 1 966 | @constraint(BnB_PEP_model, L_cholesky[j,j]^2+sum(L_cholesky[j,k]^2 for k in 1:j-1) == Z[j,j]) 967 | end 968 | end 969 | 970 | # Cholesky constraint 2 971 | # (∀ i,j ∈ dim_Z: i > j) L_cholesky[i,j] L_cholesky[j,j] + ∑_{k∈[1:j-1]} L_cholesky[i,k] L_cholesky[j,k] == Z[i,j] 972 | 973 | for i in 1:dim_Z 974 | for j in 1:dim_Z 975 | if i>j 976 | if j == 1 977 | @constraint(BnB_PEP_model, L_cholesky[i,j]*L_cholesky[j,j] == Z[i,j]) 978 | elseif j > 1 979 | @constraint(BnB_PEP_model, L_cholesky[i,j]*L_cholesky[j,j] + sum(L_cholesky[i,k]*L_cholesky[j,k] for k in 1:j-1) == Z[i,j]) 980 | end 981 | end 982 | end 983 | end 984 | 985 | elseif find_global_lower_bound_via_cholesky_lazy_constraint == :on 986 | 987 | # set_optimizer_attribute(BnB_PEP_model, "FuncPieces", -2) # FuncPieces = -2: Bounds the relative error of the approximation; the error bound is provided in the FuncPieceError attribute. See https://www.gurobi.com/documentation/9.1/refman/funcpieces.html#attr:FuncPieces 988 | 989 | # set_optimizer_attribute(BnB_PEP_model, "FuncPieceError", 0.1) # relative error 990 | 991 | set_optimizer_attribute(BnB_PEP_model, "MIPFocus", 1) # focus on finding good quality feasible solution 992 | 993 | # add initial cuts 994 | num_cutting_planes_init = 2*dim_Z^2 995 | cutting_plane_array = randn(dim_Z,num_cutting_planes_init) 996 | num_cuts_array_rows, num_cuts = size(cutting_plane_array) 997 | for i in 1:num_cuts 998 | d_cut = cutting_plane_array[:,i] 999 | d_cut = d_cut/norm(d_cut,2) # normalize the cutting plane vector 1000 | @constraint(BnB_PEP_model, tr(Z*(d_cut*d_cut')) >= 0) 1001 | end 1002 | 1003 | cutCount=0 1004 | # maxCutCount=1e3 1005 | 1006 | # add the lazy callback function 1007 | # ------------------------------ 1008 | function add_lazy_callback(cb_data) 1009 | if cutCount<=maxCutCount 1010 | Z0 = zeros(dim_Z,dim_Z) 1011 | for i=1:dim_Z 1012 | for j=1:dim_Z 1013 | Z0[i,j]=callback_value(cb_data, Z[i,j]) 1014 | end 1015 | end 1016 | if eigvals(Z0)[1]<=-0.01 1017 | u_t = eigvecs(Z0)[:,1] 1018 | u_t = u_t/norm(u_t,2) 1019 | con3 = @build_constraint(tr(Z*u_t*u_t') >=0.0) 1020 | MOI.submit(BnB_PEP_model, MOI.LazyConstraint(cb_data), con3) 1021 | # noPSDCuts+=1 1022 | end 1023 | cutCount+=1 1024 | end 1025 | end 1026 | 1027 | # submit the lazy constraint 1028 | # -------------------------- 1029 | MOI.set(BnB_PEP_model, MOI.LazyConstraintCallback(), add_lazy_callback) 1030 | 1031 | 1032 | end 1033 | 1034 | # impose bound on the variables if bound_impose == :on 1035 | 1036 | if bound_impose == :on 1037 | @info "[🌃 ] finding bound on the variables" 1038 | 1039 | # store the values 1040 | 1041 | λ_lb = 0 1042 | λ_ub = M_λ 1043 | ν_lb = 0 1044 | ν_ub = ν_ws 1045 | Z_lb = -M_Z 1046 | Z_ub = M_Z 1047 | L_cholesky_lb = -M_L_cholesky 1048 | L_cholesky_ub = M_L_cholesky 1049 | h_lb = -M_h 1050 | h_ub = M_h 1051 | 1052 | # set bound for λ 1053 | # --------------- 1054 | # set_lower_bound.(λ, λ_lb): done in definition 1055 | set_upper_bound.(λ, λ_ub) 1056 | 1057 | # set bound for ν 1058 | # --------------- 1059 | # set_lower_bound.(ν, ν_lb): done in definition 1060 | set_upper_bound(ν, ν_ub) 1061 | 1062 | # set bound for Z 1063 | # --------------- 1064 | for i in 1:dim_Z 1065 | for j in 1:dim_Z 1066 | set_lower_bound(Z[i,j], Z_lb) 1067 | set_upper_bound(Z[i,j], Z_ub) 1068 | end 1069 | end 1070 | 1071 | # set bound for L_cholesky 1072 | # ------------------------ 1073 | 1074 | if find_global_lower_bound_via_cholesky_lazy_constraint == :off 1075 | # need only upper bound for the diagonal compoments, as the lower bound is zero from the model 1076 | for i in 1:N+2 1077 | set_upper_bound(L_cholesky[i,i], L_cholesky_ub) 1078 | end 1079 | # need to bound only components, L_cholesky[i,j] with i > j, as for i < j, we have zero, due to the lower triangular structure 1080 | for i in 1:N+2 1081 | for j in 1:N+2 1082 | if i > j 1083 | set_lower_bound(L_cholesky[i,j], L_cholesky_lb) 1084 | set_upper_bound(L_cholesky[i,j], L_cholesky_ub) 1085 | end 1086 | end 1087 | end 1088 | end 1089 | 1090 | # set bound for h 1091 | # --------------- 1092 | set_lower_bound.(h, h_lb) 1093 | set_upper_bound.(h, h_ub) 1094 | 1095 | end 1096 | 1097 | # impose the effective index set of L_cholesky if reduce_index_set_for_L_cholesky == :on and we are not computing a global lower bound 1098 | # ------------------------------------------ 1099 | 1100 | if find_global_lower_bound_via_cholesky_lazy_constraint == :off && reduce_index_set_for_L_cholesky == :on 1101 | zis_Lc = zero_index_set_finder_L_cholesky(L_cholesky_ws; ϵ_tol = ϵ_tol_Cholesky) 1102 | for k in 1:length(zis_Lc) 1103 | fix(L_cholesky[CartesianIndex(zis_Lc[k])], 0; force = true) 1104 | end 1105 | end 1106 | 1107 | 1108 | # time to optimize 1109 | # ---------------- 1110 | 1111 | @info "[🙌 🙏 ] model building done, starting the optimization process" 1112 | 1113 | if show_output == :off 1114 | set_silent(BnB_PEP_model) 1115 | end 1116 | 1117 | optimize!(BnB_PEP_model) 1118 | 1119 | @info "BnB_PEP_model has termination status = " termination_status(BnB_PEP_model) 1120 | 1121 | if (solution_type == :find_locally_optimal && termination_status(BnB_PEP_model) == MOI.LOCALLY_SOLVED) || (solution_type ==:find_globally_optimal && termination_status(BnB_PEP_model) == MOI.OPTIMAL ) 1122 | 1123 | # store the solutions and return 1124 | # ------------------------------ 1125 | 1126 | @info "[😻 ] optimal solution found done, store the solution" 1127 | 1128 | # store λ_opt 1129 | 1130 | λ_opt = value.(λ) 1131 | 1132 | # store ν_opt 1133 | 1134 | ν_opt = value.(ν) 1135 | 1136 | # store h_opt 1137 | 1138 | h_opt = value.(h) 1139 | 1140 | # store Z_opt 1141 | 1142 | Z_opt = value.(Z) 1143 | 1144 | # store L_cholesky 1145 | 1146 | if find_global_lower_bound_via_cholesky_lazy_constraint == :off 1147 | 1148 | L_cholesky_opt = value.(L_cholesky) 1149 | 1150 | if norm(Z_opt - L_cholesky_opt*L_cholesky_opt', Inf) > 10^-4 1151 | @warn "||Z - L_cholesky*L_cholesky^T|| = $(norm(Z_opt - L_cholesky_opt*L_cholesky_opt', Inf))" 1152 | end 1153 | 1154 | elseif find_global_lower_bound_via_cholesky_lazy_constraint == :on 1155 | 1156 | L_cholesky_opt = compute_pivoted_cholesky_L_mat(Z_opt) 1157 | 1158 | # in this case doing the cholesky check does not make sense, because we are not aiming to find a psd Z_opt 1159 | 1160 | # if norm(Z_opt - L_cholesky_opt*L_cholesky_opt', Inf) > 10^-4 1161 | # @info "checking the norm bound" 1162 | # @warn "||Z - L*L^T|| = $(norm(Z_opt - L_cholesky_opt*L_cholesky_opt', Inf))" 1163 | # end 1164 | 1165 | end 1166 | 1167 | obj_val = objective_value(BnB_PEP_model) 1168 | 1169 | else 1170 | 1171 | @warn "[🙀 ] could not find an optimal solution, returning the warm-start point" 1172 | 1173 | obj_val, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt, idx_set_λ_opt_effective = d_star_ws, λ_ws, ν_ws, Z_ws, L_cholesky_ws, h_ws, idx_set_λ_ws_effective 1174 | 1175 | 1176 | end 1177 | 1178 | if polish_solution == :on && find_global_lower_bound_via_cholesky_lazy_constraint == :off # note that if we are finding a global lower bound, then polishing the solution would not make sense 1179 | 1180 | @info "[🎣 ] polishing and sparsifying the solution" 1181 | 1182 | obj_val, _, _, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt, _ = solve_dual_PEP_with_known_stepsizes(N, L, h_opt, R; show_output = :off, 1183 | ϵ_tol_feas = 1e-6, objective_type = :default, obj_val_upper_bound = 1.0001*obj_val) 1184 | 1185 | obj_val_sparse, _, _, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt, _ = solve_dual_PEP_with_known_stepsizes(N, L, h_opt, R; show_output = :off, 1186 | ϵ_tol_feas = 1e-6, objective_type = :find_sparse_sol, obj_val_upper_bound = (1+(1e-6))*obj_val) 1187 | 1188 | end 1189 | 1190 | # find the effective index set of the found λ 1191 | 1192 | idx_set_λ_opt_effective = effective_index_set_finder(λ_opt ; ϵ_tol = 0.0005) 1193 | 1194 | @info "[🚧 ] for λ, only $(length(idx_set_λ_opt_effective)) components out of $(length(idx_set_λ)) are non-zero for the optimal solution" 1195 | 1196 | 1197 | @info "[💹 ] warm-start objective value = $d_star_ws, and objective value of found solution = $obj_val" 1198 | 1199 | # verify if any of the imposed bounds are violated 1200 | 1201 | if bound_impose == :on && find_global_lower_bound_via_cholesky_lazy_constraint == :off 1202 | bound_satisfaction_flag = bound_violation_checker_BnB_PEP(obj_val, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt, λ_lb, λ_ub, ν_lb, ν_ub, Z_lb, Z_ub, L_cholesky_lb, L_cholesky_ub, h_lb, h_ub; show_output = :on, computing_global_lower_bound = :off) 1203 | elseif bound_impose == :on && find_global_lower_bound_via_cholesky_lazy_constraint == :on 1204 | bound_satisfaction_flag = bound_violation_checker_BnB_PEP(obj_val, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt, λ_lb, λ_ub, ν_lb, ν_ub, Z_lb, Z_ub, L_cholesky_lb, L_cholesky_ub, h_lb, h_ub; show_output = :on, computing_global_lower_bound = :on) 1205 | end 1206 | 1207 | # time to return all the stored values 1208 | 1209 | return obj_val, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt, idx_set_λ_opt_effective 1210 | 1211 | end 1212 | 1213 | 1214 | # the following function will compute w = vec(h, ν, λ) and provide index selectors from math to vec and vec to math. 1215 | function vectorize_h_ν_λ(h, ν, λ, idx_set_λ) 1216 | 1217 | k = 0 1218 | 1219 | vec_all_var = Vector{VariableRef}() # this is the vectorized version of all variables 1220 | 1221 | # vectorize h 1222 | 1223 | index_math2vec = OrderedDict() 1224 | 1225 | for i in 0:N-1 1226 | k = k+1 1227 | vec_all_var= [vec_all_var; h[i]] 1228 | index_math2vec[(:h, i)] = k 1229 | end 1230 | 1231 | # vectorize ν 1232 | 1233 | k = k+1 1234 | vec_all_var= [vec_all_var; ν] 1235 | index_math2vec[(:ν, 1)] = k 1236 | 1237 | # vectorize λ 1238 | 1239 | for i_j in idx_set_λ 1240 | k = k+1 1241 | vec_all_var = [vec_all_var; λ[i_j]] 1242 | index_math2vec[(:λ, (i_j.i, i_j.j))] = k 1243 | end 1244 | 1245 | # reverse the dictionary index_math2vec 1246 | index_vec2math = OrderedDict(value => key for (key, value) in index_math2vec) 1247 | 1248 | return vec_all_var, index_math2vec, index_vec2math 1249 | 1250 | end 1251 | 1252 | # usage: 1253 | # w, index_math2vec, index_vec2math = vectorize_h_ν_λ(h, ν, λ, idx_set_λ) 1254 | # such that 1255 | # w[index_math2vec[(:h,i)]]=w[k]=h[i] 1256 | # h[index_vec2math[k]] = w[k] 1257 | # and so on 1258 | 1259 | 1260 | ## Write the 𝔍_i matrix creator 1261 | 1262 | function 𝔍_mat(i, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1263 | if i == -1 1264 | dim_𝐱 = length(𝐱_0) 1265 | 𝔍_i = zeros(dim_𝐱, len_w+dim_𝐱) 1266 | return 𝔍_i 1267 | elseif i == 0 1268 | dim_𝐱 = length(𝐱_0) 1269 | 𝔍_i = zeros(dim_𝐱, len_w+dim_𝐱) 1270 | 𝔍_i[1:dim_𝐱,1:dim_𝐱] = I(dim_𝐱) 1271 | return 𝔍_i 1272 | elseif i >= 1 && i <= N 1273 | dim_𝐱 = length(𝐱_0) 1274 | 𝔍_i = zeros(dim_𝐱, len_w+dim_𝐱) 1275 | 𝔍_i_part_2 = zeros(dim_𝐱, len_w) 1276 | 𝔍_i[1:dim_𝐱,1:dim_𝐱] = I(dim_𝐱) 1277 | for j in 0:i-1 1278 | term = (-1/L)*( ( 𝐠[:,j] ) * transpose(e_i(len_w, index_math2vec[(:h, j)])) ) 1279 | 𝔍_i_part_2 = 𝔍_i_part_2 + term 1280 | end 1281 | 𝔍_i[1:dim_𝐱,dim_𝐱+1:len_w+dim_𝐱] = 𝔍_i_part_2 1282 | return 𝔍_i 1283 | end 1284 | end 1285 | 1286 | # usage: 1287 | # test = 𝔍_mat(2, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1288 | 1289 | 1290 | ## Write the 𝔊_i_j and ℌ_i_j matrix creator 1291 | 1292 | function 𝔊_ℌ_mat(i, j, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1293 | dim_𝐱 = length(𝐱_0) 1294 | 𝔍_i = 𝔍_mat(i, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1295 | 𝔍_j = 𝔍_mat(j, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1296 | 𝔊_i_j_ℌ_i_j = 𝔍_i - 𝔍_j 1297 | 𝔊_i_j = 𝔊_i_j_ℌ_i_j[1:dim_𝐱, 1:dim_𝐱] 1298 | ℌ_i_j = 𝔊_i_j_ℌ_i_j[1:dim_𝐱, dim_𝐱+1:len_w+dim_𝐱] 1299 | return 𝔊_i_j, ℌ_i_j 1300 | end 1301 | 1302 | # usage: 1303 | # 𝔊_1_2, ℌ_1_2 = 𝔊_ℌ_mat(1, 2, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1304 | 1305 | 1306 | ## Write the ℍ_i_j_k_ℓ matrix creator 1307 | 1308 | function constituents_of_B_h(i, j, k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1309 | 𝔊_i_j, ℌ_i_j = 𝔊_ℌ_mat(i, j, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1310 | # k-th row of 𝔊_i_j, ℌ_i_j 1311 | 𝔤_ij_k = 𝔊_i_j[k, :] 1312 | 𝔥_ij_k = ℌ_i_j[k,:] 1313 | # ℓ-th row of 𝔊_i_j, ℌ_i_j 1314 | 𝔤_ij_ℓ = 𝔊_i_j[ℓ,:] 1315 | 𝔥_ij_ℓ = ℌ_i_j[ℓ,:] 1316 | # define c_ij_k, c_ij_ℓ 1317 | c_ij_k = (𝔤_ij_k'*𝐱_0)[1] 1318 | c_ij_ℓ = (𝔤_ij_ℓ'*𝐱_0)[1] 1319 | ℍ_ij_kℓ = zeros(len_w, len_w) 1320 | for i_tilde in 1:len_w 1321 | for j_tilde in 1:len_w 1322 | ℍ_ij_kℓ[i_tilde, j_tilde] = 0.5*((𝔥_ij_k[i_tilde]*𝔥_ij_ℓ[j_tilde])+(𝔥_ij_k[j_tilde]*𝔥_ij_ℓ[i_tilde])) 1323 | end 1324 | end 1325 | return c_ij_k, c_ij_ℓ, 𝔥_ij_k, 𝔥_ij_ℓ, ℍ_ij_kℓ 1326 | end 1327 | 1328 | # # usage: 1329 | # i = 1 1330 | # j = -1 1331 | # k = 1 1332 | # ℓ = 2 1333 | # 1334 | # c_ij_k, c_ij_ℓ, 𝔥_ij_k, 𝔥_ij_ℓ, ℍ_ij_kℓ = constituents_of_B_h(i, j, k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1335 | # 1336 | # c_Nstar_k, c_Nstar_ℓ, 𝔥_Nstar_k, 𝔥_Nstar_ℓ, ℍ_Nstar_kℓ = constituents_of_B_h(N, -1, k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1337 | # 1338 | # B_N_star_h_k_ℓ = (c_Nstar_k*c_Nstar_ℓ) + (c_Nstar_k*𝔥_Nstar_ℓ'*w) + (c_Nstar_ℓ*𝔥_Nstar_k'*w) + tr(ℍ_Nstar_kℓ * W) 1339 | 1340 | 1341 | ## B_N_star_h_mat 1342 | 1343 | function B_N_star_h_mat(k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, w, W, index_math2vec) 1344 | c_Nstar_k, c_Nstar_ℓ, 𝔥_Nstar_k, 𝔥_Nstar_ℓ, ℍ_Nstar_kℓ = constituents_of_B_h(N, -1, k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1345 | B_N_star_h_k_ℓ = (c_Nstar_k*c_Nstar_ℓ) + (c_Nstar_k*𝔥_Nstar_ℓ'*w) + (c_Nstar_ℓ*𝔥_Nstar_k'*w) + tr(ℍ_Nstar_kℓ * W) 1346 | return B_N_star_h_k_ℓ 1347 | end 1348 | 1349 | # usage 1350 | # B_N_star_h_mat(k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, w, W, index_math2vec) 1351 | 1352 | 1353 | ## Constructs the elements of λ_A_h 1354 | 1355 | function constituents_of_λ_A_h(i, j, k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1356 | 1357 | 𝔊_i_j, ℌ_i_j = 𝔊_ℌ_mat(i, j, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1358 | # k-th row of 𝔊_i_j, ℌ_i_j 1359 | 𝔤_ij_k = 𝔊_i_j[k,:] 1360 | 𝔥_ij_k = ℌ_i_j[k,:] 1361 | # ℓ-th row of 𝔊_i_j, ℌ_i_j 1362 | 𝔤_ij_ℓ = 𝔊_i_j[ℓ,:] 1363 | 𝔥_ij_ℓ = ℌ_i_j[ℓ,:] 1364 | # define c_ij_k, c_ij_ℓ 1365 | c_ij_k = (𝔤_ij_k'*𝐱_0)[1] 1366 | c_ij_ℓ = (𝔤_ij_ℓ'*𝐱_0)[1] 1367 | 1368 | c_tilde_ij_kℓ = 0.5*( ( c_ij_ℓ* (𝐠[:,j])[k] ) + ( c_ij_k* (𝐠[:,j])[ℓ] ) ) 1369 | 1370 | d_ij = e_i(len_w, index_math2vec[(:λ, (i, j))]) 1371 | 1372 | 𝕊_ij_kℓ = zeros(len_w, len_w) 1373 | 1374 | for i_tilde in 1:len_w 1375 | for j_tilde in 1:len_w 1376 | q_ij_kℓ_itilde = 0.5 * ( ((𝐠[:,j])[k]* 𝔥_ij_ℓ[i_tilde]) + ((𝐠[:,j])[ℓ]* 𝔥_ij_k[i_tilde]) ) 1377 | q_ij_kℓ_jtilde = 0.5 * ( ((𝐠[:,j])[k]* 𝔥_ij_ℓ[j_tilde]) + ((𝐠[:,j])[ℓ]* 𝔥_ij_k[j_tilde]) ) 1378 | term_itilde_jtilde = d_ij[i_tilde] * q_ij_kℓ_jtilde 1379 | term_jtilde_itilde = d_ij[j_tilde] * q_ij_kℓ_itilde 1380 | 𝕊_ij_kℓ[i_tilde, j_tilde] = 0.5*(term_itilde_jtilde + term_jtilde_itilde) 1381 | end 1382 | end 1383 | 1384 | return c_tilde_ij_kℓ, d_ij, 𝕊_ij_kℓ 1385 | 1386 | end 1387 | 1388 | # usage: 1389 | # c_tilde_ij_kℓ, d_ij, 𝕊_ij_kℓ = constituents_of_λ_A_h(1, 0, 2, 2, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1390 | 1391 | 1392 | ## Construct sum_λij_Aij_k_ℓ_over_ij_mat 1393 | 1394 | function sum_λij_Aij_k_ℓ_over_ij_mat(k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, w, W, index_math2vec) 1395 | vec_1 = zeros(len_w) 1396 | mat_1 = zeros(len_w,len_w) 1397 | for i in -1:N 1398 | for j in -1:N 1399 | if i != j 1400 | c_tilde_ij_kℓ, d_ij, 𝕊_ij_kℓ = constituents_of_λ_A_h(i, j, k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, index_math2vec) 1401 | vec_1 = vec_1 + (c_tilde_ij_kℓ*d_ij) 1402 | mat_1 = mat_1 + 𝕊_ij_kℓ 1403 | end 1404 | end 1405 | end 1406 | sum_λij_Aij_k_ℓ_over_ij = dot(vec_1,w) + tr(mat_1*W) 1407 | return sum_λij_Aij_k_ℓ_over_ij 1408 | end 1409 | 1410 | # usage 1411 | 1412 | # sum_λij_Aij_k_ℓ_over_ij_mat(1, 2, 𝐱_0, 𝐱, 𝐠, len_w, N, w, W, index_math2vec) 1413 | 1414 | 1415 | ## Code to solve the semidefinite relaxation 1416 | # ------------------------------------------ 1417 | 1418 | function SDP_relaxation_solver_for_bound_generation(N, L, R; 1419 | c_λ=1, c_h=0, c_Z=0, 1420 | objective_type = :compute_bound, 1421 | # other option is :original_performance_measure 1422 | show_output = :off, 1423 | obj_val_upper_bound = default_obj_val_upper_bound) 1424 | 1425 | ϵ_tol_feas = 1e-6 1426 | 1427 | if c_λ == 1 && c_h == 0 && c_Z == 0 1428 | @info "computing M_λ" 1429 | elseif c_λ == 0 && c_h == 1 && c_Z == 0 1430 | @info "computing M_h" 1431 | elseif c_λ == 0 && c_h == 0 && c_Z == 1 1432 | @info "computing M_Z" 1433 | else 1434 | @error "exactly one of c_λ, c_h, c_Z, must be one, the other must be zero" 1435 | end 1436 | 1437 | I_N_star = -1:N 1438 | 1439 | dim_Z = N+2 1440 | 1441 | model_lifted = Model(optimizer_with_attributes(Mosek.Optimizer)) 1442 | 1443 | # define the variables 1444 | # -------------------- 1445 | 1446 | # define the index set of λ 1447 | idx_set_λ = index_set_constructor_for_dual_vars_full(I_N_star) 1448 | 1449 | # define λ 1450 | @variable(model_lifted, λ[idx_set_λ] >= 0) 1451 | 1452 | # define ν 1453 | @variable(model_lifted, ν >= 0) 1454 | 1455 | # define Z ⪰ 0 1456 | @variable(model_lifted, Z[1:dim_Z, 1:dim_Z], PSD) 1457 | 1458 | @variable(model_lifted, h[i = 0:N-1]) 1459 | 1460 | @variable(model_lifted, M_λ >= 0) 1461 | 1462 | @variable(model_lifted, M_h >= 0) 1463 | 1464 | @variable(model_lifted, M_Z >= 0) 1465 | 1466 | # bound constraints 1467 | # ----------------- 1468 | 1469 | if c_λ == 1 && c_h == 0 && c_Z == 0 1470 | 1471 | for i_j in idx_set_λ 1472 | @constraint(model_lifted, λ[i_j] <= M_λ) 1473 | end 1474 | 1475 | elseif c_λ == 0 && c_h == 1 && c_Z == 0 1476 | for i in 0:N-1 1477 | 1478 | @constraint(model_lifted, h[i] <= M_h) 1479 | @constraint(model_lifted, h[i] >= -M_h) 1480 | end 1481 | 1482 | elseif c_λ == 0 && c_h == 0 && c_Z == 1 1483 | 1484 | # for i in 1:dim_Z 1485 | # for j in 1:dim_Z 1486 | # @constraint(model_lifted, Z[i,j] <= M_Z) 1487 | # @constraint(model_lifted, Z[i,j] >= -M_Z) 1488 | # end 1489 | # end 1490 | 1491 | # Because the diagonal entries of a matrix is >= 0, and Z_{i,j} <= (Z_{i,i}+Z_{j,j})/2, 1492 | # we can bound just bound the diagonal entries 1493 | 1494 | for i in 1:dim_Z 1495 | @constraint(model_lifted, Z[i,i] <= M_Z) 1496 | end 1497 | 1498 | else 1499 | 1500 | @error "exactly one of c_λ, c_h, c_Z, must be one, the other must be zero" 1501 | 1502 | end 1503 | 1504 | # test to see if the relaxation gives the same solution if we fix h 1505 | 1506 | # define w 1507 | 1508 | w, index_math2vec, index_vec2math = vectorize_h_ν_λ(h, ν, λ, idx_set_λ) 1509 | 1510 | len_w = length(w) 1511 | 1512 | # define W 1513 | 1514 | @variable(model_lifted, W[1:len_w, 1:len_w], Symmetric) 1515 | 1516 | # ****************************** 1517 | # [🎍 ] add the data generator function 1518 | # ******************************* 1519 | 1520 | dim_𝐱 = N+2 1521 | 1522 | 𝐱_0 = e_i(dim_𝐱, 1) 1523 | 1524 | 𝐱_star = zeros(dim_𝐱, 1) 1525 | 1526 | 𝐱, 𝐠, 𝐟 = data_generator_function(N, L, h; input_type = :stepsize_variable) 1527 | 1528 | # add the objective 1529 | # ----------------- 1530 | 1531 | if objective_type == :compute_bound 1532 | 1533 | # @objective(model_lifted, Max, (c_λ*M_λ) + (c_h*M_h) + (c_Z*M_Z)) #Min, ν*R^2) 1534 | 1535 | @objective(model_lifted, Max, (c_λ*M_λ) + (c_h*M_h) + (c_Z*tr(Z))) #Min, ν*R^2) 1536 | 1537 | elseif objective_type == :original_performance_measure 1538 | 1539 | @objective(model_lifted, Min, ν*R^2) 1540 | 1541 | end 1542 | 1543 | # add the linear constraint 1544 | # ------------------------- 1545 | 1546 | @constraint(model_lifted, sum(λ[i_j_λ]*a_vec(i_j_λ.i,i_j_λ.j,𝐟) for i_j_λ in idx_set_λ) - a_vec(-1,N,𝐟) .== 0) 1547 | 1548 | # add the LMI constraint 1549 | # ---------------------- 1550 | 1551 | for k in 1:dim_𝐱 1552 | for ℓ in 1:k 1553 | 1554 | sum_λij_Aij_k_ℓ_over_ij = sum_λij_Aij_k_ℓ_over_ij_mat(k, ℓ, 𝐱_0, 𝐱, 𝐠, len_w, N, w, W, index_math2vec) 1555 | 1556 | @constraint( model_lifted, (ν*⊙(𝐱_0 - 𝐱_star, 𝐱_0 - 𝐱_star) )[k,ℓ] + (1/(2*L))*(sum(λ[i_j_λ]*C_mat(i_j_λ.i,i_j_λ.j,𝐠) for i_j_λ in idx_set_λ))[k,ℓ] + sum_λij_Aij_k_ℓ_over_ij == Z[k,ℓ] ) 1557 | end 1558 | end 1559 | 1560 | # confine the search in the space of known upper bound 1561 | # ---------------------------------------------------- 1562 | 1563 | @constraint(model_lifted, ν*R^2 <= obj_val_upper_bound) 1564 | 1565 | # add the Schur complement constraint 1566 | # ----------------------------------- 1567 | 1568 | @constraint(model_lifted, [W w; w' 1] in PSDCone()) 1569 | 1570 | # time to optimize 1571 | # ---------------- 1572 | 1573 | if show_output == :off 1574 | set_silent(model_lifted) 1575 | end 1576 | 1577 | optimize!(model_lifted) 1578 | 1579 | # store the solution and return 1580 | 1581 | if objective_type == :compute_bound 1582 | 1583 | M_λ_opt = value(M_λ) 1584 | 1585 | M_Z_opt = value(M_Z) 1586 | 1587 | M_h_opt = value(M_h) 1588 | 1589 | return (c_λ*M_λ_opt) + (c_h*M_h_opt) + (c_Z*M_Z_opt) 1590 | 1591 | elseif objective_type == :original_performance_measure 1592 | 1593 | # store λ_opt 1594 | 1595 | λ_opt = value.(λ) 1596 | 1597 | # store ν_opt 1598 | 1599 | ν_opt = value.(ν) 1600 | 1601 | # store h_opt 1602 | 1603 | h_opt = value.(h) 1604 | 1605 | # store Z_opt 1606 | 1607 | Z_opt = value.(Z) 1608 | 1609 | # store L_cholesky 1610 | 1611 | L_cholesky_opt = compute_pivoted_cholesky_L_mat(Z_opt) 1612 | 1613 | if norm(Z_opt - L_cholesky_opt*L_cholesky_opt', Inf) > 1e-6 1614 | @info "checking the norm bound" 1615 | @warn "||Z - L*L^T|| = $(norm(Z_opt - L_cholesky_opt*L_cholesky_opt', Inf))" 1616 | end 1617 | 1618 | obj_val = objective_value(model_lifted) 1619 | 1620 | return obj_val, λ_opt, ν_opt, Z_opt, L_cholesky_opt, h_opt 1621 | 1622 | end 1623 | 1624 | end 1625 | 1626 | 1627 | # L = 1 1628 | # N = 5 1629 | # R = 1 1630 | # h_test = feasible_h_generator(N, L; step_size_type = :Default) 1631 | # 1632 | # default_obj_val_upper_bound = 1e6 1633 | # # 1634 | # p_feas_1, G_feas_1, Ft_feas_1 = solve_primal_with_known_stepsizes(N, L, h_test, R; show_output = :on) 1635 | # # 1636 | # d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_test, R; show_output = :off, 1637 | # ϵ_tol_feas = 1e-6, 1638 | # objective_type = :default, 1639 | # obj_val_upper_bound = default_obj_val_upper_bound) 1640 | # # 1641 | # # 1642 | # obj_val_sdp_rlx, λ_opt_sdp_rlx, ν_opt_sdp_rlx, Z_opt_sdp_rlx, L_cholesky_opt_sdp_rlx, h_opt_sdp_rlx = SDP_relaxation_solver_for_bound_generation(N, L, R; 1643 | # c_λ=0, c_h=0, c_Z=1, 1644 | # objective_type = :original_performance_measure, 1645 | # # other option is :original_performance_measure 1646 | # show_output = :off, 1647 | # obj_val_upper_bound = default_obj_val_upper_bound) 1648 | # 1649 | # # 1650 | # M_λ = SDP_relaxation_solver_for_bound_generation(N, L, R; 1651 | # c_λ=1, c_h=0, c_Z=0, 1652 | # show_output = :off, 1653 | # obj_val_upper_bound = d_feas_1) 1654 | # 1655 | # M_h = SDP_relaxation_solver_for_bound_generation(N, L, R; 1656 | # c_λ=0, c_h=1, c_Z=0, 1657 | # show_output = :off, 1658 | # obj_val_upper_bound = d_feas_1) 1659 | # 1660 | # M_Z = SDP_relaxation_solver_for_bound_generation(N, L, R; 1661 | # c_λ=0, c_h=0, c_Z=1, 1662 | # show_output = :off, 1663 | # obj_val_upper_bound = d_feas_1) 1664 | 1665 | 1666 | ## Function that generates bounds on the variables from solving the SDP relaxation of the QCQO 1667 | # --------------------------------------------------------------------- 1668 | 1669 | function bound_generator_through_SDP_relaxation(N, L, R, ν_feas; 1670 | show_output = :off, 1671 | obj_val_upper_bound = default_obj_val_upper_bound) 1672 | 1673 | M_λ = SDP_relaxation_solver_for_bound_generation(N, L, R; 1674 | c_λ=1, c_h=0, c_Z=0, 1675 | show_output = :off, 1676 | obj_val_upper_bound = default_obj_val_upper_bound) 1677 | 1678 | M_α = SDP_relaxation_solver_for_bound_generation(N, L, R; 1679 | c_λ=0, c_h=1, c_Z=0, 1680 | show_output = :off, 1681 | obj_val_upper_bound = default_obj_val_upper_bound) 1682 | 1683 | M_Z = SDP_relaxation_solver_for_bound_generation(N, L, R; 1684 | c_λ=0, c_h=0, c_Z=1, 1685 | show_output = :off, 1686 | obj_val_upper_bound = default_obj_val_upper_bound) 1687 | 1688 | @info "computing M_P" 1689 | 1690 | M_P = sqrt(M_Z) 1691 | 1692 | M_ν = ν_feas 1693 | 1694 | return M_λ, M_α, M_Z, M_P, M_ν 1695 | 1696 | end 1697 | 1698 | 1699 | # L = 1 1700 | # N = 5 1701 | # R = 1 1702 | # h_test = feasible_h_generator(N, L; step_size_type = :Default) 1703 | # 1704 | # default_obj_val_upper_bound = 1e6 1705 | # # 1706 | # p_feas_1, G_feas_1, Ft_feas_1 = solve_primal_with_known_stepsizes(N, L, h_test, R; show_output = :on) 1707 | # # 1708 | # d_feas_1, ℓ_1_norm_λ_feas_1, tr_Z_feas_1, λ_feas_1, ν_feas_1, Z_feas_1, L_cholesky_feas_1, h_feas_1, idx_set_λ_feas_1_effective = solve_dual_PEP_with_known_stepsizes(N, L, h_test, R; show_output = :off, 1709 | # ϵ_tol_feas = 1e-6, 1710 | # objective_type = :default, 1711 | # obj_val_upper_bound = default_obj_val_upper_bound) 1712 | # # 1713 | # 1714 | # M_λ = SDP_relaxation_solver_for_bound_generation(N, L, R; 1715 | # c_λ=1, c_h=0, c_Z=0, 1716 | # show_output = :off, 1717 | # obj_val_upper_bound = d_feas_1) 1718 | # 1719 | # M_h = SDP_relaxation_solver_for_bound_generation(N, L, R; 1720 | # c_λ=0, c_h=1, c_Z=0, 1721 | # show_output = :off, 1722 | # obj_val_upper_bound = d_feas_1) 1723 | # 1724 | # M_Z = SDP_relaxation_solver_for_bound_generation(N, L, R; 1725 | # c_λ=0, c_h=0, c_Z=1, 1726 | # show_output = :off, 1727 | # obj_val_upper_bound = d_feas_1) 1728 | # 1729 | # M_λ, M_h, M_Z, M_P, M_ν = bound_generator_through_SDP_relaxation(N, L, R, ν_feas_1; show_output = :off, obj_val_upper_bound = d_feas_1) 1730 | 1731 | --------------------------------------------------------------------------------