From f299e9d3dcba5b1c3ca7586a5aa89debd8cdf04d Mon Sep 17 00:00:00 2001 From: "Klamkin, Michael" Date: Sat, 5 Jul 2025 21:21:30 -0400 Subject: [PATCH 1/5] svg logo --- docs/src/assets/logo.png | Bin 15230 -> 0 bytes docs/src/assets/logo.svg | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) delete mode 100644 docs/src/assets/logo.png create mode 100644 docs/src/assets/logo.svg diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png deleted file mode 100644 index 4f0237d9b911a587cf9b42a61c1288f03b7e6410..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15230 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 + + + + + + + + + + + + Dualization.jl + + + Logo for Dualization.jl + + Logo for Dualization.jl, an automatic dualization feature for MathOptInterface.jl and JuMP. + June 2025 + + + + + + + + + + + + From 0e3ccda0ace540262723eb2dcc62820ca8f86d49 Mon Sep 17 00:00:00 2001 From: "Klamkin, Michael" Date: Sat, 5 Jul 2025 21:23:04 -0400 Subject: [PATCH 2/5] convex.jl --- docs/Project.toml | 2 ++ docs/src/manual.md | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index fe899df8..22496e5b 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,8 +1,10 @@ [deps] +Convex = "f65535da-76fb-5f13-bab9-19810c17039a" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Dualization = "191a621a-6537-11e9-281d-650236a99e60" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" +SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" [compat] Documenter = "1" diff --git a/docs/src/manual.md b/docs/src/manual.md index 38f942e7..a3d135a6 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -71,6 +71,21 @@ model = Model(dual_optimizer(ECOS.Optimizer)) set_attribute(model, "maxit", 5) ``` +## Using Dualization.jl with Convex.jl + +Dualization.jl can be used in conjunction with [Convex.jl](https://github.com/jump-dev/Convex.jl) by wrapping the inner optimizer with [`dual_optimizer`](@ref): + +```@repl +using JuMP, Convex, Dualization, SCS +model = Model(() -> Convex.Optimizer(dual_optimizer(SCS.Optimizer))) +@variable(model, x >= 1) +@variable(model, t) +@constraint(model, t >= exp(x)) +@objective(model, Min, t) + +optimize!(model) +``` + ## The benefit of solving the dual formulation Solving an optimization problem via its dual representation can be useful From 6a693a59fcdaa701f46081148ecd55ed0c3364d8 Mon Sep 17 00:00:00 2001 From: "Klamkin, Michael" Date: Sat, 5 Jul 2025 21:23:49 -0400 Subject: [PATCH 3/5] ECOS -> SCS --- docs/Project.toml | 1 - docs/src/manual.md | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 22496e5b..02560f57 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,7 +2,6 @@ Convex = "f65535da-76fb-5f13-bab9-19810c17039a" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Dualization = "191a621a-6537-11e9-281d-650236a99e60" -ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" diff --git a/docs/src/manual.md b/docs/src/manual.md index a3d135a6..9df05b22 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -40,8 +40,8 @@ the dualization. To dualize the model and attach the optimizer to the dual model you should do `dualize(model, optimizer)`: ```@repl dualize_model -import ECOS -dual_model = dualize(model, ECOS.Optimizer) +import SCS +dual_model = dualize(model, SCS.Optimizer) ``` ## Solve a problem using its dual formulation @@ -49,25 +49,25 @@ dual_model = dualize(model, ECOS.Optimizer) Wrap an optimizer with [`dual_optimizer`](@ref) to solve the dual of the problem instead of the primal: ```@repl -using JuMP, Dualization, ECOS -model = Model(dual_optimizer(ECOS.Optimizer)) +using JuMP, Dualization, SCS +model = Model(dual_optimizer(SCS.Optimizer)) ``` You can also set the optimizer after the model is created: ```@repl -using JuMP, Dualization, ECOS +using JuMP, Dualization, SCS model = Model() -set_optimizer(model, dual_optimizer(ECOS.Optimizer)) +set_optimizer(model, dual_optimizer(SCS.Optimizer)) ``` Pass arguments to the solver by attaching them to the solver constructor: ```@repl -using JuMP, Dualization, ECOS -model = Model(dual_optimizer(optimizer_with_attributes(ECOS.Optimizer, "maxit" => 5))) +using JuMP, Dualization, SCS +model = Model(dual_optimizer(optimizer_with_attributes(SCS.Optimizer, "maxit" => 5))) ``` or by using `JuMP.set_attribute`: ```@repl -using JuMP, Dualization, ECOS -model = Model(dual_optimizer(ECOS.Optimizer)) +using JuMP, Dualization, SCS +model = Model(dual_optimizer(SCS.Optimizer)) set_attribute(model, "maxit", 5) ``` From e909fd119f4ebd9ff2b3dd5f83c7016e3cd09510 Mon Sep 17 00:00:00 2001 From: "Klamkin, Michael" Date: Sat, 5 Jul 2025 22:07:35 -0400 Subject: [PATCH 4/5] Revert "ECOS -> SCS" This reverts commit 6a693a59fcdaa701f46081148ecd55ed0c3364d8. --- docs/Project.toml | 1 + docs/src/manual.md | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 02560f57..22496e5b 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,6 +2,7 @@ Convex = "f65535da-76fb-5f13-bab9-19810c17039a" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Dualization = "191a621a-6537-11e9-281d-650236a99e60" +ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" diff --git a/docs/src/manual.md b/docs/src/manual.md index 9df05b22..a3d135a6 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -40,8 +40,8 @@ the dualization. To dualize the model and attach the optimizer to the dual model you should do `dualize(model, optimizer)`: ```@repl dualize_model -import SCS -dual_model = dualize(model, SCS.Optimizer) +import ECOS +dual_model = dualize(model, ECOS.Optimizer) ``` ## Solve a problem using its dual formulation @@ -49,25 +49,25 @@ dual_model = dualize(model, SCS.Optimizer) Wrap an optimizer with [`dual_optimizer`](@ref) to solve the dual of the problem instead of the primal: ```@repl -using JuMP, Dualization, SCS -model = Model(dual_optimizer(SCS.Optimizer)) +using JuMP, Dualization, ECOS +model = Model(dual_optimizer(ECOS.Optimizer)) ``` You can also set the optimizer after the model is created: ```@repl -using JuMP, Dualization, SCS +using JuMP, Dualization, ECOS model = Model() -set_optimizer(model, dual_optimizer(SCS.Optimizer)) +set_optimizer(model, dual_optimizer(ECOS.Optimizer)) ``` Pass arguments to the solver by attaching them to the solver constructor: ```@repl -using JuMP, Dualization, SCS -model = Model(dual_optimizer(optimizer_with_attributes(SCS.Optimizer, "maxit" => 5))) +using JuMP, Dualization, ECOS +model = Model(dual_optimizer(optimizer_with_attributes(ECOS.Optimizer, "maxit" => 5))) ``` or by using `JuMP.set_attribute`: ```@repl -using JuMP, Dualization, SCS -model = Model(dual_optimizer(SCS.Optimizer)) +using JuMP, Dualization, ECOS +model = Model(dual_optimizer(ECOS.Optimizer)) set_attribute(model, "maxit", 5) ``` From 495176b00889966fc10a7d4d98defb7d3937bc8a Mon Sep 17 00:00:00 2001 From: "Klamkin, Michael" Date: Sat, 5 Jul 2025 22:07:43 -0400 Subject: [PATCH 5/5] Revert "convex.jl" This reverts commit 0e3ccda0ace540262723eb2dcc62820ca8f86d49. --- docs/Project.toml | 2 -- docs/src/manual.md | 15 --------------- 2 files changed, 17 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 22496e5b..fe899df8 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,10 +1,8 @@ [deps] -Convex = "f65535da-76fb-5f13-bab9-19810c17039a" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Dualization = "191a621a-6537-11e9-281d-650236a99e60" ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" -SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" [compat] Documenter = "1" diff --git a/docs/src/manual.md b/docs/src/manual.md index a3d135a6..38f942e7 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -71,21 +71,6 @@ model = Model(dual_optimizer(ECOS.Optimizer)) set_attribute(model, "maxit", 5) ``` -## Using Dualization.jl with Convex.jl - -Dualization.jl can be used in conjunction with [Convex.jl](https://github.com/jump-dev/Convex.jl) by wrapping the inner optimizer with [`dual_optimizer`](@ref): - -```@repl -using JuMP, Convex, Dualization, SCS -model = Model(() -> Convex.Optimizer(dual_optimizer(SCS.Optimizer))) -@variable(model, x >= 1) -@variable(model, t) -@constraint(model, t >= exp(x)) -@objective(model, Min, t) - -optimize!(model) -``` - ## The benefit of solving the dual formulation Solving an optimization problem via its dual representation can be useful