From 113e383021872114bd86c30d57e55b74ecf876ba Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Thu, 14 Nov 2024 22:06:22 +0000 Subject: [PATCH] build based on cc217b1 --- previews/PR3883/.documenter-siteinfo.json | 2 +- previews/PR3883/JuMP.pdf | Bin 6312889 -> 6313449 bytes .../PR3883/api/JuMP.Containers/index.html | 30 +- previews/PR3883/api/JuMP/index.html | 556 +- .../algebraic_modeling_languages/index.html | 2 +- .../PR3883/background/bibliography/index.html | 2 +- previews/PR3883/changelog/index.html | 2 +- .../PR3883/developers/checklists/index.html | 2 +- .../PR3883/developers/contributing/index.html | 2 +- .../custom_solver_binaries/index.html | 2 +- .../PR3883/developers/extensions/index.html | 2 +- previews/PR3883/developers/roadmap/index.html | 2 +- previews/PR3883/developers/style/index.html | 2 +- .../extensions/DimensionalData/index.html | 2 +- .../PR3883/extensions/introduction/index.html | 2 +- previews/PR3883/index.html | 2 +- previews/PR3883/installation/index.html | 2 +- previews/PR3883/manual/callbacks/index.html | 2 +- previews/PR3883/manual/complex/index.html | 2 +- previews/PR3883/manual/constraints/index.html | 2 +- previews/PR3883/manual/containers/index.html | 2 +- previews/PR3883/manual/expressions/index.html | 2 +- previews/PR3883/manual/models/index.html | 2 +- previews/PR3883/manual/nlp/index.html | 2 +- previews/PR3883/manual/nonlinear/index.html | 2 +- previews/PR3883/manual/objective/index.html | 2 +- previews/PR3883/manual/solutions/index.html | 2 +- previews/PR3883/manual/variables/index.html | 2 +- .../PR3883/moi/background/duality/index.html | 2 +- .../infeasibility_certificates/index.html | 2 +- .../moi/background/motivation/index.html | 2 +- .../background/naming_conventions/index.html | 2 +- previews/PR3883/moi/changelog/index.html | 2 +- .../moi/developer/checklists/index.html | 2 +- previews/PR3883/moi/index.html | 2 +- .../PR3883/moi/manual/constraints/index.html | 2 +- previews/PR3883/moi/manual/models/index.html | 2 +- .../PR3883/moi/manual/modification/index.html | 2 +- .../PR3883/moi/manual/solutions/index.html | 2 +- .../moi/manual/standard_form/index.html | 2 +- .../PR3883/moi/manual/variables/index.html | 2 +- .../PR3883/moi/reference/callbacks/index.html | 2 +- .../moi/reference/constraints/index.html | 2 +- .../PR3883/moi/reference/errors/index.html | 2 +- .../PR3883/moi/reference/models/index.html | 4 +- .../moi/reference/modification/index.html | 2 +- .../PR3883/moi/reference/nonlinear/index.html | 2 +- .../moi/reference/standard_form/index.html | 2 +- .../PR3883/moi/reference/variables/index.html | 2 +- previews/PR3883/moi/release_notes/index.html | 2 +- .../submodules/Benchmarks/overview/index.html | 2 +- .../Benchmarks/reference/index.html | 2 +- .../Bridges/implementation/index.html | 2 +- .../Bridges/list_of_bridges/index.html | 2 +- .../submodules/Bridges/overview/index.html | 2 +- .../submodules/Bridges/reference/index.html | 2 +- .../FileFormats/overview/index.html | 2 +- .../FileFormats/reference/index.html | 2 +- .../submodules/Nonlinear/overview/index.html | 2 +- .../submodules/Nonlinear/reference/index.html | 2 +- .../moi/submodules/Test/overview/index.html | 2 +- .../moi/submodules/Test/reference/index.html | 2 +- .../submodules/Utilities/overview/index.html | 2 +- .../submodules/Utilities/reference/index.html | 4 +- .../tutorials/bridging_constraint/index.html | 2 +- .../PR3883/moi/tutorials/example/index.html | 2 +- .../moi/tutorials/implementing/index.html | 2 +- .../PR3883/moi/tutorials/latency/index.html | 2 +- .../manipulating_expressions/index.html | 2 +- .../moi/tutorials/mathprogbase/index.html | 2 +- previews/PR3883/packages/Alpine/index.html | 2 +- .../PR3883/packages/AmplNLWriter/index.html | 2 +- previews/PR3883/packages/BARON/index.html | 2 +- .../PR3883/packages/BilevelJuMP/index.html | 2 +- previews/PR3883/packages/CDCS/index.html | 2 +- previews/PR3883/packages/CDDLib/index.html | 2 +- previews/PR3883/packages/COPT/index.html | 2 +- previews/PR3883/packages/COSMO/index.html | 2 +- previews/PR3883/packages/CPLEX/index.html | 2 +- previews/PR3883/packages/CSDP/index.html | 2 +- previews/PR3883/packages/Cbc/index.html | 2 +- previews/PR3883/packages/Clarabel/index.html | 2 +- previews/PR3883/packages/Clp/index.html | 2 +- previews/PR3883/packages/DAQP/index.html | 2 +- previews/PR3883/packages/DSDP/index.html | 2 +- previews/PR3883/packages/DiffOpt/index.html | 2 +- .../DisjunctiveProgramming/index.html | 2 +- .../PR3883/packages/Dualization/index.html | 2 +- previews/PR3883/packages/EAGO/index.html | 2 +- previews/PR3883/packages/ECOS/index.html | 2 +- previews/PR3883/packages/GAMS/index.html | 2 +- previews/PR3883/packages/GLPK/index.html | 2 +- previews/PR3883/packages/Gurobi/index.html | 2 +- previews/PR3883/packages/HiGHS/index.html | 2 +- previews/PR3883/packages/Hypatia/index.html | 2 +- .../PR3883/packages/InfiniteOpt/index.html | 2 +- previews/PR3883/packages/Ipopt/index.html | 2 +- previews/PR3883/packages/Juniper/index.html | 2 +- previews/PR3883/packages/KNITRO/index.html | 2 +- previews/PR3883/packages/Loraine/index.html | 2 +- previews/PR3883/packages/MAiNGO/index.html | 2 +- previews/PR3883/packages/MadNLP/index.html | 2 +- previews/PR3883/packages/Manopt/index.html | 2 +- previews/PR3883/packages/MathOptAI/index.html | 2 +- .../packages/MathOptSymbolicAD/index.html | 2 +- previews/PR3883/packages/MiniZinc/index.html | 2 +- .../PR3883/packages/MosekTools/index.html | 2 +- .../MultiObjectiveAlgorithms/index.html | 2 +- .../PR3883/packages/NEOSServer/index.html | 2 +- previews/PR3883/packages/NLopt/index.html | 2 +- previews/PR3883/packages/OSQP/index.html | 2 +- previews/PR3883/packages/Optim/index.html | 2 +- .../PR3883/packages/PATHSolver/index.html | 2 +- previews/PR3883/packages/Pajarito/index.html | 2 +- .../ParametricOptInterface/index.html | 2 +- previews/PR3883/packages/Pavito/index.html | 2 +- previews/PR3883/packages/Percival/index.html | 2 +- .../packages/PiecewiseLinearOpt/index.html | 2 +- previews/PR3883/packages/Plasmo/index.html | 2 +- previews/PR3883/packages/PolyJuMP/index.html | 2 +- previews/PR3883/packages/ProxSDP/index.html | 2 +- previews/PR3883/packages/SCIP/index.html | 2 +- previews/PR3883/packages/SCS/index.html | 2 +- previews/PR3883/packages/SDDP/index.html | 2 +- previews/PR3883/packages/SDPA/index.html | 2 +- previews/PR3883/packages/SDPLR/index.html | 2 +- previews/PR3883/packages/SDPNAL/index.html | 2 +- previews/PR3883/packages/SDPT3/index.html | 2 +- previews/PR3883/packages/SeDuMi/index.html | 2 +- .../PR3883/packages/SumOfSquares/index.html | 2 +- previews/PR3883/packages/Tulip/index.html | 2 +- previews/PR3883/packages/Xpress/index.html | 2 +- previews/PR3883/packages/solvers/index.html | 2 +- previews/PR3883/release_notes/index.html | 2 +- previews/PR3883/should_i_use/index.html | 2 +- .../benders_decomposition/index.html | 4 +- .../{e9c52a5b.svg => 49ed2924.svg} | 670 +- .../{288f43e8.svg => 8556e87d.svg} | 1002 +- .../index.html | 12 +- .../algorithms/parallelism/index.html | 2 +- .../tutorials/algorithms/pdhg/index.html | 8 +- .../{2d5113d5.svg => 3f125c99.svg} | 132 +- .../{134fd116.svg => 5e7fb998.svg} | 650 +- .../{213f43dc.svg => e87a99c5.svg} | 200 +- .../algorithms/rolling_horizon/index.html | 4 +- .../{38097785.svg => 165b2136.svg} | 142 +- .../{dfd68138.svg => a7fbb5cd.svg} | 142 +- .../tsp_lazy_constraints/index.html | 6 +- .../optimal_power_flow/index.html | 6 +- .../{3aed991e.svg => b171715f.svg} | 124 +- .../{39f0cd07.svg => bc3c0452.svg} | 56 +- .../{2c4c5c3d.svg => c41a66da.svg} | 120 +- .../applications/power_systems/index.html | 10 +- .../two_stage_stochastic/2040fe83.svg | 90 - .../two_stage_stochastic/2e0b8dfe.svg | 99 + .../two_stage_stochastic/3ea6dc63.svg | 86 - .../two_stage_stochastic/52aae8ac.svg | 100 - .../two_stage_stochastic/60389e63.svg | 81 + .../two_stage_stochastic/af4ea909.svg | 85 + .../two_stage_stochastic/b54f1361.svg | 124 - .../two_stage_stochastic/e7af78cc.svg | 116 + .../two_stage_stochastic/index.html | 62 +- .../tutorials/applications/web_app/index.html | 2 +- .../conic/arbitrary_precision/index.html | 4 +- .../tutorials/conic/dualization/index.html | 50 +- .../{1c6da16e.svg => 43c7637c.svg} | 4856 +- .../{cf8278dc.svg => b4aed6d4.svg} | 4854 +- .../tutorials/conic/ellipse_approx/index.html | 12 +- .../conic/experiment_design/index.html | 2 +- .../tutorials/conic/introduction/index.html | 2 +- .../conic/logistic_regression/index.html | 2 +- .../{1d7402ce.svg => 42634a72.svg} | 76 +- .../{982b4ee4.svg => 46ffd47b.svg} | 70 +- .../tutorials/conic/min_ellipse/index.html | 6 +- .../conic/quantum_discrimination/index.html | 6 +- .../{f3de8948.svg => 4697fce8.svg} | 70 +- .../conic/simple_examples/index.html | 4 +- .../tutorials/conic/start_values/index.html | 16 +- .../conic/tips_and_tricks/index.html | 2 +- .../getting_started/debugging/index.html | 2 +- .../index.html | 2 +- .../getting_started_with_JuMP/index.html | 2 +- .../{636b167a.svg => 1a1f2b45.svg} | 118 +- .../{a2c63921.svg => 703210f8.svg} | 94 +- .../{58ebee83.svg => a51d3326.svg} | 88 +- .../index.html | 10 +- .../getting_started_with_julia/index.html | 10 +- .../index.html | 2 +- .../getting_started/introduction/index.html | 2 +- .../performance_tips/index.html | 2 +- .../sum_if/{25f1d0dd.svg => 2cf4c5ce.svg} | 84 +- .../getting_started/sum_if/3e8eef6f.svg | 70 - .../getting_started/sum_if/a3ce4cb5.svg | 68 + .../getting_started/sum_if/index.html | 8 +- .../getting_started/tolerances/index.html | 60 +- .../PR3883/tutorials/linear/basis/index.html | 6 +- .../tutorials/linear/callbacks/index.html | 2 +- .../tutorials/linear/cannery/index.html | 4 +- .../linear/constraint_programming/index.html | 2 +- .../PR3883/tutorials/linear/diet/index.html | 8 +- .../{5de62185.svg => 0cee6d7b.svg} | 108 +- .../{5c23b133.svg => 6ab085da.svg} | 84 +- .../{9bde3a39.svg => 9fe6d5ff.svg} | 94 +- .../{e66d5c8c.svg => ddddcc2e.svg} | 108 +- .../linear/facility_location/index.html | 8 +- .../{0debf07b.svg => 92045306.svg} | 124 +- .../{66e5af17.svg => a24accc9.svg} | 296 +- .../{da6c3496.svg => b191ac09.svg} | 292 +- .../linear/factory_schedule/index.html | 6 +- .../tutorials/linear/finance/index.html | 2 +- .../linear/geographic_clustering/index.html | 2 +- .../tutorials/linear/introduction/index.html | 2 +- .../tutorials/linear/knapsack/index.html | 4 +- .../linear/lp_sensitivity/index.html | 6 +- .../tutorials/linear/mip_duality/index.html | 2 +- .../PR3883/tutorials/linear/multi/index.html | 6 +- .../linear/multi_commodity_network/index.html | 4 +- .../multi_objective_examples/index.html | 8 +- .../{03994a8f.svg => 507cefa3.svg} | 80 +- .../{45db6708.svg => 81966ccb.svg} | 78 +- .../multi_objective_knapsack/index.html | 8 +- .../tutorials/linear/n-queens/index.html | 2 +- .../tutorials/linear/network_flows/index.html | 2 +- .../{3b80eb12.svg => 04fcb52f.svg} | 58 +- .../{d07b667d.svg => 11d4e316.svg} | 100 +- .../{774ec400.svg => 2c380a25.svg} | 62 +- .../{db234900.svg => 33288e92.svg} | 96 +- .../{03885d79.svg => 42fa819d.svg} | 70 +- .../{81c47fc0.svg => 44b22d67.svg} | 90 +- .../{6e263b52.svg => 5cd3b58f.svg} | 96 +- .../{06001372.svg => 619333d3.svg} | 66 +- .../{ae105088.svg => 9b872596.svg} | 92 +- .../{97e726a7.svg => a6799ee2.svg} | 60 +- .../{2fab6f90.svg => ae929f6d.svg} | 56 +- .../{60abc362.svg => c3fb6531.svg} | 66 +- .../linear/piecewise_linear/index.html | 24 +- .../PR3883/tutorials/linear/sudoku/index.html | 2 +- .../linear/tips_and_tricks/index.html | 2 +- .../PR3883/tutorials/linear/transp/index.html | 2 +- .../{a4bf0e74.svg => 011c4738.svg} | 1056 +- .../{32a4e5ef.svg => 11ef2d78.svg} | 1072 +- .../{27207c09.svg => 13aac46f.svg} | 254 +- .../{729ee2e4.svg => 1c0a1f6b.svg} | 41796 ++++++++-------- .../{422e11f8.svg => 2076085a.svg} | 1070 +- .../{bbed3495.svg => 944e7683.svg} | 2054 +- .../{ae78bd87.svg => c114f723.svg} | 256 +- .../{b8219642.svg => e3458f44.svg} | 1058 +- .../{492869a0.svg => fa31df97.svg} | 1056 +- .../nonlinear/classifiers/index.html | 18 +- .../nonlinear/complementarity/index.html | 2 +- .../nonlinear/introduction/index.html | 2 +- .../nonlinear/nested_problems/index.html | 6 +- .../nonlinear/operator_ad/index.html | 2 +- .../portfolio/{db4e55a6.svg => 6f1e4109.svg} | 1126 +- .../tutorials/nonlinear/portfolio/index.html | 6 +- .../nonlinear/querying_hessians/index.html | 2 +- .../{6fef5492.svg => cc2e1628.svg} | 206 +- .../nonlinear/rocket_control/index.html | 4 +- .../nonlinear/simple_examples/index.html | 2 +- .../{6e83781f.svg => 10cd4d7a.svg} | 148 +- .../{d413215e.svg => 6a49d815.svg} | 66 +- .../{92c535be.svg => 9d7cfd7d.svg} | 294 +- .../index.html | 6 +- .../nonlinear/tips_and_tricks/index.html | 2 +- .../user_defined_hessians/index.html | 4 +- .../transitioning_from_matlab/index.html | 4 +- 266 files changed, 34743 insertions(+), 34762 deletions(-) rename previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/{e9c52a5b.svg => 49ed2924.svg} (72%) rename previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/{288f43e8.svg => 8556e87d.svg} (69%) rename previews/PR3883/tutorials/algorithms/rolling_horizon/{2d5113d5.svg => 3f125c99.svg} (90%) rename previews/PR3883/tutorials/algorithms/rolling_horizon/{134fd116.svg => 5e7fb998.svg} (87%) rename previews/PR3883/tutorials/algorithms/rolling_horizon/{213f43dc.svg => e87a99c5.svg} (86%) rename previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/{38097785.svg => 165b2136.svg} (80%) rename previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/{dfd68138.svg => a7fbb5cd.svg} (80%) rename previews/PR3883/tutorials/applications/power_systems/{3aed991e.svg => b171715f.svg} (86%) rename previews/PR3883/tutorials/applications/power_systems/{39f0cd07.svg => bc3c0452.svg} (85%) rename previews/PR3883/tutorials/applications/power_systems/{2c4c5c3d.svg => c41a66da.svg} (86%) delete mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/2040fe83.svg create mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/2e0b8dfe.svg delete mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/3ea6dc63.svg delete mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/52aae8ac.svg create mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/60389e63.svg create mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/af4ea909.svg delete mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/b54f1361.svg create mode 100644 previews/PR3883/tutorials/applications/two_stage_stochastic/e7af78cc.svg rename previews/PR3883/tutorials/conic/ellipse_approx/{1c6da16e.svg => 43c7637c.svg} (57%) rename previews/PR3883/tutorials/conic/ellipse_approx/{cf8278dc.svg => b4aed6d4.svg} (57%) rename previews/PR3883/tutorials/conic/min_ellipse/{1d7402ce.svg => 42634a72.svg} (88%) rename previews/PR3883/tutorials/conic/min_ellipse/{982b4ee4.svg => 46ffd47b.svg} (88%) rename previews/PR3883/tutorials/conic/simple_examples/{f3de8948.svg => 4697fce8.svg} (79%) rename previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/{636b167a.svg => 1a1f2b45.svg} (82%) rename previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/{a2c63921.svg => 703210f8.svg} (84%) rename previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/{58ebee83.svg => a51d3326.svg} (85%) rename previews/PR3883/tutorials/getting_started/sum_if/{25f1d0dd.svg => 2cf4c5ce.svg} (51%) delete mode 100644 previews/PR3883/tutorials/getting_started/sum_if/3e8eef6f.svg create mode 100644 previews/PR3883/tutorials/getting_started/sum_if/a3ce4cb5.svg rename previews/PR3883/tutorials/linear/facility_location/{5de62185.svg => 0cee6d7b.svg} (79%) rename previews/PR3883/tutorials/linear/facility_location/{5c23b133.svg => 6ab085da.svg} (80%) rename previews/PR3883/tutorials/linear/facility_location/{9bde3a39.svg => 9fe6d5ff.svg} (81%) rename previews/PR3883/tutorials/linear/facility_location/{e66d5c8c.svg => ddddcc2e.svg} (79%) rename previews/PR3883/tutorials/linear/factory_schedule/{0debf07b.svg => 92045306.svg} (85%) rename previews/PR3883/tutorials/linear/factory_schedule/{66e5af17.svg => a24accc9.svg} (78%) rename previews/PR3883/tutorials/linear/factory_schedule/{da6c3496.svg => b191ac09.svg} (78%) rename previews/PR3883/tutorials/linear/multi_objective_knapsack/{03994a8f.svg => 507cefa3.svg} (83%) rename previews/PR3883/tutorials/linear/multi_objective_knapsack/{45db6708.svg => 81966ccb.svg} (87%) rename previews/PR3883/tutorials/linear/piecewise_linear/{3b80eb12.svg => 04fcb52f.svg} (85%) rename previews/PR3883/tutorials/linear/piecewise_linear/{d07b667d.svg => 11d4e316.svg} (84%) rename previews/PR3883/tutorials/linear/piecewise_linear/{774ec400.svg => 2c380a25.svg} (85%) rename previews/PR3883/tutorials/linear/piecewise_linear/{db234900.svg => 33288e92.svg} (80%) rename previews/PR3883/tutorials/linear/piecewise_linear/{03885d79.svg => 42fa819d.svg} (86%) rename previews/PR3883/tutorials/linear/piecewise_linear/{81c47fc0.svg => 44b22d67.svg} (78%) rename previews/PR3883/tutorials/linear/piecewise_linear/{6e263b52.svg => 5cd3b58f.svg} (92%) rename previews/PR3883/tutorials/linear/piecewise_linear/{06001372.svg => 619333d3.svg} (82%) rename previews/PR3883/tutorials/linear/piecewise_linear/{ae105088.svg => 9b872596.svg} (82%) rename previews/PR3883/tutorials/linear/piecewise_linear/{97e726a7.svg => a6799ee2.svg} (81%) rename previews/PR3883/tutorials/linear/piecewise_linear/{2fab6f90.svg => ae929f6d.svg} (86%) rename previews/PR3883/tutorials/linear/piecewise_linear/{60abc362.svg => c3fb6531.svg} (94%) rename previews/PR3883/tutorials/nonlinear/classifiers/{a4bf0e74.svg => 011c4738.svg} (62%) rename previews/PR3883/tutorials/nonlinear/classifiers/{32a4e5ef.svg => 11ef2d78.svg} (63%) rename previews/PR3883/tutorials/nonlinear/classifiers/{27207c09.svg => 13aac46f.svg} (72%) rename previews/PR3883/tutorials/nonlinear/classifiers/{729ee2e4.svg => 1c0a1f6b.svg} (69%) rename previews/PR3883/tutorials/nonlinear/classifiers/{422e11f8.svg => 2076085a.svg} (62%) rename previews/PR3883/tutorials/nonlinear/classifiers/{bbed3495.svg => 944e7683.svg} (61%) rename previews/PR3883/tutorials/nonlinear/classifiers/{ae78bd87.svg => c114f723.svg} (73%) rename previews/PR3883/tutorials/nonlinear/classifiers/{b8219642.svg => e3458f44.svg} (62%) rename previews/PR3883/tutorials/nonlinear/classifiers/{492869a0.svg => fa31df97.svg} (62%) rename previews/PR3883/tutorials/nonlinear/portfolio/{db4e55a6.svg => 6f1e4109.svg} (79%) rename previews/PR3883/tutorials/nonlinear/rocket_control/{6fef5492.svg => cc2e1628.svg} (89%) rename previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/{6e83781f.svg => 10cd4d7a.svg} (88%) rename previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/{d413215e.svg => 6a49d815.svg} (87%) rename previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/{92c535be.svg => 9d7cfd7d.svg} (88%) diff --git a/previews/PR3883/.documenter-siteinfo.json b/previews/PR3883/.documenter-siteinfo.json index aaa892a6af5..2dddaba2581 100644 --- a/previews/PR3883/.documenter-siteinfo.json +++ b/previews/PR3883/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-14T21:21:38","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-14T21:42:56","documenter_version":"1.7.0"}} \ No newline at end of file diff --git a/previews/PR3883/JuMP.pdf b/previews/PR3883/JuMP.pdf index 5bb0a008367bcb928f971b4f24511b9a98e52e89..553bb5cde37c331135187f10109cecc583e54d27 100644 GIT binary patch delta 262949 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®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 %sQ-w+;BZrxB~A~$At@FA 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
?Dkog`A<3G;F6=wy-B91f)C?Gh;>!nrJ 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 UU{;b-mRFQjVHOcNZ?4DuKcO)O%>V!Z delta 262559 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�oXlSg3y1Tf1leOn5W$T$X5u@!WbLw zn%KjJ&r!18S$yiHE6Y8tr62(gq3yoDeSVO68NgQ2>kL@c7O82&)gZk>;8>he}wK* zcl?kmPSbd_t323;uj(O|s!A&6?DXen`4+{cKVsrc0j znovBEV2j&G@ni*|Es77OMr>5{oJ}Mck;p;ds7C9Z3W|*6ikWP6vU=V33O?YFC{)`LMMbYrzv)cXfmV~R;MPAa z5?sB5{oAYGdC4=8!#8VH$EZB6_#~NWy@Vd2_i<;VUwY14ka;brgDGa-<+P(xM9@e!#@e*mUu5qKDUFV88DKL!A!Nfr#{A>k86 z+CJow$8)$WiBegjAix$Og@Oa|rEzK&NixE_!YZyi0*zK!a<@2w#Uf_TjAMPf5v}Xs zWNc6CHXC(}k>`2l)zh0=H3}!;CVeawF>?#DSaV(M9UU_puwaO*AE@?y-Q}KfqeHLZ ze+I5GW=+*q`{LT8_VfN3%}z-z9GhV?JI!yzPbtqLnI)WGpHfyR8ZGa5!X_|qUeW9C z9wQ4JYmXd%4*6lNKPMB41GJGpCu4=L?mW6}>XlLba0D>VpIAcu_w#$#-1+UbUjm24 zyo*oY0o2qL`lOuuH=TJdcX0RwBqXSNe>!|Z5_$`VA4ieB#lb8VF>_{2o9H(3_!PXC z?K5~iNXl$(n5!IzRCx&%lK9yTt|pDG)sLBMv3_k6m;vXfH|cVjfSH?@g{pU>3Ur(t zt6F9YmCfkNbMdT%iouhHVpl^Sl_)C36#sPW$%4!_bV4YU8?9goofr~^wbMwTf4;1^ ziW5+4p%B+_!W{oSgEx>_NlSmhsV^c4@B$5vB+BzN!TjtP1jVbGwJB%d$P zQ>3!f&M0yDYc)ngYnQ9m1IUuRv?GbSk+_;Zk*@~ep7e>z2}numed!Yw2~Xx0m%CWR z%$Wi5n2ieH7(BYI{-xG551Bdxe_bBuQQ`V|POYEEcz=^-mWr6U8G}!ICo)u)lW|Tk zNPbBkZGPFHcO3L6Gu+p)F88v7e^4YQbLjvz z;SyI~-hio*8>D~v5SC;-blsoK=UPypQN?ZC>;<`>7^MYh+m6cTdZT@2w6LZY_k;c; zmIEwupp|!sQs?E6jTv>>uk|dm23+}6Ga}-1+E~N5TDU9Kn|*F4^KefCU8pkN^*b*) zE~Q;CLXL;oUXi_Cq{Y!)f2PKZ0UdJ|aF)@mDwT52lw>bfD)aTEY@4f~xr#ZeN1w3q zB_$)Vr{VCbnc&(uQGsJB+p2b;6i1<|f~YUAdQr_l3d51XscjEzDARKK_uK?$S(Ki*S7mJuVGj^25Z&a@U#{*q8e^51Gzqoxqr61W8 zE=s@RhzHL;Gn(poGFCPCYU-i1-uGLP4)v(|kbf(3jNyHjNJBO&TiG=U=0wo99;*o* z7$Yp*TLqq}jqSloA^Wqznw6W}TrLI443x9bpZS+htOcq1`!tA~eQw9)<)qcio$f4JXr8u1};u3q;9o*}7MY9l;}Q(QQ^JNLQ3i5~>#>Sa&BiO5`o z8^MW|!{0HUevsuZwf13=xoq<+YcZy)*FJ%%V&aoqc~E5pcs0WGaD8vGXEm2Mr^`yA z9@xcTu3q#6m`vWD^hRJps>!xs?sKzO09BGM16qzgvQ|!he{?z*(A5i{092+ZXd6H! z31w*nsLj~yYXyF}2fYWTtJi)VQ=g)mO(69s5XR>iuIHoG6rZ&b`R&;JoOvdqt5<#< zP@CeKO#pR@({*zeP~ZQI^dm@q^{OX+m>7eaO|Z0_etLU0{xtn5??-LUwF@7m>CN>& zzo!Td3T19&mxdEt4wtIu1Q(b2hCU~kj<-7qf9F@|4=l^!%q_QC`tfX9ZrX@FQ4ypfdO)av*Y8--M@EpAZ$Tt z3&Wp3?&1I;DD-9k@G3A3KmQ)S-TgL-sG_y<@l3v-FJyX=#e=n0jxNgl@>LIi$>3+1 zjKL58rKvySbS(>n;h*6Tk+090_aMw`e`}d9n1`U8H6lDHj6<1u7TowK*jYZp5eP33 zv?hJ{WVLYZ9mF#eIl_8ow0x%P@jhW59?H3mTxMAm<>`2yxjh4Z!6#!-n!+2fH#lWh za=sI%>_w8j;xyVUWw&Vr%??f1Gw> zZ*YpJAiz$XqE+Pl6{oiFX*)Qr&;D_;^T_LFKD%)@_%uctG&}KWSTTe}KDpS}Lnoib z52xS7UN>{vjlIFC1aISTCr*JB+r{uyAKT*xnP@lc2Ax`j0PRGlMkO>XnrIEv?gLG< z8~Zw^>~og03#S~6vV@DF>0vs4e-x+v*c+U>oaOApsh5Jl(-o(oa8lFB4@yh>u{Sui zIm>xpP9=vH7s^g6XU0swkaHW{Znau)Nf9+NQKN#dVwY6gD59lVt>Z|U^?a_@c6ugw zUffMP^J@9aQPfoaGG~iqdE(jR-|W&>y;?}4m(8WQBog~(TMJ;KT0WD@e`92$yVoe_Vu;_;5#)#fK9A zPiO5ddsgoHlB?CWSN-k!S_1vp8l16L0_{z^xmCoC<||^2<#!93>pf$VY8z?n2%(#T z)LCFD9)unb$oJJljLzPcD=?kwr_rSs50XM270+WY!jiiRGS#(*>7L}B+;|Tb-*grb zXj(Ir`>CvTDteqse>ggoV0pR>on_Qdfi{Km3vHw9;t9)@*b$GtcC@pgwic2IVjelC z{~{u-=PG1^vL;+f$jRu{Hp@{AYusjCK-8$MLyojL;)n6d#n$NivyFDs22AFl@5k&Q z#qM-pl9aa3lq|?s`gAdnG*Tp!8%H)}K>GeXx6q5)*HAZVe@?|Po~E#uGobWB z@7A$_U5^d-cab~l`_6K!z7TTU*k!Mz+Ll_8f0tr${Zq^qd+pb?!GX^KWFHQ^RYZ1` zgAI1uuWN$?7X!&Y3^-Qg{VD?+vhiL`8~AMwC;Kp9NwEp53~b2D`*m$_z&Wh!!vUjW zw@Sf=6un>71_hX-%RUs4Q5Im8gVP2Mx^-=EV7x-RQ|bZ;%CdQtgVVNprC-+u2aqGz zT0R^Yt!%(m4mK1n{kk?d&^dDL!+{RUA+2(-p@iwzwZ#FZ7kh7L&2AQPTQ@q2HS1#E z@jbQ^$y2d~v;RH;9&6k6@_$P8-&+3i)$P=3tx(HR_V#~+fWdr|AqEqdUGD@JmvVJX zCbydJ1XBq9Opuuncb);z zF7i7k&8$9DwZp22t?6kz$RB^=)8A?GJ6bHAo&FP+ ze)Y>abIMKsntmYoyd}H^B0SexsgCdh83#?k9g}`45*}>&5Yg4;c+lLF7nCP9eO&yY zU%}%laK{4(e~vF{8WMn0vkd*xx(w4Y5A}6`X6v$3T4n}lGH}K(lkK4%s$N_cpy}oc zcD5|=x#2>`TO}Ri=sv)RD-2eO(f0>4m^4Z#Nx&^Z(uKkNQJ*6`6x{y@15$nw=!N`zlvRBqaj}pF|?5 z85&ziNV3S8#7r%>j#r$M0HdE|L< zfUj#5f1@9lOkYgY5AtJYu&{Ahc8Q-IER66l$;cpW+4;!@AE|HP^{ME)tXQ%*2VR`7SFxnF7Se`nA&#%m_E-iAxrrOjZMP`eStHOz8S zs~K!3J~`3l1K@e8OSyiOb-ytIfO4~ASYm)PrvyE-N^S> z^o3}la8eXCfGg>-kST!HP1NRnwizk~Ip#pZbOeGayg;!Qa>u!F5H!E@d<@YbfeNfR*sl7)fu2=ys7=FwM+z4SGUg&@+ z{z-`#I%LL{L~PYPW33v6ab1f|Va_xaC#;=Co%`=~gqhEhQ? znRqEPrdsvvB8oMS&>~XXMRAmhqH`>?Gm$P4;!y+#U~_RhdX-!r_a`Y)=5jb(cI7ZR zujpnjwMvBNn#yLrgfUrQtEPC7s=47e6kH14Wke?^U%JuYtL7?CB2d7BS`VmD2ev{iCm+?tWf?c z+T>%Sh(t7b6LOUOp1hgq0WvT9O~Yp0LY-w-BC)yOhaEPpdRIs@^&Zb@Ahd+7Bi-F= zou%%(Nq`F6s{#~P%728v9$=@PzB8pv$T{;(lWOE3&%@@IWdWejLbb+d<+f_S;J2os zRHt}nJ~G!QWGSM;~-BWMg2(^D1UK0fU8GWn`>KCmSTOH zbs;D9t<2K8Y}GHKl1Y)-s(K_%Im0$8RCniM~{Ulvrin&L?&YkBbU3e=}dS*$joaBpr>UaFp8egAh7PbS6psLnd-5O2H3NGG z@PkzRmVdYi-O#lQJ6nmllvO33YfmZ4uK2p6PqW1c=eW@{n8X$5#G3dE^VzvRr*afK zvb~(%nK&JFY&Zjxn3WT6q^;=gq?&LbVOZC8l+~HK33_w#N}MMgG9lDF4ZcC|vNq?O zrtUkZ0OZ^TLN!#9u?rjM(%357+pE&!jbcqmJAdZ1(AXJVr5L%T?mplA`kc0iI8 z+wb`A^X4I1F)3ZY<*%gG&j+yPo4;)zXB?B{Zx+upW^s$v%wfOdkMS(Nc@~k5DXIIN zf8IPxa%7SZ1XP>kklZn02mF5i_4y!-A+iYE#*tj4w|w31KRj>QE-8^AccajTh$Xy; zrhi^*e4palERJoe90f}^iW*<+7`#9f!lKZ6Jp#$bV$r46Ri+jT%G*Mn8i~%~4reW@ zuN6$xY!(_9)?7w)<)|flG^9(5M`>)|?GW=~*{0hOnxQo#lu|)l+hv)?+1WAQHpPW^ zWv?y=Ew0|icURXk)nr|^8fc5n4{(BUhks-9Lvv>6CYw#P9St%;F}`Rbb714U6Sc5A2jA;+)`PM} zTJG5i;-A3owZ2?_%?-s;;j&eWu5 znpH_`+7ZHmEQndMAOb0JnBTI7`5iuMc1S34(Q0fkJs z1|Hk$&-LZl^556$|3J4KP!a3gBRjk0KvAi&;_=;b(1Nm4{79GeW)M3uQ~p0%KIt_s zP{^E+U0q7$mp1nGz3<2G%DvIYLmzs9;bss!g_mao1vWP-XkkYxsMBUFEdl-DxC_r+ zetmNUYz^_V76)0dfGN)b!t)?cPqE(Tr})8G97P9oUNfrQPQ?hbY6N-f21dmxFivU_Ighs zL8}tzDnxqk>aLL*dQN9@!y0alF4g3q%0iUAI$zhhTX(b46S?DrdMVhS%V`%rxFVq< z>ue{sbhb8zIc3H(gO{bI*H$nvYFs7WC#%K035F|td>p=gczgQKBrt&BB)H5AJ{bJe+E>zeW?vD<*Nn8rW%a+` zemx8$-+yd)D}xA%5whf+(XO+#X3me3)r1BPpe*roM#os(7s(flXLPy|icTgJyk`U( zm4&i60_QADP%rs5ww@uz1F(P@Y+;O2X}D+-a}ygqdS1?re|U?DleYksTr&+~04mfb zv64GxxfzLl;0T;!K%B`3&!C5P#UY%_HyL(^reYqU$yx^C{x_P63X1B+WQA5#dR6z^ zw1H&?)ChG!+udT-?;v!78kjM-*ONH(EAJ3(DJ+u$CLCTLlWpmlx0fmN_e0i(c|TFk z-*58?9em)Ee`G}IJ8zkQ8pc?AKoX2JnrdokB+3NdStU`gCO7dL@uy^gjND#=Vx(lh zCZwJiz?TeAThcJ@%*cTFZ;hcrd4XZ!A8QPa z!@=o@q+VlaQQbSSEeq?|76iH~wnj3l_=P3jYknSj=(5DHKzvzV{kY;en&M?P?@#;Y z+e7j1n$gI!qS7pp?e(7Xx$`kEm)<-DCNx|y_B;k7X?_SEbDR~y$^<%0*)>_lBP~2A zTM60J(vk0jLUeYEFbN{e80eDuc(j?U>m`>sJq0R%-n3IHc;2WZN9wDG1m~N1pp3{8 z{Uv#ztY${KO&+X$78Sf5Z6+G`Y_Y&kK|Z&yExIvA!xWeSBJ0bwEf5;rE^g=W?+uWs zgT!*Km61PmC-B9sMSevr&#D3-uB z5THDNL(OnIh$}HeetG5BU`4QfBiyC#3o1e(aL=SPOnqfQRonCSRS`r9DJcQz6r=@d zlF$QDQqtWm-Q6YKozmUi&AZThfB*M>@WWxBS+i!%JTvpm+UHKQKTblXTzt)W z#2A2)HsGsK;o*HiS#Ro4Pssn6BH%d%RG#+4$HHo<49BlMUZR_7dVg&IX+A>FIn(jO zG-v5Xg8>G5u4#d}RxTN@BK&o;%C~Q5OrNB&vg1&3>8@y}_eddgZ(|w8)&uHdapjDv z%qvs(n@AZ7lO?>C(Q$qor>mad6*&#{-*4#@OYY6Mb`QC+K3@jo*J89reW*yJ zL*yjv(bEiaH*#FaFE;+Oj#FcnCkYBMZ#Pntp{t~bF0)+B$ZRdV4u%OCK~S!GbMRhP zl&P?%6(KkKFX7L3NaX?-PnpT_miXJ&Nw9P4~Z^ol&{((Zp` z|6x{#c`Uwm@lE69Z#nPNw5?^MfUQ_1dCxSY3rYoBIh&yUG)Q`&T!zJ;tQda&t3Y1* zPrdCrRrhSmOiJVS+^;DY7T=Da4cxHWs6U%9;)qL#SO|rw4t|v=Y-5~>N4+D=#*=&P zj~b@9V(p80H>x-?MSE?l=xf;Z{6{Q?PztFqf{sG8LRk*IA+5AJk?MZbYWQP+PWk$u z&WhyKjH@-I)9g^lI}(;*oax7F(nUS=9>bY|Q4$G3d=X;8avOD{`^#z(A4^Pl)8>B2 z>V5nqJ2++5V0gt(`W5FZQ%MgjTh^7#A#&v}PRs!5BDAutD2mVfo7({-?*-)JDQ45s z@x@n##BE%JVsL(vlko;WpM?>8nt~s&>7SZ;+BjPyT&CQh>!5Ee)fy@ns&cpc@naOYcCB}l-HvOe>t2ge-L@P+KAy*h zI;~vL(%>meyq;!la4SD@BpBj*^7&c1q7MINsuM9^s2Np)VuXHt?O0;iypHy9rQ@oe zGm`Y7t=ji&=v4r{X+TX0Od@5vb1b}~_)Xl4YVGBrx0}CbhA%O#jtLuk@!0hkoI2F( z?n2MML|cp)zUu1Jnc!)_laOua)xL79Db^ab;)r_c&UWZ#EpF-AW#-IRMw#>q@8f3s zk@IdI>I=Hel{Pw+<*_07!kBhK-zGCsvhbkvHtT0|Sx`+07BPK4WAe4Uk>f%NpMeL# zZ~j27&pOSM^K8!F%3cVyn`G^WsEVeKCT3%IQM=9uw~eb0_jel&>54W^AYpNO8q~ZP zdPAMM6)?eUw$V}B&mH-EH#y0et@t|o__6q=^vJ;IdKPi{z8H5ZUnr$*$oy`Vm;wtARtw1*o^N8$<auUxan4M){o-OH@x|(_=Z%4}&pfC!J$fVf^+8u1tE*+h~o)(+cG{#=( z$5i<09yUl|V2)}3+G3ty9dmrc3;R(c=1dXE<_G*bD#mbst;axfwt6;q{>q8&J*=Y8;D{X%TSGsD69(wfpOJad^6F-WzV^Z?F0p22K?>=wH7nbVl&* z(n#r$N+w@mc1eM)d^8nh^4QuJe!BzDi|d#3RJXv7LQLfJG9o1EpUlC|=bU}gnbUqJ zyn{^|-`2&Y@^#*lKC*sW+YzvE{wiGi;{KA9tP^d?yKIhs!&Kt||u`Z`+lKpWxTM{agT>%)|b9W;HPI zjVPalNo{T^>H#~97~kezO@l~(8iP%fgkriheXiImrOLTx*zApp3s*c(<&K(5-cOy& zR><=uZLEoPRYk0fr=_bEiaP}POL20>*V6>Tw)rEk=R_}Ah`$na|I++} z7bdg?IjjXb9Mpc#b}PkLpD)3=Gm$bVSe|p0b)BuMyl)!ga{aXX^7GY%4@*7;LE(yR8%OiQ(b_ad&!2^>;Uq5lsD^us!c2we5@^968kSq z^!vwc-XeB5Un!7gd)D__R77H$xBa7%!>#L>?pPe6f(qHNUO&2kSvV|zwa}il4 z=-`|`A1f?Y$QZnc&RvE1{mG)2?RR=29$SsO4KB_bnXug$%7B5d_B<534ONfY!p?^( zUPEbaMCg|SdQH(yOZj%~)!eiXLBSFWMl!Emr!uNdFBJY91FUprF-IF=3AT_m+G9o_rVrE$ccbZE}KsuW4>Ph`AYGlLD-M3<1LKG zp~QM(;@QfC?t)*Ha^i+2ru9~s3Kmv;5G_gD>O&cSIjCy!co^-b%8)eG_60K#b0gZB z=KUfG(R8MccYkrqvi-AGc^|O_-ath*aS+wtJv2+u`c?TLiVV|S66{S!=bQn|_fEpE zz0qxP(4OJDT!NmZr8)#Z`oU*@0bYW#H z?IStqCtUq1@Za}w5M63o&N4srTK&v7;HV*=JV=>j3c~d@?D9y)q zV!p81B+INuiwEVuB}yyP0k%^%5N zlgm^hO$W+hqKAVgt@!V5d7B*KxLpy1&5FTX4qtgH%tv~w^^!TV zQy?1e*)F|CcBRe)@@|Oo*zU8{SS+myqOy2bWRJ+#$QwOl>^s{%@}n8wjdps*re4oR z<<{3W(kX6N)`5SVR5c_RKKU2hZ}bS4eTP=aCv=ayjOaedE3r0<_jG3No zAJHqo45drp@4~P>`X1JI^}e0PNY5yRY^SM;@NvC*?g2Wn;@0#5jrWgh9<8|b(`#O6 zhL5`6SOK1AT0L%(`u$ac@sI`XdFG-=cLPyW<|JyPj_{~Mi|hg!Up~hx_)q*6YOj4| z7V#XU8`4D8D+Sq1f3(HIVh|?#h0A6fVBqEu`Q`6%a-^GDAwzzPLI)BSemMF1Ul?9& zuCldKUUd@0rEV=oa#wm}egffiJZPBZ2Ss(D`+;qGjS`vf}jmBy!v9Fom{; zcJC$Mqh9YNqmw}Ji9fYOqdL*#yR=w?ujY@^K->gVv61J@oN9Qg8Jv9@*)44DrTR%a zJ?~(>E`O4*-rV=NEViC>t`$oO>fs$JuemEcpH~+6K^F8$bH8FlE5U0tLkmZ|x6Op# zz*B<9rztj&GVt{Z&1$iG_*eVRy;O4MZ`RER>ItJC@!eR1$eGc6zNH-AAl%`z-F78N zEEu?52-VIXu6}sEV;2YA3=VJ-Ox=#%ZUuhtf7!k?jUwP|?QwzFT=u1v2%35F`1ZXdW{AyoSPoPD;Tht4Kkd-is=o%oO?_sCKwMuUqkTzQfDHrF5Foo36h zJ+{Z5M&Ro3@x*w`#PR9~e!sY@<~-V@q2b9%hZgr5vioMIRFHV#Gb~8q;}wMy+N8aw z>*K8FU+kK>WHu>t-kD?Wl#_Vn+-uQYKMB8X>{ytd1MCEKjvBXssDUgvTzBVp38F)U0&jHaSWB#(Wxw0lwOxG%49^N zn>48;ShQmO?P{px=T1_;CDG~?*;iIw-zQ~gFT*`mOFV1BMY%{Vu&FKl6nLo;>_@8@ z%S(ww_Hwoq!<5E5Ep*yUOJoE5Grq{o-alnhMa_MK5k4O~v zOIa$2xcYFfaL{sH(@WmviPxj)FLXswZ@Ok!oV$CGUh1IgSa*Wo{(JS?#YWUfSX~UE z)5tbVzD>K{?=7+h^3lQa>~Ur-cO9jxMKi92!^O$=qm6HA_ir{cnBm~wb$HV|_8S*z9=k37RH zMAJFm7;SlshZjI1qT^9`d3%zOrNIX#pD4HPiFS3#9OUK= zW*OV}esZMJ6l`J2RawM{s~SZ4wft%FLT?~XZ($_ExXqCv8U19`c5#1}!JQ?fo9^f7 zH~2T~&w|m~4E>a>%lc1Rou%h+rgHAuY&$sLsZ+>I5hawt9dzd^$!^Lj4E{vny?RVH zMT$o{7pBHAL}l1wBXGr$wVowCWVCq@eCnt3wIi0{n$$<_ThWGAiH~L5klx1+Aqsnt z11#B)ekZ5@^UsWD2$$*C@;ee~o8@tM4u~F8b)&VBghG+4d_jiAIPnHqb=l5}NeJge za&gdh<@Uvpweq&elXvPJuP~3D`pW~E*s{8C|rdGFu=|8zr zVsFX?%gF@U9l3XL3jcX=UWy+s?YZ1j2q`3D4NKe^>JunqH5{r~+8S~czPmaP&f_SV zQM?i6ChvaL{dT|H{H#^4QA^Vm$*ouJWe??=kc;jM_RUm9) znBBsn3@5h6$@v&CUp&-x*tD`3q}jG&?gu^_DN{$XnMUEMMPQqE%3sh%^0aSx&q6^K zNg^bXcH5*~RSY{v3(K(>9C&Y~O+L~N`Y)owpl>v<9->Yg^Go1JRlXKiZW~X^YgR{w z8G3>;{OHK*{82vT9xhz2kN=KC4u4tTfsDx`W`&KtvXyX89MWI03h%;xkJ0$k(TI%2 zn*@vY%SaA}%BrS1!gnh?87L)AA`OR5nuR|s5oFax-Kd>mK;){?);uQTH)gwa=G#4uu(*NVkDi&M7O8xjORSFOc7>YsO#$p zF?r2?5661sBu}oBwb3I9c)L))@Rl9Y|i`r;q zxlA!qB}E%0l)LFUzHp6#oeR@|AcO4=>d8EjrQwOmu+t^*qlj|wE>z5yLav^vF9O}{ z924C+Py;s~JyicJJFbWFYT40E;p(DSNT z&T-0W>XUhDJv?fue?FHXIEbPTgn(tQf5+LBIUfewlq?K0o+C-$kR7DBq9(o zZ>d*Ah0xS;VyV*}Vf#Ikk`8uCRI?K;T^NK|hF?|_q(s9eGrM@V7({S{zOInzU`2N8 z(TJ*@$iJWN>%4NTK_UPc+~*9J<>+j=F!{=Aqez5Q8$pi6gEf(yQ1Zoyx%H zh2I)Apus&uecVEM;>ExNrH^CQ^h=geXfBbvydTHl@vUt6HQ=2Gmv)YPS;tSz@#!DT zAqu?OL0`Eowbk78<;b1SLwdT!&m4>QNJSW)p1rBEcFfgQabgu4qjH;AR1`eSMQWU* zXy~pSEAamLUivbm~3FB7Z6UBxI$5aTABn88-vI4P~X(q-aR0W|s{gXb(x_4m#V z1SDMV-73nEwU@nJn z$(RdHs^K|AT9^l@EkiaB5@t*4>SCTwJriu&o9rcWPDvGHAMa%+=j%o+Oyxy|?WWY- zkl8eq*v~cy3eI$0%Yx8jv*Ph;+XFPOtD^(sHLDxUdn_+%%%Vt)s9{|{zb#75R2`lv z!7~V#YC`^6$)MaXf8A8M0~@K^?k4%wxb|Co3G$#@quHBKcIg?0g+^UgDZ_6@%8Q9+ z$r+Qr=#D=RS!Q|mS_7^fby?r(Lr(_tw=|@hJq=Hon+=z{B&ZV-C z_|U#T>b}OKDpw!W|LNq-d6>rXoa|X;AtJS57ko9d@&Kp8^I|lXk(x%_%%6r*#L20d z?1lkav6h?J!yBy-eD^L;-RXe9 z4;7z|Q~4vM>K6`%#&!P``wlJ^TP)SU?0z3-ZVM-2c%qB@9a6xVZQ1CHA4BNS@1a-f z&CMB*FZiH3>@+}s&LibAPeCM%=TMIA9#u)}_4{b|`#EdLA@=6G^`WM-FKNq1Uvf32 zgl3a6&0a9hEO!#wopf&fvw5G&QLO&_@s-z_bNx7p^v1h-J%KJ9o@^$Je?&t!&{!lV zs9zddxup2;+}%Ka94;B&+->8+2j2G?Df3h~ju#z^bj9JekBi9B_`eEoaKwK3y87r- zax#^>8V^>tacA)!oF$p=$!PSvhUScmqtJJipRyDe-Z=SIG^9J4j%v54lbWs%Bbh~21}jV^2I1eTA}=hQ)R z^U=iewzCB79Af%;PBj#>Z*du`pCH}Pe{3}1_!SjD(w=dcMx|#a8d17w?2PH6KZJ$o zOTru@rM~vobDPTXwb_)Xg3OkZZ+C{N4aeb3rmdrX`cto)bJ1on+11MZ;KWA=Lb8Tn zi=`;2&oVX!AO{xbD%++p>^jTqyq86@TqUtL>qlH&vJ+@j*S_iX!5@UHpDtY_;7vD_ zE{lF{XvUf^bKl#2JCAOfd2V&39?3nu@MUKh$L_cA@bI)W5{@5m-x3KWk6PUwULrr{zCo54T+^}z;GDPjOf*`Jg7x=vhDJd!6UiD_n zX74jR zVyKS#BuGU6Os1#hH(jhS*X_wj7`Y^al~v;H^*MBVI`Q`@fzZOFh#DJFABWEC2aTa& z#)l1ikzMFjS!0SH1PHz+cYn|iY{XFCAiZgLb2ii*7RMayX6hJiT_ zeUB-XC#pIfw`^-vKUg5O$^G{VuU38Gl)cMtK%FP|Mb?71>5F=m{Q#HCYXmHv$fo${ z=;-`=N)8T=Q6px27@&D>c`~7qyYoqVwRTgPSxZLWCl%-{Bu_XpZw#mLxsAqqgOiUO z(RldbJ*)e2j@%l{`y_sRV&6n(3NW(n8m|K4$jHg{4_94Ih6K&)Pa}&KMJrIy?w`JR zRX4RPN)j3!jm7ccJ_;hev~-ug1kMP1sr|g+)wQ?M{^sr;DY@G-;*QupyT}i0t+8T_qv$NwM$4& zK9^W5Ht#oFn@v}kw!xMgPrQ1}Y{ubyW}>J#As95@kf%~<7C|N79Yr^vA&%?G_YLkF zN7qP>&;2oLj5FkV^8#n59+^8bPcCD7Wq6EBOjx+deeHB1f?9EoLTaN86YDR?#ekR2wG3D_rMOAhJl0Q<|fFKO8M@f-M(rF z%o58)X*nT(?6<%e@s|g$}_g=bvr&bB7zui8Hul>g?QA zHsGseZt6=*OFIni;3FU+_8m_dhw2_-IuA0xGrxOW$boo&Hf?S^mcx7j(I>f{eQxu` zXp`&j=*VSymc~mCAL-X?iI7`$d6!(kwR{5)qoCn|F~6w~P-U_7 zjZ)E@-D3L3xb*TIb~}^6`6lvJ$j6^;`~3b11+Ni6H-u(^_?$KJxeD5= z&7LptUcdIoM~`7Lonm_PhNqWe9=dns5K0OrcT~o!!SXaw*l#WMzH?_i)I4*RDspM- zuDhJ?y>3(w)tZ*|eD7d=CxG`Ho$6@2u(9DNSE*F5?{K+eq@db*z26_3v2|2Ecg!~? zAvHC1@MjWuMgFk%gZ-Y3o!!~V33?AaJUsBO?ZK255Q5PCtvz9^U=TO`;@aAHgX=Xs z8d*GWg3F`T_78!0A6T{ttN_fh5C-epg*jafR=Y0+?O&N63vxsgpbB8G|=H)2gfsq;5pc%URwAq8T8zQ zh=v~Z#RdScOS})cWTgA8!H>B*iml9;pc8fu18@9M11A0ccofNAn)S!SM&(4<2@>Z< z_DP)1c4PycuE%TQl9B_=#^W3g2fwDLagm3oc@hi7dJA(`smZX*3LUbaaTtu@Lnp__ z)Up|3?y!i;6(*m{45an-*J<4DNC^pfi9&Slx`~Op)N1b>MX&15=X!b}$&?+LbP*qo zrV7((kJjl*b92@CGQ$x}w;vdPR=`eSUqCC?%;KWFiy(M}tXv3Js9GJ$4Y`GRna$Rm z0=JJtI_iB^uTFr1qQ!o12Tk28zy}Gh^A?-b$o-7o{v^OT17a66AzNuE9x(!U8tjTkeIU2e*AkUBn47$&`szZ@1wyAS?!yw(RmI@+!; zT{Oz0ZN=)c%@5PFQEc0IqF{G_-+VOe@U@xt9J#;UN+(Kj9nb?{#Si8ne5he=g}0bD zj>S}L{~UW@;_Z9qvpjcq_d`@Q!*zF9_ofpc=o;W$05)TLRoK~OX(s*$yIvB(ViOsb zV_u*cV_25C29o_=4q|QGsduyc=fmW!uacv%=kb@m_txe$>%gwu-6EoG;g3%Np z)e<8cl~3iXR00^WJy>Yc&LGS9A`q3YRNP#(x;tGt;`DCU8A3rp5sjolu|qrWgOa!# zrHlmd<+A0p_0B_O2N(XVOZ|iGM{x4hoO~$<4t}pMoHeGPV29;$d%D{3^?oBJjgnO6 zNcwTIRN|1k>($96a4Y+rNlTCh>~^R6qUrhbOlE7!gMxxAMLqdK#@#clgQ+6ApJPz< z#xfhvH@Ge}eDX!Fc0AS-fbh{7JL(*d8&+cb|Ae25ttn-5dI4u>!HsSOT&ugnc9ZS) zILL=GSlwwU!0Vrna5~i?ml_QH6hI>-BYQ=wI=Rt=N-Ba?C{1y3u^beD|C+@ldb37U zFz~fw3Y_OP4y&1oDiSlFW4Vf~_(_yvCrxk!{si3WV)Gt3 zzL<1oC&>=*{N6~MZZ{W`#b0{DDZiX7fW++~+2;NuAdc1ijt`m3;b0-Za&D^1av3-x zh$x6uFF^pAR;h^RLT*Np!)@vu4wFuuCh^yJz6vrPJBeOM%*g_Ik_%B94gT(8i}xQJ ziD@`>!K1wJZo`|^T7xIUFH=Uwk*@;P1c)ow!#2!KGTHO}c>;RvkHFS#btYY*r0uDy z%`Gh*0l4J77smtK`@c&Cdyo8alOTYnoxy~BA&Q0S7>iikg8Q4Bl=!VDUj>8kF@jit zx_+2+HMO-pt49Ec*Q`Hw*r@$X4YrV8lna=1-Toyn$PJsEf_RG9y$5lV?hl7CD#4BnW)r zc01fz5C9-GB_8|F?&58-jVDX%k1Q|$uVU_TP4}++)JyPFvbWvd<={_o%mRvI-B1T; zuc$Y_Py!<%pZn>bZoxbZq`5c3ijtygHJKm1^v;o+|J2yipsoA z?0(W^`-0mw|?y9IG0C0^dA(~ZqT51u)7UYP@FR^6`SbtcEp61 zPeBc9^R9(%BT*7hPo=kKf3o%s1de$BCtP1*c%ifqROX3?3(BT38N2*^d<@agal%!i zIu*s~H)O0<;eqY{DuR8PJakW@o^yhKQ+EymN2AJhXD*2-%AejK)Os6!8T!8m8_wT! zrKJuy464Z1D7&||wyv`Vp3kGvn-_7>vuYrLj)v#qaAHyD_o?MeeRPK0$x&6qR1a!5 z`P;>u+ze)nsa25N4>&{ z@mwc*$(|ep|NDsEhTiIT-kdPz+l?vC{}zv7+(45nVSBP9xmS^;?+LoP!3Qs5`^uYu zzDX}*Yf+lc3DN&ghTTKm!7btUyP^4U67GK*>6Jc3l*XM&W$o{a`2Wse54E&Mw85%` zu#NAn|Jtw${n{q$eI5PhfFXroYw{;5jdQKbLIZLIy$k4Ls3T9ET*br?03iTkh!IZewn3W3 zK3D?7G(bz)56&E#tBc`=?pj+vF82*^U7L*M$Zu9$-W(5ba&me;5|3N_*RpEguiXNb z-m4}hmkhtlZ*za>P-N15H`l&Cdg9SDY%1H}a!JVVC0C$YZSuP$$?eKeNl8f{2-G-} z(y0PZxmH0v3+u;mO^u(X--$-UF6mCVHZg|c2l}5vnEXz6Py^>lr+RH>6ipUswE%g^ zJl}%2@07$~+rkgL3EVb7h8G9|MX)nrA951Wp6&hJtpl}SiWEgex5GO$h8X_`Qba>Q zHQr^K;de8NrPcP`YI|#I=ju_fIbB^0H9puAcN@)sO{xAsB7iNCN^#I}MnZHNW~y9H zCk9iyzv-U$Y5*a99B4DeL{^&)u2w(Gy$#G(vdug$$htqY7>A0&~ugpyPD58Amekq zD?mU%h<|VS(=cw{?K&T{Kl3ifeIPxnTW!4ftH?11X_etO?ebFI+~OGUQXg$nSjL>*i<`TAzJHh@JP4}O^Q!0C&`)48UHG5THlKmGs z4PxJM%A1XiP6n(AHf>q3|L+eUzaK?}rLy)_%Kwr5M|3-?SY)A%jM=G+&aHmpe^E7X z@4>}JIBcB<4co_8R;CnE#-ku^t9(8N{{k?5-)f)_*v> z&W-9H{<*Fa#;Tb z;oZRe4%>gvUiUJRGRO(NTkIvU!~gG5ytV9rXCeI?F%En0{e39MPCm8 zAOEL|N8?$S-l>GNP#4@^{{Ub1|Ik1!|6Q7)x#@q)E(h)fSD#O`Q3yS_t``%?duNgQ zGbkFr;~&*bQfNOs33|haWpa=%I@gefvwwEMfJZ?e90onud+Of0wR!RCLh14Up4D*7 zk)wArCVGW9L7pY_WY9ruS2fR8Oh9=x{ z#Q9K+hQ_Sz&DQ>18=j6g35#5Vi{7X{jw&{lKflF&d!i7!-i0bV^uKdB9?jH5SYyI9 zJ>Yxh=~y`*6`(Tpq9%yl30We)e93Ef?~7v{=#4C_KYKVA5LtWz2H(wv)M^B8iu0ZC zwN`T=r5dNyZd)$pTDR0D%{Q+_&mM|zP_akGyp5vy{8Nq!xP4k>7h2-_A%<-&#S=+| zg4qq|6y*bnae1~zPwL#2_Ci&5!OE8|{4%A3hcsvSwl(P>tbZdLvA$OGaQKEZiX$ZX zut!BU$0>Egfa{}q1U@?VIjG9n6OjH|VzF(*wtKgS_!R5t^6GSZAF4YJ{76KpQnB;9RR3QEhqa{0DHS9YZ{Ca3U`>=+ z-taOU%djKAGG{#leMPJ8CI0C4spkvKv*TmNxtp!rLMpkeBG7n&PI4?;mVAAFz3q=3 zNmKm-d_m6ItQ8Z37pGRtKXWS`+0o~yBFjF3JM9{$;=sayFi7>l|6T63Qb{3O4zOQp z^-kqV4fgwqN(4AKzQ93&H)(#vwUcBoRh&VYx7lXK5f2dPdw!x!`#B++s>!pdEzTyo z(gEA&vnSlDRrSFvpy^tV3LEdJBKPMT&2P$mR{?_$>OtUaSN`;y9H9_q3s*fsbdp5;AAS!(z1Go55z(Te-)KuRnkAOqTs52-tM9&nAQE!GC88pd_s2qehJE-%4j+;7_dB;?>a50Nrx0$>(D2 zPs=E2|3)8qmbn^&{a!4VgFlDqq`Rv5;|Ib9N~9xM?BxZJwN=ZzVt9<-8%92W8^c2s zvhc@bnQEHvvOv_%TxERp3eD_uJ^&=~UJMzzWK7`0;A3FMQqz~kY2-#|pcn-3Q5hVv zG7SJE?4w@C6L_l25_nKNA}S*~f^Y}(1AtS7CGs9UGuItEM@~9{)XK16bX+V0hgtBr3v6c6qUS4=E&k- zJDDcKU#e_P5zj%$j!RAYb|@RCNJvPa=+M4w^+6*;o~yN&>^y98hx_+9o{*@)3vn_* zCsT%CUz@>QI?eXHyu6zn(ZRuQ#*;qS(|T)wsRf|^`XsheQVKYkkbwi^yWpqGP`Ute zHroatT@QU56hnT0T};6rxY!rn)*C{0T@s*ze-@yjqG;7loNl|q$OG_4H*K`V0ilfe z`%Ho1kKj^VcXmj4aX056Hb+w84KNuh2!S9_yxuMcapN-?Nco_WdU)Y58-UXUW+w4xA<`zN?><$N-LHL}?Wdz#>9$GWQ}nI%(1HiJZ=7 z5fFja`QB`~(HO%ldhGGhk&~IdXNq_ni#HM;sw^L9Vi6o;OQ}}1Ks#RSJi*z0IPigy z%e2LvJ)uA>hT-~rA6gYus&}#l6rngPSaWM@>*|IDl%%dF4ig(aoB*&pK+#;dD%;ww zO@wW}N`d}7T?QLjkB=-2<$L`qM0p2ydwV`l6+tz76-^C(McLNp>^^|Q^kJG+t(thb z>&dDiu7k^Bk_8wVA)(IP+1ZYc_0%9PhS?oJlYf8uV%Y2@4i2D_#n?naY;7zjC zYIm^)`UB$h-Y3{^yM^n|xOFL;Zbem+X(Y+_HEtcO3=aNwEk_{)o>1DqF_cP*DhvXF z`~K!w5jseANCe}GdjJ5fR$v0P*z6gAS>6b^#)lm8iU}v+h_c!8t#a8*S+zgMaYwxk z%_$99wxhvw-BO(!u7Btu6QspX^^*ld-d=VeA0P9&L$4x91&QppE{Y{OU7)QKyD`3U zNREn%ipI^D4qevy3V^eB1X_XVf?8V)NtJBMt=50+eJgl^fWr)svQ(2p{R9j`KD)f8 zpZH+C=I>Bewt9b4Cz-F%(b4f2%^3ZytRnrVOhYx>Y<~U4tw6w4Y*7@h58bWYfqlL8{ z{&bF#>Fqjpv>eoUQE;vC=n=4YUq7JB*Yy8;j7a&n`wvHVfYW7@soGdc70@ED-{U`X za{<%=Jc)XL%?0|uIRBXQi=rdWs4xgWpP1xm|EIgBojoxW_=EtWN>vN+cf642U1<+o9l;+l$1)=$n4Zvx==D~GZ?`n{GQ58(P zJc7izv9R#+U`EgiIBDBD0AMgLXXD}fb$4Kxknf~Hu{=V?=>RSd0A~52&IJmdh1AfU ztXHG>38YapccEF$xfd4~pW{QaIda*6;GGd|0jxPlMrV7q`~QB0CB@M}Wo>+d<;;_T zD}U4-aONR8Vu>7%9GsjFr5ea-9~?^PPL|-0JXB9KrKAR9JL&)ifuv(Rys*9w5UTp< z&q-D!JZut-zSBB7(LKXC2<7nYF+ zf0Yf(G}PE2g^pnSPBlM%^oT})g@sk_{8JlE3M2-dd)9zgp#wrg$(1f#2Ai6+1`;1A zFQ9}WEfe8c`CrNCH%C2mfRlLv4-cA(ha=3>p26IjA>AzDcKlxMPz1(-y4~SW7odD@ zuTI${U>_u0b_2@Hmzg%iPcZ#sS0`Ftk9$7DKM%FF7YCyc*^2q^9j>$LhZT15%P1al z#CX*DvTKS=)Lz%bKq&e0zgIpcAYxkAWS*ViwQ=Nepb|L*cBsN&j;^Z`K&dN;l=E>qEPBY1Q*rqdOmI**{!XaIh* zgW2|Qn9oP;zo!*&{t+aP+;HG91TJyFK7G3Sw@gq{NQC7FZD6)&CFp9qd=CwC@x|=x z3@j{)Hg;#6#vYuj2kK(9)z}CcS)u+T#u8cYBp1wBX&>Che|9aq!TJ*@s_gb_1ljKH zo-LzU4ZAzlbJ5U<NnOclY|vd;qIZqDUc ze6bd!DI9&s`D`Z}Tq009{;i*s@ZRz<*fHePK6f%Na3Afq}l^Xg3ZAtnLw5A0$(oaPga!6h>LLi+*?qCB62 z!4GAm_2Hkg(~4ZOUfuSW_k-x#BTX>O2h@{pO|{*w@*?21HlP{T2Sdcf4*)x4O~_q} zkS9>Z@?a&MEjNioP`w4icN=T41~7i#>7SCSODi1nKD@?85$|SIx?t~xwhLc@1DHm# zb!URXqlAOh<=>EG@#mscuQoNTGL}3|piXPLD3e4MxkLPegDRw#Q-+)V1ZK2QQiWUj z1jrPW&%MRKs%uSPCGk5}zyhS{n;@&1$c@(gM%Fvq99)7(rxCiRXH#3F_;W{ZH(cHb zcE01tt4RbDHZb@MAC^!+W)-+RV-Y# zcupMUA3~QDjS3xFbo3{9HpJZp!4N&bLl;5R7mHrp8@Djqv@9*qR`6{(z>A;Z*vVgngXinY$AbA{U+PZVO0Z zLH_=|ZR@EGXe8GA1m#U?1O#7{t1Xu^Zq(MH%wx?tb?V5%tB^-tAZi}`PE28AvUEN! zK~GqL9B1|D%Ak?T7H7TtUe{GS9?)ebcJu3!D5+8u9;u`~sdtA9-OH_LlrA906WWUzdPGk307KuA7P4o`HM7CnEVq=wn-R|7BRDIJnRIeaHhUc0; zu*EQjYc^MtF!aFF|J7m=u&qtBdzphV*C*T9x9Q z^#y6s$owBaerOtiUgXc^vanBf`*Ug+&QT}$@it`>gY;~N%cnILXl{%BYD<9^dUxMZ zPFTPq4lf}PHfwyeQBeg$N+o1$`EY)2Y$gMV^}laZ%Tw%$I0dN2#U?%pPKhP@|Gl`T zq&Cp2UQ~4jJNynZVx$SNU;MnT>E*``K>DB$k%N^Wz zB`qJAamVjgjxloUPk%d#Pp=s3rB&B{E{U?8raUfNe((?|~?xU4-A^(S{ zD6srX)h*yUn)Z1CW12x%*nd8%u4K}Kc3>$ek46#OBMG)2mk^>t{{+aN*aX05r!3vMTX=(~`e&G<$60HRK!-_LFGH^WtQBjnX zC@k&KqbTm9#Kd=e!18||J6gpKLfHwejX@>H!ybUs`lI_MwkW^#y;EylQ+6i2yud?F zd!PibH?du<__hrB)SO8YKRmd@FL1s)Ir^c636cFf81;@RT=aoJJI!4DI;T@3P0eJ9 zOy@=WHsflW&0%n#f(ZxlkCX%|c0j^`c@O~6BOS=)d%ly@i3{ksasUUP%k@{dQRIPXH78Hh0Zj&eUp1d_$5&pJ&N)nawd)3Q&!QnzS+i#Aj>maia<~ z8WUN~)m>qed{MVm%8gEMJce33Lx|y!UOQY+b_C+}Y#<7P;!g=j+0bGX)_${BJ)69H ze7iI35FWrgD2(ynLl(cPT=wTUeLntF$knJy4-1oR@j^sHLt}Kx0#}S0K=1Z8iAXQD zsj2BuA&@UciYnqzlT3#pCY>{V@|u-+ydQ8nIH$Fe@eHvKrg){Tt-WI9xK@cd*ZUTk z#caj_B#!n~Fm#EekY4hP>x*Z5xZ*WH@TtX3x@fKus+9dn9Ny65@n|{l0;de;2aVoW&KUc!5byffeq~y`r0~wZ}+V*v`)0n z5m1DIItq|pdFu636BCs>U7?_OVJaw8soVptZfkRfcpRvR8TERjFN07dz**LFrUpSl z;`N#ZLtlLkSKxuiKh2a#*aF6#C{R1!oz_?0TwAkS?Zzm6)BBzcaU@f+!(B6gGgZ=G z7ViKBR_=;+Bs=`i_xh0VVS0A3-PtKmiBS60Kz||T6BaZ%dudRq8A|C0ILntBL9fFj!bVy2zASpe{5s**`C8R|uF=!AGK|mU5k#0dc z1f;%oFn;&>?mymVI5V?n&t7Y<^}g>~^Y^66^@!?7_eQhnVQFBgHiqb7(hi;7H;uzZ zW*{Qb=@tQK|9_5Ca-)cNk^AwdqyG*nz-PK~iUFBEqb!&vcnuv0kkfDHeI0#Fsw`*O z^GWO6-qz|_pMO`m(k@YcsWXCZTw}{{^~pGZX@_?W^!8g zm&I|3b$Z>s&~uayBNj^e_mpo};PsInT%*5;TueFg-=ict^#m92QFG&un$t=1Q+Z9M?LrV!aqCt6^^x0Mf%)*F0Ow+=Y?@N0Spiy2i&0!3$10AnDjW-;U)1YsSykR8JqB9hHfysuElNy8xXZI?p1KB0yL6 zMb>^T3;hV$|I%sipF$+ABIG3Q)p8;F@Cpd_5}zoGp2F_Ds;dp*EV;Ym%EJNsMx$4= zFAc)!e(sk%di?K6MzPEpJlU|e9_vVSyFw-ks?W${S{#~!Q4LkncIT_zP z>}MnHmlqYw=F0B(Tq>)okWgoZtj*E!FTtDx#MFRmW0x5sV@$cc`t~!)$Jh1vX|NQ3 zR)7lp1x<{i(cv9G z9>wtIsxm*4k0@u|_8r4r_I|89H8bMLHT2x1TD?%Eh(`N^0){rg_kPsj%pza}Pt=cm z%JK~BpL+6a%Q@~|893hQ)D5V-2w9JhEQ94YAd9?rXYa(T;1ui} z!tPMyzwWc~DjcBR2l{nA%9vRyc$?VGry~AHy+R%B%9FOOu|{0Yj7(d28eCZCH|a2A z3Hat)h`&!T3K@k9Mo)kbHdW3+i>X6xjIEB)v4V!pKQ3 zf!aZXuH+lIv!1|4^rno%HH! ziAU7;)puW(Bgg}IhP&7$4aoHz$wb|IZp&f%{y`Z_W>%+8toj~n13yP)T0adak64ds z)7If?s-A!cq-nseKi}mvso53WTl;7G2k*j2amoJOe+@10U90vvw@+8#^2LW8i4^vW zW?At3hpy-5FyuLuaP#^eu|C?U^?h4zuq1omi+MFLolJ{Ca%YDZ7VvPQcBhFS`Mdy-bw3G zK*x`#ek*Dz7x$x!jk@&5e#YqSepiEuMh?B5Q6(Oo#vVk50CaL^2EcoSIOKUsRGGNd-B{3k-QG&Q?t^;WqnFon z|KFIHQPih1bIjtk6@yA|%yn}stgMQM^6G)eW*v>VR}Ig5v_=FK#hxvX^)W{+8} z#35muIDG}}s)+Bs&UX95?E6t^`qx(K7tWm9#r(Uv0m{J|Rokuc!9jUza;dIrg=N>B zcU9k)mAB=?kNzrmjNb8zGKwD}{pmiKDe2cQ{=NauR?M&3GK582x({tR$3hNqjL`G= z&u`%=MgX~m+z+wR9KD~ z@E@QBu%FBF_DZzSXonl(po=U})J0EOw5tp&LG?nD74U0PPC*=7rGfADMNg7-Fz(ip z!h8qqsW&-eF;y{do}Rny$g=dS1AFT`csIK+J|@amcAeHp&(YNEjYUue)i9UDwbCKP z#XbBNS?}E50|4~`*rCw0jEUo87$js1u;6o8ekQHI>V8pCGav|AIP8bc+jI^?!})#> zPK>`aDV1ViP(5~77V;6JH!tIF`To~%F*pYZ4YZ_(cwV_}=_sa4yJ+W;j_}z9;JWUv1Wynaxr^FrBPMQ4IhF63sGNowPaXhF9bs`OZD= z%~Q}tv9AnTfV(*Hs{Xz73MRPqP^y-8!+fn|DRrH-HNl9z}4hzaTf=OTL{Txj=X2gu7ZXYu$cmzRRz}NR433G(a zy>?qwZ^VYnTrhXlelHk-I6OgyQnc|KjjzwoM4>YtS9#Ua4n_I#Yf{iyU*%>Kf32v| ze#9F&tW2suW}-zpW+<9=91DV7ISJb*;ElaFSd0-nDRB3(v9Xa&>MixwVCO!^ufHl5 zOP!6^$-O|2Y+B2LE^hzGk>?UdS!3WMk@Ak3pke3OU*|ZiAp0 zTZ-lQ6_cUx;MaU%JA}Veb8|+3r4<_`BTkr4At>PIT|ufE5D);MD8b2-4PkiPChv5B zW=C{HHuXZqT2W}R2mp|w{-PFBzN*4~t!x?C{Rm-ToGM|zbRY2BStxazZsFw;7Z>0B z-f^BCO^SQ`xS)McTe`yKkf(G#H-FZdQH6s_o*$}IfQWcPK*2?N5zzvC=S!LlV79X* zL@~A3KR=|3tIK=qvoUA5o<@YJHqZZD|2({*MtaQ7WPYSdT1qPATua^0g#rBP2xNV+ zzcA!ni~Oxy%L)9p90%TLky~kyG}+7dR@`24ADC>8TLR%%{gif=I%H5B8HzAo6ClE* z{gffiSQ@H8D4eHG(@6~u4N0O~r?&%l-J@axN$oy7^8NDuzH}_F^DYE|gdnsh@)R)X&wqn4w4my5%z8QSEz@gt7jM zUs`w|^arqaIV-t*YcfV-cWh7KghuH^Y?_KxhW}_gQ$b~tW zH0Lt)T`1=MuoZZ&MHUK4;1#Q$nSKT@)46KTbGj61yuglk)~&MYU|*b>xxQ$68^MUy zN$?5?teYJ?{RZ2P#egNCeL&=iowl)rd`|RK)YCx9#uCQi`fDAMX_eBO1A3=BfK4J&(!2lg;cJ+vAHAhXC97@6x z-H2Gj0a%9YhDd=GT(9dj#R(4W%$6_dm!-ExF`#H6dF&DO^AiW8o>P;JF^w0(YwPR7 zq&ZKVro4k!cwg`3E1jHZJIZG~1dNRU7*Mx|`0ej{w{@pZP-I`|*w3d`px`uEb`|Poy6Un< zdqi9(m4KwIOC9w3!m$>IWnQ78%%sATj9}c1rmRGTi!saxW(lzP+pvUmUn1m7Rte2m z`6a1$=AKGC?Tz01I&6S2upytUqVC+Y9Mv|`}eP4h5)D#sp##?l9+Hl zQKplWVh;c^2HBpXu=KXBe@Ht}Xsa<%5O0P+4a5ORN@}A$P+>f3&TLFfOyH^Jf&F}L zCGQ7yt4zv|DR&TSkgIF2@{R=t{NvM{pqwA_d zkcoO&8Sty8E)&3qZvFc86m7e|yA3iqNhph2`CJS-HM3Jkj!eGA(}k)|?FfqV@%*+A z^#KSAhGN({6Befy7r7RDN}Zv5#z9&dJslk#6q+eMdefi>)&>;RE-b3r z(g^mTbD*TSNRESp18XggMFZXSA_sN=h7atE#qP6O7N5Z4Ret*$a4d22}sZ+9n z(Bj&zJ}S3o4wQqci9(zULgD0`#E(D+;jnH#{2uY%mWNSIc`XlD`dUtb+qN@0KOM@9 zTKrb5!a*nHC&G^wpgau@kc7XfXh1|%6kjw~hb;pSlxpqVuoO5xV}L{=VuwO$TO)wI z=wk4!`4Zx*34wJDLVbmTJCHI)1+(4 z`8J>|8vg*x$Y*Og-D?uGJ)w!Po77@p6(^uc^GqsA%&PQSMn%~MBgHrLCz?P+McH=}cGAhQF^gX^*zrQQ(Q5PE zkE3hZI=Qf44u0?#&)7NT8+K&`WEuQ!#FWKG{ww41`Tkm3#QDdt_COlRW&u?f)kA)&K<7&3z zDEg$}#fcl66Y#m^v6(=+^Dlb0R<})u@t3jq9E9mB zwRcjcF236h))?Wp-kIO%QZn)OBVmdPm6F0seBCaM>@L&WvuVl2eaIv@SX!7EGeh}V z3W=mA|JdK(V36dYzIP@!+(?83dVk)olG+W@PR`{#lB*_Wd-H`*WVT9|C(p zJJ~K0syB=x_gZ|p-}8t#ZmkW(JsjHpv6(SQJtdzRQ4sxvI=J)!5yNVn$N3Y(mu@t% zhfYYW9v`|Jc|qO7mQ6h&n@~2xGfbqRM&WscUV+FBw}mR20XKdNnL$=fD|OCBn;EMB zB*2|-thshy-RBcyucK@yO{)Sk=ePB&mdtnj2@j%WypUNDgn5BH?Br=_ywk@`S>F=k zbw3IUYbGvw9LD(TOOw(&@7XFALdtR)(A!~R_QaUT;y4JE-k>e*ol7Kllkw%`I!g7q z@ca`p^6}AP#QD6!;w5^nq_SvZb$>jZYKJ0~QPP5XX8s>UWfI~%HD~HunNL>wL|3$n z3rJR|n@HzB>BIlJbW7d-Uj9cpm1kDG^9l#J7S|@_UT>=CpGzeg{@_Z5jgj za}CvUS)+|f!wrNl}3u(>_lsu?A?SE!(3la^7m=J1|u7>o)dX(AMI)hj%1D0o4?eej&RPqP57jvpsx4scyv*Q z>4^vWzYL%B$*LbK6EoM982siEefN=aID5T@hBn^IR^M z7q|IH6?upIQ=tfBdzt6#bC(aJ!pp}8Hw@51$?Nm*HLO@cai#JbvkFsHZ8zmhRcP3h z(>2xdiqd%;@lMz2-JmgMjQX%Y);C8-j$xK&mKGMMyts{|5g*MOH25$gS8%h%F2f>J zk08h33~9<(&X6zj)hX52L(;l8cpE%~P<&Uzc^aQNEe7tWD4>__Oe8(^Lx0lZD=2uZ zud$Rj^;qiu{WrJHSPc(%546zS9CoB+;%i=<#LS7dwrI;w6!pi&r?@4&VdPL4`F8RJ zjl}c&GZFK3qX;vaMs2>;G^tv*BEJn^H&lyZe08D0lxO;r2Kzt+3%8f0W|@;ybNHrs zx*N_pTi0BaCCJG1ZO z$*SLJb^9W7TQk#nQr%YV#UhqkD0y$3;$vlN@)O&9q2aSeNGP zGNKi#s+ygB?XC+Qn%QhEoIC z9yv=PQHhUQ2R83$Gv=v^yj;@nU4F{8w6k#|rC#oY>|oc=jJpg+r{**1iaBnK`+Cwf zG2Fm0HVzQre-pI2{Mljq>SDds08PRy{b{~Yo!41YHwmYZh2|6T4+=>?m?(z);*Vg@ zLu+@a;}arpOU#ZcaSmL)!^8Gw=IFhvQb*2a?v11`;9a#lp0s8(pux_7vA3xxTu>aq zl+YLTv?{nEq&W|2?OJsnuyk6R5e&P04b*c|aJl&G{bkSGeh1Zi4@wlzkIKsXSTN*G z2i_*rK|N;V(L?U1sFd6((h{?B=I%)d>1AYS*YX$bOEY6`7o3ua+gshtCnaG`#;B@Z ziffmxI@cO_=95D6=7f6lvQptRoG4W% zAEV~Xs_?l-d9NnO%rM9}jLI#m`@xH~_LJn73_d<-Grq2g6X(ig7ZIp`gi^=V;HR;e zjBQQNPxOrirhFnKO-ZOjW!$r5Xv6g^rNSqi?GCS}*+J2IVdeo_{2N7yk{t8WTh>lfjhaNRkCBKf*$t1m|$-$p}e8P|J9fX`NPhnuLucu01@k2vk;cV(xfw+JgemL5Kg$s>jA{xoejRJf$8JY#Iut zx`^DY7qifDPR>_XdC@O5v0XrUr~1LbkR$ohL)~BJ;?IPl=8)l()i^F%lI2THW@q?# zmBZV*?iv4>4Or6jes?<$k6Kbfakn^9bO$r0>V&!5{X*;Rqv$?sUlq=XP1}Co)5$)^ zRh2JnQ_S~07@B|h$?Buz=b5>+&YWqqlr?^W5G6rSmI(*On zcI%FPGUr}^pWP2+>pH_TJ)Fna?@^HI2FRFHIVOpW{B?-PEykK1AfZ`;FFj z_|}z+{tO3=xG%-|KmTwD#7}jwZ!KMGlObeNu*<&m?Z?Gatj4R}r_!`jU*W7P_ooXx zESf%fSZu#dx{YW8_G;c7ZUxq`zQ$%Y*(@PC+YiQ5V5t%2mCEpP%GIa|n{} zq!2r)WqIRyDzjWy=BjAZId8%7nA74y&_YQ`mxD!$*@zT+pWsJPQXB(?21#l2{S!-g z$M|?f5Bpx}8fe?n1ZTYR?F-V)Wb|cqs;kuB`_XH(nP+e<`!tboSXmf3DFxR#`6OMJ z^t5L2|?9gNzA5s@-ns&_Lhe}Cq4%;nYPsmisK?XhEVE+wbAkvmOO zt5eOlmxguog_$nmAlJMZh(piftjeX#9mz?u%r_Vs-oUmQa2|PW>C7fAZN^G!sRVn* z(#Uz-$xw-&yMcj$@83&!okinj^EZ%q*I<_EB~EJEMzXBl!yAKeKCO*jV-g=q)|ct$ zPRm|OX&^yk|Ikf!M^|!ax0;Q9Wh1AbkYHSAdZE+Rb4~l z^V@rPS4)qsB6-voa02R6rpomnD$Oi!@9t*=+!V4Cy1DJ~bZ97eVxCZJ(~^gB*__Ec z(!hBu-bE0}>v?;<^jETiz?Z_Ue9zgUFkD+j2mY(PaJ_~HA zqAk!U_um?)j7OY@ui4$$9KfMT)y|S{fEy{y% z$G~$TDmB%ty0i=68bEhQXacMgu#F$yy^D3;6QJf~VZlS=!YX0QI?mMpxx|Kccv^jB1JDIk+V=Yzl7i4AZ2|i+;EXWW$FTC5ZSJ$YLxKz5F z|F!f%tf~BPGayxQoW`E(-#d;TJE3Iz0o3S#sDJzR?dG>4!*}l3qHECGV5=pvvV<*b zPZr$C$+<|xTD%Mo)%V8iAl+^gc~M?o{`&PIASDvegQ=xO)$1&FX>`ARgKoZ67`0rL zDeCpMKynK#mF|ZSt6|{eSc)>oC!50NO@)S3jmwuOKn;A2s}uldkdRw3hkUZ{drixG zzF1XOwkB>bEi;qZ+oHRuvT|>(=Osav;MC-oS$94L@^D}|3M}i8Q@`)`{ubI)eMCZW zJ!PX+_7qAl7Y~-pwJiH)Ey*qYGx?{jQ(ZwrZtLi%s@5LQi*fj|zqe_2?AWmcrsi=O zSud}$#6+4#+ws~^K&df!M`03`Pc3cJzFTvCHXl(SK)P)H!iR^6>4ie;)1u0jXvwmD z?^j|T&HjjWA7IZ<9iRp0?`tKz*3PYylIKyd^(^m*6$ z!E%0yli*@>6jslteo4+eNp;2AkP@Beh$3EB<8V-Q;qJglpD`5jYbjf;3}0Vg2fPWM zWp|JT{^vFz%}{X;9e8A?mpiKVe<3%%71?*vwYIb@j#O!=X~gr~T^&slbpr|{CjoF+ zuoBh7o8jU+cb#L#A2*A0@%DOqO2P{OOrs5&j`_tVpIc+IMjk%^4~$zf0WgnTS}54u z)>g3*L}*u^>%IrAHq%TOA&feW_%;`?N(-QDbi%3EWB7|bUC zXd4lMxaQ*0(gR@403>tU`{lv-6eVw~>Il=)63+|WQ%>XK_m?`;ZO9oL4}_&og0pr4 z_ixxwYSl^bCY_di%fCGk?`189E=+wrvD7@uQ*k1bQ*d34Q$Nor`SIg>E(CDKvB`@R zwMj|qt!`y9eIEu=md$m&&wj*Y4dAtvj+noYGiO>S$B0HIVTv#|v#B}^Nrv#1X$OqJd z4K-E)nwn=N?!#U@(`PZVY~g6eI_<(%hW2{Ph$g+Dh)e|?*K3_f3q^alyY)zjptzggqdR+PfkoYd_K}p9&x(qQIwgQp zY6smUG}Z$8GE)6P(e=m8KbJ-{IH_o9O$IS_n|r*Jr*GfBZ7IAu2$aOx7qQbaLWyc( z6>qKuozBH~XzXNMlX6f%mJkXdP1o<>TuM%xMy(a&9`&d4;oG{;c1E z`@txhmO8(9zDwB6Iu2K_PcI(z+w%9S4RPe z1{TOlLP<_FU;^X_ANnu=QKx-_Ee$)>#6%Y=&l696mTz)NUQS!}iL?W}9dUtj9^jI( zwzZd>p3dOm$IN>b)Ux_{1~T7-pXI_byo$cyYyoAKK!rAGeg?9JwV3J~LXZpeY0l5WR$>eeDOhPBC=iwX~ zc+e+G{<&%|5}TBC`nQ9^@JQw_Q-5=oovbkO()5;8%2{5Y?Skh3ZBL{sKN%g}!Dl)I zdWMCsTQ4pyc3AsmZ?HwjsK5IPVvUs3P#U6sETaS4zY?W_dmO_t$s5{LGIj=DlYc9q8>E^|q zU=5~Mbm%-~lvW}u^kgiB{TPNiTKIc@wmnX9)A^X2v~BM_*<>HB&RsEgbad=PoBZg0 z(^apm?RLkMCfu{wp^sYBhO{{D731X0jI`fYWIQ7q+njIe&ibtOEEUN}9Y_(LhlJK( zj(9V+E8jql*BL4bS<{XDOt;im55{{rgt>U}BBxQQqp;GO&2%Dvjfd%INr_+wcl*AM z?CbLNYtZcun52GS$AJ!(H#4h(?bT7JVqRl&ef=DSxZAbez$P9>HHHbVz%|z=&*tlC zX_i;`j#fi_SbLEKS$x4Hn6_@=@27(heCqu%-}hw6(c3mQHsD)9?D0ZE zlyDw~>VE<=I&Mxp>~E2a|lh#t+c^6cqIZ9_wL z5k@yf8d)42eG60({04*pu`LMxnKPNpVV5OD9KZ57JZ-h<%QK9*&n+PEcs+PViud;7 zwK=1koW>=OOJZwb6NDVHkgp;9WTvOKahd(&yA55mm-o4G9lXpensOYs`S$# ztfEHe`JuG@4Pk->^S;ft^9t`5s)QtDzKR$SxH-HI$^d) zABToazR{SLyIO4B#WSh8G%Ehnjb9s9Bp`ra|inqr&7E=W6lr zsjkcSIh;=k3lER+`_Re&!2mO}0tYz-!k9opLu0%f5m0bqwKgImV%*j<^0-o8fA-b$ zt5xUDgm8SESZVO%ihKF;B@L|f>9uV?sQ3c!u}$Xs2HpDATKjn4mtee}R?PnXes6Ct zT^LuiLPiHT`FGG&>(whsn-)stpvl6us)N1uj~~-O{4;4bXZjKRwH&ln7<%W?)z=qi zv;_UZ49ae$=j6;ntBV&^j3Ah3VK}h1wl21;JH==?w<`xsJ_JUT)YQ@2NcV>A=;8B* z-on}I5^g7Qb0wYJ_=pXO)Ja(+MJgQ7Nt5rFHt0Pzu68n%Kr{@36IBwo)@1QG*Kx=l zK?HP(S!qXM!~Gs8Yt)j(bmyvxH}{A(1)*3|j8jsh3c6szSYJg{QDEax9cGQ;LUH$* z5xIV=_r)w6gV&qx5PqJhMP>?!H_~=~hJAuV>?iS2ke9rQPHfyrV|Mi_W zglHWH6mj*d-CB@He3-2U^S8IN1AzggqiwCNH&@2%5O~XJuU@|Ng&rbs^y$;5u>;ti zKv08Ci7&*#0Ud6@7WP@5s``ux7Jb4YTc4`NDF2XoRx(s~5>gC3F_064JiBbxK=U|- z$_1`?|Nf&=K4>-$nz9f`5x@!LbnRUrZUmJ9G|`z`Ttw5*{Ft4+!Z|xP$0mscWWsnv zJ2RtCZjM%Cy4?c;q&nDVSr2U>>v7EuJLjZ2!Vj;@p6Usqq8WEvD|!nI^4@S`e&k-H zz$QhSof381*XkcKEgkbCduO7HMky#LP*YJs2Z~(zaPsF%tS$*8Eb4Z4b^`XD&jBSd z6AdSX9P?^v6w7L!Ba(f?ZpL&~Yq>8+4n03qu?f%&Y;ux$5czg*Xob1${Jd#-WiC>l zD=slM_Qauc0QXR6_bOaC1ljHn8Zk;dT5r?G=2tpZ`Eon{T`>*LUu;;UsxUtf3H$R}~KVi~Wro zDhPC8_!$=`*3sR4A&_542-=O;J--rDP*9+3JOJXm`T6;ADX66&f~Ua(E+cg=OP~74 z9}dhFWCh3F@l-O{GB_B_vqik#1|~@(!w@q6nkcYt{_s9u7W(nFw6^l|^COMo)RI2y zAkk7brkOpLD0m}t4IjDno3cqNVi= z5E#u;RC$@s%gY9iFgcyMli@40T7n!@hFVmmDvTt5j4?l5z86{2>#A z?mQ+jTJ6dYyCXy#&@Q8*q9VprgZ^w}0%Q}QU_s6me+1o7ad9!U$|ffx>j5K$SfQy8 zE4eXD``7|T0dNh0&SOXfumSV2pjPeLCZ!R9ME^B`gaA^~^_Zzk-^@g{@Ox7hM4f&) z1`%q9N;FvJL#}<@&Q8hbm_4!wT}A+9GRi7V{8uk!M)UAxA5wW$MxoKg=6_^>YP zaKwWK0^-~lbD^kFjfl$-Lm-4*N!n7x z7MY#N$OP`M=9ZaTA`mESZfEyLs9^1Z5-NB-a8Vl0gTdOs&zG3Cg9FH30lduz{1Tx`bFh;pm(YEdCeO zz5#I`0-i>uq}5np35UZ8DwHdGo}BYCy>)9?Gi?QHRh{oJ1{@@3HTt4$&QJDxTF zYspmU_I4$G`0F$OyT)4K6TGcV=alnJjXE*^d&cbq+|o9ZDVrRP|Bd*$xtVm^S0S@n zn;hN$9o?mmn%rFzzCJ@|$z?qB=eZw9^hjzjR)-^ae1nd)5+1w!)qe)@ky8uN zv$M~qiT^%)50A!`yF5Q4-7@3&6E49R5g=?zqq2;qE)p&Cqw<=iN;WVC_b&WhJ;hDh zj19K?#mqako=Ru`%(hM`xZJ@A$!0^_O}|K`NQOVFCr8gaY)yn}5h-X}z~KJ9gh#V> z%Y@Z@LF0z>z3*7YA`Mn0_8`{o;}PF}n)1JoJ{OyHztz&w_z3>rHwaI0|4Gybd!e0a z`wLj_i#3y6keo(8 zMu_m;g@f3r5&Kx%QI80i;&_V-`#z{HL>UR65w?+VP&d@RP+Z|70+ zd#lMiea#AWQr>q|vEx46V;lkvIM4z%vN2IYYqV!1OhjMpg%xr}_->hgv@XKl?)R^% zsYVdDRt1iMBA0`k6~}L)o_CzVx8Er=zAZ4bwtZ63LedM=$itxA-lWfIYen;e4&K05P(Zpi!H`h{u)@)Y+1bZ2hYo!Gt1qVCeS zhBqH!tRDAaCO6^xE&#&)nXEM2+VLa;bi@LIeBSAV1B-kEZqxT4XG~@#$}B#e(9qCu z0L-or0Gf;rJ8Eib2snd&zis@m^J6pCKCjv(?6})z7&Us9(+oJA;Cm~OaBfT>%VVD) zS%c>40svdVh8!w~^Ctt*yzg2_DIWK>ZE>5PoIwLBz4i3SXZJxws+igD=n1NDC`xeV zqotrwoX&dw9J^$|72?uK(Nh1C`bgoO8;_Tu%DiF%{e~0vXHt;{cRxRg1oD%(R==RT z`320%bqz@mY1f>}m?s~mtdvgJJJ?!F* zCq+}g3oxQuqPr{cqz!`$1vpre*uE?HK4eAy-7V)89||~h-+zDN&&d7t{Rt`|oEr6AzQS)!k@~kYELHH_PS# zMh9>l!?qpxeX+Uo_?G(WwsclQ9 zy$F|Q`I{kX_vbXEr~jq2VPd*xO z;{SP+Ci>0GmwBZC+k+fafO-K+^bG-}?Z#m7h>mALN*8j+Zxh1Xqnb3Nnyh?$ke*JN znmZ$4oZcqAp0x40M?W$Q85 zxZ+w+`1n|_gfaTGnQ!-IXa?_x32j5nZ2WzDi%8np+y9tjF z5~64yUKz0W4rTz_aRtM!e;T6q+|e(Z5nvgk(0>ux8VdoGtu0mhAS*S1k$Mg!;_%V| zl+cgOiaGTrJ>3P^Ek0Uu@?Pj^os^UmEu?;b2l=_M1K*H<{0)fo0E(!nsODaghe;C6 z)z;0z!eah;D!T9r>a&`>BBA!l+}c`xM-BuAkhE*o&wwe$d1-zV1=cbJ658fE&&9!V z$U7>1H?cd_3GZ0inOEY*?$kQ_0|(;rivjcaaW7=)XbfjnrU92x1x| z?%!8ZQ`>uOODi3K%%jf} zYulFeEUs>DM1fBysnF=*_g(Z)ZKW0>mnW{9>Aidy%R&CKDC>RICThsrCtzHBG6&}* zE)G|m@z1H3&3&*~dV7)HPC8g7?*sOH5Y%-dgG?<6T{Xegd^h@M$3eke$uyr&T;|L8=OSTfYY+?$ET*`cZ;XpnpOv)T8xT@Mg>963D|vs%B*niTkv`~IbSWv zN6?Cwzy&b~$4v0xmiS5!GiCQsl9ob(Mb62uybO5WF(6%lK|FyN%{n{i^ zAp-!_H~lk@JJKg-si>%Qs-1y-g|u(wIJ~CPJt$1Slq{2CZMzxp=v&o7)XJ#FWeN!| zWI1iivd821GS}oF7q;)T0zO~PcFMF7_>2=Mv>yob;Zr}60g+F=0Z)UAHFJbcSRH`{ z$RQ5?f|{1o&UoYslfm^3+RHD8>$tZK9)tv2`sD`WU7=GHs|LM=-rF{3sN({X4+{Gn zg%Y1`1GE4oF^wEl2q~%i_i#e$-=lj$L`|MKQm)^8v`TQlC*S%}zT}AqZ2K=NeNcpT zTRMcO=r_9H_W_T28u&pTW)_gP&Vo?x8E!M7SuxkWUQ!Y3kb&_cSuGRB=*~C z8zxo)c2^WFQ~6A_Xs{m0HqzFELG^)d_MsE{gy~*+23wmFx-V8*+~1 zAT44Kg@n3G`RL!92Y3!wroBn6|1h>D!+Xa3%lJ(CUGr%f zzYB1F4`?2+`wJ2K`RhpgYTo5G%VFO?j{8#b)t3@$jHezEa7u{EdY1%Q`avbe<;#}= zzQj3ptg#5tGwpxZ<-2gaCMg{6RA~_Nd-;^K0?F?a6J2RC$L6H&fLMj_-w?@kC2ZKP z&qQ-LQ}8~*NXU?RXbHN-Qr;ljXC<35t|qDS%QfwnQ!aH# zYyqGG+~1#R%)8*lP}()ml3QN_K9gy~9PH~F5dys|MUZ{JYrM~%JtOBf&CANd!^R)5 zAumQQau0kK1ceoYpd!C5W z*2)<1aBntAT=Ns(_Qvw1xM`kH3LiQ+HxCa>LS}S;6ru|XoPM8+2WWk_UEUA^k#9F$ z)!1ZCm+LO)xSvyRM=O<+(D4NK2#vJ2XwpzQ2nV5jly}=BZ22{I>(f5&IFuhQG@@9K zDS8p`@|?-!20JctfUW&p-jDW@fUVE?Ck7(!Y+h}Uy&&(!<}yl7LM#lqtKHjJhRZZ z!=PF)ynJ3&<8y>b^Qi(V>{${@B2elTgapY0dy5S^+Oko@pEXJZ7EP~@*?$XuOC8=` zEU-{~u=I)S8jCb@;G%>HVJX%eD)8Wwa9;s{0zHkfkA1)wXUH zXQ((j);Vp`N4-ZazYtezMAlAEkX%-wk`yT;J@huP)spbCu&kv?B5nr`SDnaLYqxY1 zP;8`FH+c261f)xVP0Z6s(bZbs3tjmmA&j7&x=2p6M~0^OwRqeT&Tv4PLhILSf6bAD z=&Cxi+tR7b&(uVTL8p18o(y5I1%C^RDp)TDv4;v}XVjzFhuUDUdaFIexHT0Q6Z_& zp%*E=*~?(di$ZWBG`OSzf80S`4sIwU~~M z4j2`3Uo2zVTlv&IQ3}-aid`-xukbP+Dcw#C-{)|MW;|ir08vk2Y%F<6IMys3Qf!a% zKgqv-CAKtNo;PNxbNjzpsm3HIzy{w;cj&ykSrCoRJ?ovaOy^|o=PdN(5fG|_*TM^3;^5?j z9+%x2iYPv{B7+PCLOv5tz_^djsR~X*0&nGLtXamX^HGtRGSy+c8k7s}AUkmn3K}`a z6b-BZF&WsYj@B!dMrbp8yX+; zY1!3geir~DLVI(++(bNp2Zx4+UP!|mDFFb#XaBcB%PUVyVyi=5q_){EZLCe_JN;ZkbYj$##P24|!45NvuJzF=O9z&gok3B-nty zw{@-69D@`8WGDO%@}>s#L-wbdZ##$fUAYYRgtc~P2q{4o5@-Bij76IHDZUJ$jzX+tLqv80tp%%|`xvBWi}IWm%^#pifMH z#-2R>pNnnCC}}i&z1a+)TztyC|2$9zmnN(E$nq7p_?Ge|{ptye$p5{BrsLAgjQ-7o zH3QSrHVl6UaQ9a?74MQHyqRD1hTDiUw6gd!p?9f!sOG#Vvo3-!cK}M3p#7Lr2OA{L9oj(P0xdwn3_w?Z-V19}mUwuI_m`CX z>-qGvwD68WBr9>UJG-xXpj%1vEq~*>oHSR0u$K zNShC#=aAN+P&mc8{IJuGt?>NFT9E~u2)0@u^dN8=K=o(a8yg#sizgiK?CO$d zBoeHI?hI~jZeC}zHIf_u-*UXG?DG~78u(Zt(!CDZ8tm|EPl7a(L@aDRQUL9At7Tr7rR1@@-eq53Zm`=@m$Mp^YcW(?GyK5xmIt=N@006Yctb#$6n9P z4po$vmI@2fQX-UJK{h}eBlGqG}NGy1+9bi07Lpj_GL10EFT z#s4w&)^S;VPuH-5ij=f;NP~p55>nFLozmS6mr8eccXzjdbT`u7-Oao4`#!(V{ik@H zb9T<2J+s!DA|_N3O=a!dn0m`3gLiQ)d?vp`L#uzvZP7vmo>z`HS6oU;NqRa1aQrwp z8UcG7oa+$@OC=hOK$tn)A0%Nw*{$yYkct)<7Jy3didx$6S|&XxS&Y%)DW34=8r0}Q zB(HN@X@im5eEbPI{1eVK?6>wO5GP#Q-NnJh{g}LSbd;KuBu);1iuNT~S&E>B#_L@K z2!pmyBI5TuzA=P|n6Lp62?=xKDd3?Yc9(o{zD0Om?*#|E&M!eH@|b`X-h5ODGC#|H z6IJ1KlhEb4HF~N4UUY=1^)SeNlj|>Z(7Yph6~=`te^FNj{QY?ziyJ*Lu&x&l~PPO21L^q`deq;*>{jFBp~F zcDj(b`6=GLLnsN{3I6YYbqs(j#h?d7_fX%`ngGTb>c0z6S^}_66tQ(jnJ=C3)?vf` zJ5Wqy4gaV+q`#aFF}yj%C|Bu0Bl_0 zaMeFYGVOLEezn$L$msdqkbf_~$Y;`8Bqw;zOaSW%ZiwkaZX2v8&&h`W-qdctnON%& z^S{4_2l`1=SwKak#M^8PWTIv zUqPz%X0k8(U#Y)i1a=nkpP?;))?K`7Jd{M*L~L%nuXUaqVwq1I(>{HFmh$i#iuoTR zeU57dyV0Iz}CN2b(YS0E>I&g!k>+|C)$l_TsF5KFt(iT3{z} z3wYv)h;U{MdLa`(2np2|FY&ohRMIU-Apdn(q2lELdqX@ShG_CTLUi;Aw{^k_g8BFv z^J6Sh9}vI)=Of5BzmXo$$9!4>au)A>6svS`1$x(fox2sknDN;C@4J(xFIx3>OzwO- z%#C1XqF$L6xgS^RP>@IZzjz)W;Dxk%7EHg0DQi-0GEIdD;X?N-Cc{)S9$e`Geen5!(#5u`4T7`X68E>p#FW@t%zyoXTYT}{!0aDx10YlY#G<02qO#&j zkB1d%$XPWgVP!+V3JIDxOrZLI`**HV+dx0}5+k({@K0*kCfV=|Og=BF*NXYdw1yaz zD+gQ>)4C{Mer3+6gX!(iPU{7r$^Y83{;xgMpFwS!gPX zub&otkO5kjw+x07gs!c8g79bUr+KiEa3spEua+PfyY|n=G)^s>+G4Vc_rfK@)NY3B z`L&EU;&Wzb^uO+F_Z8*G47uxZ8hsuB(AnI8OW9|LK`OW0^f#$F<=Q~|TGy*1Dw{I! zDP{XZw7{o&h?U1Qb)u^SQ>0R8|E2XtcQfCD4-7B%2Y0Qz$2Xm1GvA+(HAuL;7Z#O+ z{jPOALc+v`4ZE!?NtO&b`$gafL|fufApQjI`JR;C3!G61hUr?EyHp7w(rp(Oc@p(o@x6u>NUcpu`PdR2^8n< zaA~)T^z-n6)I~y*W4SbqHsZ%yVKP&qy$_}&d+4X$+b}C_ec08+9_o6B`bP-0 z*~af6kwb$7Cv$xov`Bi=SI!inf+SD(cgH9b=D@08hNf~pe!m$TMe8=RUMToMAtCQG z?KdIZPp&Y>)=W-!-O_<@?dI`c)}XKW!gYAndwz($;fwi#lP=FHuP(oXg~i9pMeo~6 zi2PcudzEvyQHgbx235=yzjQ6|`{0}*qF>S1{ZA`jB}FwQ8Ch(Kv97^>ywEgQwHMqM zaGB_p(zFfsXjsuWPM8i=6#Q!Kc4j6fALqJX=m~2XO4fayL#{3&1*<*gSrJcfqhh(( zDz$uqwQ-{Q*Wb@?o29Ha#y=z`Kg2&eKLg+T6%utM47cTj->Z7w>2Lc_E%{yDknY-D zhME|GR)glC^DXdOThXZXHen0lOV zj}tnUdmjeD{=GgtX=v9l3q4rkoI}Uhe9ylb`4s#$5eGuWbz>l?x}57l8`7V-b!O{D z+`_ky`~h`>d8%f1QLCX+p)fGz2;%%4*D2E8Q(E;$a&~sUP^Bz$MO`;tG|AOGcn~kB$Q-^YqZ>Z73($iVZ;xfb#q=lh_zh*V; z2p^ovPE}h`{X;{iYgzAYdaBtbg}_#56Cx#qa~jhyOA2kAIW!>G{QgH%-1X{)u13fq zJWJno_5AW?Dz9uI)uB9DEYqPp8%Cdr-&V!)%MqHhGqzjXo#=dLPSZ9D(rr)-mFVnd z!@4U6uvv;(7avjH`DQ}&3rLt28;%IanjunP(Mfw#^BPpRD=+5C`)O@_0{CUkL#C@RK*qOyW(C3sA`OuK3^>MZ{Cb6?Ct$;|* zP=cv;??gprmSd)kPovleH$$Z5O~vH z7uZ8SF=$S8T6s_;54o^@j7(}6H3fz&4nt4*%1gRIlc zm2$tU%?Ft|oY_*#O!KByD)IxT{K|jAc^iv$;d4x{Tt0a zOxul`9Z+J=($Ybk@3YGswRw|e zb~#1F6n@i!fk_gIio#A2JCEW6qZW2KL_szN`N-gQl*=!)uL+s&tf6IhlQPRPghJ68 zrDGNB!#8lTaxhS~7~&YZ%WC2z*Xofe;ure#b>nRbeSrf((ft&XJ#G)fa48WI%^m!m`lTBBw7s1HR@d; z`qxi_2@WiT-0tll==krZE{(zI2i}}>ih?Qps?)K&xhESmE=IF1@L;A}!%T{;*?sle z$BEWya4#2kvDxZjy&CMm^FMn*6Rz<=6h#BE`$^kUjWeg;6sAfazFHdi^7?2vAZ**} z=~2XfomF(PaCOvqzQm_RxImDL33tT>h-jn3KK2dYyJ5~H4|o*@&72t@xkWt9b=I^T z@0*=ERXnz8m>o%yb|*=Zz+*0T#-OJ-9QAotIW_2}Bm;OANplN+AmMvW-h}w}Cn8Tb1cu! z&PK%MlFzku?T|5O&|p8uou#Lu5*a;JDL2S|Mqh8$;)qv%cD5FrfwtIohz(tx*vGd%`Z-OCO&h! z$dsmOy>`^wsZvAE=2&hLN&i!Z}__3kskQg57s=fC0u(_^TM`p>0e&4 z5me4LO}}sx1UC}5{b{WGD_G8{#4GQ{83KI@$dUoMx@72y#6w-+AlK#Jm^@%+rdr-v zJ72Z42s&WSJ%FiI0l%$NXbn6N1KM8}pQhxe=+Op%8da_|WUoW02{A{tr%CeRr69Pp zcRUY#TY-=)5qb^<>fVOt<n$Dk0)MvL++(+ZVO@(+ViS1}LvOUz z#t$GmjPoru)qi;-4L3P-K@_p(PK%kA&T;-TJw=se`ga~6;o1b`6mg7j5Ew_xCn^cX z=;`PrM;Xu0PnqM$<_xjv_N&I-b2FMJ*4NiRWcr#U?%^OX8ylv5F>Nz@-MaGvSXk;p zm`>tV7G1Wnzu}J|cFy^QkPrBTfWmg+hv<*S?brGp2GJM>qMC3XcCq{+-ABeS=%7^Y zo*+}Dbf)48>p~K44p(lMOE6UNiAxYB7{{#XcR}f}P`#Z^`4r2TT-6vLS7sUKe0O)7 zfOPAmU=^F^<6>ZB$7TNN-)M2Y3UMov_i%mv1Ez4mGh?2{L!J_>3=nkcO2No4>>f+b z`8PS65byc-q(Wj|7!Q9Q%(O)~dTs_h4~=~^?h59XtT5H? z!TuL1eMjnb5a3?(Ww*QocdS$f9LkP=n&t_gZjW<44g>{P=xTC{irzYi8nLsnaC56k zw|ErG`UeG>Ej4DErLy$fT(v9!*Kpyo!PpTp#!`Fqcdhip`;g|U#%=TY8dz^kaD;-W zwl0A$AttyvgW@?n=@WCQxSx{;-^}uK+6ZR6O-JCi>StTHgHGT2ECutOrG?` zQ4?e0lB;p1$Fs@|qqRHl8}S#1)wmXCAqg~dT9V|GaSFhG77**2o}RX9*uU(Ogd`T_ z4kQ%(fOLcC`Io@0OS~D=&2|-_x}MkY><}{&+~4XXWg(*5+7vD~hcz6OS*v~IFH9Aj zWhSi2tJcYNhiOJB*+|tCxTdq%A~6wG3?g0l|N{AXliy) z)yK_UOfXrbMn+~ztAIenq!r{>5zOH9MN+FBz%g>ZU2YRSUA`jdQt2%FyARlufClQ< zy{53ROyvSwd?ec~z5H7LS^R*4eTuduMDie;qg>&ai*f?!PLFZD%Ac`wDA=79j< z@Tg4c!mxFk4iC?ZfA8h3cm4Eqa0VC?a!OATD+V3x8<&qm&WsSDsK|UH%YxOb6@?_% zAVo}2T0$^$Q2(~*@XqHPe@bdpb2pvDx0=R|2G8~4D`!Ta>C-#U;GCf(p9TOa0V!Kf zN|bd>y)lfZ+axlVV^_!WaM-a51uM+NQ&dz`-OuWmO-B}uFo;-Rq+e>8>*=jm{T&B) zn-Dzi+tcX&JjmQJAYy#%@C22#m1}j*PVM(V=0x*=zHuF%XlXF0m9MpGWi!1q*F8qF z;oy3`(lw|=sqeX=ZeLrITXF_21v{`~EE*S(-~GD|0`@`{>AOe$F{uZSOxk*$%K8bt z8R9|@ep}lOw{0=r6iRNj-y(yC!5N@WOF0g8?R{I}L(m8bb)E8fug0p(_ z+8A@L&8xOMLf1`BE7@P;%aG1VlLCB_(qoOsNslp_;5(ee=sr}XaXME0tsm382PG~V zj)++n?AnaOeOZi*Y|W!&O}Y+2*{q1Dn~53lfZ*)I2xpoyJK z$YJ}JAajsv^XL3Y?Ho3|Rcka#OiAe{jt0HEy$yKBv|1^|%}PLF#mq3g_lLMZZM zp5LqhLNM~N4wS^n;EM;+K9J(O)lPVmTR`gtp>KL~bHG&~jk&)-0~*Z|5)vEk@2o}D zNF?&%8taiv3`-6movFEbdLZ(;xq12{320jIyal6K0By#~@$qBfem|O}Vjv7Cb-dJI zZ@Lo-dA!*Ip;7%9Kz#uCcd5J`5J&)w^qQ(_koPwNVQ)xFYMs>zRO&D$gxAT*DYb1% zRd9Beyg|{u;j7!VbkXmyR!RROs3@e$7?27{8PO6*ezhP2P8a#2t@wt{euI4LMq!}ECyY` z!Ld0>tKe~22h2rnph*L4>FYOdh+&*%8Xe3}i*dj7cmojyqMM=NR`=1<) zv>{RmA-ATM7NpE19r&0omIXM*VCX?L-Y`$iraYC(O;G44%u^l2`GtTEcerQMCuU|d zkpKG|dv$y)9c(EFIE!_~s?U57Fq^eMlYp>r4}e&Nc{UxNp7OmtT?JbSWLgB@owg4T zAA!(|zSdWO*_B|9Esul7fTZoB1a^Xa2N$5219Ah9^+fS&dW(RNMYjY)Ei5TH1n@Q> z`GJCh@{^hRZR#*Zs@7j6zS?2f&)1 z9vcHI2ZQlO6BMhH0}|Ju3%Izrn5j|-&)5P$-Lc=Fk#X6POrt^Pj@O?l(=nYY;w8r* zWn+tVtBwOj0Xda`SH<(kpeY>{JTd^*GmMY9V(dk`1o~bU`#q!2_U4< z)d1BBRDa0F0Wu75(tnHm>Vv=OGdDF2#G~#3XsG7qW&rS6Zi72rZi7Zd3>`1aqwe>9-s^~Rjj>y~4cM?qsFef7AnQ>io<`vjnX4UR{eSy@4#wr7q=Bzb2k z|GPe3p!5r2e2WY;?$`UKnyw9H*8XEG;SOv1&DR+MW&lW%!-7j_({>X+~8f8Hg z$ARPwZMZN3BBE3>ySH**aB=YgSf%;KV_HC$b_>WJ_+_sWkm`s!Qf~mgck|hE!15Lr z@y7yk@<83VY8kD-S_)a<#hk!KI}qIgt3}l3SqU7FXRQKE1&F*8&Zohe;3pC+@n0jtdzXo{1dfrm0SBNczSNzH+bAJ}oiG6K?lod8|2rV<3iH!$OS zyut9je)WpT7mjb1=XAjp*lLg>K)VJ?}1hDKefMJgrRRLs>CAA#_T!NCEWOE~8KcD4r!Wbdvs!SC`M zkO;oIfr*Jz{00t6zgazmjg=K(SOjQCnw)KS=^!xxWygJg%nzEMh`|83d?qUZ8VOW1 zq~Z5KLFn6C(P<#a?Esef^0M~sG%%=85OnZng?*q?p>YhmYw!v%?7sjeIyf>kTRq&t zIw7tG7)asNYUeY9QvlRA0M=IU+qdiM>;1*%JN{Apzjk(ZZ$PE9#R4QC zxn_KpJTVm(5lQD%289vsKfHJWc|jTS45jWF07zxgt+1~$yKO+dDgt!VGPctbcxS-5 z$;zZ@2}(}J4<|_+%;8kdmBfF3^!Z6>AaF7e7KXf&1Q?T|&xuh<_BvpoW9!-pxLlqE z$~(7|)znN)P2s)y^06fX(mVhx20Z$YRxXUj1_7GrKotbg13{5?p!l!6%lixLHze+R zfaLW7ItK52&%jXw=2rHJ#qn?+l+OTS??4th={#C*2<*jPTcF?`4sxYap!$LC=^C(6 zE4-j_0Xw|yfYZ1;T`GmoYoeoL4S=$%1T>VCWtEkM0B2SG!WhYaC{N~z*Z@!ll|lK4 zo_pYR$T0yvVg47dH;6buA4~*-!U>eM({RFtNhe@Ewb~6T0ZI<&QftiG`g4hlV-gT( z#svNbN@SqMdxe{(CV?)@v&=IA43GOYH+tb-?8^sqv|7K_H;QyGmui=gVRBzVkFy`g zqU=+n)h1!UaOlT&+AEURKDfYqgogZa;J3LuhbEF`rgXdH&QcnsHy4L?Tq}pFJT`va z^wuyvzPhCIOXg1C`0_<_LvjFLiYtf+{Sp=}*cvjj9he_HfD1ro@|{k5+oRqq`pxIH z=?3bG3)VLen6O4{&6g3~_sc9iHl0aSwETo^CSn^6Qk+ehP_vRWjm{<%pRZouy2J zgAb(JPshxTS6-XsuLg*rrVJx(U#UylHn3=P$b|7rzqQ39)J!FM5*|}WMYa>0BmPm? zk10IM4gG;5m%|_r9p71)BlEhRQkR#?|41A$Gth+VMJnn5rEI~IWsJ~}1iD>C%+#3!4r# z$KgtS3MhYLo|t@r)+`7tp4@(9DLyU;XT*IV)~x=XCVIwjH>{xPSZW-sWCJl(o2p%y zSRk$WVj!hxdRIkCaG;0Hp1C25O79-aGfCHWf;@IqK^rTkv}DC83$ZEDwK?Sen{>9( z)tF)qaX~4KMu{NJD2tidC1Q~N>P4LKe!QOfcS$m9QR#bvPxODbB&MT+MjRg}V`&%I zG+H+51?G+Xq-5xZQEZ-M-w9kTj^evA@cRk3agO@}}Pt7_0T{OUF7auZY& zQ`H2Od4VhDHch3X&^V||BKqP^6;_pjY9bB-PnZ9uvQ`aNO|%?~d$8ESGfi)462aDU zO`~v(r_+y9T9X~&Jq~s(bD}8U_~goKHktwwnnn#RnCrZjK}=Vx9s2=Hada#%zRlfB zOQ9Z&R5!=zSNf2*NznG!Nzs!@)FCujKf_I~))l$GLBBNWQi+kfGtUsgk3oqR<6Hh& z&Ax=5{9$!?T@l^h^5SL8-{`bDX}ie?&hY}yVgm6pA~1n$=2DAXL`NyNh3gB$ zrwGnSd7LtfTpNbHjkzvji+nQf>a4wDtVFmJ5vzD9j&?$j$ZxkQDYTCKXTJyxozcZ4 z1=13W-TyH7z6?vJjTTCd9o_r|C&pw7xA-$}0)16G%dU8-2tAY05KDbbRoLHF6oqft za&$Ryk?=z}A8AgugVby`c}{Zy|AO+SeyoH8Ov;LjlgL`49c5~-vV+ute{eQ|qzbPv zo2~5k*+{WLNPTEoOvM{+)nE#dKZx==`}VTNq6uUal*U3=da%4pp?PXue4FTne;a=9 z#tD%L3x1Za&wm|gGc);e=;1mX#zVo_dx@Z;@`9Kq0o_QbUK5+Sl<=~vAmx|^x_`#O zGj=H3Rrw6t;b{r&v2x<7Lqwr|#U;*aq+F*%UwM9v3gQHLDoU{HbbqNzE*=|Rpw6>y zUS(UV!fPri_RF}+*jIqEgS2Og*ycpx@=0OHeot~k+{OCLBF(|R`C>wO2Kz64lShlt zWln?_%rB*yoZp{behzu}?nmuDY!Su@3EycsoB~DG#hOF^T@FJ#68iLOvhfpp`cInb z7m)>6KRqC!IyHG~9>y8p-z)^JVpyA02%2|~{+xvI5`0u;-`5Sc81BhZPM9;v&UUoz za7}AyYfq7LT3?v4euUABa?lY9P|}N%&ms)U#czm_&&++LHQkYig3uXsF^BzVKaCVX zogT5YDvAvIZsWB@s#uQ6u&pKWgq(kJCr-P8L<~A)u>r!_m(nqX@k*f+nz?=w?iGn^ z2iYVZi7%~*3D5kC%gpVBYt7I~OsE<4brKC?u<$UrW1B)}HcHxOEZ zg%|TDcaply_w}}cnvp!=VT~D&3Yp&;{5|tdpw1dkze%fQ=@I6~wi`v{hc{@oGTtyj zaIreUFUcXrIQ1bkwG2z8+g4g-=qh?A$7%?lm>NlVen8LRz74~`s#p@M`uQ5`a;wqF zA>4gnALSg+OtJjXGb^b@%I5au@Z9FALm;siHngwp{M20boNp{Qg4xL0MijPi^8A$j z;gph0*+udki>f-Od(={D$;oM?ZyW(*TgDg0P(BF)N#7DbQb>tio}Kr4x%1M+R@~Cg ziKdd2E5<-I_GBzBV>0UN{q5;^G7U}8xvJqSnaS;J7DQg0jJc%U1|OquJ)zdHOGudT za>#AJSd#I?k(c>=uO8=O5h^~g+qM717GcO0hZD?+3M9!v(SzqbNsNn%)yUxaRknEb z?LpBGQsGiT{Q009CcO>$=EYCJrFIxfz-493k= zZ%$r}DkHx`QkgzS-GO$04>M+FJG4DsXKG~k#`jgpIV{{u52YVC!O|6m2akk}P!m{Q z4h5LYd(-YHCWhYS7CLZ~k7fQglak!jSzIVstCSslQnL@H7%xkHIYlJ=BzV=bUxHf2 zBhS^7>ZtEC_Lf#B3cEAvZS`?%emD#@B;b1O=p6CJz1_AKDP^vqXEBa({Qay(2YtN0 zdc_`g^*R(hDf`z5$}szs!s{XZYTL)u?bzTFQ86igJTCKg^-VSfsNRjrs=DH>o95zD zlgV#l@Ct=@21ER^5n}0f$Jx~7cz$>tF9b~Q7(6oqNAUHpT916y^{MQ?A)hk;fh=~g z^3f@$SL5Fps{YL$G1B=izsCG%m?|i0soKCcstmo7mWk>uaZ-mBUr524`qnmpNGnab zVr_;LPTH0j35Gee6QL}PGkW8Aq+Oq(S`e;Z(KTIX@LN||7$Sn`n6>99w}L98qO(f3 zss;>ynqW_2CDmG4QsI(_E*Sm`#eslZQ|yZ%#t#e5L8R=8lw zALpS%@Bu@ApCF4!*zz34+#kpmr9H)qe-&x?zWoJ4f4?7zr{3}-I174y2ic71?Ew|aj9MRrw@guZ+pp<~v zejPwOS1_(xfcj>3ee&~8=D1B5E=D)6#RMKqz3y(*j!_XzeFn!-K3XTi`sv2Y`G?d? z$6uoM`fg*Ih5EzUQzt;|{=FvmX+fldW6LB=`k<|CWh8a9PbrJoZyfTeZ@b7&7%}D1 zv)Knrq-Jh=>63KTw|z`b{c%*wEJoW?%DLC7Trtx-S#P9(INt5gDuq0FLtN&`UHQRi z_Y!=C$b;~M(RxYh6x;V(69G&*=C*1A@3L!#Gi_-b6`gT?`KXt6AvG6$EO|mPXQNV@ z+E(cAr-}wY7nrEhB83sg}sR*qygfsUELBvlkexY$6O5>jS2qTEG|HOlSq!n)u#?sN|VM4 z7>AZW8x-HOo^dd#@Q2Kuvw!^%dK^63S6n>L*U8pTxIoiQYN*Wx8xvfl0@?Z?IHT#| z%&OSTm>lj{dh2B)@5Ni$O0j897D0CKOLDZzh@#4)?6T3eRPllRoXf=jpc7C z+Az)OUb^Xuk0&~Zwo)|g7aY+1zF&$8HbcsG%G${AhZac7uvQ@n^0&@zPkM`TdD0Fw zKlLtbyFXBIcU8t-U#uM;-E15#!RvSJ!%jTjU%FswVHM}Odx^-1PB`4IX^q!5wgxHR z+(ap@6OH98P`xiepOiDoD`A|#s}s2X!&j8PbFdbAH2&#S$>A5esrG66OOl?8Gjfwg zD$AhCNSBn@cg*7u0ccVOXH7H%wKb07Pmt2UXgCqE?DWdM1OM6%xUVh7OL$%Mz8I4Vw=?(a&+CI;+aZb&&w%SfA%(?i?x)*m4pur zEPDB4;wyyH9P)yUOn-lsr$(6hAZa$kTlx`ZijbD^bZ$I2wDBjrXw8@e4@zD#!Hx$` zMYF-=IaO`~-Gw?_@d2S zkP+e{EQ*YNe-{32JJu=oJvHC$n5Z@FdhXgimtXaJoS&((XQ&#QQ*@UD-5LiYe%%U* z;`EaJywMOssbP4NkiAK3XxZKt;5;fLXS#?K46KMy~b^gk7mD5$XP zM^g>o$Qi{(G2_|%HT?dWQ#n5Y+Hj|KgXAJ5e7!#z!a4ZaED6CZ>9jF4vcwHJ@AiH+ z{)XohW^FQT{_3!8<;-wU=vwZ`ZWGVG+UJhaH|71DTW#X!JdS729LAEQZlAokTIAL}RuO`G-Oa7%Q(@xDlQ zp7^y=4=Ku38kmvSO3?pY86$EDUH{mTC7a>+g3~dhboF30TWg`apWPF&H3&S8_p!)9mT%k#IPTXs)utxERFFd~)>)B#jy&L+e}B>|uX`y7eLyhxd!F%xwufqt%(h4U^p@%n zJv(M%cj^U6zePFKsa$zXD$dt?uH%)5osG4fTsD7C9Yt8^j&3c_H25SBI7vbi7OW3( zF}l~+toOGAUyRr_w|R!LvpPnOVup6lMc~9}y)yZezG9=dJmBI(FdOJ}8;_gESkKe8 zUo_afQ_6CcEdGq2plX74mp$xt(!Em~N-xDJ!8@YDyfqz~3rW2dNedTmSh=#4dbExD zB?1p^HOQQ|a+lhnCB+>}U^ASg@`U@~Mrd!0ol93eWyjhwtOZ%?AhbJyXNehl_vD?k zDvcY$`53-d9?~obHa{n-WUyj5b-n)KRO(rG4zHe20{Gz zmA?>0gfX(q6o%n_sHNEXcZ~MJoBO*=B#U!Khbb3u5>)Y4t3(O1Ow6p~=WhZ^M{`{o z5lFR&ai!RgMK1Th^g4@S^nQ*u6Hm(ZJ=?td>t}a0p%e!7DeSn+qu+^e-V&Q$fa}xg zC^=6uwMa6F9Hdk2WL1NxIA^(VjQ`K3$}|S6>KBKh!kfoyF?FeFewb;7lGA>{vzcK1 z*KE0xuL!DE>-1h_UDL znfS+dZAEyWf-6V^U>8}NjJzLpoUXnrx0&kV*dS<%IoCltbvr#STt7Z0>3Ui;{lL9} zQ|jPxBC_+&o2BDA7jb2eoI|EgrZ0Du{2@!oEg;0=5($CBr z6hFsIW!@s)Up5H38^aCsW=-ZH6=w{Kwhh!8)NHy7Tn`vUd2y&P+1qfm zmGec{ixQU*1SNGrEjX_EB*!zA6*~Tki|s#WZ3{7@zlIh5FgWKz4Hnst|B*|He1hxj zvDZkaD!k~*ZE*eiG3lE)Ylw;jAA=Gq_LqFw{$D2Wv>bg6_8PiTY7o?z(DB4F)zjVH z_NgxfkAZenB`L*JgBAoIlbi?GLskaDzmTYoVCR;8hww`uUtY@6oHEw5=ch5z&%Lb; zUp@RwC-)5#Es&owgTG6F%96-drh34?=`g2`;n!j60h|Dut?zeA)!w>-oob`(Sh8$| zbgS>;ZmuJ9+}SMh3D}hpxKOsNjvQ=NxQ)uVDvGNta{W6BFiKbd5uf=d+x-R0K%$;9S{u06mdc)^-CBw8 zY1(*p+?XDkH!*tcl5by8Wd>oI8=!2)Wp!^O_2mYeHF|q55J{1>$IevrG|SVwbfk~F zUQO@kgq#B{d=DidS!!|kFXp>;&F^tH&M}~vydX<0Ph57XZiA8?100A1hd+4?)y58W z#Z9XC?I$l@40@)hPK(J54a4@|N|%P9g^%9u`(oGd*C5JZ=TO=1yY^IjOX}KV+lWKp z{MLD+=}_17PUjh51l}nXe~z^ss=elb#Q*e6;d?|`4*Gg?t9fJ;X57cxzyUXEPO&)^ zqYBCIy*_1?oqe_9yw)w;kS@&K{#h`UdF@4?i?l>nn?iU?Ukt2L<#%XlbZzUgjye0@ zEejXzA5=er&xu}#rYr{5dJ0;!bX1L_X8qvpUq|tZPRKp~XG%f~#qQF4XID6csttLNLBCjDIIy_Kfz0cKbYO$|YM!Fq zJ{<$4ccUWkU7{#cvR82SS`*jS+_0`U!&pM~B~e$DAeNk6v?t190QB+E!H;WQdXNE6%%{mgH5goWA(hxK%OmHtC)7>W84;GN?bzeXuGz zhEI5!2>TybO0~-asL?s!24)X*2dMs?OrlR3gs$5sc!I-3Be`Tyr?lOAkx6DRqONHe zSNCTyf+1Oq!^2Sn~Ja7Hn-jVoAzL7}kywoi%w%iaR3OurYy zgE=eSR&bQ#xN@erKytH~d}Do}IfnO<;$K3tf|t>U1#m-SL3){FGNRHe1$lV;F3RB* zP4a2Qhph_PG=xwQS?7vpCDe-PA0hTbY0mchi zy6Ur+yPPPK-z=04T@Fdx%j7A%vgCs}HDU7JvjjT1bLl3>FVilw|Eb(ikYzIU-$*Nf zMuT3BYQ?Ed>)X|Y(3<#!1ep9Xs0{g1s`%cUtq{s3LqISTs>@|=__r)8BKXlP=(iOB1u5N3wiZ`<+XuA7MR;0O4j<(7lNWMu)kb{P15 z4tY7EkQ;Nc+W86Fn^K3x9Y$^47U}qXo2&^=+O}&>8v93O!QxuWrrt*j!h{RnBLWF> zcL_0j54A~2WZGF*S(>e=fdboGynU7}tWg5oSkppuNXI-W40-*$9~ZjSI!oi!>BZ$8 z+(xl!`}tY)UF^?Z7#s*&SinKHyCLD52afKC5FSloK_-)lDHeEF5jM3FLVC$V8*`cL zhtQUbKXMYy6Cnx$OuD~_tsQGkaa?DGW*BP9DmE48^@l1;{v@qxQgv5Tk{hp(<(kxB zeAbkb2|lXT_I&(M~gz^HaxZm{09$w^*Pl*TZqCFhMd!fy0mKZ-H09X8+S%yqn8QWVym=d&(FcPWJ63~00a5F>p{Ye&*!y@3^X=^Au}rq?_zQiH%;`$Zz*F?S6IWCp+fjmMYs~1o(W&ubL1h?x)n9l18`I02pYrrL&QCp9PRJ_T*Ixp~U8;=Ir0OF?E)w5AkVWQgJIXtou(0PO z*Y%kU6=78=isK{(E3&Kn>ZPtgw&*pyd{8ji<4yDZ;zn*p^cA(elLnfn&off!h4Q$j z+M9X)_V~!KNz6}79#BXKa((KrQUnY}&O17|+IUfru-0CkXvEd}5&vn`dMygssaEj# zMYb-Vg6{n5l^FRYb$^mWr>1(1(g!(3O$?d{y#^1bk={+A+lP~qW7@wW@t$u?_vO!6 zMLK#mbt5%vM5y14sT-m#>p59U#a(*z2@S`iZ?jp3vvSa&_IwV}WbA(*UZcHk?>~UO z?Th43Gq|;k-Pfs|w5S84ByObu*)I!pNXw+R{=07@4mXWNXn>I=?D;9Oof&TN)OnZp zk=M(-aRin;jg)I8=AgnSy=8#g=V#c%ah`0+!+WF`r$`O>)*y*&l?k!vcetMIy0CY! z5~W=@j=Nul=f7rMeD??6!Kfn(=fPU5#ME?WFBEk``mtV9?;xhGCfS4f_;r!7<;Nv`R!Z>-Hlx zqxE?9t{F-#*SB|6H#mi*WHx!PTQqMD+5(yipX=Fj|-lr*XB z8N&HX;&bTq6MH@=yp{~QfXEV0BR;ti!@P?_;c&vc*8MP9ja`cWkl+QQh#FPr+4Zv& zcUCj;xMAff74|4sim{K8`mgGs{o)I++Zo;b&mTLYI=mW!8z{?q2^mzJIlLO&<+CUZ z^Lbo;sj3BYQ;H(jAgkZdcG(*BWBk?XLJ(-oIiA&GvHU{6=?d?{t_SI(`7pA6TS|kp zm_Zmp<2T3~gJFn~!wO}upXryy@pbD2#S(*2GjN!gLf`sRwE#qn>n0lcD)xdiE_ zwed_k71QJ@I+gbU>Rb`BMQ5LaD%!u`V=8akDQo*PLZ2E;Rx-bUrga%Uo$Hc|K#4ve z2#~CaZ~ePpV6~~3-Hrmua}y*xG^xy&(4<_U$om*x5+6r*rKsa&9q@jnn`!WT;T6jg zK40D#XL9oe><5_dyXQ6qkO>@x;oPu*wa`7ijfTNwVF#;v;>t+}x|JB$vZB0d*nuL_ zvfTnaF-2HaTm}pV6|3DP_t{gerN-6-_2h+IFI`ceY*xri&RSx~;gO%OC+_3@^fAZA zmZV8DrO1R=!|Q_LnRRkrUcXP$+=KFyZi#*AI$y^u|H{>&nlQr)tKVFog{E_y^ zXcB~AO2DQcVcNC8*PPA; z(|z;}-iz+Ukx+AOg)5e3JB#Z@U?Zc!Hf~w_t>IZi++#lOLViUhZIf)uD9SQ0*M%^; zb8fE18L$f6=M3J#O|QgN1i-Gj&^CPDigMM(K_+8QV3LS}%PCG4mhU#(CQ*@b9A!E*wt_ z8&4aHUEvJYKfxUN8WEqF?W3~DHLg(g1=GhbyskvkO@x*|X-zTyH9jiIh0CGBSA@*> zpz%%(PQ=yh<BYVP7hQ5BE!_TGc+BUoBtha}^}IZe_&3ayGX=665M)bhXnBS=# zhqHXadrGFH1kDQ@7j?nKR(E68k|U~F*b`$)Rw5r^wG?Ou%H8u$YrmIjs|0K{=g6_{)#I5zl@GkG znbC2P`+M|Lpvxl$f=z|%3H#>4FqfM**dR?z4bgEx_XX7NnbLtG9)6nX^kqfmmO04*KOgvQ2*=X(KmDc`isvUbxRPF`V>L> zTviF3$ePXB>$D{aR5rpR{u^ezJ<3F3s+3<9DDlF;y zdC*%zS7AwCkLc$A)Plpt#JjG7&@&w$T?L#&X)BP6*uv};lRnQ+7`_UP zeQFWM)G0z8D_B|L)?7t=MfQ7-mx}&Z+sg2g&k_Ao9&vyXmD_#jqsN|}ON9O#Q(E^1 z%ClIljbp-w8zw}bW#6albnaCv5u~?}4#JLB;TAKQs{rZPDV*{2l3!Mek;gRyrNdv!wL*5%&!hs*a++H<==o6K&YUe1S?p9 z&exFa*wvHU*Fdnzp7oWG!Dv6voOk1M19z>32K_L(Ro@58t@=`S)eatQCnVGW2}faS zfRlAI;m83jn#X(fJKKk~WGp_9GF!KG_i}%3z$8hC!Y8?t1VO;mD8)D=cj$9#aUa<_ zi9AJoMkkZ!!z=L=+xw4U|1o@>`4jU*x|RLMZ3KEZAnQOIpLxeqfHpx3i_ijH;55K# zAsXDNn&i1R!!BuPHdDJ0tu~tL{?*<<(Pe7!927kfa*s9o7hDWubS`+^jpD`}x_<$+ zm%9E3B7Y^_f(ixV4R)wS@I~yBYM&HwOS4jWq0s9Dt5johB6wPkZ75a^iLzlNoRLbN zip8fbx++0?fng>=9@l4q6qX9e$*ky2pj=5Ar)*QX;URH?4=C+Ho`B;BdFXMx=>tw7L1X*&_9p^1!*rquv>vT?M_ zFqxdTCvKJI$sK3lP@>uRRP(*uN1lH^l&Z31z(grz8&>eqN}k*z{Yk6rerX-W zAvuwnK226OK}I6As^r%!dJGMs^3KhqG=KQ-(oSn7(1y8oZ9=}L6HtWrYdX#9U`CQI zc&~_-VjxE4xQg>*{nAlwKXPOodrW=kTZ+<~TA^Uc*k(z9D4db@vyD*BD@gT|_j^+O zI;)}05au3E^GN|4wbDTl34Bh;j+Cdo_FakON6KEDe59zoJL-lyMDm)IhE+9#n(v_Jyhjp}yq-;3^U6mFrbgfs3Q z4)SRc+elXwYm9$bUxh>kfm#y@T*VEnSZ+&N>tjU9|YwMi-+7Vosh5E8SY0(7#% z_{PQ6maoqnmktFl%Vm-yyCq|sNG-jWd-U~49750ZEtnq}nF}{Qu;6#4k=8b6%|Vxj zZ5|QlO!f-dUQ*1P*$a4DH-BZ2*}6Nlu2~yO3hz`lce53obZ4tmtWi1PX!J7H$thPX zTL-GU;JRhwCdta&44zBcjeU<1=+KbEO~znAhdyEzyv>i zZf$3LV$BG4X;mdIMBb6V)!3(+`lNZ=?4aVYYN^a|nF}jWXC8nO*x7W;h zj7_ZBqNjT;$lIsuW`Ap&S(hRDVdmBq-{o>pnt$bN9{9<&8^OEH-zN5{9d5ACJa?P} z4c=KoX-=1Bb+N?GI$f(*#pyVg2yLG9$-gx|FgvZ_ql$BbW>W{W`F6yLb%1&_ouAn3LUUwhngdrg^+tcy z8*|L3-K$)z;5{DRGBOj3DsOLOJ^K9Xg$d5WVh&KAN;)-tyUif){h4jF%XOi z+e)Hjdi`K?OUphN%Bx*_<(vp3fxAZbZ=DD6+1Er`Apz-yXn5F3gR+*e2;I4rY|@FD zorhjOaic^JW-2j~wAeC$@Hm}~6;eG?ttEEVm@Sborh}WmzeZS8bU}R|=D* zM8crn7JuGoiJxDWG&D0D@=121?;7dPGfFALE2%n`7h5%_-2Cgjj43m(w5T$fsbyK- zY^#Sr7N#w>n{8rOF<`sdKYjngGtA-)O&;XC3Hr1SNNY_UL#0(5QPrqzY< z?Z63n9Fuz2SQ+W~QW=@v3m;|4z73Gb{yKhITP$H!r|M5XR`HAH_zJoS>-cGO!a(R| z{CyR_Sbym-fp7Zu5q}aR`9JT_z#fw!1`~%41_-wf1_|faf5Tg+T&Ap!S%OmTeY&|P z4ux^h2H_=jOKiRO0eMQ~T~1AzP2kpZhD?^}&ZU=rV6VHmwAH{`qTH_g&$`qo+6Asc6DBzEg8?U0SLG~2j! zmUc*4RpUUhDPtwotYx}VN`~(1F{frDMSwBbOVr1{Y#x#w8o$aKUS*CG zH8-76bp`eqTaC9x-w8+qeg163||2ZnBktmIoeAApFRvlUM1jee~ z6~y~*^#;1l?jYS0<(r96T!n6Krn!wU?}lRqW|hN==fJE$fU)h7J^HQif=_2De-pgB zVOW7z<}lGF&kf#?(4t)RRQkNwH>cH;J*nVkV~P&u2^VZfs^%xXJJT z0ZaAu=n7?SWOHM-%%Q&u}tU^ z&4Zx}uT@{(n2#80vXf+u#=<8!#5HO^U8!?{UAhdJKvX)VSq}jHe4qWdTKa$mQm~zu zK2|dAa^*84TA=3i1VjIa&i?vim|giLo4#2$ebN%bfT({-k0lgCN<(nTxJ=5qO-GU> z4ygfw$|G6A(GuZ=p!bt&LX2F1Gm-uTF(y}j`96ZC1#{fY-@-9?qK&81>N7ql$?y!< ziwE!7Z{eq;-dkpFWIl%iOljQ<;mv`bJ}Q8;f>C%`@Np?6#ATg-rZj0Vc*nL`x<#EiKErb!jM&~m|9l^`#bh3ae;A?BN> z`Ika^zwKsUQi3-U<^*yE*HtJIo7vpIXs#$pb)zT~M|4S2@FL|uLDI>U+8eWGrj#UK zHR0mB)6pRssK|Ih`v4CVi^XAeSgb;W#OsUKe

pB*^n%mVE(goPOjj2X(CM+jqCIytrM$+KPq{AB?}QCX#=Sm^p# zL{T(JP--DDs^|IhE&xkg-0zhN4bx)D+T)B7Aif_qa^OH$7G^8#s*wZbI<3{hP;RSH zK#+e&pxl?Qiwzyl+fFb|HOB019822UO4}qjip6td+BSV@ILFjAe#8TQlx09Bwaw33 z8IdZgGO>kd6krbdeF(9N$cZz zIv_<8{?t7EFo~U<`E^jh7q7LDZzCw;**k`sOgLdIxZ>JVz2Fi`^n1N3Rfp2JmbHIx z#id`a23~$S)9P~;?}3;%rZ|n?hl#s1blfsl(#0zhKHuqX*pR_cB9zE%)4H-6FG0Dq z558_O8}RuxOleMnPg-WF`hE;w-X=3sa1w+WQOXjE{uVTM!qzQb1GcbedD4~<2*0wX z8?fEeRk4auJmpn|(uAs8qy|)6G0lJ7NlJolT4#H z2QKB1axjAqZ>sg9E;LFX5XjoX?2=DXr+HoOF=fQ#y2O^+oNEm(2vZ7qWkD(Hf9J zO#A0RhBQOsssY(XO);y%a2di5WPpA#8}O-^{?CCA1QP%a_^R4s1->UNu3NMQWK!oQ zrV}7joC%AMA=_VL?1idZqy|(XmH_8KB^;AdH=wHOiwY__bsu9t&NQ^`gREP$24p;@ z{&OJn+x_ECc_RhbY4Dm&GfjVgN!BgmW9Xy{rNAl3NoN?Lw=a~<>Wpk`dd#ECQg;_} z-4Zr{v#~Nb2RW;mf>O)+R?`r>Ow5?u%NkEbw0@BqP?=Z}oCB3XqSQdDsx~rGm*oPG zEuQI)pw=y212r8BfpbvPz+mi*-hgd=1ta6rAI$niYe0sv5I6@iR1ANNdJNfGm9ZJV z4qIBccn#Q8EDFwn4J1PW4cJyzG*-+Dmq;F1q3sv50iTQo!a49M!4Pq0Ca{~1YM)x% z?iaBEoro2}InYVYaBS><9OHcX@n9_tx@+Ek5nIp!qiX({4YI=|_U#FJvO>PBj}`6U z7?3jcS|6)0hT*ttI(~mZK)U1HS3jz5SB227D$@3<-%*== zUefMhc`h{h*$SDu_ub~U;P8gjS66!KQcotM8#J>cJ)^cdG=P6m(H%CvSMSt~8z7h! zdM=^&%*}p$8`bPvO5ncUj$+8j$#Q2@i`zcIuU}{;1E2GoF~1~ak_DvZy^Q^4^EAdU z5oF%ojU&v*LRXONB}Bi4y(mj^JGGR1g4UL`0jH;om_9AkRc3qLXuUAZNV|dc!jhF` zTFEU-hFz8%M@@g9A!O*xRPBE8DGCK2Yu%q^w3jZocuKTBGBNP+O<`(QSzMhpOi?Ml zC6+C(;gONvz~Y4@Rj4trK-H-q4QC^`EIM|yZ~1m}ofmoX!A8`H~JpJz=RXG+M2tSu2?t zeK>a~Lh?o0+t{%fLV8K;rEl?DI=>WY_9SM09A1M51a}$4hDc}3B&Wt@XK4yg{J37kK$ZPdJKKH^ofrT z5-ha>W)kAC-`jxhU0@5R>=3S_f?rmzt>Cx0un@E?+fZBk4{Pp?A z15ZjevtTAr&xv%D6b)+5t&vaBJR}PAJ1rqnl=D8~!+tR41B=8_Bo_P9vpZf(WIKK8+Q}XS?oP3RqBg6ZM z5_8%Ed`xMs${@ag5?E0hE#tr(;wJk;?0kKyy-W0#RZ3N(NFm!T{9 z>BC4>5Go`E9aVrv1Ub`&x`G^lT1ARYNlj4-2154~MMk0HHH}buqhT6l-#cLD#Yv>z zS-@Sw%fz}UZq<9PSE>K$(eGJ>NrLV5@PlO3t}O7y-BvMd(#~2WXA}>_`Hoqcw5Yli0|a;S9CDOqRsMVNds> z!T=^n(9y^sS4p1u`^N{(MX$$`7$f>xFCi;}s+%>0a6!H%7uSqXjWd z9nI*aU}XxD!XuNAq+2D~52!$_Q36yW_@FkzwR>7Ca0zlGh~#qEG65Q*qu1?p_d9umvP1P234w`XrTFz~z-FCYMzuM>dJ0 zOVE3Wd4{fbQ&Y*T%C211H86M2dIe3cn1y?ZDh*OX1uvcIX*5a!$74iB&Nx{MY7mlS zPF&{{d2rka=4)W&}a-8tl^^qIAmZM4;L z%$n#0U-_cl;5tUp#dThhkNvo;;BBJWzsrVG2AL4WWAxfPpwjG-H9H_Rw1z;qDt)1& zF%X#28#V?q!BB`X-673Jn0Ldm0<(@j#eHDbiit6j7YV#=@G1-X|ATio3@h+rbVBX} zFG?n>G=@k~c}iG}C|zj**XRm2+JUejR70rR&NuWq40?zJc%^{pIi{eWY!paewh`jp zP^>^KqbqVBh$+sOW2$01#0p#YTbcg@;@wcJKrFm}avy+0qQmwvO~@>%MR4Djm_!Ot ze_hgEAr@IqDO4f##>C71`K;h%qpNY3{Uohnh+_75s5Pv0pk*7UTaUYpTlGA&298>{n@6y>y;fAHNX%8e-Qp6v>X7@ddvpoofTGkVuhr(P~) zSy6#&VdC2}t^2360+q5v#J%Qd=xP$%PQyG|vF9wTKXlu0PeIb!N?RPGuxfIeQCU1g zU&*ngGy79>UO%BC>e1AAH=yjiDw(?XgkD%+%Gk-Vr3ty3*PhS|@*DgCWzC<$w*7m=+iT#f5*Dkc~-aLDNAKL%9>PmJl#+#H(^txvTZ#ll{dgh zXfiR{ZspAghC*DoZeA*h;?sruCTqq?AW~&<+s3qiHc0sZAaEe7B*|&n*x=$3(3M8b z<%lqrfIP}^N4~~Xfzyn~8z;4?qOInSonCFKBr-5fDx|f&b9Q%!nMzx|e;sX6F(jkb zwk{#!xlPFMW2^4cbu)^hDUvSI;*w*3Ze96uI}Z2TJ!6@p1!@QMPOVs&Usg#?hgWbQ zxMB*S=U`#`lE-T(Wa~!1jSnECWy+e4xahC?T|rQ3=3LKh2=rkLu=*(?g(wsNw4L}l z2OQfCdsJKeJTGA&No|(&e~^5-UUbq$#*R`}6}{X@OiGZA}70PkLshs}J`eX-B*(7e`DLa21PYdpx z*HFC#X6?-dlYEr$(?#=&c5qAy;g7_o<`vK~l%p%^(iS^DKKO;oe^-R^Ht`3%%Jz0x zWh+|*QpejG$!M(EcrW5+oRBot=G3(n&z86m{$jVwMR8U4i#Ki(w|y$dW>3QAz*o2NE;p=or_tl{gI0ib^+_Ky)H>MklGrz*F>__CdrPiYROjif(dAUMp1UGuF{tEUd778 zwe^k;HKo7E$Ysc0SO3)SxheJfb2xk+4j&V$sCD>-g|*~qho4(m3f^Z>rN|YG zgc{jgBz$n9KxI^%A<-&7C0AH08IF++2jze5kwzrIy$vZ zjkD=d#Z=_uSJ4>lRTC51yCxY>yE9{UTF)d5UTsjNWSrY>Qu)Se32vV9C=EE2r*2L>j4 zRI}00N*&paYWL3~B|q*L#uiRb_r}teyN*tLAv@)y7Wpm3_}$1u<;WF-&9=t!2H=Da z@N>D9Hcw`w-@g`Dnjy!3mMgR~J#xz}Lf*rkuSK;RFKaqNVy9*M>c3=*gm!V4ux$C$ z^W;E4b3o)4ZMjvwAJXB;BL_-(;Uzxk$bmv5!1{BlJ9*aV&_)y&szN!Koz_EP0nY71 zDXD~$`u_V+;Jq+lJ`z7~CUKCnu$@QlF_i{zboP2Y8+WkhKhM*Do~$H{@gLH{tt5^a zULdQDzgr$-@SGs7OmQiXf#wEia@@w`t6h|B4yB=XYlqV6l46~;A1OBvlN25?Y`f}_ z%gdO{CYM_ zVUY(pEOdCSEW&MnA&-VLC);gDi5mf=f=}SGHVK!M?`$hK=h}PK4jOb!V7+7?IvjDR zme5`bvi*nU+xZ zBn8VR%0t~(&lXPMBp=xa)lIBohxk7@(gU?q-*EbyPC?})v-ML6x&u(R9jglEKt~VU z@`0*+1Zz5Zvs&!$tm}UO2OBfim(h+96t~nP5x`!To61urm%4%xEdvKl_m}E|5jB77 z4ws}<2)GP|5j{@ijlY;3>01`f^1bF20_O2;HtN;{c!d?7S7VjZ& zj3aKJ*bu*QSMWdwzHk+J1otJ69N{C+gb8RDSX2lr;Ru!P1RNVMD@EY@i(r3N7AWZ~ z+Y!8d@Jh>c1+RyTM;LX45ug<|s>vhV6Kp4>-BaIyR7%2t{%atWhDc$u|EJGm?IqpGnr;X;SR({sj=hLA zLKA81an@if#iQf{lG0qo8u));j~B3~8^#Uxa89`3m(k7Ry_jwuFZgb5#MR;iM3n&I zlBjGu=_m*vQCd*8zOoGIT86x&+0Y8C={~l0PiF%r3PhNEk=9W`0GOCg_7*cw?15Dj5muaQkbBW(yz!$ycGuqXIv|C{L;U}RRck*TJ{Ks+8J(}ra3h{8{Z z!awls&p(Fd&M!$o&AfmD7)lNxU4*;rv87AuTZP$+V$NY6Fw&OFBTCx#5EsV>?n*$X z6Ut~nsA;guP+;Kuhw4r_{=`v0Mu;3Pa1ldbJsKo$yv_W) zG$W3hmWt<|4)ahGQy9n2V^6I3KRu5lKsr+0yk~jFKw$v_mVJNFJg5<%{R|dh*#&14 zfaoj`0^t;MI7Hq|a2Jr27?&lX%>4>(dkW7ucyNlIm;R3*e08VfF63!UPkKS*fde3)R4aCw6Rt#)29+MO@o9 zXhFP=%d%wPw9Skx=b1h?q*o$G(fT(O7Bmw+C0|oa4<##v?TBJVgIRTg+*J47+Q=+s z-?Ak#%GNZ=KCFxYI%lfsVo4V{BNEiB8P7eWi|QW2RXTsxTJ9lu#haH4EO$19kkw$8 zTyqZeFC&dRoF4Y@u(xFnc|pQraQvi zn09g4*w}+&!;nxzg|W#nKjLL_)Cx~sWQ~X5qZ&Ti6|BJJJDzne{pXk6?tUVEHA#Nl z@_c_xO!jgYXfGHmG4SM5!Q6%+#Zau}y|51AHj#Nxo5I2)%5aKki~6j8CU5V`%LT3* zcsVTVmH7ENu95lwdB7P*%qZun_}PTb0k3cmr>X)js_4E@ppsaUUYkai3L`P|iFegU z(lWf0bWWxfJu%J|B_dLqku4P%B!gtfb~b;oZApgXZ;Fx?0nmj-lcluPKKZ0PM2@ph z%5=wQ;Gk_eiPom%3I8af$dZG4Hqcd&Tx$sC8mfNH=W%+>S^5lQ4XP?8dCWeVQqQBY zYu-LA6qp1!n3izLLsn|Avq5smYD^m>Gl}`3Sg*sbMjIi>FV^yL14XJX9;qsF0c?M= z6{Y#ig$eFU+2#I$ujBp2>T5xT+5VcSlmt9|N$h-qwWMbHsl~jzr1r5OaiMfpw(J1b zVB%E+>-tA;A$Kq}vZ|k&V?`N}9p?E*dRk7)E8`n`xu45nA$$gv$JGy_6%XBom zk?WvIuH-UZ$?jxT#3nAKZoTAIgdo(8Ngz9JZEzV|iZNIum{^J5MEmmsk)hJMrAg?07}??(@U}3fj$?^Rno8uh%kcBN zu0qV%P}~+fL5rC@%T=AUIPGi3_wG7Ra=FdOumnyQxS$kKbb^k$j}?FFxE?h(!sDrk zpqvOQ4vbJRg{85j5qeoUAr%JvwypQ6>9PErj&FFQB+Km@tNZa9syig(tJw8;B>D~U zYjLWjLkXb4_l6k3YwMxkjvH43dbs(S*l&lbjDYv(9qu+_A#MDfVZ5$6|6npvDzteW5ziq%luP^`N3Ud1{N zpvGN3V(;i;_SCXBdmrziPpVhT%4^hXm7f#!YUVc|rgH_Efmw{w*H%!|Qs|~$6j?%# z6jvie-_4h{@ZpY&c1r$mE}n1fh;U*Fq8R~Otw1!r?*x#?%?*FJB#PgK?ud4xlW<$9ZS0q z?xQIi1KP8LwhFwY+B<3pT&JAyn^#1gbSLM?cR9+e#B9Zs2=rrP!DU03yp3JY_9s1X zL8OzVfaPNucDjF`BOl#}E+!pF_xq9_ZSP_Kd0TGi-pmR03>wT{8x4a zz}%K5vEwksyz#l^Gnq-A;|9%swGSlOxUDP3Ydiddk9B`0-faI)(SD9^NRkfKud7c) zUrjfUS4q$o`69_z5Ca>&AoFE<^pEDDa(-IZJKD2dpOg2;=v_B?{gMDxd= zJJIb%VFQ0%Toj=%dYKM`3`RIrrY>0+b-igf3ZyHJEsh)ei~XiWL3QHL#uRxI&F)!m zpoxn_@cro2HUM$VO=tUup6UFS*D{?)v`L{(dV#TX5RvBNtDr42tP#q5(KK2Pm zFDUC!V}aJZ=p8?n5vAP!(R;(X!Pt1EONc*Sg0Z3GfA*DOz0;ng%+2S20n2j`mvLTN z6PM$T5g3;e{ud^fj+ZYCe;9_~n^jv=HPVb+g~6$pI>;M0^lb!pPyeZ|9PR4FraaU=JNaZm+(MIVA6?;Q4F-d z{PnNPA1{Be913U7T=<56f9hB|#sf=Z@Y4pCzy8KA|HOwsBeC@E^501MJ&<$eae#kc z{(<~?t8@pbbZ(5+f1T37Giy*VSVA=K!vLq$u^xbhFE za0MEz8Ge5fG}<92vmcs3rA2~8qb8L-3!3-s^qZkMtily&e-yeL@;{4jmG@-6RbD9> zcsSdXfC(*;xnat>VoH3lg7<7H!LUB70h!)_qM5lwrOifM56@>sPeL#u#gkl4Xr{qe zm&&GGD>Ge=BS!MBB?^O|p_>1ADc^w&Yz-7>_eA2G}qXe$ao72iC~dr-8fV&Y8s} zO-}BFWgUp)D@=z!`0cMhFXYZI#X#+}fub_Bx@adD8ecI`<%|1vE0tL@7dQ`;lybRc zOIsIlRz3_c5(gb|4gsW-jWZS4l|ONm?#?d@@+*(Ae|Mw>vQFDFLglDsv>VFtgRJ}t zwPgmwDWQ(R(C{WNb!yHvyKKFtp5q-+HtohkF*@%7kV76NT^YwCLip z70hUqpt+P!qM~YM!AX@wq$j6`%Ep{*NBr*PJw0AI?p3%Do_SnqkTC$JC6X#8FDlWs zc!DoMNa*Yd?VW{)B&1`?jpiyUGMgf%&|v|!f1t3{MR|6g(QawV2daxCHxMVffwLIr zV5E&1H}INyN}IeOU;AxYfn{JPY`M<#zGA&9AR3}S;V|QwAy>F1$Be3k#@O~aW)7I$ zAOTH%-RzBkm?)_zlT)1$l`cS&A?AEh08{8*M4l5|5m(h#(24H##Ny9$+8Wm*c5BNx ze}>maZCSyz5F>2`6L@AG>vg!C#yZ;0e@|HPl@%%Cf|gT9A;vnr&fZf|Qxccs2Y*p(tCLcC8k{%Q z{A?^5jk3X1M2#F|eOuLU!#&w%(f0n-e_I``T6}ArZ!^O7GT3p1R*-k-%^;qHypzoO zVU4FZA%E+TSE;Oc5czd9_gKmQ2l>MYtsrka(^@_WdCY!JRp8Ag;8ija0>0S^{xOiw z4H4&oe;A|{@HHk#ubu=xu6`Y6$AZ4yjJ_YCuTF6NPV+wi{Z$LxjQ(MiR?t_Le;KKt zguccXg{r_2okTyw@ z>hWQWSSNIEV7{etLzIALY3^kf@QuC`rBv~#SE{;O4^MeHP10`ya$yst&F_VN8gxy` z%R5LV@-Rtz zo`n7cfbw1_!bIMsJ;9}_N1#w%XZr4>=9Vp?ln9#x@Aym=-k}R4qT3z-htH434sKaa zC}Wy(m`uu$NgwH6uBnb}!5HQ|bhcb1yAPb=I6}47;!5vRIfKeYX1p78rr*m6O{G(r zMm2MEsedF>Oj$_6MrBJ%e{?P(Hfx*do#u3qAso_$kf4n-vAD=Zsz^;fX-i`qHAM9k ze7VI+yf?L}7Fjc0LBo}qK_?|#V`t6nafvNw82%}=GArzz9I4$%5J}EBSt1w65k^K+ zN|+0W-P6r%ib*j#?iL>3;ePqNdvPg|Du+@jrfrSVlJ72xhPDlfe<^@)B302{9P{Y` z;TRXWa=MCNW)l)8sJ45toJ;Q-KX7p)Zqs#Mkb;3Qlv;jHo`^^xm}y%54(L0d@)J&A zkLw%tj7tg1(9Imbr^EX3M9NCB{WhtB&|=!O)KU5)qW3I8KirEzIX=+ckdLWOlo2DB z0yEbt-{bGy@TqwM}>3v>BXY z8b!W-M6k>9nUMD2fP6DiC#MFX4GSxPvWS?WQkwZ@(_#k0JCHyqx8(#vsAm#LXx8vU z)%Sq}LO2n-IpPY0p;~r@(L}Z;5Fr%9HTbDs+_OBPnT>L^4+lib@$m$IvdnR$c93Bm z`J@CwxSx=4DaZH41Tvo8r0H?=Rc=o;y`JTo*PJOpnL3eR*$lt~1Lb~T0wE)=$>%r& z=TA={U_2Wt?lbuVaLX!e%`$aky?;AJIL+mbGHEidX$m5_%Pr-yrfqDGN2L}>GRmB( z7T9`f+9FmorYw_C^*Zi`C*v+~~S;ls5qTy{Z*9&VhY<2{lDd|FIVjvtFX zxr914Cf*M;{E1M9Id3whgK*k0S zCFr=~nUOHs$^%xxB~#XRKZY_ zf4Eil!>^JERbKW?U2uD zhSx?lJI_XTe=r`DwaB8Thh+$Q98kra6d`5Um`S%y1yXUQ{m4x#JnD8_BVh*(e&mu5 zxn=B7aU(TPACXEYG2U4^x#|5Z?%>VrW_GFhqO?)0hPGxieIOFG@`VMinENqR^7xiK z{y#I}|DQQFunEY&e(FY_89DD4x{)_3PUJ45&@Bh4WhhB(&B!*C2fDfH2GtD z^7;Ao@;~6Lj<}c6ju8}>`I!+GmzRw{CV#bCIg{%)63*vW@DB_Y4K%K*S5qZvMy_(U z-j}%??XI2d3+%*ye;YRlo}#FLI!Leqe0`$~lLzi}=!U01r0b1CUE^xM+6`goUMsRcN?;N#sO`1W_YZh!O~ zV!QBOX&Wdgx&%GBgeTH{ORYFvnp$cT=~6q;{`=#%??1osGzHF__CNhs|L^Pj+n;a! zgfs#J4a2{Gy!i(xfk`U{X$b=y{`&9m``bTzsx4d=2rjO*QX{y4hxfI1O!`L=E=2=I znzkaCkS2*3e}{`Egai%Jx5{nkn|~9$bc-wBKHWotk>5YwHTR$fXgp*Xpn zC%o_}nK*Kb69|KcDAf74e_ptQX<`uX#Yuhm+0d8od%}KYnIwEO`$g*1B!5CYeSaoa z;|jYMdO*WanpVKVoA*YDZgo0d=t3Ktdf`b3z0lqI-ow=yZ=+Dyc8TADu?Gv8nufOr(KlJctYAl@{{tiullz#Z|zu{kAnKua2 zXaZq+VsMQxA4qwuOJpkvC4U{`=pHArZ)D0j=12`!$x_!&^>kMa7BHdYpt)p%%Pdd) z)9b77`r1mCOJ+=EZHC&e=rw(RC8gQ04uZ$`R1&o;wVsYQhnVyObtBPf4D;3}NN(GO z7kYqa^gfczs$cBbmQH&DetzCd`upCm`QIK-h`dDdm4)C{<|W@W&f0TT@8sO!5pN)&X(rO0jf7){Y$;8WNm0C(kH~@~ z>sCXv{9{%co3-QP9R=XXD1g}s*Wqbxz@;?f_C;tZ3M_Q-z|vH`FSY=x^i*$LEXcfk zW$3CLiYCUsMT_aJpMSXT1otQi8`z>^AmBydqNU)^7I1kZiaJ^5i@#UI(Ix0T#5_Zn zJwa?I`asE5mJ!_hz&t$b4KyWEIwD?#rler8S~xZ5)hBw*qkjuNwn<9>GL*uNEdZKE z?dRa0iAzJ=sZ)-icCz3wR2wW1F$6l@E1pcZjF)maf%qb?2!DzxDW+agB=w6NPr+1U z#i}H&^FGrH60quNxDVm5Nkq2f<1j88c=H%2yhcSiGG$8q?d^Sun0bz-w>*c`Fm@eY zMay!Fj_yOKv>an&S{Pi5sLL~Qug^XV$2!bp$wL(K5}46RMyX?24M^bagBLC6v1f*q ztB441fRUh;wtw-~{u%6p^!U^_AT=>mc@3miFkKf|wsW@vv#VKRU;;fMLA7IuDV2n4 z%;7*zudsabRsVA$2Dkm~_oiaUA>3e%j)Bf=SYv?cx(v0SHK?Yp{T$Yq7qI3qgd40; zA!<5195|V587*pt4qg)tAd)~CJCh@~t1n;6xnYwV?SIUmkI!cVCm92q*C?DXAAl?X!i|e*i()Ql9yEcTN)F7ohqyRCsR;|1QVyxYxX`yv-8rx95+3cz&+g*pSpDyY^$Nr{D05Sv01NIu_$$4FOEX-K?^zMqculK zmR$;%0K{j3kRDDsheKb+%eWf~o^^4os!jVEZeuK=#=%pT7J-OF;%G;Vyj$SWLk6l!#REERbrG9jlkyk<>s*$4@h zG=HJJvtp41xpK6Vxr)M>T^3U)A3&`DwxiM&)Mt__&FMf>NzcSWp9} znCsg{EhyUo9+hPT!@$hQa+&FULwbF1hTi&j6c#j-Y?|RUl)FBRS@CION(-2gUt$!; zbd66?sA2@hlou3=5;TUO`_?BY6c{8oG=GKTF@*x__dVcbd{v{Ss|t^Aj*0tS_8}$& zFw|~}81;XBfkzUQ?$WhWtc1~&xtYFoRmOSYSEPt)-77urjdH9sA|9#{vROa&n0+oP zF_3Eo<9Z?|M4)-o}YJ8}}s3MSrgj zxO7En5B5F!L{%)g_2hiVZ!}|wIz=hX0sTQn3G!q#I6soCZR6I}-pK1zi;@rsOTnNR zsa#oO#?Rx1d`x%ApJX;qM{(4VWYasQ2z`FGE!>5o1E#H=%;>i2A;BxEJli;Bzc;4N z`(38t{Q!>-US@Rdsk!(759RD!K2MvA;K)$H z22W~hOCD~@!4q8r*UZ)85q2@z&czequ~VzgHADtbHkv*?{>QcjtzlkN*B8jcN`H0ndRt2Y zxyn;LURY@6)3j?E#g#WOTcEISKi^f&-DdAdbJy)#!ak1J1}FT=Ea(?;LO5pYj$2T> zIDxsA)|LZK=SHbWfIYyC!>Da=!*5AZ=0)593PG^g_He>vA2)Es4f_Ia?8W^sJ{!3E zttqeCeJi}3Zx+tYZrt?n8 zJ2-|yP)Ij(9*q(qX3FNhE_ zVHJ*x7!}SwY4cwMX30EvGxYnG%K40$F?o2yD)oI~orz?N1g4{!lf!4m>!Vf>lksNE zFA14+pd(;!3iizg;Dl&fP*Wcw?^lQ|{5u`5Fv&}>V-tCimgeo`blxMhmZS~2A}NOP z+aRwZSGwjGvMIwc!hbGc9W-Z6vW294K`%-+?vm`-s+H_`r)_%~?}E>(N$QqcV|(ys z==#S^4j2}sdwlA^eqllN^3jY}hu z>Fk#jD$9L2%T{`7cFtES0WmjTA50SCBm=0m-;t>@Ymg+vl+-C3vAmDfBo!eVjVZbJ zt|d=6uslpa5=bO6S0z=JmuN>f_B@?qa3$~8wP#|?#I|isY}>Y-iJcQ`Vx64W=ER=Z zwr$(Vo8R-VdOxh{uI{S-($&@b-uK$qa-v)vDIZiWYG}?^Vd5r2Io?R2ch&b|bQ574 zk}yd1R*c3d_y9H<#@&O%wXm_!IyD3IXgDMZO~V~`Yk>y^$V5bw94l`0d`GH(W=I*s zU2p3!Nv`d79B+P!HGe{r1Rl2hU-cWtU5NZ8lqT*%)M*7^B(4etU|wg`{;U~!{gpOJ z4=S9?NA>zU)=!t$7kxuF(6v2NIa%Tt#jI}lvRD#>I-xSfw1r0yKQ=uU0|cU_{h^JBWC5=qXa@dDJsy0e{yo|}@7J-%kHuZ;$YS+q z{2$^1U9K!0ab$_yGwWiYt`CahuG!J-l3G~57X|AVJ`Nyz=P{ayIR>`$vkaBDqA zt%x4vb_K<@Q0fy+KEd_(8N$vfF|2QuU??|&L&o8g@{{V~?IyGZ3zC&_OwjIL6l|#e z2F9d%IR(H-CiR$0AF=D3=+A*4u0bNujA=w<-ClT+Kf{qB-#>`LrxVF^h{Z!weqd}- zv|ISu$WP_~(C=!}pw#QY%9mkJjqZOLLL$*zhC=^?llON_X4Gx$hr#ioXWC)#j!7-* zB4U(DP}$_2%0T=AnY1wrL*5guMWb)|uv^Sv#v>b;+qqq}=AxVZGeb9q zfWS!ph?nLCxMYr&0iERuF0a$WkkJVXDkAmX!#Jc-`SDARO z!vp~#j;JdLG;QDJGlQ0PY3u|cmjgCs>@zPj_ZObi_M|Sy%J*oe<7}m!a|itXG8A#K zIt)l&RZ=iFP9mfBzO2EWPnhwQO+ZO=d(A+H43$(~bq@Fxxw7e{Xz0b*q9S+>Pn43; zCFBv4ptZ@4#LyCxQ?~plICI3BWptRTJ}0+BUi9R(mZ8= zYjV(5?OAI+)lW&83t62c`GqQJBkVupuTOo~7yf^F=Gs|_GLptyDp}=>l_)g=sYuZ( z)m3{=cB~mufI7JJcyb*MnUVXyhf{zSA!$BCqi)Pmu2cl0gZd-7L;~fy{~C2nDbKNx zsUp;E0i~QFAhiUvtrjK;n~oSL4Omc}xs?FUNLZ3u=HO#p(g`S1>~^y@%amw5r2JBf6+u%4esmX5efu4j zxN$Ik|5_KBiaAUNC=tMxhqFI?E6#Ys&Jxv;SDpE2M{SJyu^eJ~7ykoNRGuBJ{}Xxn z{^WRaGcvY~V9`3a1A9>J6nmGBZ?Jrow)?z#VLJ(YXQIO4du}DkQx%1(4SP2QqHvQ# zufd;UH*wkbDN7z>A_hvjKc-n6PuoGO!)1sZto;t%+MgkxN5TaoT(hW0gfcnfgLttrqi3Bc&dQ`@%_^=X1>MdN zHZ?jlaK}Av33V&-4Vqs7hJb~CWNob@FiI+^$Ge`Qr-YF^}({yA@ZI}X#!XZz9Yp42!xp_C@q_P-Mx_*EY1Rr1)sXoL(H7y`&7 z_Q6@|LzOD6fasj3d=j^V?@%G`+W=L~ITT2$v(ydted`OHFPQK$U52%?=uZ3cFwlqw z%2_FPQNl?p@%&HrgxEX-2^EEL#C0Qm3vK5iwhqI15!jpbHD5y&xn<3J#*-Ai0Op6~ z`A88W5bqro7GRrt&8y0X56Z5;zjIzBV6`h4k1A4)#Le+^S(J2aQmZ5+N-Fc4&R5Mp zEs;_tX4QFZni|R#b^u~x??NA+<1k{*%>rmD{vv{Er_CAPT`Do32QAlppA@y5zSZ*< zV0sK$T6%;_1koG^@$MBWE_%HKkdc*ZzI{lCS$cpp0KA0XE)4Uc>_BNGq+U5CrU^fnpbYmLT{=VvGNp)==pU0v|3fYthu&5~b?2b1$hTXHnVcIFbPFP`_(ACkjKq?Q0{^fEZucbA+dfLX#6Gf@)$Cg#@i;*DZv$U2U4*1tp*H|ea_krS`xU%mJKQ>7~wo&L#U zBl*;xVZ-PpYnIjE6RFy5o=)Nb+W+dMPp~omp<>|n9V%KA;U_AB5TG$xxd-eV5iyg&M+c1o~<2#>*sNxi-l)__q9*&sQGsJ zdx6n_jEh%@0J_7cHnQi|fs>(G;kbpfiXWHU5)aH>{yOGv@|ilOcT377QI}UDPVf*& zxY-5R@r2#%z-IP107NrcS9I;g#A^giCs;A$e`L#lzTyoSN9p5{qLCUEn|#38jg;(z z3XH{vk4v&|;#_}6*T~Z7{8RfT4Nmn_v4M&x!~iai7PD&UH>CI!&NU!t?GS0X}0pgliUN2E=e9^%-8E^ruAD8~tJ2-47004|kJ80&#q5_;Jw&c*mZLon z4D&nA1xkAF4)uZy(vBz=8*2Y_JIxBxdPG0X^o^WJl4Fr!(D(8e*((JVHMNyV!rhk+@s zUawyKs;tL(Rk@ByDoS zc?;~;$)`8_@*F7l(Fs?wE!&3CmntW6(40H71+QR3Gq7XhGbAV_!6-EnNSFG_4YOq~ z%~_Yu4yKPX`>Xtoa(O}eC;|#1P%I@urR-AXaccu{dIgd!e4Gy6ehgm45T=}RjZ@?0$kI$THTu7_^&|dGTwTriox9sD|26mu zHpj;Jvu~7ZrZwHfrl5}jWN-Pq<3!vb$*1Cz)biMjOZ6>Ly^?zdpPL)j$;4uY)c>_n z#L*R(oMTOm8fPQHS!D|U}ldhI&I_Fl}79I@yD}ykGeMVJx^IIbm)S4 z1FH?abNRi{b&PA7nB$M@BNqDEx{3qJ=2(Jy+h`};eI#>7qo?;BtgxqXipt}hQzvnT zm5ctE#SHF2^YJaHRyN4s&_|t&?MydgV*4`$%_apAW2+)65INw6#2EQZY0= zW>RD&MDb8D7`BwAn+&(ai7SGKc#SF-L?T0Zv_0f4917n>cZxUnchpPwiNQq1T!tL@ z6?XNUx1`8QbatB&t1o}%Vn6!nG4!M_zGvyIqh@J=Z~VMMjvkc4Js3U!fKT+_mt8;E zbhr(Fa_Q)?HKy&2Vv2!59M5>qm{L(xEI3va++` zm(4}?5VD3gYisQr&v*I2a_p^KS1gXM0-k>YKW3nw@Y)fu&zQHIdy_zlN;B|V+3MXI zW^-lV{|;JUetNti?$(D004(nw?kzbEu?+Etih+k%JEAaKatdOpC^c*{~x$G#~ zXz}Zm1nSV#T?HzSX!i zeT~h^DG|FLC9>;&X(@KZ=IUN$KXvsji+EMXp(S4;q^ZVN9JO)axOrh0{$2iE zxEsa*#*Xy@Ra3-Zr{ZM`*KW-IUu@*@mDX(AjHct!Akl(y-Q|J)XNBl-=z5_3cRG)W zuzJq`HsIeux|CKH0Or%5r+s69Xj}5ie3RIRNuW6^!TG9mf@}dVTa~kjL;q>pYa0)PdfH9f^y!+`2u6v1K*C<)< z-k_t?_hy2qpWl{O&!-;m9X4CL2%?u z4pc)m4)M{ODE?z&Z<+%U%APYoBdSZSZ=#+;NqwqX^&|4C7Ff}k2*gYvnKfJQOkn0S z(p=@IPUN5jAVf`9@S3P-M{w%Dpkm}h~N2@p7w?7+G%MoxAUOb za^Dv_ubSg2dfPxrb(6S5OpN2}Y@iII&?BKAwTYeGNZxvl0tYRLLdqUpK&K-KX2~8y zd%~-tXr#f+wo|#)@h`M4#!hKXtWg{q%lBjEAhHepu;glb-2Ae!nI=URbK`*TBR?l` zy8f_Q`3O+*#PmV+)OtVU=*lR6x0-GEY+UrxERJq~>&yg0tX7kxXg^m>tmO z+7k%34ttDsx|2H6$K)@YS&&A?__>bWVUJ$RYUrFaFa9RIH)Jh75#5C~Qg3{t&zWtM z^9i0k`1k*;hhdA7XibZf=s37Q-%Zpn-qDLVL=&zl`tz5+l44yA)y0#wj@fk+aR_dT z=H>A9TP2%K0+ej&_XVsR#trBST;hy{>w|LF?jnaV#ILYoC^8F}8`ferLW!xrJT)FE=Gl7TRFc?QO&gQcT%1Yei?Ax=#kem9*}8p1Ct6W z9Cc;w2m3`bTL}O)b&}WlFd~$mif(Klt*ZNsSZeo;$mtF5TFO||SeWCrJFqTGSd1WR%v>)y;lHLAnNy$`S2}V{+Ini~E!~ihIO`BfTqq)TQ|r=FD?j}8 z457h>XV#Lj1}V+o6$xzsJ_?9@HumJjdG9D^jY6`Dos%GqUuA& zI&*AK6Oro=n3uc$@P%NHhk#rA9y#*}MTgZUli_IXHr8veLW*ZGwI_Ok#&1rWmbw$a z(EMd1H>Wy?UBF#ToIdqRnRhd12Z$+vZB49xW<+i($ za3l!tC`P?F=Pc`oG3^tZI!apUTACBZ%}BzPe2+q`$SeR5RQ4i%KEJQV0t^7);=LcI zZ8t*5fr4CH-d({Lwo&?%wSy#c9ag3L0rFY8Up zd6v{_woqZRvrjRefko8S-6|E8R-Ko2CR%DB5|*!7)ok8mwgrKiC*Bc(mvY|;J*zpw z-tE=jPYH@*^s-1S1h71EfX@R(NO8y3V2tH8GB!x8$b_rlNY?si_)7Y&2HN4eq9FrV zgB|b}HFH|t!<5j=HPL#OkTum54r_ydMt!smXxL(*N%oS%qHhSuD6PobFR!QGIE#SX z^kY0BN%1sRypTp&!JK4T1m_6vlPqtG#I$Iw-+03?k7iNo-QuE_fDuNKx`LtAT9!vM zR-$h|l9HMkt4re7w)EzrpYw^a&ZG4oLLbEw4MK1AY zE;}Pn;EU6uFC&;=rgQ;rHoMA5(G!R~?sJ^c zMY1L<$aTj;P6b@S00JOs>s!MF4}34Ba~WD$cvvBr7X7O3bR5keXB_21KI@^buudH( z)4`MBzt%b=hV>cc!?3Nie-bB6)TEy$?%_*{0;$reZVTTz9G&TrY%A>6^Dr!J9LclF z=!?g=9vHBNV|XdAwI+8<;ciW$)kcOhW^=h^n--^M&j=;_0Zy`g0vJahoPitMV*p&{ zJZ-q?H64y02hkGgQw?t!lRwAaTE2T~p^)TU$<5>3C`++@W!1wGv(w`Z%!xyh3)gp^ z&9f(t3;koLwN){!00h)D+KYv%?4<7OY_g8o^`#kqFRc`sEg&uIeuI`YLv)En!$kijIVhNoUV?`wvw%`7mVzt>Bie6 zWD{OdM<&o~H6{wv>f{Msk;3?VYjJww9ol{^20j*FZp1;+WVJ3VA?uCgX zVhCadZ@-UT9S0?iT;2CzN<|C-_a|d6U#_CInj!I?1AFVpw;TX4KBX=i4nCPT7VaJh zm-!h_IF@~vp>8} zpi4T?OYW{tfyGyWND$oYoa9l2oge&f*LNn2^Vol3MAP9h7->am!C#dfmDxewevFNDOqN9lA3vmgZo4cpiURKLb&K0wcbKG{)N zUo!h*+sJQHAw75!OE8gD6CkXPbQ0Tfa3N{v#{GQPz8;q&PNE&p-|ECR<}XzYSODV>3j57*=Kvm}`{Gk3n(tYN$nnR!aY_qjCj zoh{!6pCAA?s4~yTKWplO$g_qJ9*%zg{Un}!q5y1&SemN*?&xzps(s?I9PFBPpsEoL zxM(^qNeg8!b+R`1R$a>1&NYdPkXtb#mhnsUBU5L*~~!s=wdxoYuCK zqRq$F@iw~GJLr!yq;#9~WR|~jo%E~~*KG6D&%glqj2{%b8#1;X!U;jgG&%kxW=dCL z$}Z=r`9?-vKNzhZ6z~zRH@BzSu{Q>OGcv#B{k3?nrMk#aXzNAHw&Y-n4`-kpT!0wxPn zE=pMF3JYc&X+!c4W2rFwwk3 zH;aFkNe)eQ5Jp9Yr?H!m;%cVc+W@khZN71X zyCSV-JVwrzy;FIsdy3Az7>eOs5CtX(@s!osCLQme*k!%lh8t}=Sg>#|*#<655r0L6 zI$oborDzDZQvKl>R(|xV@oEyiKpxofPwJeAW#Cf>+~S2%<-dOH*qyaA=HJW~)0zO2 zA1f4=9M59R*~}ZNp?_@+A={=s+xG)Ar9xUY58x-|LEfOZ5BlpGMFv$J{4x74lQ|HH zde5OnE6s8tKD-c-EWRQzMkJ1MR7VA zyvPeBcQcmkUj{xmYE-G2Hu215mH^O<(Cd`x_*wpLqTM}Gr0ILP^c5F{%Oqi2eZtuq|xAv_L3bn zEFYXMeGZc0hnEP3Eqk7AVz3aO0yp`UCI_hn7es40!){Y>Ut8&4fi)(j*0{xNuH?ZERjf` zpKafK{y$OGW5C2vomedlopuAFlN;PmfsC{$?sA>I8~@i%CvGob)qrXr z6*ho*m&PRR=7+qziI}TyzY+dz-B?h*bMLw5rJta>zgt8YFO;Q3AgQUVZfj|B%KEz$ zHeI0IVS1Szq#O0+&+Ts<=BTd{?STaiJqc}v8=eh-a69r1BK5>gm7Q~&VO)9YkZ1&J zkJ`Zlt_v>4;>x zV4VsNLk!SY?XOI@7c*HBE1u1xRY5H3WRtUjIf|P8zTOBUAszbdpIIVnes?b^>>dr_ z(P<%oN?f*B*tbZ`W+nC-Jw&3u91s>MZEpCs!RZ(fCAILQlC9ubKR zGk<5UuA-lvWXRx|;)}sfo_5Ip+Dy_;lvhQhd=F^e$lKV1% z9N382h4F-UQUf8?Td+oV#F1?#kXd12cuXapqV(`488a_Ofac*hyPMmab&g2`j-3W? zU0RQLC5H8S-IyPqT##tq)GHk!nToxkt_E!utJi&D~@ z_XdSQM7>tS6!^UU*YUYbIyHYQMTV0A$71R`1LNfNQ_gth3!L({N&Beyu~!Gt43`+g+x2jw}RJ>3PqOjrdl=5@s%NxI>@$2^upQ5T031S^Wr3zUF`2 zVkVy2MGjEzNz6a-uFX3L(w!zotF$uk7Do^EDr@}4K%W{YJfELYJ{A(UjNMsa1$%`U;c}0 zvTq3_uu58rNs>9=GyHxL0oyXraRAx>j&s#9!T+)K?4J(qFFItv%Pl4|40Dm_g?8$+ zmN#iY$k15**oQ|dL{t#@|3JO;=g*>sXe(mWttZvSjui<~ViEletT zZt0?DluX!ThLf=0rEuZXGrF zY<;`FdCaoL{-c6f^akw~B>E9QlU7uFDpxA_8-b|`z&~A7o8uRT zDUO9NxA*t7KOe4^9|&<)4_XxAv5uUlVq2`3VZfo6awzycTd6q(H%3)01FYYqCFxan zDwStX-W;lhKioYJJpt?e?q~({ONg98g)t%_38stVmI-G?Hu3Q#aY>7w0-5L|0728 z&^qR>%oUQ(`G@Y9YqdML4Tu1X4k07QZ zwKj}N$M$MhIRr=h$@iU4C&J4=&rE(yNuMLsu;XGZj<=V|dGtqiwXK+kkVn`GyLuCG zEgD!V8F;G#Z=`@GS}bVC-_+DuekMIsbMOwd!WK<9ou-#>UTB3Q0LWvd|4msk)?xO; zN*4Yqw5Pr~qlEGN??t)H?1PfsGAV|bR!YAy4})H`f1RIWWMd1JjWRVH$FN?x)>rrA zCoLsa(cn0zH}xEJtB9+CJo!)vZt07vFi}1oO)(0nhb`;B2&YcLgq^RU9^_#Iz%CFl zGn!pmt13G}={{M1gKnNDO&R(oZR)lYu`14TuElAccnaHEMNiw)w;qv{a9D2b%% z=`Bm}eToz}yz;IJgn*I&)JTu&!2ip_0Ca8s0Ry+mxh$MZhoO!bZ$SGLC1b@5Uc;T$ z@jL}Yu;{E~>y9}HhoVKB&U1wCQm*R}O#7t=H+UsDRmM3$x>CCc%%TF#pR``W=O}3r z6do_tI@PHGswW|+P)2TLI6(@-kJBeeaN|R+E*R?)q$S&au18gTkpxoO&aVagWUDw~%iPxm8`|v{ z>TMiE7yMsD^bOHBF5BwA!d9=Zla11poBezM7eAkGmX@pP`8ZnK_3Upo9kchQhVqYK z3x|;CbDBnMq}?@>r3<3&b4x8S8Vj19vQ7Z&K2S?psY}s*VW$|_Sc|SpBX^I?em%-R zA_I{7BprXq82Jw6m}^$S2av0MFDd*7teA`sOnJ~}J~F@a$8*`eL<(*kG~t;)zqslJ z%;bQW4~U9-xU=IYh%*0(+_XvddW* zL)(5|7b!|n}?D97r(>KT8_^%$VqQz$)l)fF=92jiGU{0iVVM=kIVCA(#-(< zGLq-B5K+{OEG>6hd&E=P3QT=n|6>`FQ?FAQ;b1!zU2P3c&!QLp!q#fmNjXb@JC6n< zPVNcj&Mwxe7G1J$@A|>G1l<8hbna!{5EOg48 zvF^&-jw?U(YSDDm)}9gi_yPJudET!N&k8pMb#e4(_lj&QekZ0hC!!sIGK*I<5PeTq z#!%beJ1N7hX(w7t`RAa01!Duu*<&8pGEm{5KXD2TjZV!>q~UDgZ%%2_*W$qGO6$DO z+CvUk^ZKYcKjC7g6dD4f|FeacVKE;W4n~b&Xo>eu7g>*yxX}5Q+TiKBGBgY z=R>v}&Y&5%18&E=iVG~DB0q*)QMBSiC_Vx1xy9^5NyOr_P7bI9>B~l~dIPS-&iw3u zH%Yx_^*Ok`uiPrGR5W0Gx^l8uLlCO`XzU{m}tGUz8FA- z9+*$YkZ=46KT?HT-8F)EF8X}2vVX3bMM+J#?O1%hL@~n$sblIK1SUXLa?3w`rr})sO;Fbivafjc24wX5JmX#$RILFGNSKt|5%3sc*FBMk&`qs`0 z!ZNtRh)d&oSM0cDitr`ZS6En!U6tn@vX8Uk$&8MFmTdq{)EuI&w)z=l=~9m06qRwk zXRYoF$ffd7_OrTf@UCx@s*HkSGqP3X+!N|Pzc)s}O~L_1ybw^DB8$+MqJRnAFciRW zRty9H1i*rY$Hd#6CsAj$!_3J#T|Z64`S=v`4P9zDg-%A!y#6me92q|tpv0o`V1Yg1un(@j)`B{$G96yh1=7$5yt6B$VXK zFmbRu($qu7%j_%<nKex4cOM1rikiqYPiOKR)4u+5qqZCk^Ixh(g-snnnK97aEuAKJQu`G1ON9OOF?D! zO<08$1Z{>r17V>vSOz`R5oHqDD(?kgP);_|HeyW9CbiZtW3x&bVtvwCfHN2tOOU1L zApZ(p_;Uc1hVLd%grm^DLICoR1ztUDz(PFx3-&^kMDzjAQ6QO0*G2O(Gf{}qSdCex z*?{P8!kdU4b7SK~{f82{XpTV{tWkpgMlbIr7ldKtv*MaO2&YSZC-K=Q#8ZH-vr`M_ zVS-4YR66IJ8F$802Agai$cb>m3EkE_If8PvPd~z}eItL)Q@`9B=FCFE{Dxomdbd|M zI8Dmr@gPtAY5X?0qk)rPkskMcTP%oE3eUYR4n!;z-g@HIK1jA;H&=SB87!r z0^j{T6qQIj7@*6vhiZa;a>3*`&4U^qANr(#*K3FAcuTZE3%uTRu_)S=;w920E5;t`3 zX?rd9iE(w;_hsU@C3-bmJZkfvtz`bg_h|z@H9J3|IC#4+wz@jFZnTG=NH}^U&o^9H z7P_Cb%tr(HnT@q2t!V4!bmOV)hiBi()AW&C$H`djY=4vY!dlHYC&)4Y3I>x$*%#vz zv=-qbJio6yFN^jW(EvS3_;KNdkG=f}psq4hq7KKE zb(ciyy7f2lP6YGJCH}`lip~HnmDJuv&Q+Lx0w`1!g4-}h44lU zo2y(>LoI6vhkE=Cvg#*t`nIM&XwYRBE438WO8Td6YNwMgyuP%AOZrMND^;SU&Fpis z41fM#l$r6e%}_KwSt*2oBu$_e7X~*#FhBKxv(AN^{NWMm#>;nD(QJ$sQ+@Sb>z@?3 zh^t~}q&5rvppR<;Cb~vxc~E0ShL;O#moH4pseNfOUbv`#IyVxZH9{LbSO<0-WX`)5 zvK;|6!#cgO9@qFE$d1yCg~fCAj7U*w{k~La7;NW4kI33(+m60CwM7}3fjAbx)zg9x z0mkN7i)KQ0quZ|MXnO!|7vyszcf9dPi)?mwJbe%OCyKmkR#tMQ8{!2YA9cniD`w(I zi8%r$faLNY=1j;{YY3*;u=7-2A1JSxWwC) zJu-4QB3bxTA&Ms0+==(E<{}fyWJtq8-4JE4gB?(V7d8aju3_DmLHWK}PXELglr5ny zmu{}3g_2=5LLi#pH@Xrth+~fO;O%bw9TGh4S)S$J8$YSFGW5&BHfQ-)VVere+nXyf ziB#aTyMc?un0RKG`LF7 z_dqPnE1Estu*X<;8@iJtcc#9zq)qP@Qnb(v!L1tbB=R#9ie6KzJV+Y(Y=GqTpuq{( zqD>rLGB?-#il~5WIR_97RnAS?yyjimXI&=`uL%o)5+?{occQ4U{98OwrGC=s83o^} z!dozZFVq@V*YQNkGI;Jqza{pE)P79J!?8;mC;(AC?nS>%j@9&#yX8|Io_q`gZC?4B z&0>d|t0P&z`stB~dZHR*DUI({c2paC>`oEYaV38OGVi*oD#+NX^g!Lut zFX4O%_e*$R!v7M%mk671c!|1AfFLz($|kTJqA4ht6C(zni+@Oiz?C8*Y5?qVbZO8# zslE_O=F~&3?%_H~W1)M#X0zP#1r2Vi-bBT>eog$+bb9A1eSO~UEv6KkBpJg<4QtK1 z(TMmr(Gz3}2g9}z4RZ_h7?5-4C^WL`te-_RN?*HtYVlqrjA$eQy;3AO;n6@)wdY=E zm#7r1Vk6L}5-J=%t#zZWSAAoh5{F2Mw?Ppv3iIl%_XiUdScwG2(>e)94bkZ6L`X6>NR4_`F zYK2_FCHBlhL>J=V9pCo!LhMDX@OPJ}U})e?f@vJ&!Jl6aCk5p9M!Gr`UW3M%B}Fud zxQ+?;r#F}@%}>?vgK*tzeeqF##O$wug1LgDEWz%S z7h0^yVz1GUrrELSSX8FSjp(raNVE{F^VP```lgy|&KQz6k#u*sTM-xqK8~L&tJ#m; zr-m1}c}J;yR#lHyX&AsGU7M6i6LVPF92_%ZJBhmhCv6Vum|!_PIDOF-Ptyr^77cSD z1$=MS6WQBGAP=DJnE{y(T`IO^8Q03QHmD#mKy$ZB7P>jx{xwqCVvo+Idv^6qS{##h z&EXcg=nt+>x)IC_36v$IBg4iwi#Vy9KwcD~U}=P=q+M==(NGg$+pLyjuWT+d1#`-9 z_fMm(1TDq{UI(Yqvf-HzM5%J>n}&n+0{r!3H?Eh@Z#BthEoVav)*r#q3JtX<;_#?I zDWS`d#J0({Is6_8|4uYY6cjw=d|#$3RR>+!VD*&q#hlBCqMTLgTmf_}Y)f!DQ!8#0 z?&^jk)}492c}3MhWp}-f;Xmj&6&5+e!wLeKdU&{TG_+4Q@hF*}!VX*7XqkSA0>bR6 zxs#w!pRuo}$~E<8sQQvHSj0{bWqkZRmt`1jH^Re`-J1Ofu}(Avq=pmSH6dj+bW>Gy z8{tq;?8dBzkIbxO(rQ#CxAzPFjFn2={H!%{l3U?a#^5d5TE{SpfNwQrw^d_LujWsX zlQ2&+eDKg?3E)CK!Vqs&g=ir31tc+eejhGPRRSo2BH5twGKU& zQ@Yg2PmUTP3V}eZmi?M#(ZunjlrTU=0ogIZJ=!Sx13Kazrhn&h*asX9&|)Igo&z?8 z%AfOX3bj2ED@itWt)?9iAt5l9RMlD}`qEOZo&23B2~p5raql4a;Yj(6CxK|ZAkBzX z7zr^ym>P3C`eL)l@*@sKf<`h9J6nij5e`;tEtu=jc-?ho7+JrEncDmmXFDWJDoMY$ zJcChw(BIt<5<3sorO{#pAk^|tgbEJO1ScaN%ha7uIN@SG1XS^CAg^6aK|Pr?jI-m) z<)n!)6A^W{NNZnZKirLM8cVPkAZLZ;5QmYGHlOTsOJ*UEX7V5jU| ztu3AkfaMd}j##Sm0vC29Viq%gogRe9zFkq=#>jGkQR(wsSArh_tQ}KFbF*pk{iw5Q z!f+HfOKsj(6|;Nr@fkQGV^y|avl%`fI-)Sia0H)pEctC(SS9JI;Hg?li?SNa!0h8Q z{2{p7nddHjF<){N{k^00+)$zHX=?oB^^7<@(;DA{j9S8HG+ z*RJ!uy{bX*h&&iN>-{>+4IM29Nj{`jHM5NkW3%K}c~t4C;7yLBVs;LP>ornv2@~9b zLr`@bwAzfY>p`OJ?dR?J$=|WY*ji0!4joxiGBO_jFx3a#-TveOr=BFuZ?irCcNQ7j zx%&a~VX}zK%(`Ho+P^quALH=Vto~xE?|T1K{m8mxSB!l8I@^t5h~>XI;f;ed6^ z>gY+g-P<};xkNjy`vBUT!Ac-sS%di|xO#UZX9{kH{4viBD%VdCl%<%#w{av9yR{=? zMhht{?d_i$2r>JD$<6_DPl|L(jS(GQ#Ls5moeWSpp4Hk;u%N3XzR1-PX>po_-gU&m zJxW8v5LoNw!GGC8=}X8o&`4*wiwS`E$3Tb3Xeo^}0?kGa(?9gyCN-TED%zbs)}V{m z?{1?WgBtqJ_ErEch6iCDRiEqUJR*lFdTcf^ouyxr$n&^WvmVGgJ%3ImY>^_%n^$7^ z{ocm!6#TIgiE@8<%b3w^juggyY~2Y0l3_dg^`4s7&{)bpnXcNuL~p?r#eV%-|XD@ zfQq_gjriXm*rAIEbqa`F14jWYi6v$R_(`Hk66}b5OX|)3%99u9@a2C$kMyePLDppV z`C$Gg5cdX~;DCce=g$PwdlOF;8*-NBjfbvL&b{M#wqD>m&C);_o|2S!oWtxQoxcVjA zDZroo@j9n45{FE6e>F*{upJ=tl%>4;-yubuHaVoQorTVt;hw+akLOi}wt{Z#f{R1fgs^%es*X9fiz&_WraB!h|n+4weQj{LyH~u8IE3b&0nrPy>xCJJf-M<2^AaFMZPNe zbNr@cj0$6P?CT(NgZrL1uaA!$sK4S?LXlsgsEtn0-7dX?u7&lE~{3=Obb&o}3vy1E`IKaAyQi37+4$N+K3cEDT%AnMD&pOk} z0%seWcCpWQqpxtQ8kiYR%zzr(^?}#Q)8$7v_%$xg!e{1zr~%xFCk{rf#un?~B`$}c zjRl2|n*2GDykc*1O(50*1AM$Q=i>%F+#Ex6NS7f_T+y1n9<)oOV5Do9X3HdIHwm>L$FQQ$xQysC zO0OU&vQgQ&;qXRF*0}k+;Vsl4N}ORkFylZ<9hc`>$Yyt`>8Eo22jBunTNJc_VDP=P z@_$F6bL_2ZZ&a>`M)I-;zYM`!KJV;ngjxvu_#R>RbEs+#h_dSbA3C;F7~+#S!j3)y zXc-05j(HmcuPd*r3sG`z%mG#0)5(bK>!I9KyMr%WFK97M-^-V7k6&#1K_IOn8_V7}Q3z$d(dLJIwLhA{~h*uY8ZuMTS>4g|6YSoC9guBksR)<1CZPQ$tM zKJA}WQmJt$~W5=CzoVDbN z(tc0J+1TFL8{4+CNjA1^ZZNTJCmY-5#MasgLkk!v>Kvg2YYr=dWCP0d{8N4;&p=$xj(i{zX{}$49Q~jXauYWN zydBFm{q_Rvbte)G``+c+Qf16pu(=3uMM%;-k&8hQtC~qopT$(?sTfirE_c<8`~Y z&kzxE(&RMjNDR0674xoO-v8SXcN8K3XAS} zl>}CWUL(5$@4xPU28GYpLb6=5G`@{UY@pft5jZtAj&6IO#HLuL5)%MBsr(o@aGPr> zryn= zX_lSya3YJcQOvQ(>s*Rm6~3BY9e)l)>?x$g`B9^X^rR7g70FkTeihkQk$)A%S5bZy zRdY`obqiVwDlsTUb514o6)fONeN-3M-0o4+tA+A*x8|rC%n3Tm7TsQeN+|IO(l(<-U;bYh&YFCfULnc0mJt*T!2X@7l7LeFWW zOe@^d8fNaOXeN_x{I5#JyJH-Aie1_7N1I<PvvN^Z1F-&HL{3qcLQZ zI#?Pv|KZyYavTA}6J7n5q}*9u>D__pG=aPQk;0Mx>0P@&xn--~&a5&x{1x?!;&CPbVX;EfhL_XZA{HVqZgckpO?<_ILNb1G@TwM-}9d zaRTqOA)mJscD&e~cpsr6-AhBmJD+{s-~wMl$SJ08;(nvrXtdDCo6odOVbjM!WM9j8 zQ7qv4zt3H2E0lB<4s;iU$OTE^%$P&Vifa5k2q&wj#GwMUS)=WULd@8%2Pc zljn-c>A{j~D}cWqQu=}1N>OW5QsIYvyIPC?cLwHf9*mB<>fp4QfesUcRLeMoPcIcj z9>iR29SGqY%DR5Sb=88O=2WbB`6fG5w9BwTnSXZ*JXSylE~)iGggt2_w~UUPrI!y^ z{Z*zdW2`b>r^ozkcY4xK@&o)c*_G^h>Dz?Zp_{RfZ2=_vzsiUGMkEi0zA`)Z%-j&1 zQCU0*bk|DuCWk0JG2d%{PLl@Y94^r06B53$=3XyunxHj@FLSaC;G{YZK?qE6M=L${ zFg(#aYG7$EM%k+pcP!){-%%xilakr|Hdb8kzQqtF|2D}M69%Da>1S*vbknfoJ_et7 zm1+gvi~>||oV7(`d63UDnWG#H9j|ZsEpGm*)IZ47-)kF+S*JD3I3qI)QoCM)RwLQP zE^#F23Cp{G>%S59o zlOOcea>)kF7-NtU(c^ub-Kd``N!TYNo$QU?nE=0dvhs2Z+YM`b6?z`>twy8py}ZSA z4HuR6rN&?^t?2HEVLWncl?}y*rw|oTyfzo}-U(d4*pWYv@i!g(q`|#%-C}lsx2&H` z>tZ;ua!|v@f3SWTJ_uW+@>`r+w5@yU5^8ILgP1)GPLOq*P-2jE>t*3FCYUe4Lnge& zY5)_pEdpz;-S(5Zs%PbQ`+9XOc_+&IX(&;AQ~x@`Ykh)_y>xsWM;O4li*60)EZOF_ zOuBWyyNLdDTe0@`?}&zXxP|$iQ?zUwo5Q>x%ivTrwnb#RsD?sv23fi?w_hqjeZw_K zVNrO393k2HKqXeBaewQa(~&XuBNbgQ6FNbO-q4 zfaw8X>Io??{|MLI|dqK)%mlBo9NGroh9u^3SL$h?>?aUD^Kd-5YFj=yB6 zfQQNCAo8;!y)f4^fLw%ui>WUEYuUunLW$q4(Lb2R6u!F4rH+-BwAvxH;bChn1|Gq(0nX5nq<{BfG!@1xX9pv;+eEACcfG;PK|2WgB zjeh;-s2YoDWXk?ImUT)7G(6x0snc$GgfiL$_or*YW!@E2+o;4LF2HH$aegdn)vvX* zE~#Fjo!vd^Df(8KAAYwMPkY7xglhgo2w+*O zu&Ee*KNOdub8dsJ0MBFx>%vPt^QD;zYUeINLPCWo-j!K+<2+VCsfZGtJLQ~JmS4r= z#`%>d5^*v1Qd)sZWd!OLK&zg+~phnbio6AFPC8f)c0Mw7r6L>#%Etm5tdu@nh94h24zQA zVhqOJK{=VL^Sa*K1>0N-NSDbMg*^8t!CvE75Tp^966hzmE`hi0YzfyBiG@O2BjBYY z>g{6CBS;{t?$PLJPTn_2gM_3$hL=rLtCVepiWW28v-6>_nks)v(^5&}{Bqqv)!Ke= zh3a>i2e-5J)Y(HLS>iY4kRmPD4%41OJi?E&qNo@l!*bG<&QXke zqJzIfR6op<3xIp<%VVbV|322F_-zs00hMrwKR6d53oV+YgB~iKgM+DLsI&p4-sxqN+uNX<(5zwjmTlw8<7;XapdE$h@?L&r#d~#V6l9h*dt?N! zokwH^U_bFeb!Ft9^|z-63M9Ki{NW1pSs)L|bXSz28h6Ay`j^tTuN0d{5Qs#C6$fP3p=3x@6Hv%mFwXLHJMiQ2%l9&8-ZD-c9oD$uW>MLmv0=^c`= zDK~i@6g%>)5TZV!`G0_Fs{ad6`OmXbq#%p@fB?P%wJ)!}{D!f646&-y@Fp_%d8P_v z9J7Xgp|*!b6pU<5?MfjRh=#|cZmW^1|D{J~?^%xbMT8)eoA}U%38o z0r4SvW{~`tIqm`b7Qom65b_Jil)?kiZ^U2t%jmg%ubkgY(4H6UiTdwO0QvCV&l~8c zSAcpw#o@*#E4wU367=1vi1ryxTr(EioEc+VWBcIx;C+ZPZ3VhZ*vZ=)c)2Up^Nl0R zZ0@Vx%IO6c{^DQs8$s;*^tzGsa(v3rVNIyDp9TQ|IZ19}a4DlFTq&Oql8~*ZotXc@ zqiB)tkR2uWi;yobGP<_FhxPSi|q8we<-R?NtI|evf3HRUy`TD_=hMc!6Kb%k+X?TehLZ& zDRB%e6$T@?=1D0muDFoZbKg~f9QJJ`gzV#LVw`lcou3c3+JOIs*G{G63{X53m}f;j zx|D3lFak+nQ&$H`&^+SRY^`c6Pv(2FrFOU{ zOMEzI{;Yak80j-l$dP}*OqbALOg{xfCw)(KCRuFLHiOXKza%boDeff}9}33HJN$d* zTV0hTbJZ(-4)}V~Iw0bh4{W=^nTuUZ!vviQ`KxJ~UoY4|OAG}I64r;M4kk$)sma!=qEKpQ}lH9T*b+SaCR+-k(}=q2TkIVW9L#p>u^XrfwWCe5dC zIlrK;#3PPH+vgzLm7ud0&xcDTeUsygUyZ$4i!a7cFet{=kH2ae1m29$tMYXzu8f<1 z-nA(6BoBTkqJ}IE110M6I=#d!hm;HUPP{CKWbDnSUJ#aWiNL52Wkt}WG4Q4sI=57O^?@d48T7t~boqz{LMW-&G{0MDQQK^lt8P{=6L{y{Vp^EZ9->L}C?m z+ZB?~z&NU>(ttyg7qZ{ynd>we2|H}7~w^^(td#LN^jd_dpLnn@)0T;W4Z>_lcocAqDsX~ z9qtZ0YcPjHs5a*SgX%l1(L?7S{Z^^5{uKdSHYo*7&P-NdiYIq@;uaTO3ERw;>Aqab z`p(9Wmdi87*PHs5PIjCvtuY4HQ)SWiX17yCVqF5-Q@$T1vW zz*^sT+%cceDud_(tW5!;@i^Ar9yx={uaId@k!lSc0`$XaPtf_`*6l)RD~cx1TW?9t z#>$;3h4MKdHU0E8xcePW4|G0gk%MpWDBlU}yDT!FR+`z-m1DrKVpr{sm-X!YDD?~7 zIapQ9l_fqZenZKCq?e`I)y^WeiYNRwYF}MB!;B?(W4d=}Q1n*Jgr^da@K7+&Cbvl? z1P-JIuHz9|(xz-9r@~}!9cp(^YZdl+t0D>UKVMUvJe}G&IZ-O7&*>7*{FHx1)9!3x zQJD_@2-mrrd5*e~aWhp<6bbKhOs`ZK)fBIkof8}vdNa66Upeq{8!cb=HK%#-g#TdY zvX_|L5sK?rbH6EXaTG`Xl<7)qw5#-DK}o+jDz7dTwR`sup-XwX?N7R3($76w#Wt@x z3x-b0BucgoC6BJ@6Q0FK*r`O+y0^*F^^u~jV&y{s5ySXmx(HgVOWP-few3OXWq!Zb zLnIzmPDir>jp)y2XJm@aC^a_ua_B$0Mt_eDi=a|+ukrHgpR_V$zbjfD>tP(;7ZrG6 z%#I9K#8S#esqsK}QwB$=^#PEWh40}Orna&;Hh4ga8qJll1{E4+>sf7^uf6^$6%GXZ@BfMBTvoV!{WA5B-m9Tn^}`c zU9jFR)5t-5(^A@ZXia6LUklmn&Mc;3HNt!`i>h?v&GcQ7mO2e!$G}vas8ka=UW|&* z#OmBQE^ADYCYm)vjJfOLErV^McWl&;*#&52+!-<32aUyZeaK^LGe{4ccIJ%Mh0cs#Vz1r5d<9An zG7JBxJxkrx#OWz#tH8nWPZ~9+pqCibi!ZnzS-N!1be~UQq80D5XbGH5WtG7Fq`Fal zjK=dh+lb7`#8YrDyK`=}6q#X*5?Q&iI_#o!IxL5zEKd$o0{G7v(Q4WKS>@!1e)f4r z$-%YX%6yBewPs>&;;&dqdYsds@Vt#B&r+UdQflHajUnfX9#@SZE=jFz;_?lHNiPFk zVFx{tg_6ny*|rasSfGyYEW0rU`F-2N?M>t$NOhS-?RM1(*Pcs)O?zlE z(0&L#=`Wm-93arQNs2$|D2?F#8DUEWs$Y(VnnTq(#jD@?$jlAu&d!as5Oh>m-Sw>WF8vSfkAB}>pQv5Tm`WQL_ z!_54bHV6?2|3=Zx*rSe3=l<0@7o3SH`Kz|8WmEDTWykWC*PedUu|9lM`&al0lAr99 z_Ma>zrSMCYlEN@ajhW)B!bb&Y|NnKPYiN2f=RFMn>mm2rQOFtChmuH!)=aBTi}_M4N}v6H<6JFLV6163ICxuNQWTtd!wj7)k< zHXPzqaVGD#RG*JgE^}^qXUR#F6UO_MS&dE~A%oJuT)iOocSE2+@&M%+`TqI5`^a&} z76S-s)(72KGESS@k-_bmStFzA{k>M*?e%uwtNZ|&CFbPw>HfSm_5^ku>zDEIus5KW zLWQlF`q$D_P_Fya?B(I$YCyPYJnbRp`05cdVb$EU$2~*fv$q(SixK!~;OzQBivIpH zyRZ0D{<8qO0taY{gzl5nZ`TTbh8WjK8COMv#owFVuroB8U}dzi)56H)VoOJm8;7+t z)V3;YqY#&aLyxx^_>Q9>7pXa#5UqBj;`B+FP&>e}?_Ak2-IbDqv6@80fueA@LDeSd zqUwA|e;3Ui1n1~A!ACVpzC=kDC~bBG1c7LL>|d#%vjF=+h_K9~{iI$+p8Hz#Cl@r5 zYA0%?Jb1`9Pe;fDpt!w5_`3d&5>VkbijnNP8(W_fL3-EY^VzHqE(!r08}bq*p%B|+zGhdEy<8}w zg3pe)24G{mDi$hQBN{qLT68e$2|g(%aC8Hr5}ARvUWq`I7XtU#Weg!mrW2GfrouGLu||#n3AVIJ{~vCVDXC*&(Q|pQGF}%tioI@Q8n?vF z+RIu8{%Qg1R$GiI8_9)?x)(#ruK^*4G&`%O|Fwc~NSNWS)FkyBQ zV9qnzZPx4am)Kkv@T9`xuJ6$w?e>*RIB}`j=`Advp2lf;B1K&7Q+Edsq);Q z9K!|FKYJfm+VCIW>o4*?+TBwx*dEKs6o_k`SJ%PT#RpwU+j~(r-SYv1+g0+ zctDzk)wW2)9X9R=)*RoWw0RIiVL*szBVo{BMw~`7ylC9k&4Ox-o-@DVjCVjgN~yDH zrXFty!^e1jIb;}9tj|{C-V;>1{}}aty>+msV#_7Q4U^{sGp%-FmXz8lPQ>O1fHr#7OcLMsi7AGNA- zp?`uB&dGzO?OvxDxD)l&lB98ND^vI} z-?dTToZF$3e&6W1RD?Y=7q08O)=PBon~ zMyDvkYP`l&IcCmd#%I|<^E3kMl)$DLxPmw^iDAlTM;p+nI9|b??Ac+C7fB~sXul9p)+@DaI$)PL6bRxw?*E4hcgnPeco%08u2B%hG3iA#s5ysR}e|EgyK zNrDrCHY7;KR!$uwKL_Y!K`MIGtww5)UTc3j7UN z8XEbGqQspyLA`uY5{4A{e)MRa0J~xHE54mk2)*TvQO%wphY#W=p+ovRL?udf8v9|~ zK)YMUa+B^#M$+J=Ml~;eDmzn2DEXvNh$6T@DxOIRUnboL~68v^LoUx#v9hYitC~ z4;7DezylWO3^KJ7dpV?;pBsdv!Nb=aTYpXL}l6En>Ah=5DEk;sY(c1+Wx+SUQG78eu$E2}9h#=CvFloa{WM;PG zg>U@&ngj5NJG`Svbg%U{Egw!O$@&BfwlB=l@dDVPlDuUZ;LK)XI(1x2{BAA|`og{X zHNP7pBJg(=xn*w*(PmZ$0u=xKHYZnmel@e$;xYmWkJ2N3? zaaVNIQU4ukZ*zsUD7WH6Bc=hW_DIpnFY^=g4}Y!N`sX1{XgXCC(g|$fjezS{-!ff5 z-vboUmPxNTByDrs=;3vKCaLDm3jW;7)m1j1fWQK{RNJ>KAZZR#gF@OC+U2Yx(~MOE zJ|b=j=GPe28jx?9udDiujyYI^|L_XqDuon4+_F=nbg%FZIXf-WR={BYTR47QZ}{3< zqJ!(u*2XD@j1;RUVhtavx_m8I|9Jq%fqnr7-y@?_vnk08)9>rS?3SiQcZ! zSL6J)BZVo5{r<%tooWvz=~9|!Q_6)!rQq!qqv91*ru`SOH65aVf$_Xq6Xt&FN@EMQ zbNPwq4msE8a)^t0KakOx- z1}x5TN*~@r+7wPL`>zZF7rNWrf?}@o@%8Vf(Ppsm0GMQ${Ez=5x5}5lAmtMdBPDR5 z-R^kKjymyx@dj#eb3B+YUHD@{(y2W2;&MVey2FanGr(nc%WV%Kc0M)$Cm9VAor`Q4 zVp52s%`f=r{oW{Y|=TXrfJxP9|Uo=V_&Fpqhp$XbPDQ%Dm8AmrvtAbL&dCs#VyUPFhzEi8W-3WhStDg zz4^9ukJxb#uggE`oRaN-X*^8T2Vf0v5?w+7*o6r9ek}P10W;9Xvzn-gkw#ECIlS1; z{ASnWzd=xu3Fwiip3cBwkZ1XbJk0mj-e&!@_or71Io{o5KkDj|a-|{h z+x|SRk0N9RaQlJ)oe2#F_5g=uLbOH|B6E^7(`A23X~&QXB3gq`N6k3cchQbSS*o{Y@=><_J*HYyhMa9eE3HjuI~Q zU=(j(-*8N8r>fi(&-z(u4n;aC{$yQhk}-5?MCc1kUdkZF27HNSOJ*~rK*g-2$Hc_- zj{MBP3+0LZQTKbOYUdM!yhEd#y}*CsZJda-@n}kzS)(9$JMTD5%pevr@7AT~;Y`MM z@Fpo9Sm<-$e6nd20^NGH3FJ$sE>%@9WEZDex25aNSsh4s^*!xjm-oc!frHE^&P-0R zye1ere4n0>#CUNhY(p8tZy(xDKkDF||D1tNa~71Hc&4$nzE@^hBjmUBBqLrvG8tR+ zCH??)A<(>@cXpV2U0}JLzcrUcU$Cm~TTJH~zfE^z8h~Ps1DsbkK-cAa#r-z6;qs5X z;SEaCn5*Wh);(?Zs>qAW@Bf{f@3;J-&=-i$fbKCsG~{38v>o3bro`K-z9(0E?R)d& zdB%hK9UvG=aL)vxq=?|S1959iJcTihd$_BWA6}eC#N3(SzfG0@fE^){vv4`9nEcCL zNaJe{--Jr=0a%roVvNMQFFBSV+-s!L&y`u$jzyj6fB-JF5e%ZUosryKUEgS8dnT$R z!XreR8cSu7bD+y*_^$$gW5*+unB0fQ%s`Z4-{O{pJ9i9y^(mcGQ&~1O5w(TXS1B-- z&y3>djih~*>w+;7NKdKJKgdKB_3n7w#;+pLoU`2Rff-02#v92~Vaq;95iOF1O)(nM zK@%>gX)e|G#7PsbFB>P;(mWrjyJqB&Ea!3$&7#cB*W&oTvH(58h1Cqx$^7x3?k+=| zkev}n4*cxyO`D$VLsXnWNwP9;O4mH-UYWTFyK?uvgfbl@5%it*Lk;wx4Ub(nb>C8T zz9aRO0V5KKUJ+0(1DH1sbfy_pryYsODO2fUjZWxYw>phDDGcRimNcgYWAe5kT+7?4 z(9rL-^U}8psw3@ECTr7qhc^es z`ASD%cQLkpW`p~qvpzQgMq* zKt?;;Jk{6+nU#rdz1|{R9g*(i-2?|CSL72^0*N@>ka@M@cvy97a643!fqxZRwRR+C zG;y}f@7k*H6yL6#(TXz*a`H$$Cx%xeLZ7{h^}kc%Id8~siD=`k)z}{d12~lC5$?v~ z>q$c1^`YKUd%Co`Sg#thPs}_UC)ecMzywg~g$)tF$=Qf=EzDBvEbp5Www@0^ugFXS zOT}xMtol+=u#DxaOAUNHd8cnYFEwkLS@^p#CH&~8z3HB;{8oBYC_-r<8>&Q--_)kfh;osptYP9TN>PpDJz*mHrxwXc^(cz1c zO~^;?HZ6^iY;J4@_1i~r_%bG!hFr->o-xhB7M*PdYSiEL4oyhHt9ih|8cUaY-oKfm zyvk-^(Nsn7na(GWB}ufq{4Jpbk_<-YS%)dk$S;4lc<;*?t;pUMljam1hI*XT1iJe4 zQ&F;tH5?OgjY=WL5bg|1ve4{*{fNGdi!CXJPc?YW59K%qAVOUO;nFCZwqO z5wopHJhkhwYSGbh2le>(LZIdN^}dScBG~i^n8KkfXXKOruxM6ZJpVgOUq^q`=sl|k zOTpct#s@|VDsI<_$uzfEp$Le@ipb#$BieO{!p0qIW7ms>iwnbRjQ{H82nlCd6&a*NVULD`Tko5UyD880*y)7+pdu7WF(L4 zW{cGKMlXdLjo>aNeWQwZex~vHl?0WL94kFHr>=5Et&mK?sLg_V+HzwoT{{N6AwCau z_{kEowTjn{Te)*j>xiSqJNlbxw+Zw#1%Yz}D@924es@_NK}Cg9doS0pt);-w3a}LLkdaYmls0h9)6alKT$a3IHEIr&VtkA+w6X zn2GA@d2-!O7SS8Rt8KGiQ-=+YV3j5QiQ*Zy^2Q6~!-SHrI&K1aN&WuV>avAQKafph1T&OHSou(GCRul6 z2|^K$;>{7EZ-*d}>7R5Pf_nbCe_PEBZ4AkyBage6RM?08X6RWUHsJuZ1O6dxA=aRq zi$FZeV2WW8Dky41oylC>zr~8i`r}Zni&k$ zQ{mjDU{uVk>r3Dem5x0TOY8@;;CT_#dELH4BbY%XZotU_=@zTAlUFnnj;rg`-rigGf7{6FC+xRp-Uaf& zjp&p@{_K3^)yE3%&{v$$U1FoMu9}|w(8D{O@Aj83A!3%0sQL4= zE=!3W3t4KoSsc+^C;UFk0D5==v3cbMy*gd`a`qtZVsU%uUAUXAr26cw$o_yAAbgyQ z-+u{BmK#O4e-^VnSU$wpj|;F61;U&=fzs!0{+!hp~z zMU3EwzeO%Gh7Z$a5`@un?9*Y>kE&?qMvS6wiI~#w{&z_$YNut}4=K6^tABS5PKk^8 z-X>8XBfg${2CvJWWT#8npa78u`~n}^JFSqvz(>hTFod#@mh3-BAWylOLk_J2rwS=Os^{VY2o5k?A5l4ED=zf?KYf) z4a^#UCb$-w?V62)-xth?0c5Fhe%^NMx49NdCxV$%oRSt{s;A~y)|HoXh?M^D&^i{S+!1zj9UL$!*F%g8^tAEw{H2 z>)K|s2VwYg6-@^ZphtW>6F3N*%bB(x5P&)IzgXF=5pRCx4+$wPBam>sg$i_YH7+JpWmil`lNexT!vEiwY<1BCJuC_Iw3I( zMQ8~<@kgKJurLq>f@o3{PpHFz7N-mnDYpGIx_K-U``c`D9J6S*(1)zC^f?V%htq&RZudHT(;d z8wKzZl>OoN=+j?k3wJBfwNKcJ`}<|-BDiFPM(itg zV^F-3WArIsN~l9t9VhzZD_n>?a`x?gQ)g(C7|Y(ruhgI7l7~-6gBhNT z(Uc`lcyC48g3+4|wNzsksl-Baf{5P?pDHf`zU`JgC+dy~6k^m%h&UiUN+8G^vWyvh z3#i52tYzR$D#*Pt1~SwnY}I!k1f`FoLoV&~C(CGK3IilG<=M;| z)j@s6)xT9!=Fh2FK^szFE~x#1PP9`CNhrno+$cg8bWTdmL^XGfH?Kfi{Kx7%ww|8* zvI=0ZGfyqMbdod@CG+wGMCjDz+Q?aJZ`mlo&@6p+b}^s1 zb%R%0w#tb=%{w*ZYlen?FEYr%l8pUeRknGm;?kDp}LQBUpKoSKV z6B;d((_CY5%#qDMr$mL6+lVo%S=+GTj@T`+xNll$*uto%Irj(8X3>PQb`AnQ^p{W$ zp$x5Cwd@bps<5EjGQvb)J*1=JAnHwO3^NNpuPpq5C|U6IGoVK0+`C=9Oa))~TI+z` zFn-&D1PWq|=$a6%wvc2o)Qjtw6xm60 z_FM%|ggX9-B^%=>DXAyrB3jQy(cFelG#3ZAVHV*|Xr`am#SjiOepj?>A~96z)->$; zRewfOwupIRRzEh!q|rE|nvkVyv&TPK+=^pA*=M-B-N%tEiR`m$q;fG)B#Jn>(B!MT zr*GBQwc?A|q*7?7IzxECPDAnQ0MB%R;~x`O)RV8&X$o8nPKPWq)XQ4G>r_Ac*p$nv zjXEuFuGC!AfbQeK(!tBb@mSP#H6qD zUx|LckSV*ynyUsr&4r~D9z(ic{HkK;%n*! zNWkRL8COc+sxEGA<9mhum~!xkx-B_lKSB`Cp>bskDWYu;Qx=v+9t-&uFRRm-spV`% zGB*B@X>YA&d~@$jn0e&d$c-)irBj91=xxq!OA->E`SzFt(CcvZpMWwYJo*Uv3jVHR z4OyK7bicz=l>@PzsVRBsHKYzKPR?Wia3ZQp_b?x8-?ME!N%y6Hr9bC1A(If;OL2Ol zb4cpQ&~pvMT);?Ap}ooMdW=qz-nZM(occ?4l27T)EBD$Gb+@rzVQ(uecC-D?k!>M3 zh`@NYz6g`#=Ql=8DC`xpEaP^%q< z6Zw{I^Q5A(CN~Xx^W*CwF#$R$o};DQ)|6?}ug13OXoWLq5nXoA!Kei1*N|4Q99gMn zr|rHn#BN|^!tC6XL&&P%>Ttf;H4jklZ<=@%s`&YP>hRSe>(V8~AgU_+66`(oyy~U1q4jey+@@8;Z7WrL$!hE; zR`fAX`qapl*cfLvgg*GgY zupNA3gVwt$PuwDNWK7ZyIaOOxp7C(?_LdiA^R;eln-f-W)-eP4oiI*-bkE5SV@h{# zE&Dp3mM2npiuhqK5y!r0p2mYCkRGn3DLZS0s7F>$c+8x%YM%c=bCf-fy_VEWuU!`| z*TQ}?`r2&L zZ+(vDPQ1BOzA6{A$`UJsv>RFt*Y5EexYO0u5FW_2l)=s>Gw>7O5D`23j@ZrIXq^W& z@1~gy^hWR`Ebo$Eqj^LUYYICFu1xv?_Pqgw0tC~o4V~el?Wd{-T-3h*N>d0bg~BFvjg`W; zrQtL$p@n|ugK&%^Ro8oauCjr810jLux3*6P&v;C%W8qh9I%~6~)|4(2y0Sa>XL-mm zXSM}wsvA`8wR83;MUg1QN6nO@V!9EBU|rPmYBSth3-}2jLg7Gtmj*tKp~xdM>omwd zTjS~lI?Z-T%8%OO*|?sNLSmp+Ot8&Lg_K(Oa$mU;>__-9gFhDAS9U1I-I%L+-!u zekZNHXVo`g%!_Gafft;*HSK_-SN~v2tI?i*?4cxSdFibg+aWZa7rtx+vrmQ%Wx@9gtpIhyKwf0l1`HsN!>|DGin=LlI~FNm9uCs?+@E*wXSIKC z0;X>PjGU9oK3u)w+UBO9>u)ly&jZ8E*K>8jfjk=c{^cez3h3)OvO-wHotlwt0jGzw zP)p;QGdh_{?U@Y|_D}|CNw(2!|-IN=|ZpO*}SBkgLz zNOghYrQzR`2b!<4*`L)ehOI@1x|FLqWI-{FKs;RI!J8iFXi_nIl?t@;QqoHM34HeQ zrR$(i{FCtO*wwF9oAs10`>WO??5sap3)q(Nwf{n12zfZn>KpXMmwz_hcY>bQojL%z zQn@BtU9n9L^nayHGfc4p9S_zo#G6?o=NGu9n%~}4>V4^idO(y>2~g2P>nOz9FB(S^ zRjA9XZiF!;X+zvA2r3a+ht|Wo2O}!6j=6fu#|M4=-{BP9PC@Fq_gsCW7^@{a)R&s}p*%jczo5tR(+u1M=9=;Z5 zvlGs~W3kf(WWCd8-SG!s*OP}b7_p*3CuSHi(pk9Dq*i$!MiEl%$vZIJAiP3)ym6QY z#RJkviWC`*(EDM7KD4#Hvi6Q3&(Azt4xIHOOb8?k{Gd1q3@BCasM=DI0Shps|P@&W1hjKRgMeYBJn;h+E91 z?NwV?BLnZlWj-&v2hGe<}s;F1be1`@t|RJIm51YYb2y95~(R<9!ECgOG~e- zYG4L6{AhcEjwTPDVt!asW5t|MU>vGnoF|6!vYB!T{r+c*b`dslsydW}4#%<--gw0N z9n0(_&)uqgWY%$Hd{||BFP`6K4c{o!-ihvotQ{~K{x)*1OVp!#>TfKb)@ebuX+_jP zVag(~k$xwfuxUyJ|3m0;;hG)XATcKM5%JkOwSP3p4^8$rA({a?mi7!>kdKfytVaNj3K1~|PF6?ad5_c4z0tcSRoidk0yjPhF z<9F}57l{_=FD6}6kIW1M%s16|&abkunyOx- z#x_Evaq}K68Y7AsNL@XO!A2#jv>j=G;Gru65rkfI{(PVXuXjK{tDeu-Dv!ELqnp%K8;MhHD-v_to8VFZgQ`syU!$a9JtnQE16 z9HZ`4f~?>`ZT*>zXjH0$(0){DoD)74tlQ5j8N}}Ws|`U%ysG|x`0TMp9P!s4^wK(4 z2`7sW(ugm#7tXV^LfQ9G2~FMrB>5?M%XJpUL2R(#da6c^JoW$TezRuvHgpmVXbHu{eAvTfRdZv?;)?`H2vF>Q&b$*!fs~ zIHdKMO0}tfGHk(WD}iyVJTFMI)!_$0wPE(_R+z7NJG&-2x`7YL6$_gI{|}@d_cHQmJht?+_I>?2VQgw%Z+<(AW7V#VJ9q!9Vk^R+<`eUe^sKcsn8rM*(#K| zR>rv7*W18BC#(Bx!}M&rb-f%dd4>BJCZ&~70CU5nXcApq^1WypH_|XS-QZf1I%gN< zrm~lm@*vgsZSluuTpD<*WUKd)6Mqc2SCVLg0b>eMZ9zpyZ8~8NusCn zS4vU2tE}81DEgH!Z-%1*GbBe~ADERCZ0~FAIgV%>@M;J2@4>qnh6cPcIS%{4D>-b& z>ds>GL%9mMFNaXW^cP0ejU76fbE7cG@|HAi{+cO{!3Uhb&2Zd@8GP~~c7K5xyc5{x zw{CFpD)7|}@TYFz9@uZksDZspKF6~S`LpTP^@jA(PTwVfC87K85(WY0DO=*eBCodt zt3h0`GW^`Uod!yjJd%ARij2_x*9y3hR_{OCs7Be1oEYlmj9rx%mJFK2qgi~+pwvU@ z+9W=k0cikjk}I+g&_)a1Kz~(TW{~(UjuW5}UI^EiUBwpYzqKM`8MC zW#I@PEe-)HwyiWF46s}qL*mWAWN=i%=SGcWdS~eV0dwq2mq8Xz6SqwkDtkAVL8v|_ zm+ws~1%Egaz2{fx2a?StxB-O(Y*)H~zBM{;jXw2E&t>W`bD7_t;7%Y6IHe93JuR-oyUUe_t0OxSO>x=7CXv@>HS$U?HMB{fGn5$r& zu_c8i6j|y=w!xT`1V0aAOd6D=5@Q}w6@L#C(T!|*CUr!c2R1yb*ZAFie#gVNeRC9e zG4ER>7h<{|d5MFe9!$0jh~@JR64(uNgFpbnf*KDX5HtayGl421g%C>-kV=SxPN>LJ zrHtpSB0Sz>BD!8izA7RgvQoTj#aU9q6=&(GNv^+J&iZwXpKcr*{0KpqWe?^Djeif9 z0);CA+GKvNW%RlU#!Z3pQl>)2z18qPSAa`Z<|Ihq$_SqdfU`8)#x`C&#P-*8J_vO; zBn_xJCtUDBs=y_Y%x3Gu;(>#bM!Qchv&q4(tV`A2S^3i5TZy9+N%vbe&~sx-i$MdG z0g>4dc;okw!yAIfiTi6r9^}27pMM7L6ooK&H1DV_6t#v5g2OvcP%|Gb8;omh2K>x( znR!;OwaUK~)?eymUzL5Z&Y%gSkXDC2CISrM}UGg;SDv2w*O)e`A@EpbWYCy7eA*?-4ll=o88V4S;P z;?b!TutcKgD!C%Y*rTbGDgl@*;AM+~Su#>piAJ-Mb*cu)d1)qBvNjT%6_KhM8ka3u z2Z`)Pyul<3;ldc@#n{t6Ly^18S~oup-f4&y#_&#oSe+|!C7_>YGQC#Y6rr=(gzGVq zmAk(@&Ij@9e$RdUz<&mpd9>!0;C ztf1KMt81mxSjej`{I!^suB7OyN~Y%{Dz*~wSyj;({je}uSmhN5Pu~{bwpU~@bU{Og zf3_k+p*xcoWPdEA9+}=zbtO!IzMLy?R#9JyEr9RA8n17`!Bb^C6yzh`$+z{HZyNE@ z#ZS$d@U1s#%>cq!!b?^vXkr-Qf!8$JB0uttr}8jP;;)5lu@TpmWgcAw3WbbGK8Qe} zG*R5{>Ou7q6gn9=w0cMZ5ge9p%C+<#6{Q8gKX5iP3d)1SM;pX(>6K|FG#A6}C|?V}1ijR7zb~0^Q%ve@t2~!v~=yp`PX>`WPcS<$TD-&nY4o?n0^2o#GprN2bEyB z#&apbe40B~JO%CrmpXaxU0#?iH?s4kj~#gSzIOvoiFnXKOGVK_qj}m4|K=urS(kuV zc=C7fGSnB)Ri&e4*@#|0la*JQUT>4dxB7J{rZ1DeU9DNKRX9d_H$M&DAvo$o)~#}| zM1P3c68vlQ>SBUw10b{79I;yec6fsW%mx5d{*G8CIStzmI%)E7_x*R zqAFqhP+MI3k!>)>gF`-sF|G-eqR9`v#ibwU27xU2=3@wCihvY9!WNf)92@-5;6jh_ zTc{*p;s0!lOFtz0P%|66;vuTQED$NwUw^;FrT;A(=$YUH4;iS;2qLw9W)SYkAoLT| zAYOSVc*qtPra4i}Jh!+U-{R6uM}uV(LCMnUM z>~Dc;shC*p3|Z|kFu`PgwgKW&ZGg~gX~Q-^oOf0xAKc&4&p?A&5xny;Dvh1jz<-`9 zeUD0a6VxD{2e*F=@!Sw?`2T1FME|QaAaZ-E#h}FljA>%Hc<2s@bF~jl?Cn=LyaPg2 z^RIfy4hUWK@w6%N80X#GG&rXr$QZH(f>A|`f*ZF$oT}|}uuQDqxCLTwJH@SAAmonm zJKw-$H{$zD+7LAiQC=&FrSfUl?oP04-Sq6UZbA?-gmnYN&X>t{ZGTw!mif@f>!aOo zxeuP(k30rCEr>PdsW5jaOeZ;w|4pKaX6&AYo3~0hwp10RO2!|t=V5vNFZSUAm$Bhd z6NfWbDz`INE5geOpjS7$iu_pbqL=?7EEj)oaC`@j7mXe)05cMX_wU2cKX5J#zFzR9 zIF}M%7QZ|E)Td_&4o3jq1vouh1#!F-_yYWXq2Fm-cv_El#W_%r{)b4JPyJ%FmP|Q6{OkJ@-B1#kbYcKum=$iX5 z_ou)2WHU34&oE7I`0cN6LwDtC#M4>ClN+OTgC}qVSq;W`Ch69Qr}CU@L_oJILn<&! zMc_hkqdF=aF;|EWzn-2AC)^e8iMqxY-q8rDHsf`E8F}qk(Bf*GWMKVdHN*+_t;B2Q zm7Gv;L;+v)$>VSQqEITdjq`t5U!Q+ACxRd@a{`@qOybTafmRJ{I{gy#%S50QA(Gw# zP|XztDswTwJhu}rya6STw)i}le)RI22z?7MSe>+nY4J*_-;I|R< z%%iF62&&@*rNbc9?h}dZA@3;?!Z?Pnog!fkv$mhEGSLu;5TJiRLnMF4;9J{$Vv#dCkWuG3r&D3)Rzk?7{ug^Y-pPq`Kj8ZoS|tR!AZbvq7{FuX(r zQreU-y_8I5BPmO|ID@TxIphPRkW5=WLF76KRd1q7!LOX40CHAhq(UX~lU*sXKqy5} zVZ)9EizJyT+2oh|B+an|ptWb#m_FrIcCEOPcW%90qXik6T&{nS=aY7U2bEoHG~7Y* zA-+V=v{;l0nsW)|2$9POQ9nsX^d-@$M}#B`f2Ra2C*qK3hbM@}OPY&IX#h#+YsZOZ z;B(UUdO_K*WA;dqI}mp{pp{mJ)c*3dc}knJx{VN zRLC-Zm8ay64CQ|kONOpRSJXcB)8|z_fD-2Pgb~myJ~=N(5^c7YvR@zRO5DYu zA9)AQ^?nx1UF0L#V;%RmNa9o;YOfHjR^n63V=0-9_jsg!t;$4~LJ4AAb8E3sVQOM= ztGi+$MsK9V8@0l1FFDo zjpmSV{0o^p70+&!hJw&Q<8O*e%P9feTMrz-z}@Bs~(6jKD}L)R2+^paKWuBdjl zcl9BNQqg~yBpq{ADslOkyjzcu`9_=fIl!r`OD4VRDejQ;`YVx?>^y(&xoVs6<33PgvPI>q13qwve^XpA zS#tgWgRC@w$Iqx8T&>7>SIUbVq{j*SVu@@CP?I0IrIZ#E+K%cpz1wdaq+lRSPf^Iy z?W*Ux;Pbkt17;>xH?kmA{v+yjN(1t5UnR!${N0 zWwL+K5L0&BazE95&Q<#a_zBhLtf-@yGX!+f8+MLyuam4N5@oYp;OFrBjQS{&enm8Y z{)G>};>{m%Fxl?^hN0gxA3pps{DYKfgD}n}5SA#3dW|q2&@?$8$rch?`cRI#nZ(YS zp+tMI>tsvxS8d7a^w`|rw{wSQynzH}QC!^{2r3AnU*QneY8 zfVq-D&Zp+ZD?wMpP*i7~E@Ko;MPqT@2kvncHqf;Wg9q^-bR94Sbqbe7F;);&to>9y zhtz-JxzA8Vs`1LKrLH2>Eiex+dIL;jG18R}0+UV@=u%D7%Yhl!J8?KX-whn}=wk2f zneI(D&sS;8#Pnl4lTa>HLnod|m@a>OzQoUbOsz38i!pDa7b4qLb59*UP*tG2B_D@z z*}z+l&iXNWA}!Na)h*Ig=uEkQx^9_oX`r>=!jETE!^u(;&!OtEE=1Q;jbp4)jVZab zJ7GQy#|F$|3&Sy2BaVB!@q5$F^R=ESFCOE@!3kC!RxN@3xtxQe|5+) zw4n!sipl+n>v2G~fYwYa^^pSG%_R2K6p5@{5A2p|ihc1i$b@zSLg+2#5;NTj5RMtE z*Gm#vFSdFgR2LSuI?a5NI^>SAlW$AquJ40H8B9t2Id?v$y^u+Lx*iByon4q~H>m2D z3M?#mVROVzR6AIw2DTpMBUt2VTyyix;{PF9W(z&|bUd>i+#gq1=oisZW1fx8k>mCe z#Fo$oi0$AbTNnR}(-FF^9bxX4dWT(#|1@X`FYeN~rS0JMzYZHswf+-T?tdEky=|AF zMHUl>_be>8_be?bo|nYwJSTr!J#+N94etFbR3?QP0tEOmD>Fw+3FQ0}wr#yqh?(4S>)Hxs`l4RT zUKyEGZY5o$eo6Wx(II`xjnCyb$tg0fylFn-$odh*scXgYPl07}M_>_5+#)6<5E^c! z_j7JEO;KF=lX{ul>3dm5o{h}fx4i)E?qP;{Bk_G%M;27ju5EuE(H8~ZMBG?K&R4{3 zLA}1QYs3^35VcZojkq8-ZB2TAzXhqOBz-xKy|oJL3?F@CCXU2NVTR`W{+W2Az=f^- z2JxESpR7d$j6P|b5)qt2;1iUH$jae-@#w=!L_-SAOo_n9B@!x$I2+Z23<~*d?Ko77 zxK%yQD(Bo8>hXUPehi#wW9Wlo+KOfHO4H0Rc)y7mZ58tj68*8*uaTfFzJAuP-QO=7 z#csA7K*Av&U*krk88dSMP1vceB@}X)JIW?F6cQm8$q;I*5{lOu%1jcFP@l8e$V8}q zyGb>kt%gh|VmI&+?_kto$n9+ZzIl(c9GS;)(osFdWRPA9oZ}XsKo;_!NAH7TJL!c=T^6~;J*bNI2M|Ib0&vRnM6hAkj zdl-d(6?7da2lheeI!X03jj48Bj5cQ`m&75?hzKZ7I zS+AgJg{!c85So@`@I$SbZ!U>huuXtlqJ^D zB@gzGL-#NWE9mN;IXnhk9mIE3c+Gkdra&Hw60$<%iJvOqLM$o|M{L4 z2|;-Wtrmy;=YD^tw}wfFzuxbVjH219sRe?a2hh-oW%uQmNnu~OrLp(VpKUl>h7uSJ zkJ$A7T_y3tMvSnPq?h-6@*Y%w(|Uo!96hhpNWQTrT6PJW*2Bi}clTpZg19Hss*Pk# zU^uoNgG>tVC&kCMW8&Es9qf04#%>WCM@Dhq(LIJ=VYJg>doOa~5YmyNc1PHaGWp0B zKKjHltyUb`Kz!S!TF2&k;PDx*ActZO&Oe56p+QA#4X+c*JblwP=?dI^@&NVFz@F zr?>_kD>U#eZ?ad!Mh6r(m3T6=heds|v0>CL}raXc(W;~)`KI3%Bn7!rig{tL3aDUy1 z*Wr1s;RV7hzvWJLO4#T?qv2aPt$KC8;3SbHjE;R?UO827V)aGO>NvxlSGU2p#Imr_ zVO+bR-Vf#WWy2x8SKF3jx5J_B{G?QusBBaAQm(_H@4AQVXFbvdgnJQWRyR#WKb+tMo3U@~ES_SLD&mr>L$I0H}plb1nV2NQ>%)GfE4)GmrN zmqx!mD1Tf{kK?!zz4xzBZdoA1Ws$`%pkbifGaX=WN&2?fQFss0b;q})6=mMwz!0Dt`g8^V# z!tnZa`1z4@q3QKZFXUWGdKr3e>8MVhBv>i|bbl4#^vNKk@>0+X=>6G$&gDXF6|ah? zU_rXaWSP^;mo&how@G&a>5r#hUVnPvsrj5a?ce&t^3#{shuw~|5 z5}34N(3~0S{U84xetr1c(&~6Gq3E3A@!uc5!0gQ56Py+ZPOi05GdO`0#yDv0nDmz- zoPV4;skwNJKq5hh)}Qgvq2pW;IEp}`Kf2=I=kh|vt4NpdbG(WKw(@oeXyxKL{v2zE zvL=;#p%X9pJ|1i&(A9H3>+O3x{Jel$8|o{_0T@pZ%+3%5tNtp>BmtS-r>fPnyN(u> zBujQ_@o@iwZH9i-^1slN*_omzf?H;|UVq*faDmMMi(r@lwd%>|i~SZtF(Xz;Ds#Li z5}A-A=TJwd@J&R5vT%RNEOoLeE8ylmw;Xc$T}_SZ*(EIfs$WAY-78@_Pm4pK8T zHs3*}8cH{z3xYU?SY%<9sIWPPq+lTQ(xS*HEZVw?7sIrY%h~}ms)Zue77?S&7k>da zks=0)&-ps0`sY(1DHW@4Qq2|k$*~o_m$?Rl8Nyo_Lj+>}#nIQ(! zcH1nusZ&e4n^QcHB9PQ(QcTknA9M=^5|Bdx`3Sgl&cCN%0@6O9i*wgrPsw+tj?Fw| zgsi!5dzdLEjk{?ykD91-U@{BaX0JK$GEyo8v7$K-!OUij=gg~F+)mo<1b^l+kwGGX zz@V8hd>Qbyd?|dIYq!asD%4>*lP!8Kejd;2L_(PE^)l(k)Uv0jC_^h`vYK-0X`+j6=>DiiNAhd6StObtKBiAfa`)g|GJNoM9cfrp<)VBxVRO=~3D z!X+?Bvx()hji%9hSl#_;8h z#TFiLZ@-x(LX_VrLES~k1WgNBQQXa^PGjR{a^n`C3MR*vWmI%3y6~ewadyhp$2qoa zaq{+bNfb~96Q-EKbAL+ul!Z-z^T!t?mt@WuWtRhOD6c8u{qtXbNLBE16-`ySa|x`Ha4-j+hxWA%}Qo0YaC_9_5j@seCdLa z??Q~yIVQEaK#V!dR_7c=Wkd&^kh01#OSknT+1#fcs7%y6T{%)(%W%r93Xc4S8cQ0( zP<@9IYsvj-iCNy8ucz(U%4$VcL)+2h1?H~go?<}isHd!Oka=!!`|WVjQ787H9<3QV zxDZBNk;LwC{$<+m2`xvyCp4CyZsbc;f7>)M|UDcED0mPAP_Ga7q@Tr?TW3NLw(xuyYEh)5Xh** zAHwTCmr)Qe7%ks&#jw49+qi*^@~AIya>0O`>XpN{mSf<60oso(z<09+SdK^?Da~pe zB&8ddmJlx{3N3a9GYO23;J)XV#t<(kfB$K-Fh|Zb^WD5zn3-jK(zA85uzk>XoJmGq z+{c-uW>Vp|Te$nazQ-Y+Mj02(@@W}ioO^Wo#REHOvnF?H9`+q~5;0Ba<4!`6CH2+| zUhRF_!3v_>?SmB{L#g{Nbcv_QTbEub%@`kJ+LDW_*2S*)z0Q|+_B=qfrfMGWe;r5S zF^%ZsNL(^B=36eDwD)ftHyhH3E~tecU9ca|S=E1sam5j*`~y>E9(J$qz_t$kwnG`8 zen20OvcQyb{np>Yo&e4l^UI%q+3+a1|94NDk=!029g~|b17tYU^(#4;rae>c0gdE| z@z){Jr(-LlyVy2^u=+)V#qodj11`MUm!U-#6PE%KFBX^4q&+8p)mk}k>^2bY{VS9% z0b+(Tya8i@^}c5V>5{k$Qsrv$io7O&Kf{}%w5!9~7o?C^rl{d?j&BZ%4}T7Pczt+& zd-(1}$iXnHz~J!q#{l$z(_i2;sMTNqm=-X+eHwm#;v6+y&vZ%7g`msOy`^7udK6%3 z2GCQ0)1#4)<_n~M3+Vph|IhQn+bTZAbD$vHQ=-i2@-q!^;c3z;K!adUzr20_z!UpG zztH@Ce0%u&q2GYA$eeM*ub&?L11W$Bi-R+amKZ+&KK$|UL!po)^dpUO+Tm;U}G z&V)*nCkRw0om8PLQPO)<;ne_MJZn`V zb$XiLGD$suGO8$yo13a}iDrH~t>x!Pm!98Hx?h#Zl-2yb;3v=AXc=f2g|y^3kv8dd zmr1U)j@?>Zuns91NOvdekcLTNR$E87MJ}JB*ozuWl3y_g%rh=Q-RmT{d#4K$L}V!N zHeCef!1i=ENK$Afjol{6c-uMws%W9O)|LERmmCy-s^f$?>HQHc7n~s&wu+=jQ?Dph zeT>TlxWwux;Cx^UB>79wa*>NbrqBzYe2yq@POxw#EU27h&`kmFy;^AL~GG_of$w$%zP=#(jjz z1tU@H0lTfK9&XMn;82*^f-wP-T9}!pB3t3$R8rk7smN~K-?k}bV_JU~n^F#$mSV=H z{vXxBe&H+$T{EHe0@^ZXGub)THj-H4ELWv}n!)XQC|9byBiz@jD~fof1mmt0@xEx6 z&t6rhM+v^b4yu(IA^d1bLT!4QW3VlpSzC_HG;*ivE~1g4vR+(FdZ`N~hRjkhLd%&Fw%<&l zW)2e@IvV79No<&_5KN-6jhS4c2?<_*VY?PRF?_=6tqbRvqV%}m`pN_(v>#wx2W87Z z!H}2mhN>ncf#sC&M>xx|E_5DsvHg^|?pNmLg|{rTM)q%24-C?r zDOWD}Lvu2gsfq4=c_@V%$)MN%dW$QFmUmSGl7A9^?s77# zx)s$3Rp)y-v$pJO7Fl~8wn4OnzyeG};KLABc)K+H+7sPgYhdWLeU+$VGc}doBt&w@ z0_x}5R~fSrLHoSkY^0=Acp~PoUL)Fc2%&UcH>?*ch5Yo`Ku5_P0pp??W@R#pRO?a( zjg&IzezgPOSUN!^QaPc(=Z;^0SNZntidH;LoTs=M)$chzjz&k_1BmdLMsezj=}9jC zE>VkUMnDnk%ry5v_wvxGQ1)^;4mxY{veE}A32~(Ij-e7Sp$I{Z#C;_lHw)=_QekU6 zSZM0$hJ!L1yqi_itl?Rzh-#+O1bGZ#ee1L(+4G~Y;gInqZYxzZH-ox=(aceeJzjh% z6CjhIYQ1|&jW`YB^TLlI{oGk;3@&*j?MRk$r846ZFsh|eY1YtqT-FIpIni%S)!aJ> zJ?AxeEk3TZVjGc4Cl+#nW1;z)|tEkld&P4T91z z=(buqv`&X62mQQu|IHqM#!JCj?DMo|@jg9KGM~kFMAvk|cz9nb%Zya}jglrl*ZHM@ ze3?I$ND`2IsDFYbjYfWaEkYo3^n2>qOhLAGck*Pzkg&U(ech(Evm*)E*7Kt%jhM2t zt^u)`H40qD$+fIeUgcYLJ#Rto-OUVt>OhFZzMPGsCMGzOdEO?!~l#ZildR1qCf_ydx|J(rqJ@*DG-!lnh>{p zJIG8&hs}9JsFbrKo8-);xsv{Ojk0w)320l`3*w)LpjDq63IDkfPChrHD%JpO{oE*l zCKpU9+|w(*-5w`@`7qS-J?-($B-U{z{DA;J{ItYFn4mfgLk=_VOd01z(-GIBl78_x zV?XyxQqh#pzw0<-Gl_L3>d69pspAacyWnzqoN*Zy?=AY;7{X)u-z0=h8(@qsEtTBr zmml{hJ_5`4IV~&zh2Z)X;_l3cjFm}j>Wmq%#HmR97^v-k;Y0hgE9_TAJ`e6jQrLjK zJl+qfkqSG7_DH1mJ$VX6$0M~*h^!Xx@%+ssR&wU!9hdh(YV@$;%C{2X6JY;2fKJz? z`Mpd(6JEmU{k$*8gsOiB>RsB}N@Asf5?ON_{tv`yUtv&gkUjo9-vLaZEV^3WHD8V7 zK1MnwiO?K>Px4w&uRy&Iq%9_(cs_QbzX;s`}ejaGr<(R ztH#(&Vx|3>*d6~eSV%f!DC)Po2@E5gnfCBvoWX8C$Wtq76o?F?AfBOz-P&42+y|E4 zZiO^=0!u0;n8q4AMD59B#&hXE`o?fYkB%mtb53m|(4fqf^j&8P3NgNo64)G;_KUHjY583aY-PK`sW;tZB z>SM83^)<(K|L$z}!^6if58pizcfmvl0lP21cOYL_`3qJWz3T#i@dVwMuiY;ntVJ)c zkMd$`iR2aJbCh>?c~20f2gtVom-m68^e2=T$mgqn{y+4~qh0?kK4uA&J`~ATUfMH& zC6y_&fHcDO^4pgmA8b*7s;l?WgusKY^muVP6Gxph=qHiQPu4oo%Hg1i1MO2@VQdX` zAN?-(OWGw}RE zl6)0^qP)j!^P9iEEkk0LO!DZt9fHPLmLc9C`+mqzZ?|UwLpBMr)>vC+`J)U8aZNG6 z&<^Oa7-9&xo#p#71pVR=NG8(Mu^7tI zEN>k`K_JXV!KdDNWft{cefweZ-{&t6|DAh(H8}$ox_^9q&@Y%|Ng{S2ppftW{8#t; z!{4S-%LcK=2WbQ9K-QxBQ#&**KbIH~K@73py9Q$bE7l2MEK`O!#sE6(*NeN=1>+q} zrCRZO5s;;FD7#Vis(re=_g42>o+tLbw713`TOxvC5kCIOhBhrf-{waI!#>Tdvie$o z)EG(k8qP*M-E7U;a*qL)D8rAX-3{2B*EJ?HUjTqcP2FcQ(&?XJm7A7YU?LOJd`XuB zE2d~9{|2zk>$a6UN&xovSEJ}u-B~R%|vhBZR^HrQ97%Co0BNa-0J3rSmzdXb4g-dY<2rp)?wQspUgzN z5rdV$WurvV4nOp+`vYUDX*QV1rnzZex zsJ`ua#iW&8B%z1HS>=elqyQ6t8CTWVBWcT7-JCXtR=2RZuH?yhzq+hz zAxj1!wxeLPv|)>qYR{94?Q@kizqLA1lF`t{g=ORztwDfhh?bh4N{J|CA$};SvG3E= zk}XZsdgmplN~3_G^3!}$E8oaxs>iEyz~{TR_peEf?hwTszR>o z;YdRT%;lRQ!@U-ruIDuF83K>|p=Sjg4C9*$x^F2GvsP(7hbaka>L4J+mhGmbVd zos^yLJz!;r;?T<(EUM;z-rzVG;IM|RRrRWtmO=I?WoBEwCUDbkuq&@Wxx(t?9-*H7 zd6weyEnQrD3i(hN0`9f9GfRK0s>xDG=6%)kPX|#crQvK|&^j`V(FRK;J+gM$3iY5* z)y@b-qtq~3qElau*Q{5?rWJeK$I3o^|1?O6Gp4Mtbl^)wa&#GgonugBBa!Z*4-obU+LP|{(oG?AN-p&N%nK|Vc5VgsQYV^76276u~C;5$= z>0>`F>*J%5*R*$jFfi(%nNYS*uwltz2Ucn_TNTV}9oO8Rz-i-5%JcOjB;%w+ zok`A#PRrcwugI$YQYjG4Fb6(8!>y3ea-3!om)D$_rDzX-)86`^=MGX6{0>DTHA-q{JwlPNL6p@8Hcn2Sw(450+HI6d8e3iWc}eNb3}^WU zi_{~;XQDKJ1WXJGIP9~b`OG*4qq3nv&%PSQJvKD-(X-a|-8LeG(wO2IM3j&SQ~yQ5 zN#+I*!BYa-E`G%}){uD$5$#RcODaToQ&p|9qsLQ-FiF%+r+kDpgu027Na7(!Xk?UZ z3^7Rb*u=!4H#TpZGnhDCK0U%}OtxtrM{F3TUh;N-Dcfh+$|?9$5vm??FhbQs0G(ug zmYi%=84))zgX9c>ZzSwv1}Pcjp6d~v4m~)rG7+~E9SKluBp*G2qS$N#z!?-}*S{SzpXAMxGTk8~zBs(LgLC0|{vu^4xc&21Yj zL_k<#8tyN}HM2(1bW(~_%&FvNDSn{LCP`X<<#4I#zbzwj;k0%&Vn}26>;IV+`jEz_ z=1K=wJV+r~*RF7A?w_VYdj44*WSO1N{Lsi3fpz|1;E;{cj6 zA8*9=i1k3CVM_&!6qf4=-FEgHHTASpNr1dV^}gtBfSfNfO|SPvDRPq=+-(qXtLtKa zo-fMh1rN4K7T>GPUw*UQKjq6GrL%G}|I1y!j`P^=Ki%KepLYa{Hd(Nfyd`c4ww=U9 zagJW>O@yPAtM=0(j%g-2eIBzZR@@`Gsoc#y3kD?uD&v5+2xyg3x61a>;=_sI!V)z7 z@>NJ*+~sCU;}io(_gk}rQk06BUQFzNsP4;(9kmTowFh{mH4T08zr3blxP)1v!qIiR zTjL!hJQ_*WUm6L?S|#5=@63%vbrmCCf}B2F>pgm8!{hDYBTK&AIQu|B?Sgf;Q9EEc zFj9=X5?GEidr?2P9S%!7d4kg%GtDi=xqA)R-P{nX8`jsJ-B!*SpAMpXHwrs{=&~dh ziC+m_&2vjVJTUt8;~5_L_Q4@j!9G758?dXNE|r#*r^sWDxQFK5R_~xGB>|FqB{WIW zARO~)b)B08Ri84!`$MlY?}uXt=BTN_>wqi;jgR9M1Pt}Xial^S z=DPvk2;4hC*nu|miNouFt2ZHUqyind%~1fK-TAt_7ffTD(B+?W$tzWVKgCLYV8}#^ zEo}!Azx$!sf!O!i!|Oooy$O5ndkA-2!F`$muEOr_g#B)Kc3^jXn(@+S_e;wi^<^;5 z^Xr`5nHqDrP*y$;*Ary*KCc&4RXuUA=)B*a9h|67LtbY)QFHZpPNa-`swPHblezfY zF0*kq%_tv|ng>u>d2_9chGGIa!X{p2v@1N|4+@WmoFYDVE0 zjc()Z!RUA|Up?sTaSoH9?Hccsc@yL)%@sW4x?_HJ+q}{KajoGM4oqK^=D%3PM&o6% z*4nFhqsje0i>1$Nm!U-#6Ss$4FBK)11+Y&h54Bs(j^j8EzUL|Y0;Lf}m(hVQ8-J-^ z%d+FxNu>an6Ir6kPZUW}j2ylVa(Fu&-w!{%A`MnJ4OR{BUkBg^lK+F`MxzG{APmCr z{$u#{V7^koaI z0|r(aqxA$>@WL9!#J#}qC;^KMtY(0S!P1`Z?&-nE0EuQuh#_O-a;xH2$$#K!6I%G< zyF5KTfRiR*_)NM0@R1%D(F1$ejr)(0m%ShR$2TkBRrP~P8 z)#6-&NeU&^I$b5aD`b~g+ezXQXW1PvS-DQOxCq%1?%l)&KdHSDUe&b`{2Lw9Y$m@L zXA(PePQm_!9ya%&uu5LixT*tXgfH}BZ(qhI4H@4Q`9}ft2R90sC(}UEH;|rUpuN>76eb9ra@a02sO-@La_t`Uup@2>>1@`K}95Aqmx{a zeNT+RL$x?4DLi>n(EzyXjUNH81Mm7}Z=|qRtsB4Kgt$$IfBfn1Z$sDeYf)>vW+2H};j4XQ z2y0j{v5hgPnrxlUt{3tgH}!X%*wmh>~WvqDQWD zjv;LpTW=RrTVdENbQJMZ;ycJFUu(qm(nvvp-SRI=F=_erZPXIadt~SOcQ8a!LAQ@h zBa|dT+_RVSm^hnrMe=5B6*@uusC#ErB^8&+7CaSiT(qPamD}fD84|o3ol~C8^_ICg z%fDsYZf7VI*MG3%4V9t;4vc1VSxiko^G*xCW-|}Ba)Gk?f? zA5?JX`9)MhI{Lu*Mc%6+x{dRT9L;HucbH!c23x8n{K#*cTLa0P?Y25Q(DGXNnI(j) z(WhW3<%}ZWBKpLkmN9c1a=Z1cewbK3p5H>*)!=25H-9Qr6x%vmlYeEqqG3z|*4#<< zQo+r~El-;$bjz-Pm+xYE2z!o{T=!cY|JOzh^F8cd{;NHmas+4muJd9Je`F;n|LG&P zh{^)L!_GF!N(rPZ_lU?Lv;FuTB04KH+?2f8O=2Tw?54HG`)m=>df{laC8xAaj7f!( z4VL5D4u5&KWE0U((-Fz9^7Sd5hD2RHHEktcZS%~Z(g{eS%y0JT)MK=~OHadsNj*Z+ zPc`eQ}M82x$@~Wz_C~5bt}u!WD$f3V%X+Cqh?CaseSiVXV0mLc}qGp%sMe z3PQ9Kp{pgifDnhf7VMo6;>eec%LE}kLCAgJD!W>e3kWF?R=YbPq%<>cCJ33$2<_FO zt0lRBPzXxzgb#3_A<-Z4aRni}6QQdmxqy&O&iFnEIgV<_qqB&R-;B^sPk+56mk=W1k#5?W~o z>lMh__1I?D*$5kO$Kj+kxO6rWlC%MjvJGD=peV<|*z5 ztKnBDVqN{7zFR54DnEem5;@+oiuc|@m&>@?@MSoVvI0=MruBPh^@1EJ)eMf9+t4x7 zA6qI1fnaSdulwFM7N*8GM2RXF;ai}R$A+&wzKjZA!_|H-U3t`>!{O_2_*~KS$bWx) zH&&V@FhLO5kVycIKytqx0j*6w=(cqQ4R2)tVY#&tv^FYXoQZiJCoH=T94hH5Y-wo( zE=^3UP$*61-nX9tpp!L0l8kYP>Gj-S8$$m6D2m_p|P6bjO2cu>G1 zQKVJY+|qeu?p}JAqoL;~)Q?SR6O<%1-=BZuis~13yTUr6%);lPVKK@2Fbey5Ge7{m zQP&#)>a$)WFziW1Sm6bjGY7S~J9re%>sd`pt}h`a)5%Y)RB2i$e2O{bVzNxhVb&*0 z6?l`J%Tl#i9X+0DL}x*{HICfF4izygG^`Pc6IAZdAxdWiARfCTFBF=d~=2@6TiLZkhU;Y#(vK5t~{~)o@c(+$dj)V%r3~(jg9(BKS0i8dDN}*4iE<6m`fZ zrj1}AbBm)ik?U#6+NC%LF2p&rWIu1t(P7Wg1mRkE7j<;XkDQ}e7krl5bJX3ybWmb|mR1wcxX3js-u|So|eFH2Rd}hyFcGyXAQCVGI~I6!`GQRFHR# zL#_4`H9cl4Wg8b8z|y)b$y4dqE;v)p$y~D}?8G(mDD2CJm@440Xe1)HjWsCQlG|dUO9_S&@AYt3Iwf9j8K6IveFj z*rVN}PNBO(#E-?{kV{OF5yu%&Fa&$b>E0q;Z?|fbxy$#JmFS1QtL#^^?7ZS~aQq!1EjlF@Ga_+idmQ068 zThdye7wli>^p6gmj{&qf~S8s9-)XW zU_K#yrpgD1cow_9IAbD9kuw58n)r)Ob9Mdf^o3_icuK)i$K6r|Qn$1}LjU=AkEzkmJuMiZkwSK3GdG>|J# zO#(G(fszz(MZsJW=8_-&Dtv&Z@}ppG6yc%`%^O#nUP)4mk0&f`pk; zk(!*(-x#jW)Le%3;S;v3DbB=qtV5parxGPm%P#1{pa+^0YB}mbvqEMnc{04~*Ky5v zFHxS-;IpX3Sw`Vk;6g@D%9tQ68Tby=MK19r~!O2;K9);iQWBvDce8|Jg{eYYelFnR)i|Em+% z%l>wkKJyiqF_c58sM_mvkFS3NSF6HC>9e!RXVcC6nwWvSB%5T$5aaB^F3P2}qU7iL z?m<;N@7!ZKzMc)7bW9;$V=r10E6N*G3vI4sGhMT$N~Y_rf8QCgw9Q(|R(<-84yyO} zVkgjt0oedr#l+$@Kr2P8t#L+wG{f-|eAVGSYvkN&;ka$Hyg3u1fJgwV{Xz8j;x|B* zF_m}?s8SMFoexx1mqe9AJ!KF4FsgKa+&sSG4J1X(7+!;<5X4oDdsc6?+}dMRlDQVD zy;gj9IU6u>L$uY8G==Uav9AZ_$;#Ua)mk5{Z?^4tN#02!OMUP6(}L(`E=l>T-9>s` zYIn2LDCei9$&IaVUEUndZ}J{{t#)|N*sSe@wy)XR;oWC^O+&Xv9@l5@c+0tasTbeB zkDOH}C6H?V*6%=3T&d0PVkZt(9Z>UbwMKcAZOrcc5&j1o`#%}0A19Xq%P$nS880w9 zRhRK&6)CrUgfP_u45rZe{CM^GMS7GS)0bd~Fs6Ser#`-4W=gZ!ymyJIo_!B@?H%{r zb#EdEGR7XBc)j6QiI^6$5KFzy6=5dab!C~oMc1)XbNs~5SYxA#W|JvYgHo;9&pr6{ zSzYNFm%8B6Llwv5z+CS}9zwFmQ9X1p0(?!26FSiKs?UtcCDY9t&M7dJjzsmMFRHFC z3w3{WK1aDw&Awt2H%<2%NjJ#qM6YdHrBBdm$NU_zj#SLXYkf9qjm&`Z_yQ@$H`CszKNYOl(K*y*-k9m z&cJPBzv@SG1Fu~cda7=ucvCqDW9HH}^yU^o5VQz50Can~6mL>hH7xg3we1C$)c~PsN|N5XUL*avhSYL#0Lz*CD4|(1QH=7Y zHw0sabbdkk%%QMs&jy>)Lb`k%eyyIa0?I>O(BtW<==dos<-=72)jgR$C8h=^aO5*u z0IA7*@v|;(Caiflj`w*{NM!5RAHPq-oxgu=>#|lTf@heS6{+R8JlfIwWR!oy=+sy^ z)eX4Cs;r}gyr#RW8DG3|gHIw;T-iCUTYT2hQV4M+B(HFGr(a>=g6dIH{b~ey?j33a z$*r#(QBX}W5GmS(uznB#i@^H*P{@fQ`oh3VseYS7y^ertZLp;izen=X>$tGQMb6eQ zBbrol#jk?&><&>Rt#)f#ttEd5E%i7<@sQl2?Pt4YAJNTeP$Q*l`i9Z;d615s^oV)( z8}}QChIE{AMs!4}X$k2erPA}kb3tX%UiWbKa~PDcWM1=0`{fQ?5*R`SH*zUE^IG#? zyH1~~KyW!&oIWL8BR7BO@F^$|Hkgk;drvfy!Iu7FAhOB>nOIF`#wqxxn`{?(Natp>VX_mI`&$o6Jo2nq$2 zloV?{xv_oKQraAc#bR&tJ`I%r+sJ3lmJPM##y^iebFE}%-7EIKzKs+dQ~4VZpwzz-_c1YI{Fnz)Kd zFc7aziE?**m&jK7h)wjp`S4vi^bm)dlSQ#mNgyzl?<<$q_;90eOJ7lO&#^YC_jjTE z)h^WTrprc%jXcQ9Y_3zMwrxM5PX#QS!Fc?pG#yvkLaiV<-|e4V#xiQ>LAx4gufvYeSx37*ciK%}}lN%=xzUx=aA6QI7^Quy*N;{Ia;+vhl zxqM1uU$T{2U-I|UFbxA}W+m+^htZ69d^F8RKR^yY2RS@#9-lX#P8tU%yaA_%=N|)5 zg`{7QRA|lM0EE>rJiiRzwo)of&m%o3rPlN~`u6lTy9W)PTEIvT>>eD#c50_i^z47B zjf(B)d*ptELl9D1>Kkl`?ZM?|_x<_vMzWwlZ>ZkK=gsS;7u6aow8Y_$mrbld4MKZ0 zC@p9b!>_-FADb@)AtOuS;}`utEkQafymArp+jlwqNtK_eu?~LtH#L1J!^q+9;ddI~ z60jFC0c%ogcneq#N(3Jmc7`xI2#J5;c8Dt_vr1V1HY!LFOb?sL}06Ol+6 zP1r^R0%tOTj#S}ye25%C1Op-lAip(#2mbcl&M;9@`3^Gkm^alF8?F@Py?2%ulxKn< zB7bOEZ-uy$$pni*y@$#Dmbt=eSY-u*EmngT(8OI1j{YHLTVY~3Ehy5;AuWGA9!pL9 z7i(dvHMG=b%(ba4kpq41M`q+y`tD;*`4qn5CoVfQEnP+}C1kOT=9<`E=Kgh` z)QXUe$upcv8wpZ9&ou17Zu5LxJ#w6}EBzp&xNRlBSsFEIWz1Smy>+Tnac88_Ex%#v z4+q{U!6w?!>#6&yjHJcH)Y(|LP z1_vv(@Ur+M46F&5*icq0Y6u!XvTC3(2*5MssKdyWgcMO#uX`dy^kR<_|E!GK)?@ys zB1WtmlN4n%MXIEYV}cSM)$(Y(Iv6#Rf0DwQlCMvjehwX~lAR~z*2aGcOUu}`*4>PW zPdCfqya>wl$N;r=F?|uF`j>KI$ktKHc8<<`EIQMt9s-$zEi8{8N1eJd`Gq{$H}_Hck&&w zu{62nFxAYp(ek9e<5FL>t!k>ia4gi#l-SQ+18=uUIw~DqKikeGePnZJqlGqS`iwg| zd-{pyS8Ws>x0>=j+C41~#bJTmXqL0n?F||^Lniw#Wr?{`wBdi5)$FUTH5b`8bcjp- z=>r;JZ*Fwl@a}>})>8{c0osN7u8zB=ke?}Zi!GBy0MXSF&O1HRet*Ig;;U;r^;i#oC*Js$9k9tOYx`iZ)G>& zfZS;)*6hSfa^RRAbB;1apd7oqdGRLK&9Q!JoiYnQX9CkQCdFOKwSX+3L_OzPy9ZQy zJJVs#0%DEIxdi7n_*msfuFA!*4hCXR+;XXIvx_7v=B$6LjFEGt<4&8BgB00HMp8;t z%8c?jold7V*XeYso6ewQ+}4irt+1VvDF!ml(2I)F3rQ5(Sy?I0A!~scs-%_#A(!uQ68{B`n%rSTwUhY0y1q^+9C?KUVxC6=~Pxy{_c!z$jxWH91EtCHwgd zA+`5)rrxxQ=K;gLp> zco%;+)?JgIcw>Q3A7GHjzm9rRSc=bDfO{<>r{pboj9=H5lFzK#4(TdO#p|uxC7>-8 zD1>VPSM!7^sc0Lgi@AK+79Yd^V>wev153!4cB#zrWgJd#?bC%^B8cLAF8%wZB#L^>?0TI9=wYl`Jt&I&_>mgR<$00I z$KBy+_u*_{@gi8|_44#}Q8*y+uaem5?BbOY&Zy<-W%+zBrFQrn@Bt}}!N=o!z}D{X zj0!kI9r027I}hr<%+r5od>(L)PV?~nNb67zijc|S@mtC+|61-t9w*BvUKJAqmp{P4?*wae+B-LE{az16+$>SlM{ZZ{au zxFCFV)p!Q?w`eSjMzE%|fX1+nT7@kd3eaE{f6H?+s>hWOu}6QW71hiZjRc3fo_kR$ z0PWz*DA2A+Y8m6%vPgwAGtc0W2a=q3slCaG$(hOV`myRaXcM@{k?b>_nY78LP{X=o z(WI?yXY!;=IXhV@tagQ!%)?3^oiW=Sx}D=7QPM1uQLUp+1&#upiO@*R$LSYB^K}hQ zP{Qa~P>8rQ_%na#ML7|TTfY6Zd`)N@rS`EI6v9h7hY;=Ir6ghwP`VdRGQ37(;-fpK zpAw|#5P)L%&$s7g>iMk!Us)qe4D(J}4$;Z8of1*{m0mp*V$*HbR~}}4Y2E%HZlN~inMm0p{SMTJC{mW*kvbI6bEMW2Y}%OyaIm$$_gHUP z3rD2-AwPeSf@BYux-iEdmQ#OH-j`yqx*=s4 zTJhK_$C8{tNyCw%Z$ME+5j~fw?49MYL*8+nXa@`pzy;Za$$tUx7g=Zh})j*H)U>9(f4KWs*v;_#u4*h^X{R zU*CTMFnX(DidjlKfHOHN8FyqJLJj%I!C!CIHl2GRw23BWjCwSNX)0&E2Hme=v04UQCc?CbqY|y=0KSZm4M<^rJ4Tfrn}3C z*JKWeJbyNIne&#Z^V*Fyn#XF$_8C&OoG^wmui{L$EtRQ$54^G5)3ms4nbno$$eIpNEU*Lk438>fniW8Z&tC53PAsY)(#wm$5T+?obEIb%68etyC$awY#( zag&5W*AYLatAZ72x<2hjjN91QkUV|lLT-g)01fL!QkZ|nWN~XT z+@X;*yED+mC+N)-CvQq|aucAv?n5P4=Iajjc8d}R9XJ)sYKbD(Ocy%KD_nv6V0g)+ z^ViU}Mo-^Wi|wz~{Kr0VH*a-U)T;HS%N0^>WS>JPc?hH9UV)wp#UO0-&TQ2`A&4kh zs<9*q=uGYs`v{nnfT{zx+K4}AH)rR?%}B|u*N85gfs!4&hl%h!U+09>T%&c#Cv zk4N0|m0>#O#(ydP1FGaBbeDmvFcgRBkTHkpkTQqqkTbXGkTk6Dmoj=;COW-b$&TbU z61~?~=m(0!C4vjkXdqL)0KUyk-3*^RV_&8Zx; zm-c}*Ml$g|`Hij{y(9g5bU&tYB!@(BrKzmb&c83{cR}w8`25SqPj5UmRM595zQ2CF z{r|0Qmu`YJ9DgJti{{MwJNo>-kZDO44q9vaHeTk>zwqHd^zbKoSvfoW8D9P2U*}YT z8~!)^o8v43W|OHIShtK{$E^nQlOKi!cRvAbxj2*4?!R zWB^Q%{7WDM!$6r8WM&64l^|2=s|&L3t~DT2iU}vKflO%z#;%t^gEbg`CO<*+LXQ`X zHu#n?LmHNDHxv_|UryrG-Jb?dZ8$S>3TGuo>mLY)5!y(&iIU@zhT-jnM+nq^TvM1+z#o5gN5?LiT(mgQ^+m^===a)!h!!F7ssB27dR1x}XAj}G3ag~pGrTO3s} zNi40AABkY5Cy>Twcw_qYp6KC9DPCr#mM6|cCQ$?tG>kk*^!2^^Ycq)iiv66EbrNaG z*t(oTRzlAV5z-QWrJ%@3<#IyFTbf{tQoAWoifsleHhui@`%wMzukUlSskw?Ott3lc zrO)YY3dV^>)yrztjA-_JzK*IgjQ;z}JZ8xp#wJrD$(c|CrQoT_i(kqnCosVIAv8HK zsgio3uos>Tm?&a*y5uOoSV;?Jd#hh_EP8(&Z0B8xUA0_)tN?#Rs^m2OQPfg%wovs~ zlHoC2uloCh9;~6H7G9-?rL+S*JdD1jw8*%+h6<-HeO3~`?GB(xSIZJOKHM8Aq&FY! zsviUP?JG%`*cDTTva8pJ*-tWQlg7w z)9_l>8?q#S+(uCtCI!|dI?T(Yy{gY&`}v?CWXN@IaNoRuWCp~lH{)}>(8z?B3 zKqOyp<{&WZkD`ZdZWyL11FEF9xdA%oz5Tpc)+yW$C*t5t}UZ~YlZ3)1V_S2npYEiDfJ}5@i~Go z>lC*`f-hfwhTv6KUqJAxBL@~-Sw=o^)terY`{ZGT%hM#M1RLFUkM>D!Btr`FYh+`u zRs;qWhD7drBlPERK*w<_^Lk_B`b^v)HP(v?vjZ;=GzrOoXm~YIA9wHWw+Dwx?o6Z7vnd{jtTQVCS@J zzsed^Fl2%`UPJ|B7&x_z?T@LDHxJx*HW2Jk!4^Kp#QQxel-MWC?n@i%RPnN!^r6YSa-nIena zi!V-YH|f{dF%zVV$=)?g;G7vN7F3wG*_?6@V;>a`jKWwb=T^7~du$Z2V9>qTIH@-5 zyjwe?u}C58TyqZ<`c>AV0)(Z1k0&M`9~Nl|4OCkA3VXeltNnYB=e3JU((@||nwTknVNDRpjO$xh zkWx_-@%0M}Qj#@p#g&cm{iukOE#u@bjJ;-CvlPld+}PH<+PGWpB`x;Ot9be#oKm}; zw9(x?Iz~!3%dBuO-?08_xl?S)cc^{E?KoM|27R5ARB$rN}@o2E@`nBc;cc?yH#%GF$urMia8YF z8M}b*y*xO9oA&zr>8}1>H_!xNTwb&oC%`Zz=70qgUd8x@d1S+Xgq12bvh#Tpyw5dY zb&^i*ZP4gAYnP9=gc?@cG)wLJ&G_YCc{gxzc00wu<4z%RTUm zcmjpREDlMXXVsxs<9RFQc#Oj`Eh5N?U1vW;Z2W{Fe*iUohzCs{DDI@NX7uOgw`dlgW(<@6t}f+zm$qW*#G+ zYhdPzfiWkJ9&f-4R_MPE-fkF<;k6+^x&&NDnYfsOcGcd^U(Q^>Y$*H_g4AxGo7|Wb ztR@6c;oFPDF}lV_NEa={Siulmr{+(AE_Xm*ot}I#=H2KXG|qa*KvF8x2vUcT6xgFuf1(gE5; zPkar~mf}o{#eJ#hx&pyegf=5moNlLVb+te380%PbJH66X>34%pAxNN#fp!ogi=^*V5Q(3p0S?u*`!Za&?-koNA}O(HjCz0#hJjG4;od(?g;wI1 z?SV)PiAmEsfcODASi=Oznhqt}7Reu(Im8K+2od-WB@ELP-#1eGlnB|K$yXpO-HmIg zdHW8Y8U1Bz^*I0DteK@G5e&ty^8)2_q4ptvoSo20RYsF*m{;sN?u;znKJe34IB{mR zQ-Wm9;cB^)vS*3n>~d!cR#4Ia%}CVuJkUjoR(){%fk5}Ph=VLEz`cyDXa=%6`Tm>cB4O8^uL` z&;xN4+#E{Pi&B(;1DEv@pRCrdFeQlhX6;Ia$FP0Oq))Rt*gUp+n@s7aN!R6SQE~M) zm(~aJBh~VDd8~SyOONI8*edCDV@sIhD(g^zj1RYP5f$jcc~Lxr{fr5D|KPE+hp@v0 zo50Rn5V+5Tdby{5RBz~J<87G*t{TrbeV+;WZMu0(k1uAAYwS4_q$B?d@){;c=NO8T zqlWPxGz!)4qg0TIL2{QtGOtC6L^N4Z!fmd%nUOVP0e|$UDh}j^p?7Omf zgi(!khyW&RV}4-4@wA9zYphX4#qj10)b=#EU_!wivm8Q29T3 zZ)b6ZN{wI16^0HvAb z@cNwuP-KOBRb+8^By&hoP(_h!?tt!&$BB{CT$rtNGD!PaJG21*o zq7G7|dHuq2s?y&V%Psu{&dlq>ilkXU#zF09)_=@3PQh3n47JC5+(CjdMN4a19UZIb6b7X2nIB32NiLrY1=b~Ui^BkG zf~_hh!?~S&)@O>rtDd?wo|beL*T;>_^TsAS71MkQ3rb-Bdcq$=aQi@Ck*w= z&K8f4>p5Q5v6ojE#pALLm=d($>)<*`vc+EgCo9{{xZHv2~ZRVKo%D9+oxm zAeSPzP$qx9Tg{T>CJesMQ}_jzAVB<7O?B0D&(2ouEt|P*<&OR?#5UW(kCGV&4=#;A3i;u-=BVYlWH)`A{a5ee;a@vaQXyJjT#37z_f(n{m1b2 znRB7(I@6^%my#|+-!0wo^g)899zaiko&cOa7zKaNMPIta8(o)3N1cp*jx?xE3c7$U zO|&dp<*Cs#c=6Zi_xI0FJPHnUhvNS6{pp{lR&*^SQ^E{?{CM&YlmsTN7*I2`cKG?% z@a^f>Od(O`%=&Ni`Kd?JXl6%}Uw`MrpY-rEb(YQ!|AwwVG8;bpJ^V%tZV|SO2f~un z?5=+i=7V6)x=3~+fzmOq+;$QxCDVdwdz~t9=CCCjz-58J#kEGPz(t@ED2X;QN5m7j z$k>X2fCLUCuqXl!`ZoHl&ZiHWdpIG%L^=OU_;&~#iU5cZ?>N2Zd-~s=9=xVE4Ndj-x3$l^QVeu8q`%rNEX_wV3_T)SAl;w?1I3IfCm`{k#X+sF^qhP?|8$Q(g1+1 zYImu1_xNwNw%pC{LV-N;t+h8aSd3K)aQFp#g?!io<~~(bPUS8b=W23N6aT zC>+B^;8+Hkm)z5yz<3(xljP57>O6l55oJw!9BIp>w~13%Uwz4Nrm>TN=NnoJJZr6G z>T#ZllH5!HQcs^MfXWi7Dex9_F^xN>4z3#YC0nm-;S=7}Ow!R_*tHkV! z;oS7YImH=N6tpyRCgVHc*A_@g9zE)@TmdXj6v{DBGs?lHI%#>duM%s}6Z_Rj^zh~9 z@%1TZ>@ne&Xq?;nT2z)Gdr^Eq3c+0D5v90eqRw!=j?geolW9#*W_U(od>YA`EPK>P z9If)hN*`ggRm+!88I6MACS-p*I)G-qmpWUfNK1_>_!M9!YwVFlQ+ft+r7YSqx_YvB z&7AL*#Ytw!JJ-qLY?%D(&fcAZUZPb)z!viWat*cf)Nd0tjGAyFIdbYrw}SpTGoLjPg}2 zrS9Uiq$o!fBIoK{=f!{MJeZ_#=*ny<=V@J?CoY;K(Pnu*-)?)9VfoTfZfwsPDK&aC z4Kh%yTCTaa2Ijb#ad1<1o@@io*E-j^x{qFVCbutZ5iuXkcUzKjC&}&Hl8-6Odt5%d4eI5CzvQeDIGNSx5*rD%U4*mAfJCpmu9RFA-k z@RRNT4inr16VRku*bEcg50jeXBVf{SI0z;+)gxfSktrjN!O6TJfj4(0+SacM!3%vR~TWSN3n&97&hPlnaxZOSjy!eJ&Um3JteI=K@+_ z88_o_?_3~!nXe(*n7LiCN$Hq@DIGX&Ni2nBMpwnb`9fhaO->fCi4^NezX{x5Q{F#< z1b~|PWmckFgQ~?5rf5YJPeZ}6v*ni6&RD7cwIHyT$`Ik-m zDv|1?8k3n*oAv+}>mOOaTr;btqF$2iWqrMWN3ABU$s6tqb)@WHjjYG+QEaX^S!8sz zQZ3b+tYd#ZMAx0up2(ULIaAd+OfahgbCGMTADHs$#`(Zh*QxVcelCQWNy9{V*`4nQ z%FnEo3mI_Sx=ovoi!OO}JDf(uZ*PW2+A`Wh)U|HRC!N~u^4L0)3A^E|%*?k1tWKtP z&FzI%wE9+6E-&(i>LynnE7%RerHXK@Auh6?B3*v~_YK44O7_ffr=$kthmA zU8)GSJ{FZ{w)WvI=G=`KOHnuGJ56sdsQkE{bzIi9yw$=EgJaIv8E<}+A`mHPsCx(EWj}^Pz7O}j1&fU zF3ziAd5SCtXwHlrf;8bH45w=8?6o$Wc}#x=Qn@WiqRZp~Iy=b4an1!FjmJt_Zf{iz z)8CWc*_27NtBpW&dM(YzGe z>KzbU^$!iuwB#_dJ%J`9GXVSkp#ijtF(k?1|Ih#{nCAALqq&<&tdz|7<1Fqm2d-^> zCCf=uMw`8!I@Nn(Ma9LobNqgZ|M!vcKR>?B#=hsWZv$m0>MiNlC&P4&~5lIrIVWX4=rDHAL-vUz8SQXncBmfg;}*D8k_D<)4&mkL3rsp zh{+b@CYM?(VO->I*voNlbQIBtBe;zge`vTJZnRkA7Rg%G>doroba^Md@1?A^X$oj) z(9?7w{A$s(V4ZJnB|@hjOAa&J9hjAIM+$g6T3qI{iKmsQ4yfC@HV z81RLmu?h1R!3l$Ur5BOhB8kBZ+6t>;txg*jjLCV-rBZDm)tZIjL{a)by#wFKe^upi zl`Ai_vYe8U%CieFx_3hcUYZo8iAR5&&TMQgX8Cnsno(H87bkIcqLK-hO@FdgHs2r# z7(@M548^n{g3=w9n3dCzHj2cMY#llvZ}*dj#t0C4$jP1#hs`1RCJH4xAt-Y?FoOjQ zC$59It!c1cxXvt6#x8N^0BVd9f8aa2k>9ps3i+@y!n*C~cbEd@l!($ZpaX9#X}6`| z6Pyv{Uk3{0SBuT7tBc)q=dqOIEvYqrH?hb60d3dvU^yF32W%E z_g*^mKxu@ribELEdLW*Ye_+rGyta>M2STdw4Ts3v0ZPW!M(oqwk$xb*X@UsS-_j7| zHvlckgj32t-uyCbqYO?x0;lcf?&LUqIT^JWSukH$2Z2{d--&K0rz(bb&<#<$%vOIw z0al{!P5Oi6KE`k9?}To0eSVv6s6M}6HIRy3tjRgcgW5d1lXfD6fA|?Dn_a5KsO-R{ zbeiXJ^3M0~9PNJp&Q^b7|IRS)_wO6pJENHx1g7E}H3L!$knjN2 z6%sjZQ;~tjFz))^f6i7n2E{L}X_{3-GIeXX8aAhkrWur(Y`4}8Gr8}%HX_n>TMy6w z=jTKLwt=aWtrdSo0-QU{tTL`cVxX2d!G5hoTGw-$R1p?cR1Njjs*m1|Yn7Cs?2|nt z9X(TlyGr_Hm*f#CmtE8rEynw6sGI8W5c;zr6@oC>M=<(EfAtypH(Q;E-(ejhCbn=B z>-O(py`^uI=QHc=YR38_T2G^~2)1j!3T@K3)_P_rSWdJJb3C4O48}UJEv&)#K&A1q zF>I}0tFm<0v8vQ0@#c=xMICN~Ym^HkrWXUp=}MNRzHJ(`#G2ixt8MX-?7nPjF~}oP z=L~U;j!`NFf0RkupRTQg(u;*kGUTDjBlTqs3WqecNS|RG?Tymhfzvk*id)PD1ftN{O# z?fxFgUyJz)e?6Ix+`Ol40ET7M2`*(cC+SY9(DhK1+X}nCTmT(~)9VDlk{x=Y$=*EnRcXRw zfkSMHhdby^O*Hm1ph9Y(PF6PrL`NsQ)lHo6tK*$9j5LS~ibEb&JG0GlGU_&yN(f#P zX9mz+e|%(HXcX*nkaJaEezJfgjWTQ_rf3(Mt={Z5b=9xsO<27)*k#(?B&enH+{jUT z?DJ7RnZ5R?0We4Bfdlu{4)8ua`IHCu*D#ErTg)2D-;ovJICj1tkVy$n#y4yX4{ za}U5Ff4u|Z;yVLU&u{Y+HAK-<+e;N?CXOWHIJV!Ry@iWsLjh{s=qeL|cE}D*P;1 zJk_3|d~^NyNyZ+FD)n-vX=2Y~sZtfg_+>{ep>lzbo zY>unX<$a!~5LQf>wY1E_A$@CKw4z9pPQfJU%~Sb2t6}=pUNOlpaB>w~C@*jerj1RW z^!pzp(=USbE2BHE^?9;D%;SGqaxOuHO)8d(YQbD=;XNNSE7ZGs|FCfIR#`(Om9pg) zR)5f8)>taL{u47{zSA!(xTqPA^7X#s|9Fy`M`6)z37*W>?hX@wtKYLwNe z>geyNQr@*)nW3DB;P!t-wVNTA5;{cTbv)H^Z~ktJ-I1aH1I(rkjtZBOgEte0+tW3N z+tW6O+tW9P+tWC=+tWEkL6@`zQzy4a6*~P0f2No}vcHFlF>(BX`Lh|16_`!$dOQbb zqnJ|JXBD~#*wK1B4#h;Q3nQHF$>w)n{r|xlf!wU|3X5MkH^wPOPh)FFzGVmw*w)=34^jLKs+QdBtL3XOT3d& zAwxP5)P?UHHvmU>bO@X2((6x)-;MG{Qzikg z1DN{srEMcv{$~bWt5J%o#WB&PvgygEK5&HU?A(-;0b*R8YVF78QuijbMDIJC1J$)J zdnR?Ug>4^1iBna2n2zGS^@St}HSPD(VN-p_CF)=C8d8(Dfgd`eB$csAC$~yOI#UP= zxB3C!R%>YE5;eD_Ogcvc1Nv+>m%&s|6So3TI$Um-65~K7f4!T@lG`>AK=1Pv`~f3q zG#X3Q)Kp3GjH_}>GPhJtNt{c3NG|#PG!}v&wE%*}IdCWubPIUw9kiVOn&kB5>G=Ni z!yD?!3P)ho^!{}M9+3POBwsW%SpZ=WruT2tug_8{!^e>iEhQo!mOnc_)5|9W$9Dja z0FMB?e6kvzf2(`>P;Y#kvK;+l&2yH)*HG~Rd>EGH$mt->Wof6E-`;Gt&_x~e>5x9N?nFJQRpWU`9xn6>Mg=D59!@SO`Ee z1uON|Nq3k+gKh{mj&`EU)(I91U0ErkNzC*ie_SgH=`;JlSkCMs-{X9rnyH_;?8v*1 z=J2X-(%jk7qpVA`)sSc)W%iA^9K`DA?#oUXV+$jV7rskqD!=Pk(T zLpr|n22z*8_M^kxqve+QS`t$FeZm}BCzLnmaZY7(iq0xOMO{7Y#l%*o<1V?iAWt5X ze?eW3RDEM`V9~O5Y)ow1n%H(Su{lX5=EOL$C$??doM>X(wyiJs)mN|XtLm=(x9gnV zyY}wxwHCol!JAGN&;8F7*?{J-SO6=6>?fqLG)};0)DLyanQ#bmLjt%2MQ6DRHMuG! z>P0%gTYOqoB#c~z+ROw=i|@oL|7ag_@&vbt;*p zhy^eg$(a!Kl>~9v3mVIxzUiz+3-Lwf`Dqs3nGpSjgOqM$u=2O9a=c~V5G5RtHAOV5 zaPz6CF{WDB-sh~5nal;ML7-(~27^z}XMQ;km|DZI#DTD+gX8z&%Er5wEP2UIi?Qu`bXPF>Rcqag)axo6A13MEhs=zW_dt>cm%FoHYnfhdxI*^sml}d@B}kY*9w$) zCTgfRwIx{+7^Nz@?CrjKb>jCYc8cXqI|2ixhy-+qC;oO(*NCIlZ}7&~F5%8LqSo!V z3$=Kq&lQP!jloW6tmgtV^Ho|c{Q`%FXE!hmMGbGB=cAkzW8(?sBxEZ4t8V~&HIvlj zt?rq1Qjw*vV=#))&GG2L>cG2fLliil^&?X+OtjfX*P7IMEwWES0o8A9E`yFS_p}tz z&00$;y_eFeO3l4ix}aY=wbb-IOA7SC3@kQ;-DnXju%wUtO)kx$U($;hd#;v0N%88O z1{#cEeOt-DXhc|kar=x|?;HXug#COzVOWrM+Z~4ZT zr`|Nx6IiJ$Nr9smnoBgYt(y8VX0iK|-GF>LogkpKU=j&3q0P}UnQov511upc`5I-C0iyf>c2Y_Uv99 z#fzg(JGyiAU=I_=PHssV^-y~8^KT|8FhPQ>lXlKQheO&nOcsqdj699w2s<0L))*BB z-s2qKsCCz*dX?v+CIMtors=F>qm|RkbiA|{riP@P4buM0af3+AlDpL6ZFE}I4$BM6qP(-ohks!nY46#lI?)6E6toFDr8c@+5E}X`$?@$pS&UUsX zJzaaf;f62p%5Yr3u6C`%)mI5fyzA3$Mx*OFBKf7xVU<(<62Jju^NMIDl{pXM146R^Crg5xh8OXv$6F;q}N=@0bC}0}TE%Q+K|X!C=yG;5&F# z96ddhSMRs7tbx1y>MMjLUW;tw&~`7+Tw&0vV7xhlZ%tip3?|R%q9< zCTc6~XPFT;T5%>uG{4*IU$e7o9-}Wm8WmOw^^{jA0BUR&2dbPYX0uKh?Gr^aPi?pz z%;JyUZb4wdcj3vEZmlxKca#G>HZ!mt0rOXBxD~457q2zSf8&lK=Sz*9E4~QJ{EBe< zY43S{|IgRLC>Z`Ydc-AUXdcrjI%=D&Po!?pn-Kvh#<|r<@aXWS61@X!CtUFc7k{TG zM)YzzV=3#yf;~>>NMQZOQ*jGhxk%vR{U-L2&y84Ja!&;LQ*|9OA+gWvd(rlNM&l~S z;U}n7$e4DrgBCA(Nc$kqm-Bu(-O5eHJLYyM$LjZfDf#cX3tYW0CqM28M?BLX*-U>4#QygfR(e?sM-V z@?yk!8NY=E!O+G6kvk=EOm-DA-2OdiVM0HoQCe9+jYxun`gji!%!bDP>L+de$ul(V zbt^bB9e5I@`6t7_U@Mo(L@T=_ECVXmLs_r1fE&AolaS0!y3vYGOkzy_E0tmRW3&tW zNhBfBu$lu02ZdQL7*1H&uV{GaEGqoXJkg2#6ahz72?lcu;L;u*F32#r5^f~n;w$;M;`%I2g6Uojw%oGNX!!@5ALkVQR?iM4(yBE zIIrWD_S+gLfWD!nQ364mP+Q^O|C9WPj(L>+D$aL62x_}LdWRC*S8FdHbl;SETMu0) zcHoCm?{BRjYwVYw51={+cfu=^z5Wq`$G9))`_!y%=z0V3F~)+1RBWsQ)6= z=|2jH(ZNW~u5D1mT95irIx^^k!`thD*xD^IX_r4+fRuVcPo^+r>SC=-mAMY-RG3rz zUr4HFT9#cWoQND)g)Y(~Wm;tvDjXi4>)q)2Q}{qevb;@=&$q>H6nWv|9}krhx7$}Y zdwarFFpMcfals0__QvqqNnS&xW!Xdh*L!bG7o7h_K-4nl>$TW$XxiQ0_D|0iZ?*WX z&>8eQ0Gw#Em}@AsUb$Q;_ki~}v5g&2;d8^@8)EL>G}ec`0-p4*SK9bl9*^gH(aV%q zCWFS?c6T!(xdErW`YJh%4J%)@cZo3X;AM^-`*|hWNg7+ zsS$27lB)S2CptYb52;Ek1iD7bYPQJc%-PifV8EiuN&C`yhcP1|f8xgpid>^v%x0?P zcxZcCIH&x8XKJ`!GV|8NgNN^|+024BZ=0S%SC!7>y0cCv?w`Skuo>k=tU{qt4jFHK zRCj5&SyYDTW(K7Mr&evt)Ha^%N3)yXJlOA&YJz{LG{y_)M|9PJ$_;fvgQ=Zu@7ZiU zU--cCXz206MCzueN462w(#>W?=xLoD~pY&!~QI_V=` zy9UW?*AYu(`aOTY)*}ZZX)l;#8guAuyFxaUxNDbf5~3dAWir|QMC-{SvC*G>0M1kY z4?`kf9Y16zg>rVOk6RzvW1XKZqUgesi+-^*mapgJGg5eA-}k&xEq=R(eQz4}v(=8qq_ko^OosTRz0l+KsvdT%77~&TgH1bGU!R7c--Z*+aJsbDMm(x7MFQghwK^RY1^9x-AP63y8OVsLeztFsCt0TXevfV5iowH8z z=G7!x&UKlrsg?B08ky;vq{*6K7@D$`Bc}eprAMI>5zprsMIHgh+-`4n@Q!9J_>$Fn zYs=fsWRxyfv@kJn8L;|hu{Izs1f&yq?Yt&!xR1pzw_aQ&A@@hx(Nv3SY-L?PoK>O^ z?rYjC%$8BshjwoZf)$)u}3O8b%gAvR6;;;Mt}g4&*5jMT`J&axr-G1g@&U!wUY7OX4?> z#9@>+>|P7_ZALR8$_vsrkddWu63)SVl&>6x|Gbmo&s%gLn}{KC^OQ;q^T zxN0Y%Wx|;tZboE^;(XQrs_WX!jNsdq8DEzWwY%2Gmp5^kk@jt0e*Gd5>|Ae?jMJL} z67@OBjT*~#Xc4SpIvlzk1aKsURK<)5$w^$_z6Wls8wI;ceXB!+#%6`@FU~g=Cl#Ri z-`(B5jo~-yV!Z^W*-WcK-rYOK#pOdqy1|L;y{FM~)e#q{=OhH5nNwVG%g`22YK$kJ z=<&bat)8DTteM@Q_#o)11swn0kfZy@y>VPAChoyUK|qG>;_Tk;kWRrl>{)=ey3cVc zun3@9kw^~@ObTR7PH%M<)D}(Xu^){UL8(9^{;TG{pg_dBh#Lf3(-Wxo9;SeSskFS( z@=?hpDaCZs(P`=-J=5pWQ>shzxaEaNSCn;M)-0i*^K? z85!tzct17_d1>g_(tB(eSU;%B8nntfNCJM@-8lWBn8vIS4>h=OLfYHsKpf%B4HIz% zLnrP=5LrEWW|n@kyLJ5)=jPe(P+c}Yv}RScxEuo z%{`#G1V3tGa5pCc(&TpFG#OGF2n znDsJ7alDKr3rhvJqundiQ<^yRFJTtoZ1Lm$yLbCbm1Bh@B2mTB!tLt&K z+_l`S+%nS}amz{y(+A%qDOQu59Pvv#%cDv?NqG;}9x#TKE30dM+B^n(*HC(5t{PWD z`u8$&NAUZJJ2D1x%K-MeQd7{&j?K~9nGiOI;&d*G=u~qL7_pjeIa(? z5<&!=OQEPUKtfe*Akkqh$6T;vRnQ!3^P-Q7F-oC!Lq&fTz z#BFkc>Lf=2#FUjLR)b~@GOK;0qD}6I-|?*ri>Pf6iRneJUJ$(7GgiDo4z=1Hp5o7; zSc1{#$tqC13s)v^;LD85>u9WM9e#*gIEZVSSQv;`m{X+xsi#{TSJ(B+vB7W6t0ccJ zHlJ96t|&-Q-vMY^mD?Y;87gyAYSq9gwFlIqn*7D8C^fapVua5h{6@=`48amhaM}kIgAYlIJXR078Q52p`FGjKhmfx6t*ln{~?SLY;17p6I2&S;lH;7N`n_s^S zq5EVFzIT7z8ZhoG8*c?MN-icRA7*0*g&BnoAq2M)9H(6lCGU=mmTwpy zEfLy}Ti9{nDM&=MjdlYm?^lis>4F1Ed zC}_mfdO)Zidb`_A0e5C3G*d`@{lVSx?ZNz2zjfD}I#zM#W{BpxIS2lD(V*q}r~yLp z?&*jj*ZI+Gn-5`E*O52p$JB|Gkz(r%cUJb6bmWdLNu_Nu0a5cTQD$R8yDXU<*Y_1 zv?^B>pcn7WflB6Sjxjg9}gk42Pa3fe!=@8I~s0E3G%-7^=BliWf@}s;RXh;z{=( z83spR+%B5ioQ^|!q2*F=y@rId9Ks>6S2)E%*7`zjq;?5M0A+aszu zxXJ=ZlVCoi;|igjiZa9@3B!UX-9~Rbp-frC@K|`W@c3}+5s82q_Yx0m9gxD#C(U}w z6YxOxPIhkAb#WY}*gWB#&6s3k!mTqe5dSIs;r?ZcH`Vhxfn8fwj&tUVs5IzPrt}MsKjx^IcgIxn(o!IyQcLtOU z#VmAQ$)ua-5uMgc?q@JpAoQxIe>lJ!L5e80fX0sMH`y6#v%?cz{(&w2!9b}k8>%o> zNXNi1$G#Zp*CL`{@53%EHg2U*SfrOBQz@%ZIPoq<6ET=q94t=8hzpObibYuR4^&xP zQ>YdfDWe0TzT4lxw@wq{V`^{`fA#MiemW^UCar*wFfJO{^-T{@PqqoZ7?VFHz+Klm z02h1~PW6ui8xMPEWFx&O-jMYR=czfsN=H z&xlm88!rPL3KqNJ@3i_8F>uBu5G<9L*2E1W<-}u}xwxkwR8;F4Ya`SIC*Ots`gz#I zd5&*`c(2=Pf0tKMTUw_(O&LO59~_8m_Z2)reL7?b$Q%RShys8$z{>i`r$vfmbvC>+ ze*B_B41`;lD-B|V(jR1di?fZChE6lOp%tv2Z;Oq&+p3_KZ)8!~k3_q?XDMt0iMe=n zrY#eD!pJ8SEzZ5CKZc%c5rc69DVSmZupxJlxI^QQ@N)Y32Kw(ZNzAM6rkd&fc{_Ez zuM`fARs=}D)hTN>iLQ-Xe++*KI*_C``;wFHs!6eKio_ix3i5_*;KdEQc6cWmnNpQL z)C%3PuTmkOh?Zs#njnZjBFoc6Adi$8{9vrzjL;@)AvRn-kZHz8*NZS=M0*w!f3z< z%~^7{y7@g9kP0LsuB9L;qflc+aq;f`-7qGr^}^;B1yc*=Ju$Y&NkFxTgUgl|GC~R| zk^L44sxzec$bj4@#|5joSG0y-du0hjzbzYkVCnG?wshZBB7a(vnE4}phQZR*Pg^TT z{Q=;mK#|q7{&Xs)HH+-*qzheopOGBz63{VI2Sn^}2$}M0LgnfU;NYLISjmlXn z*^w$$I?CH*@MjQg9&}?;IaW~mEnJAAVQKoz=Xf#@vCj0#j z|1T7TJE*FR1PV2M(9)D+IL8dOa4*gjSv$SSjiKDc$VU*~0cjyVQNTRS+QdrP zEPABO!ENcie9jzs|8C>og(TrrNqbs_#4!%+{1u6CY?aDNNqcQ>QRt$o;3DvArC%;E zt+?Z>IO}En{vtw!O%f?_X{(wL)9S`np~K|akuCI%mB>P& zy6DT4qyrz%xd#QOA>i%S0H))NeU(t+;_c+@?1@cxU=`|Lnirx4+JtUr-}c2pB(|UF zayxfvTr+z6p4Y~4-jqjM39>X+P%>~#dWtw=yv$k(`;m96*o{pB}{ zg@O+FInjcyx?WRY5bt*riRcT+MNFRoii>kd_i^}`WX=bFD;45&v2(aZdRq_^ugVVC zU%gea_euv39zVQo^DcRt|5-Ve-^IYpc0|@FH-|HiWmltOkx+_zq57O)<9Pv3HIXb^ z_3xrR6Z6=!PtVw|{GyjEB>-Q~9c4zCm)VDLovYqsi)?bE6n-FLby950141+n_(A|;32t+^%M;Ba3;k+rh62^BxvJF;y4)wkJb zw(A^OdL{K#BGLvW1ld=5SOt=zZkU6%q@OX(iT0q(0mbuaW^CQA#R+O^Qky*f8TBA> z(3?3^b+sGm+4|cPIcg^A;GqV@;+%%)WrUDZlo`Su^LL7g zwe1?EkS?i$4Q0wiF{9iCn}?3Ps%-#cbAF{bWA$yI%`Y7%(nkmz1E5#3B3|uEX*fAj z>Zj_JD!wwM%i7(rLspC_>ZwS3!4{eNmcn@n_w2(7RuG3!0C|hp#M0bZtB7}N^NVM~ zLu@BO7lVwa1cb7WOKMRl>8!ctfV~TxCtYy+L`_K#jp3hBs0>x5^2M7%LoQ0a2+x1W zVXrL}J?A~{nEPVx{zoj5L)byO4rgpq+n`Y5kDUoJ!*Szz3y4Alc=NNTX zLhACQU3x~4)gGhU_KY3i5Mi0*IdOR~1^U*B^H#nt66<5p6+p&PkD>$IdTGP*uXZ@q zgd&fKi?%tN(%64cZnlY5NTtSC+{2U^F{59JMSs9+fu@imo6wc8OK{NmirJ3R&g;F} zQCVQ8Pk6ZmdPC1XL|8d6gSLXk+v3;zaeO`_w;~_O)l|<8gZWnE1|LYH=IXoo1L;RN z{JH=1QsIH#Kfo2u^nD*KUL#OTtOV<=iHx|l`S`KLo7B&J^gNDio0C6%wODLPC@w({ zAAC%{2v^BBIanw0oG0k2gJU289DI_BM8w=IjNXExkYybd|2bGT>zmDHOFB!LN8l>i zUgo^Y%cSA(>p^Bimg`KwO;n)i#vH+dWlV<_p^iYRIWp+rHEv z4u$d!Xu!@N*^NLncT}gVfh|TYrgREH^3Q#%XT=vwt^YL>XuB?SPjJYISWupZ6?n%d zNYuKB7;Hggfdm%^fe93930>B6Zf;&CERitCb6q<>fihm|vpAcN0g5ep$O+DG=GDDM zi_NleIzNaO2~-og-IY@abLTg9;lsHLF!YS+9Eh~sk-5=C7?!$x6GUB@gi}zKr+&j5 z(0pEEA-Xs(u>;L}9&-~LZ0&Y)57p^!$n=xu$-Ob!Xw5`kB7{=O4%who$tHhAFoC(S z)9*oG*bZ{$6{ghW#|}O@AuvZ!)Vg7MKmhGd$_FJ9joihnVIensjcOzGzCAT zX=0u^LyX@cVKbH?5&L`!ck+{RRQ{}7>&XrXbpuw93R>%gO$S- zR}tb~^sI92ojMsHbsY&(tXYmdrE=zK==%`=?KxS%m0}+CAkx}GDYQuVw?`JDMR@QA z%<1CE`8TFF_pd`)iTv}6S4*a6rVO>%g9>}S)@AjEfK4juvJ3uu;wlSAZwuHfP}Cgw zpu_1J*-GIr87kaS3oBpz5*PMJXT^p8IUPeEngB;IMVI%^j+EC$lp-1PPk=QcB5bnN zM5-~_FfPOEi=+uZm~>!njuUy&^2fvpsxayz=xpitOW6yGB~}KXX3Rwi#(NhUh7t-Q zNWx-yZzu%u(nVQKpTRtm=Ru&Ih*>yR)ep&4?DW?F_S{P=7r{3lf#a-py zS4$pG_S8k*^7 zt;lX}jt^FkdzMevZzh1pLg&#J%CPz4Ga~!&_BKM$bzPC_Hk&DW*X^a~b^m7kxwm}8 zZhe!f+mjIBK95o?9$KgFv>l4qsM)zLm-gY8X^hlK+e0BbWG&m>Wm$H>ZM-n%_=tOTI=2BG zEhbneO#QjU6P5Wb;v)SRdG^BMi8MKBNQ4;392h8Q{>aV?-^lTP)O+0LbbG8h1^GAZ zv6(JFn3+WwJ=m>(*PeOXOEPO&o$Z02!t41s3B2Rg=1%i@`O5uDE-se5v{1{>7V!6m zGCrI7p|fV%Ly!J0wU$ev^*ctV5n+9CcJ}ye;MtrHHe&c9EBfGemOrOC&z#sMAdTLW-PhJJST1DCNLrj#n$?Lbp zlWjzlc88KyRkvPuvk+)J>53BvSUz(Pom)&;v!lyyJIVGkuZ5SC)d~^@@|zDIg7Z3TV|9ITZ$514iSNC2 zFvPe%-_48vg2=zuxNr?7x+ zD5=Bw(T&W@z_+MOywoIV!^PmizUUD*v;6ow3ZoPVUOOO%YmcGzhS>xtn*vp0X}fvf zr%%lcTQw#H3RX22Q{xs#n^+6)p}_SMBJtHvkrJ3NJqPAJ7RnxR!63q94dcf+TI zWXYY$Tij^bDlonA_-+QcW{&TPfK^q)mG#rYYW-{rsEd%4G_CfLxHfi=4fXypf|A}5 zqsSAJK6@_H9X_ibID%Maa#`!Z|r9ugBuUnz&||9flsbQ~G932Se{3=2Up5 z@vjK?-Qn++1xWQ$2|vBRFc={+^fFTk$WB5vrZyrv>!#<5DxzGo*Ty=-tnl$n@T2{6y8YhR13BFSC9>Gp-cg2=US9&&< z&PHg+R}jbeb4|0hQVMEgIg8|^v0;oE#ub#r+OJK(R;&qBT+Gaz);@pOUp1Lixgee= zz1W7iq-mHBiDJkF)21NcD+Cv)1$(JOnWHaPD=%20H%|*)zCA}bhM;lTyX?vCGnRd* zs{HnhU5s&rB2LnLyJr-W-nPNW5C~h=XeXhg$;!0P&UE`zr!A`A@4H_KTX$Za8A~C1 z-Q0}Ov-AcGup2n#_*=K`Gpx|93kQK6(tn2ri?;lTobCMM%~1n;+_bW+XD%s_qFXLp z-rbxO!`Ba0NCFkv#J}4Sv8aS_x17y_v1t2|MbL!4QYsd26P>mqvHatN@%QiidDNQi zi$qt8qwDKuRit~K{kiD8j6@A$z7Dj(eqN*hEP!VhTCgbDLW9B(c@lJtLDpwi$+WBp zT&A@mAry6`jap>Cfaml>HNO0KlZ%B0L_9 z^%6x4GVJYzmFL;@*zMR769pxfu5^$d>09ECW#8t%sA2uNos_@YLPB&f^Au`mbFijX z0m0m9-!d`R{bTeZN!oQ~{Szt-Fr*qAsj$M}$bE!6;xA~Tk8ZJJ9S=JvJW zrBi#R8-!=JXzF5V``h>~!KlS4#oWRy zEJ@FpNMD1oZBq&~<-y=-L_OfG%omXvoBSF1;-^_fsPUXKw`=8UDB5Cy7mx< zsi5dVCvfhClAc{mr#h7@Zrqn;MAN3odX+$4rigD@*BS(%IY$|#wRB>6RD#o~ltvtX zkk@*5 z4%N5B86>-82Ul8&Z#IK&Ee?Zg6ETt!BV)Pp4Nlow+<)`?67BX83o&*M#L7?N-w7bi zVKrS0IH$pYIs7Ckr8d2BJMn}Ua(tNZSY|7I*uP38AhTsKfaCRlX5s zZN2oJh3$M?^%*^J_9MqP$8UQ+-b3;bC@OrOZ6g6I%dKWfA?DDmo)W4uk%TaiSLD?r zW@!AgVz>T>OOyBa z5AUbfeZ}gxYO4O;kv&7~AXg7&0ht7(sKM)XYIL4C=BWJN-z-#-kdaym17ne}4nu(c z?Y%SPyEjV>Q%}w!Ukckwt8MhoZ6=s`wmf*xx{yuF?OpcTiFGNZRW>8JA zXD<*+*-A6RK9sak83u6A-GrgwOe?ASK;djS-hZ5ilDndYlD8OVb5R_P`G10Sgv^{Z zB#pNiVo$1&>K@CUkGFLBa1-x}JE zv`N9gb3(N+D`!dS55r|ynYprS8;L)v5p1@(ei^|_{ylLtv15d*zI`7OMg8`T;XQ@_ z`(!0@=p-MJ9gV;}=(R=AAgO?whvvhZ(CLe`P>2OA3Zo7tGlRVzh6i8rKE5|ls&UlQ z>MCw8^Q$;JC;-#2*S$fOw+*LgB*kQ)6L&p(ReWG>7+jQ%mOUO4IWp5mc$K9_K9jhyogGFwu ziWUxOPe3n}yWz*@4nB+q_&NDu%(Lyl;}9AViT#jgE3>MK_7X`!CHuhor_y@>esihT z6>2-0D3vm3d=3@|j2Zly6rop;jvnpJ6f%jT0z3 zbCgC!)zIH|AV}MXqj(n@zKrD;*QPY{5iBU+a})Ik!Rb*?GtBprn%J9YHQjPJ_Tc?w^3?9Ma2FzL38jUK0I1qQzfkU)#ZesLA zPN`a$GcD=~nuRGUK;vBwT{f1#!%4XI0juNIow|wc65X@<=8rPH|G17N+b>PtBvF}< zRBVnFn;ZhT2^tRny%W9UY`nrH?DIMmEcCDL^qgg*9_Mfd_|VX4nH3_YtBw5~T$*04 zDY_ljt^wS~fg?EJ6DPs$1Ay4?SDGE&LwOBv|iH?d(?0l9<@?07%chv)?k2EpbRF<4pIbG|8Fcnwf z0=WXkvd$5A43NWLLl(ZENmigNClkf>9kw!V1#f4{JlN7jRrGtQp=Q|Q6nv{x9-~TC zOpgDr>46k<+8`1mB)248x!TT%V3YXKz+b2piC4Br=X!ps!{lQvaVdXxQ1=%i+Rz)1 z)sj>4I`MQ-H3P&L_cP>BzsM9J>-NLtkvpl+!i~dJY=8xrcQy4TA&t@%M>FdBbFhLl z>;MiLA>&i-x}SrQ%F=F>CNB9xsP)17duwJ1Ig1=*Kg}!fjmR*i8as0psFxZ4o{*cR zGrjbG50~B(TUj&Ibxg-=LuG*dG(4!o_NI+#Y0Lx74?&Dt3g_^sVq}uYmP3u_Y8kV6 zPa#NJmH>LdMrvYlrsx{^=@_l*YI9yI1`Y=I9REPz`3D<*?nNq;R<;<jT5v`td*$lKh3lsh)!@PNl-=yXEElmg`)<`_~b6zW)&sOkE_CTQQe)WPjX zu4=T?*q!T6ZYd+^h*&jpB zf^xsAspp?RmttNa^*r%gL)El$a)d$lt1H#|lL^m-#I`(v zqJF^aU^Ug98M+K#nUM$?p$dLt{U_p7Ie1S+2)!#wvSjIG{)YVAxlZ+`-QDxGsg(y-mA_b22{#)zmLt(VUfS zfVyCIYSic;04QC_V2}QHA{Rk*7!oKuULs;AEa5o^?DMaKN6)L%%X?m+Q!nNQzY!>QMw1!ixbt$!ns zGhy?G?FEVttBY=gT%;yVg@q7#}pbSfNbLAF2jU4)@(SRuy z0kNvH0JKw5Ly7KzrlELR0vJOe@{#OTA1B;@F(x+s$HD|DoOaK7W4PxrQguM*LRU_* z3x9YBd*(7i!gUI*ni3X1g?d;dx|`qZZ%BK4a0vPUZ`~tjoc0qY4^YJBe^t=`=KEEV zWic6Q5vRnCJUA(kJZazMD)5-@>6Q4n^fXD(QAcb+?7@o5?jclD0gKo%c5v40m%h76 zM)NKDAdbrSk;*6^$FuTA7|yRq6#?4mjfM9x^dHE$b#3Oy5}0ws zFzT#?N!ah?Vboh5pzd#tTBMXzKtKiCC&X3wnrF-ta~eVPAeHwG@*XkGpT8O>D!g;; z{A6uqjeLvWL?^z9n;AT(3v0$91{VIt3Z&=^tPxNN^DaVtm7};%mC4f&UF}6-ByjA6 zknDBx(6o;%87Dd)8Z!#HFA2KzMXy25V97JgeSwCY*zh3Y0_+;QMtfRWqp*9!ps_Vp z{2Zifk`@*sgzb9fswb0!e|F@(?Kb$kjT5RJfRpJaAiBVPyQAHv?4potDX2MEIU_4^ z_N8Q9q}^2DI~;eLa1B57Dpi*ILi;885imE|(a}-LJjk*DNb zsDlgfa&Sn?!r#VQN{)gf7|*?PBMw?zl#c5OzbvdX#>3B3xXNLdDJmXDNt514d`rA% zY$p~izeE{%W{q!P%s%*AVTq%1!ENE$4z(JYBjhWPaSn=&;NKY>C~S(Jksd^81?R^q z8=P+l)p&yB&v7H%n5c1oQ(%DAVXqa;gW_|MlHR3f!?idX8^HyD7y@u7~;_d z@dyXASI`iFRs?alXuc@!HEp87!}n{?ibS{j$pA7qjI;zM%n|f5zd+*Kwacma`L%O^ zp(!K)<1a<8{jx1w63f$v69KHU`PQX#-t1|0j zp~=N;W}RLenUG&aJ%JIkSwYBYQsa`JL>_^946LoiB0JI)e1&|PGxdthR?xP`C#I`*zgC`Qc@eBhR%GMbYHAX`rvoe>-|suTwT(VRbP5&AXh*d!SK#ij{!_ld*_-OG zZ6U*QU9tSRlhXgOZV^V?UF+lo)?x`Z7mdGhmQ|2dno3cT_k5KtK{3M$mThV4Q+!qf^k+)A{kfwMIBucxoUR2$MU6}+bl zHO4|+%X*ANAsMNhqP7bnj4c%uJmHpL?J2_$4$5(`BQ%X1ZWAuWP#X2?rF+y69I%(r z7UOIMagUBj;R0k?W+J>%^DEm~0R5&=J9@qJKx~mqHP1hsb4QpcODW3O2)_X7>4B1S zLa32Mg#0D@dRfRnKV{A>f&wqtVK>y8K5~S<>s_Ot-#Dtq$kY|1oS)SF@>3nik{F5w zXAUKZkZ4aPSnVOf7;60!PFoOJEIi^s;>igmC4F8h}GlrJNaTtr*_}v+^cwkNd?z5C1ceMajyK$|Da8w-AZ+Jtb*eh#Xf!EA3bCkz?4y zTx8MULsc8!obCo>#V-VD7-bwfTEMs!bB%ctXzd@~ zbZ8?R7K#+l&~a84v_SPrHV!4Z2xDUo!SMmy1WSJO(+XuYP&snb%T>FO=FiR)B&LbU zUlH5m^VfY<4~mnYyTO-cx306#MncpulKloDL?M^R7Vg&`9(7!iL06d(Wx7I94Bt%cFBYrj19^}?{7RS?d)&c17(j;5q@v)_t6iJ<4h3)UsFXP z+lR9QOd3NUCJ#nW_b2@W^{%syr@aDp?>m?YG7#A6?Ok?)P}(*lneX>HZ@! z3cI8sZV$I-a4X&23oHCm5F14OkqA9oh)L68cJ&7olH%%G^=RVHhNKk70bG^s8vVWG zkWfy@f1QLM*T5ve4X=6?d0SpzpYMrBEb)~0N0EtfCKne)N)(tW!!W7Co&VzO^bNoVoB4%?Op9I~OUWTa#pYSbfT zS4DDuhx#{(3ym|Gi2{4OJe+#GUENC?`KW=gPeJR5asxy3bgsiUS9Gh2_}bQ+AT>P+^v zY4wU^yT2z``?a99PPGWG46_OU5bRRI;O`j{ijh2mW!i1@T49mdT2GHvxdtzxpnnRn zp_CAVa}X%P2O5u{WF7K~N`-{n4zZ~pHM66yL)+aA*NMTP;xz>K9FP&jeU&){#t=3l z0V^lpACtlFoS~xbhSc55uFX*IIR8<#!so&z^wE zBcI@yi2;;o^DoybZVA(Xizol3vl#w-{A^Tg9s=(H6WV$#EfucJUU5gsqz`yo3CkFp zV8OWs!q@3BGYp!)s@UfjKd)R0CKqhjR3UI$v12w`(hcLR6y)~>Ds>{api=7{hZlA< z8qJmSYg#mOHMCh!S-8t}88u^6aSKu#{MLdkTiR9IW4=ShR>i49Y(~sS6!?9R!TsYL z^HOC(Fwq4`YGC``vcEO&%|>YdyU_@F4(*f;pA#n54{UApqPOfa?jW}BiBPQi0Tc`k z^1bp~T7y!<|1fd#WQo$G+h@$ioyz&B`h$91+R^%&qJQ(VfxO}Y1VEHI64Sn#xR^AF z`pq3GaY+vMoR^r;=&DtzhI#UnH)Wm|g}j2GG#NoHZ4Q)0tavs0a{SzKcEw(}qt zhwwaXEiS*qlExFX1KX2-I^~ITsdG1t<=Qza`EByDL1;9?I(1OtPf53z1;oC`VkGasxeDX`ip^S@030A{wiBN5 zroh*4`R#MJ4%%&j9imBez7E3tTL`5k;&`teEMGPG$X*-u9cqklJdK$NBLs!lPJqFP3uO8Pj7bw zTb^B!i9NgKwA$ZL)#U=y>Rp2VHgVb2lm*R3%Vol{4?8%fLcYMnXSTq^(-hE70)Pp* zeC?+i#p!u_ymAD8Gl(z|fKR5R&MP6R;6P;}%y7qfsgtFFzl|gp)4GtRe&jz-4HY^L z(nti5z#;H=BSG-nVSs!R0YoagxrhsXs5_iFAYM^4+WMEkp`~f8<$vB2bVz zVTKbvi&FTRI`Qcpmgew5ENwMPBQs_GDn4@_m(RF*_I=%I{xNE4bbUAfRon6YUxTIe z)vVho<7*s~vZIFduXDF!r??x(N7Q2e6I9;fHEuC_0Vd{FqK}Y-#Ondc6tv~va*F2$ zY7|!PSnJoAxX&7J)~4sy378p6i#&8a8mb!ipLth({2($JQH;h_5a3E2#GWce12RAr zhXRq7!9#&w)&Xe97xfN)q!Zxh&=RDhGL5(!09*)QfTmgCQ|STd*C%pZxB7-$<-}xk zra)_cz@OogdoN5`)_va$l`@aLl0wUl%=F0vNu1p4zB%v$cOI+NVK1wq*0;gIhu~b- zIfaNzJHoL7CKJLglJ>!g()fU~q%FW7zoEOmw;gGfW|tcC$rRA-@{`3(hviqAfQ7!I zU;`pB^4F(3o8R6hwUWh(Lcw`{j}q5r>G1xUm0*Uh>rh^!&)3uZ6h@-v?U@eG+g56gTu;=C5dp^PhP2zAy0)3|63YvauJHWK27=}3?E zoOd=Ob#s3I#t@3dP|Rf)#B&n-ojapDG59{zNhms56}_qSfq;#rfWDe;Ym?X+1DxNjq877DtlNU2XFcM$USBWIQEuT-L|~r!m%NlY zNC??d{xp+hrdhQt$k{bqN?owV!eJ8_(}89Of8)su3|S^$^qo=rgG8sZEx$q1aO0y~ zy_B%=4!xr%r8xSjwe{)9(1-Mk4mSb%uXaVeOpQ3PcRtQ-t>vnr<%&>V(>l5L)dCCX z2v9TqOjDmsz9hHo`h!B}rnEf*+VAQ}=XtYq`q(Nv&4NV861hHM-=5NNk?#)3O6XJt zjmwc`F3KJdv$n1pV_eTqFcsGyMnF!~wmiUZqEJ#7OF~&&b~E^?_#-n_i*{p(k@9hv z@k~9rzfk<;s@XnXJV1Bzs21gZIoJ)hSwf3)gb_y2V!NMsJ1<`-3EVzQyJ)|0SDSI; zd&w|WI@VKf?(VD`XS>ZI#nu(j6t<5oz`;Gfy_K{+tMZ$l#KzAB@jz5@!7hH z(NAn0V1YBaAA4tPR343oH|Q?u_F-n3M@k3bun)W1qwoxK_nS$fMe?Xh6R9Z@o2Q&z zt0RQ$L(QFonD+H`wZL1ig%2k$Pp0#SUc6$0@M&^rkFSSO`{KZzvyLJ#k4C_xwUq|L z!k&;kyTeZ1ccnQGxN=XDvqiT zrkD=u4sH#@att-@zF5|#%c($5ipAjWYLvVPUAY5Vq8UchiPVyy7XGiENgP;)?;X>` zNiz+tZlnqc;m!(5ZQB6bX1~8XE8@YbRu%qnxTt@Jg#%)STNcQ14T7Aa7QlLDLkh7+)dNfO!EB`Ueg*NRUd55^|~76J$yy zCWnI}>XHyHprTQmmA6AXz-j7ImjoK35|akE1ff%lJ%ML{5NX7$fZngRk1v~t zaTmwS%g!6^ErgTj|Eae-bsyKAAI!ee;V3LLgSUW!6G(sB*q4yr z!xCcR@UjeJfs+j0v5%5h!xxVg0jEt}gR$YeGev!>k8Ai3Thlc59t2;^SVb@d$s2gz zsCa&wmVS>Ng0f8;)U_R85!cWev~qX8hi^<^J9u)b+qiRGW5dVA@%`C2Blb-r=s(Ay zPwM0(%g35aXT}(?mGE`<`1N9a|Mm8rD-LB{5hT=kb*a#LeeApz*|W-<(I%ZXU{8JL zius*nku_TxA0zta`iVR7zagQK>smVr(PRM*?rSh4v*jnL3b2d$5qs6k6)ucvX=(K0 z^7DyCLEpQ23Pw3iFC&B4TY>?A_*4o0Z34hvyCvo9OKpA+*9{&fBUnk_a`Ae6?EG-z z<;?#(F;TzeqTfO=b8Lc;Met*P_bpiCcG_#l;=2F#c$ttogF+2HISG&g@zaBK2VoSzt0ck9^t5puDa84AAY^C@(lL`;K$U4;3$B+)q5-zO zxGcheY-V93p#{TAh&KN(Pwua*A;G#}N&C%@@6T?6)(R5Tn?gg$u16+O%f{eExd?3x z>Wa@QPn<0Fk`t7BbWHDZu_8~`zn_~&K1AS6BQwisFNP;?UST*Y>F>@$R7PMi(IDC5 zoaIixy^dF&L)z z`tHm~kic&h=Uztr`-U{v^#o45X%?ZLx~YMVhnvs4b1Chaa*C;5u;9-7#f**KX~`CZ zcHTE-$_J6-Qoo;b$eR7mB%1kE5DXWF^B~1FkYcr@E-+7j>$BJYq}RgrJAS4Dc6U+U zD=hx3!cDseyb4CXMTS|=#R|vRFETI`zH*BC_*ZVs!pPP?8p}1uhhi8)q?6MWYUy)bV+b%uP zj*{h#Ia8``B}ajD$kSs|uSYf)3wbu}ibOe~GCySB*D;1f29bkY)FwxUnB@8 zMmFiCFvkK~uxF69c4V7X!%$qgq8zom^>tB~v4FZ^>eSNB`5H4ddXm}^*rv;IiT*tI zzp09G8D;xpPMBxr5=!y%Oc!U{OSMW^M1q=EP-E|+zBa4n0ywA108`5M7|ygT(`4Sr zRR5iBDgk{;+r=qO`xK2EMyrq5=W6jXnO0yVUxX&5!X&LJt~dYw4m!W+af9zV^Ef_G z^sIc{MTiQ)^JVFUZY%Kdn(K0AG04JmbBM=7M37V^)6T^;h6uBA=u%zdej%57lD(^? zplv`t=MN@MPU^d1Pqhu;Bg$bY{h^f*WPFWoYYR$(~eidx-BykqTY8|I5=Yl8!*nRCa>Yyp- z7yFUbVEAFBpS>^du_kboY*L)^(7N;DHDTu9&~LFhysEx9gSFxe#>>^ zcwQ<@S9sYChjG|19y92+dQB>5dwV=Ro@r1_FXKSu0G{@kxi%BLZ>hypMXZ4=0qj`i z-gr6E==^Lb(-Ax2R~m8Nqtqhto@iov%>>K>BJmldBj2<=OOGi{XgE9=(2SV%&qUFc z(5I2l9E1-fc4MsM(RuRQ_W2GY(qc96-z?5&12z*PH}NFBG}mJC>wqzTu8lhXaQ?hr zu%M>6EpQT5FL0Ihuwl%aCicR<2}zeVMP*)ln*m#**alE9~(B!841+tnwO@ z&x6B!L9P}Ok3bH|1#X+TW$+X84jm~Ly8G)qEdpD4s#=Qdw~!xi)BZlF9DBNpQ+l`N zH+MkrinlWg&_5qBj7Cysu|!GGM2{E@@Z#5R;m$nhw#M5UdvSyRJO_RdxQU2$SYMul z$xz*7OxltEW{qR9k}51{ljM4`B$N~D;}>TW6a24Z8>W}uyQyaa93v0mK&#FfRO>jI zP~`p)KFY`?RmEoIOnDlPk_R{qwmA6w;XK8xU4k2JIX-qVH(aV*ngWl>JSiaZYhWRS zP7{dKk~NfU9||5atLq{DheUTh)3O`74XaI_N~X4kjcqbPffdNO*Z;!!TT>%0D~(il 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 XkNsource

DenseAxisArray{T}(undef, axes...) where T

Construct an uninitialized DenseAxisArray with element-type T indexed over the given axes.

Example

julia> array = Containers.DenseAxisArray{Float64}(undef, [:a, :b], 1:2);
+4
source
DenseAxisArray{T}(undef, axes...) where T

Construct an uninitialized DenseAxisArray with element-type T indexed over the given axes.

Example

julia> array = Containers.DenseAxisArray{Float64}(undef, [:a, :b], 1:2);
 
 julia> fill!(array, 1.0)
 2-dimensional DenseAxisArray{Float64,2,...} with index sets:
@@ -34,7 +34,7 @@
     Dimension 2, 1:2
 And data, a 2×2 Matrix{Float64}:
  1.0  5.0
- 1.0  1.0
source

SparseAxisArray

SparseAxisArray

JuMP.Containers.SparseAxisArrayType
struct SparseAxisArray{T,N,K<:NTuple{N, Any}} <: AbstractArray{T,N}
     data::OrderedCollections.OrderedDict{K,T}
 end

N-dimensional array with elements of type T where only a subset of the entries are defined. The entries with indices idx = (i1, i2, ..., iN) in keys(data) has value data[idx].

Note that, as opposed to SparseArrays.AbstractSparseArray, the missing entries are not assumed to be zero(T), they are simply not part of the array. This means that the result of map(f, sa::SparseAxisArray) or f.(sa::SparseAxisArray) has the same sparsity structure as sa, even if f(zero(T)) is not zero.

Example

julia> using OrderedCollections: OrderedDict
 
@@ -51,7 +51,7 @@
   [b, 3]  =  3.0
 
 julia> array[:b, 3]
-3.0
source

Containers.@container

JuMP.Containers.@containerMacro
@container([i=..., j=..., ...], expr[, container = :Auto])

Create a container with indices i, j, ... and values given by expr that may depend on the value of the indices.

@container(ref[i=..., j=..., ...], expr[, container = :Auto])

Same as above but the container is assigned to the variable of name ref.

The type of container can be controlled by the container keyword.

Note

When the index set is explicitly given as 1:n for any expression n, it is transformed to Base.OneTo(n) before being given to container.

Example

julia> Containers.@container([i = 1:3, j = 1:3], i + j)
+3.0
source

Containers.@container

JuMP.Containers.@containerMacro
@container([i=..., j=..., ...], expr[, container = :Auto])

Create a container with indices i, j, ... and values given by expr that may depend on the value of the indices.

@container(ref[i=..., j=..., ...], expr[, container = :Auto])

Same as above but the container is assigned to the variable of name ref.

The type of container can be controlled by the container keyword.

Note

When the index set is explicitly given as 1:n for any expression n, it is transformed to Base.OneTo(n) before being given to container.

Example

julia> Containers.@container([i = 1:3, j = 1:3], i + j)
 3×3 Matrix{Int64}:
  2  3  4
  3  4  5
@@ -86,7 +86,7 @@
   [1, 3]  =  4
   [2, 2]  =  4
   [2, 3]  =  5
-  [3, 3]  =  6
source

Containers.container

JuMP.Containers.containerFunction
container(f::Function, indices[[, ::Type{C} = AutoContainerType], names])

Create a container of type C with index names names, indices indices and values at given indices given by f.

If the method with names is not specialized on Type{C}, it falls back to calling container(f, indices, c) for backwards compatibility with containers not supporting index names.

Example

julia> Containers.container((i, j) -> i + j, Containers.vectorized_product(Base.OneTo(3), Base.OneTo(3)))
+  [3, 3]  =  6
source

Containers.container

JuMP.Containers.containerFunction
container(f::Function, indices[[, ::Type{C} = AutoContainerType], names])

Create a container of type C with index names names, indices indices and values at given indices given by f.

If the method with names is not specialized on Type{C}, it falls back to calling container(f, indices, c) for backwards compatibility with containers not supporting index names.

Example

julia> Containers.container((i, j) -> i + j, Containers.vectorized_product(Base.OneTo(3), Base.OneTo(3)))
 3×3 Matrix{Int64}:
  2  3  4
  3  4  5
@@ -115,7 +115,7 @@
   [1, 2]  =  3
   [1, 3]  =  4
   [2, 3]  =  5
-  [3, 3]  =  6
source

Containers.rowtable

JuMP.Containers.rowtableFunction
rowtable([f::Function=identity,] x; [header::Vector{Symbol} = Symbol[]])

Applies the function f to all elements of the variable container x, returning the result as a Vector of NamedTuples, where header is a vector containing the corresponding axis names.

If x is an N-dimensional array, there must be N+1 names, so that the last name corresponds to the result of f(x[i]).

If header is left empty, then the default header is [:x1, :x2, ..., :xN, :y].

Info

A Vector of NamedTuples implements the Tables.jl interface, and so the result can be used as input for any function that consumes a 'Tables.jl' compatible source.

Example

julia> model = Model();
+  [3, 3]  =  6
source

Containers.rowtable

JuMP.Containers.rowtableFunction
rowtable([f::Function=identity,] x; [header::Vector{Symbol} = Symbol[]])

Applies the function f to all elements of the variable container x, returning the result as a Vector of NamedTuples, where header is a vector containing the corresponding axis names.

If x is an N-dimensional array, there must be N+1 names, so that the last name corresponds to the result of f(x[i]).

If header is left empty, then the default header is [:x1, :x2, ..., :xN, :y].

Info

A Vector of NamedTuples implements the Tables.jl interface, and so the result can be used as input for any function that consumes a 'Tables.jl' compatible source.

Example

julia> model = Model();
 
 julia> @variable(model, x[i=1:2, j=i:2] >= 0, start = i+j);
 
@@ -129,7 +129,7 @@
 3-element Vector{@NamedTuple{x1::Int64, x2::Int64, y::VariableRef}}:
  (x1 = 1, x2 = 1, y = x[1,1])
  (x1 = 1, x2 = 2, y = x[1,2])
- (x1 = 2, x2 = 2, y = x[2,2])
source

Containers.default_container

Containers.nested

Containers.default_container

Containers.nested

JuMP.Containers.nestedFunction
nested(iterators...; condition = (args...) -> true)

Create a NestedIterator.

Example

julia> iterator = Containers.nested(
            () -> 1:2,
            (i,) -> ["A", "B"];
            condition = (i, j) -> isodd(i) || j == "B",
@@ -139,21 +139,21 @@
 3-element Vector{Tuple{Int64, String}}:
  (1, "A")
  (1, "B")
- (2, "B")
source

Containers.vectorized_product

Containers.vectorized_product

Containers.build_error_fn

JuMP.Containers.build_error_fnFunction
build_error_fn(macro_name, args, source)

Return a function that can be used in place of Base.error, but which additionally prints the macro from which it was called.

source

Containers.parse_macro_arguments

Containers.build_error_fn

JuMP.Containers.build_error_fnFunction
build_error_fn(macro_name, args, source)

Return a function that can be used in place of Base.error, but which additionally prints the macro from which it was called.

source

Containers.parse_macro_arguments

JuMP.Containers.parse_macro_argumentsFunction
parse_macro_arguments(
     error_fn::Function,
     args;
     valid_kwargs::Union{Nothing,Vector{Symbol}} = nothing,
     num_positional_args::Union{Nothing,Int,UnitRange{Int}} = nothing,
-)

Returns a Tuple{Vector{Any},Dict{Symbol,Any}} containing the ordered positional arguments and a dictionary mapping the keyword arguments.

This specially handles the distinction of @foo(key = value) and @foo(; key = value) in macros.

An error is thrown if multiple keyword arguments are passed with the same key.

If valid_kwargs is a Vector{Symbol}, an error is thrown if a keyword is not in valid_kwargs.

If num_positional_args is not nothing, an error is thrown if the number of positional arguments is not in num_positional_args.

source

Containers.parse_ref_sets

JuMP.Containers.parse_ref_setsFunction
parse_ref_sets(
+)

Returns a Tuple{Vector{Any},Dict{Symbol,Any}} containing the ordered positional arguments and a dictionary mapping the keyword arguments.

This specially handles the distinction of @foo(key = value) and @foo(; key = value) in macros.

An error is thrown if multiple keyword arguments are passed with the same key.

If valid_kwargs is a Vector{Symbol}, an error is thrown if a keyword is not in valid_kwargs.

If num_positional_args is not nothing, an error is thrown if the number of positional arguments is not in num_positional_args.

source

Containers.parse_ref_sets

JuMP.Containers.parse_ref_setsFunction
parse_ref_sets(
     error_fn::Function,
     expr;
     invalid_index_variables::Vector{Symbol} = Symbol[],
-)

Helper function for macros to construct container objects.

Warning

This function is for advanced users implementing JuMP extensions. See container_code for more details.

Arguments

  • error_fn: a function that takes a String and throws an error, potentially annotating the input string with extra information such as from which macro it was thrown from. Use error if you do not want a modified error message.
  • expr: an Expr that specifies the container, for example, :(x[i = 1:3, [:red, :blue], k = S; i + k <= 6])

Returns

  1. name: the name of the container, if given, otherwise nothing
  2. index_vars: a Vector{Any} of names for the index variables, for example, [:i, gensym(), :k]. These may also be expressions, like :((i, j)) from a call like :(x[(i, j) in S]).
  3. indices: an iterator over the indices, for example, Containers.NestedIterator

Example

See container_code for a worked example.

source

Containers.build_name_expr

JuMP.Containers.build_name_exprFunction
build_name_expr(
+)

Helper function for macros to construct container objects.

Warning

This function is for advanced users implementing JuMP extensions. See container_code for more details.

Arguments

  • error_fn: a function that takes a String and throws an error, potentially annotating the input string with extra information such as from which macro it was thrown from. Use error if you do not want a modified error message.
  • expr: an Expr that specifies the container, for example, :(x[i = 1:3, [:red, :blue], k = S; i + k <= 6])

Returns

  1. name: the name of the container, if given, otherwise nothing
  2. index_vars: a Vector{Any} of names for the index variables, for example, [:i, gensym(), :k]. These may also be expressions, like :((i, j)) from a call like :(x[(i, j) in S]).
  3. indices: an iterator over the indices, for example, Containers.NestedIterator

Example

See container_code for a worked example.

source

Containers.build_name_expr

JuMP.Containers.build_name_exprFunction
build_name_expr(
     name::Union{Symbol,Nothing},
     index_vars::Vector,
     kwargs::Dict{Symbol,Any},
@@ -164,12 +164,12 @@
 ""
 
 julia> Containers.build_name_expr(:y, [:i, :j], Dict{Symbol,Any}(:base_name => "y"))
-:(string("y", "[", string($(Expr(:escape, :i))), ",", string($(Expr(:escape, :j))), "]"))
source

Containers.add_additional_args

Containers.add_additional_args

JuMP.Containers.add_additional_argsFunction
add_additional_args(
     call::Expr,
     args::Vector,
     kwargs::Dict{Symbol,Any};
     kwarg_exclude::Vector{Symbol} = Symbol[],
-)

Add the positional arguments args to the function call expression call, escaping each argument expression.

This function is able to incorporate additional positional arguments to calls that already have keyword arguments.

source

Containers.container_code

JuMP.Containers.container_codeFunction
container_code(
+)

Add the positional arguments args to the function call expression call, escaping each argument expression.

This function is able to incorporate additional positional arguments to calls that already have keyword arguments.

source

Containers.container_code

JuMP.Containers.container_codeFunction
container_code(
     index_vars::Vector{Any},
     indices::Expr,
     code,
@@ -194,7 +194,7 @@
     Dimension 2, ["A", "B"]
 And data, a 2×2 Matrix{String}:
  "A"   "B"
- "AA"  "BB"
source

Containers.AutoContainerType

Containers.NestedIterator

Containers.AutoContainerType

Containers.NestedIterator

JuMP.Containers.NestedIteratorType
struct NestedIterator{T}
     iterators::T # Tuple of functions
     condition::Function
 end

Iterators over the tuples that are produced by a nested for loop.

Construct a NestedIterator using nested.

Example

julia> iterators = (() -> 1:2, (i,) -> ["A", "B"]);
@@ -217,6 +217,6 @@
        end
 (1, "A")
 (1, "B")
-(2, "B")
source

Containers.VectorizedProductIterator

Containers.VectorizedProductIterator

+end

A wrapper type for Iterators.ProuctIterator that discards shape information and returns a Vector.

Construct a VectorizedProductIterator using vectorized_product.

source diff --git a/previews/PR3883/api/JuMP/index.html b/previews/PR3883/api/JuMP/index.html index 5255f0f627f..69c0772cd7a 100644 --- a/previews/PR3883/api/JuMP/index.html +++ b/previews/PR3883/api/JuMP/index.html @@ -15,7 +15,7 @@ julia> @build_constraint(x .>= 0) 2-element Vector{ScalarConstraint{AffExpr, MathOptInterface.GreaterThan{Float64}}}: ScalarConstraint{AffExpr, MathOptInterface.GreaterThan{Float64}}(x[1], MathOptInterface.GreaterThan{Float64}(-0.0)) - ScalarConstraint{AffExpr, MathOptInterface.GreaterThan{Float64}}(x[2], MathOptInterface.GreaterThan{Float64}(-0.0))source

@constraint

JuMP.@constraintMacro
@constraint(model, expr, args...; kwargs...)
+ ScalarConstraint{AffExpr, MathOptInterface.GreaterThan{Float64}}(x[2], MathOptInterface.GreaterThan{Float64}(-0.0))
source

@constraint

JuMP.@constraintMacro
@constraint(model, expr, args...; kwargs...)
 @constraint(model, [index_sets...], expr, args...; kwargs...)
 @constraint(model, name, expr, args...; kwargs...)
 @constraint(model, name[index_sets...], expr, args...; kwargs...)

Add a constraint described by the expression expr.

The name argument is optional. If index sets are passed, a container is built and the constraint may depend on the indices of the index sets.

The expression expr may be one of following forms:

  • func in set, constraining the function func to belong to the set set, which is either a MOI.AbstractSet or one of the JuMP shortcuts like SecondOrderCone or PSDCone

  • a <op> b, where <op> is one of ==, , >=, , <=

  • l <= f <= u or u >= f >= l, constraining the expression f to lie between l and u

  • f(x) ⟂ x, which defines a complementarity constraint

  • z --> {expr}, which defines an indicator constraint that activates when z is 1

  • !z --> {expr}, which defines an indicator constraint that activates when z is 0

  • z <--> {expr}, which defines a reified constraint

  • expr := rhs, which defines a Boolean equality constraint

Broadcasted comparison operators like .== are also supported for the case when the left- and right-hand sides of the comparison operator are arrays.

JuMP extensions may additionally provide support for constraint expressions which are not listed here.

Keyword arguments

  • base_name: sets the name prefix used to generate constraint names. It corresponds to the constraint name for scalar constraints, otherwise, the constraint names are set to base_name[...] for each index ....

  • container = :Auto: force the container type by passing container = Array,

container = DenseAxisArray, container = SparseAxisArray, or any another container type which is supported by a JuMP extension.

  • set_string_name::Bool = true: control whether to set the MOI.ConstraintName attribute. Passing set_string_name = false can improve performance.

Other keyword arguments may be supported by JuMP extensions.

Example

julia> model = Model();
@@ -52,7 +52,7 @@
 z --> {x[1] ≥ 0}
 
 julia> @constraint(model, !z --> {2 * x[2] <= 3})
-!z --> {2 x[2] ≤ 3}
source

@constraints

JuMP.@constraintsMacro
@constraints(model, args...)

Adds groups of constraints at once, in the same fashion as the @constraint macro.

The model must be the first argument, and multiple constraints can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the constraints that were defined.

Example

julia> model = Model();
+!z --> {2 x[2] ≤ 3}
source

@constraints

JuMP.@constraintsMacro
@constraints(model, args...)

Adds groups of constraints at once, in the same fashion as the @constraint macro.

The model must be the first argument, and multiple constraints can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the constraints that were defined.

Example

julia> model = Model();
 
 julia> @variable(model, w);
 
@@ -75,7 +75,7 @@
  sum_to_one[2] : y + z[2] = 1
  sum_to_one[3] : y + z[3] = 1
  x ≥ 1
- -w + y ≤ 2
source

@expression

@expression

JuMP.@expressionMacro
@expression(model::GenericModel, expression)
 @expression(model::GenericModel, [index_sets...], expression)
 @expression(model::GenericModel, name, expression)
 @expression(model::GenericModel, name[index_sets...], expression)

Efficiently builds and returns an expression.

The name argument is optional. If index sets are passed, a container is built and the expression may depend on the indices of the index sets.

Keyword arguments

  • container = :Auto: force the container type by passing container = Array, container = DenseAxisArray, container = SparseAxisArray, or any another container type which is supported by a JuMP extension.

Example

julia> model = Model();
@@ -102,7 +102,7 @@
 3-element Vector{AffExpr}:
  x[1] + x[2] + x[3]
  2 x[1] + 2 x[2] + 2 x[3]
- 3 x[1] + 3 x[2] + 3 x[3]
source

@expressions

JuMP.@expressionsMacro
@expressions(model, args...)

Adds multiple expressions to model at once, in the same fashion as the @expression macro.

The model must be the first argument, and multiple expressions can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the expressions that were defined.

Example

julia> model = Model();
+ 3 x[1] + 3 x[2] + 3 x[3]
source

@expressions

JuMP.@expressionsMacro
@expressions(model, args...)

Adds multiple expressions to model at once, in the same fashion as the @expression macro.

The model must be the first argument, and multiple expressions can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the expressions that were defined.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -116,7 +116,7 @@
            my_expr, x^2 + y^2
            my_expr_1[i = 1:2], a[i] - z[i]
        end)
-(x² + y², AffExpr[-z[1] + 4, -z[2] + 5])
source

@force_nonlinear

JuMP.@force_nonlinearMacro
@force_nonlinear(expr)

Change the parsing of expr to construct GenericNonlinearExpr instead of GenericAffExpr or GenericQuadExpr.

This macro works by walking expr and substituting all calls to +, -, *, /, and ^ in favor of ones that construct GenericNonlinearExpr.

This macro will error if the resulting expression does not produce a GenericNonlinearExpr because, for example, it is used on an expression that does not use the basic arithmetic operators.

When to use this macro

In most cases, you should not use this macro.

Use this macro only if the intended output type is a GenericNonlinearExpr and the regular macro calls destroy problem structure, or in rare cases, if the regular macro calls introduce a large amount of intermediate variables, for example, because they promote types to a common quadratic expression.

Example

Use-case one: preserve problem structure.

julia> model = Model();
+(x² + y², AffExpr[-z[1] + 4, -z[2] + 5])
source

@force_nonlinear

JuMP.@force_nonlinearMacro
@force_nonlinear(expr)

Change the parsing of expr to construct GenericNonlinearExpr instead of GenericAffExpr or GenericQuadExpr.

This macro works by walking expr and substituting all calls to +, -, *, /, and ^ in favor of ones that construct GenericNonlinearExpr.

This macro will error if the resulting expression does not produce a GenericNonlinearExpr because, for example, it is used on an expression that does not use the basic arithmetic operators.

When to use this macro

In most cases, you should not use this macro.

Use this macro only if the intended output type is a GenericNonlinearExpr and the regular macro calls destroy problem structure, or in rare cases, if the regular macro calls introduce a large amount of intermediate variables, for example, because they promote types to a common quadratic expression.

Example

Use-case one: preserve problem structure.

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -144,7 +144,7 @@
 2640
 
 julia> @allocated @expression(model, @force_nonlinear(x * 2.0 * (1 + x) * x))
-672
source

@objective

JuMP.@objectiveMacro
@objective(model::GenericModel, sense, func)

Set the objective sense to sense and objective function to func.

The objective sense can be either Min, Max, MOI.MIN_SENSE, MOI.MAX_SENSE or MOI.FEASIBILITY_SENSE. In order to set the sense programmatically, that is, when sense is a variable whose value is the sense, one of the three MOI.OptimizationSense values must be used.

Example

Minimize the value of the variable x, do:

julia> model = Model();
+672
source

@objective

JuMP.@objectiveMacro
@objective(model::GenericModel, sense, func)

Set the objective sense to sense and objective function to func.

The objective sense can be either Min, Max, MOI.MIN_SENSE, MOI.MAX_SENSE or MOI.FEASIBILITY_SENSE. In order to set the sense programmatically, that is, when sense is a variable whose value is the sense, one of the three MOI.OptimizationSense values must be used.

Example

Minimize the value of the variable x, do:

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -165,7 +165,7 @@
 MIN_SENSE::OptimizationSense = 0
 
 julia> @objective(model, sense, x^2 - 2x + 1)
-x² - 2 x + 1
source

@operator

JuMP.@operatorMacro
@operator(model, operator, dim, f[, ∇f[, ∇²f]])

Add the nonlinear operator operator in model with dim arguments, and create a new NonlinearOperator object called operator in the current scope.

The function f evaluates the operator and must return a scalar.

The optional function ∇f evaluates the first derivative, and the optional function ∇²f evaluates the second derivative.

∇²f may be provided only if ∇f is also provided.

Univariate syntax

If dim == 1, then the method signatures of each function must be:

  • f(::T)::T where {T<:Real}
  • ∇f(::T)::T where {T<:Real}
  • ∇²f(::T)::T where {T<:Real}

Multivariate syntax

If dim > 1, then the method signatures of each function must be:

  • f(x::T...)::T where {T<:Real}
  • ∇f(g::AbstractVector{T}, x::T...)::Nothing where {T<:Real}
  • ∇²f(H::AbstractMatrix{T}, x::T...)::Nothing where {T<:Real}

Where the gradient vector g and Hessian matrix H are filled in-place. For the Hessian, you must fill in the non-zero lower-triangular entries only. Setting an off-diagonal upper-triangular element may error.

Example

julia> model = Model();
+x² - 2 x + 1
source

@operator

JuMP.@operatorMacro
@operator(model, operator, dim, f[, ∇f[, ∇²f]])

Add the nonlinear operator operator in model with dim arguments, and create a new NonlinearOperator object called operator in the current scope.

The function f evaluates the operator and must return a scalar.

The optional function ∇f evaluates the first derivative, and the optional function ∇²f evaluates the second derivative.

∇²f may be provided only if ∇f is also provided.

Univariate syntax

If dim == 1, then the method signatures of each function must be:

  • f(::T)::T where {T<:Real}
  • ∇f(::T)::T where {T<:Real}
  • ∇²f(::T)::T where {T<:Real}

Multivariate syntax

If dim > 1, then the method signatures of each function must be:

  • f(x::T...)::T where {T<:Real}
  • ∇f(g::AbstractVector{T}, x::T...)::Nothing where {T<:Real}
  • ∇²f(H::AbstractMatrix{T}, x::T...)::Nothing where {T<:Real}

Where the gradient vector g and Hessian matrix H are filled in-place. For the Hessian, you must fill in the non-zero lower-triangular entries only. Setting an off-diagonal upper-triangular element may error.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -204,7 +204,7 @@
 f (generic function with 1 method)
 
 julia> op_f = model[:op_f] = add_nonlinear_operator(model, 1, f; name = :op_f)
-NonlinearOperator(f, :op_f)
source

@variable

JuMP.@variableMacro
@variable(model, expr, args..., kw_args...)

Add a variable to the model model described by the expression expr, the positional arguments args and the keyword arguments kw_args.

Anonymous and named variables

expr must be one of the forms:

  • Omitted, like @variable(model), which creates an anonymous variable
  • A single symbol like @variable(model, x)
  • A container expression like @variable(model, x[i=1:3])
  • An anonymous container expression like @variable(model, [i=1:3])

Bounds

In addition, the expression can have bounds, such as:

  • @variable(model, x >= 0)
  • @variable(model, x <= 0)
  • @variable(model, x == 0)
  • @variable(model, 0 <= x <= 1)

and bounds can depend on the indices of the container expressions:

  • @variable(model, -i <= x[i=1:3] <= i)

Sets

You can explicitly specify the set to which the variable belongs:

  • @variable(model, x in MOI.Interval(0.0, 1.0))

For more information on this syntax, read Variables constrained on creation.

Positional arguments

The recognized positional arguments in args are the following:

  • Bin: restricts the variable to the MOI.ZeroOne set, that is, {0, 1}. For example, @variable(model, x, Bin). Note: you cannot use @variable(model, Bin), use the binary keyword instead.
  • Int: restricts the variable to the set of integers, that is, ..., -2, -1, 0, 1, 2, ... For example, @variable(model, x, Int). Note: you cannot use @variable(model, Int), use the integer keyword instead.
  • Symmetric: Only available when creating a square matrix of variables, that is when expr is of the form varname[1:n,1:n] or varname[i=1:n,j=1:n], it creates a symmetric matrix of variables.
  • PSD: A restrictive extension to Symmetric which constraints a square matrix of variables to Symmetric and constrains to be positive semidefinite.

Keyword arguments

Four keyword arguments are useful in all cases:

  • base_name: Sets the name prefix used to generate variable names. It corresponds to the variable name for scalar variable, otherwise, the variable names are set to base_name[...] for each index ... of the axes axes.
  • start::Float64: specify the value passed to set_start_value for each variable
  • container: specify the container type. See Forcing the container type for more information.
  • set_string_name::Bool = true: control whether to set the MOI.VariableName attribute. Passing set_string_name = false can improve performance.

Other keyword arguments are needed to disambiguate sitations with anonymous variables:

  • lower_bound::Float64: an alternative to x >= lb, sets the value of the variable lower bound.
  • upper_bound::Float64: an alternative to x <= ub, sets the value of the variable upper bound.
  • binary::Bool: an alternative to passing Bin, sets whether the variable is binary or not.
  • integer::Bool: an alternative to passing Int, sets whether the variable is integer or not.
  • set::MOI.AbstractSet: an alternative to using x in set
  • variable_type: used by JuMP extensions. See Extend @variable for more information.

Example

The following are equivalent ways of creating a variable x of name x with lower bound 0:

julia> model = Model();
+NonlinearOperator(f, :op_f)
source

@variable

JuMP.@variableMacro
@variable(model, expr, args..., kw_args...)

Add a variable to the model model described by the expression expr, the positional arguments args and the keyword arguments kw_args.

Anonymous and named variables

expr must be one of the forms:

  • Omitted, like @variable(model), which creates an anonymous variable
  • A single symbol like @variable(model, x)
  • A container expression like @variable(model, x[i=1:3])
  • An anonymous container expression like @variable(model, [i=1:3])

Bounds

In addition, the expression can have bounds, such as:

  • @variable(model, x >= 0)
  • @variable(model, x <= 0)
  • @variable(model, x == 0)
  • @variable(model, 0 <= x <= 1)

and bounds can depend on the indices of the container expressions:

  • @variable(model, -i <= x[i=1:3] <= i)

Sets

You can explicitly specify the set to which the variable belongs:

  • @variable(model, x in MOI.Interval(0.0, 1.0))

For more information on this syntax, read Variables constrained on creation.

Positional arguments

The recognized positional arguments in args are the following:

  • Bin: restricts the variable to the MOI.ZeroOne set, that is, {0, 1}. For example, @variable(model, x, Bin). Note: you cannot use @variable(model, Bin), use the binary keyword instead.
  • Int: restricts the variable to the set of integers, that is, ..., -2, -1, 0, 1, 2, ... For example, @variable(model, x, Int). Note: you cannot use @variable(model, Int), use the integer keyword instead.
  • Symmetric: Only available when creating a square matrix of variables, that is when expr is of the form varname[1:n,1:n] or varname[i=1:n,j=1:n], it creates a symmetric matrix of variables.
  • PSD: A restrictive extension to Symmetric which constraints a square matrix of variables to Symmetric and constrains to be positive semidefinite.

Keyword arguments

Four keyword arguments are useful in all cases:

  • base_name: Sets the name prefix used to generate variable names. It corresponds to the variable name for scalar variable, otherwise, the variable names are set to base_name[...] for each index ... of the axes axes.
  • start::Float64: specify the value passed to set_start_value for each variable
  • container: specify the container type. See Forcing the container type for more information.
  • set_string_name::Bool = true: control whether to set the MOI.VariableName attribute. Passing set_string_name = false can improve performance.

Other keyword arguments are needed to disambiguate sitations with anonymous variables:

  • lower_bound::Float64: an alternative to x >= lb, sets the value of the variable lower bound.
  • upper_bound::Float64: an alternative to x <= ub, sets the value of the variable upper bound.
  • binary::Bool: an alternative to passing Bin, sets whether the variable is binary or not.
  • integer::Bool: an alternative to passing Int, sets whether the variable is integer or not.
  • set::MOI.AbstractSet: an alternative to using x in set
  • variable_type: used by JuMP extensions. See Extend @variable for more information.

Example

The following are equivalent ways of creating a variable x of name x with lower bound 0:

julia> model = Model();
 
 julia> @variable(model, x >= 0)
 x
julia> model = Model();
@@ -233,14 +233,14 @@
 3-element Vector{VariableRef}:
  _[7]
  _[8]
- _[9]
source

@variables

JuMP.@variablesMacro
@variables(model, args...)

Adds multiple variables to model at once, in the same fashion as the @variable macro.

The model must be the first argument, and multiple variables can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the variables that were defined.

Example

julia> model = Model();
+ _[9]
source

@variables

JuMP.@variablesMacro
@variables(model, args...)

Adds multiple variables to model at once, in the same fashion as the @variable macro.

The model must be the first argument, and multiple variables can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the variables that were defined.

Example

julia> model = Model();
 
 julia> @variables(model, begin
            x
            y[i = 1:2] >= 0, (start = i)
            z, Bin, (start = 0, base_name = "Z")
        end)
-(x, VariableRef[y[1], y[2]], Z)
Note

Keyword arguments must be contained within parentheses (refer to the example above).

source

add_bridge

JuMP.add_bridgeFunction
add_bridge(
+(x, VariableRef[y[1], y[2]], Z)
Note

Keyword arguments must be contained within parentheses (refer to the example above).

source

add_bridge

JuMP.add_bridgeFunction
add_bridge(
     model::GenericModel{T},
     BT::Type{<:MOI.Bridges.AbstractBridge};
     coefficient_type::Type{S} = T,
@@ -252,11 +252,11 @@
            model,
            MOI.Bridges.Constraint.NumberConversionBridge;
            coefficient_type = Complex{Float64}
-       )
source

add_constraint

add_constraint

JuMP.add_constraintFunction
add_constraint(
     model::GenericModel,
     con::AbstractConstraint,
     name::String= "",
-)

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

add_nonlinear_operator

JuMP.add_nonlinear_operatorFunction
add_nonlinear_operator(
+)

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

add_nonlinear_operator

add_to_expression!

JuMP.add_to_expression!Function
add_to_expression!(expression, terms...)

Updates expression in-place to expression + (*)(terms...).

This is typically much more efficient than expression += (*)(terms...) because it avoids the temorary allocation of the right-hand side term.

For example, add_to_expression!(expression, a, b) produces the same result as expression += a*b, and add_to_expression!(expression, a) produces the same result as expression += a.

When to implement

Only a few methods are defined, mostly for internal use, and only for the cases when:

  1. they can be implemented efficiently
  2. expression is capable of storing the result. For example, add_to_expression!(::AffExpr, ::GenericVariableRef, ::GenericVariableRef) is not defined because a GenericAffExpr cannot store the product of two variables.

Example

julia> model = Model();
+4.0
source

add_to_expression!

JuMP.add_to_expression!Function
add_to_expression!(expression, terms...)

Updates expression in-place to expression + (*)(terms...).

This is typically much more efficient than expression += (*)(terms...) because it avoids the temorary allocation of the right-hand side term.

For example, add_to_expression!(expression, a, b) produces the same result as expression += a*b, and add_to_expression!(expression, a) produces the same result as expression += a.

When to implement

Only a few methods are defined, mostly for internal use, and only for the cases when:

  1. they can be implemented efficiently
  2. expression is capable of storing the result. For example, add_to_expression!(::AffExpr, ::GenericVariableRef, ::GenericVariableRef) is not defined because a GenericAffExpr cannot store the product of two variables.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -316,7 +316,7 @@
 3 x[1] + 3 x[2]
 
 julia> ex2
-2 x[1] + 2 x[2]
source

add_to_function_constant

JuMP.add_to_function_constantFunction
add_to_function_constant(constraint::ConstraintRef, value)

Add value to the function constant term of constraint.

Note that for scalar constraints, JuMP will aggregate all constant terms onto the right-hand side of the constraint so instead of modifying the function, the set will be translated by -value. For example, given a constraint 2x <= 3, add_to_function_constant(c, 4) will modify it to 2x <= -1.

Example

For scalar constraints, the set is translated by -value:

julia> model = Model();
+2 x[1] + 2 x[2]
source

add_to_function_constant

JuMP.add_to_function_constantFunction
add_to_function_constant(constraint::ConstraintRef, value)

Add value to the function constant term of constraint.

Note that for scalar constraints, JuMP will aggregate all constant terms onto the right-hand side of the constraint so instead of modifying the function, the set will be translated by -value. For example, given a constraint 2x <= 3, add_to_function_constant(c, 4) will modify it to 2x <= -1.

Example

For scalar constraints, the set is translated by -value:

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -338,7 +338,7 @@
 julia> add_to_function_constant(con, [1, 2, 2])
 
 julia> con
-con : [x + y + 1, x + 2, y + 2] ∈ MathOptInterface.SecondOrderCone(3)
source

add_variable

JuMP.add_variableFunction
add_variable(m::GenericModel, v::AbstractVariable, name::String = "")

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

all_constraints

JuMP.all_constraintsFunction
all_constraints(model::GenericModel, function_type, set_type)::Vector{<:ConstraintRef}

Return a list of all constraints currently in the model where the function has type function_type and the set has type set_type. The constraints are ordered by creation time.

See also list_of_constraint_types and num_constraints.

Example

julia> model = Model();
+con : [x + y + 1, x + 2, y + 2] ∈ MathOptInterface.SecondOrderCone(3)
source

add_variable

JuMP.add_variableFunction
add_variable(m::GenericModel, v::AbstractVariable, name::String = "")

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

all_constraints

JuMP.all_constraintsFunction
all_constraints(model::GenericModel, function_type, set_type)::Vector{<:ConstraintRef}

Return a list of all constraints currently in the model where the function has type function_type and the set has type set_type. The constraints are ordered by creation time.

See also list_of_constraint_types and num_constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0, Bin);
 
@@ -354,7 +354,7 @@
 
 julia> all_constraints(model, AffExpr, MOI.LessThan{Float64})
 1-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}, ScalarShape}}:
- 2 x ≤ 1
source
all_constraints(
+ 2 x ≤ 1
source
all_constraints(
     model::GenericModel;
     include_variable_in_set_constraints::Bool,
 )::Vector{ConstraintRef}

Return a list of all constraints in model.

If include_variable_in_set_constraints == true, then VariableRef constraints such as VariableRef-in-Integer are included. To return only the structural constraints (for example, the rows in the constraint matrix of a linear program), pass include_variable_in_set_constraints = false.

Example

julia> model = Model();
@@ -375,7 +375,7 @@
 julia> all_constraints(model; include_variable_in_set_constraints = false)
 2-element Vector{ConstraintRef}:
  2 x ≤ 1
- x ^ 2.0 - 1.0 ≤ 0

Performance considerations

Note that this function is type-unstable because it returns an abstractly typed vector. If performance is a problem, consider using list_of_constraint_types and a function barrier. See the Performance tips for extensions section of the documentation for more details.

source

all_variables

JuMP.all_variablesFunction
all_variables(model::GenericModel{T})::Vector{GenericVariableRef{T}} where {T}

Returns a list of all variables currently in the model. The variables are ordered by creation time.

Example

julia> model = Model();
+ x ^ 2.0 - 1.0 ≤ 0

Performance considerations

Note that this function is type-unstable because it returns an abstractly typed vector. If performance is a problem, consider using list_of_constraint_types and a function barrier. See the Performance tips for extensions section of the documentation for more details.

source

all_variables

JuMP.all_variablesFunction
all_variables(model::GenericModel{T})::Vector{GenericVariableRef{T}} where {T}

Returns a list of all variables currently in the model. The variables are ordered by creation time.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -384,12 +384,12 @@
 julia> all_variables(model)
 2-element Vector{VariableRef}:
  x
- y
source

anonymous_name

JuMP.anonymous_nameFunction
anonymous_name(::MIME, x::AbstractVariableRef)

The name to use for an anonymous variable x when printing.

Example

julia> model = Model();
+ y
source

anonymous_name

JuMP.anonymous_nameFunction
anonymous_name(::MIME, x::AbstractVariableRef)

The name to use for an anonymous variable x when printing.

Example

julia> model = Model();
 
 julia> x = @variable(model);
 
 julia> anonymous_name(MIME("text/plain"), x)
-"_[1]"
source

backend

JuMP.backendFunction
backend(model::GenericModel)

Return the lower-level MathOptInterface model that sits underneath JuMP. This model depends on which operating mode JuMP is in (see mode).

  • If JuMP is in DIRECT mode (that is, the model was created using direct_model), the backend will be the optimizer passed to direct_model.
  • If JuMP is in MANUAL or AUTOMATIC mode, the backend is a MOI.Utilities.CachingOptimizer.

Use index to get the index of a variable or constraint in the backend model.

Warning

This function should only be used by advanced users looking to access low-level MathOptInterface or solver-specific functionality.

Notes

If JuMP is not in DIRECT mode, the type returned by backend may change between any JuMP releases. Therefore, only use the public API exposed by MathOptInterface, and do not access internal fields. If you require access to the innermost optimizer, see unsafe_backend. Alternatively, use direct_model to create a JuMP model in DIRECT mode.

See also: unsafe_backend.

Example

julia> import HiGHS
+"_[1]"
source

backend

JuMP.backendFunction
backend(model::GenericModel)

Return the lower-level MathOptInterface model that sits underneath JuMP. This model depends on which operating mode JuMP is in (see mode).

  • If JuMP is in DIRECT mode (that is, the model was created using direct_model), the backend will be the optimizer passed to direct_model.
  • If JuMP is in MANUAL or AUTOMATIC mode, the backend is a MOI.Utilities.CachingOptimizer.

Use index to get the index of a variable or constraint in the backend model.

Warning

This function should only be used by advanced users looking to access low-level MathOptInterface or solver-specific functionality.

Notes

If JuMP is not in DIRECT mode, the type returned by backend may change between any JuMP releases. Therefore, only use the public API exposed by MathOptInterface, and do not access internal fields. If you require access to the innermost optimizer, see unsafe_backend. Alternatively, use direct_model to create a JuMP model in DIRECT mode.

See also: unsafe_backend.

Example

julia> import HiGHS
 
 julia> model = direct_model(HiGHS.Optimizer());
 
@@ -402,7 +402,7 @@
 A HiGHS model with 1 columns and 0 rows.
 
 julia> index(x)
-MOI.VariableIndex(1)
source

barrier_iterations

JuMP.barrier_iterationsFunction
barrier_iterations(model::GenericModel)

If available, returns the cumulative number of barrier iterations during the most-recent optimization (the MOI.BarrierIterations attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
+MOI.VariableIndex(1)
source

barrier_iterations

JuMP.barrier_iterationsFunction
barrier_iterations(model::GenericModel)

If available, returns the cumulative number of barrier iterations during the most-recent optimization (the MOI.BarrierIterations attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -411,7 +411,7 @@
 julia> optimize!(model)
 
 julia> barrier_iterations(model)
-0
source

bridge_constraints

JuMP.bridge_constraintsFunction
bridge_constraints(model::GenericModel)

When in direct mode, return false.

When in manual or automatic mode, return a Bool indicating whether the optimizer is set and unsupported constraints are automatically bridged to equivalent supported constraints when an appropriate transformation is available.

Example

julia> import Ipopt
+0
source

bridge_constraints

JuMP.bridge_constraintsFunction
bridge_constraints(model::GenericModel)

When in direct mode, return false.

When in manual or automatic mode, return a Bool indicating whether the optimizer is set and unsupported constraints are automatically bridged to equivalent supported constraints when an appropriate transformation is available.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -421,14 +421,14 @@
 julia> model = Model(Ipopt.Optimizer; add_bridges = false);
 
 julia> bridge_constraints(model)
-false
source

build_constraint

JuMP.build_constraintFunction
build_constraint(error_fn::Function, func, set, args...; kwargs...)

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

build_variable

build_constraint

JuMP.build_constraintFunction
build_constraint(error_fn::Function, func, set, args...; kwargs...)

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

build_variable

JuMP.build_variableFunction
build_variable(
     error_fn::Function,
     info::VariableInfo,
     args...;
     kwargs...,
 )

Return a new AbstractVariable object.

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

Arguments

  • error_fn: a function to call instead of error. error_fn annotates the error message with additional information for the user.
  • info: an instance of VariableInfo. This has a variety of fields relating to the variable such as info.lower_bound and info.binary.
  • args: optional additional positional arguments for extending the @variable macro.
  • kwargs: optional keyword arguments for extending the @variable macro.

See also: @variable

Warning

Extensions should define a method with ONE positional argument to dispatch the call to a different method. Creating an extension that relies on multiple positional arguments leads to MethodErrors if the user passes the arguments in the wrong order.

Example

@variable(model, x, Foo)

will call

build_variable(error_fn::Function, info::VariableInfo, ::Type{Foo})

Passing special-case positional arguments such as Bin, Int, and PSD is okay, along with keyword arguments:

@variable(model, x, Int, Foo(), mykwarg = true)
 # or
-@variable(model, x, Foo(), Int, mykwarg = true)

will call

build_variable(error_fn::Function, info::VariableInfo, ::Foo; mykwarg)

and info.integer will be true.

Note that the order of the positional arguments does not matter.

source

callback_node_status

JuMP.callback_node_statusFunction
callback_node_status(cb_data, model::GenericModel)

Return an MOI.CallbackNodeStatusCode enum, indicating if the current primal solution available from callback_value is integer feasible.

Example

julia> import GLPK
+@variable(model, x, Foo(), Int, mykwarg = true)

will call

build_variable(error_fn::Function, info::VariableInfo, ::Foo; mykwarg)

and info.integer will be true.

Note that the order of the positional arguments does not matter.

source

callback_node_status

JuMP.callback_node_statusFunction
callback_node_status(cb_data, model::GenericModel)

Return an MOI.CallbackNodeStatusCode enum, indicating if the current primal solution available from callback_value is integer feasible.

Example

julia> import GLPK
 
 julia> model = Model(GLPK.Optimizer);
 
@@ -449,7 +449,7 @@
 Status is: CALLBACK_NODE_STATUS_UNKNOWN
 Status is: CALLBACK_NODE_STATUS_UNKNOWN
 Status is: CALLBACK_NODE_STATUS_INTEGER
-Status is: CALLBACK_NODE_STATUS_INTEGER
source

callback_value

JuMP.callback_valueFunction
callback_value(cb_data, x::GenericVariableRef)
+Status is: CALLBACK_NODE_STATUS_INTEGER
source

callback_value

JuMP.callback_valueFunction
callback_value(cb_data, x::GenericVariableRef)
 callback_value(cb_data, x::Union{GenericAffExpr,GenericQuadExpr})

Return the primal solution of x inside a callback.

cb_data is the argument to the callback function, and the type is dependent on the solver.

Use callback_node_status to check whether a solution is available.

Example

julia> import GLPK
 
 julia> model = Model(GLPK.Optimizer);
@@ -471,7 +471,7 @@
 
 julia> optimize!(model)
 Solution is: 10.0
-Solution is: 10.0
source

check_belongs_to_model

check_belongs_to_model

JuMP.check_belongs_to_modelFunction
check_belongs_to_model(x::AbstractJuMPScalar, model::AbstractModel)
 check_belongs_to_model(x::AbstractConstraint, model::AbstractModel)

Throw VariableNotOwned if the owner_model of x is not model.

Example

julia> model = Model();
 
 julia> @variable(model, x);
@@ -483,7 +483,7 @@
 julia> check_belongs_to_model(x, model_2)
 ERROR: VariableNotOwned{VariableRef}(x): the variable x cannot be used in this model because
 it belongs to a different model.
-[...]
source

coefficient

JuMP.coefficientFunction
coefficient(v1::GenericVariableRef{T}, v2::GenericVariableRef{T}) where {T}

Return one(T) if v1 == v2 and zero(T) otherwise.

This is a fallback for other coefficient methods to simplify code in which the expression may be a single variable.

Example

julia> model = Model();
+[...]
source

coefficient

JuMP.coefficientFunction
coefficient(v1::GenericVariableRef{T}, v2::GenericVariableRef{T}) where {T}

Return one(T) if v1 == v2 and zero(T) otherwise.

This is a fallback for other coefficient methods to simplify code in which the expression may be a single variable.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -491,14 +491,14 @@
 1.0
 
 julia> coefficient(x[1], x[2])
-0.0
source
coefficient(a::GenericAffExpr{C,V}, v::V) where {C,V}

Return the coefficient associated with variable v in the affine expression a.

Example

julia> model = Model();
+0.0
source
coefficient(a::GenericAffExpr{C,V}, v::V) where {C,V}

Return the coefficient associated with variable v in the affine expression a.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> expr = 2.0 * x + 1.0;
 
 julia> coefficient(expr, x)
-2.0
source
coefficient(a::GenericQuadExpr{C,V}, v1::V, v2::V) where {C,V}

Return the coefficient associated with the term v1 * v2 in the quadratic expression a.

Note that coefficient(a, v1, v2) is the same as coefficient(a, v2, v1).

Example

julia> model = Model();
+2.0
source
coefficient(a::GenericQuadExpr{C,V}, v1::V, v2::V) where {C,V}

Return the coefficient associated with the term v1 * v2 in the quadratic expression a.

Note that coefficient(a, v1, v2) is the same as coefficient(a, v2, v1).

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -511,14 +511,14 @@
 2.0
 
 julia> coefficient(expr, x[1], x[1])
-0.0
source
coefficient(a::GenericQuadExpr{C,V}, v::V) where {C,V}

Return the coefficient associated with variable v in the affine component of a.

Example

julia> model = Model();
+0.0
source
coefficient(a::GenericQuadExpr{C,V}, v::V) where {C,V}

Return the coefficient associated with variable v in the affine component of a.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> expr = 2.0 * x^2 + 3.0 * x;
 
 julia> coefficient(expr, x)
-3.0
source

compute_conflict!

JuMP.compute_conflict!Function
compute_conflict!(model::GenericModel)

Compute a conflict if the model is infeasible.

The conflict is also called the Irreducible Infeasible Subsystem (IIS).

If an optimizer has not been set yet (see set_optimizer), a NoOptimizer error is thrown.

The status of the conflict can be checked with the MOI.ConflictStatus model attribute. Then, the status for each constraint can be queried with the MOI.ConstraintConflictStatus attribute.

See also: copy_conflict

Example

julia> using JuMP
+3.0
source

compute_conflict!

JuMP.compute_conflict!Function
compute_conflict!(model::GenericModel)

Compute a conflict if the model is infeasible.

The conflict is also called the Irreducible Infeasible Subsystem (IIS).

If an optimizer has not been set yet (see set_optimizer), a NoOptimizer error is thrown.

The status of the conflict can be checked with the MOI.ConflictStatus model attribute. Then, the status for each constraint can be queried with the MOI.ConstraintConflictStatus attribute.

See also: copy_conflict

Example

julia> using JuMP
 
 julia> model = Model(Gurobi.Optimizer);
 
@@ -535,21 +535,21 @@
 julia> compute_conflict!(model)
 
 julia> get_attribute(model, MOI.ConflictStatus())
-CONFLICT_FOUND::ConflictStatusCode = 3
source

constant

JuMP.constantFunction
constant(aff::GenericAffExpr{C,V})::C

Return the constant of the affine expression.

Example

julia> model = Model();
+CONFLICT_FOUND::ConflictStatusCode = 3
source

constant

JuMP.constantFunction
constant(aff::GenericAffExpr{C,V})::C

Return the constant of the affine expression.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> aff = 2.0 * x + 3.0;
 
 julia> constant(aff)
-3.0
source
constant(quad::GenericQuadExpr{C,V})::C

Return the constant of the quadratic expression.

Example

julia> model = Model();
+3.0
source
constant(quad::GenericQuadExpr{C,V})::C

Return the constant of the quadratic expression.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> quad = 2.0 * x^2 + 3.0;
 
 julia> constant(quad)
-3.0
source

constraint_by_name

JuMP.constraint_by_nameFunction
constraint_by_name(model::AbstractModel, name::String, [F, S])::Union{ConstraintRef,Nothing}

Return the reference of the constraint with name attribute name or Nothing if no constraint has this name attribute.

Throws an error if several constraints have name as their name attribute.

If F and S are provided, this method addititionally throws an error if the constraint is not an F-in-S contraint where F is either the JuMP or MOI type of the function and S is the MOI type of the set.

Providing F and S is recommended if you know the type of the function and set since its returned type can be inferred while for the method above (that is, without F and S), the exact return type of the constraint index cannot be inferred.

Example

julia> model = Model();
+3.0
source

constraint_by_name

JuMP.constraint_by_nameFunction
constraint_by_name(model::AbstractModel, name::String, [F, S])::Union{ConstraintRef,Nothing}

Return the reference of the constraint with name attribute name or Nothing if no constraint has this name attribute.

Throws an error if several constraints have name as their name attribute.

If F and S are provided, this method addititionally throws an error if the constraint is not an F-in-S contraint where F is either the JuMP or MOI type of the function and S is the MOI type of the set.

Providing F and S is recommended if you know the type of the function and set since its returned type can be inferred while for the method above (that is, without F and S), the exact return type of the constraint index cannot be inferred.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -565,7 +565,7 @@
 julia> constraint_by_name(model, "con", AffExpr, MOI.EqualTo{Float64})
 
 julia> constraint_by_name(model, "con", QuadExpr, MOI.EqualTo{Float64})
-con : x² = 1
source

constraint_object

JuMP.constraint_objectFunction
constraint_object(con_ref::ConstraintRef)

Return the underlying constraint data for the constraint referenced by con_ref.

Example

A scalar constraint:

julia> model = Model();
+con : x² = 1
source

constraint_object

JuMP.constraint_objectFunction
constraint_object(con_ref::ConstraintRef)

Return the underlying constraint data for the constraint referenced by con_ref.

Example

A scalar constraint:

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -602,7 +602,7 @@
  x[3]
 
 julia> object.set
-MathOptInterface.SecondOrderCone(3)
source

constraint_ref_with_index

JuMP.constraint_ref_with_indexFunction
constraint_ref_with_index(model::AbstractModel, index::MOI.ConstraintIndex)

Return a ConstraintRef of model corresponding to index.

This function is a helper function used internally by JuMP and some JuMP extensions. It should not need to be called in user-code.

source

constraint_string

constraint_ref_with_index

JuMP.constraint_ref_with_indexFunction
constraint_ref_with_index(model::AbstractModel, index::MOI.ConstraintIndex)

Return a ConstraintRef of model corresponding to index.

This function is a helper function used internally by JuMP and some JuMP extensions. It should not need to be called in user-code.

source

constraint_string

JuMP.constraint_stringFunction
constraint_string(
     mode::MIME,
     ref::ConstraintRef;
     in_math_mode::Bool = false,
@@ -613,7 +613,7 @@
 julia> @constraint(model, c, 2 * x <= 1);
 
 julia> constraint_string(MIME("text/plain"), c)
-"c : 2 x ≤ 1"
source

constraints_string

JuMP.constraints_stringFunction
constraints_string(mode, model::AbstractModel)::Vector{String}

Return a list of Strings describing each constraint of the model.

Example

julia> model = Model();
+"c : 2 x ≤ 1"
source

constraints_string

JuMP.constraints_stringFunction
constraints_string(mode, model::AbstractModel)::Vector{String}

Return a list of Strings describing each constraint of the model.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0);
 
@@ -622,7 +622,7 @@
 julia> constraints_string(MIME("text/plain"), model)
 2-element Vector{String}:
  "c : 2 x ≤ 1"
- "x ≥ 0"
source

copy_conflict

JuMP.copy_conflictFunction
copy_conflict(model::GenericModel)

Return a copy of the current conflict for the model model and a GenericReferenceMap that can be used to obtain the variable and constraint reference of the new model corresponding to a given model's reference.

This is a convenience function that provides a filtering function for copy_model.

Note

Model copy is not supported in DIRECT mode, that is, when a model is constructed using the direct_model constructor instead of the Model constructor. Moreover, independently on whether an optimizer was provided at model construction, the new model will have no optimizer, that is, an optimizer will have to be provided to the new model in the optimize! call.

Example

In the following example, a model model is constructed with a variable x and two constraints c1 and c2. This model has no solution, as the two constraints are mutually exclusive. The solver is asked to compute a conflict with compute_conflict!. The parts of model participating in the conflict are then copied into a model iis_model.

julia> using JuMP
+ "x ≥ 0"
source

copy_conflict

JuMP.copy_conflictFunction
copy_conflict(model::GenericModel)

Return a copy of the current conflict for the model model and a GenericReferenceMap that can be used to obtain the variable and constraint reference of the new model corresponding to a given model's reference.

This is a convenience function that provides a filtering function for copy_model.

Note

Model copy is not supported in DIRECT mode, that is, when a model is constructed using the direct_model constructor instead of the Model constructor. Moreover, independently on whether an optimizer was provided at model construction, the new model will have no optimizer, that is, an optimizer will have to be provided to the new model in the optimize! call.

Example

In the following example, a model model is constructed with a variable x and two constraints c1 and c2. This model has no solution, as the two constraints are mutually exclusive. The solver is asked to compute a conflict with compute_conflict!. The parts of model participating in the conflict are then copied into a model iis_model.

julia> using JuMP
 
 julia> import Gurobi
 
@@ -650,7 +650,7 @@
 Feasibility
 Subject to
  c1 : x ≥ 2
- c2 : x ≤ 1
source

copy_extension_data

JuMP.copy_extension_dataFunction
copy_extension_data(data, new_model::AbstractModel, model::AbstractModel)

Return a copy of the extension data data of the model model to the extension data of the new model new_model.

A method should be added for any JuMP extension storing data in the ext field.

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

Warning

Do not engage in type piracy by implementing this method for types of data that you did not define! JuMP extensions should store types that they define in model.ext, rather than regular Julia types.

source

copy_model

JuMP.copy_modelFunction
copy_model(model::GenericModel; filter_constraints::Union{Nothing, Function}=nothing)

Return a copy of the model model and a GenericReferenceMap that can be used to obtain the variable and constraint reference of the new model corresponding to a given model's reference. A Base.copy(::AbstractModel) method has also been implemented, it is similar to copy_model but does not return the reference map.

If the filter_constraints argument is given, only the constraints for which this function returns true will be copied. This function is given a constraint reference as argument.

Note

Model copy is not supported in DIRECT mode, that is, when a model is constructed using the direct_model constructor instead of the Model constructor. Moreover, independently on whether an optimizer was provided at model construction, the new model will have no optimizer, that is, an optimizer will have to be provided to the new model in the optimize! call.

Example

In the following example, a model model is constructed with a variable x and a constraint cref. It is then copied into a model new_model with the new references assigned to x_new and cref_new.

julia> model = Model();
+ c2 : x ≤ 1
source

copy_extension_data

JuMP.copy_extension_dataFunction
copy_extension_data(data, new_model::AbstractModel, model::AbstractModel)

Return a copy of the extension data data of the model model to the extension data of the new model new_model.

A method should be added for any JuMP extension storing data in the ext field.

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

Warning

Do not engage in type piracy by implementing this method for types of data that you did not define! JuMP extensions should store types that they define in model.ext, rather than regular Julia types.

source

copy_model

JuMP.copy_modelFunction
copy_model(model::GenericModel; filter_constraints::Union{Nothing, Function}=nothing)

Return a copy of the model model and a GenericReferenceMap that can be used to obtain the variable and constraint reference of the new model corresponding to a given model's reference. A Base.copy(::AbstractModel) method has also been implemented, it is similar to copy_model but does not return the reference map.

If the filter_constraints argument is given, only the constraints for which this function returns true will be copied. This function is given a constraint reference as argument.

Note

Model copy is not supported in DIRECT mode, that is, when a model is constructed using the direct_model constructor instead of the Model constructor. Moreover, independently on whether an optimizer was provided at model construction, the new model will have no optimizer, that is, an optimizer will have to be provided to the new model in the optimize! call.

Example

In the following example, a model model is constructed with a variable x and a constraint cref. It is then copied into a model new_model with the new references assigned to x_new and cref_new.

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -664,7 +664,7 @@
 x
 
 julia> cref_new = reference_map[cref]
-cref : x = 2
source

delete

JuMP.deleteFunction
delete(model::GenericModel, con_ref::ConstraintRef)

Delete the constraint associated with constraint_ref from the model model.

Note that delete does not unregister the name from the model, so adding a new constraint of the same name will throw an error. Use unregister to unregister the name after deletion.

Example

julia> model = Model();
+cref : x = 2
source

delete

JuMP.deleteFunction
delete(model::GenericModel, con_ref::ConstraintRef)

Delete the constraint associated with constraint_ref from the model model.

Note that delete does not unregister the name from the model, so adding a new constraint of the same name will throw an error. Use unregister to unregister the name after deletion.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -682,7 +682,7 @@
 julia> model[:c]
 ERROR: KeyError: key :c not found
 Stacktrace:
-[...]
source
delete(model::GenericModel, con_refs::Vector{<:ConstraintRef})

Delete the constraints associated with con_refs from the model model.

Solvers may implement specialized methods for deleting multiple constraints of the same concrete type. These methods may be more efficient than repeatedly calling the single constraint delete method.

See also: unregister

Example

julia> model = Model();
+[...]
source
delete(model::GenericModel, con_refs::Vector{<:ConstraintRef})

Delete the constraints associated with con_refs from the model model.

Solvers may implement specialized methods for deleting multiple constraints of the same concrete type. These methods may be more efficient than repeatedly calling the single constraint delete method.

See also: unregister

Example

julia> model = Model();
 
 julia> @variable(model, x[1:3]);
 
@@ -703,7 +703,7 @@
 julia> model[:c]
 ERROR: KeyError: key :c not found
 Stacktrace:
-[...]
source
delete(model::GenericModel, variable_ref::GenericVariableRef)

Delete the variable associated with variable_ref from the model model.

Note that delete does not unregister the name from the model, so adding a new variable of the same name will throw an error. Use unregister to unregister the name after deletion.

Example

julia> model = Model();
+[...]
source
delete(model::GenericModel, variable_ref::GenericVariableRef)

Delete the variable associated with variable_ref from the model model.

Note that delete does not unregister the name from the model, so adding a new variable of the same name will throw an error. Use unregister to unregister the name after deletion.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -719,7 +719,7 @@
 julia> model[:x]
 ERROR: KeyError: key :x not found
 Stacktrace:
-[...]
source
delete(model::GenericModel, variable_refs::Vector{<:GenericVariableRef})

Delete the variables associated with variable_refs from the model model. Solvers may implement methods for deleting multiple variables that are more efficient than repeatedly calling the single variable delete method.

See also: unregister

Example

julia> model = Model();
+[...]
source
delete(model::GenericModel, variable_refs::Vector{<:GenericVariableRef})

Delete the variables associated with variable_refs from the model model. Solvers may implement methods for deleting multiple variables that are more efficient than repeatedly calling the single variable delete method.

See also: unregister

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -734,7 +734,7 @@
 julia> model[:x]
 ERROR: KeyError: key :x not found
 Stacktrace:
-[...]
source

delete_lower_bound

delete_lower_bound

delete_upper_bound

delete_upper_bound

direct_generic_model

direct_generic_model

JuMP.direct_generic_modelFunction
direct_generic_model(
     value_type::Type{T},
     backend::MOI.ModelLike;
-) where {T<:Real}

Return a new JuMP model using backend to store the model and solve it.

As opposed to the Model constructor, no cache of the model is stored outside of backend and no bridges are automatically applied to backend.

Notes

The absence of a cache reduces the memory footprint but, it is important to bear in mind the following implications of creating models using this direct mode:

  • When backend does not support an operation, such as modifying constraints or adding variables/constraints after solving, an error is thrown. For models created using the Model constructor, such situations can be dealt with by storing the modifications in a cache and loading them into the optimizer when optimize! is called.
  • No constraint bridging is supported by default.
  • The optimizer used cannot be changed the model is constructed.
  • The model created cannot be copied.
source
direct_generic_model(::Type{T}, factory::MOI.OptimizerWithAttributes)

Create a direct_generic_model using factory, a MOI.OptimizerWithAttributes object created by optimizer_with_attributes.

Example

julia> import HiGHS
+) where {T<:Real}

Return a new JuMP model using backend to store the model and solve it.

As opposed to the Model constructor, no cache of the model is stored outside of backend and no bridges are automatically applied to backend.

Notes

The absence of a cache reduces the memory footprint but, it is important to bear in mind the following implications of creating models using this direct mode:

  • When backend does not support an operation, such as modifying constraints or adding variables/constraints after solving, an error is thrown. For models created using the Model constructor, such situations can be dealt with by storing the modifications in a cache and loading them into the optimizer when optimize! is called.
  • No constraint bridging is supported by default.
  • The optimizer used cannot be changed the model is constructed.
  • The model created cannot be copied.
source
direct_generic_model(::Type{T}, factory::MOI.OptimizerWithAttributes)

Create a direct_generic_model using factory, a MOI.OptimizerWithAttributes object created by optimizer_with_attributes.

Example

julia> import HiGHS
 
 julia> optimizer = optimizer_with_attributes(
            HiGHS.Optimizer,
@@ -785,7 +785,7 @@
 
 julia> set_attribute(model, "presolve", "off")
 
-julia> set_attribute(model, MOI.Silent(), true)
source

direct_model

JuMP.direct_modelFunction
direct_model(backend::MOI.ModelLike)

Return a new JuMP model using backend to store the model and solve it.

As opposed to the Model constructor, no cache of the model is stored outside of backend and no bridges are automatically applied to backend.

Notes

The absence of a cache reduces the memory footprint but, it is important to bear in mind the following implications of creating models using this direct mode:

  • When backend does not support an operation, such as modifying constraints or adding variables/constraints after solving, an error is thrown. For models created using the Model constructor, such situations can be dealt with by storing the modifications in a cache and loading them into the optimizer when optimize! is called.
  • No constraint bridging is supported by default.
  • The optimizer used cannot be changed the model is constructed.
  • The model created cannot be copied.
source
direct_model(factory::MOI.OptimizerWithAttributes)

Create a direct_model using factory, a MOI.OptimizerWithAttributes object created by optimizer_with_attributes.

Example

julia> import HiGHS
+julia> set_attribute(model, MOI.Silent(), true)
source

direct_model

JuMP.direct_modelFunction
direct_model(backend::MOI.ModelLike)

Return a new JuMP model using backend to store the model and solve it.

As opposed to the Model constructor, no cache of the model is stored outside of backend and no bridges are automatically applied to backend.

Notes

The absence of a cache reduces the memory footprint but, it is important to bear in mind the following implications of creating models using this direct mode:

  • When backend does not support an operation, such as modifying constraints or adding variables/constraints after solving, an error is thrown. For models created using the Model constructor, such situations can be dealt with by storing the modifications in a cache and loading them into the optimizer when optimize! is called.
  • No constraint bridging is supported by default.
  • The optimizer used cannot be changed the model is constructed.
  • The model created cannot be copied.
source
direct_model(factory::MOI.OptimizerWithAttributes)

Create a direct_model using factory, a MOI.OptimizerWithAttributes object created by optimizer_with_attributes.

Example

julia> import HiGHS
 
 julia> optimizer = optimizer_with_attributes(
            HiGHS.Optimizer,
@@ -813,7 +813,7 @@
 
 julia> set_attribute(model, "presolve", "off")
 
-julia> set_attribute(model, MOI.Silent(), true)
source

drop_zeros!

JuMP.drop_zeros!Function
drop_zeros!(expr::GenericAffExpr)

Remove terms in the affine expression with 0 coefficients.

Example

julia> model = Model();
+julia> set_attribute(model, MOI.Silent(), true)
source

drop_zeros!

JuMP.drop_zeros!Function
drop_zeros!(expr::GenericAffExpr)

Remove terms in the affine expression with 0 coefficients.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -825,7 +825,7 @@
 julia> drop_zeros!(expr)
 
 julia> expr
-x[2]
source
drop_zeros!(expr::GenericQuadExpr)

Remove terms in the quadratic expression with 0 coefficients.

Example

julia> model = Model();
+x[2]
source
drop_zeros!(expr::GenericQuadExpr)

Remove terms in the quadratic expression with 0 coefficients.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -837,7 +837,7 @@
 julia> drop_zeros!(expr)
 
 julia> expr
-x[2]²
source

dual

JuMP.dualFunction
dual(con_ref::ConstraintRef; result::Int = 1)

Return the dual value of constraint con_ref associated with result index result of the most-recent solution returned by the solver.

Use has_duals to check if a result exists before asking for values.

See also: result_count, shadow_price.

Example

julia> import HiGHS
+x[2]²
source

dual

JuMP.dualFunction
dual(con_ref::ConstraintRef; result::Int = 1)

Return the dual value of constraint con_ref associated with result index result of the most-recent solution returned by the solver.

Use has_duals to check if a result exists before asking for values.

See also: result_count, shadow_price.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -856,7 +856,7 @@
 true
 
 julia> dual(c)
--2.0
source

dual_objective_value

JuMP.dual_objective_valueFunction
dual_objective_value(model::GenericModel; result::Int = 1)

Return the value of the objective of the dual problem associated with result index result of the most-recent solution returned by the solver.

Throws MOI.UnsupportedAttribute{MOI.DualObjectiveValue} if the solver does not support this attribute.

This function is equivalent to querying the MOI.DualObjectiveValue attribute.

See also: result_count.

Example

julia> import HiGHS
+-2.0
source

dual_objective_value

JuMP.dual_objective_valueFunction
dual_objective_value(model::GenericModel; result::Int = 1)

Return the value of the objective of the dual problem associated with result index result of the most-recent solution returned by the solver.

Throws MOI.UnsupportedAttribute{MOI.DualObjectiveValue} if the solver does not support this attribute.

This function is equivalent to querying the MOI.DualObjectiveValue attribute.

See also: result_count.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -874,7 +874,7 @@
 julia> dual_objective_value(model; result = 2)
 ERROR: Result index of attribute MathOptInterface.DualObjectiveValue(2) out of bounds. There are currently 1 solution(s) in the model.
 Stacktrace:
-[...]
source

dual_shape

JuMP.dual_shapeFunction
dual_shape(shape::AbstractShape)::AbstractShape

Returns the shape of the dual space of the space of objects of shape shape. By default, the dual_shape of a shape is itself. See the examples section below for an example for which this is not the case.

Example

Consider polynomial constraints for which the dual is moment constraints and moment constraints for which the dual is polynomial constraints. Shapes for polynomials can be defined as follows:

struct Polynomial
+[...]
source

dual_shape

JuMP.dual_shapeFunction
dual_shape(shape::AbstractShape)::AbstractShape

Returns the shape of the dual space of the space of objects of shape shape. By default, the dual_shape of a shape is itself. See the examples section below for an example for which this is not the case.

Example

Consider polynomial constraints for which the dual is moment constraints and moment constraints for which the dual is polynomial constraints. Shapes for polynomials can be defined as follows:

struct Polynomial
     coefficients::Vector{Float64}
     monomials::Vector{Monomial}
 end
@@ -889,7 +889,7 @@
     monomials::Vector{Monomial}
 end
 JuMP.reshape_vector(x::Vector, shape::MomentsShape) = Moments(x, shape.monomials)

Then dual_shape allows the definition of the shape of the dual of polynomial and moment constraints:

dual_shape(shape::PolynomialShape) = MomentsShape(shape.monomials)
-dual_shape(shape::MomentsShape) = PolynomialShape(shape.monomials)
source

dual_start_value

JuMP.dual_start_valueFunction
dual_start_value(con_ref::ConstraintRef)

Return the dual start value (MOI attribute ConstraintDualStart) of the constraint con_ref.

If no dual start value has been set, dual_start_value will return nothing.

See also set_dual_start_value.

Example

julia> model = Model();
+dual_shape(shape::MomentsShape) = PolynomialShape(shape.monomials)
source

dual_start_value

JuMP.dual_start_valueFunction
dual_start_value(con_ref::ConstraintRef)

Return the dual start value (MOI attribute ConstraintDualStart) of the constraint con_ref.

If no dual start value has been set, dual_start_value will return nothing.

See also set_dual_start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 2.0);
 
@@ -904,19 +904,19 @@
 
 julia> set_dual_start_value(c, nothing)
 
-julia> dual_start_value(c)
source

dual_status

JuMP.dual_statusFunction
dual_status(model::GenericModel; result::Int = 1)

Return a MOI.ResultStatusCode describing the status of the most recent dual solution of the solver (that is, the MOI.DualStatus attribute) associated with the result index result.

See also: result_count.

Example

julia> import Ipopt
+julia> dual_start_value(c)
source

dual_status

JuMP.dual_statusFunction
dual_status(model::GenericModel; result::Int = 1)

Return a MOI.ResultStatusCode describing the status of the most recent dual solution of the solver (that is, the MOI.DualStatus attribute) associated with the result index result.

See also: result_count.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
 julia> dual_status(model; result = 2)
-NO_SOLUTION::ResultStatusCode = 0
source

error_if_direct_mode

JuMP.error_if_direct_modeFunction
error_if_direct_mode(model::GenericModel, func::Symbol)

Errors if model is in direct mode during a call from the function named func.

Used internally within JuMP, or by JuMP extensions who do not want to support models in direct mode.

Example

julia> import HiGHS
+NO_SOLUTION::ResultStatusCode = 0
source

error_if_direct_mode

JuMP.error_if_direct_modeFunction
error_if_direct_mode(model::GenericModel, func::Symbol)

Errors if model is in direct mode during a call from the function named func.

Used internally within JuMP, or by JuMP extensions who do not want to support models in direct mode.

Example

julia> import HiGHS
 
 julia> model = direct_model(HiGHS.Optimizer());
 
 julia> error_if_direct_mode(model, :foo)
 ERROR: The `foo` function is not supported in DIRECT mode.
 Stacktrace:
-[...]
source

fix

JuMP.fixFunction
fix(v::GenericVariableRef, value::Number; force::Bool = false)

Fix a variable to a value. Update the fixing constraint if one exists, otherwise create a new one.

If the variable already has variable bounds and force=false, calling fix will throw an error. If force=true, existing variable bounds will be deleted, and the fixing constraint will be added. Note a variable will have no bounds after a call to unfix.

See also FixRef, is_fixed, fix_value, unfix.

Example

julia> model = Model();
+[...]
source

fix

JuMP.fixFunction
fix(v::GenericVariableRef, value::Number; force::Bool = false)

Fix a variable to a value. Update the fixing constraint if one exists, otherwise create a new one.

If the variable already has variable bounds and force=false, calling fix will throw an error. If force=true, existing variable bounds will be deleted, and the fixing constraint will be added. Note a variable will have no bounds after a call to unfix.

See also FixRef, is_fixed, fix_value, unfix.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -936,7 +936,7 @@
 julia> fix(x, 1.0; force = true)
 
 julia> is_fixed(x)
-true
source

fix_discrete_variables

JuMP.fix_discrete_variablesFunction
fix_discrete_variables([var_value::Function = value,] model::GenericModel)

Modifies model to convert all binary and integer variables to continuous variables with fixed bounds of var_value(x).

Return

Returns a function that can be called without any arguments to restore the original model. The behavior of this function is undefined if additional changes are made to the affected variables in the meantime.

Notes

  • An error is thrown if semi-continuous or semi-integer constraints are present (support may be added for these in the future).
  • All other constraints are ignored (left in place). This includes discrete constraints like SOS and indicator constraints.

Example

julia> model = Model();
+true
source

fix_discrete_variables

JuMP.fix_discrete_variablesFunction
fix_discrete_variables([var_value::Function = value,] model::GenericModel)

Modifies model to convert all binary and integer variables to continuous variables with fixed bounds of var_value(x).

Return

Returns a function that can be called without any arguments to restore the original model. The behavior of this function is undefined if additional changes are made to the affected variables in the meantime.

Notes

  • An error is thrown if semi-continuous or semi-integer constraints are present (support may be added for these in the future).
  • All other constraints are ignored (left in place). This includes discrete constraints like SOS and indicator constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x, Bin, start = 1);
 
@@ -960,12 +960,12 @@
  y ≥ 1
  y ≤ 10
  y integer
- x binary
source

fix_value

JuMP.fix_valueFunction
fix_value(v::GenericVariableRef)

Return the value to which a variable is fixed.

Error if one does not exist.

See also FixRef, is_fixed, fix, unfix.

Example

julia> model = Model();
+ x binary
source

fix_value

JuMP.fix_valueFunction
fix_value(v::GenericVariableRef)

Return the value to which a variable is fixed.

Error if one does not exist.

See also FixRef, is_fixed, fix, unfix.

Example

julia> model = Model();
 
 julia> @variable(model, x == 1);
 
 julia> fix_value(x)
-1.0
source

flatten!

JuMP.flatten!Function
flatten!(expr::GenericNonlinearExpr)

Flatten a nonlinear expression in-place by lifting nested + and * nodes into a single n-ary operation.

Motivation

Nonlinear expressions created using operator overloading can be deeply nested and unbalanced. For example, prod(x for i in 1:4) creates *(x, *(x, *(x, x))) instead of the more preferable *(x, x, x, x).

Example

julia> model = Model();
+1.0
source

flatten!

JuMP.flatten!Function
flatten!(expr::GenericNonlinearExpr)

Flatten a nonlinear expression in-place by lifting nested + and * nodes into a single n-ary operation.

Motivation

Nonlinear expressions created using operator overloading can be deeply nested and unbalanced. For example, prod(x for i in 1:4) creates *(x, *(x, *(x, x))) instead of the more preferable *(x, x, x, x).

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -977,7 +977,7 @@
 (x²) * x * x
 
 julia> flatten!(sin(prod(x for i in 1:4)))
-sin((x²) * x * x)
source

function_string

function_string

JuMP.function_stringFunction
function_string(
     mode::MIME,
     func::Union{JuMP.AbstractJuMPScalar,Vector{<:JuMP.AbstractJuMPScalar}},
 )

Return a String representing the function func using print mode mode.

Example

julia> model = Model();
@@ -985,7 +985,7 @@
 julia> @variable(model, x);
 
 julia> function_string(MIME("text/plain"), 2 * x + 1)
-"2 x + 1"
source

get_attribute

get_attribute

JuMP.get_attributeFunction
get_attribute(model::GenericModel, attr::MOI.AbstractModelAttribute)
 get_attribute(x::GenericVariableRef, attr::MOI.AbstractVariableAttribute)
 get_attribute(cr::ConstraintRef, attr::MOI.AbstractConstraintAttribute)

Get the value of a solver-specifc attribute attr.

This is equivalent to calling MOI.get with the associated MOI model and, for variables and constraints, with the associated MOI.VariableIndex or MOI.ConstraintIndex.

Example

julia> model = Model();
 
@@ -1002,7 +1002,7 @@
 "x"
 
 julia> get_attribute(c, MOI.ConstraintName())
-"c"
source
get_attribute(
+"c"
source
get_attribute(
     model::Union{GenericModel,MOI.OptimizerWithAttributes},
     attr::Union{AbstractString,MOI.AbstractOptimizerAttribute},
 )

Get the value of a solver-specifc attribute attr.

This is equivalent to calling MOI.get with the associated MOI model.

If attr is an AbstractString, it is converted to MOI.RawOptimizerAttribute.

Example

julia> import HiGHS
@@ -1021,7 +1021,7 @@
 true
 
 julia> get_attribute(opt, MOI.RawOptimizerAttribute("output_flag"))
-true
source

has_duals

JuMP.has_dualsFunction
has_duals(model::GenericModel; result::Int = 1)

Return true if the solver has a dual solution in result index result available to query, otherwise return false.

See also dual, shadow_price, and result_count.

Example

julia> import HiGHS
+true
source

has_duals

JuMP.has_dualsFunction
has_duals(model::GenericModel; result::Int = 1)

Return true if the solver has a dual solution in result index result available to query, otherwise return false.

See also dual, shadow_price, and result_count.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1040,12 +1040,12 @@
 julia> optimize!(model)
 
 julia> has_duals(model)
-true
source

has_lower_bound

has_lower_bound

has_start_value

has_start_value

JuMP.has_start_valueFunction
has_start_value(variable::AbstractVariableRef)

Return true if the variable has a start value set, otherwise return false.

See also: start_value, set_start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 1.5);
 
@@ -1066,12 +1066,12 @@
 true
 
 julia> start_value(y)
-2.0
source

has_upper_bound

has_upper_bound

has_values

JuMP.has_valuesFunction
has_values(model::GenericModel; result::Int = 1)

Return true if the solver has a primal solution in result index result available to query, otherwise return false.

See also value and result_count.

Example

julia> import HiGHS
+true
source

has_values

JuMP.has_valuesFunction
has_values(model::GenericModel; result::Int = 1)

Return true if the solver has a primal solution in result index result available to query, otherwise return false.

See also value and result_count.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1090,25 +1090,25 @@
 julia> optimize!(model)
 
 julia> has_values(model)
-true
source

in_set_string

JuMP.in_set_stringFunction
in_set_string(mode::MIME, set)

Return a String representing the membership to the set set using print mode mode.

Extensions

JuMP extensions may extend this method for new set types to improve the legibility of their printing.

Example

julia> in_set_string(MIME("text/plain"), MOI.Interval(1.0, 2.0))
-"∈ [1, 2]"
source

index

JuMP.indexFunction
index(cr::ConstraintRef)::MOI.ConstraintIndex

Return the index of the constraint that corresponds to cr in the MOI backend.

Example

julia> model = Model();
+true
source

in_set_string

JuMP.in_set_stringFunction
in_set_string(mode::MIME, set)

Return a String representing the membership to the set set using print mode mode.

Extensions

JuMP extensions may extend this method for new set types to improve the legibility of their printing.

Example

julia> in_set_string(MIME("text/plain"), MOI.Interval(1.0, 2.0))
+"∈ [1, 2]"
source

index

JuMP.indexFunction
index(cr::ConstraintRef)::MOI.ConstraintIndex

Return the index of the constraint that corresponds to cr in the MOI backend.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> @constraint(model, c, x >= 0);
 
 julia> index(c)
-MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}(1)
source
index(v::GenericVariableRef)::MOI.VariableIndex

Return the index of the variable that corresponds to v in the MOI backend.

Example

julia> model = Model();
+MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}(1)
source
index(v::GenericVariableRef)::MOI.VariableIndex

Return the index of the variable that corresponds to v in the MOI backend.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> index(x)
-MOI.VariableIndex(1)
source

is_binary

is_binary

is_fixed

is_fixed

JuMP.is_fixedFunction
is_fixed(v::GenericVariableRef)

Return true if v is a fixed variable. If true, the fixed value can be queried with fix_value.

See also FixRef, fix_value, fix, unfix.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1118,7 +1118,7 @@
 julia> fix(x, 1.0)
 
 julia> is_fixed(x)
-true
source

is_integer

is_integer

JuMP.is_integerFunction
is_integer(v::GenericVariableRef)

Return true if v is constrained to be integer.

See also IntegerRef, set_integer, unset_integer.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1128,7 +1128,7 @@
 julia> set_integer(x)
 
 julia> is_integer(x)
-true
source

is_parameter

is_parameter

is_solved_and_feasible

is_solved_and_feasible

JuMP.is_solved_and_feasibleFunction
is_solved_and_feasible(
     model::GenericModel;
     allow_local::Bool = true,
     allow_almost::Bool = false,
@@ -1151,7 +1151,7 @@
 julia> model = Model(Ipopt.Optimizer);
 
 julia> is_solved_and_feasible(model)
-false
source

is_valid

JuMP.is_validFunction
is_valid(model::GenericModel, con_ref::ConstraintRef{<:AbstractModel})

Return true if con_ref refers to a valid constraint in model.

Example

julia> model = Model();
+false
source

is_valid

JuMP.is_validFunction
is_valid(model::GenericModel, con_ref::ConstraintRef{<:AbstractModel})

Return true if con_ref refers to a valid constraint in model.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1163,7 +1163,7 @@
 julia> model_2 = Model();
 
 julia> is_valid(model_2, c)
-false
source
is_valid(model::GenericModel, variable_ref::GenericVariableRef)

Return true if variable refers to a valid variable in model.

Example

julia> model = Model();
+false
source
is_valid(model::GenericModel, variable_ref::GenericVariableRef)

Return true if variable refers to a valid variable in model.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1173,7 +1173,7 @@
 julia> model_2 = Model();
 
 julia> is_valid(model_2, x)
-false
source

isequal_canonical

isequal_canonical

JuMP.isequal_canonicalFunction
isequal_canonical(
     x::T,
     y::T
 ) where {T<:AbstractJuMPScalar,AbstractArray{<:AbstractJuMPScalar}}

Return true if x is equal to y after dropping zeros and disregarding the order.

This method is mainly useful for testing, because fallbacks like x == y do not account for valid mathematical comparisons like x[1] + 0 x[2] + 1 == x[1] + 1.

Example

julia> model = Model();
@@ -1193,7 +1193,7 @@
 false
 
 julia> isequal_canonical(a, b)
-true
source

jump_function

JuMP.jump_functionFunction
jump_function(model::AbstractModel, x::MOI.AbstractFunction)

Given an MathOptInterface object x, return the JuMP equivalent.

See also: moi_function.

Example

julia> model = Model();
+true
source

jump_function

JuMP.jump_functionFunction
jump_function(model::AbstractModel, x::MOI.AbstractFunction)

Given an MathOptInterface object x, return the JuMP equivalent.

See also: moi_function.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1201,10 +1201,10 @@
 1.0 + 2.0 MOI.VariableIndex(1)
 
 julia> jump_function(model, f)
-2 x + 1
source

jump_function_type

JuMP.jump_function_typeFunction
jump_function_type(model::AbstractModel, ::Type{T}) where {T}

Given an MathOptInterface object type T, return the JuMP equivalent.

See also: moi_function_type.

Example

julia> model = Model();
+2 x + 1
source

jump_function_type

JuMP.jump_function_typeFunction
jump_function_type(model::AbstractModel, ::Type{T}) where {T}

Given an MathOptInterface object type T, return the JuMP equivalent.

See also: moi_function_type.

Example

julia> model = Model();
 
 julia> jump_function_type(model, MOI.ScalarAffineFunction{Float64})
-AffExpr (alias for GenericAffExpr{Float64, GenericVariableRef{Float64}})
source

latex_formulation

JuMP.latex_formulationFunction
latex_formulation(model::AbstractModel)

Wrap model in a type so that it can be pretty-printed as text/latex in a notebook like IJulia, or in Documenter.

To render the model, end the cell with latex_formulation(model), or call display(latex_formulation(model)) in to force the display of the model from inside a function.

source

linear_terms

JuMP.linear_termsFunction
linear_terms(aff::GenericAffExpr{C,V})

Provides an iterator over coefficient-variable tuples (a_i::C, x_i::V) in the linear part of the affine expression.

source
linear_terms(quad::GenericQuadExpr{C,V})

Provides an iterator over tuples (coefficient::C, variable::V) in the linear part of the quadratic expression.

source

list_of_constraint_types

JuMP.list_of_constraint_typesFunction
list_of_constraint_types(model::GenericModel)::Vector{Tuple{Type,Type}}

Return a list of tuples of the form (F, S) where F is a JuMP function type and S is an MOI set type such that all_constraints(model, F, S) returns a nonempty list.

Example

julia> model = Model();
+AffExpr (alias for GenericAffExpr{Float64, GenericVariableRef{Float64}})
source

latex_formulation

JuMP.latex_formulationFunction
latex_formulation(model::AbstractModel)

Wrap model in a type so that it can be pretty-printed as text/latex in a notebook like IJulia, or in Documenter.

To render the model, end the cell with latex_formulation(model), or call display(latex_formulation(model)) in to force the display of the model from inside a function.

source

linear_terms

JuMP.linear_termsFunction
linear_terms(aff::GenericAffExpr{C,V})

Provides an iterator over coefficient-variable tuples (a_i::C, x_i::V) in the linear part of the affine expression.

source
linear_terms(quad::GenericQuadExpr{C,V})

Provides an iterator over tuples (coefficient::C, variable::V) in the linear part of the quadratic expression.

source

list_of_constraint_types

JuMP.list_of_constraint_typesFunction
list_of_constraint_types(model::GenericModel)::Vector{Tuple{Type,Type}}

Return a list of tuples of the form (F, S) where F is a JuMP function type and S is an MOI set type such that all_constraints(model, F, S) returns a nonempty list.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0, Bin);
 
@@ -1214,12 +1214,12 @@
 3-element Vector{Tuple{Type, Type}}:
  (AffExpr, MathOptInterface.LessThan{Float64})
  (VariableRef, MathOptInterface.GreaterThan{Float64})
- (VariableRef, MathOptInterface.ZeroOne)

Performance considerations

Iterating over the list of function and set types is a type-unstable operation. Consider using a function barrier. See the Performance tips for extensions section of the documentation for more details.

source

lower_bound

JuMP.lower_boundFunction
lower_bound(v::GenericVariableRef)

Return the lower bound of a variable. Error if one does not exist.

See also LowerBoundRef, has_lower_bound, set_lower_bound, delete_lower_bound.

Example

julia> model = Model();
+ (VariableRef, MathOptInterface.ZeroOne)

Performance considerations

Iterating over the list of function and set types is a type-unstable operation. Consider using a function barrier. See the Performance tips for extensions section of the documentation for more details.

source

lower_bound

lp_matrix_data

JuMP.lp_matrix_dataFunction
lp_matrix_data(model::GenericModel{T})

Given a JuMP model of a linear program, return an LPMatrixData{T} struct storing data for an equivalent linear program in the form:

\[\begin{aligned} +1.0

source

lp_matrix_data

JuMP.lp_matrix_dataFunction
lp_matrix_data(model::GenericModel{T})

Given a JuMP model of a linear program, return an LPMatrixData{T} struct storing data for an equivalent linear program in the form:

\[\begin{aligned} \min & c^\top x + c_0 \\ & b_l \le A x \le b_u \\ & x_l \le x \le x_u @@ -1264,7 +1264,7 @@ 0.0 julia> data.sense -MAX_SENSE::OptimizationSense = 1

source

lp_sensitivity_report

JuMP.lp_sensitivity_reportFunction
lp_sensitivity_report(model::GenericModel{T}; atol::T = Base.rtoldefault(T))::SensitivityReport{T} where {T}

Given a linear program model with a current optimal basis, return a SensitivityReport object, which maps:

  • Every variable reference to a tuple (d_lo, d_hi)::Tuple{T,T}, explaining how much the objective coefficient of the corresponding variable can change by, such that the original basis remains optimal.
  • Every constraint reference to a tuple (d_lo, d_hi)::Tuple{T,T}, explaining how much the right-hand side of the corresponding constraint can change by, such that the basis remains optimal.

Both tuples are relative, rather than absolute. So given a objective coefficient of 1.0 and a tuple (-0.5, 0.5), the objective coefficient can range between 1.0 - 0.5 an 1.0 + 0.5.

atol is the primal/dual optimality tolerance, and should match the tolerance of the solver used to compute the basis.

Note: interval constraints are NOT supported.

Example

julia> import HiGHS
+MAX_SENSE::OptimizationSense = 1
source

lp_sensitivity_report

JuMP.lp_sensitivity_reportFunction
lp_sensitivity_report(model::GenericModel{T}; atol::T = Base.rtoldefault(T))::SensitivityReport{T} where {T}

Given a linear program model with a current optimal basis, return a SensitivityReport object, which maps:

  • Every variable reference to a tuple (d_lo, d_hi)::Tuple{T,T}, explaining how much the objective coefficient of the corresponding variable can change by, such that the original basis remains optimal.
  • Every constraint reference to a tuple (d_lo, d_hi)::Tuple{T,T}, explaining how much the right-hand side of the corresponding constraint can change by, such that the basis remains optimal.

Both tuples are relative, rather than absolute. So given a objective coefficient of 1.0 and a tuple (-0.5, 0.5), the objective coefficient can range between 1.0 - 0.5 an 1.0 + 0.5.

atol is the primal/dual optimality tolerance, and should match the tolerance of the solver used to compute the basis.

Note: interval constraints are NOT supported.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1296,7 +1296,7 @@
            "The lower bound of `x` can decrease by $dRHS_lo or increase " *
            "by $dRHS_hi."
        )
-The lower bound of `x` can decrease by -Inf or increase by 3.0.
source

map_coefficients

map_coefficients

JuMP.map_coefficientsFunction
map_coefficients(f::Function, a::GenericAffExpr)

Apply f to the coefficients and constant term of an GenericAffExpr a and return a new expression.

See also: map_coefficients_inplace!

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1307,7 +1307,7 @@
 2 x + 2
 
 julia> a
-x + 1
source
map_coefficients(f::Function, a::GenericQuadExpr)

Apply f to the coefficients and constant term of an GenericQuadExpr a and return a new expression.

See also: map_coefficients_inplace!

Example

julia> model = Model();
+x + 1
source
map_coefficients(f::Function, a::GenericQuadExpr)

Apply f to the coefficients and constant term of an GenericQuadExpr a and return a new expression.

See also: map_coefficients_inplace!

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1318,7 +1318,7 @@
 2 x² + 2 x + 2
 
 julia> a
-x² + x + 1
source

map_coefficients_inplace!

map_coefficients_inplace!

JuMP.map_coefficients_inplace!Function
map_coefficients_inplace!(f::Function, a::GenericAffExpr)

Apply f to the coefficients and constant term of an GenericAffExpr a and update them in-place.

See also: map_coefficients

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1329,7 +1329,7 @@
 2 x + 2
 
 julia> a
-2 x + 2
source
map_coefficients_inplace!(f::Function, a::GenericQuadExpr)

Apply f to the coefficients and constant term of an GenericQuadExpr a and update them in-place.

See also: map_coefficients

Example

julia> model = Model();
+2 x + 2
source
map_coefficients_inplace!(f::Function, a::GenericQuadExpr)

Apply f to the coefficients and constant term of an GenericQuadExpr a and update them in-place.

See also: map_coefficients

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1340,10 +1340,10 @@
 2 x² + 2 x + 2
 
 julia> a
-2 x² + 2 x + 2
source

mode

JuMP.modeFunction
mode(model::GenericModel)

Return the ModelMode of model.

Example

julia> model = Model();
+2 x² + 2 x + 2
source

mode

JuMP.modeFunction
mode(model::GenericModel)

Return the ModelMode of model.

Example

julia> model = Model();
 
 julia> mode(model)
-AUTOMATIC::ModelMode = 0
source

model_convert

model_convert

JuMP.model_convertFunction
model_convert(
     model::AbstractModel,
     rhs::Union{
         AbstractConstraint,
@@ -1351,14 +1351,14 @@
         AbstractJuMPScalar,
         MOI.AbstractSet,
     },
-)

Convert the coefficients and constants of functions and sets in the rhs to the coefficient type value_type(typeof(model)).

Purpose

Creating and adding a constraint is a two-step process. The first step calls build_constraint, and the result of that is passed to add_constraint.

However, because build_constraint does not take the model as an argument, the coefficients and constants of the function or set might be different than value_type(typeof(model)).

Therefore, the result of build_constraint is converted in a call to model_convert before the result is passed to add_constraint.

source

model_string

JuMP.model_stringFunction
model_string(mode::MIME, model::AbstractModel)

Return a String representation of model given the mode.

Example

julia> model = Model();
+)

Convert the coefficients and constants of functions and sets in the rhs to the coefficient type value_type(typeof(model)).

Purpose

Creating and adding a constraint is a two-step process. The first step calls build_constraint, and the result of that is passed to add_constraint.

However, because build_constraint does not take the model as an argument, the coefficients and constants of the function or set might be different than value_type(typeof(model)).

Therefore, the result of build_constraint is converted in a call to model_convert before the result is passed to add_constraint.

source

model_string

JuMP.model_stringFunction
model_string(mode::MIME, model::AbstractModel)

Return a String representation of model given the mode.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0);
 
 julia> print(model_string(MIME("text/plain"), model))
 Feasibility
 Subject to
- x ≥ 0
source

moi_function

moi_function

JuMP.moi_functionFunction
moi_function(x::AbstractJuMPScalar)
 moi_function(x::AbstractArray{<:AbstractJuMPScalar})

Given a JuMP object x, return the MathOptInterface equivalent.

See also: jump_function.

Example

julia> model = Model();
 
 julia> @variable(model, x);
@@ -1367,8 +1367,8 @@
 2 x + 1
 
 julia> moi_function(f)
-1.0 + 2.0 MOI.VariableIndex(1)
source

moi_function_type

JuMP.moi_function_typeFunction
moi_function_type(::Type{T}) where {T}

Given a JuMP object type T, return the MathOptInterface equivalent.

See also: jump_function_type.

Example

julia> moi_function_type(AffExpr)
-MathOptInterface.ScalarAffineFunction{Float64}
source

moi_set

JuMP.moi_setFunction
moi_set(constraint::AbstractConstraint)

Return the set of the constraint constraint in the function-in-set form as a MathOptInterface.AbstractSet.

moi_set(s::AbstractVectorSet, dim::Int)

Returns the MOI set of dimension dim corresponding to the JuMP set s.

moi_set(s::AbstractScalarSet)

Returns the MOI set corresponding to the JuMP set s.

source

name

JuMP.nameFunction
name(con_ref::ConstraintRef)

Get a constraint's name attribute.

Example

julia> model = Model();
+1.0 + 2.0 MOI.VariableIndex(1)
source

moi_function_type

JuMP.moi_function_typeFunction
moi_function_type(::Type{T}) where {T}

Given a JuMP object type T, return the MathOptInterface equivalent.

See also: jump_function_type.

Example

julia> moi_function_type(AffExpr)
+MathOptInterface.ScalarAffineFunction{Float64}
source

moi_set

JuMP.moi_setFunction
moi_set(constraint::AbstractConstraint)

Return the set of the constraint constraint in the function-in-set form as a MathOptInterface.AbstractSet.

moi_set(s::AbstractVectorSet, dim::Int)

Returns the MOI set of dimension dim corresponding to the JuMP set s.

moi_set(s::AbstractScalarSet)

Returns the MOI set corresponding to the JuMP set s.

source

name

JuMP.nameFunction
name(con_ref::ConstraintRef)

Get a constraint's name attribute.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1376,7 +1376,7 @@
 c : [2 x] ∈ Nonnegatives()
 
 julia> name(c)
-"c"
source
name(v::GenericVariableRef)::String

Get a variable's name attribute.

Example

julia> model = Model();
+"c"
source
name(v::GenericVariableRef)::String

Get a variable's name attribute.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2])
 2-element Vector{VariableRef}:
@@ -1384,10 +1384,10 @@
  x[2]
 
 julia> name(x[1])
-"x[1]"
source
name(model::AbstractModel)

Return the MOI.Name attribute of model's backend, or a default if empty.

Example

julia> model = Model();
+"x[1]"
source
name(model::AbstractModel)

Return the MOI.Name attribute of model's backend, or a default if empty.

Example

julia> model = Model();
 
 julia> name(model)
-"A JuMP Model"
source

node_count

JuMP.node_countFunction
node_count(model::GenericModel)

If available, returns the total number of branch-and-bound nodes explored during the most recent optimization in a Mixed Integer Program (the MOI.NodeCount attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
+"A JuMP Model"
source

node_count

JuMP.node_countFunction
node_count(model::GenericModel)

If available, returns the total number of branch-and-bound nodes explored during the most recent optimization in a Mixed Integer Program (the MOI.NodeCount attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1396,7 +1396,7 @@
 julia> optimize!(model)
 
 julia> node_count(model)
-0
source

normalized_coefficient

normalized_coefficient

JuMP.normalized_coefficientFunction
normalized_coefficient(
     constraint::ConstraintRef,
     variable::GenericVariableRef,
 )

Return the coefficient associated with variable in constraint after JuMP has normalized the constraint into its standard form.

See also set_normalized_coefficient.

Example

julia> model = Model();
@@ -1416,7 +1416,7 @@
 julia> normalized_coefficient(con_vec, x)
 2-element Vector{Tuple{Int64, Float64}}:
  (1, 1.0)
- (2, 2.0)
source
normalized_coefficient(
+ (2, 2.0)
source
normalized_coefficient(
     constraint::ConstraintRef,
     variable_1::GenericVariableRef,
     variable_2::GenericVariableRef,
@@ -1441,7 +1441,7 @@
  (1, 1.0)
 
 julia> normalized_coefficient(con_vec, x[1], x[2])
-Tuple{Int64, Float64}[]
source

normalized_rhs

JuMP.normalized_rhsFunction
normalized_rhs(constraint::ConstraintRef)

Return the right-hand side term of constraint after JuMP has converted the constraint into its normalized form.

See also set_normalized_rhs.

Example

julia> model = Model();
+Tuple{Int64, Float64}[]
source

normalized_rhs

JuMP.normalized_rhsFunction
normalized_rhs(constraint::ConstraintRef)

Return the right-hand side term of constraint after JuMP has converted the constraint into its normalized form.

See also set_normalized_rhs.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1449,7 +1449,7 @@
 con : 2 x ≤ 1
 
 julia> normalized_rhs(con)
-1.0
source

num_constraints

num_constraints

JuMP.num_constraintsFunction
num_constraints(model::GenericModel, function_type, set_type)::Int64

Return the number of constraints currently in the model where the function has type function_type and the set has type set_type.

See also list_of_constraint_types and all_constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0, Bin);
 
@@ -1468,7 +1468,7 @@
 1
 
 julia> num_constraints(model, AffExpr, MOI.LessThan{Float64})
-2
source
num_constraints(model::GenericModel; count_variable_in_set_constraints::Bool)

Return the number of constraints in model.

If count_variable_in_set_constraints == true, then VariableRef constraints such as VariableRef-in-Integer are included. To count only the number of structural constraints (for example, the rows in the constraint matrix of a linear program), pass count_variable_in_set_constraints = false.

Example

julia> model = Model();
+2
source
num_constraints(model::GenericModel; count_variable_in_set_constraints::Bool)

Return the number of constraints in model.

If count_variable_in_set_constraints == true, then VariableRef constraints such as VariableRef-in-Integer are included. To count only the number of structural constraints (for example, the rows in the constraint matrix of a linear program), pass count_variable_in_set_constraints = false.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0, Int);
 
@@ -1478,18 +1478,18 @@
 3
 
 julia> num_constraints(model; count_variable_in_set_constraints = false)
-1
source

num_variables

JuMP.num_variablesFunction
num_variables(model::GenericModel)::Int64

Returns number of variables in model.

Example

julia> model = Model();
+1
source

num_variables

JuMP.num_variablesFunction
num_variables(model::GenericModel)::Int64

Returns number of variables in model.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
 julia> num_variables(model)
-2
source

object_dictionary

JuMP.object_dictionaryFunction
object_dictionary(model::GenericModel)

Return the dictionary that maps the symbol name of a variable, constraint, or expression to the corresponding object.

Objects are registered to a specific symbol in the macros. For example, @variable(model, x[1:2, 1:2]) registers the array of variables x to the symbol :x.

This method should be defined for any subtype of AbstractModel.

See also: unregister.

Example

julia> model = Model();
+2
source

object_dictionary

JuMP.object_dictionaryFunction
object_dictionary(model::GenericModel)

Return the dictionary that maps the symbol name of a variable, constraint, or expression to the corresponding object.

Objects are registered to a specific symbol in the macros. For example, @variable(model, x[1:2, 1:2]) registers the array of variables x to the symbol :x.

This method should be defined for any subtype of AbstractModel.

See also: unregister.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
 julia> object_dictionary(model)
 Dict{Symbol, Any} with 1 entry:
-  :x => VariableRef[x[1], x[2]]
source

objective_bound

JuMP.objective_boundFunction
objective_bound(model::GenericModel)

Return the best known bound on the optimal objective value after a call to optimize!(model).

For scalar-valued objectives, this function returns a Float64. For vector-valued objectives, it returns a Vector{Float64}.

In the case of a vector-valued objective, this returns the ideal point, that is, the point obtained if each objective was optimized independently.

This function is equivalent to querying the MOI.ObjectiveBound attribute.

Example

julia> import HiGHS
+  :x => VariableRef[x[1], x[2]]
source

objective_bound

JuMP.objective_boundFunction
objective_bound(model::GenericModel)

Return the best known bound on the optimal objective value after a call to optimize!(model).

For scalar-valued objectives, this function returns a Float64. For vector-valued objectives, it returns a Vector{Float64}.

In the case of a vector-valued objective, this returns the ideal point, that is, the point obtained if each objective was optimized independently.

This function is equivalent to querying the MOI.ObjectiveBound attribute.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1502,7 +1502,7 @@
 julia> optimize!(model)
 
 julia> objective_bound(model)
-3.0
source

objective_function

objective_function

JuMP.objective_functionFunction
objective_function(
     model::GenericModel,
     ::Type{F} = objective_function_type(model),
 ) where {F}

Return an object of type F representing the objective function.

Errors if the objective is not convertible to type F.

This function is equivalent to querying the MOI.ObjectiveFunction{F} attribute.

Example

julia> model = Model();
@@ -1522,21 +1522,21 @@
 julia> typeof(objective_function(model, QuadExpr))
 QuadExpr (alias for GenericQuadExpr{Float64, GenericVariableRef{Float64}})

We see with the last two commands that even if the objective function is affine, as it is convertible to a quadratic function, it can be queried as a quadratic function and the result is quadratic.

However, it is not convertible to a variable:

julia> objective_function(model, VariableRef)
 ERROR: InexactError: convert(MathOptInterface.VariableIndex, 1.0 + 2.0 MOI.VariableIndex(1))
-[...]
source

objective_function_string

JuMP.objective_function_stringFunction
objective_function_string(mode, model::AbstractModel)::String

Return a String describing the objective function of the model.

Example

julia> model = Model();
+[...]
source

objective_function_string

JuMP.objective_function_stringFunction
objective_function_string(mode, model::AbstractModel)::String

Return a String describing the objective function of the model.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> @objective(model, Min, 2 * x);
 
 julia> objective_function_string(MIME("text/plain"), model)
-"2 x"
source

objective_function_type

objective_function_type

JuMP.objective_function_typeFunction
objective_function_type(model::GenericModel)::AbstractJuMPScalar

Return the type of the objective function.

This function is equivalent to querying the MOI.ObjectiveFunctionType attribute.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> @objective(model, Min, 2 * x + 1);
 
 julia> objective_function_type(model)
-AffExpr (alias for GenericAffExpr{Float64, GenericVariableRef{Float64}})
source

objective_sense

JuMP.objective_senseFunction
objective_sense(model::GenericModel)::MOI.OptimizationSense

Return the objective sense.

This function is equivalent to querying the MOI.ObjectiveSense attribute.

Example

julia> model = Model();
+AffExpr (alias for GenericAffExpr{Float64, GenericVariableRef{Float64}})
source

objective_sense

JuMP.objective_senseFunction
objective_sense(model::GenericModel)::MOI.OptimizationSense

Return the objective sense.

This function is equivalent to querying the MOI.ObjectiveSense attribute.

Example

julia> model = Model();
 
 julia> objective_sense(model)
 FEASIBILITY_SENSE::OptimizationSense = 2
@@ -1547,7 +1547,7 @@
 x
 
 julia> objective_sense(model)
-MAX_SENSE::OptimizationSense = 1
source

objective_value

JuMP.objective_valueFunction
objective_value(model::GenericModel; result::Int = 1)

Return the objective value associated with result index result of the most-recent solution returned by the solver.

For scalar-valued objectives, this function returns a Float64. For vector-valued objectives, it returns a Vector{Float64}.

This function is equivalent to querying the MOI.ObjectiveValue attribute.

See also: result_count.

Example

julia> import HiGHS
+MAX_SENSE::OptimizationSense = 1
source

objective_value

JuMP.objective_valueFunction
objective_value(model::GenericModel; result::Int = 1)

Return the objective value associated with result index result of the most-recent solution returned by the solver.

For scalar-valued objectives, this function returns a Float64. For vector-valued objectives, it returns a Vector{Float64}.

This function is equivalent to querying the MOI.ObjectiveValue attribute.

See also: result_count.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1565,7 +1565,7 @@
 julia> objective_value(model; result = 2)
 ERROR: Result index of attribute MathOptInterface.ObjectiveValue(2) out of bounds. There are currently 1 solution(s) in the model.
 Stacktrace:
-[...]
source

op_ifelse

JuMP.op_ifelseFunction
op_ifelse(a, x, y)

A function that falls back to ifelse(a, x, y), but when called with a JuMP variables or expression in the first argument, returns a GenericNonlinearExpr.

Example

julia> model = Model();
+[...]
source

op_ifelse

JuMP.op_ifelseFunction
op_ifelse(a, x, y)

A function that falls back to ifelse(a, x, y), but when called with a JuMP variables or expression in the first argument, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1576,14 +1576,14 @@
 ifelse(x, 1.0, 2.0)
 
 julia> op_ifelse(true, x, 2.0)
-x
source

op_string

JuMP.op_stringFunction
op_string(mime::MIME, x::GenericNonlinearExpr, ::Val{op}) where {op}

Return the string that should be printed for the operator op when function_string is called with mime and x.

Example

julia> model = Model();
+x
source

op_string

JuMP.op_stringFunction
op_string(mime::MIME, x::GenericNonlinearExpr, ::Val{op}) where {op}

Return the string that should be printed for the operator op when function_string is called with mime and x.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2], Bin);
 
 julia> f = @expression(model, x[1] || x[2]);
 
 julia> op_string(MIME("text/plain"), f, Val(:||))
-"||"
source

operator_to_set

JuMP.operator_to_setFunction
operator_to_set(error_fn::Function, ::Val{sense_symbol})

Converts a sense symbol to a set set such that @constraint(model, func sense_symbol 0) is equivalent to @constraint(model, func in set) for any func::AbstractJuMPScalar.

Example

Once a custom set is defined you can directly create a JuMP constraint with it:

julia> struct CustomSet{T} <: MOI.AbstractScalarSet
+"||"
source

operator_to_set

JuMP.operator_to_setFunction
operator_to_set(error_fn::Function, ::Val{sense_symbol})

Converts a sense symbol to a set set such that @constraint(model, func sense_symbol 0) is equivalent to @constraint(model, func in set) for any func::AbstractJuMPScalar.

Example

Once a custom set is defined you can directly create a JuMP constraint with it:

julia> struct CustomSet{T} <: MOI.AbstractScalarSet
            value::T
        end
 
@@ -1602,8 +1602,8 @@
 julia> MOIU.shift_constant(set::CustomSet, value) = CustomSet(set.value + value)
 
 julia> cref = @constraint(model, x ⊰ 1)
-x ∈ CustomSet{Float64}(1.0)

Note that the whole function is first moved to the right-hand side, then the sign is transformed into a set with zero constant and finally the constant is moved to the set with MOIU.shift_constant.

source

operator_warn

JuMP.operator_warnFunction
operator_warn(model::AbstractModel)
-operator_warn(model::GenericModel)

This function is called on the model whenever two affine expressions are added together without using destructive_add!, and at least one of the two expressions has more than 50 terms.

For the case of Model, if this function is called more than 20,000 times then a warning is generated once.

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

optimize!

JuMP.optimize!Function
optimize!(
+x ∈ CustomSet{Float64}(1.0)

Note that the whole function is first moved to the right-hand side, then the sign is transformed into a set with zero constant and finally the constant is moved to the set with MOIU.shift_constant.

source

operator_warn

JuMP.operator_warnFunction
operator_warn(model::AbstractModel)
+operator_warn(model::GenericModel)

This function is called on the model whenever two affine expressions are added together without using destructive_add!, and at least one of the two expressions has more than 50 terms.

For the case of Model, if this function is called more than 20,000 times then a warning is generated once.

This method should only be implemented by developers creating JuMP extensions. It should never be called by users of JuMP.

source

optimize!

JuMP.optimize!Function
optimize!(
     model::GenericModel;
     ignore_optimize_hook = (model.optimize_hook === nothing),
     kwargs...,
@@ -1623,7 +1623,7 @@
 my_optimize_hook (generic function with 1 method)
 
 julia> optimize!(model; foo = 2)
-Hook called with foo = 2
source

optimizer_index

optimizer_index

JuMP.optimizer_indexFunction
optimizer_index(x::GenericVariableRef)::MOI.VariableIndex
 optimizer_index(x::ConstraintRef{<:GenericModel})::MOI.ConstraintIndex

Return the variable or constraint index that corresponds to x in the associated model unsafe_backend(owner_model(x)).

This function should be used with unsafe_backend.

As a safer alternative, use backend and index. See the docstrings of backend and unsafe_backend for more details.

Throws

  • Throws NoOptimizer if no optimizer is set.
  • Throws an ErrorException if the optimizer is set but is not attached.
  • Throws an ErrorException if the index is bridged.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
@@ -1639,7 +1639,7 @@
 A HiGHS model with 1 columns and 0 rows.
 
 julia> optimizer_index(x)
-MOI.VariableIndex(1)
source

optimizer_with_attributes

JuMP.optimizer_with_attributesFunction
optimizer_with_attributes(optimizer_constructor, attrs::Pair...)

Groups an optimizer constructor with the list of attributes attrs. Note that it is equivalent to MOI.OptimizerWithAttributes.

When provided to the Model constructor or to set_optimizer, it creates an optimizer by calling optimizer_constructor(), and then sets the attributes using set_attribute.

See also: set_attribute, get_attribute.

Note

The string names of the attributes are specific to each solver. One should consult the solver's documentation to find the attributes of interest.

Example

julia> import HiGHS
+MOI.VariableIndex(1)
source

optimizer_with_attributes

JuMP.optimizer_with_attributesFunction
optimizer_with_attributes(optimizer_constructor, attrs::Pair...)

Groups an optimizer constructor with the list of attributes attrs. Note that it is equivalent to MOI.OptimizerWithAttributes.

When provided to the Model constructor or to set_optimizer, it creates an optimizer by calling optimizer_constructor(), and then sets the attributes using set_attribute.

See also: set_attribute, get_attribute.

Note

The string names of the attributes are specific to each solver. One should consult the solver's documentation to find the attributes of interest.

Example

julia> import HiGHS
 
 julia> optimizer = optimizer_with_attributes(
            HiGHS.Optimizer, "presolve" => "off", MOI.Silent() => true,
@@ -1651,12 +1651,12 @@
 
 julia> set_attribute(model, "presolve", "off")
 
-julia> set_attribute(model, MOI.Silent(), true)
source

owner_model

JuMP.owner_modelFunction
owner_model(s::AbstractJuMPScalar)

Return the model owning the scalar s.

Example

julia> model = Model();
+julia> set_attribute(model, MOI.Silent(), true)
source

owner_model

JuMP.owner_modelFunction
owner_model(s::AbstractJuMPScalar)

Return the model owning the scalar s.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> owner_model(x) === model
-true
source

parameter_value

parameter_value

JuMP.parameter_valueFunction
parameter_value(x::GenericVariableRef)

Return the value of the parameter x.

Errors if x is not a parameter.

See also ParameterRef, is_parameter, set_parameter_value.

Example

julia> model = Model();
 
 julia> @variable(model, p in Parameter(2))
 p
@@ -1667,23 +1667,23 @@
 julia> set_parameter_value(p, 2.5)
 
 julia> parameter_value(p)
-2.5
source

parse_constraint

JuMP.parse_constraintFunction
parse_constraint(error_fn::Function, expr::Expr)

The entry-point for all constraint-related parsing.

Arguments

  • The error_fn function is passed everywhere to provide better error messages
  • expr comes from the @constraint macro. There are two possibilities:
    • @constraint(model, expr)
    • @constraint(model, name[args], expr)
    In both cases, expr is the main component of the constraint.

Supported syntax

JuMP currently supports the following expr objects:

  • lhs <= rhs
  • lhs == rhs
  • lhs >= rhs
  • l <= body <= u
  • u >= body >= l
  • lhs ⟂ rhs
  • lhs in rhs
  • lhs ∈ rhs
  • z --> {constraint}
  • !z --> {constraint}
  • z <--> {constraint}
  • !z <--> {constraint}
  • z => {constraint}
  • !z => {constraint}

as well as all broadcasted variants.

Extensions

The infrastructure behind parse_constraint is extendable. See parse_constraint_head and parse_constraint_call for details.

source

parse_constraint_call

parse_constraint

JuMP.parse_constraintFunction
parse_constraint(error_fn::Function, expr::Expr)

The entry-point for all constraint-related parsing.

Arguments

  • The error_fn function is passed everywhere to provide better error messages
  • expr comes from the @constraint macro. There are two possibilities:
    • @constraint(model, expr)
    • @constraint(model, name[args], expr)
    In both cases, expr is the main component of the constraint.

Supported syntax

JuMP currently supports the following expr objects:

  • lhs <= rhs
  • lhs == rhs
  • lhs >= rhs
  • l <= body <= u
  • u >= body >= l
  • lhs ⟂ rhs
  • lhs in rhs
  • lhs ∈ rhs
  • z --> {constraint}
  • !z --> {constraint}
  • z <--> {constraint}
  • !z <--> {constraint}
  • z => {constraint}
  • !z => {constraint}

as well as all broadcasted variants.

Extensions

The infrastructure behind parse_constraint is extendable. See parse_constraint_head and parse_constraint_call for details.

source

parse_constraint_call

JuMP.parse_constraint_callFunction
parse_constraint_call(
     error_fn::Function,
     is_vectorized::Bool,
     ::Val{op},
     args...,
-)

Implement this method to intercept the parsing of a :call expression with operator op.

Warning

Extending the constraint macro at parse time is an advanced operation and has the potential to interfere with existing JuMP syntax. Please discuss with the developer chatroom before publishing any code that implements these methods.

Arguments

  • error_fn: a function that accepts a String and throws the string as an error, along with some descriptive information of the macro from which it was thrown.
  • is_vectorized: a boolean to indicate if op should be broadcast or not
  • op: the first element of the .args field of the Expr to intercept
  • args...: the .args field of the Expr.

Returns

This function must return:

  • parse_code::Expr: an expression containing any setup or rewriting code that needs to be called before build_constraint
  • build_code::Expr: an expression that calls build_constraint( or build_constraint.( depending on is_vectorized.

See also: parse_constraint_head, build_constraint

source
parse_constraint_call(
+)

Implement this method to intercept the parsing of a :call expression with operator op.

Warning

Extending the constraint macro at parse time is an advanced operation and has the potential to interfere with existing JuMP syntax. Please discuss with the developer chatroom before publishing any code that implements these methods.

Arguments

  • error_fn: a function that accepts a String and throws the string as an error, along with some descriptive information of the macro from which it was thrown.
  • is_vectorized: a boolean to indicate if op should be broadcast or not
  • op: the first element of the .args field of the Expr to intercept
  • args...: the .args field of the Expr.

Returns

This function must return:

  • parse_code::Expr: an expression containing any setup or rewriting code that needs to be called before build_constraint
  • build_code::Expr: an expression that calls build_constraint( or build_constraint.( depending on is_vectorized.

See also: parse_constraint_head, build_constraint

source
parse_constraint_call(
     error_fn::Function,
     vectorized::Bool,
     ::Val{op},
     lhs,
     rhs,
-) where {op}

Fallback handler for binary operators. These might be infix operators like @constraint(model, lhs op rhs), or normal operators like @constraint(model, op(lhs, rhs)).

In both cases, we rewrite as lhs - rhs in operator_to_set(error_fn, op).

See operator_to_set for details.

source

parse_constraint_head

JuMP.parse_constraint_headFunction
parse_constraint_head(error_fn::Function, ::Val{head}, args...)

Implement this method to intercept the parsing of an expression with head head.

Warning

Extending the constraint macro at parse time is an advanced operation and has the potential to interfere with existing JuMP syntax. Please discuss with the developer chatroom before publishing any code that implements these methods.

Arguments

  • error_fn: a function that accepts a String and throws the string as an error, along with some descriptive information of the macro from which it was thrown.
  • head: the .head field of the Expr to intercept
  • args...: the .args field of the Expr.

Returns

This function must return:

  • is_vectorized::Bool: whether the expression represents a broadcasted expression like x .<= 1
  • parse_code::Expr: an expression containing any setup or rewriting code that needs to be called before build_constraint
  • build_code::Expr: an expression that calls build_constraint( or build_constraint.( depending on is_vectorized.

Existing implementations

JuMP currently implements:

  • ::Val{:call}, which forwards calls to parse_constraint_call
  • ::Val{:comparison}, which handles the special case of l <= body <= u.

See also: parse_constraint_call, build_constraint

source

parse_one_operator_variable

JuMP.parse_one_operator_variableFunction
parse_one_operator_variable(
+) where {op}

Fallback handler for binary operators. These might be infix operators like @constraint(model, lhs op rhs), or normal operators like @constraint(model, op(lhs, rhs)).

In both cases, we rewrite as lhs - rhs in operator_to_set(error_fn, op).

See operator_to_set for details.

source

parse_constraint_head

JuMP.parse_constraint_headFunction
parse_constraint_head(error_fn::Function, ::Val{head}, args...)

Implement this method to intercept the parsing of an expression with head head.

Warning

Extending the constraint macro at parse time is an advanced operation and has the potential to interfere with existing JuMP syntax. Please discuss with the developer chatroom before publishing any code that implements these methods.

Arguments

  • error_fn: a function that accepts a String and throws the string as an error, along with some descriptive information of the macro from which it was thrown.
  • head: the .head field of the Expr to intercept
  • args...: the .args field of the Expr.

Returns

This function must return:

  • is_vectorized::Bool: whether the expression represents a broadcasted expression like x .<= 1
  • parse_code::Expr: an expression containing any setup or rewriting code that needs to be called before build_constraint
  • build_code::Expr: an expression that calls build_constraint( or build_constraint.( depending on is_vectorized.

Existing implementations

JuMP currently implements:

  • ::Val{:call}, which forwards calls to parse_constraint_call
  • ::Val{:comparison}, which handles the special case of l <= body <= u.

See also: parse_constraint_call, build_constraint

source

parse_one_operator_variable

JuMP.parse_one_operator_variableFunction
parse_one_operator_variable(
     error_fn::Function,
     info_expr::_VariableInfoExpr,
     sense::Val{S},
     value,
-) where {S}

Update infoexr for a variable expression in the @variable macro of the form variable name S value.

source

parse_ternary_variable

JuMP.parse_ternary_variableFunction
parse_ternary_variable(error_fn, info_expr, lhs_sense, lhs, rhs_sense, rhs)

A hook for JuMP extensions to intercept the parsing of a :comparison expression, which has the form lhs lhs_sense variable rhs_sense rhs.

source

parse_variable

JuMP.parse_variableFunction
parse_variable(error_fn::Function, ::_VariableInfoExpr, args...)

A hook for extensions to intercept the parsing of inequality constraints in the @variable macro.

source

primal_feasibility_report

JuMP.primal_feasibility_reportFunction
primal_feasibility_report(
+) where {S}

Update infoexr for a variable expression in the @variable macro of the form variable name S value.

source

parse_ternary_variable

JuMP.parse_ternary_variableFunction
parse_ternary_variable(error_fn, info_expr, lhs_sense, lhs, rhs_sense, rhs)

A hook for JuMP extensions to intercept the parsing of a :comparison expression, which has the form lhs lhs_sense variable rhs_sense rhs.

source

parse_variable

JuMP.parse_variableFunction
parse_variable(error_fn::Function, ::_VariableInfoExpr, args...)

A hook for extensions to intercept the parsing of inequality constraints in the @variable macro.

source

primal_feasibility_report

JuMP.primal_feasibility_reportFunction
primal_feasibility_report(
     model::GenericModel{T},
     point::AbstractDict{GenericVariableRef{T},T} = _last_primal_solution(model),
     atol::T = zero(T),
@@ -1694,7 +1694,7 @@
 
 julia> primal_feasibility_report(model, Dict(x => 0.2))
 Dict{Any, Float64} with 1 entry:
-  x ≥ 0.5 => 0.3
source
primal_feasibility_report(
+  x ≥ 0.5 => 0.3
source
primal_feasibility_report(
     point::Function,
     model::GenericModel{T};
     atol::T = zero(T),
@@ -1707,30 +1707,30 @@
            return start_value(v)
        end
 Dict{Any, Float64} with 1 entry:
-  x ≤ 1 => 0.3
source

primal_status

primal_status

JuMP.primal_statusFunction
primal_status(model::GenericModel; result::Int = 1)

Return a MOI.ResultStatusCode describing the status of the most recent primal solution of the solver (that is, the MOI.PrimalStatus attribute) associated with the result index result.

See also: result_count.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
 julia> primal_status(model; result = 2)
-NO_SOLUTION::ResultStatusCode = 0
source
JuMP.print_active_bridgesFunction
print_active_bridges([io::IO = stdout,] model::GenericModel)

Print a list of the variable, constraint, and objective bridges that are currently used in the model.

source
print_active_bridges([io::IO = stdout,] model::GenericModel, ::Type{F}) where {F}

Print a list of bridges required for an objective function of type F.

source
print_active_bridges(
+NO_SOLUTION::ResultStatusCode = 0
source
JuMP.print_active_bridgesFunction
print_active_bridges([io::IO = stdout,] model::GenericModel)

Print a list of the variable, constraint, and objective bridges that are currently used in the model.

source
print_active_bridges([io::IO = stdout,] model::GenericModel, ::Type{F}) where {F}

Print a list of bridges required for an objective function of type F.

source
print_active_bridges(
     [io::IO = stdout,]
     model::GenericModel,
     F::Type,
     S::Type{<:MOI.AbstractSet},
-)

Print a list of bridges required for a constraint of type F-in-S.

source
print_active_bridges(
+)

Print a list of bridges required for a constraint of type F-in-S.

source
print_active_bridges(
     [io::IO = stdout,]
     model::GenericModel,
     S::Type{<:MOI.AbstractSet},
-)

Print a list of bridges required to add a variable constrained to the set S.

source
JuMP.print_bridge_graphFunction
 print_bridge_graph([io::IO,] model::GenericModel)

Print the hyper-graph containing all variable, constraint, and objective types that could be obtained by bridging the variables, constraints, and objectives that are present in the model.

Warning

This function is intended for advanced users. If you want to see only the bridges that are currently used, use print_active_bridges instead.

Explanation of output

Each node in the hyper-graph corresponds to a variable, constraint, or objective type.

  • Variable nodes are indicated by [ ]
  • Constraint nodes are indicated by ( )
  • Objective nodes are indicated by | |

The number inside each pair of brackets is an index of the node in the hyper-graph.

Note that this hyper-graph is the full list of possible transformations. When the bridged model is created, we select the shortest hyper-path(s) from this graph, so many nodes may be un-used.

For more information, see Legat, B., Dowson, O., Garcia, J., and Lubin, M. (2020). "MathOptInterface: a data structure for mathematical optimization problems." URL: https://arxiv.org/abs/2002.03447

source

quad_terms

JuMP.quad_termsFunction
quad_terms(quad::GenericQuadExpr{C,V})

Provides an iterator over tuples (coefficient::C, var_1::V, var_2::V) in the quadratic part of the quadratic expression.

source

raw_status

JuMP.raw_statusFunction
raw_status(model::GenericModel)

Return the reason why the solver stopped in its own words (that is, the MathOptInterface model attribute MOI.RawStatusString).

Example

julia> import Ipopt
+)

Print a list of bridges required to add a variable constrained to the set S.

source
JuMP.print_bridge_graphFunction
 print_bridge_graph([io::IO,] model::GenericModel)

Print the hyper-graph containing all variable, constraint, and objective types that could be obtained by bridging the variables, constraints, and objectives that are present in the model.

Warning

This function is intended for advanced users. If you want to see only the bridges that are currently used, use print_active_bridges instead.

Explanation of output

Each node in the hyper-graph corresponds to a variable, constraint, or objective type.

  • Variable nodes are indicated by [ ]
  • Constraint nodes are indicated by ( )
  • Objective nodes are indicated by | |

The number inside each pair of brackets is an index of the node in the hyper-graph.

Note that this hyper-graph is the full list of possible transformations. When the bridged model is created, we select the shortest hyper-path(s) from this graph, so many nodes may be un-used.

For more information, see Legat, B., Dowson, O., Garcia, J., and Lubin, M. (2020). "MathOptInterface: a data structure for mathematical optimization problems." URL: https://arxiv.org/abs/2002.03447

source

quad_terms

JuMP.quad_termsFunction
quad_terms(quad::GenericQuadExpr{C,V})

Provides an iterator over tuples (coefficient::C, var_1::V, var_2::V) in the quadratic part of the quadratic expression.

source

raw_status

JuMP.raw_statusFunction
raw_status(model::GenericModel)

Return the reason why the solver stopped in its own words (that is, the MathOptInterface model attribute MOI.RawStatusString).

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
 julia> raw_status(model)
-"optimize not called"
source

read_from_file

read_from_file

JuMP.read_from_fileFunction
read_from_file(
     filename::String;
     format::MOI.FileFormats.FileFormat = MOI.FileFormats.FORMAT_AUTOMATIC,
     kwargs...,
-)

Return a JuMP model read from filename in the format format.

If the filename ends in .gz, it will be uncompressed using GZip. If the filename ends in .bz2, it will be uncompressed using BZip2.

Other kwargs are passed to the Model constructor of the chosen format.

source

reduced_cost

JuMP.reduced_costFunction
reduced_cost(x::GenericVariableRef{T})::T where {T}

Return the reduced cost associated with variable x.

One interpretation of the reduced cost is that it is the change in the objective from an infinitesimal relaxation of the variable bounds.

This method is equivalent to querying the shadow price of the active variable bound (if one exists and is active).

See also: shadow_price.

Example

julia> import HiGHS
+)

Return a JuMP model read from filename in the format format.

If the filename ends in .gz, it will be uncompressed using GZip. If the filename ends in .bz2, it will be uncompressed using BZip2.

Other kwargs are passed to the Model constructor of the chosen format.

source

reduced_cost

JuMP.reduced_costFunction
reduced_cost(x::GenericVariableRef{T})::T where {T}

Return the reduced cost associated with variable x.

One interpretation of the reduced cost is that it is the change in the objective from an infinitesimal relaxation of the variable bounds.

This method is equivalent to querying the shadow price of the active variable bound (if one exists and is active).

See also: shadow_price.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1746,7 +1746,7 @@
 true
 
 julia> reduced_cost(x)
-2.0
source

relative_gap

JuMP.relative_gapFunction
relative_gap(model::GenericModel)

Return the final relative optimality gap after a call to optimize!(model).

Exact value depends upon implementation of MOI.RelativeGap by the particular solver used for optimization.

This function is equivalent to querying the MOI.RelativeGap attribute.

Example

julia> import HiGHS
+2.0
source

relative_gap

JuMP.relative_gapFunction
relative_gap(model::GenericModel)

Return the final relative optimality gap after a call to optimize!(model).

Exact value depends upon implementation of MOI.RelativeGap by the particular solver used for optimization.

This function is equivalent to querying the MOI.RelativeGap attribute.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -1759,7 +1759,7 @@
 julia> optimize!(model)
 
 julia> relative_gap(model)
-0.0
source

relax_integrality

JuMP.relax_integralityFunction
relax_integrality(model::GenericModel)

Modifies model to "relax" all binary and integrality constraints on variables. Specifically,

  • Binary constraints are deleted, and variable bounds are tightened if necessary to ensure the variable is constrained to the interval $[0, 1]$.
  • Integrality constraints are deleted without modifying variable bounds.
  • An error is thrown if semi-continuous or semi-integer constraints are present (support may be added for these in the future).
  • All other constraints are ignored (left in place). This includes discrete constraints like SOS and indicator constraints.

Returns a function that can be called without any arguments to restore the original model. The behavior of this function is undefined if additional changes are made to the affected variables in the meantime.

Example

julia> model = Model();
+0.0
source

relax_integrality

JuMP.relax_integralityFunction
relax_integrality(model::GenericModel)

Modifies model to "relax" all binary and integrality constraints on variables. Specifically,

  • Binary constraints are deleted, and variable bounds are tightened if necessary to ensure the variable is constrained to the interval $[0, 1]$.
  • Integrality constraints are deleted without modifying variable bounds.
  • An error is thrown if semi-continuous or semi-integer constraints are present (support may be added for these in the future).
  • All other constraints are ignored (left in place). This includes discrete constraints like SOS and indicator constraints.

Returns a function that can be called without any arguments to restore the original model. The behavior of this function is undefined if additional changes are made to the affected variables in the meantime.

Example

julia> model = Model();
 
 julia> @variable(model, x, Bin);
 
@@ -1785,7 +1785,7 @@
  y ≥ 1
  y ≤ 10
  y integer
- x binary
source

relax_with_penalty!

relax_with_penalty!

JuMP.relax_with_penalty!Function
relax_with_penalty!(
     model::GenericModel{T},
     [penalties::Dict{ConstraintRef,T}];
     [default::Union{Nothing,Real} = nothing,]
@@ -1828,7 +1828,7 @@
 Subject to
  c2 : 3 x + _[2] ≥ 0
  c1 : 2 x ≤ -1
- _[2] ≥ 0
source

remove_bridge

remove_bridge

JuMP.remove_bridgeFunction
remove_bridge(
     model::GenericModel{S},
     BT::Type{<:MOI.Bridges.AbstractBridge};
     coefficient_type::Type{T} = S,
@@ -1848,17 +1848,17 @@
            model,
            MOI.Bridges.Constraint.NumberConversionBridge;
            coefficient_type = Complex{Float64},
-       )
source

reshape_set

JuMP.reshape_setFunction
reshape_set(vectorized_set::MOI.AbstractSet, shape::AbstractShape)

Return a set in its original shape shape given its vectorized form vectorized_form.

Example

Given a SymmetricMatrixShape of vectorized form [1, 2, 3] in MOI.PositiveSemidefinieConeTriangle(2), the following code returns the set of the original constraint Symmetric(Matrix[1 2; 2 3]) in PSDCone():

julia> reshape_set(MOI.PositiveSemidefiniteConeTriangle(2), SymmetricMatrixShape(2))
-PSDCone()
source

reshape_vector

JuMP.reshape_vectorFunction
reshape_vector(vectorized_form::Vector, shape::AbstractShape)

Return an object in its original shape shape given its vectorized form vectorized_form.

Example

Given a SymmetricMatrixShape of vectorized form [1, 2, 3], the following code returns the matrix Symmetric(Matrix[1 2; 2 3]):

julia> reshape_vector([1, 2, 3], SymmetricMatrixShape(2))
+       )
source

reshape_set

JuMP.reshape_setFunction
reshape_set(vectorized_set::MOI.AbstractSet, shape::AbstractShape)

Return a set in its original shape shape given its vectorized form vectorized_form.

Example

Given a SymmetricMatrixShape of vectorized form [1, 2, 3] in MOI.PositiveSemidefinieConeTriangle(2), the following code returns the set of the original constraint Symmetric(Matrix[1 2; 2 3]) in PSDCone():

julia> reshape_set(MOI.PositiveSemidefiniteConeTriangle(2), SymmetricMatrixShape(2))
+PSDCone()
source

reshape_vector

JuMP.reshape_vectorFunction
reshape_vector(vectorized_form::Vector, shape::AbstractShape)

Return an object in its original shape shape given its vectorized form vectorized_form.

Example

Given a SymmetricMatrixShape of vectorized form [1, 2, 3], the following code returns the matrix Symmetric(Matrix[1 2; 2 3]):

julia> reshape_vector([1, 2, 3], SymmetricMatrixShape(2))
 2×2 LinearAlgebra.Symmetric{Int64, Matrix{Int64}}:
  1  2
- 2  3
source

result_count

JuMP.result_countFunction
result_count(model::GenericModel)

Return the number of results available to query after a call to optimize!.

Example

julia> import Ipopt
+ 2  3
source

result_count

JuMP.result_countFunction
result_count(model::GenericModel)

Return the number of results available to query after a call to optimize!.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
 julia> result_count(model)
-0
source

reverse_sense

JuMP.reverse_senseFunction
reverse_sense(::Val{T}) where {T}

Given an (in)equality symbol T, return a new Val object with the opposite (in)equality symbol.

This function is intended for use in JuMP extensions.

Example

julia> reverse_sense(Val(:>=))
-Val{:<=}()
source

set_attribute

reverse_sense

JuMP.reverse_senseFunction
reverse_sense(::Val{T}) where {T}

Given an (in)equality symbol T, return a new Val object with the opposite (in)equality symbol.

This function is intended for use in JuMP extensions.

Example

julia> reverse_sense(Val(:>=))
+Val{:<=}()
source

set_attribute

JuMP.set_attributeFunction
set_attribute(model::GenericModel, attr::MOI.AbstractModelAttribute, value)
 set_attribute(x::GenericVariableRef, attr::MOI.AbstractVariableAttribute, value)
 set_attribute(cr::ConstraintRef, attr::MOI.AbstractConstraintAttribute, value)

Set the value of a solver-specifc attribute attr to value.

This is equivalent to calling MOI.set with the associated MOI model and, for variables and constraints, with the associated MOI.VariableIndex or MOI.ConstraintIndex.

Example

julia> model = Model();
 
@@ -1872,7 +1872,7 @@
 
 julia> set_attribute(x, MOI.VariableName(), "x_new")
 
-julia> set_attribute(c, MOI.ConstraintName(), "c_new")
source
set_attribute(
+julia> set_attribute(c, MOI.ConstraintName(), "c_new")
source
set_attribute(
     model::Union{GenericModel,MOI.OptimizerWithAttributes},
     attr::Union{AbstractString,MOI.AbstractOptimizerAttribute},
     value,
@@ -1888,7 +1888,7 @@
 
 julia> set_attribute(opt, "output_flag", true)
 
-julia> set_attribute(opt, MOI.RawOptimizerAttribute("output_flag"), false)
source

set_attributes

JuMP.set_attributesFunction
set_attributes(
+julia> set_attribute(opt, MOI.RawOptimizerAttribute("output_flag"), false)
source

set_attributes

JuMP.set_attributesFunction
set_attributes(
     destination::Union{
         GenericModel,
         MOI.OptimizerWithAttributes,
@@ -1906,7 +1906,7 @@
 
 julia> set_attribute(model, "tol", 1e-4)
 
-julia> set_attribute(model, "max_iter", 100)
source

set_binary

JuMP.set_binaryFunction
set_binary(v::GenericVariableRef)

Add a constraint on the variable v that it must take values in the set $\{0,1\}$.

See also BinaryRef, is_binary, unset_binary.

Example

julia> model = Model();
+julia> set_attribute(model, "max_iter", 100)
source

set_binary

JuMP.set_binaryFunction
set_binary(v::GenericVariableRef)

Add a constraint on the variable v that it must take values in the set $\{0,1\}$.

See also BinaryRef, is_binary, unset_binary.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1916,7 +1916,7 @@
 julia> set_binary(x)
 
 julia> is_binary(x)
-true
source

set_dual_start_value

JuMP.set_dual_start_valueFunction
set_dual_start_value(con_ref::ConstraintRef, value)

Set the dual start value (MOI attribute ConstraintDualStart) of the constraint con_ref to value.

To remove a dual start value set it to nothing.

See also dual_start_value.

Example

julia> model = Model();
+true
source

set_dual_start_value

JuMP.set_dual_start_valueFunction
set_dual_start_value(con_ref::ConstraintRef, value)

Set the dual start value (MOI attribute ConstraintDualStart) of the constraint con_ref to value.

To remove a dual start value set it to nothing.

See also dual_start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 2.0);
 
@@ -1931,7 +1931,7 @@
 
 julia> set_dual_start_value(c, nothing)
 
-julia> dual_start_value(c)
source

set_integer

set_integer

JuMP.set_integerFunction
set_integer(variable_ref::GenericVariableRef)

Add an integrality constraint on the variable variable_ref.

See also IntegerRef, is_integer, unset_integer.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1941,7 +1941,7 @@
 julia> set_integer(x)
 
 julia> is_integer(x)
-true
source

set_lower_bound

set_lower_bound

set_name

JuMP.set_nameFunction
set_name(con_ref::ConstraintRef, s::AbstractString)

Set a constraint's name attribute.

Example

julia> model = Model();
+2.0
source

set_name

JuMP.set_nameFunction
set_name(con_ref::ConstraintRef, s::AbstractString)

Set a constraint's name attribute.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -1964,7 +1964,7 @@
 "my_constraint"
 
 julia> c
-my_constraint : [2 x] ∈ Nonnegatives()
source
set_name(v::GenericVariableRef, s::AbstractString)

Set a variable's name attribute.

Example

julia> model = Model();
+my_constraint : [2 x] ∈ Nonnegatives()
source
set_name(v::GenericVariableRef, s::AbstractString)

Set a variable's name attribute.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -1975,7 +1975,7 @@
 x_foo
 
 julia> name(x)
-"x_foo"
source

set_normalized_coefficient

set_normalized_coefficient

JuMP.set_normalized_coefficientFunction
set_normalized_coefficient(
     constraint::ConstraintRef,
     variable::GenericVariableRef,
     value::Number,
@@ -1990,7 +1990,7 @@
 julia> set_normalized_coefficient(con, x, 4)
 
 julia> con
-con : 4 x ≤ 2
source
set_normalized_coefficient(
+con : 4 x ≤ 2
source
set_normalized_coefficient(
     constraints::AbstractVector{<:ConstraintRef},
     variables::AbstractVector{<:GenericVariableRef},
     values::AbstractVector{<:Number},
@@ -2008,7 +2008,7 @@
 julia> set_normalized_coefficient([con, con], [x, y], [6, 7])
 
 julia> con
-con : 6 x + 7 y ≤ 2
source
set_normalized_coefficient(
+con : 6 x + 7 y ≤ 2
source
set_normalized_coefficient(
     con_ref::ConstraintRef,
     variable::AbstractVariableRef,
     new_coefficients::Vector{Tuple{Int64,T}},
@@ -2023,7 +2023,7 @@
 julia> set_normalized_coefficient(con, x, [(1, 2.0), (2, 5.0)])
 
 julia> con
-con : [2 x, 5 x] ∈ MathOptInterface.Nonnegatives(2)
source
set_normalized_coefficient(
+con : [2 x, 5 x] ∈ MathOptInterface.Nonnegatives(2)
source
set_normalized_coefficient(
     constraint::ConstraintRef,
     variable_1:GenericVariableRef,
     variable_2:GenericVariableRef,
@@ -2040,7 +2040,7 @@
 julia> set_normalized_coefficient(con, x[1], x[2], 5)
 
 julia> con
-con : 4 x[1]² + 5 x[1]*x[2] + x[2] ≤ 2
source
set_normalized_coefficient(
+con : 4 x[1]² + 5 x[1]*x[2] + x[2] ≤ 2
source
set_normalized_coefficient(
     constraints::AbstractVector{<:ConstraintRef},
     variables_1:AbstractVector{<:GenericVariableRef},
     variables_2:AbstractVector{<:GenericVariableRef},
@@ -2055,7 +2055,7 @@
 julia> set_normalized_coefficient([con, con], [x[1], x[1]], [x[1], x[2]], [4, 5])
 
 julia> con
-con : 4 x[1]² + 5 x[1]*x[2] + x[2] ≤ 2
source

set_normalized_rhs

JuMP.set_normalized_rhsFunction
set_normalized_rhs(constraint::ConstraintRef, value::Number)

Set the right-hand side term of constraint to value.

Note that prior to this step, JuMP will aggregate all constant terms onto the right-hand side of the constraint. For example, given a constraint 2x + 1 <= 2, set_normalized_rhs(con, 4) will create the constraint 2x <= 4, not 2x + 1 <= 4.

Example

julia> model = Model();
+con : 4 x[1]² + 5 x[1]*x[2] + x[2] ≤ 2
source

set_normalized_rhs

JuMP.set_normalized_rhsFunction
set_normalized_rhs(constraint::ConstraintRef, value::Number)

Set the right-hand side term of constraint to value.

Note that prior to this step, JuMP will aggregate all constant terms onto the right-hand side of the constraint. For example, given a constraint 2x + 1 <= 2, set_normalized_rhs(con, 4) will create the constraint 2x <= 4, not 2x + 1 <= 4.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -2065,7 +2065,7 @@
 julia> set_normalized_rhs(con, 4)
 
 julia> con
-con : 2 x ≤ 4
source
set_normalized_rhs(
+con : 2 x ≤ 4
source
set_normalized_rhs(
     constraints::AbstractVector{<:ConstraintRef},
     values::AbstractVector{<:Number}
 )

Set the right-hand side terms of all constraints to values.

Note that prior to this step, JuMP will aggregate all constant terms onto the right-hand side of the constraint. For example, given a constraint 2x + 1 <= 2, set_normalized_rhs([con], [4]) will create the constraint 2x <= 4, not 2x + 1 <= 4.

Example

julia> model = Model();
@@ -2084,12 +2084,12 @@
 con1 : 2 x ≤ 4
 
 julia> con2
-con2 : 3 x ≤ 5
source

set_objective

set_objective

JuMP.set_objectiveFunction
set_objective(model::AbstractModel, sense::MOI.OptimizationSense, func)

The functional equivalent of the @objective macro.

Sets the objective sense and objective function simultaneously, and is equivalent to calling set_objective_sense and set_objective_function separately.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
 
-julia> set_objective(model, MIN_SENSE, x)
source

set_objective_coefficient

set_objective_coefficient

JuMP.set_objective_coefficientFunction
set_objective_coefficient(
     model::GenericModel,
     variable::GenericVariableRef,
     coefficient::Real,
@@ -2103,7 +2103,7 @@
 julia> set_objective_coefficient(model, x, 3)
 
 julia> objective_function(model)
-3 x + 1
source
set_objective_coefficient(
+3 x + 1
source
set_objective_coefficient(
     model::GenericModel,
     variables::Vector{<:GenericVariableRef},
     coefficients::Vector{<:Real},
@@ -2119,7 +2119,7 @@
 julia> set_objective_coefficient(model, [x, y], [5, 4])
 
 julia> objective_function(model)
-5 x + 4 y + 1
source
set_objective_coefficient(
+5 x + 4 y + 1
source
set_objective_coefficient(
     model::GenericModel{T},
     variable_1::GenericVariableRef{T},
     variable_2::GenericVariableRef{T},
@@ -2136,7 +2136,7 @@
 julia> set_objective_coefficient(model, x[1], x[2], 3)
 
 julia> objective_function(model)
-2 x[1]² + 3 x[1]*x[2]
source
set_objective_coefficient(
+2 x[1]² + 3 x[1]*x[2]
source
set_objective_coefficient(
     model::GenericModel{T},
     variables_1::AbstractVector{<:GenericVariableRef{T}},
     variables_2::AbstractVector{<:GenericVariableRef{T}},
@@ -2151,7 +2151,7 @@
 julia> set_objective_coefficient(model, [x[1], x[1]], [x[1], x[2]], [2, 3])
 
 julia> objective_function(model)
-2 x[1]² + 3 x[1]*x[2]
source

set_objective_function

set_objective_function

JuMP.set_objective_functionFunction
set_objective_function(model::GenericModel, func::MOI.AbstractFunction)
 set_objective_function(model::GenericModel, func::AbstractJuMPScalar)
 set_objective_function(model::GenericModel, func::Real)
 set_objective_function(model::GenericModel, func::Vector{<:AbstractJuMPScalar})

Sets the objective function of the model to the given function.

See set_objective_sense to set the objective sense.

These are low-level functions; the recommended way to set the objective is with the @objective macro.

Example

julia> model = Model();
@@ -2166,7 +2166,7 @@
 julia> set_objective_function(model, 2 * x + 1)
 
 julia> objective_function(model)
-2 x + 1
source

set_objective_sense

JuMP.set_objective_senseFunction
set_objective_sense(model::GenericModel, sense::MOI.OptimizationSense)

Sets the objective sense of the model to the given sense.

See set_objective_function to set the objective function.

These are low-level functions; the recommended way to set the objective is with the @objective macro.

Example

julia> model = Model();
+2 x + 1
source

set_objective_sense

JuMP.set_objective_senseFunction
set_objective_sense(model::GenericModel, sense::MOI.OptimizationSense)

Sets the objective sense of the model to the given sense.

See set_objective_function to set the objective function.

These are low-level functions; the recommended way to set the objective is with the @objective macro.

Example

julia> model = Model();
 
 julia> objective_sense(model)
 FEASIBILITY_SENSE::OptimizationSense = 2
@@ -2174,7 +2174,7 @@
 julia> set_objective_sense(model, MOI.MAX_SENSE)
 
 julia> objective_sense(model)
-MAX_SENSE::OptimizationSense = 1
source

set_optimize_hook

JuMP.set_optimize_hookFunction
set_optimize_hook(model::GenericModel, f::Union{Function,Nothing})

Set the function f as the optimize hook for model.

f should have a signature f(model::GenericModel; kwargs...), where the kwargs are those passed to optimize!.

Notes

  • The optimize hook should generally modify the model, or some external state in some way, and then call optimize!(model; ignore_optimize_hook = true) to optimize the problem, bypassing the hook.
  • Use set_optimize_hook(model, nothing) to unset an optimize hook.

Example

julia> model = Model();
+MAX_SENSE::OptimizationSense = 1
source

set_optimize_hook

JuMP.set_optimize_hookFunction
set_optimize_hook(model::GenericModel, f::Union{Function,Nothing})

Set the function f as the optimize hook for model.

f should have a signature f(model::GenericModel; kwargs...), where the kwargs are those passed to optimize!.

Notes

  • The optimize hook should generally modify the model, or some external state in some way, and then call optimize!(model; ignore_optimize_hook = true) to optimize the problem, bypassing the hook.
  • Use set_optimize_hook(model, nothing) to unset an optimize hook.

Example

julia> model = Model();
 
 julia> function my_hook(model::Model; kwargs...)
            println(kwargs)
@@ -2191,7 +2191,7 @@
 Base.Pairs{Symbol, Bool, Tuple{Symbol}, @NamedTuple{test_arg::Bool}}(:test_arg => 1)
 Calling with `ignore_optimize_hook = true`
 ERROR: NoOptimizer()
-[...]
source

set_optimizer

set_optimizer

JuMP.set_optimizerFunction
set_optimizer(
     model::GenericModel,
     optimizer_factory;
     add_bridges::Bool = true,
@@ -2201,7 +2201,7 @@
 
 julia> set_optimizer(model, () -> HiGHS.Optimizer())
 
-julia> set_optimizer(model, HiGHS.Optimizer; add_bridges = false)
source

set_parameter_value

set_parameter_value

JuMP.set_parameter_valueFunction
set_parameter_value(x::GenericVariableRef, value)

Update the parameter constraint on the variable x to value.

Errors if x is not a parameter.

See also ParameterRef, is_parameter, parameter_value.

Example

julia> model = Model();
 
 julia> @variable(model, p in Parameter(2))
 p
@@ -2212,7 +2212,7 @@
 julia> set_parameter_value(p, 2.5)
 
 julia> parameter_value(p)
-2.5
source

set_silent

JuMP.set_silentFunction
set_silent(model::GenericModel)

Takes precedence over any other attribute controlling verbosity and requires the solver to produce no output.

See also: unset_silent.

Example

julia> import Ipopt
+2.5
source

set_silent

JuMP.set_silentFunction
set_silent(model::GenericModel)

Takes precedence over any other attribute controlling verbosity and requires the solver to produce no output.

See also: unset_silent.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -2224,7 +2224,7 @@
 julia> unset_silent(model)
 
 julia> get_attribute(model, MOI.Silent())
-false
source

set_start_value

set_start_value

JuMP.set_start_valueFunction
set_start_value(con_ref::ConstraintRef, value)

Set the primal start value (MOI.ConstraintPrimalStart) of the constraint con_ref to value.

To remove a primal start value set it to nothing.

See also start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 2.0);
 
@@ -2239,7 +2239,7 @@
 
 julia> set_start_value(c, nothing)
 
-julia> start_value(c)
source
set_start_value(variable::GenericVariableRef, value::Union{Real,Nothing})

Set the start value (MOI.VariablePrimalStart) of the variable to value.

Pass nothing to unset the start value.

Note: VariablePrimalStarts are sometimes called "MIP-starts" or "warmstarts".

See also: has_start_value, start_value.

Example

julia> model = Model();
+julia> start_value(c)
source
set_start_value(variable::GenericVariableRef, value::Union{Real,Nothing})

Set the start value (MOI.VariablePrimalStart) of the variable to value.

Pass nothing to unset the start value.

Note: VariablePrimalStarts are sometimes called "MIP-starts" or "warmstarts".

See also: has_start_value, start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 1.5);
 
@@ -2265,13 +2265,13 @@
 true
 
 julia> start_value(y)
-2.0
source

set_start_values

set_start_values

JuMP.set_start_valuesFunction
set_start_values(
     model::GenericModel;
     variable_primal_start::Union{Nothing,Function} = value,
     constraint_primal_start::Union{Nothing,Function} = value,
     constraint_dual_start::Union{Nothing,Function} = dual,
     nonlinear_dual_start::Union{Nothing,Function} = nonlinear_dual_start_value,
-)

Set the primal and dual starting values in model using the functions provided.

If any keyword argument is nothing, the corresponding start value is skipped.

If the optimizer does not support setting the starting value, the value will be skipped.

variable_primal_start

This function controls the primal starting solution for the variables. It is equivalent to calling set_start_value for each variable, or setting the MOI.VariablePrimalStart attribute.

If it is a function, it must have the form variable_primal_start(x::VariableRef) that maps each variable x to the starting primal value.

The default is value.

constraint_primal_start

This function controls the primal starting solution for the constraints. It is equivalent to calling set_start_value for each constraint, or setting the MOI.ConstraintPrimalStart attribute.

If it is a function, it must have the form constraint_primal_start(ci::ConstraintRef) that maps each constraint ci to the starting primal value.

The default is value.

constraint_dual_start

This function controls the dual starting solution for the constraints. It is equivalent to calling set_dual_start_value for each constraint, or setting the MOI.ConstraintDualStart attribute.

If it is a function, it must have the form constraint_dual_start(ci::ConstraintRef) that maps each constraint ci to the starting dual value.

The default is dual.

nonlinear_dual_start

This function controls the dual starting solution for the nonlinear constraints It is equivalent to calling set_nonlinear_dual_start_value.

If it is a function, it must have the form nonlinear_dual_start(model::GenericModel) that returns a vector corresponding to the dual start of the constraints.

The default is nonlinear_dual_start_value.

source

set_string_names_on_creation

JuMP.set_string_names_on_creationFunction
set_string_names_on_creation(model::GenericModel, value::Bool)

Set the default argument of the set_string_name keyword in the @variable and @constraint macros to value.

The set_string_name keyword is used to determine whether to assign String names to all variables and constraints in model.

By default, value is true. However, for larger models calling set_string_names_on_creation(model, false) can improve performance at the cost of reducing the readability of printing and solver log messages.

Example

julia> import HiGHS
+)

Set the primal and dual starting values in model using the functions provided.

If any keyword argument is nothing, the corresponding start value is skipped.

If the optimizer does not support setting the starting value, the value will be skipped.

variable_primal_start

This function controls the primal starting solution for the variables. It is equivalent to calling set_start_value for each variable, or setting the MOI.VariablePrimalStart attribute.

If it is a function, it must have the form variable_primal_start(x::VariableRef) that maps each variable x to the starting primal value.

The default is value.

constraint_primal_start

This function controls the primal starting solution for the constraints. It is equivalent to calling set_start_value for each constraint, or setting the MOI.ConstraintPrimalStart attribute.

If it is a function, it must have the form constraint_primal_start(ci::ConstraintRef) that maps each constraint ci to the starting primal value.

The default is value.

constraint_dual_start

This function controls the dual starting solution for the constraints. It is equivalent to calling set_dual_start_value for each constraint, or setting the MOI.ConstraintDualStart attribute.

If it is a function, it must have the form constraint_dual_start(ci::ConstraintRef) that maps each constraint ci to the starting dual value.

The default is dual.

nonlinear_dual_start

This function controls the dual starting solution for the nonlinear constraints It is equivalent to calling set_nonlinear_dual_start_value.

If it is a function, it must have the form nonlinear_dual_start(model::GenericModel) that returns a vector corresponding to the dual start of the constraints.

The default is nonlinear_dual_start_value.

source

set_string_names_on_creation

JuMP.set_string_names_on_creationFunction
set_string_names_on_creation(model::GenericModel, value::Bool)

Set the default argument of the set_string_name keyword in the @variable and @constraint macros to value.

The set_string_name keyword is used to determine whether to assign String names to all variables and constraints in model.

By default, value is true. However, for larger models calling set_string_names_on_creation(model, false) can improve performance at the cost of reducing the readability of printing and solver log messages.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -2281,7 +2281,7 @@
 julia> set_string_names_on_creation(model, false)
 
 julia> set_string_names_on_creation(model)
-false
source

set_time_limit_sec

set_time_limit_sec

set_upper_bound

set_upper_bound

shadow_price

JuMP.shadow_priceFunction
shadow_price(con_ref::ConstraintRef)

Return the change in the objective from an infinitesimal relaxation of the constraint.

The shadow price is computed from dual and can be queried only when has_duals is true and the objective sense is MIN_SENSE or MAX_SENSE (not FEASIBILITY_SENSE).

See also reduced_cost.

Comparison to dual

The shadow prices differ at most in sign from the dual value depending on the objective sense. The differences are summarized in the table:

MinMax
f(x) <= b+1-1
f(x) >= b-1+1

Notes

  • The function simply translates signs from dual and does not validate the conditions needed to guarantee the sensitivity interpretation of the shadow price. The caller is responsible, for example, for checking whether the solver converged to an optimal primal-dual pair or a proof of infeasibility.
  • The computation is based on the current objective sense of the model. If this has changed since the last solve, the results will be incorrect.
  • Relaxation of equality constraints (and hence the shadow price) is defined based on which sense of the equality constraint is active.

Example

julia> import HiGHS
+2.0
source

shadow_price

JuMP.shadow_priceFunction
shadow_price(con_ref::ConstraintRef)

Return the change in the objective from an infinitesimal relaxation of the constraint.

The shadow price is computed from dual and can be queried only when has_duals is true and the objective sense is MIN_SENSE or MAX_SENSE (not FEASIBILITY_SENSE).

See also reduced_cost.

Comparison to dual

The shadow prices differ at most in sign from the dual value depending on the objective sense. The differences are summarized in the table:

MinMax
f(x) <= b+1-1
f(x) >= b-1+1

Notes

  • The function simply translates signs from dual and does not validate the conditions needed to guarantee the sensitivity interpretation of the shadow price. The caller is responsible, for example, for checking whether the solver converged to an optimal primal-dual pair or a proof of infeasibility.
  • The computation is based on the current objective sense of the model. If this has changed since the last solve, the results will be incorrect.
  • Relaxation of equality constraints (and hence the shadow price) is defined based on which sense of the equality constraint is active.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -2323,7 +2323,7 @@
 true
 
 julia> shadow_price(c)
-2.0
source

shape

JuMP.shapeFunction
shape(c::AbstractConstraint)::AbstractShape

Return the shape of the constraint c.

Example

julia> model = Model();
+2.0
source

shape

JuMP.shapeFunction
shape(c::AbstractConstraint)::AbstractShape

Return the shape of the constraint c.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -2335,20 +2335,20 @@
 julia> d = @constraint(model, x in SOS1());
 
 julia> shape(constraint_object(d))
-VectorShape()
source

show_backend_summary

JuMP.show_backend_summaryFunction
show_backend_summary(io::IO, model::GenericModel)

Print a summary of the optimizer backing model.

Extensions

AbstractModels should implement this method.

Example

julia> model = Model();
+VectorShape()
source

show_backend_summary

JuMP.show_backend_summaryFunction
show_backend_summary(io::IO, model::GenericModel)

Print a summary of the optimizer backing model.

Extensions

AbstractModels should implement this method.

Example

julia> model = Model();
 
 julia> show_backend_summary(stdout, model)
 Model mode: AUTOMATIC
 CachingOptimizer state: NO_OPTIMIZER
-Solver name: No optimizer attached.
source

show_constraints_summary

JuMP.show_constraints_summaryFunction
show_constraints_summary(io::IO, model::AbstractModel)

Write to io a summary of the number of constraints.

Extensions

AbstractModels should implement this method.

Example

julia> model = Model();
+Solver name: No optimizer attached.
source

show_constraints_summary

JuMP.show_constraints_summaryFunction
show_constraints_summary(io::IO, model::AbstractModel)

Write to io a summary of the number of constraints.

Extensions

AbstractModels should implement this method.

Example

julia> model = Model();
 
 julia> @variable(model, x >= 0);
 
 julia> show_constraints_summary(stdout, model)
-`VariableRef`-in-`MathOptInterface.GreaterThan{Float64}`: 1 constraint
source

show_objective_function_summary

JuMP.show_objective_function_summaryFunction
show_objective_function_summary(io::IO, model::AbstractModel)

Write to io a summary of the objective function type.

Extensions

AbstractModels should implement this method.

Example

julia> model = Model();
+`VariableRef`-in-`MathOptInterface.GreaterThan{Float64}`: 1 constraint
source

show_objective_function_summary

JuMP.show_objective_function_summaryFunction
show_objective_function_summary(io::IO, model::AbstractModel)

Write to io a summary of the objective function type.

Extensions

AbstractModels should implement this method.

Example

julia> model = Model();
 
 julia> show_objective_function_summary(stdout, model)
-Objective function type: AffExpr
source

simplex_iterations

JuMP.simplex_iterationsFunction
simplex_iterations(model::GenericModel)

If available, returns the cumulative number of simplex iterations during the most-recent optimization (the MOI.SimplexIterations attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
+Objective function type: AffExpr
source

simplex_iterations

JuMP.simplex_iterationsFunction
simplex_iterations(model::GenericModel)

If available, returns the cumulative number of simplex iterations during the most-recent optimization (the MOI.SimplexIterations attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -2357,7 +2357,7 @@
 julia> optimize!(model)
 
 julia> simplex_iterations(model)
-0
source

solution_summary

JuMP.solution_summaryFunction
solution_summary(model::GenericModel; result::Int = 1, verbose::Bool = false)

Return a struct that can be used print a summary of the solution in result result.

If verbose=true, write out the primal solution for every variable and the dual solution for every constraint, excluding those with empty names.

Example

When called at the REPL, the summary is automatically printed:

julia> model = Model();
+0
source

solution_summary

JuMP.solution_summaryFunction
solution_summary(model::GenericModel; result::Int = 1, verbose::Bool = false)

Return a struct that can be used print a summary of the solution in result result.

If verbose=true, write out the primal solution for every variable and the dual solution for every constraint, excluding those with empty names.

Example

When called at the REPL, the summary is automatically printed:

julia> model = Model();
 
 julia> solution_summary(model)
 * Solver : No optimizer attached.
@@ -2393,7 +2393,7 @@
   Primal status      : NO_SOLUTION
   Dual status        : NO_SOLUTION
 
-* Work counters
source

solve_time

JuMP.solve_timeFunction
solve_time(model::GenericModel)

If available, returns the solve time in wall-clock seconds reported by the solver (the MOI.SolveTimeSec attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
+* Work counters
source

solve_time

JuMP.solve_timeFunction
solve_time(model::GenericModel)

If available, returns the solve time in wall-clock seconds reported by the solver (the MOI.SolveTimeSec attribute).

Throws a MOI.GetAttributeNotAllowed error if the attribute is not implemented by the solver.

Example

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer);
 
@@ -2402,7 +2402,7 @@
 julia> optimize!(model)
 
 julia> solve_time(model)
-1.0488089174032211e-5
source

solver_name

JuMP.solver_nameFunction
solver_name(model::GenericModel)

If available, returns the MOI.SolverName property of the underlying optimizer.

Returns "No optimizer attached." in AUTOMATIC or MANUAL modes when no optimizer is attached.

Returns "SolverName() attribute not implemented by the optimizer." if the attribute is not implemented.

Example

julia> import Ipopt
+1.0488089174032211e-5
source

solver_name

JuMP.solver_nameFunction
solver_name(model::GenericModel)

If available, returns the MOI.SolverName property of the underlying optimizer.

Returns "No optimizer attached." in AUTOMATIC or MANUAL modes when no optimizer is attached.

Returns "SolverName() attribute not implemented by the optimizer." if the attribute is not implemented.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -2417,7 +2417,7 @@
 julia> model = Model(MOI.FileFormats.MPS.Model);
 
 julia> solver_name(model)
-"SolverName() attribute not implemented by the optimizer."
source

start_value

JuMP.start_valueFunction
start_value(con_ref::ConstraintRef)

Return the primal start value (MOI.ConstraintPrimalStart) of the constraint con_ref.

If no primal start value has been set, start_value will return nothing.

See also set_start_value.

Example

julia> model = Model();
+"SolverName() attribute not implemented by the optimizer."
source

start_value

JuMP.start_valueFunction
start_value(con_ref::ConstraintRef)

Return the primal start value (MOI.ConstraintPrimalStart) of the constraint con_ref.

If no primal start value has been set, start_value will return nothing.

See also set_start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 2.0);
 
@@ -2432,7 +2432,7 @@
 
 julia> set_start_value(c, nothing)
 
-julia> start_value(c)
source
start_value(v::GenericVariableRef)

Return the start value (MOI.VariablePrimalStart) of the variable v.

Note: VariablePrimalStarts are sometimes called "MIP-starts" or "warmstarts".

See also: has_start_value, set_start_value.

Example

julia> model = Model();
+julia> start_value(c)
source
start_value(v::GenericVariableRef)

Return the start value (MOI.VariablePrimalStart) of the variable v.

Note: VariablePrimalStarts are sometimes called "MIP-starts" or "warmstarts".

See also: has_start_value, set_start_value.

Example

julia> model = Model();
 
 julia> @variable(model, x, start = 1.5);
 
@@ -2453,12 +2453,12 @@
 true
 
 julia> start_value(y)
-2.0
source

termination_status

termination_status

time_limit_sec

time_limit_sec

JuMP.time_limit_secFunction
time_limit_sec(model::GenericModel)

Return the time limit (in seconds) of the model.

Returns nothing if unset.

See also: set_time_limit_sec, unset_time_limit_sec.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -2471,7 +2471,7 @@
 
 julia> unset_time_limit_sec(model)
 
-julia> time_limit_sec(model)
source

triangle_vec

JuMP.triangle_vecFunction
triangle_vec(matrix::Matrix)

Return the upper triangle of a matrix concatenated into a vector in the order required by JuMP and MathOptInterface for Triangle sets.

Example

julia> model = Model();
+julia> time_limit_sec(model)
source

triangle_vec

JuMP.triangle_vecFunction
triangle_vec(matrix::Matrix)

Return the upper triangle of a matrix concatenated into a vector in the order required by JuMP and MathOptInterface for Triangle sets.

Example

julia> model = Model();
 
 julia> @variable(model, X[1:3, 1:3], Symmetric);
 
@@ -2479,7 +2479,7 @@
 t
 
 julia> @constraint(model, [t; triangle_vec(X)] in MOI.RootDetConeTriangle(3))
-[t, X[1,1], X[1,2], X[2,2], X[1,3], X[2,3], X[3,3]] ∈ MathOptInterface.RootDetConeTriangle(3)
source

unfix

JuMP.unfixFunction
unfix(v::GenericVariableRef)

Delete the fixing constraint of a variable.

Error if one does not exist.

See also FixRef, is_fixed, fix_value, fix.

Example

julia> model = Model();
+[t, X[1,1], X[1,2], X[2,2], X[1,3], X[2,3], X[3,3]] ∈ MathOptInterface.RootDetConeTriangle(3)
source

unfix

JuMP.unfixFunction
unfix(v::GenericVariableRef)

Delete the fixing constraint of a variable.

Error if one does not exist.

See also FixRef, is_fixed, fix_value, fix.

Example

julia> model = Model();
 
 julia> @variable(model, x == 1);
 
@@ -2489,7 +2489,7 @@
 julia> unfix(x)
 
 julia> is_fixed(x)
-false
source

unregister

JuMP.unregisterFunction
unregister(model::GenericModel, key::Symbol)

Unregister the name key from model so that a new variable, constraint, or expression can be created with the same key.

Note that this will not delete the object model[key]; it will just remove the reference at model[key]. To delete the object, use delete as well.

See also: delete, object_dictionary.

Example

julia> model = Model();
+false
source

unregister

JuMP.unregisterFunction
unregister(model::GenericModel, key::Symbol)

Unregister the name key from model so that a new variable, constraint, or expression can be created with the same key.

Note that this will not delete the object model[key]; it will just remove the reference at model[key]. To delete the object, use delete as well.

See also: delete, object_dictionary.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -2516,7 +2516,7 @@
 x
 
 julia> num_variables(model)
-2
source

unsafe_backend

JuMP.unsafe_backendFunction
unsafe_backend(model::GenericModel)

Return the innermost optimizer associated with the JuMP model model.

This function should only be used by advanced users looking to access low-level solver-specific functionality. It has a high-risk of incorrect usage. We strongly suggest you use the alternative suggested below.

See also: backend.

To obtain the index of a variable or constraint in the unsafe backend, use optimizer_index.

Unsafe behavior

This function is unsafe for two main reasons.

First, the formulation and order of variables and constraints in the unsafe backend may be different to the variables and constraints in model. This can happen because of bridges, or because the solver requires the variables or constraints in a specific order. In addition, the variable or constraint index returned by index at the JuMP level may be different to the index of the corresponding variable or constraint in the unsafe_backend. There is no solution to this. Use the alternative suggested below instead.

Second, the unsafe_backend may be empty, or lack some modifications made to the JuMP model. Thus, before calling unsafe_backend you should first call MOI.Utilities.attach_optimizer to ensure that the backend is synchronized with the JuMP model.

julia> import HiGHS
+2
source

unsafe_backend

JuMP.unsafe_backendFunction
unsafe_backend(model::GenericModel)

Return the innermost optimizer associated with the JuMP model model.

This function should only be used by advanced users looking to access low-level solver-specific functionality. It has a high-risk of incorrect usage. We strongly suggest you use the alternative suggested below.

See also: backend.

To obtain the index of a variable or constraint in the unsafe backend, use optimizer_index.

Unsafe behavior

This function is unsafe for two main reasons.

First, the formulation and order of variables and constraints in the unsafe backend may be different to the variables and constraints in model. This can happen because of bridges, or because the solver requires the variables or constraints in a specific order. In addition, the variable or constraint index returned by index at the JuMP level may be different to the index of the corresponding variable or constraint in the unsafe_backend. There is no solution to this. Use the alternative suggested below instead.

Second, the unsafe_backend may be empty, or lack some modifications made to the JuMP model. Thus, before calling unsafe_backend you should first call MOI.Utilities.attach_optimizer to ensure that the backend is synchronized with the JuMP model.

julia> import HiGHS
 
 julia> model = Model(HiGHS.Optimizer)
 A JuMP Model
@@ -2557,7 +2557,7 @@
 A HiGHS model with 1 columns and 0 rows.
 
 julia> index(x)
-MOI.VariableIndex(1)
source

unset_binary

unset_binary

JuMP.unset_binaryFunction
unset_binary(variable_ref::GenericVariableRef)

Remove the binary constraint on the variable variable_ref.

See also BinaryRef, is_binary, set_binary.

Example

julia> model = Model();
 
 julia> @variable(model, x, Bin);
 
@@ -2567,7 +2567,7 @@
 julia> unset_binary(x)
 
 julia> is_binary(x)
-false
source

unset_integer

unset_integer

JuMP.unset_integerFunction
unset_integer(variable_ref::GenericVariableRef)

Remove the integrality constraint on the variable variable_ref.

Errors if one does not exist.

See also IntegerRef, is_integer, set_integer.

Example

julia> model = Model();
 
 julia> @variable(model, x, Int);
 
@@ -2577,7 +2577,7 @@
 julia> unset_integer(x)
 
 julia> is_integer(x)
-false
source

unset_silent

JuMP.unset_silentFunction
unset_silent(model::GenericModel)

Neutralize the effect of the set_silent function and let the solver attributes control the verbosity.

See also: set_silent.

Example

julia> import Ipopt
+false
source

unset_silent

JuMP.unset_silentFunction
unset_silent(model::GenericModel)

Neutralize the effect of the set_silent function and let the solver attributes control the verbosity.

See also: set_silent.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -2589,7 +2589,7 @@
 julia> unset_silent(model)
 
 julia> get_attribute(model, MOI.Silent())
-false
source

unset_time_limit_sec

unset_time_limit_sec

JuMP.unset_time_limit_secFunction
unset_time_limit_sec(model::GenericModel)

Unset the time limit of the solver.

See also: set_time_limit_sec, time_limit_sec.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -2602,19 +2602,19 @@
 
 julia> unset_time_limit_sec(model)
 
-julia> time_limit_sec(model)
source

upper_bound

upper_bound

value

JuMP.valueFunction
value(con_ref::ConstraintRef; result::Int = 1)

Return the primal value of constraint con_ref associated with result index result of the most-recent solution returned by the solver.

That is, if con_ref is the reference of a constraint func-in-set, it returns the value of func evaluated at the value of the variables (given by value(::GenericVariableRef)).

Use has_values to check if a result exists before asking for values.

See also: result_count.

Note

For scalar constraints, the constant is moved to the set so it is not taken into account in the primal value of the constraint. For instance, the constraint @constraint(model, 2x + 3y + 1 == 5) is transformed into 2x + 3y-in-MOI.EqualTo(4) so the value returned by this function is the evaluation of 2x + 3y.

source
value(var_value::Function, con_ref::ConstraintRef)

Evaluate the primal value of the constraint con_ref using var_value(v) as the value for each variable v.

source
value(v::GenericVariableRef; result = 1)

Return the value of variable v associated with result index result of the most-recent returned by the solver.

Use has_values to check if a result exists before asking for values.

See also: result_count.

source
value(var_value::Function, v::GenericVariableRef)

Evaluate the value of the variable v as var_value(v).

source
value(var_value::Function, ex::GenericAffExpr)

Evaluate ex using var_value(v) as the value for each variable v.

source
value(v::GenericAffExpr; result::Int = 1)

Return the value of the GenericAffExpr v associated with result index result of the most-recent solution returned by the solver.

See also: result_count.

source
value(var_value::Function, ex::GenericQuadExpr)

Evaluate ex using var_value(v) as the value for each variable v.

source
value(v::GenericQuadExpr; result::Int = 1)

Return the value of the GenericQuadExpr v associated with result index result of the most-recent solution returned by the solver.

Replaces getvalue for most use cases.

See also: result_count.

source
value(p::NonlinearParameter)

Return the current value stored in the nonlinear parameter p.

Example

julia> model = Model();
+1.0
source

value

JuMP.valueFunction
value(con_ref::ConstraintRef; result::Int = 1)

Return the primal value of constraint con_ref associated with result index result of the most-recent solution returned by the solver.

That is, if con_ref is the reference of a constraint func-in-set, it returns the value of func evaluated at the value of the variables (given by value(::GenericVariableRef)).

Use has_values to check if a result exists before asking for values.

See also: result_count.

Note

For scalar constraints, the constant is moved to the set so it is not taken into account in the primal value of the constraint. For instance, the constraint @constraint(model, 2x + 3y + 1 == 5) is transformed into 2x + 3y-in-MOI.EqualTo(4) so the value returned by this function is the evaluation of 2x + 3y.

source
value(var_value::Function, con_ref::ConstraintRef)

Evaluate the primal value of the constraint con_ref using var_value(v) as the value for each variable v.

source
value(v::GenericVariableRef; result = 1)

Return the value of variable v associated with result index result of the most-recent returned by the solver.

Use has_values to check if a result exists before asking for values.

See also: result_count.

source
value(var_value::Function, v::GenericVariableRef)

Evaluate the value of the variable v as var_value(v).

source
value(var_value::Function, ex::GenericAffExpr)

Evaluate ex using var_value(v) as the value for each variable v.

source
value(v::GenericAffExpr; result::Int = 1)

Return the value of the GenericAffExpr v associated with result index result of the most-recent solution returned by the solver.

See also: result_count.

source
value(var_value::Function, ex::GenericQuadExpr)

Evaluate ex using var_value(v) as the value for each variable v.

source
value(v::GenericQuadExpr; result::Int = 1)

Return the value of the GenericQuadExpr v associated with result index result of the most-recent solution returned by the solver.

Replaces getvalue for most use cases.

See also: result_count.

source
value(p::NonlinearParameter)

Return the current value stored in the nonlinear parameter p.

Example

julia> model = Model();
 
 julia> @NLparameter(model, p == 10)
 p == 10.0
 
 julia> value(p)
-10.0
source
value(ex::NonlinearExpression; result::Int = 1)

Return the value of the NonlinearExpression ex associated with result index result of the most-recent solution returned by the solver.

See also: result_count.

source
value(var_value::Function, ex::NonlinearExpression)

Evaluate ex using var_value(v) as the value for each variable v.

source
value(c::NonlinearConstraintRef; result::Int = 1)

Return the value of the NonlinearConstraintRef c associated with result index result of the most-recent solution returned by the solver.

See also: result_count.

source
value(var_value::Function, c::NonlinearConstraintRef)

Evaluate c using var_value(v) as the value for each variable v.

source

value_type

JuMP.value_typeFunction
value_type(::Type{<:Union{AbstractModel,AbstractVariableRef}})

Return the return type of value for variables of that model. It defaults to Float64 if it is not implemented.

Example

julia> value_type(GenericModel{BigFloat})
-BigFloat
source

variable_by_name

JuMP.variable_by_nameFunction
variable_by_name(
+10.0
source
value(ex::NonlinearExpression; result::Int = 1)

Return the value of the NonlinearExpression ex associated with result index result of the most-recent solution returned by the solver.

See also: result_count.

source
value(var_value::Function, ex::NonlinearExpression)

Evaluate ex using var_value(v) as the value for each variable v.

source
value(c::NonlinearConstraintRef; result::Int = 1)

Return the value of the NonlinearConstraintRef c associated with result index result of the most-recent solution returned by the solver.

See also: result_count.

source
value(var_value::Function, c::NonlinearConstraintRef)

Evaluate c using var_value(v) as the value for each variable v.

source

value_type

JuMP.value_typeFunction
value_type(::Type{<:Union{AbstractModel,AbstractVariableRef}})

Return the return type of value for variables of that model. It defaults to Float64 if it is not implemented.

Example

julia> value_type(GenericModel{BigFloat})
+BigFloat
source

variable_by_name

JuMP.variable_by_nameFunction
variable_by_name(
     model::AbstractModel,
     name::String,
 )::Union{AbstractVariableRef,Nothing}

Returns the reference of the variable with name attribute name or Nothing if no variable has this name attribute. Throws an error if several variables have name as their name attribute.

Example

julia> model = Model();
@@ -2657,12 +2657,12 @@
  u[2]
 
 julia> variable_by_name(model, "u[2]")
-u[2]
source

variable_ref_type

JuMP.variable_ref_typeFunction
variable_ref_type(::Union{F,Type{F}}) where {F}

A helper function used internally by JuMP and some JuMP extensions. Returns the variable type associated with the model or expression type F.

source

vectorize

JuMP.vectorizeFunction
vectorize(matrix::AbstractMatrix, ::Shape)

Convert the matrix into a vector according to Shape.

source

write_to_file

variable_ref_type

JuMP.variable_ref_typeFunction
variable_ref_type(::Union{F,Type{F}}) where {F}

A helper function used internally by JuMP and some JuMP extensions. Returns the variable type associated with the model or expression type F.

source

vectorize

JuMP.vectorizeFunction
vectorize(matrix::AbstractMatrix, ::Shape)

Convert the matrix into a vector according to Shape.

source

write_to_file

JuMP.write_to_fileFunction
write_to_file(
     model::GenericModel,
     filename::String;
     format::MOI.FileFormats.FileFormat = MOI.FileFormats.FORMAT_AUTOMATIC,
     kwargs...,
-)

Write the JuMP model model to filename in the format format.

If the filename ends in .gz, it will be compressed using GZip. If the filename ends in .bz2, it will be compressed using BZip2.

Other kwargs are passed to the Model constructor of the chosen format.

source

AbstractConstraint

JuMP.AbstractConstraintType
abstract type AbstractConstraint

An abstract base type for all constraint types. AbstractConstraints store the function and set directly, unlike ConstraintRefs that are merely references to constraints stored in a model. AbstractConstraints do not need to be attached to a model.

source

AbstractJuMPScalar

JuMP.AbstractJuMPScalarType
AbstractJuMPScalar <: MutableArithmetics.AbstractMutable

Abstract base type for all scalar types

The subtyping of AbstractMutable will allow calls of some Base functions to be redirected to a method in MA that handles type promotion more carefully (for example the promotion in sparse matrix products in SparseArrays usually does not work for JuMP types) and exploits the mutability of AffExpr and QuadExpr.

source

AbstractModel

JuMP.AbstractModelType
AbstractModel

An abstract type that should be subtyped for users creating JuMP extensions.

source

AbstractScalarSet

JuMP.AbstractScalarSetType
AbstractScalarSet

An abstract type for defining new scalar sets in JuMP.

Implement moi_set(::AbstractScalarSet) to convert the type into an MOI set.

See also: moi_set.

source

AbstractShape

AbstractVariable

AbstractVariableRef

JuMP.AbstractVariableRefType
AbstractVariableRef

Variable returned by add_variable. Affine (resp. quadratic) operations with variables of type V<:AbstractVariableRef and coefficients of type T create a GenericAffExpr{T,V} (resp. GenericQuadExpr{T,V}).

source

AbstractVectorSet

JuMP.AbstractVectorSetType
AbstractVectorSet

An abstract type for defining new sets in JuMP.

Implement moi_set(::AbstractVectorSet, dim::Int) to convert the type into an MOI set.

See also: moi_set.

source

AffExpr

ArrayShape

JuMP.ArrayShapeType
ArrayShape{N}(dims::NTuple{N,Int}) where {N}

An AbstractShape that represents array-valued constraints.

Example

julia> model = Model();
+)

Write the JuMP model model to filename in the format format.

If the filename ends in .gz, it will be compressed using GZip. If the filename ends in .bz2, it will be compressed using BZip2.

Other kwargs are passed to the Model constructor of the chosen format.

source

AbstractConstraint

JuMP.AbstractConstraintType
abstract type AbstractConstraint

An abstract base type for all constraint types. AbstractConstraints store the function and set directly, unlike ConstraintRefs that are merely references to constraints stored in a model. AbstractConstraints do not need to be attached to a model.

source

AbstractJuMPScalar

JuMP.AbstractJuMPScalarType
AbstractJuMPScalar <: MutableArithmetics.AbstractMutable

Abstract base type for all scalar types

The subtyping of AbstractMutable will allow calls of some Base functions to be redirected to a method in MA that handles type promotion more carefully (for example the promotion in sparse matrix products in SparseArrays usually does not work for JuMP types) and exploits the mutability of AffExpr and QuadExpr.

source

AbstractModel

JuMP.AbstractModelType
AbstractModel

An abstract type that should be subtyped for users creating JuMP extensions.

source

AbstractScalarSet

JuMP.AbstractScalarSetType
AbstractScalarSet

An abstract type for defining new scalar sets in JuMP.

Implement moi_set(::AbstractScalarSet) to convert the type into an MOI set.

See also: moi_set.

source

AbstractShape

AbstractVariable

AbstractVariableRef

JuMP.AbstractVariableRefType
AbstractVariableRef

Variable returned by add_variable. Affine (resp. quadratic) operations with variables of type V<:AbstractVariableRef and coefficients of type T create a GenericAffExpr{T,V} (resp. GenericQuadExpr{T,V}).

source

AbstractVectorSet

JuMP.AbstractVectorSetType
AbstractVectorSet

An abstract type for defining new sets in JuMP.

Implement moi_set(::AbstractVectorSet, dim::Int) to convert the type into an MOI set.

See also: moi_set.

source

AffExpr

ArrayShape

JuMP.ArrayShapeType
ArrayShape{N}(dims::NTuple{N,Int}) where {N}

An AbstractShape that represents array-valued constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2, 1:3]);
 
@@ -2671,12 +2671,12 @@
  x[2,1]  x[2,2]  x[2,3]] ∈ Nonnegatives()
 
 julia> shape(constraint_object(c))
-ArrayShape{2}((2, 3))
source

BinaryRef

JuMP.BinaryRefFunction
BinaryRef(v::GenericVariableRef)

Return a constraint reference to the constraint constraining v to be binary. Errors if one does not exist.

See also is_binary, set_binary, unset_binary.

Example

julia> model = Model();
+ArrayShape{2}((2, 3))
source

BinaryRef

JuMP.BinaryRefFunction
BinaryRef(v::GenericVariableRef)

Return a constraint reference to the constraint constraining v to be binary. Errors if one does not exist.

See also is_binary, set_binary, unset_binary.

Example

julia> model = Model();
 
 julia> @variable(model, x, Bin);
 
 julia> BinaryRef(x)
-x binary
source

BridgeableConstraint

BridgeableConstraint

JuMP.BridgeableConstraintType
BridgeableConstraint(
     constraint::C,
     bridge_type::B;
     coefficient_type::Type{T} = Float64,
@@ -2691,7 +2691,7 @@
 )
     constraint = ScalarConstraint(func, set)
     return BridgeableConstraint(constraint, CustomBridge)
-end

Note

JuMP extensions should extend JuMP.build_constraint only if they also defined CustomSet, for three reasons:

  1. It is problematic if multiple extensions overload the same JuMP method.
  2. A missing method will not inform the users that they forgot to load the extension module defining the build_constraint method.
  3. Defining a method where neither the function nor any of the argument types are defined in the package is called type piracy and is discouraged in the Julia style guide.
source

ComplexPlane

JuMP.ComplexPlaneType
ComplexPlane

Complex plane object that can be used to create a complex variable in the @variable macro.

Example

Consider the following example:

julia> model = Model();
+end

Note

JuMP extensions should extend JuMP.build_constraint only if they also defined CustomSet, for three reasons:

  1. It is problematic if multiple extensions overload the same JuMP method.
  2. A missing method will not inform the users that they forgot to load the extension module defining the build_constraint method.
  3. Defining a method where neither the function nor any of the argument types are defined in the package is called type piracy and is discouraged in the Julia style guide.
source

ComplexPlane

JuMP.ComplexPlaneType
ComplexPlane

Complex plane object that can be used to create a complex variable in the @variable macro.

Example

Consider the following example:

julia> model = Model();
 
 julia> @variable(model, x in ComplexPlane())
 real(x) + imag(x) im
@@ -2699,7 +2699,7 @@
 julia> all_variables(model)
 2-element Vector{VariableRef}:
  real(x)
- imag(x)

We see in the output of the last command that two real variables were created. The Julia variable x binds to an affine expression in terms of these two variables that parametrize the complex plane.

source

ComplexVariable

ConstraintNotOwned

JuMP.ConstraintNotOwnedType
struct ConstraintNotOwned{C<:ConstraintRef} <: Exception
+ imag(x)

We see in the output of the last command that two real variables were created. The Julia variable x binds to an affine expression in terms of these two variables that parametrize the complex plane.

source

ComplexVariable

ConstraintNotOwned

JuMP.ConstraintNotOwnedType
struct ConstraintNotOwned{C<:ConstraintRef} <: Exception
     constraint_ref::C
 end

An error thrown when the constraint constraint_ref was used in a model different to owner_model(constraint_ref).

Example

julia> model = Model();
 
@@ -2713,12 +2713,12 @@
 julia> MOI.get(model_new, MOI.ConstraintName(), c)
 ERROR: ConstraintNotOwned{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}, ScalarShape}}(c : x ≥ 0)
 Stacktrace:
-[...]
source

ConstraintRef

FixRef

JuMP.FixRefFunction
FixRef(v::GenericVariableRef)

Return a constraint reference to the constraint fixing the value of v.

Errors if one does not exist.

See also is_fixed, fix_value, fix, unfix.

Example

julia> model = Model();
+[...]
source

ConstraintRef

FixRef

JuMP.FixRefFunction
FixRef(v::GenericVariableRef)

Return a constraint reference to the constraint fixing the value of v.

Errors if one does not exist.

See also is_fixed, fix_value, fix, unfix.

Example

julia> model = Model();
 
 julia> @variable(model, x == 1);
 
 julia> FixRef(x)
-x = 1
source

GenericAffExpr

GenericAffExpr

JuMP.GenericAffExprType
mutable struct GenericAffExpr{CoefType,VarType} <: AbstractJuMPScalar
     constant::CoefType
     terms::OrderedDict{VarType,CoefType}
 end

An expression type representing an affine expression of the form: $\sum a_i x_i + c$.

Fields

  • .constant: the constant c in the expression.
  • .terms: an OrderedDict, with keys of VarType and values of CoefType describing the sparse vector a.

Example

julia> model = Model();
@@ -2734,13 +2734,13 @@
 julia> expr.terms
 OrderedCollections.OrderedDict{VariableRef, Float64} with 2 entries:
   x[2] => 1.0
-  x[1] => 3.0
source

GenericModel

GenericModel

JuMP.GenericModelType
GenericModel{T}(
     [optimizer_factory;]
     add_bridges::Bool = true,
 ) where {T<:Real}

Create a new instance of a JuMP model.

If optimizer_factory is provided, the model is initialized with the optimizer returned by MOI.instantiate(optimizer_factory).

If optimizer_factory is not provided, use set_optimizer to set the optimizer before calling optimize!.

If add_bridges, JuMP adds a MOI.Bridges.LazyBridgeOptimizer to automatically reformulate the problem into a form supported by the optimizer.

Value type T

Passing a type other than Float64 as the value type T is an advanced operation. The value type must match that expected by the chosen optimizer. Consult the optimizers documentation for details.

If not documented, assume that the optimizer supports only Float64.

Choosing an unsupported value type will throw an MOI.UnsupportedConstraint or an MOI.UnsupportedAttribute error, the timing of which (during the model construction or during a call to optimize!) depends on how the solver is interfaced to JuMP.

Example

julia> model = GenericModel{BigFloat}();
 
 julia> typeof(model)
-GenericModel{BigFloat}
source

GenericNonlinearExpr

GenericNonlinearExpr

JuMP.GenericNonlinearExprType
GenericNonlinearExpr{V}(head::Symbol, args::Vector{Any})
 GenericNonlinearExpr{V}(head::Symbol, args::Any...)

The scalar-valued nonlinear function head(args...), represented as a symbolic expression tree, with the call operator head and ordered arguments in args.

V is the type of AbstractVariableRef present in the expression, and is used to help dispatch JuMP extensions.

head

The head::Symbol must be an operator supported by the model.

The default list of supported univariate operators is given by:

and the default list of supported multivariate operators is given by:

Additional operators can be add using @operator.

See the full list of operators supported by a MOI.ModelLike by querying the MOI.ListOfSupportedNonlinearOperators attribute.

args

The vector args contains the arguments to the nonlinear function. If the operator is univariate, it must contain one element. Otherwise, it may contain multiple elements.

Given a subtype of AbstractVariableRef, V, for GenericNonlinearExpr{V}, each element must be one of the following:

where T<:Real and T == value_type(V).

Unsupported operators

If the optimizer does not support head, an MOI.UnsupportedNonlinearOperator error will be thrown.

There is no guarantee about when this error will be thrown; it may be thrown when the function is first added to the model, or it may be thrown when optimize! is called.

Example

To represent the function $f(x) = sin(x)^2$, do:

julia> model = Model();
 
 julia> @variable(model, x)
@@ -2754,7 +2754,7 @@
            GenericNonlinearExpr{VariableRef}(:sin, x),
            2.0,
        )
-sin(x) ^ 2.0
source

GenericQuadExpr

GenericQuadExpr

JuMP.GenericQuadExprType
mutable struct GenericQuadExpr{CoefType,VarType} <: AbstractJuMPScalar
     aff::GenericAffExpr{CoefType,VarType}
     terms::OrderedDict{UnorderedPair{VarType}, CoefType}
 end

An expression type representing an quadratic expression of the form: $\sum q_{i,j} x_i x_j + \sum a_i x_i + c$.

Fields

  • .aff: an GenericAffExpr representing the affine portion of the expression.
  • .terms: an OrderedDict, with keys of UnorderedPair{VarType} and values of CoefType, describing the sparse list of terms q.

Example

julia> model = Model();
@@ -2770,16 +2770,16 @@
 julia> expr.terms
 OrderedCollections.OrderedDict{UnorderedPair{VariableRef}, Float64} with 2 entries:
   UnorderedPair{VariableRef}(x[1], x[1]) => 2.0
-  UnorderedPair{VariableRef}(x[1], x[2]) => 1.0
source

GenericReferenceMap

JuMP.GenericReferenceMapType
GenericReferenceMap{T}

Mapping between variable and constraint reference of a model and its copy. The reference of the copied model can be obtained by indexing the map with the reference of the corresponding reference of the original model.

source

GenericVariableRef

JuMP.GenericVariableRefType
GenericVariableRef{T} <: AbstractVariableRef

Holds a reference to the model and the corresponding MOI.VariableIndex.

source

GreaterThanZero

JuMP.GreaterThanZeroType
GreaterThanZero()

A struct used to intercept when >= or is used in a macro via operator_to_set.

This struct is not the same as Nonnegatives so that we can disambiguate x >= y and x - y in Nonnegatives().

This struct is not intended for general usage, but it may be useful to some JuMP extensions.

Example

julia> operator_to_set(error, Val(:>=))
-GreaterThanZero()
source

HermitianMatrixAdjointShape

HermitianMatrixShape

GenericReferenceMap

JuMP.GenericReferenceMapType
GenericReferenceMap{T}

Mapping between variable and constraint reference of a model and its copy. The reference of the copied model can be obtained by indexing the map with the reference of the corresponding reference of the original model.

source

GenericVariableRef

JuMP.GenericVariableRefType
GenericVariableRef{T} <: AbstractVariableRef

Holds a reference to the model and the corresponding MOI.VariableIndex.

source

GreaterThanZero

JuMP.GreaterThanZeroType
GreaterThanZero()

A struct used to intercept when >= or is used in a macro via operator_to_set.

This struct is not the same as Nonnegatives so that we can disambiguate x >= y and x - y in Nonnegatives().

This struct is not intended for general usage, but it may be useful to some JuMP extensions.

Example

julia> operator_to_set(error, Val(:>=))
+GreaterThanZero()
source

HermitianMatrixAdjointShape

HermitianMatrixShape

JuMP.HermitianMatrixShapeType
HermitianMatrixShape(
     side_dimension::Int;
     needs_adjoint_dual::Bool = false,
-)

The shape object for a Hermitian square matrix of side_dimension rows and columns.

The vectorized form corresponds to MOI.HermitianPositiveSemidefiniteConeTriangle.

needs_adjoint_dual

By default, the dual_shape of HermitianMatrixShape is also HermitianMatrixShape. This is true for cases such as a LinearAlgebra.Hermitian matrix in HermitianPSDCone.

However, JuMP also supports LinearAlgebra.Hermitian matrix in Zeros, which is interpreted as an element-wise equality constraint. By exploiting symmetry, we pass only the upper triangle of the equality constraints. This works for the primal, but it leads to a factor of 2 difference in the off-diagonal dual elements. (The dual value of the (i, j) element in the triangle formulation should be divided by 2 when spread across the (i, j) and (j, i) elements in the square matrix formulation.) If the constraint has this dual inconsistency, set needs_adjoint_dual = true.

source

HermitianMatrixSpace

JuMP.HermitianMatrixSpaceType
HermitianMatrixSpace()

Use in the @variable macro to constrain a matrix of variables to be hermitian.

Example

julia> model = Model();
+)

The shape object for a Hermitian square matrix of side_dimension rows and columns.

The vectorized form corresponds to MOI.HermitianPositiveSemidefiniteConeTriangle.

needs_adjoint_dual

By default, the dual_shape of HermitianMatrixShape is also HermitianMatrixShape. This is true for cases such as a LinearAlgebra.Hermitian matrix in HermitianPSDCone.

However, JuMP also supports LinearAlgebra.Hermitian matrix in Zeros, which is interpreted as an element-wise equality constraint. By exploiting symmetry, we pass only the upper triangle of the equality constraints. This works for the primal, but it leads to a factor of 2 difference in the off-diagonal dual elements. (The dual value of the (i, j) element in the triangle formulation should be divided by 2 when spread across the (i, j) and (j, i) elements in the square matrix formulation.) If the constraint has this dual inconsistency, set needs_adjoint_dual = true.

source

HermitianMatrixSpace

JuMP.HermitianMatrixSpaceType
HermitianMatrixSpace()

Use in the @variable macro to constrain a matrix of variables to be hermitian.

Example

julia> model = Model();
 
 julia> @variable(model, Q[1:2, 1:2] in HermitianMatrixSpace())
 2×2 LinearAlgebra.Hermitian{GenericAffExpr{ComplexF64, VariableRef}, Matrix{GenericAffExpr{ComplexF64, VariableRef}}}:
  real(Q[1,1])                    real(Q[1,2]) + imag(Q[1,2]) im
- real(Q[1,2]) - imag(Q[1,2]) im  real(Q[2,2])
source

HermitianPSDCone

JuMP.HermitianPSDConeType
HermitianPSDCone

Hermitian positive semidefinite cone object that can be used to create a Hermitian positive semidefinite square matrix in the @variable and @constraint macros.

Example

Consider the following example:

julia> model = Model();
+ real(Q[1,2]) - imag(Q[1,2]) im  real(Q[2,2])
source

HermitianPSDCone

JuMP.HermitianPSDConeType
HermitianPSDCone

Hermitian positive semidefinite cone object that can be used to create a Hermitian positive semidefinite square matrix in the @variable and @constraint macros.

Example

Consider the following example:

julia> model = Model();
 
 julia> @variable(model, H[1:3, 1:3] in HermitianPSDCone())
 3×3 LinearAlgebra.Hermitian{GenericAffExpr{ComplexF64, VariableRef}, Matrix{GenericAffExpr{ComplexF64, VariableRef}}}:
@@ -2801,18 +2801,18 @@
 
 julia> all_constraints(model, Vector{VariableRef}, MOI.HermitianPositiveSemidefiniteConeTriangle)
 1-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.HermitianPositiveSemidefiniteConeTriangle}}}:
- [real(H[1,1]), real(H[1,2]), real(H[2,2]), real(H[1,3]), real(H[2,3]), real(H[3,3]), imag(H[1,2]), imag(H[1,3]), imag(H[2,3])] ∈ MathOptInterface.HermitianPositiveSemidefiniteConeTriangle(3)

We see in the output of the last commands that 9 real variables were created. The matrix H constrains affine expressions in terms of these 9 variables that parametrize a Hermitian matrix.

source

IntegerRef

JuMP.IntegerRefFunction
IntegerRef(v::GenericVariableRef)

Return a constraint reference to the constraint constraining v to be integer.

Errors if one does not exist.

See also is_integer, set_integer, unset_integer.

Example

julia> model = Model();
+ [real(H[1,1]), real(H[1,2]), real(H[2,2]), real(H[1,3]), real(H[2,3]), real(H[3,3]), imag(H[1,2]), imag(H[1,3]), imag(H[2,3])] ∈ MathOptInterface.HermitianPositiveSemidefiniteConeTriangle(3)

We see in the output of the last commands that 9 real variables were created. The matrix H constrains affine expressions in terms of these 9 variables that parametrize a Hermitian matrix.

source

IntegerRef

JuMP.IntegerRefFunction
IntegerRef(v::GenericVariableRef)

Return a constraint reference to the constraint constraining v to be integer.

Errors if one does not exist.

See also is_integer, set_integer, unset_integer.

Example

julia> model = Model();
 
 julia> @variable(model, x, Int);
 
 julia> IntegerRef(x)
-x integer
source

LPMatrixData

LessThanZero

JuMP.LessThanZeroType
GreaterThanZero()

A struct used to intercept when <= or is used in a macro via operator_to_set.

This struct is not the same as Nonpositives so that we can disambiguate x <= y and x - y in Nonpositives().

This struct is not intended for general usage, but it may be useful to some JuMP extensions.

Example

julia> operator_to_set(error, Val(:<=))
-LessThanZero()
source

LinearTermIterator

JuMP.LinearTermIteratorType
LinearTermIterator{GAE<:GenericAffExpr}

A struct that implements the iterate protocol in order to iterate over tuples of (coefficient, variable) in the GenericAffExpr.

source

LowerBoundRef

LPMatrixData

LessThanZero

JuMP.LessThanZeroType
GreaterThanZero()

A struct used to intercept when <= or is used in a macro via operator_to_set.

This struct is not the same as Nonpositives so that we can disambiguate x <= y and x - y in Nonpositives().

This struct is not intended for general usage, but it may be useful to some JuMP extensions.

Example

julia> operator_to_set(error, Val(:<=))
+LessThanZero()
source

LinearTermIterator

JuMP.LinearTermIteratorType
LinearTermIterator{GAE<:GenericAffExpr}

A struct that implements the iterate protocol in order to iterate over tuples of (coefficient, variable) in the GenericAffExpr.

source

LowerBoundRef

Model

JuMP.ModelType
Model([optimizer_factory;] add_bridges::Bool = true)

Create a new instance of a JuMP model.

If optimizer_factory is provided, the model is initialized with thhe optimizer returned by MOI.instantiate(optimizer_factory).

If optimizer_factory is not provided, use set_optimizer to set the optimizer before calling optimize!.

If add_bridges, JuMP adds a MOI.Bridges.LazyBridgeOptimizer to automatically reformulate the problem into a form supported by the optimizer.

Example

julia> import Ipopt
+x ≥ 1
source

Model

JuMP.ModelType
Model([optimizer_factory;] add_bridges::Bool = true)

Create a new instance of a JuMP model.

If optimizer_factory is provided, the model is initialized with thhe optimizer returned by MOI.instantiate(optimizer_factory).

If optimizer_factory is not provided, use set_optimizer to set the optimizer before calling optimize!.

If add_bridges, JuMP adds a MOI.Bridges.LazyBridgeOptimizer to automatically reformulate the problem into a form supported by the optimizer.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
@@ -2823,16 +2823,16 @@
 
 julia> import MultiObjectiveAlgorithms as MOA
 
-julia> model = Model(() -> MOA.Optimizer(HiGHS.Optimizer); add_bridges = false);
source

ModelMode

JuMP.ModelModeType
ModelMode

An enum to describe the state of the CachingOptimizer inside a JuMP model.

See also: mode.

Values

Possible values are:

  • [AUTOMATIC]: moi_backend field holds a CachingOptimizer in AUTOMATIC mode.
  • [MANUAL]: moi_backend field holds a CachingOptimizer in MANUAL mode.
  • [DIRECT]: moi_backend field holds an AbstractOptimizer. No extra copy of the model is stored. The moi_backend must support add_constraint etc.
source

NLPEvaluator

JuMP.NLPEvaluatorFunction
NLPEvaluator(
+julia> model = Model(() -> MOA.Optimizer(HiGHS.Optimizer); add_bridges = false);
source

ModelMode

JuMP.ModelModeType
ModelMode

An enum to describe the state of the CachingOptimizer inside a JuMP model.

See also: mode.

Values

Possible values are:

  • [AUTOMATIC]: moi_backend field holds a CachingOptimizer in AUTOMATIC mode.
  • [MANUAL]: moi_backend field holds a CachingOptimizer in MANUAL mode.
  • [DIRECT]: moi_backend field holds an AbstractOptimizer. No extra copy of the model is stored. The moi_backend must support add_constraint etc.
source

NLPEvaluator

JuMP.NLPEvaluatorFunction
NLPEvaluator(
     model::Model,
     _differentiation_backend::MOI.Nonlinear.AbstractAutomaticDifferentiation =
         MOI.Nonlinear.SparseReverseMode(),
-)

Return an MOI.AbstractNLPEvaluator constructed from model

Warning

Before using, you must initialize the evaluator using MOI.initialize.

Experimental

These features may change or be removed in any future version of JuMP.

Pass _differentiation_backend to specify the differentiation backend used to compute derivatives.

source

NoOptimizer

JuMP.NoOptimizerType
struct NoOptimizer <: Exception end

An error thrown when no optimizer is set and one is required.

The optimizer can be provided to the Model constructor or by calling set_optimizer.

Example

julia> model = Model();
+)

Return an MOI.AbstractNLPEvaluator constructed from model

Warning

Before using, you must initialize the evaluator using MOI.initialize.

Experimental

These features may change or be removed in any future version of JuMP.

Pass _differentiation_backend to specify the differentiation backend used to compute derivatives.

source

NoOptimizer

JuMP.NoOptimizerType
struct NoOptimizer <: Exception end

An error thrown when no optimizer is set and one is required.

The optimizer can be provided to the Model constructor or by calling set_optimizer.

Example

julia> model = Model();
 
 julia> optimize!(model)
 ERROR: NoOptimizer()
 Stacktrace:
-[...]
source

NonlinearExpr

NonlinearOperator

JuMP.NonlinearOperatorType
NonlinearOperator(func::Function, head::Symbol)

A callable struct (functor) representing a function named head.

When called with AbstractJuMPScalars, the struct returns a GenericNonlinearExpr.

When called with non-JuMP types, the struct returns the evaluation of func(args...).

Unless head is special-cased by the optimizer, the operator must have already been added to the model using add_nonlinear_operator or @operator.

Example

julia> model = Model();
+[...]
source

NonlinearExpr

NonlinearOperator

JuMP.NonlinearOperatorType
NonlinearOperator(func::Function, head::Symbol)

A callable struct (functor) representing a function named head.

When called with AbstractJuMPScalars, the struct returns a GenericNonlinearExpr.

When called with non-JuMP types, the struct returns the evaluation of func(args...).

Unless head is special-cased by the optimizer, the operator must have already been added to the model using add_nonlinear_operator or @operator.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -2856,7 +2856,7 @@
 op_f(x)
 
 julia> bar(2.0)
-4.0
source

Nonnegatives

JuMP.NonnegativesType
Nonnegatives()

The JuMP equivalent of the MOI.Nonnegatives set, in which the dimension is inferred from the corresponding function.

Example

julia> model = Model();
+4.0
source

Nonnegatives

JuMP.NonnegativesType
Nonnegatives()

The JuMP equivalent of the MOI.Nonnegatives set, in which the dimension is inferred from the corresponding function.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2])
 2-element Vector{VariableRef}:
@@ -2871,7 +2871,7 @@
 julia> b = [5, 6];
 
 julia> @constraint(model, A * x >= b)
-[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] ∈ Nonnegatives()
source

Nonpositives

JuMP.NonpositivesType
Nonpositives()

The JuMP equivalent of the MOI.Nonpositives set, in which the dimension is inferred from the corresponding function.

Example

julia> model = Model();
+[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] ∈ Nonnegatives()
source

Nonpositives

JuMP.NonpositivesType
Nonpositives()

The JuMP equivalent of the MOI.Nonpositives set, in which the dimension is inferred from the corresponding function.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2])
 2-element Vector{VariableRef}:
@@ -2886,14 +2886,14 @@
 julia> b = [5, 6];
 
 julia> @constraint(model, A * x <= b)
-[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] ∈ Nonpositives()
source

OptimizationSense

OptimizeNotCalled

JuMP.OptimizeNotCalledType
struct OptimizeNotCalled <: Exception end

An error thrown when a result attribute cannot be queried before optimize! is called.

Example

julia> import Ipopt
+[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] ∈ Nonpositives()
source

OptimizationSense

OptimizeNotCalled

JuMP.OptimizeNotCalledType
struct OptimizeNotCalled <: Exception end

An error thrown when a result attribute cannot be queried before optimize! is called.

Example

julia> import Ipopt
 
 julia> model = Model(Ipopt.Optimizer);
 
 julia> objective_value(model)
 ERROR: OptimizeNotCalled()
 Stacktrace:
-[...]
source

PSDCone

JuMP.PSDConeType
PSDCone

Positive semidefinite cone object that can be used to constrain a square matrix to be positive semidefinite in the @constraint macro.

If the matrix has type Symmetric then the columns vectorization (the vector obtained by concatenating the columns) of its upper triangular part is constrained to belong to the MOI.PositiveSemidefiniteConeTriangle set, otherwise its column vectorization is constrained to belong to the MOI.PositiveSemidefiniteConeSquare set.

Example

Non-symmetric case:

julia> model = Model();
+[...]
source

PSDCone

JuMP.PSDConeType
PSDCone

Positive semidefinite cone object that can be used to constrain a square matrix to be positive semidefinite in the @constraint macro.

If the matrix has type Symmetric then the columns vectorization (the vector obtained by concatenating the columns) of its upper triangular part is constrained to belong to the MOI.PositiveSemidefiniteConeTriangle set, otherwise its column vectorization is constrained to belong to the MOI.PositiveSemidefiniteConeSquare set.

Example

Non-symmetric case:

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -2934,7 +2934,7 @@
  x - 4
 
 julia> moi_set(constraint_object(cref))
-MathOptInterface.PositiveSemidefiniteConeTriangle(2)
source

Parameter

JuMP.ParameterType
Parameter(value)

A short-cut for the MOI.Parameter set.

Example

julia> model = Model();
+MathOptInterface.PositiveSemidefiniteConeTriangle(2)
source

Parameter

JuMP.ParameterType
Parameter(value)

A short-cut for the MOI.Parameter set.

Example

julia> model = Model();
 
 julia> @variable(model, x in Parameter(2))
 x
@@ -2942,7 +2942,7 @@
 julia> print(model)
 Feasibility
 Subject to
- x ∈ MathOptInterface.Parameter{Float64}(2.0)
source

ParameterRef

ParameterRef

JuMP.ParameterRefFunction
ParameterRef(x::GenericVariableRef)

Return a constraint reference to the constraint constraining x to be a parameter.

Errors if one does not exist.

See also is_parameter, set_parameter_value, parameter_value.

Example

julia> model = Model();
 
 julia> @variable(model, p in Parameter(2))
 p
@@ -2955,7 +2955,7 @@
 julia> ParameterRef(x)
 ERROR: Variable x is not a parameter.
 Stacktrace:
-[...]
source

QuadExpr

QuadTermIterator

JuMP.QuadTermIteratorType
QuadTermIterator{GQE<:GenericQuadExpr}

A struct that implements the iterate protocol in order to iterate over tuples of (coefficient, variable, variable) in the GenericQuadExpr.

source

ReferenceMap

JuMP.ReferenceMapType
GenericReferenceMap{T}

Mapping between variable and constraint reference of a model and its copy. The reference of the copied model can be obtained by indexing the map with the reference of the corresponding reference of the original model.

source

ResultStatusCode

JuMP.ResultStatusCodeType
ResultStatusCode

An Enum of possible values for the PrimalStatus and DualStatus attributes.

The values indicate how to interpret the result vector.

Values

Possible values are:

  • NO_SOLUTION: the result vector is empty.
  • FEASIBLE_POINT: the result vector is a feasible point.
  • NEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.
  • INFEASIBLE_POINT: the result vector is an infeasible point.
  • INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.
  • NEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.
  • REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.
  • NEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.
  • UNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.
  • OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above
source

RotatedSecondOrderCone

JuMP.RotatedSecondOrderConeType
RotatedSecondOrderCone

Rotated second order cone object that can be used to constrain the square of the euclidean norm of a vector x to be less than or equal to $2tu$ where t and u are nonnegative scalars. This is a shortcut for the MOI.RotatedSecondOrderCone.

Example

The following constrains $\|(x-1, x-2)\|^2_2 \le 2tx$ and $t, x \ge 0$:

julia> model = Model();
+[...]
source

QuadExpr

QuadTermIterator

JuMP.QuadTermIteratorType
QuadTermIterator{GQE<:GenericQuadExpr}

A struct that implements the iterate protocol in order to iterate over tuples of (coefficient, variable, variable) in the GenericQuadExpr.

source

ReferenceMap

JuMP.ReferenceMapType
GenericReferenceMap{T}

Mapping between variable and constraint reference of a model and its copy. The reference of the copied model can be obtained by indexing the map with the reference of the corresponding reference of the original model.

source

ResultStatusCode

JuMP.ResultStatusCodeType
ResultStatusCode

An Enum of possible values for the PrimalStatus and DualStatus attributes.

The values indicate how to interpret the result vector.

Values

Possible values are:

  • NO_SOLUTION: the result vector is empty.
  • FEASIBLE_POINT: the result vector is a feasible point.
  • NEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.
  • INFEASIBLE_POINT: the result vector is an infeasible point.
  • INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.
  • NEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.
  • REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.
  • NEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.
  • UNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.
  • OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above
source

RotatedSecondOrderCone

JuMP.RotatedSecondOrderConeType
RotatedSecondOrderCone

Rotated second order cone object that can be used to constrain the square of the euclidean norm of a vector x to be less than or equal to $2tu$ where t and u are nonnegative scalars. This is a shortcut for the MOI.RotatedSecondOrderCone.

Example

The following constrains $\|(x-1, x-2)\|^2_2 \le 2tx$ and $t, x \ge 0$:

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -2964,7 +2964,7 @@
 t
 
 julia> @constraint(model, [t, x, x-1, x-2] in RotatedSecondOrderCone())
-[t, x, x - 1, x - 2] ∈ MathOptInterface.RotatedSecondOrderCone(4)
source

SOS1

JuMP.SOS1Type
SOS1(weights = Real[])

The SOS1 (Special Ordered Set of Type 1) set constrains a vector x to the set where at most one variable can take a non-zero value, and all other elements are zero.

The weights vector, if specified, induces an ordering of the variables; as such, it should contain unique values. The weights vector must have the same number of elements as the vector x, and the element weights[i] corresponds to element x[i]. If not provided, the weights vector defaults to weights[i] = i.

This is a shortcut for the MOI.SOS1 set.

Example

julia> model = Model();
+[t, x, x - 1, x - 2] ∈ MathOptInterface.RotatedSecondOrderCone(4)
source

SOS1

JuMP.SOS1Type
SOS1(weights = Real[])

The SOS1 (Special Ordered Set of Type 1) set constrains a vector x to the set where at most one variable can take a non-zero value, and all other elements are zero.

The weights vector, if specified, induces an ordering of the variables; as such, it should contain unique values. The weights vector must have the same number of elements as the vector x, and the element weights[i] corresponds to element x[i]. If not provided, the weights vector defaults to weights[i] = i.

This is a shortcut for the MOI.SOS1 set.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:3] in SOS1([4.1, 3.2, 5.0]))
 3-element Vector{VariableRef}:
@@ -2975,7 +2975,7 @@
 julia> print(model)
 Feasibility
 Subject to
- [x[1], x[2], x[3]] ∈ MathOptInterface.SOS1{Float64}([4.1, 3.2, 5.0])
source

SOS2

JuMP.SOS2Type
SOS2(weights = Real[])

The SOS2 (Special Ordered Set of Type 2) set constrains a vector x to the set where at most two variables can take a non-zero value, and all other elements are zero. In addition, the two non-zero values must be consecutive given the ordering of the x vector induced by weights.

The weights vector, if specified, induces an ordering of the variables; as such, it must contain unique values. The weights vector must have the same number of elements as the vector x, and the element weights[i] corresponds to element x[i]. If not provided, the weights vector defaults to weights[i] = i.

This is a shortcut for the MOI.SOS2 set.

Example

julia> model = Model();
+ [x[1], x[2], x[3]] ∈ MathOptInterface.SOS1{Float64}([4.1, 3.2, 5.0])
source

SOS2

JuMP.SOS2Type
SOS2(weights = Real[])

The SOS2 (Special Ordered Set of Type 2) set constrains a vector x to the set where at most two variables can take a non-zero value, and all other elements are zero. In addition, the two non-zero values must be consecutive given the ordering of the x vector induced by weights.

The weights vector, if specified, induces an ordering of the variables; as such, it must contain unique values. The weights vector must have the same number of elements as the vector x, and the element weights[i] corresponds to element x[i]. If not provided, the weights vector defaults to weights[i] = i.

This is a shortcut for the MOI.SOS2 set.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:3] in SOS2([4.1, 3.2, 5.0]))
 3-element Vector{VariableRef}:
@@ -2986,7 +2986,7 @@
 julia> print(model)
 Feasibility
 Subject to
- [x[1], x[2], x[3]] ∈ MathOptInterface.SOS2{Float64}([4.1, 3.2, 5.0])
source

ScalarConstraint

JuMP.ScalarConstraintType
struct ScalarConstraint

The data for a scalar constraint.

See also the documentation on JuMP's representation of constraints for more background.

Fields

  • .func: field contains a JuMP object representing the function
  • .set: field contains the MOI set

Example

A scalar constraint:

julia> model = Model();
+ [x[1], x[2], x[3]] ∈ MathOptInterface.SOS2{Float64}([4.1, 3.2, 5.0])
source

ScalarConstraint

JuMP.ScalarConstraintType
struct ScalarConstraint

The data for a scalar constraint.

See also the documentation on JuMP's representation of constraints for more background.

Fields

  • .func: field contains a JuMP object representing the function
  • .set: field contains the MOI set

Example

A scalar constraint:

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3003,14 +3003,14 @@
 2 x
 
 julia> object.set
-MathOptInterface.LessThan{Float64}(1.0)
source

ScalarShape

ScalarShape

JuMP.ScalarShapeType
ScalarShape()

An AbstractShape that represents scalar constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
 julia> c = @constraint(model, x[2] <= 1);
 
 julia> shape(constraint_object(c))
-ScalarShape()
source

ScalarVariable

SecondOrderCone

JuMP.SecondOrderConeType
SecondOrderCone

Second order cone object that can be used to constrain the euclidean norm of a vector x to be less than or equal to a nonnegative scalar t. This is a shortcut for the MOI.SecondOrderCone.

Example

The following constrains $\|(x-1, x-2)\|_2 \le t$ and $t \ge 0$:

julia> model = Model();
+ScalarShape()
source

ScalarVariable

SecondOrderCone

JuMP.SecondOrderConeType
SecondOrderCone

Second order cone object that can be used to constrain the euclidean norm of a vector x to be less than or equal to a nonnegative scalar t. This is a shortcut for the MOI.SecondOrderCone.

Example

The following constrains $\|(x-1, x-2)\|_2 \le t$ and $t \ge 0$:

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -3019,7 +3019,7 @@
 t
 
 julia> @constraint(model, [t, x-1, x-2] in SecondOrderCone())
-[t, x - 1, x - 2] ∈ MathOptInterface.SecondOrderCone(3)
source

Semicontinuous

JuMP.SemicontinuousType
Semicontinuous(lower, upper)

A short-cut for the MOI.Semicontinuous set.

This short-cut is useful because it automatically promotes lower and upper to the same type, and converts them into the element type supported by the JuMP model.

Example

julia> model = Model();
+[t, x - 1, x - 2] ∈ MathOptInterface.SecondOrderCone(3)
source

Semicontinuous

JuMP.SemicontinuousType
Semicontinuous(lower, upper)

A short-cut for the MOI.Semicontinuous set.

This short-cut is useful because it automatically promotes lower and upper to the same type, and converts them into the element type supported by the JuMP model.

Example

julia> model = Model();
 
 julia> @variable(model, x in Semicontinuous(1, 2))
 x
@@ -3027,7 +3027,7 @@
 julia> print(model)
 Feasibility
 Subject to
- x ∈ MathOptInterface.Semicontinuous{Int64}(1, 2)
source

Semiinteger

JuMP.SemiintegerType
Semiinteger(lower, upper)

A short-cut for the MOI.Semiinteger set.

This short-cut is useful because it automatically promotes lower and upper to the same type, and converts them into the element type supported by the JuMP model.

Example

julia> model = Model();
+ x ∈ MathOptInterface.Semicontinuous{Int64}(1, 2)
source

Semiinteger

JuMP.SemiintegerType
Semiinteger(lower, upper)

A short-cut for the MOI.Semiinteger set.

This short-cut is useful because it automatically promotes lower and upper to the same type, and converts them into the element type supported by the JuMP model.

Example

julia> model = Model();
 
 julia> @variable(model, x in Semiinteger(3, 5))
 x
@@ -3035,12 +3035,12 @@
 julia> print(model)
 Feasibility
 Subject to
- x ∈ MathOptInterface.Semiinteger{Int64}(3, 5)
source

SensitivityReport

SkewSymmetricMatrixShape

JuMP.SkewSymmetricMatrixShapeType
SkewSymmetricMatrixShape

Shape object for a skew symmetric square matrix of side_dimension rows and columns. The vectorized form contains the entries of the upper-right triangular part of the matrix (without the diagonal) given column by column (or equivalently, the entries of the lower-left triangular part given row by row). The diagonal is zero.

source

SkewSymmetricMatrixSpace

JuMP.SkewSymmetricMatrixSpaceType
SkewSymmetricMatrixSpace()

Use in the @variable macro to constrain a matrix of variables to be skew-symmetric.

Example

julia> model = Model();
+ x ∈ MathOptInterface.Semiinteger{Int64}(3, 5)
source

SensitivityReport

SkewSymmetricMatrixShape

JuMP.SkewSymmetricMatrixShapeType
SkewSymmetricMatrixShape

Shape object for a skew symmetric square matrix of side_dimension rows and columns. The vectorized form contains the entries of the upper-right triangular part of the matrix (without the diagonal) given column by column (or equivalently, the entries of the lower-left triangular part given row by row). The diagonal is zero.

source

SkewSymmetricMatrixSpace

JuMP.SkewSymmetricMatrixSpaceType
SkewSymmetricMatrixSpace()

Use in the @variable macro to constrain a matrix of variables to be skew-symmetric.

Example

julia> model = Model();
 
 julia> @variable(model, Q[1:2, 1:2] in SkewSymmetricMatrixSpace())
 2×2 Matrix{AffExpr}:
  0        Q[1,2]
- -Q[1,2]  0
source

SkipModelConvertScalarSetWrapper

JuMP.SkipModelConvertScalarSetWrapperType
SkipModelConvertScalarSetWrapper(set::MOI.AbstractScalarSet)

JuMP uses model_convert to automatically promote MOI.AbstractScalarSet sets to the same value_type as the model.

In cases there this is undesirable, wrap the set in SkipModelConvertScalarSetWrapper to pass the set un-changed to the solver.

Warning

This struct is intended for use internally by JuMP extensions. You should not need to use it in regular JuMP code.

Example

julia> model = Model();
+ -Q[1,2]  0
source

SkipModelConvertScalarSetWrapper

JuMP.SkipModelConvertScalarSetWrapperType
SkipModelConvertScalarSetWrapper(set::MOI.AbstractScalarSet)

JuMP uses model_convert to automatically promote MOI.AbstractScalarSet sets to the same value_type as the model.

In cases there this is undesirable, wrap the set in SkipModelConvertScalarSetWrapper to pass the set un-changed to the solver.

Warning

This struct is intended for use internally by JuMP extensions. You should not need to use it in regular JuMP code.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3048,15 +3048,15 @@
 x = 0.5
 
 julia> @constraint(model, x in SkipModelConvertScalarSetWrapper(MOI.EqualTo(1 // 2)))
-x = 1//2
source

SquareMatrixShape

JuMP.SquareMatrixShapeType
SquareMatrixShape

Shape object for a square matrix of side_dimension rows and columns. The vectorized form contains the entries of the matrix given column by column (or equivalently, the entries of the lower-left triangular part given row by row).

source

SymmetricMatrixAdjointShape

SymmetricMatrixShape

SquareMatrixShape

JuMP.SquareMatrixShapeType
SquareMatrixShape

Shape object for a square matrix of side_dimension rows and columns. The vectorized form contains the entries of the matrix given column by column (or equivalently, the entries of the lower-left triangular part given row by row).

source

SymmetricMatrixAdjointShape

SymmetricMatrixShape

JuMP.SymmetricMatrixShapeType
SymmetricMatrixShape(
     side_dimension::Int;
     needs_adjoint_dual::Bool = false,
-)

The shape object for a symmetric square matrix of side_dimension rows and columns.

The vectorized form contains the entries of the upper-right triangular part of the matrix given column by column (or equivalently, the entries of the lower-left triangular part given row by row).

needs_adjoint_dual

By default, the dual_shape of SymmetricMatrixShape is also SymmetricMatrixShape. This is true for cases such as a LinearAlgebra.Symmetric matrix in PSDCone.

However, JuMP also supports LinearAlgebra.Symmetric matrix in Zeros, which is interpreted as an element-wise equality constraint. By exploiting symmetry, we pass only the upper triangle of the equality constraints. This works for the primal, but it leads to a factor of 2 difference in the off-diagonal dual elements. (The dual value of the (i, j) element in the triangle formulation should be divided by 2 when spread across the (i, j) and (j, i) elements in the square matrix formulation.) If the constraint has this dual inconsistency, set needs_adjoint_dual = true.

source

SymmetricMatrixSpace

JuMP.SymmetricMatrixSpaceType
SymmetricMatrixSpace()

Use in the @variable macro to constrain a matrix of variables to be symmetric.

Example

julia> model = Model();
+)

The shape object for a symmetric square matrix of side_dimension rows and columns.

The vectorized form contains the entries of the upper-right triangular part of the matrix given column by column (or equivalently, the entries of the lower-left triangular part given row by row).

needs_adjoint_dual

By default, the dual_shape of SymmetricMatrixShape is also SymmetricMatrixShape. This is true for cases such as a LinearAlgebra.Symmetric matrix in PSDCone.

However, JuMP also supports LinearAlgebra.Symmetric matrix in Zeros, which is interpreted as an element-wise equality constraint. By exploiting symmetry, we pass only the upper triangle of the equality constraints. This works for the primal, but it leads to a factor of 2 difference in the off-diagonal dual elements. (The dual value of the (i, j) element in the triangle formulation should be divided by 2 when spread across the (i, j) and (j, i) elements in the square matrix formulation.) If the constraint has this dual inconsistency, set needs_adjoint_dual = true.

source

SymmetricMatrixSpace

JuMP.SymmetricMatrixSpaceType
SymmetricMatrixSpace()

Use in the @variable macro to constrain a matrix of variables to be symmetric.

Example

julia> model = Model();
 
 julia> @variable(model, Q[1:2, 1:2] in SymmetricMatrixSpace())
 2×2 LinearAlgebra.Symmetric{VariableRef, Matrix{VariableRef}}:
  Q[1,1]  Q[1,2]
- Q[1,2]  Q[2,2]
source

TerminationStatusCode

JuMP.TerminationStatusCodeType
TerminationStatusCode

An Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.

Values

Possible values are:

  • OPTIMIZE_NOT_CALLED: The algorithm has not started.
  • OPTIMAL: The algorithm found a globally optimal solution.
  • INFEASIBLE: The algorithm concluded that no feasible solution exists.
  • DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.
  • LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.
  • LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.
  • INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.
  • ALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.
  • ALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.
  • ALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.
  • ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.
  • ITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.
  • TIME_LIMIT: The algorithm stopped after a user-specified computation time.
  • NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.
  • SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.
  • MEMORY_LIMIT: The algorithm stopped because it ran out of memory.
  • OBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.
  • NORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.
  • OTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.
  • SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.
  • NUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.
  • INVALID_MODEL: The algorithm stopped because the model is invalid.
  • INVALID_OPTION: The algorithm stopped because it was provided an invalid option.
  • INTERRUPTED: The algorithm stopped because of an interrupt signal.
  • OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.
source

UnorderedPair

TerminationStatusCode

JuMP.TerminationStatusCodeType
TerminationStatusCode

An Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.

Values

Possible values are:

  • OPTIMIZE_NOT_CALLED: The algorithm has not started.
  • OPTIMAL: The algorithm found a globally optimal solution.
  • INFEASIBLE: The algorithm concluded that no feasible solution exists.
  • DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.
  • LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.
  • LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.
  • INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.
  • ALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.
  • ALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.
  • ALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.
  • ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.
  • ITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.
  • TIME_LIMIT: The algorithm stopped after a user-specified computation time.
  • NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.
  • SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.
  • MEMORY_LIMIT: The algorithm stopped because it ran out of memory.
  • OBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.
  • NORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.
  • OTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.
  • SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.
  • NUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.
  • INVALID_MODEL: The algorithm stopped because the model is invalid.
  • INVALID_OPTION: The algorithm stopped because it was provided an invalid option.
  • INTERRUPTED: The algorithm stopped because of an interrupt signal.
  • OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.
source

UnorderedPair

JuMP.UnorderedPairType
UnorderedPair(a::T, b::T)

A wrapper type used by GenericQuadExpr with fields .a and .b.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -3065,12 +3065,12 @@
 
 julia> expr.terms
 OrderedCollections.OrderedDict{UnorderedPair{VariableRef}, Float64} with 1 entry:
-  UnorderedPair{VariableRef}(x[1], x[2]) => 2.0
source

UpperBoundRef

UpperBoundRef

VariableConstrainedOnCreation

JuMP.VariableConstrainedOnCreationType
VariableConstrainedOnCreation <: AbstractVariable

Variable scalar_variables constrained to belong to set.

Adding this variable can be understood as doing:

function JuMP.add_variable(
+x ≤ 1
source

VariableConstrainedOnCreation

JuMP.VariableConstrainedOnCreationType
VariableConstrainedOnCreation <: AbstractVariable

Variable scalar_variables constrained to belong to set.

Adding this variable can be understood as doing:

function JuMP.add_variable(
     model::GenericModel,
     variable::VariableConstrainedOnCreation,
     names,
@@ -3078,9 +3078,9 @@
     var_ref = add_variable(model, variable.scalar_variable, name)
     add_constraint(model, VectorConstraint(var_ref, variable.set))
     return var_ref
-end

but adds the variables with MOI.add_constrained_variable(model, variable.set) instead.

source

VariableInfo

JuMP.VariableInfoType
VariableInfo{S,T,U,V}

A struct by JuMP internally when creating variables. This may also be used by JuMP extensions to create new types of variables.

See also: ScalarVariable.

source

VariableNotOwned

JuMP.VariableNotOwnedType
struct VariableNotOwned{V<:AbstractVariableRef} <: Exception
+end

but adds the variables with MOI.add_constrained_variable(model, variable.set) instead.

source

VariableInfo

JuMP.VariableInfoType
VariableInfo{S,T,U,V}

A struct by JuMP internally when creating variables. This may also be used by JuMP extensions to create new types of variables.

See also: ScalarVariable.

source

VariableNotOwned

JuMP.VariableNotOwnedType
struct VariableNotOwned{V<:AbstractVariableRef} <: Exception
     variable::V
-end

The variable variable was used in a model different to owner_model(variable).

source

VariableRef

JuMP.VariableRefType
GenericVariableRef{T} <: AbstractVariableRef

Holds a reference to the model and the corresponding MOI.VariableIndex.

source

VariablesConstrainedOnCreation

JuMP.VariablesConstrainedOnCreationType
VariablesConstrainedOnCreation <: AbstractVariable

Vector of variables scalar_variables constrained to belong to set. Adding this variable can be thought as doing:

function JuMP.add_variable(
+end

The variable variable was used in a model different to owner_model(variable).

source

VariableRef

JuMP.VariableRefType
GenericVariableRef{T} <: AbstractVariableRef

Holds a reference to the model and the corresponding MOI.VariableIndex.

source

VariablesConstrainedOnCreation

JuMP.VariablesConstrainedOnCreationType
VariablesConstrainedOnCreation <: AbstractVariable

Vector of variables scalar_variables constrained to belong to set. Adding this variable can be thought as doing:

function JuMP.add_variable(
     model::GenericModel,
     variable::VariablesConstrainedOnCreation,
     names,
@@ -3089,7 +3089,7 @@
     var_refs = add_variable.(model, variable.scalar_variables, v_names)
     add_constraint(model, VectorConstraint(var_refs, variable.set))
     return reshape_vector(var_refs, variable.shape)
-end

but adds the variables with MOI.add_constrained_variables(model, variable.set) instead. See the MOI documentation for the difference between adding the variables with MOI.add_constrained_variables and adding them with MOI.add_variables and adding the constraint separately.

source

VectorConstraint

JuMP.VectorConstraintType
struct VectorConstraint

The data for a vector constraint.

See also the documentation on JuMP's representation of constraints.

Fields

  • func: field contains a JuMP object representing the function
  • set: field contains the MOI set.
  • shape: field contains an AbstractShape matching the form in which the constraint was constructed (for example, by using matrices or flat vectors).

Example

julia> model = Model();
+end

but adds the variables with MOI.add_constrained_variables(model, variable.set) instead. See the MOI documentation for the difference between adding the variables with MOI.add_constrained_variables and adding them with MOI.add_variables and adding the constraint separately.

source

VectorConstraint

JuMP.VectorConstraintType
struct VectorConstraint

The data for a vector constraint.

See also the documentation on JuMP's representation of constraints.

Fields

  • func: field contains a JuMP object representing the function
  • set: field contains the MOI set.
  • shape: field contains an AbstractShape matching the form in which the constraint was constructed (for example, by using matrices or flat vectors).

Example

julia> model = Model();
 
 julia> @variable(model, x[1:3]);
 
@@ -3112,14 +3112,14 @@
 MathOptInterface.SecondOrderCone(3)
 
 julia> object.shape
-VectorShape()
source

VectorShape

VectorShape

JuMP.VectorShapeType
VectorShape()

An AbstractShape that represents vector-valued constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
 julia> c = @constraint(model, x in SOS1());
 
 julia> shape(constraint_object(c))
-VectorShape()
source

Zeros

JuMP.ZerosType
Zeros()

The JuMP equivalent of the MOI.Zeros set, in which the dimension is inferred from the corresponding function.

Example

julia> model = Model();
+VectorShape()
source

Zeros

JuMP.ZerosType
Zeros()

The JuMP equivalent of the MOI.Zeros set, in which the dimension is inferred from the corresponding function.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2])
 2-element Vector{VariableRef}:
@@ -3134,7 +3134,7 @@
 julia> b = [5, 6];
 
 julia> @constraint(model, A * x == b)
-[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] ∈ Zeros()
source

ALMOST_DUAL_INFEASIBLE

ALMOST_INFEASIBLE

ALMOST_LOCALLY_SOLVED

JuMP.ALMOST_LOCALLY_SOLVEDConstant
ALMOST_LOCALLY_SOLVED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.

source

ALMOST_OPTIMAL

AUTOMATIC

DIRECT

JuMP.DIRECTConstant

moi_backend field holds an AbstractOptimizer. No extra copy of the model is stored. The moi_backend must support add_constraint etc.

source

DUAL_INFEASIBLE

JuMP.DUAL_INFEASIBLEConstant
DUAL_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.

source

FEASIBILITY_SENSE

FEASIBLE_POINT

INFEASIBILITY_CERTIFICATE

JuMP.INFEASIBILITY_CERTIFICATEConstant
INFEASIBILITY_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.

source

INFEASIBLE

INFEASIBLE_OR_UNBOUNDED

JuMP.INFEASIBLE_OR_UNBOUNDEDConstant
INFEASIBLE_OR_UNBOUNDED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.

source

INFEASIBLE_POINT

INTERRUPTED

INVALID_MODEL

INVALID_OPTION

ITERATION_LIMIT

LOCALLY_INFEASIBLE

JuMP.LOCALLY_INFEASIBLEConstant
LOCALLY_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.

source

LOCALLY_SOLVED

JuMP.LOCALLY_SOLVEDConstant
LOCALLY_SOLVED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.

source

MANUAL

JuMP.MANUALConstant

moi_backend field holds a CachingOptimizer in MANUAL mode.

source

MAX_SENSE

MEMORY_LIMIT

MIN_SENSE

NEARLY_FEASIBLE_POINT

NEARLY_INFEASIBILITY_CERTIFICATE

NEARLY_REDUCTION_CERTIFICATE

NODE_LIMIT

JuMP.NODE_LIMITConstant
NODE_LIMIT::TerminationStatusCode

An instance of the TerminationStatusCode enum.

NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.

source

NORM_LIMIT

NO_SOLUTION

NUMERICAL_ERROR

OBJECTIVE_LIMIT

OPTIMAL

OPTIMIZE_NOT_CALLED

OTHER_ERROR

JuMP.OTHER_ERRORConstant
OTHER_ERROR::TerminationStatusCode

An instance of the TerminationStatusCode enum.

OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.

source

OTHER_LIMIT

OTHER_RESULT_STATUS

JuMP.OTHER_RESULT_STATUSConstant
OTHER_RESULT_STATUS::ResultStatusCode

An instance of the ResultStatusCode enum.

OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above

source

REDUCTION_CERTIFICATE

JuMP.REDUCTION_CERTIFICATEConstant
REDUCTION_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.

source

SLOW_PROGRESS

JuMP.SLOW_PROGRESSConstant
SLOW_PROGRESS::TerminationStatusCode

An instance of the TerminationStatusCode enum.

SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.

source

SOLUTION_LIMIT

JuMP.SOLUTION_LIMITConstant
SOLUTION_LIMIT::TerminationStatusCode

An instance of the TerminationStatusCode enum.

SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.

source

TIME_LIMIT

UNKNOWN_RESULT_STATUS

op_and

JuMP.op_andConstant
op_and(x, y)

A function that falls back to x & y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
+[x[1] + 2 x[2] - 5, 3 x[1] + 4 x[2] - 6] ∈ Zeros()
source

ALMOST_DUAL_INFEASIBLE

ALMOST_INFEASIBLE

ALMOST_LOCALLY_SOLVED

JuMP.ALMOST_LOCALLY_SOLVEDConstant
ALMOST_LOCALLY_SOLVED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.

source

ALMOST_OPTIMAL

AUTOMATIC

DIRECT

JuMP.DIRECTConstant

moi_backend field holds an AbstractOptimizer. No extra copy of the model is stored. The moi_backend must support add_constraint etc.

source

DUAL_INFEASIBLE

JuMP.DUAL_INFEASIBLEConstant
DUAL_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.

source

FEASIBILITY_SENSE

FEASIBLE_POINT

INFEASIBILITY_CERTIFICATE

JuMP.INFEASIBILITY_CERTIFICATEConstant
INFEASIBILITY_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.

source

INFEASIBLE

INFEASIBLE_OR_UNBOUNDED

JuMP.INFEASIBLE_OR_UNBOUNDEDConstant
INFEASIBLE_OR_UNBOUNDED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.

source

INFEASIBLE_POINT

INTERRUPTED

INVALID_MODEL

INVALID_OPTION

ITERATION_LIMIT

LOCALLY_INFEASIBLE

JuMP.LOCALLY_INFEASIBLEConstant
LOCALLY_INFEASIBLE::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.

source

LOCALLY_SOLVED

JuMP.LOCALLY_SOLVEDConstant
LOCALLY_SOLVED::TerminationStatusCode

An instance of the TerminationStatusCode enum.

LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.

source

MANUAL

JuMP.MANUALConstant

moi_backend field holds a CachingOptimizer in MANUAL mode.

source

MAX_SENSE

MEMORY_LIMIT

MIN_SENSE

NEARLY_FEASIBLE_POINT

NEARLY_INFEASIBILITY_CERTIFICATE

NEARLY_REDUCTION_CERTIFICATE

NODE_LIMIT

JuMP.NODE_LIMITConstant
NODE_LIMIT::TerminationStatusCode

An instance of the TerminationStatusCode enum.

NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.

source

NORM_LIMIT

NO_SOLUTION

NUMERICAL_ERROR

OBJECTIVE_LIMIT

OPTIMAL

OPTIMIZE_NOT_CALLED

OTHER_ERROR

JuMP.OTHER_ERRORConstant
OTHER_ERROR::TerminationStatusCode

An instance of the TerminationStatusCode enum.

OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.

source

OTHER_LIMIT

OTHER_RESULT_STATUS

JuMP.OTHER_RESULT_STATUSConstant
OTHER_RESULT_STATUS::ResultStatusCode

An instance of the ResultStatusCode enum.

OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above

source

REDUCTION_CERTIFICATE

JuMP.REDUCTION_CERTIFICATEConstant
REDUCTION_CERTIFICATE::ResultStatusCode

An instance of the ResultStatusCode enum.

REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.

source

SLOW_PROGRESS

JuMP.SLOW_PROGRESSConstant
SLOW_PROGRESS::TerminationStatusCode

An instance of the TerminationStatusCode enum.

SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.

source

SOLUTION_LIMIT

JuMP.SOLUTION_LIMITConstant
SOLUTION_LIMIT::TerminationStatusCode

An instance of the TerminationStatusCode enum.

SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.

source

TIME_LIMIT

UNKNOWN_RESULT_STATUS

op_and

JuMP.op_andConstant
op_and(x, y)

A function that falls back to x & y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3142,7 +3142,7 @@
 false
 
 julia> op_and(true, x)
-true && x
source

op_equal_to

JuMP.op_equal_toConstant
op_equal_to(x, y)

A function that falls back to x == y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
+true && x
source

op_equal_to

JuMP.op_equal_toConstant
op_equal_to(x, y)

A function that falls back to x == y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3150,7 +3150,7 @@
 true
 
 julia> op_equal_to(x, 2)
-x == 2
source

op_greater_than_or_equal_to

op_greater_than_or_equal_to

JuMP.op_greater_than_or_equal_toConstant
op_greater_than_or_equal_to(x, y)

A function that falls back to x >= y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3158,7 +3158,7 @@
 true
 
 julia> op_greater_than_or_equal_to(x, 2)
-x >= 2
source

op_less_than_or_equal_to

op_less_than_or_equal_to

JuMP.op_less_than_or_equal_toConstant
op_less_than_or_equal_to(x, y)

A function that falls back to x <= y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3166,7 +3166,7 @@
 true
 
 julia> op_less_than_or_equal_to(x, 2)
-x <= 2
source

op_or

JuMP.op_orConstant
op_or(x, y)

A function that falls back to x | y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
+x <= 2
source

op_or

JuMP.op_orConstant
op_or(x, y)

A function that falls back to x | y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3174,7 +3174,7 @@
 true
 
 julia> op_or(true, x)
-true || x
source

op_strictly_greater_than

op_strictly_greater_than

JuMP.op_strictly_greater_thanConstant
op_strictly_greater_than(x, y)

A function that falls back to x > y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3182,7 +3182,7 @@
 false
 
 julia> op_strictly_greater_than(x, 2)
-x > 2
source

op_strictly_less_than

op_strictly_less_than

JuMP.op_strictly_less_thanConstant
op_strictly_less_than(x, y)

A function that falls back to x < y, but when called with JuMP variables or expressions, returns a GenericNonlinearExpr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3190,7 +3190,7 @@
 true
 
 julia> op_strictly_less_than(x, 2)
-x < 2
source

Base.empty!(::GenericModel)

Base.empty!Method
empty!(model::GenericModel)::GenericModel

Empty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes. Always return the argument.

Note: removes extensions data.

Example

julia> model = Model();
+x < 2
source

Base.empty!(::GenericModel)

Base.empty!Method
empty!(model::GenericModel)::GenericModel

Empty the model, that is, remove all variables, constraints and model attributes but not optimizer attributes. Always return the argument.

Note: removes extensions data.

Example

julia> model = Model();
 
 julia> @variable(model, x[1:2]);
 
@@ -3210,7 +3210,7 @@
 Subject to
 
 julia> isempty(model)
-true
source

Base.isempty(::GenericModel)

Base.isemptyMethod
isempty(model::GenericModel)

Verifies whether the model is empty, that is, whether the MOI backend is empty and whether the model is in the same state as at its creation, apart from optimizer attributes.

Example

julia> model = Model();
+true
source

Base.isempty(::GenericModel)

Base.isemptyMethod
isempty(model::GenericModel)

Verifies whether the model is empty, that is, whether the MOI backend is empty and whether the model is in the same state as at its creation, apart from optimizer attributes.

Example

julia> model = Model();
 
 julia> isempty(model)
 true
@@ -3218,7 +3218,7 @@
 julia> @variable(model, x[1:2]);
 
 julia> isempty(model)
-false
source

Base.copy(::AbstractModel)

Base.copyMethod
copy(model::AbstractModel)

Return a copy of the model model. It is similar to copy_model except that it does not return the mapping between the references of model and its copy.

Note

Model copy is not supported in DIRECT mode, that is, when a model is constructed using the direct_model constructor instead of the Model constructor. Moreover, independently on whether an optimizer was provided at model construction, the new model will have no optimizer, that is, an optimizer will have to be provided to the new model in the optimize! call.

Example

In the following example, a model model is constructed with a variable x and a constraint cref. It is then copied into a model new_model with the new references assigned to x_new and cref_new.

julia> model = Model();
+false
source

Base.copy(::AbstractModel)

Base.copyMethod
copy(model::AbstractModel)

Return a copy of the model model. It is similar to copy_model except that it does not return the mapping between the references of model and its copy.

Note

Model copy is not supported in DIRECT mode, that is, when a model is constructed using the direct_model constructor instead of the Model constructor. Moreover, independently on whether an optimizer was provided at model construction, the new model will have no optimizer, that is, an optimizer will have to be provided to the new model in the optimize! call.

Example

In the following example, a model model is constructed with a variable x and a constraint cref. It is then copied into a model new_model with the new references assigned to x_new and cref_new.

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -3232,12 +3232,12 @@
 x
 
 julia> cref_new = model[:cref]
-cref : x = 2
source

Base.write(::IO, ::GenericModel; ::MOI.FileFormats.FileFormat)

Base.write(::IO, ::GenericModel; ::MOI.FileFormats.FileFormat)

Base.writeMethod
Base.write(
     io::IO,
     model::GenericModel;
     format::MOI.FileFormats.FileFormat = MOI.FileFormats.FORMAT_MOF,
     kwargs...,
-)

Write the JuMP model model to io in the format format.

Other kwargs are passed to the Model constructor of the chosen format.

source

MOI.Utilities.reset_optimizer(::GenericModel)

MOI.Utilities.drop_optimizer(::GenericModel)

MOI.Utilities.attach_optimizer(::GenericModel)

@NLconstraint

JuMP.@NLconstraintMacro
@NLconstraint(model::GenericModel, expr)

Add a constraint described by the nonlinear expression expr. See also @constraint.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLconstraint with @constraint.

Example

julia> model = Model();
+)

Write the JuMP model model to io in the format format.

Other kwargs are passed to the Model constructor of the chosen format.

source

MOI.Utilities.reset_optimizer(::GenericModel)

MOI.Utilities.drop_optimizer(::GenericModel)

MOI.Utilities.attach_optimizer(::GenericModel)

@NLconstraint

JuMP.@NLconstraintMacro
@NLconstraint(model::GenericModel, expr)

Add a constraint described by the nonlinear expression expr. See also @constraint.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLconstraint with @constraint.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -3249,7 +3249,7 @@
 3-element Vector{NonlinearConstraintRef{ScalarShape}}:
  (sin(1.0 * x) - 1.0 / 1.0) - 0.0 ≤ 0
  (sin(2.0 * x) - 1.0 / 2.0) - 0.0 ≤ 0
- (sin(3.0 * x) - 1.0 / 3.0) - 0.0 ≤ 0
source

@NLconstraints

JuMP.@NLconstraintsMacro
@NLconstraints(model, args...)

Adds multiple nonlinear constraints to model at once, in the same fashion as the @NLconstraint macro.

The model must be the first argument, and multiple constraints can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the constraints that were defined.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLconstraints with @constraints.

Example

julia> model = Model();
+ (sin(3.0 * x) - 1.0 / 3.0) - 0.0 ≤ 0
source

@NLconstraints

JuMP.@NLconstraintsMacro
@NLconstraints(model, args...)

Adds multiple nonlinear constraints to model at once, in the same fashion as the @NLconstraint macro.

The model must be the first argument, and multiple constraints can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the constraints that were defined.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLconstraints with @constraints.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3265,7 +3265,7 @@
            t >= sqrt(x^2 + y^2)
            [i = 1:2], z[i] <= log(a[i])
        end)
-((t - sqrt(x ^ 2.0 + y ^ 2.0)) - 0.0 ≥ 0, NonlinearConstraintRef{ScalarShape}[(z[1] - log(4.0)) - 0.0 ≤ 0, (z[2] - log(5.0)) - 0.0 ≤ 0])
source

@NLexpression

JuMP.@NLexpressionMacro
@NLexpression(args...)

Efficiently build a nonlinear expression which can then be inserted in other nonlinear constraints and the objective. See also [@expression].

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLexpression with @expression.

Example

julia> model = Model();
+((t - sqrt(x ^ 2.0 + y ^ 2.0)) - 0.0 ≥ 0, NonlinearConstraintRef{ScalarShape}[(z[1] - log(4.0)) - 0.0 ≤ 0, (z[2] - log(5.0)) - 0.0 ≤ 0])
source

@NLexpression

JuMP.@NLexpressionMacro
@NLexpression(args...)

Efficiently build a nonlinear expression which can then be inserted in other nonlinear constraints and the objective. See also [@expression].

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLexpression with @expression.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -3286,7 +3286,7 @@
  subexpression[4]: sin(3.0 * x)
 
 julia> my_expr_2 = @NLexpression(model, log(1 + sum(exp(my_expr_1[i]) for i in 1:2)))
-subexpression[5]: log(1.0 + (exp(subexpression[2]) + exp(subexpression[3])))
source

@NLexpressions

JuMP.@NLexpressionsMacro
@NLexpressions(model, args...)

Adds multiple nonlinear expressions to model at once, in the same fashion as the @NLexpression macro.

The model must be the first argument, and multiple expressions can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the expressions that were defined.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLexpressions with @expressions.

Example

julia> model = Model();
+subexpression[5]: log(1.0 + (exp(subexpression[2]) + exp(subexpression[3])))
source

@NLexpressions

JuMP.@NLexpressionsMacro
@NLexpressions(model, args...)

Adds multiple nonlinear expressions to model at once, in the same fashion as the @NLexpression macro.

The model must be the first argument, and multiple expressions can be added on multiple lines wrapped in a begin ... end block.

The macro returns a tuple containing the expressions that were defined.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLexpressions with @expressions.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
@@ -3300,7 +3300,7 @@
            my_expr, sqrt(x^2 + y^2)
            my_expr_1[i = 1:2], log(a[i]) - z[i]
        end)
-(subexpression[1]: sqrt(x ^ 2.0 + y ^ 2.0), NonlinearExpression[subexpression[2]: log(4.0) - z[1], subexpression[3]: log(5.0) - z[2]])
source

@NLobjective

JuMP.@NLobjectiveMacro
@NLobjective(model, sense, expression)

Add a nonlinear objective to model with optimization sense sense. sense must be Max or Min.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLobjective with @objective.

Example

julia> model = Model();
+(subexpression[1]: sqrt(x ^ 2.0 + y ^ 2.0), NonlinearExpression[subexpression[2]: log(4.0) - z[1], subexpression[3]: log(5.0) - z[2]])
source

@NLobjective

JuMP.@NLobjectiveMacro
@NLobjective(model, sense, expression)

Add a nonlinear objective to model with optimization sense sense. sense must be Max or Min.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace @NLobjective with @objective.

Example

julia> model = Model();
 
 julia> @variable(model, x)
 x
@@ -3309,7 +3309,7 @@
 
 julia> print(model)
 Max 2.0 * x + 1.0 + sin(x)
-Subject to
source

@NLparameter

JuMP.@NLparameterMacro
@NLparameter(model, param == value)

Create and return a nonlinear parameter param attached to the model model with initial value set to value. Nonlinear parameters may be used only in nonlinear expressions.

Example

julia> model = Model();
+Subject to
source

@NLparameter

JuMP.@NLparameterMacro
@NLparameter(model, param == value)

Create and return a nonlinear parameter param attached to the model model with initial value set to value. Nonlinear parameters may be used only in nonlinear expressions.

Example

julia> model = Model();
 
 julia> @NLparameter(model, x == 10)
 x == 10.0
@@ -3339,7 +3339,7 @@
  parameter[3] == 6.0
 
 julia> value(y[2])
-4.0
source

@NLparameters

JuMP.@NLparametersMacro
 @NLparameters(model, args...)

Create and return multiple nonlinear parameters attached to model model, in the same fashion as @NLparameter macro.

The model must be the first argument, and multiple parameters can be added on multiple lines wrapped in a begin ... end block. Distinct parameters need to be placed on separate lines as in the following example.

The macro returns a tuple containing the parameters that were defined.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace a call like

@NLparameters(model, begin
+4.0
source

@NLparameters

JuMP.@NLparametersMacro
 @NLparameters(model, args...)

Create and return multiple nonlinear parameters attached to model model, in the same fashion as @NLparameter macro.

The model must be the first argument, and multiple parameters can be added on multiple lines wrapped in a begin ... end block. Distinct parameters need to be placed on separate lines as in the following example.

The macro returns a tuple containing the parameters that were defined.

Compat

This macro is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling. In most cases, you can replace a call like

@NLparameters(model, begin
     p == value
 end)

with

@variables(model, begin
     p in Parameter(value)
@@ -3351,17 +3351,17 @@
        end);
 
 julia> value(x)
-10.0
source

add_nonlinear_constraint

JuMP.add_nonlinear_constraintFunction
add_nonlinear_constraint(model::Model, expr::Expr)

Add a nonlinear constraint described by the Julia expression ex to model.

This function is most useful if the expression ex is generated programmatically, and you cannot use @NLconstraint.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

Notes

  • You must interpolate the variables directly into the expression expr.

Example

julia> model = Model();
+10.0
source

add_nonlinear_constraint

JuMP.add_nonlinear_constraintFunction
add_nonlinear_constraint(model::Model, expr::Expr)

Add a nonlinear constraint described by the Julia expression ex to model.

This function is most useful if the expression ex is generated programmatically, and you cannot use @NLconstraint.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

Notes

  • You must interpolate the variables directly into the expression expr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> add_nonlinear_constraint(model, :($(x) + $(x)^2 <= 1))
-(x + x ^ 2.0) - 1.0 ≤ 0
source

add_nonlinear_expression

JuMP.add_nonlinear_expressionFunction
add_nonlinear_expression(model::Model, expr::Expr)

Add a nonlinear expression expr to model.

This function is most useful if the expression expr is generated programmatically, and you cannot use @NLexpression.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

Notes

  • You must interpolate the variables directly into the expression expr.

Example

julia> model = Model();
+(x + x ^ 2.0) - 1.0 ≤ 0
source

add_nonlinear_expression

JuMP.add_nonlinear_expressionFunction
add_nonlinear_expression(model::Model, expr::Expr)

Add a nonlinear expression expr to model.

This function is most useful if the expression expr is generated programmatically, and you cannot use @NLexpression.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

Notes

  • You must interpolate the variables directly into the expression expr.

Example

julia> model = Model();
 
 julia> @variable(model, x);
 
 julia> add_nonlinear_expression(model, :($(x) + $(x)^2))
-subexpression[1]: x + x ^ 2.0
source

add_nonlinear_parameter

JuMP.add_nonlinear_parameterFunction
add_nonlinear_parameter(model::Model, value::Real)

Add an anonymous parameter to the model.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

all_nonlinear_constraints

get_optimizer_attribute

add_nonlinear_parameter

JuMP.add_nonlinear_parameterFunction
add_nonlinear_parameter(model::Model, value::Real)

Add an anonymous parameter to the model.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

all_nonlinear_constraints

get_optimizer_attribute

JuMP.get_optimizer_attributeFunction
get_optimizer_attribute(
     model::Union{GenericModel,MOI.OptimizerWithAttributes},
     attr::Union{AbstractString,MOI.AbstractOptimizerAttribute},
 )

Return the value associated with the solver-specific attribute attr.

If attr is an AbstractString, this is equivalent to get_optimizer_attribute(model, MOI.RawOptimizerAttribute(name)).

Compat

This method will remain in all v1.X releases of JuMP, but it may be removed in a future v2.0 release. We recommend using get_attribute instead.

See also: set_optimizer_attribute, set_optimizer_attributes.

Example

julia> import Ipopt
@@ -3369,18 +3369,18 @@
 julia> model = Model(Ipopt.Optimizer);
 
 julia> get_optimizer_attribute(model, MOI.Silent())
-false
source

nonlinear_constraint_string

nonlinear_constraint_string

JuMP.nonlinear_constraint_stringFunction
nonlinear_constraint_string(
     model::GenericModel,
     mode::MIME,
     c::_NonlinearConstraint,
-)

Return a string representation of the nonlinear constraint c belonging to model, given the mode.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

nonlinear_dual_start_value

nonlinear_expr_string

JuMP.nonlinear_expr_stringFunction
nonlinear_expr_string(
+)

Return a string representation of the nonlinear constraint c belonging to model, given the mode.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

nonlinear_dual_start_value

nonlinear_expr_string

JuMP.nonlinear_expr_stringFunction
nonlinear_expr_string(
     model::GenericModel,
     mode::MIME,
     c::MOI.Nonlinear.Expression,
-)

Return a string representation of the nonlinear expression c belonging to model, given the mode.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

nonlinear_model

JuMP.nonlinear_modelFunction
nonlinear_model(
+)

Return a string representation of the nonlinear expression c belonging to model, given the mode.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

nonlinear_model

JuMP.nonlinear_modelFunction
nonlinear_model(
     model::GenericModel;
     force::Bool = false,
-)::Union{MOI.Nonlinear.Model,Nothing}

If model has nonlinear components, return a MOI.Nonlinear.Model, otherwise return nothing.

If force, always return a MOI.Nonlinear.Model, and if one does not exist for the model, create an empty one.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

num_nonlinear_constraints

register

JuMP.registerFunction
register(
+)::Union{MOI.Nonlinear.Model,Nothing}

If model has nonlinear components, return a MOI.Nonlinear.Model, otherwise return nothing.

If force, always return a MOI.Nonlinear.Model, and if one does not exist for the model, create an empty one.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source

num_nonlinear_constraints

register

JuMP.registerFunction
register(
     model::Model,
     op::Symbol,
     dimension::Integer,
@@ -3408,7 +3408,7 @@
 
 julia> register(model, :g, 2, g; autodiff = true)
 
-julia> @NLobjective(model, Min, g(x[1], x[2]))
source
register(
+julia> @NLobjective(model, Min, g(x[1], x[2]))
source
register(
     model::Model,
     s::Symbol,
     dimension::Integer,
@@ -3447,7 +3447,7 @@
 
 julia> register(model, :g, 2, g, ∇g)
 
-julia> @NLobjective(model, Min, g(x[1], x[2]))
source
register(
+julia> @NLobjective(model, Min, g(x[1], x[2]))
source
register(
     model::Model,
     s::Symbol,
     dimension::Integer,
@@ -3471,7 +3471,7 @@
 julia> register(model, :foo, 1, f, ∇f, ∇²f)
 
 julia> @NLobjective(model, Min, foo(x))
-
source

set_nonlinear_dual_start_value

set_nonlinear_dual_start_value

JuMP.set_nonlinear_dual_start_valueFunction
set_nonlinear_dual_start_value(
     model::Model,
     start::Union{Nothing,Vector{Float64}},
 )

Set the value of the MOI attribute MOI.NLPBlockDualStart.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

The start vector corresponds to the Lagrangian duals of the nonlinear constraints, in the order given by all_nonlinear_constraints. That is, you must pass a single start vector corresponding to all of the nonlinear constraints in a single function call; you cannot set the dual start value of nonlinear constraints one-by-one. The example below demonstrates how to use all_nonlinear_constraints to create a mapping between the nonlinear constraint references and the start vector.

Pass nothing to unset a previous start.

Example

julia> model = Model();
@@ -3494,7 +3494,7 @@
 julia> nonlinear_dual_start_value(model)
 2-element Vector{Float64}:
  -1.0
-  1.0
source

set_nonlinear_objective

set_nonlinear_objective

JuMP.set_nonlinear_objectiveFunction
set_nonlinear_objective(
     model::Model,
     sense::MOI.OptimizationSense,
     expr::Expr,
@@ -3502,17 +3502,17 @@
 
 julia> @variable(model, x);
 
-julia> set_nonlinear_objective(model, MIN_SENSE, :($(x) + $(x)^2))
source

set_normalized_coefficients

set_normalized_coefficients

JuMP.set_normalized_coefficientsFunction
set_normalized_coefficients(
     constraint::ConstraintRef{<:AbstractModel,<:MOI.ConstraintIndex{F}},
     variable::AbstractVariableRef,
     new_coefficients::Vector{Tuple{Int64,T}},
-) where {T,F<:Union{MOI.VectorAffineFunction{T},MOI.VectorQuadraticFunction{T}}}

A deprecated method that now redirects to set_normalized_coefficient.

source

set_optimizer_attribute

set_optimizer_attribute

JuMP.set_optimizer_attributeFunction
set_optimizer_attribute(
     model::Union{GenericModel,MOI.OptimizerWithAttributes},
     attr::Union{AbstractString,MOI.AbstractOptimizerAttribute},
     value,
 )

Set the solver-specific attribute attr in model to value.

If attr is an AbstractString, this is equivalent to set_optimizer_attribute(model, MOI.RawOptimizerAttribute(name), value).

Compat

This method will remain in all v1.X releases of JuMP, but it may be removed in a future v2.0 release. We recommend using set_attribute instead.

See also: set_optimizer_attributes, get_optimizer_attribute.

Example

julia> model = Model();
 
-julia> set_optimizer_attribute(model, MOI.Silent(), true)
source

set_optimizer_attributes

set_optimizer_attributes

JuMP.set_optimizer_attributesFunction
set_optimizer_attributes(
     model::Union{GenericModel,MOI.OptimizerWithAttributes},
     pairs::Pair...,
 )

Given a list of attribute => value pairs, calls set_optimizer_attribute(model, attribute, value) for each pair.

Compat

This method will remain in all v1.X releases of JuMP, but it may be removed in a future v2.0 release. We recommend using set_attributes instead.

See also: set_optimizer_attribute, get_optimizer_attribute.

Example

julia> import Ipopt
@@ -3525,7 +3525,7 @@
 
 julia> set_optimizer_attribute(model, "tol", 1e-4)
 
-julia> set_optimizer_attribute(model, "max_iter", 100)
source

set_value

JuMP.set_valueFunction
set_value(p::NonlinearParameter, v::Number)

Store the value v in the nonlinear parameter p.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

Example

julia> model = Model();
+julia> set_optimizer_attribute(model, "max_iter", 100)
source

set_value

JuMP.set_valueFunction
set_value(p::NonlinearParameter, v::Number)

Store the value v in the nonlinear parameter p.

Compat

This function is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

Example

julia> model = Model();
 
 julia> @NLparameter(model, p == 0)
 p == 0.0
@@ -3534,4 +3534,4 @@
 5
 
 julia> value(p)
-5.0
source

NonlinearConstraintIndex

NonlinearConstraintRef

NonlinearExpression

NonlinearParameter

JuMP.NonlinearParameterType
NonlinearParameter <: AbstractJuMPScalar

A struct to represent a nonlinear parameter.

Create a parameter using @NLparameter.

Compat

This type is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source
+5.0source

NonlinearConstraintIndex

NonlinearConstraintRef

NonlinearExpression

NonlinearParameter

JuMP.NonlinearParameterType
NonlinearParameter <: AbstractJuMPScalar

A struct to represent a nonlinear parameter.

Create a parameter using @NLparameter.

Compat

This type is part of the legacy nonlinear interface. Consider using the new nonlinear interface documented in Nonlinear Modeling.

source
diff --git a/previews/PR3883/background/algebraic_modeling_languages/index.html b/previews/PR3883/background/algebraic_modeling_languages/index.html index ce0c23e43f8..5398a75f632 100644 --- a/previews/PR3883/background/algebraic_modeling_languages/index.html +++ b/previews/PR3883/background/algebraic_modeling_languages/index.html @@ -138,4 +138,4 @@ julia> highs_knapsack([1.0, 2.0], [0.5, 0.5], 1.25) 2-element Vector{Float64}: 0.0 - 2.0

We've now gone from a algebraic model that looked identical to the mathematical model we started with, to a verbose function that uses HiGHS-specific functionality.

The difference between algebraic_knapsack and highs_knapsack highlights the benefit that algebraic modeling languages provide to users. Moreover, if we used a different solver, the solver-specific function would be entirely different. A key benefit of an algebraic modeling language is that you can change the solver without needing to rewrite the model.

+ 2.0

We've now gone from a algebraic model that looked identical to the mathematical model we started with, to a verbose function that uses HiGHS-specific functionality.

The difference between algebraic_knapsack and highs_knapsack highlights the benefit that algebraic modeling languages provide to users. Moreover, if we used a different solver, the solver-specific function would be entirely different. A key benefit of an algebraic modeling language is that you can change the solver without needing to rewrite the model.

diff --git a/previews/PR3883/background/bibliography/index.html b/previews/PR3883/background/bibliography/index.html index ea20b64c32f..959c6f57d4a 100644 --- a/previews/PR3883/background/bibliography/index.html +++ b/previews/PR3883/background/bibliography/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

Bibliography

+

Bibliography

diff --git a/previews/PR3883/changelog/index.html b/previews/PR3883/changelog/index.html index c568410a258..a149260a29f 100644 --- a/previews/PR3883/changelog/index.html +++ b/previews/PR3883/changelog/index.html @@ -12,4 +12,4 @@ new_b = backend(model)
  • All usages of @SDconstraint are deprecated. The new syntax is @constraint(model, X >= Y, PSDCone()).
  • Creating a DenseAxisArray with a Number as an axis will now display a warning. This catches a common error in which users write @variable(model, x[length(S)]) instead of @variable(model, x[1:length(S)]).
  • The caching_mode argument to Model, for example, Model(caching_mode = MOIU.MANUAL) mode has been removed. For more control over the optimizer, use direct_model instead.
  • The previously deprecated lp_objective_perturbation_range and lp_rhs_perturbation_range functions have been removed. Use lp_sensitivity_report instead.
  • The .m fields of NonlinearExpression and NonlinearParameter have been renamed to .model.
  • Infinite variable bounds are now ignored. Thus, @variable(model, x <= Inf) will show has_upper_bound(x) == false. Previously, these bounds were passed through to the solvers which caused numerical issues for solvers expecting finite bounds.
  • The variable_type and constraint_type functions were removed. This should only affect users who previously wrote JuMP extensions. The functions can be deleted without consequence.
  • The internal functions moi_mode, moi_bridge_constraints, moi_add_constraint, and moi_add_to_function_constant are no longer exported.
  • The un-used method Containers.generate_container has been deleted.
  • The Containers API has been refactored, and _build_ref_sets is now public as Containers.build_ref_sets.
  • The parse_constraint_ methods for extending @constraint at parse time have been refactored in a breaking way. Consult the Extensions documentation for more details and examples.
  • Added

    • The TerminationStatusCode and ResultStatusCode enums are now exported by JuMP. Prefer termination_status(model) == OPTIMAL instead of == MOI.OPTIMAL, although the MOI. prefix way still works.
    • Copy a x::DenseAxisArray to an Array by calling Array(x).
    • NonlinearExpression is now a subtype of AbstractJuMPScalar
    • Constraints such as @constraint(model, x + 1 in MOI.Integer()) are now supported.
    • primal_feasibility_report now accepts a function as the first argument.
    • Scalar variables @variable(model, x[1:2] in MOI.Integer()) creates two variables, both of which are constrained to be in the set MOI.Integer.
    • Conic constraints can now be specified as inequalities under a different partial ordering. So @constraint(model, x - y in MOI.Nonnegatives()) can now be written as @constraint(model, x >= y, MOI.Nonnegatives()).
    • Names are now set for vectorized constraints.

    Fixed

    • Fixed a performance issue when show was called on a SparseAxisArray with a large number of elements.
    • Fixed a bug displaying barrier and simplex iterations in solution_summary.
    • Fixed a bug by implementing hash for DenseAxisArray and SparseAxisArray.
    • Names are now only set if the solver supports them. Previously, this prevented solvers such as Ipopt from being used with direct_model.
    • MutableArithmetics.Zero is converted into a 0.0 before being returned to the user. Previously, some calls to @expression would return the undocumented MutableArithmetics.Zero() object. One example is summing over an empty set @expression(model, sum(x[i] for i in 1:0)). You will now get 0.0 instead.
    • AffExpr and QuadExpr can now be used with == 0 instead of iszero. This fixes a number of issues relating to Julia standard libraries such as LinearAlgebra and SparseArrays.
    • Fixed a bug when registering a user-defined function with splatting.

    Other

    • The documentation is now available as a PDF.
    • The documentation now includes a full copy of the MathOptInterface documentation to make it easy to link concepts between the docs. (The MathOptInterface documentation has also been significantly improved.)
    • The documentation contains a large number of improvements and clarifications on a range of topics. Thanks to @sshin23, @DilumAluthge, and @jlwether.
    • The documentation is now built with Julia 1.6 instead of 1.0.
    • Various error messages have been improved to be more readable.

    Version 0.21.10 (September 4, 2021)

    Added

    • Added add_NL_expression
    • add_NL_xxx functions now support AffExpr and QuadExpr as terms

    Fixed

    • Fixed a bug in solution_summary
    • Fixed a bug in relax_integrality

    Other

    • Improved error message in lp_sensitivity_report

    Version 0.21.9 (August 1, 2021)

    Added

    • Containers now support arbitrary container types by passing the type to the container keyword and overloading Containers.container.
    • is_valid now supports nonlinear constraints
    • Added unsafe_backend for querying the inner-most optimizer of a JuMP model.
    • Nonlinear parameters now support the plural @NLparameters macro.
    • Containers (for example, DenseAxisArray) can now be used in vector-valued constraints.

    Other

    • Various improvements to the documentation.

    Version 0.21.8 (May 8, 2021)

    Added

    • The @constraint macro is now extendable in the same way as @variable.
    • AffExpr and QuadExpr can now be used in nonlinear macros.

    Fixed

    • Fixed a bug in lp_sensitivity_report.
    • Fixed an inference issue when creating empty SparseAxisArrays.

    Version 0.21.7 (April 12, 2021)

    Added

    • Added primal_feasibility_report, which can be used to check whether a primal point satisfies primal feasibility.
    • Added coefficient, which returns the coefficient associated with a variable in affine and quadratic expressions.
    • Added copy_conflict, which returns the IIS of an infeasible model.
    • Added solution_summary, which returns (and prints) a struct containing a summary of the solution.
    • Allow AbstractVector in vector constraints instead of just Vector.
    • Added latex_formulation(model) which returns an object representing the latex formulation of a model. Use print(latex_formulation(model)) to print the formulation as a string.
    • User-defined functions in nonlinear expressions are now automatically registered to aid quick model prototyping. However, a warning is printed to encourage the manual registration.
    • DenseAxisArray's now support broadcasting over multiple arrays.
    • Container indices can now be iterators of Base.SizeUnknown.

    Fixed

    • Fixed bug in rad2deg and deg2rad in nonlinear expressions.
    • Fixed a MethodError bug in Containers when forcing container type.
    • Allow partial slicing of a DenseAxisArray, resolving an issue from 2014.
    • Fixed a bug printing variable names in IJulia.
    • Ending an IJulia cell with model now prints a summary of the model (like in the REPL) not the latex formulation. Use print(model) to print the latex formulation.
    • Fixed a bug when copying models containing nested arrays.

    Other

    • Tutorials are now part of the documentation, and more refactoring has taken place.
    • Added JuliaFormatter added as a code formatter.
    • Added some precompilation statements to reduce initial latency.
    • Various improvements to error messages to make them more helpful.
    • Improved performance of value(::NonlinearExpression).
    • Improved performance of fix(::VariableRef).

    Version 0.21.6 (January 29, 2021)

    Added

    • Added support for skew symmetric variables via @variable(model, X[1:2, 1:2] in SkewSymmetricMatrixSpace()).
    • lp_sensitivity_report has been added which significantly improves the performance of querying the sensitivity summary of an LP. lp_objective_perturbation_range and lp_rhs_perturbation_range are deprecated.
    • Dual warm-starts are now supported with set_dual_start_value and dual_start_value.
    • (\in<tab>) can now be used in macros instead of = or in.
    • Use haskey(model::Model, key::Symbol) to check if a name key is registered in a model.
    • Added unregister(model::Model, key::Symbol) to unregister a name key from model.
    • Added callback_node_status for use in callbacks.
    • Added print_bridge_graph to visualize the bridging graph generated by MathOptInterface.
    • Improved error message for containers with duplicate indices.

    Fixed

    • Various fixes to pass tests on Julia 1.6.
    • Fixed a bug in the printing of nonlinear expressions in IJulia.
    • Fixed a bug when nonlinear expressions are passed to user-defined functions.
    • Some internal functions that were previously exported are now no longer exported.
    • Fixed a bug when relaxing a fixed binary variable.
    • Fixed a StackOverflowError that occurred when SparseAxisArrays had a large number of elements.
    • Removed an unnecessary type assertion in list_of_constraint_types.
    • Fixed a bug when copying models with registered expressions.

    Other

    • The documentation has been significantly overhauled. It now has distinct sections for the manual, API reference, and examples. The existing examples in /examples have now been moved to /docs/src/examples and rewritten using Literate.jl, and they are now included in the documentation.
    • JuliaFormatter has been applied to most of the codebase. This will continue to roll out over time, as we fix upstream issues in the formatter, and will eventually become compulsory.
    • The root cause of a large number of method invalidations has been resolved.
    • We switched continuous integration from Travis and Appveyor to GitHub Actions.

    Version 0.21.5 (September 18, 2020)

    Fixed

    • Fixed deprecation warnings
    • Throw DimensionMismatch for incompatibly sized functions and sets
    • Unify treatment of keys(x) on JuMP containers

    Version 0.21.4 (September 14, 2020)

    Added

    • Add debug info when adding unsupported constraints
    • Add relax_integrality for solving continuous relaxation
    • Allow querying constraint conflicts

    Fixed

    • Dispatch on Real for MOI.submit
    • Implement copy for CustomSet in tests
    • Don't export private macros
    • Fix invalid assertion in nonlinear
    • Error if constraint has NaN right-hand side
    • Improve speed of tests
    • Lots of work modularizing files in /test
    • Improve line numbers in macro error messages
    • Print nonlinear subexpressions
    • Various documentation updates
    • Dependency updates:
      • Datastructures 0.18
      • MathOptFormat v0.5
      • Prep for MathOptInterface 0.9.15

    Version 0.21.3 (June 18, 2020)

    • Added Special Order Sets (SOS1 and SOS2) to JuMP with default weights to ease the creation of such constraints (#2212).
    • Added functions simplex_iterations, barrier_iterations and node_count (#2201).
    • Added function reduced_cost (#2205).
    • Implemented callback_value for affine and quadratic expressions (#2231).
    • Support MutableArithmetics.Zero in objective and constraints (#2219).
    • Documentation improvements:
      • Mention tutorials in the docs (#2223).
      • Update COIN-OR links (#2242).
      • Explicit link to the documentation of MOI.FileFormats (#2253).
      • Typo fixes (#2261).
    • Containers improvements:
      • Fix Base.map for DenseAxisArray (#2235).
      • Throw BoundsError if number of indices is incorrect for DenseAxisArray and SparseAxisArray (#2240).
    • Extensibility improvements:
      • Implement a set_objective method fallback that redirects to set_objective_sense and set_objective_function (#2247).
      • Add parse_constraint method with arbitrary number of arguments (#2051).
      • Add parse_constraint_expr and parse_constraint_head (#2228).

    Version 0.21.2 (April 2, 2020)

    • Added relative_gap() to access MOI.RelativeGap() attribute (#2199).
    • Documentation fixes:
      • Added link to source for docstrings in the documentation (#2207).
      • Added docstring for @variables macro (#2216).
      • Typo fixes (#2177, #2184, #2182).
    • Implementation of methods for Base functions:
      • Implemented Base.empty! for JuMP.Model (#2198).
      • Implemented Base.conj for JuMP scalar types (#2209).

    Fixed

    • Fixed sum of expression with scalar product in macro (#2178).
    • Fixed writing of nonlinear models to MathOptFormat (#2181).
    • Fixed construction of empty SparseAxisArray (#2179).
    • Fixed constraint with zero function (#2188).

    Version 0.21.1 (Feb 18, 2020)

    • Improved the clarity of the with_optimizer deprecation warning.

    Version 0.21.0 (Feb 16, 2020)

    Breaking

    • Deprecated with_optimizer (#2090, #2084, #2141). You can replace with_optimizer by either nothing, optimizer_with_attributes or a closure:

      • replace with_optimizer(Ipopt.Optimizer) by Ipopt.Optimizer.
      • replace with_optimizer(Ipopt.Optimizer, max_cpu_time=60.0) by optimizer_with_attributes(Ipopt.Optimizer, "max_cpu_time" => 60.0).
      • replace with_optimizer(Gurobi.Optimizer, env) by () -> Gurobi.Optimizer(env).
      • replace with_optimizer(Gurobi.Optimizer, env, Presolve=0) by optimizer_with_attributes(() -> Gurobi.Optimizer(env), "Presolve" => 0).

      alternatively to optimizer_with_attributes, you can also set the attributes separately with set_optimizer_attribute.

    • Renamed set_parameter and set_parameters to set_optimizer_attribute and set_optimizer_attributes (#2150).

    • Broadcast should now be explicit inside macros. @SDconstraint(model, x >= 1) and @constraint(model, x + 1 in SecondOrderCone()) now throw an error instead of broadcasting 1 along the dimension of x (#2107).

    • @SDconstraint(model, x >= 0) is now equivalent to @constraint(model, x in PSDCone()) instead of @constraint(model, (x .- 0) in PSDCone()) (#2107).

    • The macros now create the containers with map instead of for loops, as a consequence, containers created by @expression can now have any element type and containers of constraint references now have concrete element types when possible. This fixes a long-standing issue where @expression could only be used to generate a collection of linear expressions. Now it works for quadratic expressions as well (#2070).

    • Calling deepcopy(::AbstractModel) now throws an error.

    • The constraint name is now printed in the model string (#2108).

    Added

    • Added support for solver-independent and solver-specific callbacks (#2101).
    • Added write_to_file and read_from_file, supported formats are CBF, LP, MathOptFormat, MPS and SDPA (#2114).
    • Added support for complementarity constraints (#2132).
    • Added support for indicator constraints (#2092).
    • Added support for querying multiple solutions with the result keyword (#2100).
    • Added support for constraining variables on creation (#2128).
    • Added method delete that deletes a vector of variables at once if it is supported by the underlying solver (#2135).
    • The arithmetic between JuMP expression has be refactored into the MutableArithmetics package (#2107).
    • Improved error on complex values in NLP (#1978).
    • Added an example of column generation (#2010).

    Fixed

    • Incorrect coefficients generated when using Symmetric variables (#2102)

    Version 0.20.1 (Oct 18, 2019)

    • Add sections on @variables and @constraints in the documentation (#2062).
    • Fixed product of sparse matrices for Julia v1.3 (#2063).
    • Added set_objective_coefficient to modify the coefficient of a linear term of the objective function (#2008).
    • Added set_time_limit_sec, unset_time_limit_sec and time_limit_sec to set and query the time limit for the solver in seconds (#2053).

    Version 0.20.0 (Aug 24, 2019)

    • Documentation updates.
    • Numerous bug fixes.
    • Better error messages (#1977, #1978, #1997, #2017).
    • Performance improvements (#1947, #2032).
    • Added LP sensitivity summary functions lp_objective_perturbation_range and lp_rhs_perturbation_range (#1917).
    • Added functions dual_objective_value, raw_status and set_parameter.
    • Added function set_objective_coefficient to modify the coefficient of a linear term of the objective (#2008).
    • Added functions set_normalized_rhs, normalized_rhs, and add_to_function_constant to modify and get the constant part of a constraint (#1935, #1960).
    • Added functions set_normalized_coefficient and normalized_coefficient to modify and get the coefficient of a linear term of a constraint (#1935, #1960).
    • Numerous other improvements in MOI 0.9, see the NEWS.md file of MOI for more details.

    Version 0.19.2 (June 8, 2019)

    • Fix a bug in derivatives that could arise in models with nested nonlinear subexpressions.

    Version 0.19.1 (May 12, 2019)

    • Usability and performance improvements.
    • Bug fixes.

    Version 0.19.0 (February 15, 2019)

    JuMP 0.19 contains significant breaking changes.

    Breaking

    • JuMP's abstraction layer for communicating with solvers changed from MathProgBase (MPB) to MathOptInterface (MOI). MOI addresses many longstanding design issues. (See @mlubin's slides from JuMP-dev 2018.) JuMP 0.19 is compatible only with solvers that have been updated for MOI. See the installation guide for a list of solvers that have and have not yet been updated.

    • Most solvers have been renamed to PackageName.Optimizer. For example, GurobiSolver() is now Gurobi.Optimizer.

    • Solvers are no longer added to a model via Model(solver = XXX(kwargs...)). Instead use Model(with_optimizer(XXX, kwargs...)). For example, Model(with_optimizer(Gurobi.Optimizer, OutputFlag=0)).

    • JuMP containers (for example, the objects returned by @variable) have been redesigned. Containers.SparseAxisArray replaces JuMPDict, JuMPArray was rewritten (inspired by AxisArrays) and renamed Containers.DenseAxisArray, and you can now request a container type with the container= keyword to the macros. See the corresponding documentation for more details.

    • The statuses returned by solvers have changed. See the possible status values here. The MOI statuses are much richer than the MPB statuses and can be used to distinguish between previously indistinguishable cases (for example, did the solver have a feasible solution when it stopped because of the time limit?).

    • Starting values are separate from result values. Use value to query the value of a variable in a solution. Use start_value and set_start_value to get and set an initial starting point provided to the solver. The solutions from previous solves are no longer automatically set as the starting points for the next solve.

    • The data structures for affine and quadratic expressions AffExpr and QuadExpr have changed. Internally, terms are stored in dictionaries instead of lists. Duplicate coefficients can no longer exist. Accessors and iteration methods have changed.

    • JuMPNLPEvaluator no longer includes the linear and quadratic parts of the model in the evaluation calls. These are now handled separately to allow NLP solvers that support various types of constraints.

    • JuMP solver-independent callbacks have been replaced by solver-specific callbacks. See your favorite solver for more details. (See the note below: No solver-specific callbacks are implemented yet.)

    • The norm() syntax is no longer recognized inside macros. Use the SecondOrderCone() set instead.

    • JuMP no longer performs automatic transformation between special quadratic forms and second-order cone constraints. Support for these constraint classes depends on the solver.

    • The symbols :Min and :Max are no longer used as optimization senses. Instead, JuMP uses the OptimizationSense enum from MathOptInterface. @objective(model, Max, ...), @objective(model, Min, ...), @NLobjective(model, Max, ...), and @objective(model, Min, ...) remain valid, but @objective(m, :Max, ...) is no longer accepted.

    • The sign conventions for duals has changed in some cases for consistency with conic duality (see the documentation). The shadow_price helper method returns duals with signs that match conventional LP interpretations of dual values as sensitivities of the objective value to relaxations of constraints.

    • @constraintref is no longer defined. Instead, create the appropriate container to hold constraint references manually. For example,

      constraints = Dict() # Optionally, specify types for improved performance.
       for i in 1:N
         constraints[i] = @constraint(model, ...)
      -end
    • The lowerbound, upperbound, and basename keyword arguments to the @variable macro have been renamed to lower_bound, upper_bound, and base_name, for consistency with JuMP's new style recommendations.

    • We rely on broadcasting syntax to apply accessors to collections of variables, for example, value.(x) instead of getvalue(x) for collections. (Use value(x) when x is a scalar object.)

    Added

    • Splatting (like f(x...)) is recognized in restricted settings in nonlinear expressions.

    • Support for deleting constraints and variables.

    • The documentation has been completely rewritten using docstrings and Documenter.

    • Support for modeling mixed conic and quadratic models (for example, conic models with quadratic objectives and bi-linear matrix inequalities).

    • Significantly improved support for modeling new types of constraints and for extending JuMP's macros.

    • Support for providing dual warm starts.

    • Improved support for accessing solver-specific attributes (for example, the irreducible inconsistent subsystem).

    • Explicit control of whether symmetry-enforcing constraints are added to PSD constraints.

    • Support for modeling exponential cones.

    • Significant improvements in internal code quality and testing.

    • Style and naming guidelines.

    • Direct mode and manual mode provide explicit control over when copies of a model are stored or regenerated. See the corresponding documentation.

    Regressions

    There are known regressions from JuMP 0.18 that will be addressed in a future release (0.19.x or later):

    • Performance regressions in model generation (issue). Please file an issue anyway if you notice a significant performance regression. We have plans to address a number of performance issues, but we might not be aware of all of them.

    • Fast incremental NLP solves are not yet reimplemented (issue).

    • We do not yet have an implementation of solver-specific callbacks.

    • The column generation syntax in @variable has been removed (that is, the objective, coefficients, and inconstraints keyword arguments). Support for column generation will be re-introduced in a future release.

    • The ability to solve the continuous relaxation (that is, via solve(model; relaxation = true)) is not yet reimplemented (issue).

    Version 0.18.5 (December 1, 2018)

    • Support views in some derivative evaluation functions.
    • Improved compatibility with PackageCompiler.

    Version 0.18.4 (October 8, 2018)

    • Fix a bug in model printing on Julia 0.7 and 1.0.

    Version 0.18.3 (October 1, 2018)

    • Add support for Julia v1.0 (Thanks @ExpandingMan)
    • Fix matrix expressions with quadratic functions (#1508)

    Version 0.18.2 (June 10, 2018)

    • Fix a bug in second-order derivatives when expressions are present (#1319)
    • Fix a bug in @constraintref (#1330)

    Version 0.18.1 (April 9, 2018)

    • Fix for nested tuple destructuring (#1193)
    • Preserve internal model when relaxation=true (#1209)
    • Minor bug fixes and updates for example

    Version 0.18.0 (July 27, 2017)

    • Drop support for Julia 0.5.
    • Update for ForwardDiff 0.5.
    • Minor bug fixes.

    Version 0.17.1 (June 9, 2017)

    • Use of constructconstraint! in @SDconstraint.
    • Minor bug fixes.

    Version 0.17.0 (May 27, 2017)

    • Breaking change: Mixing quadratic and conic constraints is no longer supported.
    • Breaking change: The getvariable and getconstraint functions are replaced by indexing on the corresponding symbol. For instance, to access the variable with name x, one should now write m[:x] instead of getvariable(m, :x). As a consequence, creating a variable and constraint with the same name now triggers a warning, and accessing one of them afterwards throws an error. This change is breaking only in the latter case.
    • Addition of the getobjectivebound function that mirrors the functionality of the MathProgBase getobjbound function except that it takes into account transformations performed by JuMP.
    • Minor bug fixes.

    The following changes are primarily of interest to developers of JuMP extensions:

    • The new syntax @constraint(model, expr in Cone) creates the constraint ensuring that expr is inside Cone. The Cone argument is passed to constructconstraint! which enables the call to the dispatched to an extension.
    • The @variable macro now calls constructvariable! instead of directly calling the Variable constructor. Extra arguments and keyword arguments passed to @variable are passed to constructvariable! which enables the call to be dispatched to an extension.
    • Refactor the internal function conicdata (used build the MathProgBase conic model) into smaller sub-functions to make these parts reusable by extensions.

    Version 0.16.2 (March 28, 2017)

    • Minor bug fixes and printing tweaks
    • Address deprecation warnings for Julia 0.6

    Version 0.16.1 (March 7, 2017)

    • Better support for AbstractArray in JuMP (Thanks @tkoolen)
    • Minor bug fixes

    Version 0.16.0 (February 23, 2017)

    • Breaking change: JuMP no longer has a mechanism for selecting solvers by default (the previous mechanism was flawed and incompatible with Julia 0.6). Not specifying a solver before calling solve() will result in an error.
    • Breaking change: User-defined functions are no longer global. The first argument to JuMP.register is now a JuMP Model object within whose scope the function will be registered. Calling JuMP.register without a Model now produces an error.
    • Breaking change: Use the new JuMP.fix method to fix a variable to a value or to update the value to which a variable is fixed. Calling setvalue on a fixed variable now results in an error in order to avoid silent behavior changes. (Thanks @joaquimg)
    • Nonlinear expressions now print out similarly to linear/quadratic expressions (useful for debugging!)
    • New category keyword to @variable. Used for specifying categories of anonymous variables.
    • Compatibility with Julia 0.6-dev.
    • Minor fixes and improvements (Thanks @cossio, @ccoffrin, @blegat)

    Version 0.15.1 (January 31, 2017)

    • Bugfix for @LinearConstraints and friends

    Version 0.15.0 (December 22, 2016)

    • Julia 0.5.0 is the minimum required version for this release.
    • Document support for BARON solver
    • Enable info callbacks in more states than before, for example, for recording solutions. New when argument to addinfocallback (#814, thanks @yeesian)
    • Improved support for anonymous variables. This includes new warnings for potentially confusing use of the traditional non-anonymous syntax:
      • When multiple variables in a model are given the same name
      • When non-symbols are used as names, for example, @variable(m, x[1][1:N])
    • Improvements in iterating over JuMP containers (#836, thanks @IssamT)
    • Support for writing variable names in .lp file output (Thanks @leethargo)
    • Support for querying duals to SDP problems (Thanks @blegat)
    • The comprehension syntax with curly braces sum{}, prod{}, and norm2{} has been deprecated in favor of Julia's native comprehension syntax sum(), prod() and norm() as previously announced. (For early adopters of the new syntax, norm2() was renamed to norm() without deprecation.)
    • Unit tests rewritten to use Base.Test instead of FactCheck
    • Improved support for operations with matrices of JuMP types (Thanks @ExpandingMan)
    • The syntax to halt a solver from inside a callback has changed from throw(CallbackAbort()) to return JuMP.StopTheSolver
    • Minor bug fixes

    Version 0.14.2 (December 12, 2016)

    • Allow singleton anonymous variables (includes bugfix)

    Version 0.14.1 (September 12, 2016)

    • More consistent handling of states in informational callbacks, includes a new when parameter to addinfocallback for specifying in which state an informational callback should be called.

    Version 0.14.0 (August 7, 2016)

    • Compatibility with Julia 0.5 and ForwardDiff 0.2
    • Support for "anonymous" variables, constraints, expressions, and parameters, for example, x = @variable(m, [1:N]) instead of @variable(m, x[1:N])
    • Support for retrieving constraints from a model by name via getconstraint
    • @NLconstraint now returns constraint references (as expected).
    • Support for vectorized expressions within lazy constraints
    • On Julia 0.5, parse new comprehension syntax sum(x[i] for i in 1:N if isodd(i)) instead of sum{ x[i], i in 1:N; isodd(i) }. The old syntax with curly braces will be deprecated in JuMP 0.15.
    • Now possible to provide nonlinear expressions as "raw" Julia Expr objects instead of using JuMP's nonlinear macros. This input format is useful for programmatically generated expressions.
    • s/Mathematical Programming/Mathematical Optimization/
    • Support for local cuts (Thanks to @madanim, Mehdi Madani)
    • Document Xpress interface developed by @joaquimg, Joaquim Dias Garcia
    • Minor bug and deprecation fixes (Thanks @odow, @jrevels)

    Version 0.13.2 (May 16, 2016)

    • Compatibility update for MathProgBase

    Version 0.13.1 (May 3, 2016)

    • Fix broken deprecation for registerNLfunction.

    Version 0.13.0 (April 29, 2016)

    • Most exported methods and macros have been renamed to avoid camelCase. See the list of changes here. There is a 1-1 mapping from the old names to the new, and it is safe to simply replace the names to update existing models.
    • Specify variable lower/upper bounds in @variable using the lowerbound and upperbound keyword arguments.
    • Change name printed for variable using the basename keyword argument to @variable.
    • New @variables macro allows multi-line declaration of groups of variables.
    • A number of solver methods previously available only through MathProgBase are now exposed directly in JuMP. The fix was recorded live.
    • Compatibility fixes with Julia 0.5.
    • The "end" indexing syntax is no longer supported within JuMPArrays which do not use 1-based indexing until upstream issues are resolved, see here.

    Version 0.12.2 (March 9, 2016)

    • Small fixes for nonlinear optimization

    Version 0.12.1 (March 1, 2016)

    • Fix a regression in slicing for JuMPArrays (when not using 1-based indexing)

    Version 0.12.0 (February 27, 2016)

    • The automatic differentiation functionality has been completely rewritten with a number of user-facing changes:
      • @defExpr and @defNLExpr now take the model as the first argument. The previous one-argument version of @defExpr is deprecated; all expressions should be named. For example, replace @defExpr(2x+y) with @defExpr(jump_model, my_expr, 2x+y).
      • JuMP no longer uses Julia's variable binding rules for efficiently re-solving a sequence of nonlinear models. Instead, we have introduced nonlinear parameters. This is a breaking change, so we have added a warning message when we detect models that may depend on the old behavior.
      • Support for user-defined functions integrated within nonlinear JuMP expressions.
    • Replaced iteration over AffExpr with Number-like scalar iteration; previous iteration behavior is now available via linearterms(::AffExpr).
    • Stopping the solver via throw(CallbackAbort()) from a callback no longer triggers an exception. Instead, solve() returns UserLimit status.
    • getDual() now works for conic problems (Thanks @emreyamangil.)

    Version 0.11.3 (February 4, 2016)

    • Bug-fix for problems with quadratic objectives and semidefinite constraints

    Version 0.11.2 (January 14, 2016)

    • Compatibility update for Mosek

    Version 0.11.1 (December 1, 2015)

    • Remove usage of @compat in tests.
    • Fix updating quadratic objectives for nonlinear models.

    Version 0.11.0 (November 30, 2015)

    • Julia 0.4.0 is the minimum required version for this release.
    • Fix for scoping semantics of index variables in sum{}. Index variables no longer leak into the surrounding scope.
    • Addition of the solve(m::Model, relaxation=true) keyword argument to solve the standard continuous relaxation of model m
    • The getConstraintBounds() method allows access to the lower and upper bounds of all constraints in a (nonlinear) model.
    • Update for breaking changes in MathProgBase

    Version 0.10.3 (November 20, 2015)

    • Fix a rare error when parsing quadratic expressions
    • Fix Variable() constructor with default arguments
    • Detect unrecognized keywords in solve()

    Version 0.10.2 (September 28, 2015)

    • Fix for deprecation warnings

    Version 0.10.1 (September 3, 2015)

    • Fixes for ambiguity warnings.
    • Fix for breaking change in precompilation syntax in Julia 0.4-pre

    Version 0.10.0 (August 31, 2015)

    • Support (on Julia 0.4 and later) for conditions in indexing @defVar and @addConstraint constructs, for example, @defVar(m, x[i=1:5,j=1:5; i+j >= 3])
    • Support for vectorized operations on Variables and expressions. See the documentation for details.
    • New getVar() method to access variables in a model by name
    • Support for semidefinite programming.
    • Dual solutions are now available for general nonlinear problems. You may call getDual on a reference object for a nonlinear constraint, and getDual on a variable object for Lagrange multipliers from active bounds.
    • Introduce warnings for two common performance traps: too many calls to getValue() on a collection of variables and use of the + operator in a loop to sum expressions.
    • Second-order cone constraints can be written directly with the norm() and norm2{} syntax.
    • Implement MathProgBase interface for querying Hessian-vector products.
    • Iteration over JuMPContainers is deprecated; instead, use the keys and values functions, and zip(keys(d),values(d)) for the old behavior.
    • @defVar returns Array{Variable,N} when each of N index sets are of the form 1:nᵢ.
    • Module precompilation: on Julia 0.4 and later, using JuMP is now much faster.

    Version 0.9.3 (August 11, 2015)

    • Fixes for FactCheck testing on julia v0.4.

    Version 0.9.2 (June 27, 2015)

    • Fix bug in @addConstraints.

    Version 0.9.1 (April 25, 2015)

    • Fix for Julia 0.4-dev.
    • Small infrastructure improvements for extensions.

    Version 0.9.0 (April 18, 2015)

    • Comparison operators for constructing constraints (for example, 2x >= 1) have been deprecated. Instead, construct the constraints explicitly in the @addConstraint macro to add them to the model, or in the @LinearConstraint macro to create a stand-alone linear constraint instance.
    • getValue() method implemented to compute the value of a nonlinear subexpression
    • JuMP is now released under the Mozilla Public License version 2.0 (was previously LGPL). MPL is a copyleft license which is less restrictive than LGPL, especially for embedding JuMP within other applications.
    • A number of performance improvements in ReverseDiffSparse for computing derivatives.
    • MathProgBase.getsolvetime(m) now returns the solution time reported by the solver, if available. (Thanks @odow, Oscar Dowson)
    • Formatting fix for LP format output. (Thanks @sbebo, Leonardo Taccari).

    Version 0.8.0 (February 17, 2015)

    • Nonlinear subexpressions now supported with the @defNLExpr macro.
    • SCS supported for solving second-order conic problems.
    • setXXXCallback family deprecated in favor of addXXXCallback.
    • Multiple callbacks of the same type can be registered.
    • Added support for informational callbacks via addInfoCallback.
    • A CallbackAbort exception can be thrown from callback to safely exit optimization.

    Version 0.7.4 (February 4, 2015)

    • Reduced costs and linear constraint duals are now accessible when quadratic constraints are present.
    • Two-sided nonlinear constraints are supported.
    • Methods for accessing the number of variables and constraints in a model are renamed.
    • New default procedure for setting initial values in nonlinear optimization: project zero onto the variable bounds.
    • Small bug fixes.

    Version 0.7.3 (January 14, 2015)

    • Fix a method ambiguity conflict with Compose.jl (cosmetic fix)

    Version 0.7.2 (January 9, 2015)

    • Fix a bug in sum(::JuMPDict)
    • Added the setCategory function to change a variables category (for example, continuous or binary)

    after construction, and getCategory to retrieve the variable category.

    Version 0.7.1 (January 2, 2015)

    • Fix a bug in parsing linear expressions in macros. Affects only Julia 0.4 and later.

    Version 0.7.0 (December 29, 2014)

    Linear/quadratic/conic programming

    • Breaking change: The syntax for column-wise model generation has been changed to use keyword arguments in @defVar.
    • On Julia 0.4 and later, variables and coefficients may be multiplied in any order within macros. That is, variable*coefficient is now valid syntax.
    • ECOS supported for solving second-order conic problems.

    Nonlinear programming

    • Support for skipping model generation when solving a sequence of nonlinear models with changing data.
    • Fix a memory leak when solving a sequence of nonlinear models.
    • The @addNLConstraint macro now supports the three-argument version to define sets of nonlinear constraints.
    • KNITRO supported as a nonlinear solver.
    • Speed improvements for model generation.
    • The @addNLConstraints macro supports adding multiple (groups of) constraints at once. Syntax is similar to @addConstraints.
    • Discrete variables allowed in nonlinear problems for solvers which support them (currently only KNITRO).

    General

    • Starting values for variables may now be specified with @defVar(m, x, start=value).
    • The setSolver function allows users to change the solver subsequent to model creation.
    • Support for "fixed" variables via the @defVar(m, x == 1) syntax.
    • Unit tests rewritten to use FactCheck.jl, improved testing across solvers.

    Version 0.6.3 (October 19, 2014)

    • Fix a bug in multiplying two AffExpr objects.

    Version 0.6.2 (October 11, 2014)

    • Further improvements and bug fixes for printing.
    • Fixed a bug in @defExpr.
    • Support for accessing expression graphs through the MathProgBase NLP interface.

    Version 0.6.1 (September 19, 2014)

    • Improvements and bug fixes for printing.

    Version 0.6.0 (September 9, 2014)

    • Julia 0.3.0 is the minimum required version for this release.
    • buildInternalModel(m::Model) added to build solver-level model in memory without optimizing.
    • Deprecate load_model_only keyword argument to solve.
    • Add groups of constraints with @addConstraints macro.
    • Unicode operators now supported, including for sum, for prod, and /
    • Quadratic constraints supported in @addConstraint macro.
    • Quadratic objectives supported in @setObjective macro.
    • MathProgBase solver-independent interface replaces Ipopt-specific interface for nonlinear problems
      • Breaking change: IpoptOptions no longer supported to specify solver options, use m = Model(solver=IpoptSolver(options...)) instead.
    • New solver interfaces: ECOS, NLopt, and nonlinear support for MOSEK
    • New option to control whether the lazy constraint callback is executed at each node in the B&B tree or just when feasible solutions are found
    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
    • Add support for index dependencies (for example, triangular indexing) in @defVar, @addConstraint, and @defExpr (for example, @defVar(m, x[i=1:10,j=i:10])).
      • This required some changes to the internal structure of JuMP containers, which may break code that explicitly stored JuMPDict objects.

    Version 0.5.8 (September 24, 2014)

    • Fix a bug with specifying solvers (affects Julia 0.2 only)

    Version 0.5.7 (September 5, 2014)

    • Fix a bug in printing models

    Version 0.5.6 (September 2, 2014)

    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
      • Breaking change: Syntax for Variable() constructor has changed (use of this interface remains discouraged)
    • Update for breaking changes in MathProgBase

    Version 0.5.5 (July 6, 2014)

    • Fix bug with problem modification: adding variables that did not appear in existing constraints or objective.

    Version 0.5.4 (June 19, 2014)

    • Update for breaking change in MathProgBase which reduces loading times for using JuMP
    • Fix error when MIPs not solved to optimality

    Version 0.5.3 (May 21, 2014)

    • Update for breaking change in ReverseDiffSparse

    Version 0.5.2 (May 9, 2014)

    • Fix compatibility with Julia 0.3 prerelease

    Version 0.5.1 (May 5, 2014)

    • Fix a bug in coefficient handling inside lazy constraints and user cuts

    Version 0.5.0 (May 2, 2014)

    • Support for nonlinear optimization with exact, sparse second-order derivatives automatically computed. Ipopt is currently the only solver supported.
    • getValue for AffExpr and QuadExpr
    • Breaking change: getSolverModel replaced by getInternalModel, which returns the internal MathProgBase-level model
    • Groups of constraints can be specified with @addConstraint (see documentation for details). This is not a breaking change.
    • dot(::JuMPDict{Variable},::JuMPDict{Variable}) now returns the corresponding quadratic expression.

    Version 0.4.1 (March 24, 2014)

    • Fix bug where change in objective sense was ignored when re-solving a model.
    • Fix issue with handling zero coefficients in AffExpr.

    Version 0.4.0 (March 10, 2014)

    • Support for SOS1 and SOS2 constraints.
    • Solver-independent callback for user heuristics.
    • dot and sum implemented for JuMPDict objects. Now you can say @addConstraint(m, dot(a,x) <= b).
    • Developers: support for extensions to JuMP. See definition of Model in src/JuMP.jl for more details.
    • Option to construct the low-level model before optimizing.

    Version 0.3.2 (February 17, 2014)

    • Improved model printing
      • Preliminary support for IJulia output

    Version 0.3.1 (January 30, 2014)

    • Documentation updates
    • Support for MOSEK
    • CPLEXLink renamed to CPLEX

    Version 0.3.0 (January 21, 2014)

    • Unbounded/infeasibility rays: getValue() will return the corresponding components of an unbounded ray when a model is unbounded, if supported by the selected solver. getDual() will return an infeasibility ray (Farkas proof) if a model is infeasible and the selected solver supports this feature.
    • Solver-independent callbacks for user generated cuts.
    • Use new interface for solver-independent QCQP.
    • setlazycallback renamed to setLazyCallback for consistency.

    Version 0.2.0 (December 15, 2013)

    Breaking

    • Objective sense is specified in setObjective instead of in the Model constructor.
    • lpsolver and mipsolver merged into single solver option.

    Added

    • Problem modification with efficient LP restarts and MIP warm-starts.
    • Relatedly, column-wise modeling now supported.
    • Solver-independent callbacks supported. Currently we support only a "lazy constraint" callback, which works with Gurobi, CPLEX, and GLPK. More callbacks coming soon.

    Version 0.1.2 (November 16, 2013)

    • Bug fixes for printing, improved error messages.
    • Allow AffExpr to be used in macros; for example, ex = y + z; @addConstraint(m, x + 2*ex <= 3)

    Version 0.1.1 (October 23, 2013)

    • Update for solver specification API changes in MathProgBase.

    Version 0.1.0 (October 3, 2013)

    • Initial public release.
    +end
  • The lowerbound, upperbound, and basename keyword arguments to the @variable macro have been renamed to lower_bound, upper_bound, and base_name, for consistency with JuMP's new style recommendations.

  • We rely on broadcasting syntax to apply accessors to collections of variables, for example, value.(x) instead of getvalue(x) for collections. (Use value(x) when x is a scalar object.)

  • Added

    • Splatting (like f(x...)) is recognized in restricted settings in nonlinear expressions.

    • Support for deleting constraints and variables.

    • The documentation has been completely rewritten using docstrings and Documenter.

    • Support for modeling mixed conic and quadratic models (for example, conic models with quadratic objectives and bi-linear matrix inequalities).

    • Significantly improved support for modeling new types of constraints and for extending JuMP's macros.

    • Support for providing dual warm starts.

    • Improved support for accessing solver-specific attributes (for example, the irreducible inconsistent subsystem).

    • Explicit control of whether symmetry-enforcing constraints are added to PSD constraints.

    • Support for modeling exponential cones.

    • Significant improvements in internal code quality and testing.

    • Style and naming guidelines.

    • Direct mode and manual mode provide explicit control over when copies of a model are stored or regenerated. See the corresponding documentation.

    Regressions

    There are known regressions from JuMP 0.18 that will be addressed in a future release (0.19.x or later):

    • Performance regressions in model generation (issue). Please file an issue anyway if you notice a significant performance regression. We have plans to address a number of performance issues, but we might not be aware of all of them.

    • Fast incremental NLP solves are not yet reimplemented (issue).

    • We do not yet have an implementation of solver-specific callbacks.

    • The column generation syntax in @variable has been removed (that is, the objective, coefficients, and inconstraints keyword arguments). Support for column generation will be re-introduced in a future release.

    • The ability to solve the continuous relaxation (that is, via solve(model; relaxation = true)) is not yet reimplemented (issue).

    Version 0.18.5 (December 1, 2018)

    • Support views in some derivative evaluation functions.
    • Improved compatibility with PackageCompiler.

    Version 0.18.4 (October 8, 2018)

    • Fix a bug in model printing on Julia 0.7 and 1.0.

    Version 0.18.3 (October 1, 2018)

    • Add support for Julia v1.0 (Thanks @ExpandingMan)
    • Fix matrix expressions with quadratic functions (#1508)

    Version 0.18.2 (June 10, 2018)

    • Fix a bug in second-order derivatives when expressions are present (#1319)
    • Fix a bug in @constraintref (#1330)

    Version 0.18.1 (April 9, 2018)

    • Fix for nested tuple destructuring (#1193)
    • Preserve internal model when relaxation=true (#1209)
    • Minor bug fixes and updates for example

    Version 0.18.0 (July 27, 2017)

    • Drop support for Julia 0.5.
    • Update for ForwardDiff 0.5.
    • Minor bug fixes.

    Version 0.17.1 (June 9, 2017)

    • Use of constructconstraint! in @SDconstraint.
    • Minor bug fixes.

    Version 0.17.0 (May 27, 2017)

    • Breaking change: Mixing quadratic and conic constraints is no longer supported.
    • Breaking change: The getvariable and getconstraint functions are replaced by indexing on the corresponding symbol. For instance, to access the variable with name x, one should now write m[:x] instead of getvariable(m, :x). As a consequence, creating a variable and constraint with the same name now triggers a warning, and accessing one of them afterwards throws an error. This change is breaking only in the latter case.
    • Addition of the getobjectivebound function that mirrors the functionality of the MathProgBase getobjbound function except that it takes into account transformations performed by JuMP.
    • Minor bug fixes.

    The following changes are primarily of interest to developers of JuMP extensions:

    • The new syntax @constraint(model, expr in Cone) creates the constraint ensuring that expr is inside Cone. The Cone argument is passed to constructconstraint! which enables the call to the dispatched to an extension.
    • The @variable macro now calls constructvariable! instead of directly calling the Variable constructor. Extra arguments and keyword arguments passed to @variable are passed to constructvariable! which enables the call to be dispatched to an extension.
    • Refactor the internal function conicdata (used build the MathProgBase conic model) into smaller sub-functions to make these parts reusable by extensions.

    Version 0.16.2 (March 28, 2017)

    • Minor bug fixes and printing tweaks
    • Address deprecation warnings for Julia 0.6

    Version 0.16.1 (March 7, 2017)

    • Better support for AbstractArray in JuMP (Thanks @tkoolen)
    • Minor bug fixes

    Version 0.16.0 (February 23, 2017)

    • Breaking change: JuMP no longer has a mechanism for selecting solvers by default (the previous mechanism was flawed and incompatible with Julia 0.6). Not specifying a solver before calling solve() will result in an error.
    • Breaking change: User-defined functions are no longer global. The first argument to JuMP.register is now a JuMP Model object within whose scope the function will be registered. Calling JuMP.register without a Model now produces an error.
    • Breaking change: Use the new JuMP.fix method to fix a variable to a value or to update the value to which a variable is fixed. Calling setvalue on a fixed variable now results in an error in order to avoid silent behavior changes. (Thanks @joaquimg)
    • Nonlinear expressions now print out similarly to linear/quadratic expressions (useful for debugging!)
    • New category keyword to @variable. Used for specifying categories of anonymous variables.
    • Compatibility with Julia 0.6-dev.
    • Minor fixes and improvements (Thanks @cossio, @ccoffrin, @blegat)

    Version 0.15.1 (January 31, 2017)

    • Bugfix for @LinearConstraints and friends

    Version 0.15.0 (December 22, 2016)

    • Julia 0.5.0 is the minimum required version for this release.
    • Document support for BARON solver
    • Enable info callbacks in more states than before, for example, for recording solutions. New when argument to addinfocallback (#814, thanks @yeesian)
    • Improved support for anonymous variables. This includes new warnings for potentially confusing use of the traditional non-anonymous syntax:
      • When multiple variables in a model are given the same name
      • When non-symbols are used as names, for example, @variable(m, x[1][1:N])
    • Improvements in iterating over JuMP containers (#836, thanks @IssamT)
    • Support for writing variable names in .lp file output (Thanks @leethargo)
    • Support for querying duals to SDP problems (Thanks @blegat)
    • The comprehension syntax with curly braces sum{}, prod{}, and norm2{} has been deprecated in favor of Julia's native comprehension syntax sum(), prod() and norm() as previously announced. (For early adopters of the new syntax, norm2() was renamed to norm() without deprecation.)
    • Unit tests rewritten to use Base.Test instead of FactCheck
    • Improved support for operations with matrices of JuMP types (Thanks @ExpandingMan)
    • The syntax to halt a solver from inside a callback has changed from throw(CallbackAbort()) to return JuMP.StopTheSolver
    • Minor bug fixes

    Version 0.14.2 (December 12, 2016)

    • Allow singleton anonymous variables (includes bugfix)

    Version 0.14.1 (September 12, 2016)

    • More consistent handling of states in informational callbacks, includes a new when parameter to addinfocallback for specifying in which state an informational callback should be called.

    Version 0.14.0 (August 7, 2016)

    • Compatibility with Julia 0.5 and ForwardDiff 0.2
    • Support for "anonymous" variables, constraints, expressions, and parameters, for example, x = @variable(m, [1:N]) instead of @variable(m, x[1:N])
    • Support for retrieving constraints from a model by name via getconstraint
    • @NLconstraint now returns constraint references (as expected).
    • Support for vectorized expressions within lazy constraints
    • On Julia 0.5, parse new comprehension syntax sum(x[i] for i in 1:N if isodd(i)) instead of sum{ x[i], i in 1:N; isodd(i) }. The old syntax with curly braces will be deprecated in JuMP 0.15.
    • Now possible to provide nonlinear expressions as "raw" Julia Expr objects instead of using JuMP's nonlinear macros. This input format is useful for programmatically generated expressions.
    • s/Mathematical Programming/Mathematical Optimization/
    • Support for local cuts (Thanks to @madanim, Mehdi Madani)
    • Document Xpress interface developed by @joaquimg, Joaquim Dias Garcia
    • Minor bug and deprecation fixes (Thanks @odow, @jrevels)

    Version 0.13.2 (May 16, 2016)

    • Compatibility update for MathProgBase

    Version 0.13.1 (May 3, 2016)

    • Fix broken deprecation for registerNLfunction.

    Version 0.13.0 (April 29, 2016)

    • Most exported methods and macros have been renamed to avoid camelCase. See the list of changes here. There is a 1-1 mapping from the old names to the new, and it is safe to simply replace the names to update existing models.
    • Specify variable lower/upper bounds in @variable using the lowerbound and upperbound keyword arguments.
    • Change name printed for variable using the basename keyword argument to @variable.
    • New @variables macro allows multi-line declaration of groups of variables.
    • A number of solver methods previously available only through MathProgBase are now exposed directly in JuMP. The fix was recorded live.
    • Compatibility fixes with Julia 0.5.
    • The "end" indexing syntax is no longer supported within JuMPArrays which do not use 1-based indexing until upstream issues are resolved, see here.

    Version 0.12.2 (March 9, 2016)

    • Small fixes for nonlinear optimization

    Version 0.12.1 (March 1, 2016)

    • Fix a regression in slicing for JuMPArrays (when not using 1-based indexing)

    Version 0.12.0 (February 27, 2016)

    • The automatic differentiation functionality has been completely rewritten with a number of user-facing changes:
      • @defExpr and @defNLExpr now take the model as the first argument. The previous one-argument version of @defExpr is deprecated; all expressions should be named. For example, replace @defExpr(2x+y) with @defExpr(jump_model, my_expr, 2x+y).
      • JuMP no longer uses Julia's variable binding rules for efficiently re-solving a sequence of nonlinear models. Instead, we have introduced nonlinear parameters. This is a breaking change, so we have added a warning message when we detect models that may depend on the old behavior.
      • Support for user-defined functions integrated within nonlinear JuMP expressions.
    • Replaced iteration over AffExpr with Number-like scalar iteration; previous iteration behavior is now available via linearterms(::AffExpr).
    • Stopping the solver via throw(CallbackAbort()) from a callback no longer triggers an exception. Instead, solve() returns UserLimit status.
    • getDual() now works for conic problems (Thanks @emreyamangil.)

    Version 0.11.3 (February 4, 2016)

    • Bug-fix for problems with quadratic objectives and semidefinite constraints

    Version 0.11.2 (January 14, 2016)

    • Compatibility update for Mosek

    Version 0.11.1 (December 1, 2015)

    • Remove usage of @compat in tests.
    • Fix updating quadratic objectives for nonlinear models.

    Version 0.11.0 (November 30, 2015)

    • Julia 0.4.0 is the minimum required version for this release.
    • Fix for scoping semantics of index variables in sum{}. Index variables no longer leak into the surrounding scope.
    • Addition of the solve(m::Model, relaxation=true) keyword argument to solve the standard continuous relaxation of model m
    • The getConstraintBounds() method allows access to the lower and upper bounds of all constraints in a (nonlinear) model.
    • Update for breaking changes in MathProgBase

    Version 0.10.3 (November 20, 2015)

    • Fix a rare error when parsing quadratic expressions
    • Fix Variable() constructor with default arguments
    • Detect unrecognized keywords in solve()

    Version 0.10.2 (September 28, 2015)

    • Fix for deprecation warnings

    Version 0.10.1 (September 3, 2015)

    • Fixes for ambiguity warnings.
    • Fix for breaking change in precompilation syntax in Julia 0.4-pre

    Version 0.10.0 (August 31, 2015)

    • Support (on Julia 0.4 and later) for conditions in indexing @defVar and @addConstraint constructs, for example, @defVar(m, x[i=1:5,j=1:5; i+j >= 3])
    • Support for vectorized operations on Variables and expressions. See the documentation for details.
    • New getVar() method to access variables in a model by name
    • Support for semidefinite programming.
    • Dual solutions are now available for general nonlinear problems. You may call getDual on a reference object for a nonlinear constraint, and getDual on a variable object for Lagrange multipliers from active bounds.
    • Introduce warnings for two common performance traps: too many calls to getValue() on a collection of variables and use of the + operator in a loop to sum expressions.
    • Second-order cone constraints can be written directly with the norm() and norm2{} syntax.
    • Implement MathProgBase interface for querying Hessian-vector products.
    • Iteration over JuMPContainers is deprecated; instead, use the keys and values functions, and zip(keys(d),values(d)) for the old behavior.
    • @defVar returns Array{Variable,N} when each of N index sets are of the form 1:nᵢ.
    • Module precompilation: on Julia 0.4 and later, using JuMP is now much faster.

    Version 0.9.3 (August 11, 2015)

    • Fixes for FactCheck testing on julia v0.4.

    Version 0.9.2 (June 27, 2015)

    • Fix bug in @addConstraints.

    Version 0.9.1 (April 25, 2015)

    • Fix for Julia 0.4-dev.
    • Small infrastructure improvements for extensions.

    Version 0.9.0 (April 18, 2015)

    • Comparison operators for constructing constraints (for example, 2x >= 1) have been deprecated. Instead, construct the constraints explicitly in the @addConstraint macro to add them to the model, or in the @LinearConstraint macro to create a stand-alone linear constraint instance.
    • getValue() method implemented to compute the value of a nonlinear subexpression
    • JuMP is now released under the Mozilla Public License version 2.0 (was previously LGPL). MPL is a copyleft license which is less restrictive than LGPL, especially for embedding JuMP within other applications.
    • A number of performance improvements in ReverseDiffSparse for computing derivatives.
    • MathProgBase.getsolvetime(m) now returns the solution time reported by the solver, if available. (Thanks @odow, Oscar Dowson)
    • Formatting fix for LP format output. (Thanks @sbebo, Leonardo Taccari).

    Version 0.8.0 (February 17, 2015)

    • Nonlinear subexpressions now supported with the @defNLExpr macro.
    • SCS supported for solving second-order conic problems.
    • setXXXCallback family deprecated in favor of addXXXCallback.
    • Multiple callbacks of the same type can be registered.
    • Added support for informational callbacks via addInfoCallback.
    • A CallbackAbort exception can be thrown from callback to safely exit optimization.

    Version 0.7.4 (February 4, 2015)

    • Reduced costs and linear constraint duals are now accessible when quadratic constraints are present.
    • Two-sided nonlinear constraints are supported.
    • Methods for accessing the number of variables and constraints in a model are renamed.
    • New default procedure for setting initial values in nonlinear optimization: project zero onto the variable bounds.
    • Small bug fixes.

    Version 0.7.3 (January 14, 2015)

    • Fix a method ambiguity conflict with Compose.jl (cosmetic fix)

    Version 0.7.2 (January 9, 2015)

    • Fix a bug in sum(::JuMPDict)
    • Added the setCategory function to change a variables category (for example, continuous or binary)

    after construction, and getCategory to retrieve the variable category.

    Version 0.7.1 (January 2, 2015)

    • Fix a bug in parsing linear expressions in macros. Affects only Julia 0.4 and later.

    Version 0.7.0 (December 29, 2014)

    Linear/quadratic/conic programming

    • Breaking change: The syntax for column-wise model generation has been changed to use keyword arguments in @defVar.
    • On Julia 0.4 and later, variables and coefficients may be multiplied in any order within macros. That is, variable*coefficient is now valid syntax.
    • ECOS supported for solving second-order conic problems.

    Nonlinear programming

    • Support for skipping model generation when solving a sequence of nonlinear models with changing data.
    • Fix a memory leak when solving a sequence of nonlinear models.
    • The @addNLConstraint macro now supports the three-argument version to define sets of nonlinear constraints.
    • KNITRO supported as a nonlinear solver.
    • Speed improvements for model generation.
    • The @addNLConstraints macro supports adding multiple (groups of) constraints at once. Syntax is similar to @addConstraints.
    • Discrete variables allowed in nonlinear problems for solvers which support them (currently only KNITRO).

    General

    • Starting values for variables may now be specified with @defVar(m, x, start=value).
    • The setSolver function allows users to change the solver subsequent to model creation.
    • Support for "fixed" variables via the @defVar(m, x == 1) syntax.
    • Unit tests rewritten to use FactCheck.jl, improved testing across solvers.

    Version 0.6.3 (October 19, 2014)

    • Fix a bug in multiplying two AffExpr objects.

    Version 0.6.2 (October 11, 2014)

    • Further improvements and bug fixes for printing.
    • Fixed a bug in @defExpr.
    • Support for accessing expression graphs through the MathProgBase NLP interface.

    Version 0.6.1 (September 19, 2014)

    • Improvements and bug fixes for printing.

    Version 0.6.0 (September 9, 2014)

    • Julia 0.3.0 is the minimum required version for this release.
    • buildInternalModel(m::Model) added to build solver-level model in memory without optimizing.
    • Deprecate load_model_only keyword argument to solve.
    • Add groups of constraints with @addConstraints macro.
    • Unicode operators now supported, including for sum, for prod, and /
    • Quadratic constraints supported in @addConstraint macro.
    • Quadratic objectives supported in @setObjective macro.
    • MathProgBase solver-independent interface replaces Ipopt-specific interface for nonlinear problems
      • Breaking change: IpoptOptions no longer supported to specify solver options, use m = Model(solver=IpoptSolver(options...)) instead.
    • New solver interfaces: ECOS, NLopt, and nonlinear support for MOSEK
    • New option to control whether the lazy constraint callback is executed at each node in the B&B tree or just when feasible solutions are found
    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
    • Add support for index dependencies (for example, triangular indexing) in @defVar, @addConstraint, and @defExpr (for example, @defVar(m, x[i=1:10,j=i:10])).
      • This required some changes to the internal structure of JuMP containers, which may break code that explicitly stored JuMPDict objects.

    Version 0.5.8 (September 24, 2014)

    • Fix a bug with specifying solvers (affects Julia 0.2 only)

    Version 0.5.7 (September 5, 2014)

    • Fix a bug in printing models

    Version 0.5.6 (September 2, 2014)

    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
      • Breaking change: Syntax for Variable() constructor has changed (use of this interface remains discouraged)
    • Update for breaking changes in MathProgBase

    Version 0.5.5 (July 6, 2014)

    • Fix bug with problem modification: adding variables that did not appear in existing constraints or objective.

    Version 0.5.4 (June 19, 2014)

    • Update for breaking change in MathProgBase which reduces loading times for using JuMP
    • Fix error when MIPs not solved to optimality

    Version 0.5.3 (May 21, 2014)

    • Update for breaking change in ReverseDiffSparse

    Version 0.5.2 (May 9, 2014)

    • Fix compatibility with Julia 0.3 prerelease

    Version 0.5.1 (May 5, 2014)

    • Fix a bug in coefficient handling inside lazy constraints and user cuts

    Version 0.5.0 (May 2, 2014)

    • Support for nonlinear optimization with exact, sparse second-order derivatives automatically computed. Ipopt is currently the only solver supported.
    • getValue for AffExpr and QuadExpr
    • Breaking change: getSolverModel replaced by getInternalModel, which returns the internal MathProgBase-level model
    • Groups of constraints can be specified with @addConstraint (see documentation for details). This is not a breaking change.
    • dot(::JuMPDict{Variable},::JuMPDict{Variable}) now returns the corresponding quadratic expression.

    Version 0.4.1 (March 24, 2014)

    • Fix bug where change in objective sense was ignored when re-solving a model.
    • Fix issue with handling zero coefficients in AffExpr.

    Version 0.4.0 (March 10, 2014)

    • Support for SOS1 and SOS2 constraints.
    • Solver-independent callback for user heuristics.
    • dot and sum implemented for JuMPDict objects. Now you can say @addConstraint(m, dot(a,x) <= b).
    • Developers: support for extensions to JuMP. See definition of Model in src/JuMP.jl for more details.
    • Option to construct the low-level model before optimizing.

    Version 0.3.2 (February 17, 2014)

    • Improved model printing
      • Preliminary support for IJulia output

    Version 0.3.1 (January 30, 2014)

    • Documentation updates
    • Support for MOSEK
    • CPLEXLink renamed to CPLEX

    Version 0.3.0 (January 21, 2014)

    • Unbounded/infeasibility rays: getValue() will return the corresponding components of an unbounded ray when a model is unbounded, if supported by the selected solver. getDual() will return an infeasibility ray (Farkas proof) if a model is infeasible and the selected solver supports this feature.
    • Solver-independent callbacks for user generated cuts.
    • Use new interface for solver-independent QCQP.
    • setlazycallback renamed to setLazyCallback for consistency.

    Version 0.2.0 (December 15, 2013)

    Breaking

    • Objective sense is specified in setObjective instead of in the Model constructor.
    • lpsolver and mipsolver merged into single solver option.

    Added

    • Problem modification with efficient LP restarts and MIP warm-starts.
    • Relatedly, column-wise modeling now supported.
    • Solver-independent callbacks supported. Currently we support only a "lazy constraint" callback, which works with Gurobi, CPLEX, and GLPK. More callbacks coming soon.

    Version 0.1.2 (November 16, 2013)

    • Bug fixes for printing, improved error messages.
    • Allow AffExpr to be used in macros; for example, ex = y + z; @addConstraint(m, x + 2*ex <= 3)

    Version 0.1.1 (October 23, 2013)

    • Update for solver specification API changes in MathProgBase.

    Version 0.1.0 (October 3, 2013)

    • Initial public release.
    diff --git a/previews/PR3883/developers/checklists/index.html b/previews/PR3883/developers/checklists/index.html index 8fa7ed112ea..a905c55b075 100644 --- a/previews/PR3883/developers/checklists/index.html +++ b/previews/PR3883/developers/checklists/index.html @@ -69,4 +69,4 @@ - [ ] Implement `vectorize(data, ::NewShape)::Vector` - [ ] Implement `reshape_vector(vector, ::NewShape)` - [ ] Implement `dual_shape`, or verify that the shape is self-dual - - [ ] Add the tests from https://github.com/jump-dev/JuMP.jl/pull/3816 + - [ ] Add the tests from https://github.com/jump-dev/JuMP.jl/pull/3816 diff --git a/previews/PR3883/developers/contributing/index.html b/previews/PR3883/developers/contributing/index.html index 0cd0da5a3eb..5fd778aa6fd 100644 --- a/previews/PR3883/developers/contributing/index.html +++ b/previews/PR3883/developers/contributing/index.html @@ -25,4 +25,4 @@ $ git checkout master -$ git pull
    Note

    If you have suggestions to improve this guide, please make a pull request. It's particularly helpful if you do this after your first pull request because you'll know all the parts that could be explained better.

    +$ git pull
    Note

    If you have suggestions to improve this guide, please make a pull request. It's particularly helpful if you do this after your first pull request because you'll know all the parts that could be explained better.

    diff --git a/previews/PR3883/developers/custom_solver_binaries/index.html b/previews/PR3883/developers/custom_solver_binaries/index.html index ba43aef3aab..6f811f01fa2 100644 --- a/previews/PR3883/developers/custom_solver_binaries/index.html +++ b/previews/PR3883/developers/custom_solver_binaries/index.html @@ -90,4 +90,4 @@ libCbc_path = "/usr/local/Cellar/cbc/2.10.5/lib/libCbc.3.10.5" libOsiCbc_path = "/usr/local/Cellar/cbc/2.10.5/lib/libOsiCbc.3.10.5" libcbcsolver_path = "/usr/local/Cellar/cbc/2.10.5/lib/libCbcSolver.3.10.5"
    Info

    Note that capitalization matters, so libcbcsolver_path corresponds to libCbcSolver.3.10.5.

    Override entire artifact

    To use the homebrew install as our custom binary we add the following to ~/.julia/artifacts/Overrides.toml:

    # Override for Cbc_jll
    -e481bc81db5e229ba1f52b2b4bd57484204b1b06 = "/usr/local/Cellar/cbc/2.10.5"
    +e481bc81db5e229ba1f52b2b4bd57484204b1b06 = "/usr/local/Cellar/cbc/2.10.5" diff --git a/previews/PR3883/developers/extensions/index.html b/previews/PR3883/developers/extensions/index.html index c7c2c2e717c..ad5558d235d 100644 --- a/previews/PR3883/developers/extensions/index.html +++ b/previews/PR3883/developers/extensions/index.html @@ -310,4 +310,4 @@ _function_barrier(names, model, F, S) end return names -end
    Note

    It is important to explicitly type the F and S arguments. If you leave them untyped, for example, function _function_barrier(names, model, F, S), Julia will not specialize the function calls and performance will not be improved.

    +end
    Note

    It is important to explicitly type the F and S arguments. If you leave them untyped, for example, function _function_barrier(names, model, F, S), Julia will not specialize the function calls and performance will not be improved.

    diff --git a/previews/PR3883/developers/roadmap/index.html b/previews/PR3883/developers/roadmap/index.html index b463e97ed1d..fae1aa09c2c 100644 --- a/previews/PR3883/developers/roadmap/index.html +++ b/previews/PR3883/developers/roadmap/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Development roadmap

    The JuMP developers have compiled this roadmap document to share their plans and goals with the JuMP community. Contributions to roadmap issues are especially invited.

    Most of these issues will require changes to both JuMP and MathOptInterface, and are non-trivial in their implementation. They are in no particular order, but represent broad themes that we see as areas in which JuMP could be improved.

    • Support nonlinear expressions with vector-valued inputs and outputs. There are a few related components:
      • Representing terms like log(det(X)) as necessary for Convex.jl
      • Automatic differentiation of terms with vector inputs and outputs
      • User-defined functions with vector–as opposed to scalar–inputs, which is particularly useful for optimal control problems
      • User-defined functions with vector outputs, avoiding the need for User-defined operators with vector outputs
    • Add support for modeling with SI units. The UnitJuMP.jl extension is a good proof of concept for what this would look like. We want to make units a first-class concept in JuMP. See #1350 for more details.

    Completed

    +

    Development roadmap

    The JuMP developers have compiled this roadmap document to share their plans and goals with the JuMP community. Contributions to roadmap issues are especially invited.

    Most of these issues will require changes to both JuMP and MathOptInterface, and are non-trivial in their implementation. They are in no particular order, but represent broad themes that we see as areas in which JuMP could be improved.

    • Support nonlinear expressions with vector-valued inputs and outputs. There are a few related components:
      • Representing terms like log(det(X)) as necessary for Convex.jl
      • Automatic differentiation of terms with vector inputs and outputs
      • User-defined functions with vector–as opposed to scalar–inputs, which is particularly useful for optimal control problems
      • User-defined functions with vector outputs, avoiding the need for User-defined operators with vector outputs
    • Add support for modeling with SI units. The UnitJuMP.jl extension is a good proof of concept for what this would look like. We want to make units a first-class concept in JuMP. See #1350 for more details.

    Completed

    diff --git a/previews/PR3883/developers/style/index.html b/previews/PR3883/developers/style/index.html index ca4c6af9b1d..56ce4f838a1 100644 --- a/previews/PR3883/developers/style/index.html +++ b/previews/PR3883/developers/style/index.html @@ -182,4 +182,4 @@ end # module TestPkg -TestPkg.runtests()

    Break the tests into multiple files, with one module per file, so that subsets of the codebase can be tested by calling include with the relevant file.

    +TestPkg.runtests()

    Break the tests into multiple files, with one module per file, so that subsets of the codebase can be tested by calling include with the relevant file.

    diff --git a/previews/PR3883/extensions/DimensionalData/index.html b/previews/PR3883/extensions/DimensionalData/index.html index e3b97a5af82..6be5993d000 100644 --- a/previews/PR3883/extensions/DimensionalData/index.html +++ b/previews/PR3883/extensions/DimensionalData/index.html @@ -48,4 +48,4 @@ ↓ j Categorical{String} ["a", "b"] ForwardOrdered └──────────────────────────────────────────────────────────────────────────────┘ "a" x[2,a] + x[3,a] + x[4,a] ≤ 1 - "b" x[2,b] + x[3,b] + x[4,b] ≤ 1

    Documentation

    See the DimensionalData.jl documentation for more details on the syntax and features of DimensionalData.DimArray.

    + "b" x[2,b] + x[3,b] + x[4,b] ≤ 1

    Documentation

    See the DimensionalData.jl documentation for more details on the syntax and features of DimensionalData.DimArray.

    diff --git a/previews/PR3883/extensions/introduction/index.html b/previews/PR3883/extensions/introduction/index.html index f7fe0153401..41a979cde85 100644 --- a/previews/PR3883/extensions/introduction/index.html +++ b/previews/PR3883/extensions/introduction/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Introduction

    This section of the documentation contains brief documentation for some popular JuMP extensions. The list of extensions is not exhaustive, but instead is intended to help you discover popular JuMP extensions, and to give you an overview of the types of extensions that are possible to write with JuMP.

    Affiliation

    Packages beginning with jump-dev/ are developed and maintained by the JuMP developers.

    Packages that do not begin with jump-dev/ are developed independently. The developers of these packages requested or consented to the inclusion of their README contents in the JuMP documentation for the benefit of users.

    Adding new extensions

    Written an extension? Add it to this section of the JuMP documentation by making a pull request to the docs/packages.toml file.

    Weak dependencies

    Some extensions listed in this section are implemented using the weak dependency feature added to Julia in v1.9. These extensions are activated if and only if you have JuMP and the other package loaded into your current scope with using or import.

    Compat

    Using a weak dependency requires Julia v1.9 or later.

    +

    Introduction

    This section of the documentation contains brief documentation for some popular JuMP extensions. The list of extensions is not exhaustive, but instead is intended to help you discover popular JuMP extensions, and to give you an overview of the types of extensions that are possible to write with JuMP.

    Affiliation

    Packages beginning with jump-dev/ are developed and maintained by the JuMP developers.

    Packages that do not begin with jump-dev/ are developed independently. The developers of these packages requested or consented to the inclusion of their README contents in the JuMP documentation for the benefit of users.

    Adding new extensions

    Written an extension? Add it to this section of the JuMP documentation by making a pull request to the docs/packages.toml file.

    Weak dependencies

    Some extensions listed in this section are implemented using the weak dependency feature added to Julia in v1.9. These extensions are activated if and only if you have JuMP and the other package loaded into your current scope with using or import.

    Compat

    Using a weak dependency requires Julia v1.9 or later.

    diff --git a/previews/PR3883/index.html b/previews/PR3883/index.html index 970db99d8ea..74e28664ce8 100644 --- a/previews/PR3883/index.html +++ b/previews/PR3883/index.html @@ -32,4 +32,4 @@ journal = {Mathematical Programming Computation}, year = {2023}, doi = {10.1007/s12532-023-00239-3} -}

    NumFOCUS

    NumFOCUS logo

    JuMP is a Sponsored Project of NumFOCUS, a 501(c)(3) nonprofit charity in the United States. NumFOCUS provides JuMP with fiscal, legal, and administrative support to help ensure the health and sustainability of the project. Visit numfocus.org for more information.

    You can support JuMP by donating.

    Donations to JuMP are managed by NumFOCUS. For donors in the United States, your gift is tax-deductible to the extent provided by law. As with any donation, you should consult with your tax adviser about your particular tax situation.

    JuMP's largest expense is the annual JuMP-dev workshop. Donations will help us provide travel support for JuMP-dev attendees and take advantage of other opportunities that arise to support JuMP development.

    License

    JuMP is licensed under the MPL-2.0 software license. Consult the license and the Mozilla FAQ for more information. In addition, JuMP is typically used in conjunction with solver packages and extensions which have their own licences. Consult their package repositories for the specific licenses that apply.

    +}

    NumFOCUS

    NumFOCUS logo

    JuMP is a Sponsored Project of NumFOCUS, a 501(c)(3) nonprofit charity in the United States. NumFOCUS provides JuMP with fiscal, legal, and administrative support to help ensure the health and sustainability of the project. Visit numfocus.org for more information.

    You can support JuMP by donating.

    Donations to JuMP are managed by NumFOCUS. For donors in the United States, your gift is tax-deductible to the extent provided by law. As with any donation, you should consult with your tax adviser about your particular tax situation.

    JuMP's largest expense is the annual JuMP-dev workshop. Donations will help us provide travel support for JuMP-dev attendees and take advantage of other opportunities that arise to support JuMP development.

    License

    JuMP is licensed under the MPL-2.0 software license. Consult the license and the Mozilla FAQ for more information. In addition, JuMP is typically used in conjunction with solver packages and extensions which have their own licences. Consult their package repositories for the specific licenses that apply.

    diff --git a/previews/PR3883/installation/index.html b/previews/PR3883/installation/index.html index d0a4fa41819..9f320a7b7c7 100644 --- a/previews/PR3883/installation/index.html +++ b/previews/PR3883/installation/index.html @@ -28,4 +28,4 @@ [4076af6c] ↓ JuMP v0.21.5 ⇒ v0.18.6 [707a9f91] + JuMPeR v0.6.0 Updating `~/jump_example/Manifest.toml` - ... lines omitted ...

    JuMPeR gets added at version 0.6.0 (+ JuMPeR v0.6.0), but JuMP gets downgraded from 0.21.5 to 0.18.6 (↓ JuMP v0.21.5 ⇒ v0.18.6)! The reason for this is that JuMPeR doesn't support a version of JuMP newer than 0.18.6.

    Tip

    Pay careful attention to the output of the package manager when adding new packages, especially when you see a package being downgraded.

    + ... lines omitted ...

    JuMPeR gets added at version 0.6.0 (+ JuMPeR v0.6.0), but JuMP gets downgraded from 0.21.5 to 0.18.6 (↓ JuMP v0.21.5 ⇒ v0.18.6)! The reason for this is that JuMPeR doesn't support a version of JuMP newer than 0.18.6.

    Tip

    Pay careful attention to the output of the package manager when adding new packages, especially when you see a package being downgraded.

    diff --git a/previews/PR3883/manual/callbacks/index.html b/previews/PR3883/manual/callbacks/index.html index 5f911aa2571..02f649d0f82 100644 --- a/previews/PR3883/manual/callbacks/index.html +++ b/previews/PR3883/manual/callbacks/index.html @@ -84,4 +84,4 @@ end my_callback_function (generic function with 1 method) -julia> set_attribute(model, MOI.HeuristicCallback(), my_callback_function)

    The third argument to submit is a vector of JuMP variables, and the fourth argument is a vector of values corresponding to each variable.

    MOI.submit returns an enum that depends on whether the solver accepted the solution. The possible return codes are:

    • MOI.HEURISTIC_SOLUTION_ACCEPTED
    • MOI.HEURISTIC_SOLUTION_REJECTED
    • MOI.HEURISTIC_SOLUTION_UNKNOWN
    Warning

    Some solvers may accept partial solutions. Others require a feasible integer solution for every variable. If in doubt, provide a complete solution.

    Info

    The heuristic solution callback may be called at fractional nodes in the branch-and-bound tree. There is no guarantee that the callback is called at every fractional primal solution.

    +julia> set_attribute(model, MOI.HeuristicCallback(), my_callback_function)

    The third argument to submit is a vector of JuMP variables, and the fourth argument is a vector of values corresponding to each variable.

    MOI.submit returns an enum that depends on whether the solver accepted the solution. The possible return codes are:

    • MOI.HEURISTIC_SOLUTION_ACCEPTED
    • MOI.HEURISTIC_SOLUTION_REJECTED
    • MOI.HEURISTIC_SOLUTION_UNKNOWN
    Warning

    Some solvers may accept partial solutions. Others require a feasible integer solution for every variable. If in doubt, provide a complete solution.

    Info

    The heuristic solution callback may be called at fractional nodes in the branch-and-bound tree. There is no guarantee that the callback is called at every fractional primal solution.

    diff --git a/previews/PR3883/manual/complex/index.html b/previews/PR3883/manual/complex/index.html index 068c5e747af..1253839a083 100644 --- a/previews/PR3883/manual/complex/index.html +++ b/previews/PR3883/manual/complex/index.html @@ -197,4 +197,4 @@ julia> @constraint(model, H in HermitianPSDCone()) [x[1] im - -im -x[2]] ∈ HermitianPSDCone()
    Note

    The matrix H in H in HermitianPSDCone() must be a LinearAlgebra.Hermitian matrix type. A build_constraint error will be thrown if the matrix is a different matrix type.

    + -im -x[2]] ∈ HermitianPSDCone()
    Note

    The matrix H in H in HermitianPSDCone() must be a LinearAlgebra.Hermitian matrix type. A build_constraint error will be thrown if the matrix is a different matrix type.

    diff --git a/previews/PR3883/manual/constraints/index.html b/previews/PR3883/manual/constraints/index.html index 68e2947d040..4a4310e9fc8 100644 --- a/previews/PR3883/manual/constraints/index.html +++ b/previews/PR3883/manual/constraints/index.html @@ -801,4 +801,4 @@ (x[1] == x[2]) - 0.0 = 0 julia> @constraint(model, x[1] == x[2] := rhs) -x[1] == x[2] = false +x[1] == x[2] = false diff --git a/previews/PR3883/manual/containers/index.html b/previews/PR3883/manual/containers/index.html index 29ca7433f1a..3927893698f 100644 --- a/previews/PR3883/manual/containers/index.html +++ b/previews/PR3883/manual/containers/index.html @@ -232,4 +232,4 @@ julia> Containers.@container([i = 1:2, j = 1:4; condition(i, j)], i + j) JuMP.Containers.SparseAxisArray{Int64, 2, Tuple{Int64, Int64}} with 2 entries: [1, 2] = 3 - [1, 4] = 5 + [1, 4] = 5 diff --git a/previews/PR3883/manual/expressions/index.html b/previews/PR3883/manual/expressions/index.html index 42b17518dc3..54f9d5076cc 100644 --- a/previews/PR3883/manual/expressions/index.html +++ b/previews/PR3883/manual/expressions/index.html @@ -247,4 +247,4 @@ julia> x 2-element Vector{AffExpr}: 1.1 - 0

    Note that for large expressions this will be slower due to the allocation of additional temporary objects.

    + 0

    Note that for large expressions this will be slower due to the allocation of additional temporary objects.

    diff --git a/previews/PR3883/manual/models/index.html b/previews/PR3883/manual/models/index.html index 61e64155818..48befa46cbf 100644 --- a/previews/PR3883/manual/models/index.html +++ b/previews/PR3883/manual/models/index.html @@ -313,4 +313,4 @@ If you expected the solver to support your problem, you may have an error in your formulation. Otherwise, consider using a different solver. The list of available solvers, along with the problem types they support, is available at https://jump.dev/JuMP.jl/stable/installation/#Supported-solvers. -Stacktrace:
    Warning

    Another downside of direct mode is that the behavior of querying solution information after modifying the problem is solver-specific. This can lead to errors, or the solver silently returning an incorrect value. See OptimizeNotCalled errors for more information.

    +Stacktrace:
    Warning

    Another downside of direct mode is that the behavior of querying solution information after modifying the problem is solver-specific. This can lead to errors, or the solver silently returning an incorrect value. See OptimizeNotCalled errors for more information.

    diff --git a/previews/PR3883/manual/nlp/index.html b/previews/PR3883/manual/nlp/index.html index 799474651db..7e1befd861f 100644 --- a/previews/PR3883/manual/nlp/index.html +++ b/previews/PR3883/manual/nlp/index.html @@ -344,4 +344,4 @@ f1(x[1]) - 1.0 ≤ 0 f2(x[1], x[2]) - 1.0 ≤ 0 f3(x[2], x[3], x[4]) - 1.0 ≤ 0 - f4(x[1], x[3], x[4], x[5]) - 1.0 ≤ 0

    Known performance issues

    The macro-based input to JuMP's nonlinear interface can cause a performance issue if you:

    1. write a macro with a large number (hundreds) of terms
    2. call that macro from within a function instead of from the top-level in global scope.

    The first issue does not depend on the number of resulting terms in the mathematical expression, but rather the number of terms in the Julia Expr representation of that expression. For example, the expression sum(x[i] for i in 1:1_000_000) contains one million mathematical terms, but the Expr representation is just a single sum.

    The most common cause, other than a lot of tedious typing, is if you write a program that automatically writes a JuMP model as a text file, which you later execute. One example is MINLPlib.jl which automatically transpiled models in the GAMS scalar format into JuMP examples.

    As a rule of thumb, if you are writing programs to automatically generate expressions for the JuMP macros, you should target the Raw expression input instead. For more information, read MathOptInterface Issue#1997.

    + f4(x[1], x[3], x[4], x[5]) - 1.0 ≤ 0

    Known performance issues

    The macro-based input to JuMP's nonlinear interface can cause a performance issue if you:

    1. write a macro with a large number (hundreds) of terms
    2. call that macro from within a function instead of from the top-level in global scope.

    The first issue does not depend on the number of resulting terms in the mathematical expression, but rather the number of terms in the Julia Expr representation of that expression. For example, the expression sum(x[i] for i in 1:1_000_000) contains one million mathematical terms, but the Expr representation is just a single sum.

    The most common cause, other than a lot of tedious typing, is if you write a program that automatically writes a JuMP model as a text file, which you later execute. One example is MINLPlib.jl which automatically transpiled models in the GAMS scalar format into JuMP examples.

    As a rule of thumb, if you are writing programs to automatically generate expressions for the JuMP macros, you should target the Raw expression input instead. For more information, read MathOptInterface Issue#1997.

    diff --git a/previews/PR3883/manual/nonlinear/index.html b/previews/PR3883/manual/nonlinear/index.html index 39d1412fbcc..31199b509df 100644 --- a/previews/PR3883/manual/nonlinear/index.html +++ b/previews/PR3883/manual/nonlinear/index.html @@ -319,4 +319,4 @@ julia> ForwardDiff.gradient(x -> my_operator_good(x...), [1.0, 2.0]) 2-element Vector{Float64}: 2.0 - 4.0 + 4.0 diff --git a/previews/PR3883/manual/objective/index.html b/previews/PR3883/manual/objective/index.html index 1bb783786dd..edefa1e5b96 100644 --- a/previews/PR3883/manual/objective/index.html +++ b/previews/PR3883/manual/objective/index.html @@ -179,4 +179,4 @@ 2 x[1] julia> @constraint(model, obj3 <= 2.0) -x[1] + x[2] ≤ 2 +x[1] + x[2] ≤ 2 diff --git a/previews/PR3883/manual/solutions/index.html b/previews/PR3883/manual/solutions/index.html index 05b04dce868..ad4fb144b45 100644 --- a/previews/PR3883/manual/solutions/index.html +++ b/previews/PR3883/manual/solutions/index.html @@ -429,4 +429,4 @@ x integer => 0.1

    You can also use the functional form, where the first argument is a function that maps variables to their primal values:

    julia> optimize!(model)
     
     julia> primal_feasibility_report(v -> value(v), model)
    -Dict{Any, Float64}()
    +Dict{Any, Float64}() diff --git a/previews/PR3883/manual/variables/index.html b/previews/PR3883/manual/variables/index.html index 5c7a04f45da..2cab49e9a52 100644 --- a/previews/PR3883/manual/variables/index.html +++ b/previews/PR3883/manual/variables/index.html @@ -639,4 +639,4 @@ p*x julia> typeof(px) -QuadExpr (alias for GenericQuadExpr{Float64, GenericVariableRef{Float64}})

    When to use a parameter

    Parameters are most useful when solving nonlinear models in a sequence:

    julia> using JuMP, Ipopt
    julia> model = Model(Ipopt.Optimizer);
    julia> set_silent(model)
    julia> @variable(model, x)x
    julia> @variable(model, p in Parameter(1.0))p
    julia> @objective(model, Min, (x - p)^2)x² - 2 p*x + p²
    julia> optimize!(model)
    julia> value(x)1.0
    julia> set_parameter_value(p, 5.0)
    julia> optimize!(model)
    julia> value(x)5.0

    Using parameters can be faster than creating a new model from scratch with updated data because JuMP is able to avoid repeating a number of steps in processing the model before handing it off to the solver.

    +QuadExpr (alias for GenericQuadExpr{Float64, GenericVariableRef{Float64}})

    When to use a parameter

    Parameters are most useful when solving nonlinear models in a sequence:

    julia> using JuMP, Ipopt
    julia> model = Model(Ipopt.Optimizer);
    julia> set_silent(model)
    julia> @variable(model, x)x
    julia> @variable(model, p in Parameter(1.0))p
    julia> @objective(model, Min, (x - p)^2)x² - 2 p*x + p²
    julia> optimize!(model)
    julia> value(x)1.0
    julia> set_parameter_value(p, 5.0)
    julia> optimize!(model)
    julia> value(x)5.0

    Using parameters can be faster than creating a new model from scratch with updated data because JuMP is able to avoid repeating a number of steps in processing the model before handing it off to the solver.

    diff --git a/previews/PR3883/moi/background/duality/index.html b/previews/PR3883/moi/background/duality/index.html index b87a508e3ea..8a7759a358b 100644 --- a/previews/PR3883/moi/background/duality/index.html +++ b/previews/PR3883/moi/background/duality/index.html @@ -81,4 +81,4 @@ \max & \sum b_k y_k \\ \text{s.t.} \;\; & C+C^\top - \sum (A_k+A_k^\top) y_k \in \mathcal{S}_+ \\ & C-C^\top - \sum(A_k-A_k^\top) y_k = 0 -\end{align}\]

    and we recover $Z = X + X^\top$.

    +\end{align}\]

    and we recover $Z = X + X^\top$.

    diff --git a/previews/PR3883/moi/background/infeasibility_certificates/index.html b/previews/PR3883/moi/background/infeasibility_certificates/index.html index 85652e868c4..4cd70000140 100644 --- a/previews/PR3883/moi/background/infeasibility_certificates/index.html +++ b/previews/PR3883/moi/background/infeasibility_certificates/index.html @@ -29,4 +29,4 @@ \end{align}\]

    and:

    \[-\sum_{i=1}^m b_i^\top (y_i + \eta d_i) > -\sum_{i=1}^m b_i^\top y_i,\]

    for any feasible dual solution $y$. The latter simplifies to $-\sum_{i=1}^m b_i^\top d_i > 0$. For a maximization problem, the inequality is $\sum_{i=1}^m b_i^\top d_i < 0$. (Note that these are the same inequality, modulo a - sign.)

    If the solver has found a certificate of primal infeasibility:

    Note

    The choice of whether to scale the ray $d$ to have magnitude 1 is left to the solver.

    Infeasibility certificates of variable bounds

    Many linear solvers (for example, Gurobi) do not provide explicit access to the primal infeasibility certificate of a variable bound. However, given a set of linear constraints:

    \[\begin{align} l_A \le A x \le u_A \\ l_x \le x \le u_x, -\end{align}\]

    the primal certificate of the variable bounds can be computed using the primal certificate associated with the affine constraints, $d$. (Note that $d$ will have one element for each row of the $A$ matrix, and that some or all of the elements in the vectors $l_A$ and $u_A$ may be $\pm \infty$. If both $l_A$ and $u_A$ are finite for some row, the corresponding element in `d must be 0.)

    Given $d$, compute $\bar{d} = d^\top A$. If the bound is finite, a certificate for the lower variable bound of $x_i$ is $\max\{\bar{d}_i, 0\}$, and a certificate for the upper variable bound is $\min\{\bar{d}_i, 0\}$.

    +\end{align}\]

    the primal certificate of the variable bounds can be computed using the primal certificate associated with the affine constraints, $d$. (Note that $d$ will have one element for each row of the $A$ matrix, and that some or all of the elements in the vectors $l_A$ and $u_A$ may be $\pm \infty$. If both $l_A$ and $u_A$ are finite for some row, the corresponding element in `d must be 0.)

    Given $d$, compute $\bar{d} = d^\top A$. If the bound is finite, a certificate for the lower variable bound of $x_i$ is $\max\{\bar{d}_i, 0\}$, and a certificate for the upper variable bound is $\min\{\bar{d}_i, 0\}$.

    diff --git a/previews/PR3883/moi/background/motivation/index.html b/previews/PR3883/moi/background/motivation/index.html index c21043ed3d0..371676e0dc0 100644 --- a/previews/PR3883/moi/background/motivation/index.html +++ b/previews/PR3883/moi/background/motivation/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Motivation

    MathOptInterface (MOI) is a replacement for MathProgBase, the first-generation abstraction layer for mathematical optimization previously used by JuMP and Convex.jl.

    To address a number of limitations of MathProgBase, MOI is designed to:

    • Be simple and extensible
      • unifying linear, quadratic, and conic optimization,
      • seamlessly facilitating extensions to essentially arbitrary constraints and functions (for example, indicator constraints, complementarity constraints, and piecewise-linear functions)
    • Be fast
      • by allowing access to a solver's in-memory representation of a problem without writing intermediate files (when possible)
      • by using multiple dispatch and avoiding requiring containers of non-concrete types
    • Allow a solver to return multiple results (for example, a pool of solutions)
    • Allow a solver to return extra arbitrary information via attributes (for example, variable- and constraint-wise membership in an irreducible inconsistent subset for infeasibility analysis)
    • Provide a greatly expanded set of status codes explaining what happened during the optimization procedure
    • Enable a solver to more precisely specify which problem classes it supports
    • Enable both primal and dual warm starts
    • Enable adding and removing both variables and constraints by indices that are not required to be consecutive
    • Enable any modification that the solver supports to an existing model
    • Avoid requiring the solver wrapper to store an additional copy of the problem data
    +

    Motivation

    MathOptInterface (MOI) is a replacement for MathProgBase, the first-generation abstraction layer for mathematical optimization previously used by JuMP and Convex.jl.

    To address a number of limitations of MathProgBase, MOI is designed to:

    • Be simple and extensible
      • unifying linear, quadratic, and conic optimization,
      • seamlessly facilitating extensions to essentially arbitrary constraints and functions (for example, indicator constraints, complementarity constraints, and piecewise-linear functions)
    • Be fast
      • by allowing access to a solver's in-memory representation of a problem without writing intermediate files (when possible)
      • by using multiple dispatch and avoiding requiring containers of non-concrete types
    • Allow a solver to return multiple results (for example, a pool of solutions)
    • Allow a solver to return extra arbitrary information via attributes (for example, variable- and constraint-wise membership in an irreducible inconsistent subset for infeasibility analysis)
    • Provide a greatly expanded set of status codes explaining what happened during the optimization procedure
    • Enable a solver to more precisely specify which problem classes it supports
    • Enable both primal and dual warm starts
    • Enable adding and removing both variables and constraints by indices that are not required to be consecutive
    • Enable any modification that the solver supports to an existing model
    • Avoid requiring the solver wrapper to store an additional copy of the problem data
    diff --git a/previews/PR3883/moi/background/naming_conventions/index.html b/previews/PR3883/moi/background/naming_conventions/index.html index 3d941b2a777..63b03d44188 100644 --- a/previews/PR3883/moi/background/naming_conventions/index.html +++ b/previews/PR3883/moi/background/naming_conventions/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Naming conventions

    MOI follows several conventions for naming functions and structures. These should also be followed by packages extending MOI.

    Sets

    Sets encode the structure of constraints. Their names should follow the following conventions:

    • Abstract types in the set hierarchy should begin with Abstract and end in Set, for example, AbstractScalarSet, AbstractVectorSet.
    • Vector-valued conic sets should end with Cone, for example, NormInfinityCone, SecondOrderCone.
    • Vector-valued Cartesian products should be plural and not end in Cone, for example, Nonnegatives, not NonnegativeCone.
    • Matrix-valued conic sets should provide two representations: ConeSquare and ConeTriangle, for example, RootDetConeTriangle and RootDetConeSquare. See Matrix cones for more details.
    • Scalar sets should be singular, not plural, for example, Integer, not Integers.
    • As much as possible, the names should follow established conventions in the domain where this set is used: for instance, convex sets should have names close to those of CVX, and constraint-programming sets should follow MiniZinc's constraints.
    +

    Naming conventions

    MOI follows several conventions for naming functions and structures. These should also be followed by packages extending MOI.

    Sets

    Sets encode the structure of constraints. Their names should follow the following conventions:

    • Abstract types in the set hierarchy should begin with Abstract and end in Set, for example, AbstractScalarSet, AbstractVectorSet.
    • Vector-valued conic sets should end with Cone, for example, NormInfinityCone, SecondOrderCone.
    • Vector-valued Cartesian products should be plural and not end in Cone, for example, Nonnegatives, not NonnegativeCone.
    • Matrix-valued conic sets should provide two representations: ConeSquare and ConeTriangle, for example, RootDetConeTriangle and RootDetConeSquare. See Matrix cones for more details.
    • Scalar sets should be singular, not plural, for example, Integer, not Integers.
    • As much as possible, the names should follow established conventions in the domain where this set is used: for instance, convex sets should have names close to those of CVX, and constraint-programming sets should follow MiniZinc's constraints.
    diff --git a/previews/PR3883/moi/changelog/index.html b/previews/PR3883/moi/changelog/index.html index 5355372249d..20668328584 100644 --- a/previews/PR3883/moi/changelog/index.html +++ b/previews/PR3883/moi/changelog/index.html @@ -31,4 +31,4 @@ end write(path, s) end -end

    v0.9.22 (May 22, 2021)

    This release contains backports from the ongoing development of the v0.10 release.

    • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
    • Improved performance of Utilities.is_canonical.
    • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
    • Fixed performance regression of Utilities.Model.
    • Fixed ordering of objective setting in parser.

    v0.9.21 (April 23, 2021)

    • Added supports_shift_constant.
    • Improve performance of bridging quadratic constraints.
    • Add precompilation statements.
    • Large improvements to the documentation.
    • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
    • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
    • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

    v0.9.20 (February 20, 2021)

    • Improved performance of Utilities.ScalarFunctionIterator
    • Added support for compute_conflict to MOI layers
    • Added test with zero off-diagonal quadratic term in objective
    • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
    • Fixed modification of un-set objective
    • Fixed function modification with duplicate terms
    • Made unit tests abort without failing if the problem class is not supported
    • Formatted code with JuliaFormatter
    • Clarified BasisStatusCode's docstring

    v0.9.19 (December 1, 2020)

    • Added CallbackNodeStatus attribute
    • Added bridge from GreaterThan or LessThan to Interval
    • Added tests for infeasibility certificates and double optimize
    • Fixed support for Julia v1.6
    • Re-organized MOI docs and added documentation for adding a test

    v0.9.18 (November 3, 2020)

    • Various improvements for working with complex numbers
    • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

    v0.9.17 (September 21, 2020)

    • Fixed CleverDict with variable of negative index value
    • Implement supports_add_constrained_variable for MockOptimizer

    v0.9.16 (September 17, 2020)

    • Various fixes:
      • 32-bit support
      • CleverDict with abstract value type
      • Checks in test suite

    v0.9.15 (September 14, 2020)

    • Bridges improvements:
      • (R)SOCtoNonConvexQuad bridge
      • ZeroOne bridge
      • Use supports_add_constrained_variable in LazyBridgeOptimizer
      • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
      • Prioritize constraining variables on creation according to these costs
      • Refactor bridge debugging
    • Large performance improvements across all submodules
    • Lots of documentation improvements
    • FileFormats improvements:
      • Update MathOptFormat to v0.5
      • Fix supported objectives in FileFormats
    • Testing improvements:
      • Add name option for basic_constraint_test
    • Bug fixes and missing methods
      • Add length for iterators
      • Fix bug with duplicate terms
      • Fix order of LinearOfConstraintIndices

    v0.9.14 (May 30, 2020)

    • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
    • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
    • Documentation improvements:
      • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
      • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
    • Utilities improvements:
      • Fix is_canonical for quadratic functions (#1081, #1089).
      • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
      • Add support for custom objective functions for UniversalFallback (#1086).
      • Deterministic ordering of constraints in UniversalFallback (#1088).
    • Testing improvements:
      • Add NormOneCone/NormInfinityCone tests (#1045).
    • Bridges improvements:
      • Add bridges from Semiinteger and Semicontinuous (#1059).
      • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
      • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
      • Fix NormOne/NormInf bridges with nonzero constants (#1045).
      • Fix StackOverflow in debug (#1063).
    • FileFormats improvements:
      • [SDPA] Implement the extension for integer variables (#1079).
      • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
      • [SDPA] No scaling of off-diagonal coefficient (#1076).
      • [SDPA] Add missing negation of constant (#1075).

    v0.9.13 (March 24, 2020)

    • Added tests for Semicontinuous and Semiinteger variables (#1033).
    • Added tests for using ExprGraphs from NLP evaluators (#1043).
    • Update version compatibilities of dependencies (#1034, #1051, #1052).
    • Fixed typos in documentation (#1044).

    v0.9.12 (February 28, 2020)

    • Fixed writing NLPBlock in MathOptFormat (#1037).
    • Fixed MockOptimizer for result attributes with non-one result index (#1039).
    • Updated test template with instantiate (#1032).

    v0.9.11 (February 21, 2020)

    • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
    • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
    • Fixed typos in documentation (#1022, #1024).
    • Fixed warning of unsupported attribute (#1027).
    • Added more rootdet/logdet conic tests (#1026).
    • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

    v0.9.10 (January 31, 2020)

    • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
    • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
    • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
    • Added supports_constrained_variable(s) (#1004).
    • Added dual_set_type (#1002).
    • Added tests for vector specialized version of delete (#989, #1011).
    • Added PSD3 test (#1007).
    • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
    • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
    • Fixed Utilities.vectorize for empty vector (#1003).
    • Fixed free variables in LP writer (#1006).

    v0.9.9 (December 29, 2019)

    • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
    • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
    • Updated to MutableArithmetics v0.2 (#981).
    • Added MutableArithmetics.promote_operation allocation tests (#975).
    • Fixed inference issue on Julia v1.1 (#982).

    v0.9.8 (December 19, 2019)

    • Implemented MutableArithmetics API (#924).
    • Fixed callbacks with CachingOptimizer (#959).
    • Fixed MOI.dimension for MOI.Complements (#948).
    • Added fallback for add_variables (#972).
    • Added is_diagonal_vectorized_index utility (#965).
    • Improved linear constraints display in manual (#963, #964).
    • Bridges improvements:
      • Added IndicatorSet to SOS1 bridge (#877).
      • Added support for starting values for Variable.VectorizeBridge (#944).
      • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
      • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
      • Fixed choice between variable or constraint bridges for constrained variables (#973).
      • Improve performance of bridge shortest path (#945, #946, #956).
      • Added docstring for test_delete_bridge (#954).
      • Added Variable bridge tests (#952).

    v0.9.7 (October 30, 2019)

    • Implemented _result_index_field for NLPBlockDual (#934).
    • Fixed copy of model with starting values for vector constraints (#941).
    • Bridges improvements:
      • Improved performance of add_bridge and added has_bridge (#935).
      • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
      • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

    v0.9.6 (October 25, 2019)

    • Added complementarity constraints (#913).
    • Allowed ModelLike objects as value of attributes (#928).
    • Testing improvements:
      • Added dual_objective_value option to MOI.Test.TestConfig (#922).
      • Added InvalidIndex tests in basic_constraint_tests (#921).
      • Added tests for the constant term in indicator constraint (#929).
    • Bridges improvements:
      • Added support for starting values for Functionize bridges (#923).
      • Added variable indices context to variable bridges (#920).
      • Fixed a typo in printing o debug_supports (#927).

    v0.9.5 (October 9, 2019)

    • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
    • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
    • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
    • Bridges improvements:
      • Added debug utilities for unsupported variable/constraint/objective (#861).
      • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
      • Fixed result_index with objective bridges (#911).

    v0.9.4 (October 2, 2019)

    • Added solver-independent MIP callbacks (#782).
    • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
    • Added tests for result count of solution attributes (#901, #904).
    • Added NumberOfThreads attribute (#892).
    • Added Utilities.get_bounds to get the bounds on a variable (#890).
    • Added a note on duplicate coefficients in documentation (#581).
    • Added result index in ConstraintBasisStatus (#898).
    • Added extension dictionary to Utilities.Model (#884, #895).
    • Fixed deletion of constrained variables for CachingOptimizer (#905).
    • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
    • Bridges improvements:
      • Added Variable.RSOCtoSOCBridge (#907).
      • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

    v0.9.3 (September 20, 2019)

    • Fixed ambiguity detected in Julia v1.3 (#891, #893).
    • Fixed missing sets from ListOfSupportedConstraints (#880).
    • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
    • Added extension dictionary to MOIU.Model (#884).
    • Implemented MOI.get for function and set for GeoMeanBridge (#888).
    • Updated documentation for SingleVariable indices and bridges (#885).
    • Testing improvements:
      • Added more comprehensive tests for names (#882).
      • Added tests for SingleVariable duals (#883).
      • Added tests for DualExponentialCone and DualPowerCone (#873).
    • Improvements for arbitrary coefficient type:
      • Fixed == for sets with mutable fields (#887).
      • Removed some Float64 assumptions in bridges (#878).
      • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

    v0.9.2 (September 5, 2019)

    • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
    • Generalized contlinear tests for arbitrary coefficient type (#855).
    • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
    • Fixed Allocate-Load copy for single variable constraints (#856).
    • Bridges improvements:
      • Add objective bridges (#789).
      • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
      • Added Variable.SOCtoRSOCBridge (#865).
      • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
      • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

    v0.9.1 (August 22, 2019)

    • Fix support for Julia v1.2 (#834).
    • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
    • Added tests to MOI.Test.nametest (#833).
    • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
    • Implements operate for operators * and / between vector function and constant (#837).
    • Implements show for MOI.Utilities.IndexMap (#847).
    • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
    • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

    v0.9.0 (August 13, 2019)

    • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
    • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
    • add_constrained_variable and add_constrained_variables were added (#759).
    • Support for indicator constraints was added (#709, #712).
    • DualObjectiveValue attribute was added (#473).
    • RawParameter attribute was added (#733).
    • A dual_set function was added (#804).
    • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
    • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
    • The field of ObjectiveValue was renamed to result_index (#729).
    • The _constant and Utilities.getconstant function were renamed to constant
    • REDUCTION_CERTIFICATE result status was added (#734).
    • Abstract matrix sets were added (#731).
    • Testing improvements:
      • The testing guideline was updated (#728).
      • Quadratic tests were added (#697).
      • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
      • A rotated second-order cone test was added (#759).
      • A power cone test was added (#768).
      • Tests for ZeroOne variables with variable bounds were added (#772).
      • An unbounded test was added (#773).
      • Existing tests had a few updates (#702, #703, #763).
    • Documentation improvements:
      • Added a section on CachingOptimizer (#777).
      • Added a section on UniversalFallback, Model and @model (#762).
      • Transition the knapsack example to a doctest with MockOptimizer (#786).
    • Utilities improvements:
      • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
      • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
      • Implement optimizer attributes for CachingOptimizer (#745).
      • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
      • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
      • Fix a type piracy of operate (#784).
      • The load_constraint fallback signature was fixed (#760).
      • The set_dot function was extended to work with sparse arrays (#805).
    • Bridges improvements:
      • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
      • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
      • Fix constraint attributes for bridges (#699).
      • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
      • Variable bridges were added in (#759).
      • Various improvements (#746, #747).

    v0.8.4 (March 13, 2019)

    • Performance improvement in default_copy_to and bridge optimizer (#696).
    • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
    • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
    • Minor typo fixes (#694).

    v0.8.3 (March 6, 2019)

    • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
    • Fix variable deletion with SingleVariable objective function (#690).
    • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
    • Error message improvements (#673, #685, #686, #688).
    • Documentation improvements (#682, #683, #687).
    • Basis status:
      • Remove VariableBasisStatus (#679).
      • Test ConstraintBasisStatus and implement it in bridges (#678).
    • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
    • Implement division between a quadratic function and a number (#675).

    v0.8.2 (February 7, 2019)

    • Add RawStatusString attribute (#629).
    • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
    • Make scalar MOI functions act as scalars in broadcast (#646).
    • Add function utilities:
      • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
      • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
    • Improve support for starting values:
      • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
      • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
      • Add a test in contlineartest with partially set VariablePrimalStart.
    • Bridges improvements:
      • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
      • Add Slack bridges (#610, #650).
      • Add FlipSign bridges (#658).
    • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
    • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
    • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

    v0.8.1 (January 7, 2019)

    • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
    • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
    • Allow custom constraint types with full_bridge_optimizer (#617).
    • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

    v0.8.0 (December 18, 2018)

    • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
    • Rename CachingOptimizer methods for style compliance.
    • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

    v0.7.0 (December 13, 2018)

    • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
    • Check supports_default_copy_to in tests (#594).
    • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
    • Add perspective dimension to log-det cone (#593).

    v0.6.4 (November 27, 2018)

    • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
    • Add a solver naming guideline (#578).
    • Make FeasibilitySense the default ObjectiveSense (#579).
    • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
    • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

    v0.6.3 (November 16, 2018)

    • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
    • Attributes may now be partially set (some values could be nothing). (#563)
    • Performance improvements in Utilities.Model (#549, #567, #568)
    • Fix bug in QuadtoSOC (#558).
    • New supports_default_copy_to method that optimizers should implement to control caching behavior.
    • Documentation improvements.

    v0.6.2 (October 26, 2018)

    • Improve hygiene of @model macro (#544).
    • Fix bug in copy tests (#543).
    • Fix bug in UniversalFallback attribute getter (#540).
    • Allow all correct solutions for solve_blank_obj unit test (#537).
    • Add errors for Allocate-Load and bad constraints (#534).
    • [performance] Add specialized implementation of hash for VariableIndex (#533).
    • [performance] Construct the name to object dictionaries lazily in model (#535).
    • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

    v0.6.1 (September 22, 2018)

    • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
    • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
    • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
    • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

    v0.6.0 (August 30, 2018)

    • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
    • Rename functions according to the JuMP style guide:
      • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
      • set! -> set;
      • addvariable[s]! -> add_variable[s];
      • supportsconstraint -> supports_constraint;
      • addconstraint[s]! -> add_constraint[s];
      • isvalid -> is_valid;
      • isempty -> is_empty;
      • Base.delete! -> delete;
      • modify! -> modify;
      • transform! -> transform;
      • initialize! -> initialize;
      • write -> write_to_file; and
      • read! -> read_from_file.
    • Remove free! (use Base.finalize instead).
    • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
    • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
    • Add tests for ObjectiveBound.
    • Add test for empty rows in vector linear constraint.
    • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
    • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

    v0.5.0 (August 5, 2018)

    • Fix names with CachingOptimizer.
    • Cleanup thanks to @mohamed82008.
    • Added a universal fallback for constraints.
    • Fast utilities for function canonicalization thanks to @rdeits.
    • Renamed dimension field to side_dimension in the context of matrix-like sets.
    • New and improved tests for cases like duplicate terms and ObjectiveBound.
    • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
    • The API for copy! is updated to remove the CopyResult type.
    • Updates for the new JuMP style guide.

    v0.4.1 (June 28, 2018)

    • Fixes vector function modification on 32 bits.
    • Fixes Bellman-Ford algorithm for bridges.
    • Added an NLP test with FeasibilitySense.
    • Update modification documentation.

    v0.4.0 (June 23, 2018)

    • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
    • Added modify_lhs to TestConfig.
    • Additional unit tests for optimizers.
    • Added a type parameter to CachingOptimizer for the optimizer field.
    • New API for problem modification (#388)
    • Tests pass without deprecation warnings on Julia 0.7.
    • Small fixes and documentation updates.

    v0.3.0 (May 25, 2018)

    • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
    • Improvements to MockOptimizer.
    • Significant changes to Bridges.
    • New and improved unit tests.
    • Fixes for Julia 0.7.

    v0.2.0 (April 24, 2018)

    • Improvements to and better coverage of Tests.
    • Documentation fixes.
    • SolverName attribute.
    • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
    • Addition of NLP tests.
    • Introduction of UniversalFallback.
    • copynames keyword argument to MOI.copy!.
    • Add Bridges submodule.

    v0.1.0 (February 28, 2018)

    • Initial public release.
    • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
    +end

    v0.9.22 (May 22, 2021)

    This release contains backports from the ongoing development of the v0.10 release.

    • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
    • Improved performance of Utilities.is_canonical.
    • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
    • Fixed performance regression of Utilities.Model.
    • Fixed ordering of objective setting in parser.

    v0.9.21 (April 23, 2021)

    • Added supports_shift_constant.
    • Improve performance of bridging quadratic constraints.
    • Add precompilation statements.
    • Large improvements to the documentation.
    • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
    • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
    • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

    v0.9.20 (February 20, 2021)

    • Improved performance of Utilities.ScalarFunctionIterator
    • Added support for compute_conflict to MOI layers
    • Added test with zero off-diagonal quadratic term in objective
    • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
    • Fixed modification of un-set objective
    • Fixed function modification with duplicate terms
    • Made unit tests abort without failing if the problem class is not supported
    • Formatted code with JuliaFormatter
    • Clarified BasisStatusCode's docstring

    v0.9.19 (December 1, 2020)

    • Added CallbackNodeStatus attribute
    • Added bridge from GreaterThan or LessThan to Interval
    • Added tests for infeasibility certificates and double optimize
    • Fixed support for Julia v1.6
    • Re-organized MOI docs and added documentation for adding a test

    v0.9.18 (November 3, 2020)

    • Various improvements for working with complex numbers
    • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

    v0.9.17 (September 21, 2020)

    • Fixed CleverDict with variable of negative index value
    • Implement supports_add_constrained_variable for MockOptimizer

    v0.9.16 (September 17, 2020)

    • Various fixes:
      • 32-bit support
      • CleverDict with abstract value type
      • Checks in test suite

    v0.9.15 (September 14, 2020)

    • Bridges improvements:
      • (R)SOCtoNonConvexQuad bridge
      • ZeroOne bridge
      • Use supports_add_constrained_variable in LazyBridgeOptimizer
      • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
      • Prioritize constraining variables on creation according to these costs
      • Refactor bridge debugging
    • Large performance improvements across all submodules
    • Lots of documentation improvements
    • FileFormats improvements:
      • Update MathOptFormat to v0.5
      • Fix supported objectives in FileFormats
    • Testing improvements:
      • Add name option for basic_constraint_test
    • Bug fixes and missing methods
      • Add length for iterators
      • Fix bug with duplicate terms
      • Fix order of LinearOfConstraintIndices

    v0.9.14 (May 30, 2020)

    • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
    • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
    • Documentation improvements:
      • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
      • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
    • Utilities improvements:
      • Fix is_canonical for quadratic functions (#1081, #1089).
      • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
      • Add support for custom objective functions for UniversalFallback (#1086).
      • Deterministic ordering of constraints in UniversalFallback (#1088).
    • Testing improvements:
      • Add NormOneCone/NormInfinityCone tests (#1045).
    • Bridges improvements:
      • Add bridges from Semiinteger and Semicontinuous (#1059).
      • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
      • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
      • Fix NormOne/NormInf bridges with nonzero constants (#1045).
      • Fix StackOverflow in debug (#1063).
    • FileFormats improvements:
      • [SDPA] Implement the extension for integer variables (#1079).
      • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
      • [SDPA] No scaling of off-diagonal coefficient (#1076).
      • [SDPA] Add missing negation of constant (#1075).

    v0.9.13 (March 24, 2020)

    • Added tests for Semicontinuous and Semiinteger variables (#1033).
    • Added tests for using ExprGraphs from NLP evaluators (#1043).
    • Update version compatibilities of dependencies (#1034, #1051, #1052).
    • Fixed typos in documentation (#1044).

    v0.9.12 (February 28, 2020)

    • Fixed writing NLPBlock in MathOptFormat (#1037).
    • Fixed MockOptimizer for result attributes with non-one result index (#1039).
    • Updated test template with instantiate (#1032).

    v0.9.11 (February 21, 2020)

    • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
    • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
    • Fixed typos in documentation (#1022, #1024).
    • Fixed warning of unsupported attribute (#1027).
    • Added more rootdet/logdet conic tests (#1026).
    • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

    v0.9.10 (January 31, 2020)

    • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
    • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
    • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
    • Added supports_constrained_variable(s) (#1004).
    • Added dual_set_type (#1002).
    • Added tests for vector specialized version of delete (#989, #1011).
    • Added PSD3 test (#1007).
    • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
    • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
    • Fixed Utilities.vectorize for empty vector (#1003).
    • Fixed free variables in LP writer (#1006).

    v0.9.9 (December 29, 2019)

    • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
    • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
    • Updated to MutableArithmetics v0.2 (#981).
    • Added MutableArithmetics.promote_operation allocation tests (#975).
    • Fixed inference issue on Julia v1.1 (#982).

    v0.9.8 (December 19, 2019)

    • Implemented MutableArithmetics API (#924).
    • Fixed callbacks with CachingOptimizer (#959).
    • Fixed MOI.dimension for MOI.Complements (#948).
    • Added fallback for add_variables (#972).
    • Added is_diagonal_vectorized_index utility (#965).
    • Improved linear constraints display in manual (#963, #964).
    • Bridges improvements:
      • Added IndicatorSet to SOS1 bridge (#877).
      • Added support for starting values for Variable.VectorizeBridge (#944).
      • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
      • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
      • Fixed choice between variable or constraint bridges for constrained variables (#973).
      • Improve performance of bridge shortest path (#945, #946, #956).
      • Added docstring for test_delete_bridge (#954).
      • Added Variable bridge tests (#952).

    v0.9.7 (October 30, 2019)

    • Implemented _result_index_field for NLPBlockDual (#934).
    • Fixed copy of model with starting values for vector constraints (#941).
    • Bridges improvements:
      • Improved performance of add_bridge and added has_bridge (#935).
      • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
      • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

    v0.9.6 (October 25, 2019)

    • Added complementarity constraints (#913).
    • Allowed ModelLike objects as value of attributes (#928).
    • Testing improvements:
      • Added dual_objective_value option to MOI.Test.TestConfig (#922).
      • Added InvalidIndex tests in basic_constraint_tests (#921).
      • Added tests for the constant term in indicator constraint (#929).
    • Bridges improvements:
      • Added support for starting values for Functionize bridges (#923).
      • Added variable indices context to variable bridges (#920).
      • Fixed a typo in printing o debug_supports (#927).

    v0.9.5 (October 9, 2019)

    • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
    • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
    • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
    • Bridges improvements:
      • Added debug utilities for unsupported variable/constraint/objective (#861).
      • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
      • Fixed result_index with objective bridges (#911).

    v0.9.4 (October 2, 2019)

    • Added solver-independent MIP callbacks (#782).
    • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
    • Added tests for result count of solution attributes (#901, #904).
    • Added NumberOfThreads attribute (#892).
    • Added Utilities.get_bounds to get the bounds on a variable (#890).
    • Added a note on duplicate coefficients in documentation (#581).
    • Added result index in ConstraintBasisStatus (#898).
    • Added extension dictionary to Utilities.Model (#884, #895).
    • Fixed deletion of constrained variables for CachingOptimizer (#905).
    • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
    • Bridges improvements:
      • Added Variable.RSOCtoSOCBridge (#907).
      • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

    v0.9.3 (September 20, 2019)

    • Fixed ambiguity detected in Julia v1.3 (#891, #893).
    • Fixed missing sets from ListOfSupportedConstraints (#880).
    • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
    • Added extension dictionary to MOIU.Model (#884).
    • Implemented MOI.get for function and set for GeoMeanBridge (#888).
    • Updated documentation for SingleVariable indices and bridges (#885).
    • Testing improvements:
      • Added more comprehensive tests for names (#882).
      • Added tests for SingleVariable duals (#883).
      • Added tests for DualExponentialCone and DualPowerCone (#873).
    • Improvements for arbitrary coefficient type:
      • Fixed == for sets with mutable fields (#887).
      • Removed some Float64 assumptions in bridges (#878).
      • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

    v0.9.2 (September 5, 2019)

    • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
    • Generalized contlinear tests for arbitrary coefficient type (#855).
    • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
    • Fixed Allocate-Load copy for single variable constraints (#856).
    • Bridges improvements:
      • Add objective bridges (#789).
      • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
      • Added Variable.SOCtoRSOCBridge (#865).
      • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
      • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

    v0.9.1 (August 22, 2019)

    • Fix support for Julia v1.2 (#834).
    • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
    • Added tests to MOI.Test.nametest (#833).
    • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
    • Implements operate for operators * and / between vector function and constant (#837).
    • Implements show for MOI.Utilities.IndexMap (#847).
    • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
    • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

    v0.9.0 (August 13, 2019)

    • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
    • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
    • add_constrained_variable and add_constrained_variables were added (#759).
    • Support for indicator constraints was added (#709, #712).
    • DualObjectiveValue attribute was added (#473).
    • RawParameter attribute was added (#733).
    • A dual_set function was added (#804).
    • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
    • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
    • The field of ObjectiveValue was renamed to result_index (#729).
    • The _constant and Utilities.getconstant function were renamed to constant
    • REDUCTION_CERTIFICATE result status was added (#734).
    • Abstract matrix sets were added (#731).
    • Testing improvements:
      • The testing guideline was updated (#728).
      • Quadratic tests were added (#697).
      • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
      • A rotated second-order cone test was added (#759).
      • A power cone test was added (#768).
      • Tests for ZeroOne variables with variable bounds were added (#772).
      • An unbounded test was added (#773).
      • Existing tests had a few updates (#702, #703, #763).
    • Documentation improvements:
      • Added a section on CachingOptimizer (#777).
      • Added a section on UniversalFallback, Model and @model (#762).
      • Transition the knapsack example to a doctest with MockOptimizer (#786).
    • Utilities improvements:
      • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
      • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
      • Implement optimizer attributes for CachingOptimizer (#745).
      • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
      • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
      • Fix a type piracy of operate (#784).
      • The load_constraint fallback signature was fixed (#760).
      • The set_dot function was extended to work with sparse arrays (#805).
    • Bridges improvements:
      • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
      • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
      • Fix constraint attributes for bridges (#699).
      • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
      • Variable bridges were added in (#759).
      • Various improvements (#746, #747).

    v0.8.4 (March 13, 2019)

    • Performance improvement in default_copy_to and bridge optimizer (#696).
    • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
    • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
    • Minor typo fixes (#694).

    v0.8.3 (March 6, 2019)

    • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
    • Fix variable deletion with SingleVariable objective function (#690).
    • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
    • Error message improvements (#673, #685, #686, #688).
    • Documentation improvements (#682, #683, #687).
    • Basis status:
      • Remove VariableBasisStatus (#679).
      • Test ConstraintBasisStatus and implement it in bridges (#678).
    • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
    • Implement division between a quadratic function and a number (#675).

    v0.8.2 (February 7, 2019)

    • Add RawStatusString attribute (#629).
    • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
    • Make scalar MOI functions act as scalars in broadcast (#646).
    • Add function utilities:
      • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
      • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
    • Improve support for starting values:
      • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
      • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
      • Add a test in contlineartest with partially set VariablePrimalStart.
    • Bridges improvements:
      • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
      • Add Slack bridges (#610, #650).
      • Add FlipSign bridges (#658).
    • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
    • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
    • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

    v0.8.1 (January 7, 2019)

    • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
    • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
    • Allow custom constraint types with full_bridge_optimizer (#617).
    • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

    v0.8.0 (December 18, 2018)

    • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
    • Rename CachingOptimizer methods for style compliance.
    • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

    v0.7.0 (December 13, 2018)

    • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
    • Check supports_default_copy_to in tests (#594).
    • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
    • Add perspective dimension to log-det cone (#593).

    v0.6.4 (November 27, 2018)

    • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
    • Add a solver naming guideline (#578).
    • Make FeasibilitySense the default ObjectiveSense (#579).
    • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
    • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

    v0.6.3 (November 16, 2018)

    • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
    • Attributes may now be partially set (some values could be nothing). (#563)
    • Performance improvements in Utilities.Model (#549, #567, #568)
    • Fix bug in QuadtoSOC (#558).
    • New supports_default_copy_to method that optimizers should implement to control caching behavior.
    • Documentation improvements.

    v0.6.2 (October 26, 2018)

    • Improve hygiene of @model macro (#544).
    • Fix bug in copy tests (#543).
    • Fix bug in UniversalFallback attribute getter (#540).
    • Allow all correct solutions for solve_blank_obj unit test (#537).
    • Add errors for Allocate-Load and bad constraints (#534).
    • [performance] Add specialized implementation of hash for VariableIndex (#533).
    • [performance] Construct the name to object dictionaries lazily in model (#535).
    • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

    v0.6.1 (September 22, 2018)

    • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
    • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
    • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
    • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

    v0.6.0 (August 30, 2018)

    • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
    • Rename functions according to the JuMP style guide:
      • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
      • set! -> set;
      • addvariable[s]! -> add_variable[s];
      • supportsconstraint -> supports_constraint;
      • addconstraint[s]! -> add_constraint[s];
      • isvalid -> is_valid;
      • isempty -> is_empty;
      • Base.delete! -> delete;
      • modify! -> modify;
      • transform! -> transform;
      • initialize! -> initialize;
      • write -> write_to_file; and
      • read! -> read_from_file.
    • Remove free! (use Base.finalize instead).
    • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
    • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
    • Add tests for ObjectiveBound.
    • Add test for empty rows in vector linear constraint.
    • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
    • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

    v0.5.0 (August 5, 2018)

    • Fix names with CachingOptimizer.
    • Cleanup thanks to @mohamed82008.
    • Added a universal fallback for constraints.
    • Fast utilities for function canonicalization thanks to @rdeits.
    • Renamed dimension field to side_dimension in the context of matrix-like sets.
    • New and improved tests for cases like duplicate terms and ObjectiveBound.
    • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
    • The API for copy! is updated to remove the CopyResult type.
    • Updates for the new JuMP style guide.

    v0.4.1 (June 28, 2018)

    • Fixes vector function modification on 32 bits.
    • Fixes Bellman-Ford algorithm for bridges.
    • Added an NLP test with FeasibilitySense.
    • Update modification documentation.

    v0.4.0 (June 23, 2018)

    • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
    • Added modify_lhs to TestConfig.
    • Additional unit tests for optimizers.
    • Added a type parameter to CachingOptimizer for the optimizer field.
    • New API for problem modification (#388)
    • Tests pass without deprecation warnings on Julia 0.7.
    • Small fixes and documentation updates.

    v0.3.0 (May 25, 2018)

    • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
    • Improvements to MockOptimizer.
    • Significant changes to Bridges.
    • New and improved unit tests.
    • Fixes for Julia 0.7.

    v0.2.0 (April 24, 2018)

    • Improvements to and better coverage of Tests.
    • Documentation fixes.
    • SolverName attribute.
    • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
    • Addition of NLP tests.
    • Introduction of UniversalFallback.
    • copynames keyword argument to MOI.copy!.
    • Add Bridges submodule.

    v0.1.0 (February 28, 2018)

    • Initial public release.
    • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
    diff --git a/previews/PR3883/moi/developer/checklists/index.html b/previews/PR3883/moi/developer/checklists/index.html index 1c043bb1f3a..acce64a12c4 100644 --- a/previews/PR3883/moi/developer/checklists/index.html +++ b/previews/PR3883/moi/developer/checklists/index.html @@ -112,4 +112,4 @@ ## Documentation - - [ ] The version fields are updated in `docs/src/submodules/FileFormats/overview.md` + - [ ] The version fields are updated in `docs/src/submodules/FileFormats/overview.md` diff --git a/previews/PR3883/moi/index.html b/previews/PR3883/moi/index.html index 6cc8ae74994..746baf50846 100644 --- a/previews/PR3883/moi/index.html +++ b/previews/PR3883/moi/index.html @@ -10,4 +10,4 @@ year={2021}, doi={10.1287/ijoc.2021.1067}, publisher={INFORMS} -}

    A preprint of this paper is freely available.

    +}

    A preprint of this paper is freely available.

    diff --git a/previews/PR3883/moi/manual/constraints/index.html b/previews/PR3883/moi/manual/constraints/index.html index 3b3c4345594..d5a60b47819 100644 --- a/previews/PR3883/moi/manual/constraints/index.html +++ b/previews/PR3883/moi/manual/constraints/index.html @@ -23,4 +23,4 @@ false

    Constraint attributes

    The following attributes are available for constraints:

    Get and set these attributes using get and set.

    julia> MOI.set(model, MOI.ConstraintName(), c, "con_c")
     
     julia> MOI.get(model, MOI.ConstraintName(), c)
    -"con_c"

    Constraints by function-set pairs

    Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, $x$ is a vector of decision variables, $x_i$ is a scalar decision variable, $\alpha, \beta$ are scalar constants, $a, b$ are constant vectors, A is a constant matrix and $\mathbb{R}_+$ (resp. $\mathbb{R}_-$) is the set of non-negative (resp. non-positive) real numbers.

    Linear constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $a^Tx \le \beta$ScalarAffineFunctionLessThan
    $a^Tx \ge \alpha$ScalarAffineFunctionGreaterThan
    $a^Tx = \beta$ScalarAffineFunctionEqualTo
    $\alpha \le a^Tx \le \beta$ScalarAffineFunctionInterval
    $x_i \le \beta$VariableIndexLessThan
    $x_i \ge \alpha$VariableIndexGreaterThan
    $x_i = \beta$VariableIndexEqualTo
    $\alpha \le x_i \le \beta$VariableIndexInterval
    $Ax + b \in \mathbb{R}_+^n$VectorAffineFunctionNonnegatives
    $Ax + b \in \mathbb{R}_-^n$VectorAffineFunctionNonpositives
    $Ax + b = 0$VectorAffineFunctionZeros

    By convention, solvers are not expected to support nonzero constant terms in the ScalarAffineFunctions the first four rows of the preceding table because they are redundant with the parameters of the sets. For example, encode $2x + 1 \le 2$ as $2x \le 1$.

    Constraints with VariableIndex in LessThan, GreaterThan, EqualTo, or Interval sets have a natural interpretation as variable bounds. As such, it is typically not natural to impose multiple lower- or upper-bounds on the same variable, and the solver interfaces will throw respectively LowerBoundAlreadySet or UpperBoundAlreadySet.

    Moreover, adding two VariableIndex constraints on the same variable with the same set is impossible because they share the same index as it is the index of the variable, see ConstraintIndex.

    It is natural, however, to impose upper- and lower-bounds separately as two different constraints on a single variable. The difference between imposing bounds by using a single Interval constraint and by using separate LessThan and GreaterThan constraints is that the latter will allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint.

    Conic constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $\lVert Ax + b\rVert_2 \le c^Tx + d$VectorAffineFunctionSecondOrderCone
    $y \ge \lVert x \rVert_2$VectorOfVariablesSecondOrderCone
    $2yz \ge \lVert x \rVert_2^2, y,z \ge 0$VectorOfVariablesRotatedSecondOrderCone
    $(a_1^Tx + b_1,a_2^Tx + b_2,a_3^Tx + b_3) \in \mathcal{E}$VectorAffineFunctionExponentialCone
    $A(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeTriangle
    $B(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeSquare
    $x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeTriangle
    $x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeSquare

    where $\mathcal{E}$ is the exponential cone (see ExponentialCone), $\mathcal{S}_+$ is the set of positive semidefinite symmetric matrices, $A$ is an affine map that outputs symmetric matrices and $B$ is an affine map that outputs square matrices.

    Quadratic constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $\frac{1}{2}x^TQx + a^Tx + b \ge 0$ScalarQuadraticFunctionGreaterThan
    $\frac{1}{2}x^TQx + a^Tx + b \le 0$ScalarQuadraticFunctionLessThan
    $\frac{1}{2}x^TQx + a^Tx + b = 0$ScalarQuadraticFunctionEqualTo
    Bilinear matrix inequalityVectorQuadraticFunctionPositiveSemidefiniteCone...
    Note

    For more details on the internal format of the quadratic functions see ScalarQuadraticFunction or VectorQuadraticFunction.

    Discrete and logical constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $x_i \in \mathbb{Z}$VariableIndexInteger
    $x_i \in \{0,1\}$VariableIndexZeroOne
    $x_i \in \{0\} \cup [l,u]$VariableIndexSemicontinuous
    $x_i \in \{0\} \cup \{l,l+1,\ldots,u-1,u\}$VariableIndexSemiinteger
    At most one component of $x$ can be nonzeroVectorOfVariablesSOS1
    At most two components of $x$ can be nonzero, and if so they must be adjacent componentsVectorOfVariablesSOS2
    $y = 1 \implies a^T x \in S$VectorAffineFunctionIndicator

    JuMP mapping

    The following bullet points show examples of how JuMP constraints are translated into MOI function-set pairs:

    • @constraint(m, 2x + y <= 10) becomes ScalarAffineFunction-in-LessThan
    • @constraint(m, 2x + y >= 10) becomes ScalarAffineFunction-in-GreaterThan
    • @constraint(m, 2x + y == 10) becomes ScalarAffineFunction-in-EqualTo
    • @constraint(m, 0 <= 2x + y <= 10) becomes ScalarAffineFunction-in-Interval
    • @constraint(m, 2x + y in ArbitrarySet()) becomes ScalarAffineFunction-in-ArbitrarySet.

    Variable bounds are handled in a similar fashion:

    • @variable(m, x <= 1) becomes VariableIndex-in-LessThan
    • @variable(m, x >= 1) becomes VariableIndex-in-GreaterThan

    One notable difference is that a variable with an upper and lower bound is translated into two constraints, rather than an interval, that is:

    • @variable(m, 0 <= x <= 1) becomes VariableIndex-in-LessThan and VariableIndex-in-GreaterThan.
    +"con_c"

    Constraints by function-set pairs

    Below is a list of common constraint types and how they are represented as function-set pairs in MOI. In the notation below, $x$ is a vector of decision variables, $x_i$ is a scalar decision variable, $\alpha, \beta$ are scalar constants, $a, b$ are constant vectors, A is a constant matrix and $\mathbb{R}_+$ (resp. $\mathbb{R}_-$) is the set of non-negative (resp. non-positive) real numbers.

    Linear constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $a^Tx \le \beta$ScalarAffineFunctionLessThan
    $a^Tx \ge \alpha$ScalarAffineFunctionGreaterThan
    $a^Tx = \beta$ScalarAffineFunctionEqualTo
    $\alpha \le a^Tx \le \beta$ScalarAffineFunctionInterval
    $x_i \le \beta$VariableIndexLessThan
    $x_i \ge \alpha$VariableIndexGreaterThan
    $x_i = \beta$VariableIndexEqualTo
    $\alpha \le x_i \le \beta$VariableIndexInterval
    $Ax + b \in \mathbb{R}_+^n$VectorAffineFunctionNonnegatives
    $Ax + b \in \mathbb{R}_-^n$VectorAffineFunctionNonpositives
    $Ax + b = 0$VectorAffineFunctionZeros

    By convention, solvers are not expected to support nonzero constant terms in the ScalarAffineFunctions the first four rows of the preceding table because they are redundant with the parameters of the sets. For example, encode $2x + 1 \le 2$ as $2x \le 1$.

    Constraints with VariableIndex in LessThan, GreaterThan, EqualTo, or Interval sets have a natural interpretation as variable bounds. As such, it is typically not natural to impose multiple lower- or upper-bounds on the same variable, and the solver interfaces will throw respectively LowerBoundAlreadySet or UpperBoundAlreadySet.

    Moreover, adding two VariableIndex constraints on the same variable with the same set is impossible because they share the same index as it is the index of the variable, see ConstraintIndex.

    It is natural, however, to impose upper- and lower-bounds separately as two different constraints on a single variable. The difference between imposing bounds by using a single Interval constraint and by using separate LessThan and GreaterThan constraints is that the latter will allow the solver to return separate dual multipliers for the two bounds, while the former will allow the solver to return only a single dual for the interval constraint.

    Conic constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $\lVert Ax + b\rVert_2 \le c^Tx + d$VectorAffineFunctionSecondOrderCone
    $y \ge \lVert x \rVert_2$VectorOfVariablesSecondOrderCone
    $2yz \ge \lVert x \rVert_2^2, y,z \ge 0$VectorOfVariablesRotatedSecondOrderCone
    $(a_1^Tx + b_1,a_2^Tx + b_2,a_3^Tx + b_3) \in \mathcal{E}$VectorAffineFunctionExponentialCone
    $A(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeTriangle
    $B(x) \in \mathcal{S}_+$VectorAffineFunctionPositiveSemidefiniteConeSquare
    $x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeTriangle
    $x \in \mathcal{S}_+$VectorOfVariablesPositiveSemidefiniteConeSquare

    where $\mathcal{E}$ is the exponential cone (see ExponentialCone), $\mathcal{S}_+$ is the set of positive semidefinite symmetric matrices, $A$ is an affine map that outputs symmetric matrices and $B$ is an affine map that outputs square matrices.

    Quadratic constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $\frac{1}{2}x^TQx + a^Tx + b \ge 0$ScalarQuadraticFunctionGreaterThan
    $\frac{1}{2}x^TQx + a^Tx + b \le 0$ScalarQuadraticFunctionLessThan
    $\frac{1}{2}x^TQx + a^Tx + b = 0$ScalarQuadraticFunctionEqualTo
    Bilinear matrix inequalityVectorQuadraticFunctionPositiveSemidefiniteCone...
    Note

    For more details on the internal format of the quadratic functions see ScalarQuadraticFunction or VectorQuadraticFunction.

    Discrete and logical constraints

    Mathematical ConstraintMOI FunctionMOI Set
    $x_i \in \mathbb{Z}$VariableIndexInteger
    $x_i \in \{0,1\}$VariableIndexZeroOne
    $x_i \in \{0\} \cup [l,u]$VariableIndexSemicontinuous
    $x_i \in \{0\} \cup \{l,l+1,\ldots,u-1,u\}$VariableIndexSemiinteger
    At most one component of $x$ can be nonzeroVectorOfVariablesSOS1
    At most two components of $x$ can be nonzero, and if so they must be adjacent componentsVectorOfVariablesSOS2
    $y = 1 \implies a^T x \in S$VectorAffineFunctionIndicator

    JuMP mapping

    The following bullet points show examples of how JuMP constraints are translated into MOI function-set pairs:

    • @constraint(m, 2x + y <= 10) becomes ScalarAffineFunction-in-LessThan
    • @constraint(m, 2x + y >= 10) becomes ScalarAffineFunction-in-GreaterThan
    • @constraint(m, 2x + y == 10) becomes ScalarAffineFunction-in-EqualTo
    • @constraint(m, 0 <= 2x + y <= 10) becomes ScalarAffineFunction-in-Interval
    • @constraint(m, 2x + y in ArbitrarySet()) becomes ScalarAffineFunction-in-ArbitrarySet.

    Variable bounds are handled in a similar fashion:

    • @variable(m, x <= 1) becomes VariableIndex-in-LessThan
    • @variable(m, x >= 1) becomes VariableIndex-in-GreaterThan

    One notable difference is that a variable with an upper and lower bound is translated into two constraints, rather than an interval, that is:

    • @variable(m, 0 <= x <= 1) becomes VariableIndex-in-LessThan and VariableIndex-in-GreaterThan.
    diff --git a/previews/PR3883/moi/manual/models/index.html b/previews/PR3883/moi/manual/models/index.html index 3b5cd0727c4..5506c12c90e 100644 --- a/previews/PR3883/moi/manual/models/index.html +++ b/previews/PR3883/moi/manual/models/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Models

    The most significant part of MOI is the definition of the model API that is used to specify an instance of an optimization problem (for example, by adding variables and constraints). Objects that implement the model API must inherit from the ModelLike abstract type.

    Notably missing from the model API is the method to solve an optimization problem. ModelLike objects may store an instance (for example, in memory or backed by a file format) without being linked to a particular solver. In addition to the model API, MOI defines AbstractOptimizer and provides methods to solve the model and interact with solutions. See the Solutions section for more details.

    Info

    Throughout the rest of the manual, model is used as a generic ModelLike, and optimizer is used as a generic AbstractOptimizer.

    Tip

    MOI does not export functions, but for brevity we often omit qualifying names with the MOI module. Best practice is to have

    import MathOptInterface as MOI

    and prefix all MOI methods with MOI. in user code. If a name is also available in base Julia, we always explicitly use the module prefix, for example, with MOI.get.

    Attributes

    Attributes are properties of the model that can be queried and modified. These include constants such as the number of variables in a model NumberOfVariables), and properties of variables and constraints such as the name of a variable (VariableName).

    There are four types of attributes:

    Some attributes are values that can be queried by the user but not modified, while other attributes can be modified by the user.

    All interactions with attributes occur through the get and set functions.

    Consult the docstrings of each attribute for information on what it represents.

    ModelLike API

    The following attributes are available:

    AbstractOptimizer API

    The following attributes are available:

    +

    Models

    The most significant part of MOI is the definition of the model API that is used to specify an instance of an optimization problem (for example, by adding variables and constraints). Objects that implement the model API must inherit from the ModelLike abstract type.

    Notably missing from the model API is the method to solve an optimization problem. ModelLike objects may store an instance (for example, in memory or backed by a file format) without being linked to a particular solver. In addition to the model API, MOI defines AbstractOptimizer and provides methods to solve the model and interact with solutions. See the Solutions section for more details.

    Info

    Throughout the rest of the manual, model is used as a generic ModelLike, and optimizer is used as a generic AbstractOptimizer.

    Tip

    MOI does not export functions, but for brevity we often omit qualifying names with the MOI module. Best practice is to have

    import MathOptInterface as MOI

    and prefix all MOI methods with MOI. in user code. If a name is also available in base Julia, we always explicitly use the module prefix, for example, with MOI.get.

    Attributes

    Attributes are properties of the model that can be queried and modified. These include constants such as the number of variables in a model NumberOfVariables), and properties of variables and constraints such as the name of a variable (VariableName).

    There are four types of attributes:

    Some attributes are values that can be queried by the user but not modified, while other attributes can be modified by the user.

    All interactions with attributes occur through the get and set functions.

    Consult the docstrings of each attribute for information on what it represents.

    ModelLike API

    The following attributes are available:

    AbstractOptimizer API

    The following attributes are available:

    diff --git a/previews/PR3883/moi/manual/modification/index.html b/previews/PR3883/moi/manual/modification/index.html index 182ca7975f1..8d154681b51 100644 --- a/previews/PR3883/moi/manual/modification/index.html +++ b/previews/PR3883/moi/manual/modification/index.html @@ -152,4 +152,4 @@ ); julia> MOI.get(model, MOI.ConstraintFunction(), c) ≈ new_f -true +true diff --git a/previews/PR3883/moi/manual/solutions/index.html b/previews/PR3883/moi/manual/solutions/index.html index 768b1444c53..ed5a72f5009 100644 --- a/previews/PR3883/moi/manual/solutions/index.html +++ b/previews/PR3883/moi/manual/solutions/index.html @@ -36,4 +36,4 @@ end rethrow(err) # Something else went wrong. Rethrow the error end -end +end diff --git a/previews/PR3883/moi/manual/standard_form/index.html b/previews/PR3883/moi/manual/standard_form/index.html index 8d21893694d..2b4dae011fe 100644 --- a/previews/PR3883/moi/manual/standard_form/index.html +++ b/previews/PR3883/moi/manual/standard_form/index.html @@ -7,4 +7,4 @@ & \min_{x \in \mathbb{R}^n} & f_0(x) \\ & \;\;\text{s.t.} & f_i(x) & \in \mathcal{S}_i & i = 1 \ldots m -\end{align}\]

    where:

    • the functions $f_0, f_1, \ldots, f_m$ are specified by AbstractFunction objects
    • the sets $\mathcal{S}_1, \ldots, \mathcal{S}_m$ are specified by AbstractSet objects
    Tip

    For more information on this standard form, read our paper.

    MOI defines some commonly used functions and sets, but the interface is extensible to other sets recognized by the solver.

    Functions

    The function types implemented in MathOptInterface.jl are:

    FunctionDescription
    VariableIndex$x_j$, the projection onto a single coordinate defined by a variable index $j$.
    VectorOfVariablesThe projection onto multiple coordinates (that is, extracting a sub-vector).
    ScalarAffineFunction$a^T x + b$, where $a$ is a vector and $b$ scalar.
    ScalarNonlinearFunction$f(x)$, where $f$ is a nonlinear function.
    VectorAffineFunction$A x + b$, where $A$ is a matrix and $b$ is a vector.
    ScalarQuadraticFunction$\frac{1}{2} x^T Q x + a^T x + b$, where $Q$ is a symmetric matrix, $a$ is a vector, and $b$ is a constant.
    VectorQuadraticFunctionA vector of scalar-valued quadratic functions.
    VectorNonlinearFunction$f(x)$, where $f$ is a vector-valued nonlinear function.

    Extensions for nonlinear programming are present but not yet well documented.

    One-dimensional sets

    The one-dimensional set types implemented in MathOptInterface.jl are:

    SetDescription
    LessThan(u)$(-\infty, u]$
    GreaterThan(l)$[l, \infty)$
    EqualTo(v)$\{v\}$
    Interval(l, u)$[l, u]$
    Integer()$\mathbb{Z}$
    ZeroOne()$\{ 0, 1 \}$
    Semicontinuous(l, u)$\{ 0\} \cup [l, u]$
    Semiinteger(l, u)$\{ 0\} \cup \{l,l+1,\ldots,u-1,u\}$

    Vector cones

    The vector-valued set types implemented in MathOptInterface.jl are:

    SetDescription
    Reals(d)$\mathbb{R}^{d}$
    Zeros(d)$0^{d}$
    Nonnegatives(d)$\{ x \in \mathbb{R}^{d} : x \ge 0 \}$
    Nonpositives(d)$\{ x \in \mathbb{R}^{d} : x \le 0 \}$
    SecondOrderCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \lVert x \rVert_2 \}$
    RotatedSecondOrderCone(d)$\{ (t,u,x) \in \mathbb{R}^{d} : 2tu \ge \lVert x \rVert_2^2, t \ge 0,u \ge 0 \}$
    ExponentialCone()$\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$
    DualExponentialCone()$\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$
    GeometricMeanCone(d)$\{ (t,x) \in \mathbb{R}^{1+n} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$ where $n$ is $d - 1$
    PowerCone(α)$\{ (x,y,z) \in \mathbb{R}^3 : x^{\alpha} y^{1-\alpha} \ge |z|, x \ge 0,y \ge 0 \}$
    DualPowerCone(α)$\{ (u,v,w) \in \mathbb{R}^3 : \left(\frac{u}{\alpha}\right)^{\alpha}\left(\frac{v}{1-\alpha}\right)^{1-\alpha} \ge |w|, u,v \ge 0 \}$
    NormOneCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \sum_i \lvert x_i \rvert \}$
    NormInfinityCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \max_i \lvert x_i \rvert \}$
    RelativeEntropyCone(d)$\{ (u, v, w) \in \mathbb{R}^{d} : u \ge \sum_i w_i \log (\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}$
    HyperRectangle(l, u)$\{x \in \bar{\mathbb{R}}^d: x_i \in [l_i, u_i] \forall i=1,\ldots,d\}$
    NormCone(p, d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \left(\sum\limits_i \lvert x_i \rvert^p\right)^{\frac{1}{p}} \}$

    Matrix cones

    The matrix-valued set types implemented in MathOptInterface.jl are:

    SetDescription
    RootDetConeTriangle(d)$\{ (t,X) \in \mathbb{R}^{1+d(1+d)/2} : t \le \det(X)^{1/d}, X \mbox{ is the upper triangle of a PSD matrix} \}$
    RootDetConeSquare(d)$\{ (t,X) \in \mathbb{R}^{1+d^2} : t \le \det(X)^{1/d}, X \mbox{ is a PSD matrix} \}$
    PositiveSemidefiniteConeTriangle(d)$\{ X \in \mathbb{R}^{d(d+1)/2} : X \mbox{ is the upper triangle of a PSD matrix} \}$
    PositiveSemidefiniteConeSquare(d)$\{ X \in \mathbb{R}^{d^2} : X \mbox{ is a PSD matrix} \}$
    LogDetConeTriangle(d)$\{ (t,u,X) \in \mathbb{R}^{2+d(1+d)/2} : t \le u\log(\det(X/u)), X \mbox{ is the upper triangle of a PSD matrix}, u > 0 \}$
    LogDetConeSquare(d)$\{ (t,u,X) \in \mathbb{R}^{2+d^2} : t \le u \log(\det(X/u)), X \mbox{ is a PSD matrix}, u > 0 \}$
    NormSpectralCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sigma_1(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
    NormNuclearCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sum_i \sigma_i(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
    HermitianPositiveSemidefiniteConeTriangle(d)The cone of Hermitian positive semidefinite matrices, with
    side_dimension rows and columns.
    Scaled(S)The set S scaled so that Utilities.set_dot corresponds to LinearAlgebra.dot

    Some of these cones can take two forms: XXXConeTriangle and XXXConeSquare.

    In XXXConeTriangle sets, the matrix is assumed to be symmetric, and the elements are provided by a vector, in which the entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row).

    In XXXConeSquare sets, the entries of the matrix are given column by column (or equivalently, row by row), and the matrix is constrained to be symmetric. As an example, given a 2-by-2 matrix of variables X and a one-dimensional variable t, we can specify a root-det constraint as [t, X11, X12, X22] ∈ RootDetConeTriangle or [t, X11, X12, X21, X22] ∈ RootDetConeSquare.

    We provide both forms to enable flexibility for solvers who may natively support one or the other. Transformations between XXXConeTriangle and XXXConeSquare are handled by bridges, which removes the chance of conversion mistakes by users or solver developers.

    Multi-dimensional sets with combinatorial structure

    Other sets are vector-valued, with a particular combinatorial structure. Read their docstrings for more information on how to interpret them.

    SetDescription
    SOS1A Special Ordered Set (SOS) of Type I
    SOS2A Special Ordered Set (SOS) of Type II
    IndicatorA set to specify an indicator constraint
    ComplementsA set to specify a mixed complementarity constraint
    AllDifferentThe all_different global constraint
    BinPackingThe bin_packing global constraint
    CircuitThe circuit global constraint
    CountAtLeastThe at_least global constraint
    CountBelongsThe nvalue global constraint
    CountDistinctThe distinct global constraint
    CountGreaterThanThe count_gt global constraint
    CumulativeThe cumulative global constraint
    PathThe path global constraint
    TableThe table global constraint
    +\end{align}\]

    where:

    • the functions $f_0, f_1, \ldots, f_m$ are specified by AbstractFunction objects
    • the sets $\mathcal{S}_1, \ldots, \mathcal{S}_m$ are specified by AbstractSet objects
    Tip

    For more information on this standard form, read our paper.

    MOI defines some commonly used functions and sets, but the interface is extensible to other sets recognized by the solver.

    Functions

    The function types implemented in MathOptInterface.jl are:

    FunctionDescription
    VariableIndex$x_j$, the projection onto a single coordinate defined by a variable index $j$.
    VectorOfVariablesThe projection onto multiple coordinates (that is, extracting a sub-vector).
    ScalarAffineFunction$a^T x + b$, where $a$ is a vector and $b$ scalar.
    ScalarNonlinearFunction$f(x)$, where $f$ is a nonlinear function.
    VectorAffineFunction$A x + b$, where $A$ is a matrix and $b$ is a vector.
    ScalarQuadraticFunction$\frac{1}{2} x^T Q x + a^T x + b$, where $Q$ is a symmetric matrix, $a$ is a vector, and $b$ is a constant.
    VectorQuadraticFunctionA vector of scalar-valued quadratic functions.
    VectorNonlinearFunction$f(x)$, where $f$ is a vector-valued nonlinear function.

    Extensions for nonlinear programming are present but not yet well documented.

    One-dimensional sets

    The one-dimensional set types implemented in MathOptInterface.jl are:

    SetDescription
    LessThan(u)$(-\infty, u]$
    GreaterThan(l)$[l, \infty)$
    EqualTo(v)$\{v\}$
    Interval(l, u)$[l, u]$
    Integer()$\mathbb{Z}$
    ZeroOne()$\{ 0, 1 \}$
    Semicontinuous(l, u)$\{ 0\} \cup [l, u]$
    Semiinteger(l, u)$\{ 0\} \cup \{l,l+1,\ldots,u-1,u\}$

    Vector cones

    The vector-valued set types implemented in MathOptInterface.jl are:

    SetDescription
    Reals(d)$\mathbb{R}^{d}$
    Zeros(d)$0^{d}$
    Nonnegatives(d)$\{ x \in \mathbb{R}^{d} : x \ge 0 \}$
    Nonpositives(d)$\{ x \in \mathbb{R}^{d} : x \le 0 \}$
    SecondOrderCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \lVert x \rVert_2 \}$
    RotatedSecondOrderCone(d)$\{ (t,u,x) \in \mathbb{R}^{d} : 2tu \ge \lVert x \rVert_2^2, t \ge 0,u \ge 0 \}$
    ExponentialCone()$\{ (x,y,z) \in \mathbb{R}^3 : y \exp (x/y) \le z, y > 0 \}$
    DualExponentialCone()$\{ (u,v,w) \in \mathbb{R}^3 : -u \exp (v/u) \le \exp(1) w, u < 0 \}$
    GeometricMeanCone(d)$\{ (t,x) \in \mathbb{R}^{1+n} : x \ge 0, t \le \sqrt[n]{x_1 x_2 \cdots x_n} \}$ where $n$ is $d - 1$
    PowerCone(α)$\{ (x,y,z) \in \mathbb{R}^3 : x^{\alpha} y^{1-\alpha} \ge |z|, x \ge 0,y \ge 0 \}$
    DualPowerCone(α)$\{ (u,v,w) \in \mathbb{R}^3 : \left(\frac{u}{\alpha}\right)^{\alpha}\left(\frac{v}{1-\alpha}\right)^{1-\alpha} \ge |w|, u,v \ge 0 \}$
    NormOneCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \sum_i \lvert x_i \rvert \}$
    NormInfinityCone(d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \max_i \lvert x_i \rvert \}$
    RelativeEntropyCone(d)$\{ (u, v, w) \in \mathbb{R}^{d} : u \ge \sum_i w_i \log (\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}$
    HyperRectangle(l, u)$\{x \in \bar{\mathbb{R}}^d: x_i \in [l_i, u_i] \forall i=1,\ldots,d\}$
    NormCone(p, d)$\{ (t,x) \in \mathbb{R}^{d} : t \ge \left(\sum\limits_i \lvert x_i \rvert^p\right)^{\frac{1}{p}} \}$

    Matrix cones

    The matrix-valued set types implemented in MathOptInterface.jl are:

    SetDescription
    RootDetConeTriangle(d)$\{ (t,X) \in \mathbb{R}^{1+d(1+d)/2} : t \le \det(X)^{1/d}, X \mbox{ is the upper triangle of a PSD matrix} \}$
    RootDetConeSquare(d)$\{ (t,X) \in \mathbb{R}^{1+d^2} : t \le \det(X)^{1/d}, X \mbox{ is a PSD matrix} \}$
    PositiveSemidefiniteConeTriangle(d)$\{ X \in \mathbb{R}^{d(d+1)/2} : X \mbox{ is the upper triangle of a PSD matrix} \}$
    PositiveSemidefiniteConeSquare(d)$\{ X \in \mathbb{R}^{d^2} : X \mbox{ is a PSD matrix} \}$
    LogDetConeTriangle(d)$\{ (t,u,X) \in \mathbb{R}^{2+d(1+d)/2} : t \le u\log(\det(X/u)), X \mbox{ is the upper triangle of a PSD matrix}, u > 0 \}$
    LogDetConeSquare(d)$\{ (t,u,X) \in \mathbb{R}^{2+d^2} : t \le u \log(\det(X/u)), X \mbox{ is a PSD matrix}, u > 0 \}$
    NormSpectralCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sigma_1(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
    NormNuclearCone(r, c)$\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sum_i \sigma_i(X), X \mbox{ is a } r\times c\mbox{ matrix} \}$
    HermitianPositiveSemidefiniteConeTriangle(d)The cone of Hermitian positive semidefinite matrices, with
    side_dimension rows and columns.
    Scaled(S)The set S scaled so that Utilities.set_dot corresponds to LinearAlgebra.dot

    Some of these cones can take two forms: XXXConeTriangle and XXXConeSquare.

    In XXXConeTriangle sets, the matrix is assumed to be symmetric, and the elements are provided by a vector, in which the entries of the upper-right triangular part of the matrix are given column by column (or equivalently, the entries of the lower-left triangular part are given row by row).

    In XXXConeSquare sets, the entries of the matrix are given column by column (or equivalently, row by row), and the matrix is constrained to be symmetric. As an example, given a 2-by-2 matrix of variables X and a one-dimensional variable t, we can specify a root-det constraint as [t, X11, X12, X22] ∈ RootDetConeTriangle or [t, X11, X12, X21, X22] ∈ RootDetConeSquare.

    We provide both forms to enable flexibility for solvers who may natively support one or the other. Transformations between XXXConeTriangle and XXXConeSquare are handled by bridges, which removes the chance of conversion mistakes by users or solver developers.

    Multi-dimensional sets with combinatorial structure

    Other sets are vector-valued, with a particular combinatorial structure. Read their docstrings for more information on how to interpret them.

    SetDescription
    SOS1A Special Ordered Set (SOS) of Type I
    SOS2A Special Ordered Set (SOS) of Type II
    IndicatorA set to specify an indicator constraint
    ComplementsA set to specify a mixed complementarity constraint
    AllDifferentThe all_different global constraint
    BinPackingThe bin_packing global constraint
    CircuitThe circuit global constraint
    CountAtLeastThe at_least global constraint
    CountBelongsThe nvalue global constraint
    CountDistinctThe distinct global constraint
    CountGreaterThanThe count_gt global constraint
    CumulativeThe cumulative global constraint
    PathThe path global constraint
    TableThe table global constraint
    diff --git a/previews/PR3883/moi/manual/variables/index.html b/previews/PR3883/moi/manual/variables/index.html index 55d05ef76f0..b374780909e 100644 --- a/previews/PR3883/moi/manual/variables/index.html +++ b/previews/PR3883/moi/manual/variables/index.html @@ -14,4 +14,4 @@ false
    Warning

    Not all ModelLike models support deleting variables. A DeleteNotAllowed error is thrown if this is not supported.

    Variable attributes

    The following attributes are available for variables:

    Get and set these attributes using get and set.

    julia> MOI.set(model, MOI.VariableName(), x, "var_x")
     
     julia> MOI.get(model, MOI.VariableName(), x)
    -"var_x"
    +"var_x" diff --git a/previews/PR3883/moi/reference/callbacks/index.html b/previews/PR3883/moi/reference/callbacks/index.html index ce506366860..1bc2362302a 100644 --- a/previews/PR3883/moi/reference/callbacks/index.html +++ b/previews/PR3883/moi/reference/callbacks/index.html @@ -33,4 +33,4 @@ MOI.submit(optimizer, MOI.HeuristicSolution(callback_data), x, values) end -endsource
    MathOptInterface.HeuristicSolutionType
    HeuristicSolution(callback_data)

    Heuristically obtained feasible solution. The solution is submitted as variables, values where values[i] gives the value of variables[i], similarly to set. The submit call returns a HeuristicSolutionStatus indicating whether the provided solution was accepted or rejected.

    This can be submitted only from the HeuristicCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the heuristic callback.

    Some solvers require a complete solution, others only partial solutions.

    source
    +endsource
    MathOptInterface.HeuristicSolutionType
    HeuristicSolution(callback_data)

    Heuristically obtained feasible solution. The solution is submitted as variables, values where values[i] gives the value of variables[i], similarly to set. The submit call returns a HeuristicSolutionStatus indicating whether the provided solution was accepted or rejected.

    This can be submitted only from the HeuristicCallback. The field callback_data is a solver-specific callback type that is passed as the argument to the heuristic callback.

    Some solvers require a complete solution, others only partial solutions.

    source
    diff --git a/previews/PR3883/moi/reference/constraints/index.html b/previews/PR3883/moi/reference/constraints/index.html index b2ea4cab3b1..da489fcec4b 100644 --- a/previews/PR3883/moi/reference/constraints/index.html +++ b/previews/PR3883/moi/reference/constraints/index.html @@ -44,4 +44,4 @@ model::ModelLike, ::Type{F}, ::Type{S}, -)::Bool where {F<:AbstractFunction,S<:AbstractSet}

    Return a Bool indicating whether model supports F-in-S constraints, that is, copy_to(model, src) does not throw UnsupportedConstraint when src contains F-in-S constraints. If F-in-S constraints are only not supported in specific circumstances, for example, F-in-S constraints cannot be combined with another type of constraint, it should still return true.

    source

    Attributes

    MathOptInterface.ConstraintNameType
    ConstraintName()

    A constraint attribute for a string identifying the constraint.

    It is valid for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using get, regardless of whether they have the same F-in-S type.

    ConstraintName has a default value of "" if not set.

    Notes

    You should not implement ConstraintName for VariableIndex constraints.

    source
    MathOptInterface.ConstraintPrimalType
    ConstraintPrimal(result_index::Int = 1)

    A constraint attribute for the assignment to some constraint's primal value in result result_index.

    If the constraint is f(x) in S, then in most cases the ConstraintPrimal is the value of f, evaluated at the corresponding VariablePrimal solution.

    However, some conic solvers reformulate b - Ax in S to s = b - Ax, s in S. These solvers may return the value of s for ConstraintPrimal, rather than b - Ax. (Although these are constrained by an equality constraint, due to numerical tolerances they may not be identical.)

    If the solver does not have a primal value for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintPrimal attribute.

    If result_index is omitted, it is 1 by default. See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.ConstraintDualType
    ConstraintDual(result_index::Int = 1)

    A constraint attribute for the assignment to some constraint's dual value in result result_index. If result_index is omitted, it is 1 by default.

    If the solver does not have a dual value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the ConstraintDual attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.ConstraintBasisStatusType
    ConstraintBasisStatus(result_index::Int = 1)

    A constraint attribute for the BasisStatusCode of some constraint in result result_index, with respect to an available optimal solution basis. If result_index is omitted, it is 1 by default.

    If the solver does not have a basis status for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintBasisStatus attribute.

    See ResultCount for information on how the results are ordered.

    Notes

    For the basis status of a variable, query VariableBasisStatus.

    ConstraintBasisStatus does not apply to VariableIndex constraints. You can infer the basis status of a VariableIndex constraint by looking at the result of VariableBasisStatus.

    source
    MathOptInterface.ConstraintFunctionType
    ConstraintFunction()

    A constraint attribute for the AbstractFunction object used to define the constraint.

    It is guaranteed to be equivalent but not necessarily identical to the function provided by the user.

    source
    MathOptInterface.CanonicalConstraintFunctionType
    CanonicalConstraintFunction()

    A constraint attribute for a canonical representation of the AbstractFunction object used to define the constraint.

    Getting this attribute is guaranteed to return a function that is equivalent but not necessarily identical to the function provided by the user.

    By default, MOI.get(model, MOI.CanonicalConstraintFunction(), ci) fallbacks to MOI.Utilities.canonical(MOI.get(model, MOI.ConstraintFunction(), ci)). However, if model knows that the constraint function is canonical then it can implement a specialized method that directly return the function without calling Utilities.canonical. Therefore, the value returned cannot be assumed to be a copy of the function stored in model. Moreover, Utilities.Model checks with Utilities.is_canonical whether the function stored internally is already canonical and if it's the case, then it returns the function stored internally instead of a copy.

    source
    MathOptInterface.BasisStatusCodeType
    BasisStatusCode

    An Enum of possible values for the ConstraintBasisStatus and VariableBasisStatus attributes, explaining the status of a given element with respect to an optimal solution basis.

    Notes

    • NONBASIC_AT_LOWER and NONBASIC_AT_UPPER should be used only for constraints with the Interval set. In this case, they are necessary to distinguish which side of the constraint is active. One-sided constraints (for example, LessThan and GreaterThan) should use NONBASIC instead of the NONBASIC_AT_* values. This restriction does not apply to VariableBasisStatus, which should return NONBASIC_AT_* regardless of whether the alternative bound exists.

    • In linear programs, SUPER_BASIC occurs when a variable with no bounds is not in the basis.

    Values

    Possible values are:

    source
    +)::Bool where {F<:AbstractFunction,S<:AbstractSet}

    Return a Bool indicating whether model supports F-in-S constraints, that is, copy_to(model, src) does not throw UnsupportedConstraint when src contains F-in-S constraints. If F-in-S constraints are only not supported in specific circumstances, for example, F-in-S constraints cannot be combined with another type of constraint, it should still return true.

    source

    Attributes

    MathOptInterface.ConstraintNameType
    ConstraintName()

    A constraint attribute for a string identifying the constraint.

    It is valid for constraints variables to have the same name; however, constraints with duplicate names cannot be looked up using get, regardless of whether they have the same F-in-S type.

    ConstraintName has a default value of "" if not set.

    Notes

    You should not implement ConstraintName for VariableIndex constraints.

    source
    MathOptInterface.ConstraintPrimalType
    ConstraintPrimal(result_index::Int = 1)

    A constraint attribute for the assignment to some constraint's primal value in result result_index.

    If the constraint is f(x) in S, then in most cases the ConstraintPrimal is the value of f, evaluated at the corresponding VariablePrimal solution.

    However, some conic solvers reformulate b - Ax in S to s = b - Ax, s in S. These solvers may return the value of s for ConstraintPrimal, rather than b - Ax. (Although these are constrained by an equality constraint, due to numerical tolerances they may not be identical.)

    If the solver does not have a primal value for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintPrimal attribute.

    If result_index is omitted, it is 1 by default. See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.ConstraintDualType
    ConstraintDual(result_index::Int = 1)

    A constraint attribute for the assignment to some constraint's dual value in result result_index. If result_index is omitted, it is 1 by default.

    If the solver does not have a dual value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the ConstraintDual attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.ConstraintBasisStatusType
    ConstraintBasisStatus(result_index::Int = 1)

    A constraint attribute for the BasisStatusCode of some constraint in result result_index, with respect to an available optimal solution basis. If result_index is omitted, it is 1 by default.

    If the solver does not have a basis status for the constraint because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ConstraintBasisStatus attribute.

    See ResultCount for information on how the results are ordered.

    Notes

    For the basis status of a variable, query VariableBasisStatus.

    ConstraintBasisStatus does not apply to VariableIndex constraints. You can infer the basis status of a VariableIndex constraint by looking at the result of VariableBasisStatus.

    source
    MathOptInterface.ConstraintFunctionType
    ConstraintFunction()

    A constraint attribute for the AbstractFunction object used to define the constraint.

    It is guaranteed to be equivalent but not necessarily identical to the function provided by the user.

    source
    MathOptInterface.CanonicalConstraintFunctionType
    CanonicalConstraintFunction()

    A constraint attribute for a canonical representation of the AbstractFunction object used to define the constraint.

    Getting this attribute is guaranteed to return a function that is equivalent but not necessarily identical to the function provided by the user.

    By default, MOI.get(model, MOI.CanonicalConstraintFunction(), ci) fallbacks to MOI.Utilities.canonical(MOI.get(model, MOI.ConstraintFunction(), ci)). However, if model knows that the constraint function is canonical then it can implement a specialized method that directly return the function without calling Utilities.canonical. Therefore, the value returned cannot be assumed to be a copy of the function stored in model. Moreover, Utilities.Model checks with Utilities.is_canonical whether the function stored internally is already canonical and if it's the case, then it returns the function stored internally instead of a copy.

    source
    MathOptInterface.BasisStatusCodeType
    BasisStatusCode

    An Enum of possible values for the ConstraintBasisStatus and VariableBasisStatus attributes, explaining the status of a given element with respect to an optimal solution basis.

    Notes

    • NONBASIC_AT_LOWER and NONBASIC_AT_UPPER should be used only for constraints with the Interval set. In this case, they are necessary to distinguish which side of the constraint is active. One-sided constraints (for example, LessThan and GreaterThan) should use NONBASIC instead of the NONBASIC_AT_* values. This restriction does not apply to VariableBasisStatus, which should return NONBASIC_AT_* regardless of whether the alternative bound exists.

    • In linear programs, SUPER_BASIC occurs when a variable with no bounds is not in the basis.

    Values

    Possible values are:

    source
    diff --git a/previews/PR3883/moi/reference/errors/index.html b/previews/PR3883/moi/reference/errors/index.html index 4a16396dc9b..ea5b6b59edc 100644 --- a/previews/PR3883/moi/reference/errors/index.html +++ b/previews/PR3883/moi/reference/errors/index.html @@ -57,4 +57,4 @@ julia> throw(MOI.UnsupportedNonlinearOperator(:black_box)) ERROR: MathOptInterface.UnsupportedNonlinearOperator: The nonlinear operator `:black_box` is not supported by the model. Stacktrace: -[...]source

    Note that setting the ConstraintFunction of a VariableIndex constraint is not allowed:

    +[...]source

    Note that setting the ConstraintFunction of a VariableIndex constraint is not allowed:

    diff --git a/previews/PR3883/moi/reference/models/index.html b/previews/PR3883/moi/reference/models/index.html index 8683cfc10c4..c9e283ace79 100644 --- a/previews/PR3883/moi/reference/models/index.html +++ b/previews/PR3883/moi/reference/models/index.html @@ -7,7 +7,7 @@ model::MOI.ModelLike, attr::MOI.AbstractConstraintAttribute, bridge::AbstractBridge, -)

    Return the value of the attribute attr of the model model for the constraint bridged by bridge.

    source
    get(model::GenericModel, attr::MathOptInterface.AbstractOptimizerAttribute)

    Return the value of the attribute attr from the model's MOI backend.

    source
    get(model::GenericModel, attr::MathOptInterface.AbstractModelAttribute)

    Return the value of the attribute attr from the model's MOI backend.

    source
    get(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)

    Return an attribute attr of the optimizer optimizer.

    get(model::ModelLike, attr::AbstractModelAttribute)

    Return an attribute attr of the model model.

    get(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)

    If the attribute attr is set for the variable v in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

    get(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})

    Return a vector of attributes corresponding to each variable in the collection v in the model model.

    get(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)

    If the attribute attr is set for the constraint c in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

    get(
    +)

    Return the value of the attribute attr of the model model for the constraint bridged by bridge.

    source
    get(model::GenericModel, attr::MathOptInterface.AbstractOptimizerAttribute)

    Return the value of the attribute attr from the model's MOI backend.

    source
    get(model::GenericModel, attr::MathOptInterface.AbstractModelAttribute)

    Return the value of the attribute attr from the model's MOI backend.

    source
    get(optimizer::AbstractOptimizer, attr::AbstractOptimizerAttribute)

    Return an attribute attr of the optimizer optimizer.

    get(model::ModelLike, attr::AbstractModelAttribute)

    Return an attribute attr of the model model.

    get(model::ModelLike, attr::AbstractVariableAttribute, v::VariableIndex)

    If the attribute attr is set for the variable v in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

    get(model::ModelLike, attr::AbstractVariableAttribute, v::Vector{VariableIndex})

    Return a vector of attributes corresponding to each variable in the collection v in the model model.

    get(model::ModelLike, attr::AbstractConstraintAttribute, c::ConstraintIndex)

    If the attribute attr is set for the constraint c in the model model, return its value, return nothing otherwise. If the attribute attr is not supported by model then an error should be thrown instead of returning nothing.

    get(
         model::ModelLike,
         attr::AbstractConstraintAttribute,
         c::Vector{ConstraintIndex{F,S}},
    @@ -139,4 +139,4 @@
     MOI.get(model, MOI.RelativeGapTolerance())  # returns 1e-3
     # ... and the relative gap of the obtained solution is smaller or equal to the
     # tolerance
    -MOI.get(model, MOI.RelativeGap())  # should return something ≤ 1e-3
    Warning

    The mathematical definition of "relative gap", and its allowed range, are solver-dependent. Typically, solvers expect a value between 0.0 and 1.0.

    source

    List of attributes useful for optimizers

    MathOptInterface.TerminationStatusCodeType
    TerminationStatusCode

    An Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.

    Values

    Possible values are:

    • OPTIMIZE_NOT_CALLED: The algorithm has not started.
    • OPTIMAL: The algorithm found a globally optimal solution.
    • INFEASIBLE: The algorithm concluded that no feasible solution exists.
    • DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.
    • LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.
    • LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.
    • INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.
    • ALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.
    • ALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.
    • ALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.
    • ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.
    • ITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.
    • TIME_LIMIT: The algorithm stopped after a user-specified computation time.
    • NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.
    • SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.
    • MEMORY_LIMIT: The algorithm stopped because it ran out of memory.
    • OBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.
    • NORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.
    • OTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.
    • SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.
    • NUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.
    • INVALID_MODEL: The algorithm stopped because the model is invalid.
    • INVALID_OPTION: The algorithm stopped because it was provided an invalid option.
    • INTERRUPTED: The algorithm stopped because of an interrupt signal.
    • OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.
    source
    MathOptInterface.DUAL_INFEASIBLEConstant
    DUAL_INFEASIBLE::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.

    source
    MathOptInterface.LOCALLY_SOLVEDConstant
    LOCALLY_SOLVED::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.

    source
    MathOptInterface.LOCALLY_INFEASIBLEConstant
    LOCALLY_INFEASIBLE::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.

    source
    MathOptInterface.SOLUTION_LIMITConstant
    SOLUTION_LIMIT::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.

    source
    MathOptInterface.DualStatusType
    DualStatus(result_index::Int = 1)

    A model attribute for the ResultStatusCode of the dual result result_index. If result_index is omitted, it defaults to 1.

    See ResultCount for information on how the results are ordered.

    If result_index is larger than the value of ResultCount then NO_SOLUTION is returned.

    source
    MathOptInterface.ResultCountType
    ResultCount()

    A model attribute for the number of results available.

    Order of solutions

    A number of attributes contain an index, result_index, which is used to refer to one of the available results. Thus, result_index must be an integer between 1 and the number of available results.

    As a general rule, the first result (result_index=1) is the most important result (for example, an optimal solution or an infeasibility certificate). Other results will typically be alternate solutions that the solver found during the search for the first result.

    If a (local) optimal solution is available, that is, TerminationStatus is OPTIMAL or LOCALLY_SOLVED, the first result must correspond to the (locally) optimal solution. Other results may be alternative optimal solutions, or they may be other suboptimal solutions; use ObjectiveValue to distinguish between them.

    If a primal or dual infeasibility certificate is available, that is, TerminationStatus is INFEASIBLE or DUAL_INFEASIBLE and the corresponding PrimalStatus or DualStatus is INFEASIBILITY_CERTIFICATE, then the first result must be a certificate. Other results may be alternate certificates, or infeasible points.

    source
    MathOptInterface.ObjectiveValueType
    ObjectiveValue(result_index::Int = 1)

    A model attribute for the objective value of the primal solution result_index.

    If the solver does not have a primal value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ObjectiveValue attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.DualObjectiveValueType
    DualObjectiveValue(result_index::Int = 1)

    A model attribute for the value of the objective function of the dual problem for the result_indexth dual result.

    If the solver does not have a dual value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the DualObjectiveValue attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.RelativeGapType
    RelativeGap()

    A model attribute for the final relative optimality gap.

    Warning

    The definition of this gap is solver-dependent. However, most solvers implementing this attribute define the relative gap as some variation of $\frac{|b-f|}{|f|}$, where $b$ is the best bound and $f$ is the best feasible objective value.

    source
    MathOptInterface.SimplexIterationsType
    SimplexIterations()

    A model attribute for the cumulative number of simplex iterations during the optimization process.

    For a mixed-integer program (MIP), the return value is the total simplex iterations for all nodes.

    source
    MathOptInterface.NodeCountType
    NodeCount()

    A model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).

    source

    ResultStatusCode

    MathOptInterface.ResultStatusCodeType
    ResultStatusCode

    An Enum of possible values for the PrimalStatus and DualStatus attributes.

    The values indicate how to interpret the result vector.

    Values

    Possible values are:

    • NO_SOLUTION: the result vector is empty.
    • FEASIBLE_POINT: the result vector is a feasible point.
    • NEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.
    • INFEASIBLE_POINT: the result vector is an infeasible point.
    • INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.
    • NEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.
    • REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.
    • NEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.
    • UNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.
    • OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above
    source
    MathOptInterface.INFEASIBILITY_CERTIFICATEConstant
    INFEASIBILITY_CERTIFICATE::ResultStatusCode

    An instance of the ResultStatusCode enum.

    INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.

    source
    MathOptInterface.REDUCTION_CERTIFICATEConstant
    REDUCTION_CERTIFICATE::ResultStatusCode

    An instance of the ResultStatusCode enum.

    REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.

    source

    Conflict Status

    MathOptInterface.compute_conflict!Function
    compute_conflict!(optimizer::AbstractOptimizer)

    Computes a minimal subset of constraints such that the model with the other constraint removed is still infeasible.

    Some solvers call a set of conflicting constraints an Irreducible Inconsistent Subsystem (IIS).

    See also ConflictStatus and ConstraintConflictStatus.

    Note

    If the model is modified after a call to compute_conflict!, the implementor is not obliged to purge the conflict. Any calls to the above attributes may return values for the original conflict without a warning. Similarly, when modifying the model, the conflict can be discarded.

    source
    MathOptInterface.ConflictStatusCodeType
    ConflictStatusCode

    An Enum of possible values for the ConflictStatus attribute. This attribute is meant to explain the reason why the conflict finder stopped executing in the most recent call to compute_conflict!.

    Possible values are:

    • COMPUTE_CONFLICT_NOT_CALLED: the function compute_conflict! has not yet been called
    • NO_CONFLICT_EXISTS: there is no conflict because the problem is feasible
    • NO_CONFLICT_FOUND: the solver could not find a conflict
    • CONFLICT_FOUND: at least one conflict could be found
    source
    MathOptInterface.ConflictParticipationStatusCodeType
    ConflictParticipationStatusCode

    An Enum of possible values for the ConstraintConflictStatus attribute. This attribute is meant to indicate whether a given constraint participates or not in the last computed conflict.

    Values

    Possible values are:

    • NOT_IN_CONFLICT: the constraint does not participate in the conflict
    • IN_CONFLICT: the constraint participates in the conflict
    • MAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict
    source
    +MOI.get(model, MOI.RelativeGap()) # should return something ≤ 1e-3
    Warning

    The mathematical definition of "relative gap", and its allowed range, are solver-dependent. Typically, solvers expect a value between 0.0 and 1.0.

    source

    List of attributes useful for optimizers

    MathOptInterface.TerminationStatusCodeType
    TerminationStatusCode

    An Enum of possible values for the TerminationStatus attribute. This attribute is meant to explain the reason why the optimizer stopped executing in the most recent call to optimize!.

    Values

    Possible values are:

    • OPTIMIZE_NOT_CALLED: The algorithm has not started.
    • OPTIMAL: The algorithm found a globally optimal solution.
    • INFEASIBLE: The algorithm concluded that no feasible solution exists.
    • DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.
    • LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.
    • LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.
    • INFEASIBLE_OR_UNBOUNDED: The algorithm stopped because it decided that the problem is infeasible or unbounded; this occasionally happens during MIP presolve.
    • ALMOST_OPTIMAL: The algorithm found a globally optimal solution to relaxed tolerances.
    • ALMOST_INFEASIBLE: The algorithm concluded that no feasible solution exists within relaxed tolerances.
    • ALMOST_DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem within relaxed tolerances.
    • ALMOST_LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, or could not find directions for improvement within relaxed tolerances.
    • ITERATION_LIMIT: An iterative algorithm stopped after conducting the maximum number of iterations.
    • TIME_LIMIT: The algorithm stopped after a user-specified computation time.
    • NODE_LIMIT: A branch-and-bound algorithm stopped because it explored a maximum number of nodes in the branch-and-bound tree.
    • SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.
    • MEMORY_LIMIT: The algorithm stopped because it ran out of memory.
    • OBJECTIVE_LIMIT: The algorithm stopped because it found a solution better than a minimum limit set by the user.
    • NORM_LIMIT: The algorithm stopped because the norm of an iterate became too large.
    • OTHER_LIMIT: The algorithm stopped due to a limit not covered by one of the _LIMIT_ statuses above.
    • SLOW_PROGRESS: The algorithm stopped because it was unable to continue making progress towards the solution.
    • NUMERICAL_ERROR: The algorithm stopped because it encountered unrecoverable numerical error.
    • INVALID_MODEL: The algorithm stopped because the model is invalid.
    • INVALID_OPTION: The algorithm stopped because it was provided an invalid option.
    • INTERRUPTED: The algorithm stopped because of an interrupt signal.
    • OTHER_ERROR: The algorithm stopped because of an error not covered by one of the statuses defined above.
    source
    MathOptInterface.DUAL_INFEASIBLEConstant
    DUAL_INFEASIBLE::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    DUAL_INFEASIBLE: The algorithm concluded that no dual bound exists for the problem. If, additionally, a feasible (primal) solution is known to exist, this status typically implies that the problem is unbounded, with some technical exceptions.

    source
    MathOptInterface.LOCALLY_SOLVEDConstant
    LOCALLY_SOLVED::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    LOCALLY_SOLVED: The algorithm converged to a stationary point, local optimal solution, could not find directions for improvement, or otherwise completed its search without global guarantees.

    source
    MathOptInterface.LOCALLY_INFEASIBLEConstant
    LOCALLY_INFEASIBLE::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    LOCALLY_INFEASIBLE: The algorithm converged to an infeasible point or otherwise completed its search without finding a feasible solution, without guarantees that no feasible solution exists.

    source
    MathOptInterface.SOLUTION_LIMITConstant
    SOLUTION_LIMIT::TerminationStatusCode

    An instance of the TerminationStatusCode enum.

    SOLUTION_LIMIT: The algorithm stopped because it found the required number of solutions. This is often used in MIPs to get the solver to return the first feasible solution it encounters.

    source
    MathOptInterface.DualStatusType
    DualStatus(result_index::Int = 1)

    A model attribute for the ResultStatusCode of the dual result result_index. If result_index is omitted, it defaults to 1.

    See ResultCount for information on how the results are ordered.

    If result_index is larger than the value of ResultCount then NO_SOLUTION is returned.

    source
    MathOptInterface.ResultCountType
    ResultCount()

    A model attribute for the number of results available.

    Order of solutions

    A number of attributes contain an index, result_index, which is used to refer to one of the available results. Thus, result_index must be an integer between 1 and the number of available results.

    As a general rule, the first result (result_index=1) is the most important result (for example, an optimal solution or an infeasibility certificate). Other results will typically be alternate solutions that the solver found during the search for the first result.

    If a (local) optimal solution is available, that is, TerminationStatus is OPTIMAL or LOCALLY_SOLVED, the first result must correspond to the (locally) optimal solution. Other results may be alternative optimal solutions, or they may be other suboptimal solutions; use ObjectiveValue to distinguish between them.

    If a primal or dual infeasibility certificate is available, that is, TerminationStatus is INFEASIBLE or DUAL_INFEASIBLE and the corresponding PrimalStatus or DualStatus is INFEASIBILITY_CERTIFICATE, then the first result must be a certificate. Other results may be alternate certificates, or infeasible points.

    source
    MathOptInterface.ObjectiveValueType
    ObjectiveValue(result_index::Int = 1)

    A model attribute for the objective value of the primal solution result_index.

    If the solver does not have a primal value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the ObjectiveValue attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.DualObjectiveValueType
    DualObjectiveValue(result_index::Int = 1)

    A model attribute for the value of the objective function of the dual problem for the result_indexth dual result.

    If the solver does not have a dual value for the objective because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a primal solution is available), the result is undefined. Users should first check DualStatus before accessing the DualObjectiveValue attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.RelativeGapType
    RelativeGap()

    A model attribute for the final relative optimality gap.

    Warning

    The definition of this gap is solver-dependent. However, most solvers implementing this attribute define the relative gap as some variation of $\frac{|b-f|}{|f|}$, where $b$ is the best bound and $f$ is the best feasible objective value.

    source
    MathOptInterface.SimplexIterationsType
    SimplexIterations()

    A model attribute for the cumulative number of simplex iterations during the optimization process.

    For a mixed-integer program (MIP), the return value is the total simplex iterations for all nodes.

    source
    MathOptInterface.NodeCountType
    NodeCount()

    A model attribute for the total number of branch-and-bound nodes explored while solving a mixed-integer program (MIP).

    source

    ResultStatusCode

    MathOptInterface.ResultStatusCodeType
    ResultStatusCode

    An Enum of possible values for the PrimalStatus and DualStatus attributes.

    The values indicate how to interpret the result vector.

    Values

    Possible values are:

    • NO_SOLUTION: the result vector is empty.
    • FEASIBLE_POINT: the result vector is a feasible point.
    • NEARLY_FEASIBLE_POINT: the result vector is feasible if some constraint tolerances are relaxed.
    • INFEASIBLE_POINT: the result vector is an infeasible point.
    • INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.
    • NEARLY_INFEASIBILITY_CERTIFICATE: the result satisfies a relaxed criterion for a certificate of infeasibility.
    • REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.
    • NEARLY_REDUCTION_CERTIFICATE: the result satisfies a relaxed criterion for an ill-posed certificate.
    • UNKNOWN_RESULT_STATUS: the result vector contains a solution with an unknown interpretation.
    • OTHER_RESULT_STATUS: the result vector contains a solution with an interpretation not covered by one of the statuses defined above
    source
    MathOptInterface.INFEASIBILITY_CERTIFICATEConstant
    INFEASIBILITY_CERTIFICATE::ResultStatusCode

    An instance of the ResultStatusCode enum.

    INFEASIBILITY_CERTIFICATE: the result vector is an infeasibility certificate. If the PrimalStatus is INFEASIBILITY_CERTIFICATE, then the primal result vector is a certificate of dual infeasibility. If the DualStatus is INFEASIBILITY_CERTIFICATE, then the dual result vector is a proof of primal infeasibility.

    source
    MathOptInterface.REDUCTION_CERTIFICATEConstant
    REDUCTION_CERTIFICATE::ResultStatusCode

    An instance of the ResultStatusCode enum.

    REDUCTION_CERTIFICATE: the result vector is an ill-posed certificate; see this article for details. If the PrimalStatus is REDUCTION_CERTIFICATE, then the primal result vector is a proof that the dual problem is ill-posed. If the DualStatus is REDUCTION_CERTIFICATE, then the dual result vector is a proof that the primal is ill-posed.

    source

    Conflict Status

    MathOptInterface.compute_conflict!Function
    compute_conflict!(optimizer::AbstractOptimizer)

    Computes a minimal subset of constraints such that the model with the other constraint removed is still infeasible.

    Some solvers call a set of conflicting constraints an Irreducible Inconsistent Subsystem (IIS).

    See also ConflictStatus and ConstraintConflictStatus.

    Note

    If the model is modified after a call to compute_conflict!, the implementor is not obliged to purge the conflict. Any calls to the above attributes may return values for the original conflict without a warning. Similarly, when modifying the model, the conflict can be discarded.

    source
    MathOptInterface.ConflictStatusCodeType
    ConflictStatusCode

    An Enum of possible values for the ConflictStatus attribute. This attribute is meant to explain the reason why the conflict finder stopped executing in the most recent call to compute_conflict!.

    Possible values are:

    • COMPUTE_CONFLICT_NOT_CALLED: the function compute_conflict! has not yet been called
    • NO_CONFLICT_EXISTS: there is no conflict because the problem is feasible
    • NO_CONFLICT_FOUND: the solver could not find a conflict
    • CONFLICT_FOUND: at least one conflict could be found
    source
    MathOptInterface.ConflictParticipationStatusCodeType
    ConflictParticipationStatusCode

    An Enum of possible values for the ConstraintConflictStatus attribute. This attribute is meant to indicate whether a given constraint participates or not in the last computed conflict.

    Values

    Possible values are:

    • NOT_IN_CONFLICT: the constraint does not participate in the conflict
    • IN_CONFLICT: the constraint participates in the conflict
    • MAYBE_IN_CONFLICT: the constraint may participate in the conflict, the solver was not able to prove that the constraint can be excluded from the conflict
    source
    diff --git a/previews/PR3883/moi/reference/modification/index.html b/previews/PR3883/moi/reference/modification/index.html index 89317753148..79a068286dd 100644 --- a/previews/PR3883/moi/reference/modification/index.html +++ b/previews/PR3883/moi/reference/modification/index.html @@ -97,4 +97,4 @@ )

    A struct used to request a change in the quadratic coefficient of a ScalarQuadraticFunction.

    Scaling factors

    A ScalarQuadraticFunction has an implicit 0.5 scaling factor in front of the Q matrix. This modification applies to terms in the Q matrix.

    If variable_1 == variable_2, this modification sets the corresponding diagonal element of the Q matrix to new_coefficient.

    If variable_1 != variable_2, this modification is equivalent to setting both the corresponding upper- and lower-triangular elements of the Q matrix to new_coefficient.

    As a consequence:

    • to modify the term x^2 to become 2x^2, new_coefficient must be 4
    • to modify the term xy to become 2xy, new_coefficient must be 2
    source +) where {T}

    A struct used to request a change in the linear coefficients of a single variable in a vector-valued function.

    New coefficients are specified by (output_index, coefficient) tuples.

    Applicable to VectorAffineFunction and VectorQuadraticFunction.

    source diff --git a/previews/PR3883/moi/reference/nonlinear/index.html b/previews/PR3883/moi/reference/nonlinear/index.html index e2fb849fe88..e27bc7ae558 100644 --- a/previews/PR3883/moi/reference/nonlinear/index.html +++ b/previews/PR3883/moi/reference/nonlinear/index.html @@ -425,4 +425,4 @@ :(x[MOI.VariableIndex(1)] * x[MOI.VariableIndex(2)] * x[MOI.VariableIndex(3)] * x[MOI.VariableIndex(4)] >= 25.0) julia> MOI.constraint_expr(evaluator, 2) -:(x[MOI.VariableIndex(1)] ^ 2 + x[MOI.VariableIndex(2)] ^ 2 + x[MOI.VariableIndex(3)] ^ 2 + x[MOI.VariableIndex(4)] ^ 2 == 40.0)source +:(x[MOI.VariableIndex(1)] ^ 2 + x[MOI.VariableIndex(2)] ^ 2 + x[MOI.VariableIndex(3)] ^ 2 + x[MOI.VariableIndex(4)] ^ 2 == 40.0)source diff --git a/previews/PR3883/moi/reference/standard_form/index.html b/previews/PR3883/moi/reference/standard_form/index.html index 589f13d2541..4c953dc7bba 100644 --- a/previews/PR3883/moi/reference/standard_form/index.html +++ b/previews/PR3883/moi/reference/standard_form/index.html @@ -944,4 +944,4 @@ MOI.VectorOfVariables([t; vec(X)]), MOI.RootDetConeSquare(2), ) -MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeSquare}(1)source +MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.RootDetConeSquare}(1)source diff --git a/previews/PR3883/moi/reference/variables/index.html b/previews/PR3883/moi/reference/variables/index.html index 1b45064ee7d..88b7cbf0b09 100644 --- a/previews/PR3883/moi/reference/variables/index.html +++ b/previews/PR3883/moi/reference/variables/index.html @@ -63,4 +63,4 @@ )::Bool

    Return a Bool indicating whether model supports constraining a variable to belong to a set of type S either on creation of the variable with add_constrained_variable or after the variable is created with add_constraint.

    By default, this function falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VariableIndex, S) which is the correct definition for most models.

    Example

    Suppose that a solver supports only two kind of variables: binary variables and continuous variables with a lower bound. If the solver decides not to support VariableIndex-in-Binary and VariableIndex-in-GreaterThan constraints, it only has to implement add_constrained_variable for these two sets which prevents the user to add both a binary constraint and a lower bound on the same variable. Moreover, if the user adds a VariableIndex-in-GreaterThan constraint, implementing this interface (that is, supports_add_constrained_variables) enables the constraint to be transparently bridged into a supported constraint.

    source
    MathOptInterface.supports_add_constrained_variablesFunction
    supports_add_constrained_variables(
         model::ModelLike,
         S::Type{<:AbstractVectorSet}
    -)::Bool

    Return a Bool indicating whether model supports constraining a vector of variables to belong to a set of type S either on creation of the vector of variables with add_constrained_variables or after the variable is created with add_constraint.

    By default, if S is Reals then this function returns true and otherwise, it falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S) which is the correct definition for most models.

    Example

    In the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If Reals is not one of the cones supported by the solvers then it needs to implement supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false as free variables are not supported. The solvers should then implement supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true where SupportedCones is the union of all cone types that are supported; it does not have to implement the method supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones}) as it should return false and it's the default. This prevents the user to constrain the same variable in two different cones. When a VectorOfVariables-in-S is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in S and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.

    Note that there may also be sets for which !supports_add_constrained_variables(model, S) and supports_constraint(model, MOI.VectorOfVariables, S). For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding VectorOfVariables-in-PositiveSemidefiniteConeTriangle constraints, but it should not support creating variables constrained to belong to the PositiveSemidefiniteConeTriangle because the variables in PositiveSemidefiniteConeTriangle should first be created as either binary or non-negative.

    source
    MathOptInterface.is_validMethod
    is_valid(model::ModelLike, index::Index)::Bool

    Return a Bool indicating whether this index refers to a valid object in the model model.

    source
    MathOptInterface.deleteMethod
    delete(model::ModelLike, index::Index)

    Delete the referenced object from the model. Throw DeleteNotAllowed if if index cannot be deleted.

    The following modifications also take effect if Index is VariableIndex:

    • If index used in the objective function, it is removed from the function, that is, it is substituted for zero.
    • For each func-in-set constraint of the model:
      • If func isa VariableIndex and func == index then the constraint is deleted.
      • If func isa VectorOfVariables and index in func.variables then
        • if length(func.variables) == 1 is one, the constraint is deleted;
        • if length(func.variables) > 1 and supports_dimension_update(set) then then the variable is removed from func and set is replaced by update_dimension(set, MOI.dimension(set) - 1).
        • Otherwise, a DeleteNotAllowed error is thrown.
      • Otherwise, the variable is removed from func, that is, it is substituted for zero.
    source
    MathOptInterface.deleteMethod
    delete(model::ModelLike, indices::Vector{R<:Index}) where {R}

    Delete the referenced objects in the vector indices from the model. It may be assumed that R is a concrete type. The default fallback sequentially deletes the individual items in indices, although specialized implementations may be more efficient.

    source

    Attributes

    MathOptInterface.VariableNameType
    VariableName()

    A variable attribute for a string identifying the variable. It is valid for two variables to have the same name; however, variables with duplicate names cannot be looked up using get. It has a default value of "" if not set`.

    source
    MathOptInterface.VariablePrimalStartType
    VariablePrimalStart()

    A variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or nothing (unset).

    source
    MathOptInterface.VariablePrimalType
    VariablePrimal(result_index::Int = 1)

    A variable attribute for the assignment to some primal variable's value in result result_index. If result_index is omitted, it is 1 by default.

    If the solver does not have a primal value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariablePrimal attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.VariableBasisStatusType
    VariableBasisStatus(result_index::Int = 1)

    A variable attribute for the BasisStatusCode of a variable in result result_index, with respect to an available optimal solution basis.

    If the solver does not have a basis status for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariableBasisStatus attribute.

    See ResultCount for information on how the results are ordered.

    source
    +)::Bool

    Return a Bool indicating whether model supports constraining a vector of variables to belong to a set of type S either on creation of the vector of variables with add_constrained_variables or after the variable is created with add_constraint.

    By default, if S is Reals then this function returns true and otherwise, it falls back to supports_add_constrained_variables(model, Reals) && supports_constraint(model, MOI.VectorOfVariables, S) which is the correct definition for most models.

    Example

    In the standard conic form (see Duality), the variables are grouped into several cones and the constraints are affine equality constraints. If Reals is not one of the cones supported by the solvers then it needs to implement supports_add_constrained_variables(::Optimizer, ::Type{Reals}) = false as free variables are not supported. The solvers should then implement supports_add_constrained_variables(::Optimizer, ::Type{<:SupportedCones}) = true where SupportedCones is the union of all cone types that are supported; it does not have to implement the method supports_constraint(::Type{VectorOfVariables}, Type{<:SupportedCones}) as it should return false and it's the default. This prevents the user to constrain the same variable in two different cones. When a VectorOfVariables-in-S is added, the variables of the vector have already been created so they already belong to given cones. If bridges are enabled, the constraint will therefore be bridged by adding slack variables in S and equality constraints ensuring that the slack variables are equal to the corresponding variables of the given constraint function.

    Note that there may also be sets for which !supports_add_constrained_variables(model, S) and supports_constraint(model, MOI.VectorOfVariables, S). For instance, suppose a solver supports positive semidefinite variable constraints and two types of variables: binary variables and nonnegative variables. Then the solver should support adding VectorOfVariables-in-PositiveSemidefiniteConeTriangle constraints, but it should not support creating variables constrained to belong to the PositiveSemidefiniteConeTriangle because the variables in PositiveSemidefiniteConeTriangle should first be created as either binary or non-negative.

    source
    MathOptInterface.is_validMethod
    is_valid(model::ModelLike, index::Index)::Bool

    Return a Bool indicating whether this index refers to a valid object in the model model.

    source
    MathOptInterface.deleteMethod
    delete(model::ModelLike, index::Index)

    Delete the referenced object from the model. Throw DeleteNotAllowed if if index cannot be deleted.

    The following modifications also take effect if Index is VariableIndex:

    • If index used in the objective function, it is removed from the function, that is, it is substituted for zero.
    • For each func-in-set constraint of the model:
      • If func isa VariableIndex and func == index then the constraint is deleted.
      • If func isa VectorOfVariables and index in func.variables then
        • if length(func.variables) == 1 is one, the constraint is deleted;
        • if length(func.variables) > 1 and supports_dimension_update(set) then then the variable is removed from func and set is replaced by update_dimension(set, MOI.dimension(set) - 1).
        • Otherwise, a DeleteNotAllowed error is thrown.
      • Otherwise, the variable is removed from func, that is, it is substituted for zero.
    source
    MathOptInterface.deleteMethod
    delete(model::ModelLike, indices::Vector{R<:Index}) where {R}

    Delete the referenced objects in the vector indices from the model. It may be assumed that R is a concrete type. The default fallback sequentially deletes the individual items in indices, although specialized implementations may be more efficient.

    source

    Attributes

    MathOptInterface.VariableNameType
    VariableName()

    A variable attribute for a string identifying the variable. It is valid for two variables to have the same name; however, variables with duplicate names cannot be looked up using get. It has a default value of "" if not set`.

    source
    MathOptInterface.VariablePrimalStartType
    VariablePrimalStart()

    A variable attribute for the initial assignment to some primal variable's value that the optimizer may use to warm-start the solve. May be a number or nothing (unset).

    source
    MathOptInterface.VariablePrimalType
    VariablePrimal(result_index::Int = 1)

    A variable attribute for the assignment to some primal variable's value in result result_index. If result_index is omitted, it is 1 by default.

    If the solver does not have a primal value for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariablePrimal attribute.

    See ResultCount for information on how the results are ordered.

    source
    MathOptInterface.VariableBasisStatusType
    VariableBasisStatus(result_index::Int = 1)

    A variable attribute for the BasisStatusCode of a variable in result result_index, with respect to an available optimal solution basis.

    If the solver does not have a basis status for the variable because the result_index is beyond the available solutions (whose number is indicated by the ResultCount attribute), getting this attribute must throw a ResultIndexBoundsError. Otherwise, if the result is unavailable for another reason (for instance, only a dual solution is available), the result is undefined. Users should first check PrimalStatus before accessing the VariableBasisStatus attribute.

    See ResultCount for information on how the results are ordered.

    source
    diff --git a/previews/PR3883/moi/release_notes/index.html b/previews/PR3883/moi/release_notes/index.html index 289304a2650..fe218438d2d 100644 --- a/previews/PR3883/moi/release_notes/index.html +++ b/previews/PR3883/moi/release_notes/index.html @@ -31,4 +31,4 @@ end write(path, s) end -end

    v0.9.22 (May 22, 2021)

    This release contains backports from the ongoing development of the v0.10 release.

    • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
    • Improved performance of Utilities.is_canonical.
    • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
    • Fixed performance regression of Utilities.Model.
    • Fixed ordering of objective setting in parser.

    v0.9.21 (April 23, 2021)

    • Added supports_shift_constant.
    • Improve performance of bridging quadratic constraints.
    • Add precompilation statements.
    • Large improvements to the documentation.
    • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
    • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
    • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

    v0.9.20 (February 20, 2021)

    • Improved performance of Utilities.ScalarFunctionIterator
    • Added support for compute_conflict to MOI layers
    • Added test with zero off-diagonal quadratic term in objective
    • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
    • Fixed modification of un-set objective
    • Fixed function modification with duplicate terms
    • Made unit tests abort without failing if the problem class is not supported
    • Formatted code with JuliaFormatter
    • Clarified BasisStatusCode's docstring

    v0.9.19 (December 1, 2020)

    • Added CallbackNodeStatus attribute
    • Added bridge from GreaterThan or LessThan to Interval
    • Added tests for infeasibility certificates and double optimize
    • Fixed support for Julia v1.6
    • Re-organized MOI docs and added documentation for adding a test

    v0.9.18 (November 3, 2020)

    • Various improvements for working with complex numbers
    • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

    v0.9.17 (September 21, 2020)

    • Fixed CleverDict with variable of negative index value
    • Implement supports_add_constrained_variable for MockOptimizer

    v0.9.16 (September 17, 2020)

    • Various fixes:
      • 32-bit support
      • CleverDict with abstract value type
      • Checks in test suite

    v0.9.15 (September 14, 2020)

    • Bridges improvements:
      • (R)SOCtoNonConvexQuad bridge
      • ZeroOne bridge
      • Use supports_add_constrained_variable in LazyBridgeOptimizer
      • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
      • Prioritize constraining variables on creation according to these costs
      • Refactor bridge debugging
    • Large performance improvements across all submodules
    • Lots of documentation improvements
    • FileFormats improvements:
      • Update MathOptFormat to v0.5
      • Fix supported objectives in FileFormats
    • Testing improvements:
      • Add name option for basic_constraint_test
    • Bug fixes and missing methods
      • Add length for iterators
      • Fix bug with duplicate terms
      • Fix order of LinearOfConstraintIndices

    v0.9.14 (May 30, 2020)

    • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
    • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
    • Documentation improvements:
      • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
      • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
    • Utilities improvements:
      • Fix is_canonical for quadratic functions (#1081, #1089).
      • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
      • Add support for custom objective functions for UniversalFallback (#1086).
      • Deterministic ordering of constraints in UniversalFallback (#1088).
    • Testing improvements:
      • Add NormOneCone/NormInfinityCone tests (#1045).
    • Bridges improvements:
      • Add bridges from Semiinteger and Semicontinuous (#1059).
      • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
      • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
      • Fix NormOne/NormInf bridges with nonzero constants (#1045).
      • Fix StackOverflow in debug (#1063).
    • FileFormats improvements:
      • [SDPA] Implement the extension for integer variables (#1079).
      • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
      • [SDPA] No scaling of off-diagonal coefficient (#1076).
      • [SDPA] Add missing negation of constant (#1075).

    v0.9.13 (March 24, 2020)

    • Added tests for Semicontinuous and Semiinteger variables (#1033).
    • Added tests for using ExprGraphs from NLP evaluators (#1043).
    • Update version compatibilities of dependencies (#1034, #1051, #1052).
    • Fixed typos in documentation (#1044).

    v0.9.12 (February 28, 2020)

    • Fixed writing NLPBlock in MathOptFormat (#1037).
    • Fixed MockOptimizer for result attributes with non-one result index (#1039).
    • Updated test template with instantiate (#1032).

    v0.9.11 (February 21, 2020)

    • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
    • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
    • Fixed typos in documentation (#1022, #1024).
    • Fixed warning of unsupported attribute (#1027).
    • Added more rootdet/logdet conic tests (#1026).
    • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

    v0.9.10 (January 31, 2020)

    • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
    • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
    • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
    • Added supports_constrained_variable(s) (#1004).
    • Added dual_set_type (#1002).
    • Added tests for vector specialized version of delete (#989, #1011).
    • Added PSD3 test (#1007).
    • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
    • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
    • Fixed Utilities.vectorize for empty vector (#1003).
    • Fixed free variables in LP writer (#1006).

    v0.9.9 (December 29, 2019)

    • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
    • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
    • Updated to MutableArithmetics v0.2 (#981).
    • Added MutableArithmetics.promote_operation allocation tests (#975).
    • Fixed inference issue on Julia v1.1 (#982).

    v0.9.8 (December 19, 2019)

    • Implemented MutableArithmetics API (#924).
    • Fixed callbacks with CachingOptimizer (#959).
    • Fixed MOI.dimension for MOI.Complements (#948).
    • Added fallback for add_variables (#972).
    • Added is_diagonal_vectorized_index utility (#965).
    • Improved linear constraints display in manual (#963, #964).
    • Bridges improvements:
      • Added IndicatorSet to SOS1 bridge (#877).
      • Added support for starting values for Variable.VectorizeBridge (#944).
      • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
      • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
      • Fixed choice between variable or constraint bridges for constrained variables (#973).
      • Improve performance of bridge shortest path (#945, #946, #956).
      • Added docstring for test_delete_bridge (#954).
      • Added Variable bridge tests (#952).

    v0.9.7 (October 30, 2019)

    • Implemented _result_index_field for NLPBlockDual (#934).
    • Fixed copy of model with starting values for vector constraints (#941).
    • Bridges improvements:
      • Improved performance of add_bridge and added has_bridge (#935).
      • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
      • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

    v0.9.6 (October 25, 2019)

    • Added complementarity constraints (#913).
    • Allowed ModelLike objects as value of attributes (#928).
    • Testing improvements:
      • Added dual_objective_value option to MOI.Test.TestConfig (#922).
      • Added InvalidIndex tests in basic_constraint_tests (#921).
      • Added tests for the constant term in indicator constraint (#929).
    • Bridges improvements:
      • Added support for starting values for Functionize bridges (#923).
      • Added variable indices context to variable bridges (#920).
      • Fixed a typo in printing o debug_supports (#927).

    v0.9.5 (October 9, 2019)

    • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
    • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
    • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
    • Bridges improvements:
      • Added debug utilities for unsupported variable/constraint/objective (#861).
      • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
      • Fixed result_index with objective bridges (#911).

    v0.9.4 (October 2, 2019)

    • Added solver-independent MIP callbacks (#782).
    • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
    • Added tests for result count of solution attributes (#901, #904).
    • Added NumberOfThreads attribute (#892).
    • Added Utilities.get_bounds to get the bounds on a variable (#890).
    • Added a note on duplicate coefficients in documentation (#581).
    • Added result index in ConstraintBasisStatus (#898).
    • Added extension dictionary to Utilities.Model (#884, #895).
    • Fixed deletion of constrained variables for CachingOptimizer (#905).
    • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
    • Bridges improvements:
      • Added Variable.RSOCtoSOCBridge (#907).
      • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

    v0.9.3 (September 20, 2019)

    • Fixed ambiguity detected in Julia v1.3 (#891, #893).
    • Fixed missing sets from ListOfSupportedConstraints (#880).
    • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
    • Added extension dictionary to MOIU.Model (#884).
    • Implemented MOI.get for function and set for GeoMeanBridge (#888).
    • Updated documentation for SingleVariable indices and bridges (#885).
    • Testing improvements:
      • Added more comprehensive tests for names (#882).
      • Added tests for SingleVariable duals (#883).
      • Added tests for DualExponentialCone and DualPowerCone (#873).
    • Improvements for arbitrary coefficient type:
      • Fixed == for sets with mutable fields (#887).
      • Removed some Float64 assumptions in bridges (#878).
      • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

    v0.9.2 (September 5, 2019)

    • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
    • Generalized contlinear tests for arbitrary coefficient type (#855).
    • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
    • Fixed Allocate-Load copy for single variable constraints (#856).
    • Bridges improvements:
      • Add objective bridges (#789).
      • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
      • Added Variable.SOCtoRSOCBridge (#865).
      • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
      • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

    v0.9.1 (August 22, 2019)

    • Fix support for Julia v1.2 (#834).
    • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
    • Added tests to MOI.Test.nametest (#833).
    • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
    • Implements operate for operators * and / between vector function and constant (#837).
    • Implements show for MOI.Utilities.IndexMap (#847).
    • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
    • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

    v0.9.0 (August 13, 2019)

    • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
    • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
    • add_constrained_variable and add_constrained_variables were added (#759).
    • Support for indicator constraints was added (#709, #712).
    • DualObjectiveValue attribute was added (#473).
    • RawParameter attribute was added (#733).
    • A dual_set function was added (#804).
    • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
    • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
    • The field of ObjectiveValue was renamed to result_index (#729).
    • The _constant and Utilities.getconstant function were renamed to constant
    • REDUCTION_CERTIFICATE result status was added (#734).
    • Abstract matrix sets were added (#731).
    • Testing improvements:
      • The testing guideline was updated (#728).
      • Quadratic tests were added (#697).
      • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
      • A rotated second-order cone test was added (#759).
      • A power cone test was added (#768).
      • Tests for ZeroOne variables with variable bounds were added (#772).
      • An unbounded test was added (#773).
      • Existing tests had a few updates (#702, #703, #763).
    • Documentation improvements:
      • Added a section on CachingOptimizer (#777).
      • Added a section on UniversalFallback, Model and @model (#762).
      • Transition the knapsack example to a doctest with MockOptimizer (#786).
    • Utilities improvements:
      • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
      • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
      • Implement optimizer attributes for CachingOptimizer (#745).
      • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
      • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
      • Fix a type piracy of operate (#784).
      • The load_constraint fallback signature was fixed (#760).
      • The set_dot function was extended to work with sparse arrays (#805).
    • Bridges improvements:
      • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
      • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
      • Fix constraint attributes for bridges (#699).
      • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
      • Variable bridges were added in (#759).
      • Various improvements (#746, #747).

    v0.8.4 (March 13, 2019)

    • Performance improvement in default_copy_to and bridge optimizer (#696).
    • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
    • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
    • Minor typo fixes (#694).

    v0.8.3 (March 6, 2019)

    • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
    • Fix variable deletion with SingleVariable objective function (#690).
    • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
    • Error message improvements (#673, #685, #686, #688).
    • Documentation improvements (#682, #683, #687).
    • Basis status:
      • Remove VariableBasisStatus (#679).
      • Test ConstraintBasisStatus and implement it in bridges (#678).
    • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
    • Implement division between a quadratic function and a number (#675).

    v0.8.2 (February 7, 2019)

    • Add RawStatusString attribute (#629).
    • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
    • Make scalar MOI functions act as scalars in broadcast (#646).
    • Add function utilities:
      • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
      • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
    • Improve support for starting values:
      • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
      • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
      • Add a test in contlineartest with partially set VariablePrimalStart.
    • Bridges improvements:
      • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
      • Add Slack bridges (#610, #650).
      • Add FlipSign bridges (#658).
    • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
    • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
    • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

    v0.8.1 (January 7, 2019)

    • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
    • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
    • Allow custom constraint types with full_bridge_optimizer (#617).
    • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

    v0.8.0 (December 18, 2018)

    • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
    • Rename CachingOptimizer methods for style compliance.
    • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

    v0.7.0 (December 13, 2018)

    • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
    • Check supports_default_copy_to in tests (#594).
    • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
    • Add perspective dimension to log-det cone (#593).

    v0.6.4 (November 27, 2018)

    • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
    • Add a solver naming guideline (#578).
    • Make FeasibilitySense the default ObjectiveSense (#579).
    • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
    • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

    v0.6.3 (November 16, 2018)

    • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
    • Attributes may now be partially set (some values could be nothing). (#563)
    • Performance improvements in Utilities.Model (#549, #567, #568)
    • Fix bug in QuadtoSOC (#558).
    • New supports_default_copy_to method that optimizers should implement to control caching behavior.
    • Documentation improvements.

    v0.6.2 (October 26, 2018)

    • Improve hygiene of @model macro (#544).
    • Fix bug in copy tests (#543).
    • Fix bug in UniversalFallback attribute getter (#540).
    • Allow all correct solutions for solve_blank_obj unit test (#537).
    • Add errors for Allocate-Load and bad constraints (#534).
    • [performance] Add specialized implementation of hash for VariableIndex (#533).
    • [performance] Construct the name to object dictionaries lazily in model (#535).
    • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

    v0.6.1 (September 22, 2018)

    • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
    • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
    • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
    • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

    v0.6.0 (August 30, 2018)

    • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
    • Rename functions according to the JuMP style guide:
      • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
      • set! -> set;
      • addvariable[s]! -> add_variable[s];
      • supportsconstraint -> supports_constraint;
      • addconstraint[s]! -> add_constraint[s];
      • isvalid -> is_valid;
      • isempty -> is_empty;
      • Base.delete! -> delete;
      • modify! -> modify;
      • transform! -> transform;
      • initialize! -> initialize;
      • write -> write_to_file; and
      • read! -> read_from_file.
    • Remove free! (use Base.finalize instead).
    • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
    • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
    • Add tests for ObjectiveBound.
    • Add test for empty rows in vector linear constraint.
    • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
    • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

    v0.5.0 (August 5, 2018)

    • Fix names with CachingOptimizer.
    • Cleanup thanks to @mohamed82008.
    • Added a universal fallback for constraints.
    • Fast utilities for function canonicalization thanks to @rdeits.
    • Renamed dimension field to side_dimension in the context of matrix-like sets.
    • New and improved tests for cases like duplicate terms and ObjectiveBound.
    • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
    • The API for copy! is updated to remove the CopyResult type.
    • Updates for the new JuMP style guide.

    v0.4.1 (June 28, 2018)

    • Fixes vector function modification on 32 bits.
    • Fixes Bellman-Ford algorithm for bridges.
    • Added an NLP test with FeasibilitySense.
    • Update modification documentation.

    v0.4.0 (June 23, 2018)

    • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
    • Added modify_lhs to TestConfig.
    • Additional unit tests for optimizers.
    • Added a type parameter to CachingOptimizer for the optimizer field.
    • New API for problem modification (#388)
    • Tests pass without deprecation warnings on Julia 0.7.
    • Small fixes and documentation updates.

    v0.3.0 (May 25, 2018)

    • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
    • Improvements to MockOptimizer.
    • Significant changes to Bridges.
    • New and improved unit tests.
    • Fixes for Julia 0.7.

    v0.2.0 (April 24, 2018)

    • Improvements to and better coverage of Tests.
    • Documentation fixes.
    • SolverName attribute.
    • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
    • Addition of NLP tests.
    • Introduction of UniversalFallback.
    • copynames keyword argument to MOI.copy!.
    • Add Bridges submodule.

    v0.1.0 (February 28, 2018)

    • Initial public release.
    • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
    +end

    v0.9.22 (May 22, 2021)

    This release contains backports from the ongoing development of the v0.10 release.

    • Improved type inference in Utilities, Bridges and FileFormats submodules to reduce latency.
    • Improved performance of Utilities.is_canonical.
    • Fixed Utilities.pass_nonvariable_constraints with bridged variables.
    • Fixed performance regression of Utilities.Model.
    • Fixed ordering of objective setting in parser.

    v0.9.21 (April 23, 2021)

    • Added supports_shift_constant.
    • Improve performance of bridging quadratic constraints.
    • Add precompilation statements.
    • Large improvements to the documentation.
    • Fix a variety of inference issues, benefiting precompilation and reducing initial latency.
    • RawParameters are now ignored when resetting a CachingOptimizer. Previously, changing the underlying optimizer after RawParameters were set would throw an error.
    • Utilities.AbstractModel is being refactored. This may break users interacting with private fields of a model generated using @model.

    v0.9.20 (February 20, 2021)

    • Improved performance of Utilities.ScalarFunctionIterator
    • Added support for compute_conflict to MOI layers
    • Added test with zero off-diagonal quadratic term in objective
    • Fixed double deletion of nested bridged SingleVariable/VectorOfVariables constraints
    • Fixed modification of un-set objective
    • Fixed function modification with duplicate terms
    • Made unit tests abort without failing if the problem class is not supported
    • Formatted code with JuliaFormatter
    • Clarified BasisStatusCode's docstring

    v0.9.19 (December 1, 2020)

    • Added CallbackNodeStatus attribute
    • Added bridge from GreaterThan or LessThan to Interval
    • Added tests for infeasibility certificates and double optimize
    • Fixed support for Julia v1.6
    • Re-organized MOI docs and added documentation for adding a test

    v0.9.18 (November 3, 2020)

    • Various improvements for working with complex numbers
    • Added GeoMeantoRelEntrBridge to bridge a GeometricMeanCone constraint to a relative entropy constraint

    v0.9.17 (September 21, 2020)

    • Fixed CleverDict with variable of negative index value
    • Implement supports_add_constrained_variable for MockOptimizer

    v0.9.16 (September 17, 2020)

    • Various fixes:
      • 32-bit support
      • CleverDict with abstract value type
      • Checks in test suite

    v0.9.15 (September 14, 2020)

    • Bridges improvements:
      • (R)SOCtoNonConvexQuad bridge
      • ZeroOne bridge
      • Use supports_add_constrained_variable in LazyBridgeOptimizer
      • Exposed VariableBridgeCost and ConstraintBridgeCost attributes
      • Prioritize constraining variables on creation according to these costs
      • Refactor bridge debugging
    • Large performance improvements across all submodules
    • Lots of documentation improvements
    • FileFormats improvements:
      • Update MathOptFormat to v0.5
      • Fix supported objectives in FileFormats
    • Testing improvements:
      • Add name option for basic_constraint_test
    • Bug fixes and missing methods
      • Add length for iterators
      • Fix bug with duplicate terms
      • Fix order of LinearOfConstraintIndices

    v0.9.14 (May 30, 2020)

    • Add a solver-independent interface for accessing the set of conflicting constraints an Irreducible Inconsistent Subsystem (#1056).
    • Bump JSONSchema dependency from v0.2 to v0.3 (#1090).
    • Documentation improvements:
      • Fix typos (#1054, #1060, #1061, #1064, #1069, #1070).
      • Remove the outdated recommendation for a package implementing MOI for a solver XXX to be called MathOptInterfaceXXX (#1087).
    • Utilities improvements:
      • Fix is_canonical for quadratic functions (#1081, #1089).
      • Implement add_constrained_variable[s] for CachingOptimizer so that it is added as constrained variables to the underlying optimizer (#1084).
      • Add support for custom objective functions for UniversalFallback (#1086).
      • Deterministic ordering of constraints in UniversalFallback (#1088).
    • Testing improvements:
      • Add NormOneCone/NormInfinityCone tests (#1045).
    • Bridges improvements:
      • Add bridges from Semiinteger and Semicontinuous (#1059).
      • Implement getting ConstraintSet for Variable.FlipSignBridge (#1066).
      • Fix setting ConstraintFunction for Constraint.ScalarizeBridge (#1093).
      • Fix NormOne/NormInf bridges with nonzero constants (#1045).
      • Fix StackOverflow in debug (#1063).
    • FileFormats improvements:
      • [SDPA] Implement the extension for integer variables (#1079).
      • [SDPA] Ignore comments after m and nblocks and detect dat-s extension (#1077).
      • [SDPA] No scaling of off-diagonal coefficient (#1076).
      • [SDPA] Add missing negation of constant (#1075).

    v0.9.13 (March 24, 2020)

    • Added tests for Semicontinuous and Semiinteger variables (#1033).
    • Added tests for using ExprGraphs from NLP evaluators (#1043).
    • Update version compatibilities of dependencies (#1034, #1051, #1052).
    • Fixed typos in documentation (#1044).

    v0.9.12 (February 28, 2020)

    • Fixed writing NLPBlock in MathOptFormat (#1037).
    • Fixed MockOptimizer for result attributes with non-one result index (#1039).
    • Updated test template with instantiate (#1032).

    v0.9.11 (February 21, 2020)

    • Add an option for the model created by Utilities.@model to be a subtype of AbstractOptimizer (#1031).
    • Described dual cone in docstrings of GeoMeanCone and RelativeEntropyCone (#1018, #1028).
    • Fixed typos in documentation (#1022, #1024).
    • Fixed warning of unsupported attribute (#1027).
    • Added more rootdet/logdet conic tests (#1026).
    • Implemented ConstraintDual for Constraint.GeoMeanBridge, Constraint.RootDetBridge and Constraint.LogDetBridge and test duals in tests with GeoMeanCone and RootDetConeTriangle and LogDetConeTriangle cones (#1025, #1026).

    v0.9.10 (January 31, 2020)

    • Added OptimizerWithAttributes grouping an optimizer constructor and a list of optimizer attributes (#1008).
    • Added RelativeEntropyCone with corresponding bridge into exponential cone constraints (#993).
    • Added NormSpectralCone and NormNuclearCone with corresponding bridges into positive semidefinite constraints (#976).
    • Added supports_constrained_variable(s) (#1004).
    • Added dual_set_type (#1002).
    • Added tests for vector specialized version of delete (#989, #1011).
    • Added PSD3 test (#1007).
    • Clarified dual solution of Tests.pow1v and Tests.pow1f (#1013).
    • Added support for EqualTo and Zero in Bridges.Constraint.SplitIntervalBridge (#1005).
    • Fixed Utilities.vectorize for empty vector (#1003).
    • Fixed free variables in LP writer (#1006).

    v0.9.9 (December 29, 2019)

    • Incorporated MathOptFormat.jl as the FileFormats submodule. FileFormats provides readers and writers for a number of standard file formats and MOF, a file format specialized for MOI (#969).
    • Improved performance of deletion of vector of variables in MOI.Utilities.Model (#983).
    • Updated to MutableArithmetics v0.2 (#981).
    • Added MutableArithmetics.promote_operation allocation tests (#975).
    • Fixed inference issue on Julia v1.1 (#982).

    v0.9.8 (December 19, 2019)

    • Implemented MutableArithmetics API (#924).
    • Fixed callbacks with CachingOptimizer (#959).
    • Fixed MOI.dimension for MOI.Complements (#948).
    • Added fallback for add_variables (#972).
    • Added is_diagonal_vectorized_index utility (#965).
    • Improved linear constraints display in manual (#963, #964).
    • Bridges improvements:
      • Added IndicatorSet to SOS1 bridge (#877).
      • Added support for starting values for Variable.VectorizeBridge (#944).
      • Fixed MOI.add_constraints with non-bridged variable constraint on bridged variable (#951).
      • Fixed corner cases and docstring of GeoMeanBridge (#961, #962, #966).
      • Fixed choice between variable or constraint bridges for constrained variables (#973).
      • Improve performance of bridge shortest path (#945, #946, #956).
      • Added docstring for test_delete_bridge (#954).
      • Added Variable bridge tests (#952).

    v0.9.7 (October 30, 2019)

    • Implemented _result_index_field for NLPBlockDual (#934).
    • Fixed copy of model with starting values for vector constraints (#941).
    • Bridges improvements:
      • Improved performance of add_bridge and added has_bridge (#935).
      • Added AbstractSetMapBridge for bridges between sets S1, S2 such that there is a linear map A such that A*S1 = S2 (#933).
      • Added support for starting values for FlipSignBridge, VectorizeBridge, ScalarizeBridge, SlackBridge, SplitIntervalBridge, RSOCBridge, SOCRBridge NormInfinityBridge, SOCtoPSDBridge and RSOCtoPSDBridge (#933, #936, #937, #938, #939).

    v0.9.6 (October 25, 2019)

    • Added complementarity constraints (#913).
    • Allowed ModelLike objects as value of attributes (#928).
    • Testing improvements:
      • Added dual_objective_value option to MOI.Test.TestConfig (#922).
      • Added InvalidIndex tests in basic_constraint_tests (#921).
      • Added tests for the constant term in indicator constraint (#929).
    • Bridges improvements:
      • Added support for starting values for Functionize bridges (#923).
      • Added variable indices context to variable bridges (#920).
      • Fixed a typo in printing o debug_supports (#927).

    v0.9.5 (October 9, 2019)

    • Clarified PrimalStatus/DualStatus to be NO_SOLUTION if result_index is out of bounds (#912).
    • Added tolerance for checks and use ResultCount + 1 for the result_index in MOI.Test.solve_result_status (#910, #917).
    • Use 0.5 instead of 2.0 for power in PowerCone in basic_constraint_test (#916).
    • Bridges improvements:
      • Added debug utilities for unsupported variable/constraint/objective (#861).
      • Fixed deletion of variables in bridged VectorOfVariables constraints (#909).
      • Fixed result_index with objective bridges (#911).

    v0.9.4 (October 2, 2019)

    • Added solver-independent MIP callbacks (#782).
    • Implements submit for Utilities.CachingOptimizer and Bridges.AbstractBridgeOptimizer (#906).
    • Added tests for result count of solution attributes (#901, #904).
    • Added NumberOfThreads attribute (#892).
    • Added Utilities.get_bounds to get the bounds on a variable (#890).
    • Added a note on duplicate coefficients in documentation (#581).
    • Added result index in ConstraintBasisStatus (#898).
    • Added extension dictionary to Utilities.Model (#884, #895).
    • Fixed deletion of constrained variables for CachingOptimizer (#905).
    • Implemented Utilities.shift_constraint for Test.UnknownScalarSet (#896).
    • Bridges improvements:
      • Added Variable.RSOCtoSOCBridge (#907).
      • Implemented MOI.get for ConstraintFunction/ConstraintSet for Bridges.Constraint.SquareBridge (#899).

    v0.9.3 (September 20, 2019)

    • Fixed ambiguity detected in Julia v1.3 (#891, #893).
    • Fixed missing sets from ListOfSupportedConstraints (#880).
    • Fixed copy of VectorOfVariables constraints with duplicate indices (#886).
    • Added extension dictionary to MOIU.Model (#884).
    • Implemented MOI.get for function and set for GeoMeanBridge (#888).
    • Updated documentation for SingleVariable indices and bridges (#885).
    • Testing improvements:
      • Added more comprehensive tests for names (#882).
      • Added tests for SingleVariable duals (#883).
      • Added tests for DualExponentialCone and DualPowerCone (#873).
    • Improvements for arbitrary coefficient type:
      • Fixed == for sets with mutable fields (#887).
      • Removed some Float64 assumptions in bridges (#878).
      • Automatic selection of Constraint.[Scalar|Vector]FunctionizeBridge (#889).

    v0.9.2 (September 5, 2019)

    • Implemented model printing for MOI.ModelLike and specialized it for models defined in MOI (864).
    • Generalized contlinear tests for arbitrary coefficient type (#855).
    • Fixed supports_constraint for Semiinteger and Semicontinuous and supports for ObjectiveFunction (#859).
    • Fixed Allocate-Load copy for single variable constraints (#856).
    • Bridges improvements:
      • Add objective bridges (#789).
      • Fixed Variable.RSOCtoPSDBridge for dimension 2 (#869).
      • Added Variable.SOCtoRSOCBridge (#865).
      • Added Constraint.SOCRBridge and disable MOI.Bridges.Constraint.SOCtoPSDBridge (#751).
      • Fixed added_constraint_types for Contraint.LogDetBridge and Constraint.RootDetBridge (#870).

    v0.9.1 (August 22, 2019)

    • Fix support for Julia v1.2 (#834).
    • L1 and L∞ norm epigraph cones and corresponding bridges to LP were added (#818).
    • Added tests to MOI.Test.nametest (#833).
    • Fix MOI.Test.soc3test for solvers not supporting infeasibility certificates (#839).
    • Implements operate for operators * and / between vector function and constant (#837).
    • Implements show for MOI.Utilities.IndexMap (#847).
    • Fix corner cases for mapping of variables in MOI.Utilities.CachingOptimizer and substitution of variables in MOI.Bridges.AbstractBridgeOptimizer (#848).
    • Fix transformation of constant terms for MOI.Bridges.Constraint.SOCtoPSDBridge and MOI.Bridges.Constraint.RSOCtoPSDBridge (#840).

    v0.9.0 (August 13, 2019)

    • Support for Julia v0.6 and v0.7 was dropped (#714, #717).
    • A MOI.Utilities.Model implementation of ModelLike, this should replace most use cases of MOI.Utilities.@model (#781).
    • add_constrained_variable and add_constrained_variables were added (#759).
    • Support for indicator constraints was added (#709, #712).
    • DualObjectiveValue attribute was added (#473).
    • RawParameter attribute was added (#733).
    • A dual_set function was added (#804).
    • A Benchmarks submodule was added to facilitate solver benchmarking (#769).
    • A submit function was added, this may for instance allow the user to submit solutions or cuts to the solver from a callback (#775).
    • The field of ObjectiveValue was renamed to result_index (#729).
    • The _constant and Utilities.getconstant function were renamed to constant
    • REDUCTION_CERTIFICATE result status was added (#734).
    • Abstract matrix sets were added (#731).
    • Testing improvements:
      • The testing guideline was updated (#728).
      • Quadratic tests were added (#697).
      • Unit tests for RawStatusString, SolveTime, Silent and SolverName were added (#726, #741).
      • A rotated second-order cone test was added (#759).
      • A power cone test was added (#768).
      • Tests for ZeroOne variables with variable bounds were added (#772).
      • An unbounded test was added (#773).
      • Existing tests had a few updates (#702, #703, #763).
    • Documentation improvements:
      • Added a section on CachingOptimizer (#777).
      • Added a section on UniversalFallback, Model and @model (#762).
      • Transition the knapsack example to a doctest with MockOptimizer (#786).
    • Utilities improvements:
      • A CleverDict utility was added for a vector that automatically transform into a dictionary once a first index is removed (#767).
      • The Utilities.constant function was renamed to Utilities.constant_vector (#740).
      • Implement optimizer attributes for CachingOptimizer (#745).
      • Rename Utilities.add_scalar_constraint to Utilities.normalize_and_add_constraint (#801).
      • operate with vcat, SingleVariable and VectorOfVariables now returns a VectorOfVariables (#616).
      • Fix a type piracy of operate (#784).
      • The load_constraint fallback signature was fixed (#760).
      • The set_dot function was extended to work with sparse arrays (#805).
    • Bridges improvements:
      • The bridges no longer store the constraint function and set before it is bridged, the bridges now have to implement ConstraintFunction and ConstraintSet if the user wants to recover them. As a consequence, the @bridge macro was removed (#722).
      • Bridge are now instantiated with a bridge_constraint function instead of using a constructor (#730).
      • Fix constraint attributes for bridges (#699).
      • Constraint bridges were moved to the Bridges/Constraint submodule so they should now inherit from MOI.Bridges.Constraint.Abstract and should implement MOI.Bridges.Constraint.concrete_bridge_type instead of MOI.Bridges.concrete_bridge_type (#756).
      • Variable bridges were added in (#759).
      • Various improvements (#746, #747).

    v0.8.4 (March 13, 2019)

    • Performance improvement in default_copy_to and bridge optimizer (#696).
    • Add Silent and implement setting optimizer attributes in caching and mock optimizers (#695).
    • Add Functionize bridges (SingleVariable and VectorOfVariables) (#659).
    • Minor typo fixes (#694).

    v0.8.3 (March 6, 2019)

    • Use zero constant in scalar constraint function of MOI.Test.copytest (#691).
    • Fix variable deletion with SingleVariable objective function (#690).
    • Fix LazyBridgeOptimizer with bridges that add no constraints (#689).
    • Error message improvements (#673, #685, #686, #688).
    • Documentation improvements (#682, #683, #687).
    • Basis status:
      • Remove VariableBasisStatus (#679).
      • Test ConstraintBasisStatus and implement it in bridges (#678).
    • Fix inference of NumberOfVariables and NumberOfConstraints (#677).
    • Implement division between a quadratic function and a number (#675).

    v0.8.2 (February 7, 2019)

    • Add RawStatusString attribute (#629).
    • Do not set names to the optimizer but only to the cache in CachingOptimizer (#638).
    • Make scalar MOI functions act as scalars in broadcast (#646).
    • Add function utilities:
      • Implement Base.zero (#634), Base.iszero (#643), add missing arithmetic operations (#644, #645) and fix division (#648).
      • Add a vectorize function that turns a vector of ScalarAffineFunction into a VectorAffineFunction (#642).
    • Improve support for starting values:
      • Show a warning in copy when starting values are not supported instead of throwing an error (#630).
      • Fix UniversalFallback for getting an variable or constraint attribute set to no indices (#623).
      • Add a test in contlineartest with partially set VariablePrimalStart.
    • Bridges improvements:
      • Fix StackOverFlow in LazyBridgeOptimizer when there is a cycle in the graph of bridges.
      • Add Slack bridges (#610, #650).
      • Add FlipSign bridges (#658).
    • Add tests with duplicate coefficients in ScalarAffineFunction and VectorAffineFunction (#639).
    • Use tolerance to compare VariablePrimal in rotatedsoc1 test (#632).
    • Use a zero constant in ScalarAffineFunction of constraints in psdt2 (#622).

    v0.8.1 (January 7, 2019)

    • Adding an NLP objective now overrides any objective set using the ObjectiveFunction attribute (#619).
    • Rename fullbridgeoptimizer into full_bridge_optimizer (#621).
    • Allow custom constraint types with full_bridge_optimizer (#617).
    • Add Vectorize bridge which transforms scalar linear constraints into vector linear constraints (#615).

    v0.8.0 (December 18, 2018)

    • Rename all enum values to follow the JuMP naming guidelines for constants, for example, Optimal becomes OPTIMAL, and DualInfeasible becomes DUAL_INFEASIBLE.
    • Rename CachingOptimizer methods for style compliance.
    • Add an MOI.TerminationStatusCode called ALMOST_DUAL_INFEASIBLE.

    v0.7.0 (December 13, 2018)

    • Test that MOI.TerminationStatus is MOI.OptimizeNotCalled before MOI.optimize! is called.
    • Check supports_default_copy_to in tests (#594).
    • Key pieces of information like optimality, infeasibility, etc., are now reported through TerminationStatusCode. It is typically no longer necessary to check the result statuses in addition to the termination status.
    • Add perspective dimension to log-det cone (#593).

    v0.6.4 (November 27, 2018)

    • Add OptimizeNotCalled termination status (#577) and improve documentation of other statuses (#575).
    • Add a solver naming guideline (#578).
    • Make FeasibilitySense the default ObjectiveSense (#579).
    • Fix Utilities.@model and Bridges.@bridge macros for functions and sets defined outside MOI (#582).
    • Document solver-specific attributes (#580) and implement them in Utilities.CachingOptimizer (#565).

    v0.6.3 (November 16, 2018)

    • Variables and constraints are now allowed to have duplicate names. An error is thrown only on lookup. This change breaks some existing tests. (#549)
    • Attributes may now be partially set (some values could be nothing). (#563)
    • Performance improvements in Utilities.Model (#549, #567, #568)
    • Fix bug in QuadtoSOC (#558).
    • New supports_default_copy_to method that optimizers should implement to control caching behavior.
    • Documentation improvements.

    v0.6.2 (October 26, 2018)

    • Improve hygiene of @model macro (#544).
    • Fix bug in copy tests (#543).
    • Fix bug in UniversalFallback attribute getter (#540).
    • Allow all correct solutions for solve_blank_obj unit test (#537).
    • Add errors for Allocate-Load and bad constraints (#534).
    • [performance] Add specialized implementation of hash for VariableIndex (#533).
    • [performance] Construct the name to object dictionaries lazily in model (#535).
    • Add the QuadtoSOC bridge which transforms ScalarQuadraticFunction constraints into RotatedSecondOrderCone (#483).

    v0.6.1 (September 22, 2018)

    • Enable PositiveSemidefiniteConeSquare set and quadratic functions in MOIB.fullbridgeoptimizer (#524).
    • Add warning in the bridge between PositiveSemidefiniteConeSquare and PositiveSemidefiniteConeTriangle when the matrix is almost symmetric (#522).
    • Modify MOIT.copytest to not add multiples constraints on the same variable (#521).
    • Add missing keyword argument in one of MOIU.add_scalar_constraint methods (#520).

    v0.6.0 (August 30, 2018)

    • The MOIU.@model and MOIB.@bridge macros now support functions and sets defined in external modules. As a consequence, function and set names in the macro arguments need to be prefixed by module name.
    • Rename functions according to the JuMP style guide:
      • copy! with keyword arguments copynames and warnattributes -> copy_to with keyword arguments copy_names and warn_attributes;
      • set! -> set;
      • addvariable[s]! -> add_variable[s];
      • supportsconstraint -> supports_constraint;
      • addconstraint[s]! -> add_constraint[s];
      • isvalid -> is_valid;
      • isempty -> is_empty;
      • Base.delete! -> delete;
      • modify! -> modify;
      • transform! -> transform;
      • initialize! -> initialize;
      • write -> write_to_file; and
      • read! -> read_from_file.
    • Remove free! (use Base.finalize instead).
    • Add the SquarePSD bridge which transforms PositiveSemidefiniteConeTriangle constraints into PositiveSemidefiniteConeTriangle.
    • Add result fallback for ConstraintDual of variable-wise constraint, ConstraintPrimal and ObjectiveValue.
    • Add tests for ObjectiveBound.
    • Add test for empty rows in vector linear constraint.
    • Rework errors: CannotError has been renamed NotAllowedError and the distinction between UnsupportedError and NotAllowedError is now about whether the element is not supported (for example, it cannot be copied a model containing this element) or the operation is not allowed (either because it is not implemented, because it cannot be performed in the current state of the model, or because it cannot be performed for a specific index)
    • canget is removed. NoSolution is added as a result status to indicate that the solver does not have either a primal or dual solution available (See #479).

    v0.5.0 (August 5, 2018)

    • Fix names with CachingOptimizer.
    • Cleanup thanks to @mohamed82008.
    • Added a universal fallback for constraints.
    • Fast utilities for function canonicalization thanks to @rdeits.
    • Renamed dimension field to side_dimension in the context of matrix-like sets.
    • New and improved tests for cases like duplicate terms and ObjectiveBound.
    • Removed cantransform, canaddconstraint, canaddvariable, canset, canmodify, and candelete functions from the API. They are replaced by a new set of errors that are thrown: Subtypes of UnsupportedError indicate unsupported operations, while subtypes of CannotError indicate operations that cannot be performed in the current state.
    • The API for copy! is updated to remove the CopyResult type.
    • Updates for the new JuMP style guide.

    v0.4.1 (June 28, 2018)

    • Fixes vector function modification on 32 bits.
    • Fixes Bellman-Ford algorithm for bridges.
    • Added an NLP test with FeasibilitySense.
    • Update modification documentation.

    v0.4.0 (June 23, 2018)

    • Helper constructors for VectorAffineTerm and VectorQuadraticTerm.
    • Added modify_lhs to TestConfig.
    • Additional unit tests for optimizers.
    • Added a type parameter to CachingOptimizer for the optimizer field.
    • New API for problem modification (#388)
    • Tests pass without deprecation warnings on Julia 0.7.
    • Small fixes and documentation updates.

    v0.3.0 (May 25, 2018)

    • Functions have been redefined to use arrays-of-structs instead of structs-of-arrays.
    • Improvements to MockOptimizer.
    • Significant changes to Bridges.
    • New and improved unit tests.
    • Fixes for Julia 0.7.

    v0.2.0 (April 24, 2018)

    • Improvements to and better coverage of Tests.
    • Documentation fixes.
    • SolverName attribute.
    • Changes to the NLP interface (new definition of variable order and arrays of structs for bound pairs and sparsity patterns).
    • Addition of NLP tests.
    • Introduction of UniversalFallback.
    • copynames keyword argument to MOI.copy!.
    • Add Bridges submodule.

    v0.1.0 (February 28, 2018)

    • Initial public release.
    • The framework for MOI was developed at the JuMP-dev workshop at MIT in June 2017 as a sorely needed replacement for MathProgBase.
    diff --git a/previews/PR3883/moi/submodules/Benchmarks/overview/index.html b/previews/PR3883/moi/submodules/Benchmarks/overview/index.html index a49e1be8e18..0f0b0c04f8a 100644 --- a/previews/PR3883/moi/submodules/Benchmarks/overview/index.html +++ b/previews/PR3883/moi/submodules/Benchmarks/overview/index.html @@ -21,4 +21,4 @@ MOI.Benchmarks.compare_against_baseline( suite, "current"; directory = "/tmp", verbose = true -)

    This comparison will create a report detailing improvements and regressions.

    +)

    This comparison will create a report detailing improvements and regressions.

    diff --git a/previews/PR3883/moi/submodules/Benchmarks/reference/index.html b/previews/PR3883/moi/submodules/Benchmarks/reference/index.html index 59ed746fd3d..24793429dab 100644 --- a/previews/PR3883/moi/submodules/Benchmarks/reference/index.html +++ b/previews/PR3883/moi/submodules/Benchmarks/reference/index.html @@ -37,4 +37,4 @@ "glpk_master"; directory = "/tmp", verbose = true, - )source + )source diff --git a/previews/PR3883/moi/submodules/Bridges/implementation/index.html b/previews/PR3883/moi/submodules/Bridges/implementation/index.html index 2dddb5d4d1e..060fbff2892 100644 --- a/previews/PR3883/moi/submodules/Bridges/implementation/index.html +++ b/previews/PR3883/moi/submodules/Bridges/implementation/index.html @@ -33,4 +33,4 @@ Subject to: ScalarAffineFunction{Int64}-in-LessThan{Int64} - (0) - (1) x <= (-1) + (0) - (1) x <= (-1) diff --git a/previews/PR3883/moi/submodules/Bridges/list_of_bridges/index.html b/previews/PR3883/moi/submodules/Bridges/list_of_bridges/index.html index c4a7ffed7da..b9d279bad22 100644 --- a/previews/PR3883/moi/submodules/Bridges/list_of_bridges/index.html +++ b/previews/PR3883/moi/submodules/Bridges/list_of_bridges/index.html @@ -129,4 +129,4 @@ & & & x_{11} & x_{12} & x_{13} \\ & & & & x_{22} & x_{23} \\ & & & & & x_{33} -\end{bmatrix}\]

    is positive semidefinite.

    The bridge achieves this reformulation by adding a new set of variables in MOI.PositiveSemidefiniteConeTriangle(6), and then adding three groups of equality constraints to:

    • constrain the two x blocks to be equal
    • force the diagonal of the y blocks to be 0
    • force the lower triangular of the y block to be the negative of the upper triangle.
    source
    MathOptInterface.Bridges.Variable.RSOCtoPSDBridgeType
    RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge

    RSOCtoPSDBridge implements the following reformulation:

    • $||x||_2^2 \le 2tu$ where $t, u \ge 0$ into $Y \succeq 0$, with the substitution rule: $Y = \left[\begin{array}{c c}t & x^\top \\ x & 2u \mathbf{I}\end{array}\right].$

    Additional bounds are added to ensure the off-diagonals of the $2uI$ submatrix are 0, and linear constraints are added to ensure the diagonal of $2uI$ takes the same values.

    As a special case, if $|x|| = 0$, then RSOCtoPSDBridge reformulates into $(t, u) \in \mathbb{R}_+$.

    Source node

    RSOCtoPSDBridge supports:

    Target nodes

    RSOCtoPSDBridge creates:

    source
    MathOptInterface.Bridges.Variable.RSOCtoSOCBridgeType
    RSOCtoSOCBridge{T} <: Bridges.Variable.AbstractBridge

    RSOCtoSOCBridge implements the following reformulation:

    • $||x||_2^2 \le 2tu$ into $||v||_2 \le w$, with the substitution rules $t = \frac{w}{\sqrt 2} + \frac{v_1}{\sqrt 2}$, $u = \frac{w}{\sqrt 2} - \frac{v_1}{\sqrt 2}$, and $x = (v_2,\ldots,v_N)$.

    Source node

    RSOCtoSOCBridge supports:

    Target node

    RSOCtoSOCBridge creates:

    source
    MathOptInterface.Bridges.Variable.SOCtoRSOCBridgeType
    SOCtoRSOCBridge{T} <: Bridges.Variable.AbstractBridge

    SOCtoRSOCBridge implements the following reformulation:

    • $||x||_2 \le t$ into $2uv \ge ||w||_2^2$, with the substitution rules $t = \frac{u}{\sqrt 2} + \frac{v}{\sqrt 2}$, $x = (\frac{u}{\sqrt 2} - \frac{v}{\sqrt 2}, w)$.

    Assumptions

    • SOCtoRSOCBridge assumes that $|x| \ge 1$.

    Source node

    SOCtoRSOCBridge supports:

    Target node

    SOCtoRSOCBridge creates:

    source
    MathOptInterface.Bridges.Variable.SetMapBridgeType
    abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end

    Consider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.

    A SetMapBridge{T,S1,S2} is a bridge that substitutes constrained variables in S2 into the image through A of constrained variables in S1.

    The linear map A is described by:

    Implementing a method for these two functions is sufficient to bridge constrained variables. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:

    See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.

    source
    MathOptInterface.Bridges.Variable.VectorizeBridgeType
    VectorizeBridge{T,S} <: Bridges.Variable.AbstractBridge

    VectorizeBridge implements the following reformulations:

    • $x \ge a$ into $[y] \in \mathbb{R}_+$ with the substitution rule $x = a + y$
    • $x \le a$ into $[y] \in \mathbb{R}_-$ with the substitution rule $x = a + y$
    • $x == a$ into $[y] \in \{0\}$ with the substitution rule $x = a + y$

    where T is the coefficient type of a + y.

    Source node

    VectorizeBridge supports:

    Target nodes

    VectorizeBridge creates:

    source
    MathOptInterface.Bridges.Variable.ZerosBridgeType
    ZerosBridge{T} <: Bridges.Variable.AbstractBridge

    ZerosBridge implements the following reformulation:

    • $x \in \{0\}$ into the substitution rule $x = 0$,

    where T is the coefficient type of 0.

    Source node

    ZerosBridge supports:

    Target nodes

    ZerosBridge does not create target nodes. It replaces all instances of x with 0 via substitution. This means that no variables are created in the underlying model.

    Caveats

    The bridged variables are similar to parameters with zero values. Parameters with non-zero values can be created with constrained variables in MOI.EqualTo by combining a VectorizeBridge and this bridge.

    However, functions modified by ZerosBridge cannot be unbridged. That is, for a given function, we cannot determine if the bridged variables were used.

    A related implication is that this bridge does not support MOI.ConstraintDual. However, if a MOI.Utilities.CachingOptimizer is used, the dual can be determined by the bridged optimizer using MOI.Utilities.get_fallback because the caching optimizer records the unbridged function.

    source
    +\end{bmatrix}\]

    is positive semidefinite.

    The bridge achieves this reformulation by adding a new set of variables in MOI.PositiveSemidefiniteConeTriangle(6), and then adding three groups of equality constraints to:

    • constrain the two x blocks to be equal
    • force the diagonal of the y blocks to be 0
    • force the lower triangular of the y block to be the negative of the upper triangle.
    source
    MathOptInterface.Bridges.Variable.RSOCtoPSDBridgeType
    RSOCtoPSDBridge{T} <: Bridges.Variable.AbstractBridge

    RSOCtoPSDBridge implements the following reformulation:

    • $||x||_2^2 \le 2tu$ where $t, u \ge 0$ into $Y \succeq 0$, with the substitution rule: $Y = \left[\begin{array}{c c}t & x^\top \\ x & 2u \mathbf{I}\end{array}\right].$

    Additional bounds are added to ensure the off-diagonals of the $2uI$ submatrix are 0, and linear constraints are added to ensure the diagonal of $2uI$ takes the same values.

    As a special case, if $|x|| = 0$, then RSOCtoPSDBridge reformulates into $(t, u) \in \mathbb{R}_+$.

    Source node

    RSOCtoPSDBridge supports:

    Target nodes

    RSOCtoPSDBridge creates:

    source
    MathOptInterface.Bridges.Variable.RSOCtoSOCBridgeType
    RSOCtoSOCBridge{T} <: Bridges.Variable.AbstractBridge

    RSOCtoSOCBridge implements the following reformulation:

    • $||x||_2^2 \le 2tu$ into $||v||_2 \le w$, with the substitution rules $t = \frac{w}{\sqrt 2} + \frac{v_1}{\sqrt 2}$, $u = \frac{w}{\sqrt 2} - \frac{v_1}{\sqrt 2}$, and $x = (v_2,\ldots,v_N)$.

    Source node

    RSOCtoSOCBridge supports:

    Target node

    RSOCtoSOCBridge creates:

    source
    MathOptInterface.Bridges.Variable.SOCtoRSOCBridgeType
    SOCtoRSOCBridge{T} <: Bridges.Variable.AbstractBridge

    SOCtoRSOCBridge implements the following reformulation:

    • $||x||_2 \le t$ into $2uv \ge ||w||_2^2$, with the substitution rules $t = \frac{u}{\sqrt 2} + \frac{v}{\sqrt 2}$, $x = (\frac{u}{\sqrt 2} - \frac{v}{\sqrt 2}, w)$.

    Assumptions

    • SOCtoRSOCBridge assumes that $|x| \ge 1$.

    Source node

    SOCtoRSOCBridge supports:

    Target node

    SOCtoRSOCBridge creates:

    source
    MathOptInterface.Bridges.Variable.SetMapBridgeType
    abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end

    Consider two type of sets, S1 and S2, and a linear mapping A such that the image of a set of type S1 under A is a set of type S2.

    A SetMapBridge{T,S1,S2} is a bridge that substitutes constrained variables in S2 into the image through A of constrained variables in S1.

    The linear map A is described by:

    Implementing a method for these two functions is sufficient to bridge constrained variables. However, in order for the getters and setters of attributes such as dual solutions and starting values to work as well, a method for the following functions must be implemented:

    See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge.

    source
    MathOptInterface.Bridges.Variable.VectorizeBridgeType
    VectorizeBridge{T,S} <: Bridges.Variable.AbstractBridge

    VectorizeBridge implements the following reformulations:

    • $x \ge a$ into $[y] \in \mathbb{R}_+$ with the substitution rule $x = a + y$
    • $x \le a$ into $[y] \in \mathbb{R}_-$ with the substitution rule $x = a + y$
    • $x == a$ into $[y] \in \{0\}$ with the substitution rule $x = a + y$

    where T is the coefficient type of a + y.

    Source node

    VectorizeBridge supports:

    Target nodes

    VectorizeBridge creates:

    source
    MathOptInterface.Bridges.Variable.ZerosBridgeType
    ZerosBridge{T} <: Bridges.Variable.AbstractBridge

    ZerosBridge implements the following reformulation:

    • $x \in \{0\}$ into the substitution rule $x = 0$,

    where T is the coefficient type of 0.

    Source node

    ZerosBridge supports:

    Target nodes

    ZerosBridge does not create target nodes. It replaces all instances of x with 0 via substitution. This means that no variables are created in the underlying model.

    Caveats

    The bridged variables are similar to parameters with zero values. Parameters with non-zero values can be created with constrained variables in MOI.EqualTo by combining a VectorizeBridge and this bridge.

    However, functions modified by ZerosBridge cannot be unbridged. That is, for a given function, we cannot determine if the bridged variables were used.

    A related implication is that this bridge does not support MOI.ConstraintDual. However, if a MOI.Utilities.CachingOptimizer is used, the dual can be determined by the bridged optimizer using MOI.Utilities.get_fallback because the caching optimizer records the unbridged function.

    source
    diff --git a/previews/PR3883/moi/submodules/Bridges/overview/index.html b/previews/PR3883/moi/submodules/Bridges/overview/index.html index 89986dacdb5..657148b702c 100644 --- a/previews/PR3883/moi/submodules/Bridges/overview/index.html +++ b/previews/PR3883/moi/submodules/Bridges/overview/index.html @@ -66,4 +66,4 @@ julia> MOI.get(inner_optimizer, MOI.ListOfConstraintTypesPresent()) 1-element Vector{Tuple{Type, Type}}: - (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}) + (MathOptInterface.VariableIndex, MathOptInterface.Interval{Float64}) diff --git a/previews/PR3883/moi/submodules/Bridges/reference/index.html b/previews/PR3883/moi/submodules/Bridges/reference/index.html index 4387c372713..00a6c66c095 100644 --- a/previews/PR3883/moi/submodules/Bridges/reference/index.html +++ b/previews/PR3883/moi/submodules/Bridges/reference/index.html @@ -221,4 +221,4 @@ cost::Int, )

    As an alternative to variable_node, add a virtual edge to graph that represents adding a free variable, followed by a constraint of type constraint_node, with bridging cost cost.

    Why is this needed?

    Variables can either be added as a variable constrained on creation, or as a free variable which then has a constraint added to it.

    source
    MathOptInterface.Bridges.bridge_indexFunction
    bridge_index(graph::Graph, node::VariableNode)::Int
     bridge_index(graph::Graph, node::ConstraintNode)::Int
    -bridge_index(graph::Graph, node::ObjectiveNode)::Int

    Return the optimal index of the bridge to chose from node.

    source
    MathOptInterface.Bridges.is_variable_edge_bestFunction
    is_variable_edge_best(graph::Graph, node::VariableNode)::Bool

    Return a Bool indicating whether node should be added as a variable constrained on creation, or as a free variable followed by a constraint.

    source
    +bridge_index(graph::Graph, node::ObjectiveNode)::Int

    Return the optimal index of the bridge to chose from node.

    source
    MathOptInterface.Bridges.is_variable_edge_bestFunction
    is_variable_edge_best(graph::Graph, node::VariableNode)::Bool

    Return a Bool indicating whether node should be added as a variable constrained on creation, or as a free variable followed by a constraint.

    source
    diff --git a/previews/PR3883/moi/submodules/FileFormats/overview/index.html b/previews/PR3883/moi/submodules/FileFormats/overview/index.html index 2a079aba9b7..c480309d435 100644 --- a/previews/PR3883/moi/submodules/FileFormats/overview/index.html +++ b/previews/PR3883/moi/submodules/FileFormats/overview/index.html @@ -158,4 +158,4 @@ path: [variables][1] instance: Dict{String, Any}("NaMe" => "x") schema key: required -schema value: Any["name"] +schema value: Any["name"] diff --git a/previews/PR3883/moi/submodules/FileFormats/reference/index.html b/previews/PR3883/moi/submodules/FileFormats/reference/index.html index cc52782ce40..219c30282f5 100644 --- a/previews/PR3883/moi/submodules/FileFormats/reference/index.html +++ b/previews/PR3883/moi/submodules/FileFormats/reference/index.html @@ -26,4 +26,4 @@ )

    Parse the .sol file filename created by solving model and return a SolFileResults struct.

    The returned struct supports the MOI.get API for querying result attributes such as MOI.TerminationStatus, MOI.VariablePrimal, and MOI.ConstraintDual.

    source
    SolFileResults(
         raw_status::String,
         termination_status::MOI.TerminationStatusCode,
    -)

    Return a SolFileResults struct with MOI.RawStatusString set to raw_status, MOI.TerminationStatus set to termination_status, and MOI.PrimalStatus and MOI.DualStatus set to NO_SOLUTION.

    All other attributes are un-set.

    source
    +)

    Return a SolFileResults struct with MOI.RawStatusString set to raw_status, MOI.TerminationStatus set to termination_status, and MOI.PrimalStatus and MOI.DualStatus set to NO_SOLUTION.

    All other attributes are un-set.

    source diff --git a/previews/PR3883/moi/submodules/Nonlinear/overview/index.html b/previews/PR3883/moi/submodules/Nonlinear/overview/index.html index e57be090583..5d35a772f30 100644 --- a/previews/PR3883/moi/submodules/Nonlinear/overview/index.html +++ b/previews/PR3883/moi/submodules/Nonlinear/overview/index.html @@ -184,4 +184,4 @@ Node(NODE_VARIABLE, 1, 1), ], [2.0], - );

    The ordering of the nodes in the tape must satisfy two rules:

    • The children of a node must appear after the parent. This means that the tape is ordered topologically, so that a reverse pass of the nodes evaluates all children nodes before their parent
    • The arguments for a CALL node are ordered in the tape based on the order in which they appear in the function call.

    Design goals

    This is less readable than the other options, but does this data structure meet our design goals?

    Instead of a heap-allocated object for each node, we only have two Vectors for each expression, nodes and values, as well as two constant vectors for the OPERATORS. In addition, all fields are concretely typed, and there are no Union or Any types.

    For our third goal, it is not easy to identify the children of a node, but it is easy to identify the parent of any node. Therefore, we can use Nonlinear.adjacency_matrix to compute a sparse matrix that maps parents to their children.

    The design in practice

    In practice, Node and Expression are exactly Nonlinear.Node and Nonlinear.Expression. However, Nonlinear.NodeType has more fields to account for comparison operators such as :>= and :<=, logic operators such as :&& and :||, nonlinear parameters, and nested subexpressions.

    Moreover, instead of storing the operators as global constants, they are stored in Nonlinear.OperatorRegistry, and it also stores a vector of logic operators and a vector of comparison operators. In addition to Nonlinear.DEFAULT_UNIVARIATE_OPERATORS and Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS, you can register user-defined functions using Nonlinear.register_operator.

    Nonlinear.Model is a struct that stores the Nonlinear.OperatorRegistry, as well as a list of parameters and subexpressions in the model.

    ReverseAD

    Nonlinear.ReverseAD is a submodule for computing derivatives of a nonlinear optimization problem using sparse reverse-mode automatic differentiation (AD).

    This section does not attempt to explain how sparse reverse-mode AD works, but instead explains why MOI contains its own implementation, and highlights notable differences from similar packages.

    Warning

    Don't use the API in ReverseAD to compute derivatives. Instead, create a Nonlinear.Evaluator object with Nonlinear.SparseReverseMode as the backend, and then query the MOI API methods.

    Design goals

    The JuliaDiff organization maintains a list of packages for doing AD in Julia. At last count, there were at least ten packages——not including ReverseAD——for reverse-mode AD in Julia. ReverseAD exists because it has a different set of design goals.

    • Goal: handle scale and sparsity. The types of nonlinear optimization problems that MOI represents can be large scale (10^5 or more functions across 10^5 or more variables) with very sparse derivatives. The ability to compute a sparse Hessian matrix is essential. To the best of our knowledge, ReverseAD is the only reverse-mode AD system in Julia that handles sparsity by default.
    • Goal: limit the scope to improve robustness. Most other AD packages accept arbitrary Julia functions as input and then trace an expression graph using operator overloading. This means they must deal (or detect and ignore) with control flow, I/O, and other vagaries of Julia. In contrast, ReverseAD only accepts functions in the form of Nonlinear.Expression, which greatly limits the range of syntax that it must deal with. By reducing the scope of what we accept as input to functions relevant for mathematical optimization, we can provide a simpler implementation with various performance optimizations.
    • Goal: provide outputs which match what solvers expect. Other AD packages focus on differentiating individual Julia functions. In contrast, ReverseAD has a very specific use-case: to generate outputs needed by the MOI nonlinear API. This means it needs to efficiently compute sparse Hessians, and it needs subexpression handling to avoid recomputing subexpressions that are shared between functions.

    History

    ReverseAD started life as ReverseDiffSparse.jl, development of which began in early 2014(!). This was well before the other AD packages started development. Because we had a well-tested, working AD in JuMP, there was less motivation to contribute to and explore other AD packages. The lack of historical interaction also meant that other packages were not optimized for the types of problems that JuMP is built for (that is, large-scale sparse problems). When we first created MathOptInterface, we kept the AD in JuMP to simplify the transition, and post-poned the development of a first-class nonlinear interface in MathOptInterface.

    Prior to the introduction of Nonlinear, JuMP's nonlinear implementation was a confusing mix of functions and types spread across the code base and in the private _Derivatives submodule. This made it hard to swap the AD system for another. The main motivation for refactoring JuMP to create the Nonlinear submodule in MathOptInterface was to abstract the interface between JuMP and the AD system, allowing us to swap-in and test new AD systems in the future.

    + );

    The ordering of the nodes in the tape must satisfy two rules:

    • The children of a node must appear after the parent. This means that the tape is ordered topologically, so that a reverse pass of the nodes evaluates all children nodes before their parent
    • The arguments for a CALL node are ordered in the tape based on the order in which they appear in the function call.

    Design goals

    This is less readable than the other options, but does this data structure meet our design goals?

    Instead of a heap-allocated object for each node, we only have two Vectors for each expression, nodes and values, as well as two constant vectors for the OPERATORS. In addition, all fields are concretely typed, and there are no Union or Any types.

    For our third goal, it is not easy to identify the children of a node, but it is easy to identify the parent of any node. Therefore, we can use Nonlinear.adjacency_matrix to compute a sparse matrix that maps parents to their children.

    The design in practice

    In practice, Node and Expression are exactly Nonlinear.Node and Nonlinear.Expression. However, Nonlinear.NodeType has more fields to account for comparison operators such as :>= and :<=, logic operators such as :&& and :||, nonlinear parameters, and nested subexpressions.

    Moreover, instead of storing the operators as global constants, they are stored in Nonlinear.OperatorRegistry, and it also stores a vector of logic operators and a vector of comparison operators. In addition to Nonlinear.DEFAULT_UNIVARIATE_OPERATORS and Nonlinear.DEFAULT_MULTIVARIATE_OPERATORS, you can register user-defined functions using Nonlinear.register_operator.

    Nonlinear.Model is a struct that stores the Nonlinear.OperatorRegistry, as well as a list of parameters and subexpressions in the model.

    ReverseAD

    Nonlinear.ReverseAD is a submodule for computing derivatives of a nonlinear optimization problem using sparse reverse-mode automatic differentiation (AD).

    This section does not attempt to explain how sparse reverse-mode AD works, but instead explains why MOI contains its own implementation, and highlights notable differences from similar packages.

    Warning

    Don't use the API in ReverseAD to compute derivatives. Instead, create a Nonlinear.Evaluator object with Nonlinear.SparseReverseMode as the backend, and then query the MOI API methods.

    Design goals

    The JuliaDiff organization maintains a list of packages for doing AD in Julia. At last count, there were at least ten packages——not including ReverseAD——for reverse-mode AD in Julia. ReverseAD exists because it has a different set of design goals.

    • Goal: handle scale and sparsity. The types of nonlinear optimization problems that MOI represents can be large scale (10^5 or more functions across 10^5 or more variables) with very sparse derivatives. The ability to compute a sparse Hessian matrix is essential. To the best of our knowledge, ReverseAD is the only reverse-mode AD system in Julia that handles sparsity by default.
    • Goal: limit the scope to improve robustness. Most other AD packages accept arbitrary Julia functions as input and then trace an expression graph using operator overloading. This means they must deal (or detect and ignore) with control flow, I/O, and other vagaries of Julia. In contrast, ReverseAD only accepts functions in the form of Nonlinear.Expression, which greatly limits the range of syntax that it must deal with. By reducing the scope of what we accept as input to functions relevant for mathematical optimization, we can provide a simpler implementation with various performance optimizations.
    • Goal: provide outputs which match what solvers expect. Other AD packages focus on differentiating individual Julia functions. In contrast, ReverseAD has a very specific use-case: to generate outputs needed by the MOI nonlinear API. This means it needs to efficiently compute sparse Hessians, and it needs subexpression handling to avoid recomputing subexpressions that are shared between functions.

    History

    ReverseAD started life as ReverseDiffSparse.jl, development of which began in early 2014(!). This was well before the other AD packages started development. Because we had a well-tested, working AD in JuMP, there was less motivation to contribute to and explore other AD packages. The lack of historical interaction also meant that other packages were not optimized for the types of problems that JuMP is built for (that is, large-scale sparse problems). When we first created MathOptInterface, we kept the AD in JuMP to simplify the transition, and post-poned the development of a first-class nonlinear interface in MathOptInterface.

    Prior to the introduction of Nonlinear, JuMP's nonlinear implementation was a confusing mix of functions and types spread across the code base and in the private _Derivatives submodule. This made it hard to swap the AD system for another. The main motivation for refactoring JuMP to create the Nonlinear submodule in MathOptInterface was to abstract the interface between JuMP and the AD system, allowing us to swap-in and test new AD systems in the future.

    diff --git a/previews/PR3883/moi/submodules/Nonlinear/reference/index.html b/previews/PR3883/moi/submodules/Nonlinear/reference/index.html index 39134101d8d..4c6a35f84a6 100644 --- a/previews/PR3883/moi/submodules/Nonlinear/reference/index.html +++ b/previews/PR3883/moi/submodules/Nonlinear/reference/index.html @@ -236,4 +236,4 @@ julia> MOI.initialize(evaluator, Symbol[]) julia> MOI.Nonlinear.ordinal_index(evaluator, c2) # Returns 1 -1source +1source diff --git a/previews/PR3883/moi/submodules/Test/overview/index.html b/previews/PR3883/moi/submodules/Test/overview/index.html index cb3b2e235d5..6191ba32661 100644 --- a/previews/PR3883/moi/submodules/Test/overview/index.html +++ b/previews/PR3883/moi/submodules/Test/overview/index.html @@ -167,4 +167,4 @@ ), ) return -end

    Finally, you also need to implement Test.version_added. If we added this test when the latest released version of MOI was v0.10.5, define:

    version_added(::typeof(test_unit_optimize!_twice)) = v"0.10.6"

    Step 6

    Commit the changes to git from ~/.julia/dev/MathOptInterface and submit the PR for review.

    Tip

    If you need help writing a test, open an issue on GitHub, or ask the Developer Chatroom.

    +end

    Finally, you also need to implement Test.version_added. If we added this test when the latest released version of MOI was v0.10.5, define:

    version_added(::typeof(test_unit_optimize!_twice)) = v"0.10.6"

    Step 6

    Commit the changes to git from ~/.julia/dev/MathOptInterface and submit the PR for review.

    Tip

    If you need help writing a test, open an issue on GitHub, or ask the Developer Chatroom.

    diff --git a/previews/PR3883/moi/submodules/Test/reference/index.html b/previews/PR3883/moi/submodules/Test/reference/index.html index cd1f5e4dca8..f1289675800 100644 --- a/previews/PR3883/moi/submodules/Test/reference/index.html +++ b/previews/PR3883/moi/submodules/Test/reference/index.html @@ -63,4 +63,4 @@ \text{subject to}\ & x_1 * x_2 * x_3 * x_4 \ge 25 \\ & x_1^2 + x_2^2 + x_3^2 + x_4^2 = 40 \\ & 1 \le x_1, x_2, x_3, x_4 \le 5 -\end{aligned}\]

    The optimal solution is [1.000, 4.743, 3.821, 1.379].

    source +\end{aligned}\]

    The optimal solution is [1.000, 4.743, 3.821, 1.379].

    source diff --git a/previews/PR3883/moi/submodules/Utilities/overview/index.html b/previews/PR3883/moi/submodules/Utilities/overview/index.html index b065e44c3bb..476f4eef950 100644 --- a/previews/PR3883/moi/submodules/Utilities/overview/index.html +++ b/previews/PR3883/moi/submodules/Utilities/overview/index.html @@ -378,4 +378,4 @@ index_map = MOI.copy_to(dest, src) for (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent()) function_barrier(dest, src, index_map[F, S]) -end +end diff --git a/previews/PR3883/moi/submodules/Utilities/reference/index.html b/previews/PR3883/moi/submodules/Utilities/reference/index.html index 8540b1b8873..4672fbe2bce 100644 --- a/previews/PR3883/moi/submodules/Utilities/reference/index.html +++ b/previews/PR3883/moi/submodules/Utilities/reference/index.html @@ -91,7 +91,7 @@ typeof(CleverDicts.key_to_index), typeof(CleverDicts.index_to_key), } -end

    A struct storing F-in-S constraints as a mapping between the constraint indices to the corresponding tuple of function and set.

    source
    MathOptInterface.Utilities.@struct_of_constraints_by_function_typesMacro
    Utilities.@struct_of_constraints_by_function_types(name, func_types...)

    Given a vector of n function types (F1, F2,..., Fn) in func_types, defines a subtype of StructOfConstraints of name name and which type parameters {T, C1, C2, ..., Cn}. It contains n field where the ith field has type Ci and stores the constraints of function type Fi.

    The expression Fi can also be a union in which case any constraint for which the function type is in the union is stored in the field with type Ci.

    source
    MathOptInterface.Utilities.@struct_of_constraints_by_set_typesMacro
    Utilities.@struct_of_constraints_by_set_types(name, func_types...)

    Given a vector of n set types (S1, S2,..., Sn) in func_types, defines a subtype of StructOfConstraints of name name and which type parameters {T, C1, C2, ..., Cn}. It contains n field where the ith field has type Ci and stores the constraints of set type Si. The expression Si can also be a union in which case any constraint for which the set type is in the union is stored in the field with type Ci. This can be useful if Ci is a MatrixOfConstraints in order to concatenate the coefficients of constraints of several different set types in the same matrix.

    source
    MathOptInterface.Utilities.struct_of_constraint_codeFunction
    struct_of_constraint_code(struct_name, types, field_types = nothing)

    Given a vector of n Union{SymbolFun,_UnionSymbolFS{SymbolFun}} or Union{SymbolSet,_UnionSymbolFS{SymbolSet}} in types, defines a subtype of StructOfConstraints of name name and which type parameters {T, F1, F2, ..., Fn} if field_types is nothing and a {T} otherwise. It contains n field where the ith field has type Ci if field_types is nothing and type field_types[i] otherwise. If types is vector of Union{SymbolFun,_UnionSymbolFS{SymbolFun}} (resp. Union{SymbolSet,_UnionSymbolFS{SymbolSet}}) then the constraints of that function (resp. set) type are stored in the corresponding field.

    This function is used by the macros @model, @struct_of_constraints_by_function_types and @struct_of_constraints_by_set_types.

    source

    Caching optimizer

    MathOptInterface.Utilities.CachingOptimizerType
    CachingOptimizer

    CachingOptimizer is an intermediate layer that stores a cache of the model and links it with an optimizer. It supports incremental model construction and modification even when the optimizer doesn't.

    Constructors

        CachingOptimizer(cache::MOI.ModelLike, optimizer::AbstractOptimizer)

    Creates a CachingOptimizer in AUTOMATIC mode, with the optimizer optimizer.

    The type of the optimizer returned is CachingOptimizer{typeof(optimizer), typeof(cache)} so it does not support the function reset_optimizer(::CachingOptimizer, new_optimizer) if the type of new_optimizer is different from the type of optimizer.

        CachingOptimizer(cache::MOI.ModelLike, mode::CachingOptimizerMode)

    Creates a CachingOptimizer in the NO_OPTIMIZER state and mode mode.

    The type of the optimizer returned is CachingOptimizer{MOI.AbstractOptimizer,typeof(cache)} so it does support the function reset_optimizer(::CachingOptimizer, new_optimizer) if the type of new_optimizer is different from the type of optimizer.

    About the type

    States

    A CachingOptimizer may be in one of three possible states (CachingOptimizerState):

    • NO_OPTIMIZER: The CachingOptimizer does not have any optimizer.
    • EMPTY_OPTIMIZER: The CachingOptimizer has an empty optimizer. The optimizer is not synchronized with the cached model.
    • ATTACHED_OPTIMIZER: The CachingOptimizer has an optimizer, and it is synchronized with the cached model.

    Modes

    A CachingOptimizer has two modes of operation (CachingOptimizerMode):

    • MANUAL: The only methods that change the state of the CachingOptimizer are Utilities.reset_optimizer, Utilities.drop_optimizer, and Utilities.attach_optimizer. Attempting to perform an operation in the incorrect state results in an error.
    • AUTOMATIC: The CachingOptimizer changes its state when necessary. For example, optimize! will automatically call attach_optimizer (an optimizer must have been previously set). Attempting to add a constraint or perform a modification not supported by the optimizer results in a drop to EMPTY_OPTIMIZER mode.
    source
    MathOptInterface.Utilities.attach_optimizerFunction
    attach_optimizer(model::CachingOptimizer)

    Attaches the optimizer to model, copying all model data into it. Can be called only from the EMPTY_OPTIMIZER state. If the copy succeeds, the CachingOptimizer will be in state ATTACHED_OPTIMIZER after the call, otherwise an error is thrown; see MOI.copy_to for more details on which errors can be thrown.

    source
    MOIU.attach_optimizer(model::GenericModel)

    Call MOIU.attach_optimizer on the backend of model.

    Cannot be called in direct mode.

    source
    MathOptInterface.Utilities.reset_optimizerFunction
    reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)

    Sets or resets m to have the given empty optimizer optimizer.

    Can be called from any state. An assertion error will be thrown if optimizer is not empty.

    The CachingOptimizer m will be in state EMPTY_OPTIMIZER after the call.

    source
    reset_optimizer(m::CachingOptimizer)

    Detaches and empties the current optimizer. Can be called from ATTACHED_OPTIMIZER or EMPTY_OPTIMIZER state. The CachingOptimizer will be in state EMPTY_OPTIMIZER after the call.

    source
    MOIU.reset_optimizer(model::GenericModel, optimizer::MOI.AbstractOptimizer)

    Call MOIU.reset_optimizer on the backend of model.

    Cannot be called in direct mode.

    source
    MOIU.reset_optimizer(model::GenericModel)

    Call MOIU.reset_optimizer on the backend of model.

    Cannot be called in direct mode.

    source
    MathOptInterface.Utilities.drop_optimizerFunction
    drop_optimizer(m::CachingOptimizer)

    Drops the optimizer, if one is present. Can be called from any state. The CachingOptimizer will be in state NO_OPTIMIZER after the call.

    source
    MOIU.drop_optimizer(model::GenericModel)

    Call MOIU.drop_optimizer on the backend of model.

    Cannot be called in direct mode.

    source

    Mock optimizer

    Printing

    MathOptInterface.Utilities.latex_formulationFunction
    latex_formulation(model::MOI.ModelLike; kwargs...)

    Wrap model in a type so that it can be pretty-printed as text/latex in a notebook like IJulia, or in Documenter.

    To render the model, end the cell with latex_formulation(model), or call display(latex_formulation(model)) in to force the display of the model from inside a function.

    Possible keyword arguments are:

    • simplify_coefficients : Simplify coefficients if possible by omitting them or removing trailing zeros.
    • default_name : The name given to variables with an empty name.
    • print_types : Print the MOI type of each function and set for clarity.
    source

    Copy utilities

    MathOptInterface.Utilities.ModelFilterType
    ModelFilter(filter::Function, model::MOI.ModelLike)

    A layer to filter out various components of model.

    The filter function takes a single argument, which is each element from the list returned by the attributes below. It returns true if the element should be visible in the filtered model and false otherwise.

    The components that are filtered are:

    • Entire constraint types via:
      • MOI.ListOfConstraintTypesPresent
    • Individual constraints via:
      • MOI.ListOfConstraintIndices{F,S}
    • Specific attributes via:
      • MOI.ListOfModelAttributesSet
      • MOI.ListOfConstraintAttributesSet
      • MOI.ListOfVariableAttributesSet
    Warning

    The list of attributes filtered may change in a future release. You should write functions that are generic and not limited to the five types listed above. Thus, you should probably define a fallback filter(::Any) = true.

    See below for examples of how this works.

    Note

    This layer has a limited scope. It is intended by be used in conjunction with MOI.copy_to.

    Example: copy model excluding integer constraints

    Use the do syntax to provide a single function.

    filtered_src = MOI.Utilities.ModelFilter(src) do item
    +end

    A struct storing F-in-S constraints as a mapping between the constraint indices to the corresponding tuple of function and set.

    source
    MathOptInterface.Utilities.@struct_of_constraints_by_function_typesMacro
    Utilities.@struct_of_constraints_by_function_types(name, func_types...)

    Given a vector of n function types (F1, F2,..., Fn) in func_types, defines a subtype of StructOfConstraints of name name and which type parameters {T, C1, C2, ..., Cn}. It contains n field where the ith field has type Ci and stores the constraints of function type Fi.

    The expression Fi can also be a union in which case any constraint for which the function type is in the union is stored in the field with type Ci.

    source
    MathOptInterface.Utilities.@struct_of_constraints_by_set_typesMacro
    Utilities.@struct_of_constraints_by_set_types(name, func_types...)

    Given a vector of n set types (S1, S2,..., Sn) in func_types, defines a subtype of StructOfConstraints of name name and which type parameters {T, C1, C2, ..., Cn}. It contains n field where the ith field has type Ci and stores the constraints of set type Si. The expression Si can also be a union in which case any constraint for which the set type is in the union is stored in the field with type Ci. This can be useful if Ci is a MatrixOfConstraints in order to concatenate the coefficients of constraints of several different set types in the same matrix.

    source
    MathOptInterface.Utilities.struct_of_constraint_codeFunction
    struct_of_constraint_code(struct_name, types, field_types = nothing)

    Given a vector of n Union{SymbolFun,_UnionSymbolFS{SymbolFun}} or Union{SymbolSet,_UnionSymbolFS{SymbolSet}} in types, defines a subtype of StructOfConstraints of name name and which type parameters {T, F1, F2, ..., Fn} if field_types is nothing and a {T} otherwise. It contains n field where the ith field has type Ci if field_types is nothing and type field_types[i] otherwise. If types is vector of Union{SymbolFun,_UnionSymbolFS{SymbolFun}} (resp. Union{SymbolSet,_UnionSymbolFS{SymbolSet}}) then the constraints of that function (resp. set) type are stored in the corresponding field.

    This function is used by the macros @model, @struct_of_constraints_by_function_types and @struct_of_constraints_by_set_types.

    source

    Caching optimizer

    MathOptInterface.Utilities.CachingOptimizerType
    CachingOptimizer

    CachingOptimizer is an intermediate layer that stores a cache of the model and links it with an optimizer. It supports incremental model construction and modification even when the optimizer doesn't.

    Constructors

        CachingOptimizer(cache::MOI.ModelLike, optimizer::AbstractOptimizer)

    Creates a CachingOptimizer in AUTOMATIC mode, with the optimizer optimizer.

    The type of the optimizer returned is CachingOptimizer{typeof(optimizer), typeof(cache)} so it does not support the function reset_optimizer(::CachingOptimizer, new_optimizer) if the type of new_optimizer is different from the type of optimizer.

        CachingOptimizer(cache::MOI.ModelLike, mode::CachingOptimizerMode)

    Creates a CachingOptimizer in the NO_OPTIMIZER state and mode mode.

    The type of the optimizer returned is CachingOptimizer{MOI.AbstractOptimizer,typeof(cache)} so it does support the function reset_optimizer(::CachingOptimizer, new_optimizer) if the type of new_optimizer is different from the type of optimizer.

    About the type

    States

    A CachingOptimizer may be in one of three possible states (CachingOptimizerState):

    • NO_OPTIMIZER: The CachingOptimizer does not have any optimizer.
    • EMPTY_OPTIMIZER: The CachingOptimizer has an empty optimizer. The optimizer is not synchronized with the cached model.
    • ATTACHED_OPTIMIZER: The CachingOptimizer has an optimizer, and it is synchronized with the cached model.

    Modes

    A CachingOptimizer has two modes of operation (CachingOptimizerMode):

    • MANUAL: The only methods that change the state of the CachingOptimizer are Utilities.reset_optimizer, Utilities.drop_optimizer, and Utilities.attach_optimizer. Attempting to perform an operation in the incorrect state results in an error.
    • AUTOMATIC: The CachingOptimizer changes its state when necessary. For example, optimize! will automatically call attach_optimizer (an optimizer must have been previously set). Attempting to add a constraint or perform a modification not supported by the optimizer results in a drop to EMPTY_OPTIMIZER mode.
    source
    MathOptInterface.Utilities.attach_optimizerFunction
    attach_optimizer(model::CachingOptimizer)

    Attaches the optimizer to model, copying all model data into it. Can be called only from the EMPTY_OPTIMIZER state. If the copy succeeds, the CachingOptimizer will be in state ATTACHED_OPTIMIZER after the call, otherwise an error is thrown; see MOI.copy_to for more details on which errors can be thrown.

    source
    MOIU.attach_optimizer(model::GenericModel)

    Call MOIU.attach_optimizer on the backend of model.

    Cannot be called in direct mode.

    source
    MathOptInterface.Utilities.reset_optimizerFunction
    reset_optimizer(m::CachingOptimizer, optimizer::MOI.AbstractOptimizer)

    Sets or resets m to have the given empty optimizer optimizer.

    Can be called from any state. An assertion error will be thrown if optimizer is not empty.

    The CachingOptimizer m will be in state EMPTY_OPTIMIZER after the call.

    source
    reset_optimizer(m::CachingOptimizer)

    Detaches and empties the current optimizer. Can be called from ATTACHED_OPTIMIZER or EMPTY_OPTIMIZER state. The CachingOptimizer will be in state EMPTY_OPTIMIZER after the call.

    source
    MOIU.reset_optimizer(model::GenericModel, optimizer::MOI.AbstractOptimizer)

    Call MOIU.reset_optimizer on the backend of model.

    Cannot be called in direct mode.

    source
    MOIU.reset_optimizer(model::GenericModel)

    Call MOIU.reset_optimizer on the backend of model.

    Cannot be called in direct mode.

    source
    MathOptInterface.Utilities.drop_optimizerFunction
    drop_optimizer(m::CachingOptimizer)

    Drops the optimizer, if one is present. Can be called from any state. The CachingOptimizer will be in state NO_OPTIMIZER after the call.

    source
    MOIU.drop_optimizer(model::GenericModel)

    Call MOIU.drop_optimizer on the backend of model.

    Cannot be called in direct mode.

    source

    Mock optimizer

    Printing

    MathOptInterface.Utilities.latex_formulationFunction
    latex_formulation(model::MOI.ModelLike; kwargs...)

    Wrap model in a type so that it can be pretty-printed as text/latex in a notebook like IJulia, or in Documenter.

    To render the model, end the cell with latex_formulation(model), or call display(latex_formulation(model)) in to force the display of the model from inside a function.

    Possible keyword arguments are:

    • simplify_coefficients : Simplify coefficients if possible by omitting them or removing trailing zeros.
    • default_name : The name given to variables with an empty name.
    • print_types : Print the MOI type of each function and set for clarity.
    source

    Copy utilities

    MathOptInterface.Utilities.ModelFilterType
    ModelFilter(filter::Function, model::MOI.ModelLike)

    A layer to filter out various components of model.

    The filter function takes a single argument, which is each element from the list returned by the attributes below. It returns true if the element should be visible in the filtered model and false otherwise.

    The components that are filtered are:

    • Entire constraint types via:
      • MOI.ListOfConstraintTypesPresent
    • Individual constraints via:
      • MOI.ListOfConstraintIndices{F,S}
    • Specific attributes via:
      • MOI.ListOfModelAttributesSet
      • MOI.ListOfConstraintAttributesSet
      • MOI.ListOfVariableAttributesSet
    Warning

    The list of attributes filtered may change in a future release. You should write functions that are generic and not limited to the five types listed above. Thus, you should probably define a fallback filter(::Any) = true.

    See below for examples of how this works.

    Note

    This layer has a limited scope. It is intended by be used in conjunction with MOI.copy_to.

    Example: copy model excluding integer constraints

    Use the do syntax to provide a single function.

    filtered_src = MOI.Utilities.ModelFilter(src) do item
         return item != (MOI.VariableIndex, MOI.Integer)
     end
     MOI.copy_to(dest, filtered_src)

    Example: copy model excluding names

    Use type dispatch to simplify the implementation:

    my_filter(::Any) = true  # Note the generic fallback
    @@ -343,4 +343,4 @@
     For performance, it is recommended that the inner loop lies in a separate
     function to guarantee type-stability.
     
    -If you want an iterator of all current outer keys, use [`outer_keys`](@ref).
    source
    +If you want an iterator of all current outer keys, use [`outer_keys`](@ref).source diff --git a/previews/PR3883/moi/tutorials/bridging_constraint/index.html b/previews/PR3883/moi/tutorials/bridging_constraint/index.html index 5156572aa8a..54087ebfffd 100644 --- a/previews/PR3883/moi/tutorials/bridging_constraint/index.html +++ b/previews/PR3883/moi/tutorials/bridging_constraint/index.html @@ -103,4 +103,4 @@ end

    Bridge deletion

    When a bridge is deleted, the constraints it added must be deleted too.

    function delete(model::ModelLike, bridge::SignBridge)
         delete(model, bridge.constraint)
         return
    -end
    +end diff --git a/previews/PR3883/moi/tutorials/example/index.html b/previews/PR3883/moi/tutorials/example/index.html index d7b6d9229f9..1bf55ffde6d 100644 --- a/previews/PR3883/moi/tutorials/example/index.html +++ b/previews/PR3883/moi/tutorials/example/index.html @@ -46,4 +46,4 @@ 3-element Vector{Float64}: 1.0 1.0 - 1.0 + 1.0 diff --git a/previews/PR3883/moi/tutorials/implementing/index.html b/previews/PR3883/moi/tutorials/implementing/index.html index 4fe19273c47..0cc46f1d080 100644 --- a/previews/PR3883/moi/tutorials/implementing/index.html +++ b/previews/PR3883/moi/tutorials/implementing/index.html @@ -115,4 +115,4 @@ n = # Code to get NumberOfObjectives return n end

    Then, the user can write:

    model = Gurobi.Optimizer()
    -MOI.set(model, Gurobi.NumberofObjectives(), 3)
    +MOI.set(model, Gurobi.NumberofObjectives(), 3) diff --git a/previews/PR3883/moi/tutorials/latency/index.html b/previews/PR3883/moi/tutorials/latency/index.html index 490e52b3964..82299ce6409 100644 --- a/previews/PR3883/moi/tutorials/latency/index.html +++ b/previews/PR3883/moi/tutorials/latency/index.html @@ -130,4 +130,4 @@ end

    You can create a flame-graph via

    using SnoopCompile
     tinf = @snoopi_deep example_diet(GLPK.Optimizer, true)
     using ProfileView
    -ProfileView.view(flamegraph(tinf))

    Here's how things looked in mid-August 2021: flamegraph

    There are a few opportunities for improvement (non-red flames, particularly on the right). But the main problem is a large red (non-precompilable due to method ownership) flame.

    +ProfileView.view(flamegraph(tinf))

    Here's how things looked in mid-August 2021: flamegraph

    There are a few opportunities for improvement (non-red flames, particularly on the right). But the main problem is a large red (non-precompilable due to method ownership) flame.

    diff --git a/previews/PR3883/moi/tutorials/manipulating_expressions/index.html b/previews/PR3883/moi/tutorials/manipulating_expressions/index.html index 4d8c6bf1e11..15f53da419c 100644 --- a/previews/PR3883/moi/tutorials/manipulating_expressions/index.html +++ b/previews/PR3883/moi/tutorials/manipulating_expressions/index.html @@ -23,4 +23,4 @@ 2-element Vector{MathOptInterface.ScalarAffineFunction{Int64}}: (2) + (1) MOI.VariableIndex(1) (4) + (2) MOI.VariableIndex(1)
    Note

    Utilities.eachscalar returns an iterator on the dimensions, which serves the same purpose as Utilities.scalarize.

    output_dimension returns the number of dimensions of the output of a function:

    julia> MOI.output_dimension(g)
    -2
    +2 diff --git a/previews/PR3883/moi/tutorials/mathprogbase/index.html b/previews/PR3883/moi/tutorials/mathprogbase/index.html index ab0e2b8c0ae..6611c188803 100644 --- a/previews/PR3883/moi/tutorials/mathprogbase/index.html +++ b/previews/PR3883/moi/tutorials/mathprogbase/index.html @@ -55,4 +55,4 @@ objval = objective_value(model), sol = value.(x) ) -end +end diff --git a/previews/PR3883/packages/Alpine/index.html b/previews/PR3883/packages/Alpine/index.html index de158dff6dc..385b01d05f8 100644 --- a/previews/PR3883/packages/Alpine/index.html +++ b/previews/PR3883/packages/Alpine/index.html @@ -46,4 +46,4 @@ author={Kim, Jongeun and Richard, Jean-Philippe P. and Tawarmalani, Mohit}, eprinttype={Optimization Online}, date={2022} -} +} diff --git a/previews/PR3883/packages/AmplNLWriter/index.html b/previews/PR3883/packages/AmplNLWriter/index.html index a512aa557c0..e18124f9c56 100644 --- a/previews/PR3883/packages/AmplNLWriter/index.html +++ b/previews/PR3883/packages/AmplNLWriter/index.html @@ -12,4 +12,4 @@ import Bonmin_jll model = Model(() -> AmplNLWriter.Optimizer(Bonmin_jll.amplexe)) set_attribute(model, "bonmin.nlp_log_level", 0)

    opt files

    Some options need to be specified via an .opt file.

    This file must be located in the current working directory whenever the model is solved.

    The .opt file must be named after the name of the solver, for example, bonmin.opt, and each line must contain an option name and the desired value, separated by a space.

    For example, to set the absolute and relative tolerances in Couenne to 1 and 0.05 respectively, the couenne.opt file should contain:

    allowable_gap 1
    -allowable_fraction_gap 0.05
    +allowable_fraction_gap 0.05 diff --git a/previews/PR3883/packages/BARON/index.html b/previews/PR3883/packages/BARON/index.html index f10fddbebb3..0a7199c829d 100644 --- a/previews/PR3883/packages/BARON/index.html +++ b/previews/PR3883/packages/BARON/index.html @@ -6,4 +6,4 @@

    BARON.jl

    Build Status codecov

    BARON.jl is a wrapper for BARON by The Optimization Firm.

    Affiliation

    This wrapper is maintained by the JuMP community and is not officially supported by The Optimization Firm.

    Getting help

    If you need help, please ask a question on the JuMP community forum.

    If you have a reproducible example of a bug, please open a GitHub issue.

    License

    BARON.jl is licensed under the MIT License.

    The underlying solver is a closed-source commercial product for which you must obtain a license from The Optimization Firm, although a small trial version is available for free.

    Installation

    First, download a copy of the BARON solver and unpack the executable in a location of your choosing.

    Once installed, set the BARON_EXEC environment variable pointing to the BARON executable (full path, including file name as it differs across platforms), and run Pkg.add("BARON"). For example:

    ENV["BARON_EXEC"] = "/path/to/baron.exe"
     using Pkg
     Pkg.add("BARON")

    The baronlice.txt license file should be placed in the same directory as the BARON executable, or in your current working directory.

    Use with JuMP

    using JuMP, BARON
    -model = Model(BARON.Optimizer)

    MathOptInterface API

    The BARON optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    +model = Model(BARON.Optimizer)

    MathOptInterface API

    The BARON optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    diff --git a/previews/PR3883/packages/BilevelJuMP/index.html b/previews/PR3883/packages/BilevelJuMP/index.html index 490c3e36ac3..42f16d858a6 100644 --- a/previews/PR3883/packages/BilevelJuMP/index.html +++ b/previews/PR3883/packages/BilevelJuMP/index.html @@ -34,4 +34,4 @@ objective_value(model) # = 3 * (3.5 * 8/15) + 8/15 # = 6.13... value(x) # = 3.5 * 8/15 # = 1.86... -value(y) # = 8/15 # = 0.53... +value(y) # = 8/15 # = 0.53... diff --git a/previews/PR3883/packages/CDCS/index.html b/previews/PR3883/packages/CDCS/index.html index f3970033ef3..b0e3398e2bd 100644 --- a/previews/PR3883/packages/CDCS/index.html +++ b/previews/PR3883/packages/CDCS/index.html @@ -27,4 +27,4 @@ mat"cdcsInstall" end -julia> mat"savepath" +julia> mat"savepath" diff --git a/previews/PR3883/packages/CDDLib/index.html b/previews/PR3883/packages/CDDLib/index.html index f3e1781af14..da004f6f1cf 100644 --- a/previews/PR3883/packages/CDDLib/index.html +++ b/previews/PR3883/packages/CDDLib/index.html @@ -6,4 +6,4 @@

    CDDLib

    CDDLib.jl is a wrapper for cddlib.

    CDDLib.jl can be used with C API of cddlib, the higher level interface of Polyhedra.jl, or as a linear programming solver with JuMP or MathOptInterface.

    Problem description

    As written in the README of cddlib:

    The C-library cddlib is a C implementation of the Double Description Method of Motzkin et al. for generating all vertices (that is, extreme points) and extreme rays of a general convex polyhedron in R^d given by a system of linear inequalities:

    P = { x=(x1, ..., xd)^T :  b - A  x  >= 0 }

    where A is a given m x d real matrix, b is a given m-vector and 0 is the m-vector of all zeros.

    The program can be used for the reverse operation (that is, convex hull computation). This means that one can move back and forth between an inequality representation and a generator (that is, vertex and ray) representation of a polyhedron with cdd. Also, cdd can solve a linear programming problem, that is, a problem of maximizing and minimizing a linear function over P.

    License

    CDDLib.jl is licensed under the GPL v2 license.

    The underlying solver, cddlib/cddlib is also licensed under the GPL v2 license.

    Installation

    Install CDDLib.jl using the Julia package manager:

    import Pkg
     Pkg.add("CDDLib")

    Building the package will download binaries of cddlib that are provided by cddlib_jll.jl.

    Use with JuMP

    Use CDDLib.Optimizer{Float64} to use CDDLib.jl with JuMP:

    using JuMP, CDDLib
     model = Model(CDDLib.Optimizer{Float64})

    When using CDDLib.jl with MathOptInterface, you can pass a different number type:

    using MathOptInterface, CDDLib
    -model = CDDLib.Optimizer{Rational{BigInt}}()

    Debugging

    CDDLib.jl uses two global Boolean variables to enable debugging outputs: debug and log.

    You can query the value of debug and log with get_debug and get_log, and set their values with set_debug and set_log.

    +model = CDDLib.Optimizer{Rational{BigInt}}()

    Debugging

    CDDLib.jl uses two global Boolean variables to enable debugging outputs: debug and log.

    You can query the value of debug and log with get_debug and get_log, and set their values with set_debug and set_log.

    diff --git a/previews/PR3883/packages/COPT/index.html b/previews/PR3883/packages/COPT/index.html index 309561c137e..0d7f4d2bd35 100644 --- a/previews/PR3883/packages/COPT/index.html +++ b/previews/PR3883/packages/COPT/index.html @@ -39,4 +39,4 @@ @show value.(X) @show value.(z) @show shadow_price(c1) -@show shadow_price(c2) +@show shadow_price(c2) diff --git a/previews/PR3883/packages/COSMO/index.html b/previews/PR3883/packages/COSMO/index.html index 5fa1b24efa1..a6631b8bbc8 100644 --- a/previews/PR3883/packages/COSMO/index.html +++ b/previews/PR3883/packages/COSMO/index.html @@ -34,4 +34,4 @@ publisher = {Springer}, doi = {10.1007/s10957-021-01896-x}, url = {https://doi.org/10.1007/s10957-021-01896-x} -}

    The article is available under Open Access here.

    Contributing

    • Contributions are always welcome. Our style guide can be found here.
    • Current issues, tasks and future ideas are listed in Issues. Please report any issues or bugs that you encounter.
    • As an open source project we are also interested in any projects and applications that use COSMO. Please let us know by opening a GitHub issue.

    Python - Interface

    COSMO can also be called from Python. Take a look at: cosmo-python

    Licence 🔍

    This project is licensed under the Apache License - see the LICENSE.md file for details.

    +}

    The article is available under Open Access here.

    Contributing

    • Contributions are always welcome. Our style guide can be found here.
    • Current issues, tasks and future ideas are listed in Issues. Please report any issues or bugs that you encounter.
    • As an open source project we are also interested in any projects and applications that use COSMO. Please let us know by opening a GitHub issue.

    Python - Interface

    COSMO can also be called from Python. Take a look at: cosmo-python

    Licence 🔍

    This project is licensed under the Apache License - see the LICENSE.md file for details.

    diff --git a/previews/PR3883/packages/CPLEX/index.html b/previews/PR3883/packages/CPLEX/index.html index f0fe3caa9ee..4dde2982b64 100644 --- a/previews/PR3883/packages/CPLEX/index.html +++ b/previews/PR3883/packages/CPLEX/index.html @@ -163,4 +163,4 @@ x_optimal = value.(x) y_optimal = value.(y) println("x: $(x_optimal), y: $(y_optimal)") -end +end diff --git a/previews/PR3883/packages/CSDP/index.html b/previews/PR3883/packages/CSDP/index.html index 44a1d574e5b..b29fbfef648 100644 --- a/previews/PR3883/packages/CSDP/index.html +++ b/previews/PR3883/packages/CSDP/index.html @@ -10,4 +10,4 @@ A(X) = a X ⪰ 0

    where A(X) = [⟨A_1, X⟩, ..., ⟨A_m, X⟩]. The corresponding dual is:

    min ⟨a, y⟩
          A'(y) - C = Z
    -             Z ⪰ 0

    where A'(y) = y_1A_1 + ... + y_mA_m

    Termination criteria

    CSDP will terminate successfully (or partially) in the following cases:

    • If CSDP finds X, Z ⪰ 0 such that the following 3 tolerances are satisfied:
      • primal feasibility tolerance: ||A(x) - a||_2 / (1 + ||a||_2) < axtol
      • dual feasibility tolerance: ||A'(y) - C - Z||_F / (1 + ||C||_F) < atytol
      • relative duality gap tolerance: gap / (1 + |⟨a, y⟩| + |⟨C, X⟩|) < objtol
        • objective duality gap: if usexygap is 0, gap = ⟨a, y⟩ - ⟨C, X⟩
        • XY duality gap: if usexygap is 1, gap = ⟨Z, X⟩
      then it returns 0.
    • If CSDP finds y and Z ⪰ 0 such that -⟨a, y⟩ / ||A'(y) - Z||_F > pinftol, it returns 1 with y such that ⟨a, y⟩ = -1.
    • If CSDP finds X ⪰ 0 such that ⟨C, X⟩ / ||A(X)||_2 > dinftol, it returns 2 with X such that ⟨C, X⟩ = 1.
    • If CSDP finds X, Z ⪰ 0 such that the following 3 tolerances are satisfied with 1000*axtol, 1000*atytol and 1000*objtol but at least one of them is not satisfied with axtol, atytol and objtol and cannot make progress, then it returns 3.

    In addition, if the printlevel option is at least 1, the following will be printed:

    • If the return code is 1, CSDP will print ⟨a, y⟩ and ||A'(y) - Z||_F
    • If the return code is 2, CSDP will print ⟨C, X⟩ and ||A(X)||_F
    • Otherwise, CSDP will print
      • the primal/dual objective value,
      • the relative primal/dual infeasibility,
      • the objective duality gap ⟨a, y⟩ - ⟨C, X⟩ and objective relative duality gap (⟨a, y⟩ - ⟨C, X⟩) / (1 + |⟨a, y⟩| + |⟨C, X⟩|),
      • the XY duality gap ⟨Z, X⟩ and XY relative duality gap ⟨Z, X⟩ / (1 + |⟨a, y⟩| + |⟨C, X⟩|)
      • and the DIMACS error measures.

    In theory, for feasible primal and dual solutions, ⟨a, y⟩ - ⟨C, X⟩ = ⟨Z, X⟩, so the objective and XY duality gap should be equivalent. However, in practice, there are sometimes solution which satisfy primal and dual feasibility tolerances but have objective duality gap which are not close to XY duality gap. In some cases, the objective duality gap may even become negative (hence the tweakgap option). This is the reason usexygap is 1 by default.

    CSDP considers that X ⪰ 0 (resp. Z ⪰ 0) is satisfied when the Cholesky factorizations can be computed. In practice, this is somewhat more conservative than simply requiring all eigenvalues to be nonnegative.

    Status

    The table below shows how the different CSDP statuses are converted to the MathOptInterface statuses.

    CSDP codeStateDescriptionMOI status
    0SuccessSDP solvedMOI.OPTIMAL
    1SuccessThe problem is primal infeasible, and we have a certificateMOI.INFEASIBLE
    2SuccessThe problem is dual infeasible, and we have a certificateMOI.DUAL_INFEASIBLE
    3Partial SuccessA solution has been found, but full accuracy was not achievedMOI.ALMOST_OPTIMAL
    4FailureMaximum iterations reachedMOI.ITERATION_LIMIT
    5FailureStuck at edge of primal feasibilityMOI.SLOW_PROGRESS
    6FailureStuck at edge of dual infeasibilityMOI.SLOW_PROGRESS
    7FailureLack of progressMOI.SLOW_PROGRESS
    8FailureX, Z, or O was singularMOI.NUMERICAL_ERROR
    9FailureDetected NaN or Inf valuesMOI.NUMERICAL_ERROR
    + Z ⪰ 0

    where A'(y) = y_1A_1 + ... + y_mA_m

    Termination criteria

    CSDP will terminate successfully (or partially) in the following cases:

    • If CSDP finds X, Z ⪰ 0 such that the following 3 tolerances are satisfied:
      • primal feasibility tolerance: ||A(x) - a||_2 / (1 + ||a||_2) < axtol
      • dual feasibility tolerance: ||A'(y) - C - Z||_F / (1 + ||C||_F) < atytol
      • relative duality gap tolerance: gap / (1 + |⟨a, y⟩| + |⟨C, X⟩|) < objtol
        • objective duality gap: if usexygap is 0, gap = ⟨a, y⟩ - ⟨C, X⟩
        • XY duality gap: if usexygap is 1, gap = ⟨Z, X⟩
      then it returns 0.
    • If CSDP finds y and Z ⪰ 0 such that -⟨a, y⟩ / ||A'(y) - Z||_F > pinftol, it returns 1 with y such that ⟨a, y⟩ = -1.
    • If CSDP finds X ⪰ 0 such that ⟨C, X⟩ / ||A(X)||_2 > dinftol, it returns 2 with X such that ⟨C, X⟩ = 1.
    • If CSDP finds X, Z ⪰ 0 such that the following 3 tolerances are satisfied with 1000*axtol, 1000*atytol and 1000*objtol but at least one of them is not satisfied with axtol, atytol and objtol and cannot make progress, then it returns 3.

    In addition, if the printlevel option is at least 1, the following will be printed:

    • If the return code is 1, CSDP will print ⟨a, y⟩ and ||A'(y) - Z||_F
    • If the return code is 2, CSDP will print ⟨C, X⟩ and ||A(X)||_F
    • Otherwise, CSDP will print
      • the primal/dual objective value,
      • the relative primal/dual infeasibility,
      • the objective duality gap ⟨a, y⟩ - ⟨C, X⟩ and objective relative duality gap (⟨a, y⟩ - ⟨C, X⟩) / (1 + |⟨a, y⟩| + |⟨C, X⟩|),
      • the XY duality gap ⟨Z, X⟩ and XY relative duality gap ⟨Z, X⟩ / (1 + |⟨a, y⟩| + |⟨C, X⟩|)
      • and the DIMACS error measures.

    In theory, for feasible primal and dual solutions, ⟨a, y⟩ - ⟨C, X⟩ = ⟨Z, X⟩, so the objective and XY duality gap should be equivalent. However, in practice, there are sometimes solution which satisfy primal and dual feasibility tolerances but have objective duality gap which are not close to XY duality gap. In some cases, the objective duality gap may even become negative (hence the tweakgap option). This is the reason usexygap is 1 by default.

    CSDP considers that X ⪰ 0 (resp. Z ⪰ 0) is satisfied when the Cholesky factorizations can be computed. In practice, this is somewhat more conservative than simply requiring all eigenvalues to be nonnegative.

    Status

    The table below shows how the different CSDP statuses are converted to the MathOptInterface statuses.

    CSDP codeStateDescriptionMOI status
    0SuccessSDP solvedMOI.OPTIMAL
    1SuccessThe problem is primal infeasible, and we have a certificateMOI.INFEASIBLE
    2SuccessThe problem is dual infeasible, and we have a certificateMOI.DUAL_INFEASIBLE
    3Partial SuccessA solution has been found, but full accuracy was not achievedMOI.ALMOST_OPTIMAL
    4FailureMaximum iterations reachedMOI.ITERATION_LIMIT
    5FailureStuck at edge of primal feasibilityMOI.SLOW_PROGRESS
    6FailureStuck at edge of dual infeasibilityMOI.SLOW_PROGRESS
    7FailureLack of progressMOI.SLOW_PROGRESS
    8FailureX, Z, or O was singularMOI.NUMERICAL_ERROR
    9FailureDetected NaN or Inf valuesMOI.NUMERICAL_ERROR
    diff --git a/previews/PR3883/packages/Cbc/index.html b/previews/PR3883/packages/Cbc/index.html index 610e52e4879..7e6799b84fb 100644 --- a/previews/PR3883/packages/Cbc/index.html +++ b/previews/PR3883/packages/Cbc/index.html @@ -9,4 +9,4 @@ set_attribute(model, "logLevel", 1)

    MathOptInterface API

    The COIN Branch-and-Cut (Cbc) optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    List of supported optimizer attributes:

    List of supported variable attributes:

    List of supported constraint attributes:

    Options

    Options are, unfortunately, not well documented.

    The following options are likely to be the most useful:

    ParameterExampleExplanation
    seconds60.0Solution timeout limit
    logLevel2Set to 0 to disable solution output
    maxSolutions1Terminate after this many feasible solutions have been found
    maxNodes1Terminate after this many branch-and-bound nodes have been evaluated
    allowableGap0.05Terminate after optimality gap is less than this value (on an absolute scale)
    ratioGap0.05Terminate after optimality gap is smaller than this relative fraction
    threads1Set the number of threads to use for parallel branch & bound

    The complete list of parameters can be found by running the cbc executable and typing ? at the prompt.

    Start the cbc executable from Julia as follows:

    using Cbc_jll
     Cbc_jll.cbc() do exe
         run(`$(exe)`)
    -end
    +end diff --git a/previews/PR3883/packages/Clarabel/index.html b/previews/PR3883/packages/Clarabel/index.html index 7bf8e2bf301..22b50d4b9ba 100644 --- a/previews/PR3883/packages/Clarabel/index.html +++ b/previews/PR3883/packages/Clarabel/index.html @@ -33,4 +33,4 @@

    eprint={2405.12762}, archivePrefix={arXiv}, primaryClass={math.OC} -}

    License 🔍

    This project is licensed under the Apache License 2.0 - see the LICENSE.md file for details.

    +}

    License 🔍

    This project is licensed under the Apache License 2.0 - see the LICENSE.md file for details.

    diff --git a/previews/PR3883/packages/Clp/index.html b/previews/PR3883/packages/Clp/index.html index 42e0c4e34e8..7a16c28d72e 100644 --- a/previews/PR3883/packages/Clp/index.html +++ b/previews/PR3883/packages/Clp/index.html @@ -7,4 +7,4 @@ Pkg.add("Clp")

    In addition to installing the Clp.jl package, this will also download and install the Clp binaries. You do not need to install Clp separately.

    To use a custom binary, read the Custom solver binaries section of the JuMP documentation.

    Use with JuMP

    To use Clp with JuMP, use Clp.Optimizer:

    using JuMP, Clp
     model = Model(Clp.Optimizer)
     set_attribute(model, "LogLevel", 1)
    -set_attribute(model, "Algorithm", 4)

    MathOptInterface API

    The Clp optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    Options are, unfortunately, not well documented.

    The following options are likely to be the most useful:

    ParameterExampleExplanation
    PrimalTolerance1e-7Primal feasibility tolerance
    DualTolerance1e-7Dual feasibility tolerance
    DualObjectiveLimit1e308When using dual simplex (where the objective is monotonically changing), terminate when the objective exceeds this limit
    MaximumIterations2147483647Terminate after performing this number of simplex iterations
    MaximumSeconds-1.0Terminate after this many seconds have passed. A negative value means no time limit
    LogLevel1Set to 1, 2, 3, or 4 for increasing output. Set to 0 to disable output
    PresolveType0Set to 1 to disable presolve
    SolveType5Solution method: dual simplex (0), primal simplex (1), sprint (2), barrier with crossover (3), barrier without crossover (4), automatic (5)
    InfeasibleReturn0Set to 1 to return as soon as the problem is found to be infeasible (by default, an infeasibility proof is computed as well)
    Scaling30 -off, 1 equilibrium, 2 geometric, 3 auto, 4 dynamic(later)
    Perturbation100switch on perturbation (50), automatic (100), don't try perturbing (102)

    C API

    The C API can be accessed via Clp.Clp_XXX functions, where the names and arguments are identical to the C API.

    +set_attribute(model, "Algorithm", 4)

    MathOptInterface API

    The Clp optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    Options are, unfortunately, not well documented.

    The following options are likely to be the most useful:

    ParameterExampleExplanation
    PrimalTolerance1e-7Primal feasibility tolerance
    DualTolerance1e-7Dual feasibility tolerance
    DualObjectiveLimit1e308When using dual simplex (where the objective is monotonically changing), terminate when the objective exceeds this limit
    MaximumIterations2147483647Terminate after performing this number of simplex iterations
    MaximumSeconds-1.0Terminate after this many seconds have passed. A negative value means no time limit
    LogLevel1Set to 1, 2, 3, or 4 for increasing output. Set to 0 to disable output
    PresolveType0Set to 1 to disable presolve
    SolveType5Solution method: dual simplex (0), primal simplex (1), sprint (2), barrier with crossover (3), barrier without crossover (4), automatic (5)
    InfeasibleReturn0Set to 1 to return as soon as the problem is found to be infeasible (by default, an infeasibility proof is computed as well)
    Scaling30 -off, 1 equilibrium, 2 geometric, 3 auto, 4 dynamic(later)
    Perturbation100switch on perturbation (50), automatic (100), don't try perturbing (102)

    C API

    The C API can be accessed via Clp.Clp_XXX functions, where the names and arguments are identical to the C API.

    diff --git a/previews/PR3883/packages/DAQP/index.html b/previews/PR3883/packages/DAQP/index.html index 745ece5088d..bd5810d18e4 100644 --- a/previews/PR3883/packages/DAQP/index.html +++ b/previews/PR3883/packages/DAQP/index.html @@ -5,4 +5,4 @@ gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash});

    DAQP.jl

    DAQP.jl is a Julia wrapper for the Quadratic Programming solver DAQP.

    License

    DAQP.jl is licensed under the MIT license.

    The underlying solver, darnstrom/daqp is licensed under the MIT license.

    Installation

    Install DAQP.jl using the Julia package manager:

    import Pkg
     Pkg.add("DAQP")

    Use with JuMP

    To use DAQP with JuMP, do:

    using JuMP, DAQP
    -model = Model(DAQP.Optimizer)

    Documentation

    General information about the solver is available at https://darnstrom.github.io/daqp/, and specifics for the Julia interface are available at https://darnstrom.github.io/daqp/start/julia.

    +model = Model(DAQP.Optimizer)

    Documentation

    General information about the solver is available at https://darnstrom.github.io/daqp/, and specifics for the Julia interface are available at https://darnstrom.github.io/daqp/start/julia.

    diff --git a/previews/PR3883/packages/DSDP/index.html b/previews/PR3883/packages/DSDP/index.html index eaeaac160ef..c96765fe6ea 100644 --- a/previews/PR3883/packages/DSDP/index.html +++ b/previews/PR3883/packages/DSDP/index.html @@ -8,4 +8,4 @@ model = Model(DSDP.Optimizer)

    MathOptInterface API

    The DSDP optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Compile your own binaries

    In order to compile your own libdsdp.so to be used of DSDP.jl, use the following

    OB_DIR=$(julia --project=. -e 'import OpenBLAS32_jll; println(OpenBLAS32_jll.OpenBLAS32_jll.artifact_dir)')
     OB="-L${LIBOB_DIR}/lib -lopenblas"
     make DSDPCFLAGS="-g -Wall -fPIC -DPIC" LAPACKBLAS="$OB" dsdplibrary
    -make DSDPCFLAGS="-g -Wall -fPIC -DPIC" LAPACKBLAS="$OB" SH_LD="${CC} ${CFLAGS} -Wall -fPIC -DPIC -shared $OB" oshared
    +make DSDPCFLAGS="-g -Wall -fPIC -DPIC" LAPACKBLAS="$OB" SH_LD="${CC} ${CFLAGS} -Wall -fPIC -DPIC -shared $OB" oshared diff --git a/previews/PR3883/packages/DiffOpt/index.html b/previews/PR3883/packages/DiffOpt/index.html index 82af7ab78f4..a452370678a 100644 --- a/previews/PR3883/packages/DiffOpt/index.html +++ b/previews/PR3883/packages/DiffOpt/index.html @@ -20,4 +20,4 @@ # fetch the gradients grad_exp = MOI.get(model, DiffOpt.ReverseConstraintFunction(), cons) # -3 x - 1 constant(grad_exp) # -1 -coefficient(grad_exp, x) # -3

    GSOC2020

    DiffOpt began as a NumFOCUS sponsored Google Summer of Code (2020) project

    +coefficient(grad_exp, x) # -3

    GSOC2020

    DiffOpt began as a NumFOCUS sponsored Google Summer of Code (2020) project

    diff --git a/previews/PR3883/packages/DisjunctiveProgramming/index.html b/previews/PR3883/packages/DisjunctiveProgramming/index.html index 18833a83908..3020443a653 100644 --- a/previews/PR3883/packages/DisjunctiveProgramming/index.html +++ b/previews/PR3883/packages/DisjunctiveProgramming/index.html @@ -8,4 +8,4 @@ author={Perez, Hector D and Joshi, Shivank and Grossmann, Ignacio E}, journal={arXiv preprint arXiv:2304.10492}, year={2023} -} +} diff --git a/previews/PR3883/packages/Dualization/index.html b/previews/PR3883/packages/Dualization/index.html index 10d9cc987d6..10a474ca3f4 100644 --- a/previews/PR3883/packages/Dualization/index.html +++ b/previews/PR3883/packages/Dualization/index.html @@ -10,4 +10,4 @@ dual_model = dualize(model)

    To solve the dual formulation of a JuMP model, create a dual_optimizer:

    using JuMP, Dualization, SCS
     model = Model(dual_optimizer(SCS.Optimizer))
     # ... build model ...
    -optimize!(model)  # Solves the dual instead of the primal

    Documentation

    The documentation for Dualization.jl includes a detailed description of the dual reformulation, along with examples and an API reference.

    +optimize!(model) # Solves the dual instead of the primal

    Documentation

    The documentation for Dualization.jl includes a detailed description of the dual reformulation, along with examples and an API reference.

    diff --git a/previews/PR3883/packages/EAGO/index.html b/previews/PR3883/packages/EAGO/index.html index a3f419b82ae..71d27b3b106 100644 --- a/previews/PR3883/packages/EAGO/index.html +++ b/previews/PR3883/packages/EAGO/index.html @@ -71,4 +71,4 @@ doi = {10.1080/10556788.2020.1786566}, URL = {https://doi.org/10.1080/10556788.2020.1786566}, eprint = {https://doi.org/10.1080/10556788.2020.1786566} -}

    References

    1. Mitsos, A., Chachuat, B., and Barton, P.I. McCormick-based relaxations of algorithms. SIAM Journal on Optimization. 20(2): 573—601 (2009).
    2. Khan, K.A., Watson, H.A.J., and Barton, P.I. Differentiable McCormick relaxations. Journal of Global Optimization. 67(4): 687—729 (2017).
    3. Stuber, M.D., Scott, J.K., and Barton, P.I.: Convex and concave relaxations of implicit functions. Optimization Methods and Software 30(3): 424—460 (2015).
    4. Wechsung, A., Scott, J.K., Watson, H.A.J., and Barton, P.I. Reverse propagation of McCormick relaxations. Journal of Global Optimization 63(1): 1—36 (2015).
    5. Bracken, J., and McCormick, G.P. Selected Applications of Nonlinear Programming. John Wiley and Sons, New York (1968).
    +}

    References

    1. Mitsos, A., Chachuat, B., and Barton, P.I. McCormick-based relaxations of algorithms. SIAM Journal on Optimization. 20(2): 573—601 (2009).
    2. Khan, K.A., Watson, H.A.J., and Barton, P.I. Differentiable McCormick relaxations. Journal of Global Optimization. 67(4): 687—729 (2017).
    3. Stuber, M.D., Scott, J.K., and Barton, P.I.: Convex and concave relaxations of implicit functions. Optimization Methods and Software 30(3): 424—460 (2015).
    4. Wechsung, A., Scott, J.K., Watson, H.A.J., and Barton, P.I. Reverse propagation of McCormick relaxations. Journal of Global Optimization 63(1): 1—36 (2015).
    5. Bracken, J., and McCormick, G.P. Selected Applications of Nonlinear Programming. John Wiley and Sons, New York (1968).
    diff --git a/previews/PR3883/packages/ECOS/index.html b/previews/PR3883/packages/ECOS/index.html index 82510cb5159..3fe0854ffd3 100644 --- a/previews/PR3883/packages/ECOS/index.html +++ b/previews/PR3883/packages/ECOS/index.html @@ -6,4 +6,4 @@

    ECOS.jl

    Build Status codecov

    ECOS.jl is a wrapper for the ECOS solver.

    The wrapper has two components:

    Affiliation

    This wrapper is maintained by the JuMP community and is not a product of Embotech AG.

    License

    ECOS.jl is licensed under the MIT License.

    The underlying solver, embotech/ecos, is licensed under the GPL v3 license.

    Installation

    Install ECOS.jl using Pkg.add:

    import Pkg
     Pkg.add("ECOS")

    In addition to installing the ECOS.jl package, this will also download and install the ECOS binaries. You do not need to install ECOS separately.

    To use a custom binary, read the Custom solver binaries section of the JuMP documentation.

    Use with JuMP

    To use ECOS with JuMP, use ECOS.Optimizer:

    using JuMP, ECOS
     model = Model(ECOS.Optimizer)
    -set_attribute(model, "maxit", 100)

    MathOptInterface API

    The ECOS optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    The following options are supported:

    ParameterExplanation
    gammascaling the final step length
    deltaregularization parameter
    epsregularization threshold
    feastolprimal/dual infeasibility tolerance
    abstolabsolute tolerance on duality gap
    reltolrelative tolerance on duality gap
    feastol_inaccprimal/dual infeasibility relaxed tolerance
    abstol_inaccabsolute relaxed tolerance on duality gap
    reltol_inaccrelative relaxed tolerance on duality gap
    nitrefnumber of iterative refinement steps
    maxitmaximum number of iterations
    verboseverbosity bool for PRINTLEVEL < 3
    +set_attribute(model, "maxit", 100)

    MathOptInterface API

    The ECOS optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    The following options are supported:

    ParameterExplanation
    gammascaling the final step length
    deltaregularization parameter
    epsregularization threshold
    feastolprimal/dual infeasibility tolerance
    abstolabsolute tolerance on duality gap
    reltolrelative tolerance on duality gap
    feastol_inaccprimal/dual infeasibility relaxed tolerance
    abstol_inaccabsolute relaxed tolerance on duality gap
    reltol_inaccrelative relaxed tolerance on duality gap
    nitrefnumber of iterative refinement steps
    maxitmaximum number of iterations
    verboseverbosity bool for PRINTLEVEL < 3
    diff --git a/previews/PR3883/packages/GAMS/index.html b/previews/PR3883/packages/GAMS/index.html index ea0b93da5b0..c6d78578049 100644 --- a/previews/PR3883/packages/GAMS/index.html +++ b/previews/PR3883/packages/GAMS/index.html @@ -22,4 +22,4 @@ MOI.get(model, GAMS.GeneratedConstraintName(), c[2]) # returns eq2 MOI.get(model, GAMS.OriginalConstraintName("eq1")) # returns c[1] -MOI.get(model, GAMS.OriginalConstraintName("eq10")) # returns nothing

    Note that JuMP direct-mode is used.

    +MOI.get(model, GAMS.OriginalConstraintName("eq10")) # returns nothing

    Note that JuMP direct-mode is used.

    diff --git a/previews/PR3883/packages/GLPK/index.html b/previews/PR3883/packages/GLPK/index.html index e07e03fd2a3..de580deece4 100644 --- a/previews/PR3883/packages/GLPK/index.html +++ b/previews/PR3883/packages/GLPK/index.html @@ -36,4 +36,4 @@ @test primal_status(model) == MOI.FEASIBLE_POINT @test value(x) == 1 @test value(y) == 2 -@show reasons

    C API

    The C API can be accessed via GLPK.glp_XXX functions, where the names and arguments are identical to the C API. See the /tests folder for inspiration.

    Thread safety

    GLPK is not thread-safe and should not be used with multithreading.

    +@show reasons

    C API

    The C API can be accessed via GLPK.glp_XXX functions, where the names and arguments are identical to the C API. See the /tests folder for inspiration.

    Thread safety

    GLPK is not thread-safe and should not be used with multithreading.

    diff --git a/previews/PR3883/packages/Gurobi/index.html b/previews/PR3883/packages/Gurobi/index.html index af59fcbf992..640a6c1c6aa 100644 --- a/previews/PR3883/packages/Gurobi/index.html +++ b/previews/PR3883/packages/Gurobi/index.html @@ -169,4 +169,4 @@ println(lower_bound(x[i])) end

    Common errors

    Using Gurobi v9.0 and you got an error like Q not PSD?

    You need to set the NonConvex parameter:

    model = Model(Gurobi.Optimizer)
     set_optimizer_attribute(model, "NonConvex", 2)

    Gurobi Error 1009: Version number is XX.X, license is for version XX.X

    Make sure that your license is correct for your Gurobi version. See the Gurobi documentation for details.

    Once you are sure that the license and Gurobi versions match, re-install Gurobi.jl by running:

    import Pkg
    -Pkg.build("Gurobi")
    +Pkg.build("Gurobi") diff --git a/previews/PR3883/packages/HiGHS/index.html b/previews/PR3883/packages/HiGHS/index.html index b7753848a39..3ca133c97c8 100644 --- a/previews/PR3883/packages/HiGHS/index.html +++ b/previews/PR3883/packages/HiGHS/index.html @@ -11,4 +11,4 @@ set_attribute(model, "time_limit", 60.0)

    MathOptInterface API

    The HiGHS optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    See the HiGHS documentation for a full list of the available options.

    C API

    The C API can be accessed via HiGHS.Highs_xxx functions, where the names and arguments are identical to the C API.

    Threads

    HiGHS uses a global scheduler that is shared between threads.

    Before changing the number of threads using MOI.Threads(), you must call Highs_resetGlobalScheduler(1):

    using JuMP, HiGHS
     model = Model(HiGHS.Optimizer)
     Highs_resetGlobalScheduler(1)
    -set_attribute(model, MOI.NumberOfThreads(), 1)

    If modifying the number of HiGHS threads across different Julia threads, be sure to read the docstring of Highs_resetGlobalScheduler. In particular, resetting the scheduler is not thread-safe.

    +set_attribute(model, MOI.NumberOfThreads(), 1)

    If modifying the number of HiGHS threads across different Julia threads, be sure to read the docstring of Highs_resetGlobalScheduler. In particular, resetting the scheduler is not thread-safe.

    diff --git a/previews/PR3883/packages/Hypatia/index.html b/previews/PR3883/packages/Hypatia/index.html index ba06f047f50..5e7d8c90b87 100644 --- a/previews/PR3883/packages/Hypatia/index.html +++ b/previews/PR3883/packages/Hypatia/index.html @@ -42,4 +42,4 @@ volume={15}, pages={53--101}, doi={https://doi.org/10.1007/s12532-022-00226-0} -} +} diff --git a/previews/PR3883/packages/InfiniteOpt/index.html b/previews/PR3883/packages/InfiniteOpt/index.html index 35acc0c54a7..d7ca6c181bc 100644 --- a/previews/PR3883/packages/InfiniteOpt/index.html +++ b/previews/PR3883/packages/InfiniteOpt/index.html @@ -12,4 +12,4 @@ doi = {https://doi.org/10.1016/j.compchemeng.2021.107567}, url = {https://www.sciencedirect.com/science/article/pii/S0098135421003458}, author = {Joshua L. Pulsipher and Weiqi Zhang and Tyler J. Hongisto and Victor M. Zavala}, -}

    A pre-print version is freely available though arXiv.

    +}

    A pre-print version is freely available though arXiv.

    diff --git a/previews/PR3883/packages/Ipopt/index.html b/previews/PR3883/packages/Ipopt/index.html index 2db091cba78..5635f0c2c8a 100644 --- a/previews/PR3883/packages/Ipopt/index.html +++ b/previews/PR3883/packages/Ipopt/index.html @@ -124,4 +124,4 @@ LinearAlgebra.BLAS.lbt_forward(liblapack32) using Ipopt

    AppleAccelerate

    If you are using macOS ≥ v13.4 and you have AppleAccelerate.jl installed, add using AppleAccelerate to your code:

    using AppleAccelerate
     using Ipopt

    Display backends

    Check what backends are loaded using:

    import LinearAlgebra
    -LinearAlgebra.BLAS.lbt_get_config()
    +LinearAlgebra.BLAS.lbt_get_config() diff --git a/previews/PR3883/packages/Juniper/index.html b/previews/PR3883/packages/Juniper/index.html index 83a2c7d75f0..0cb1700f48e 100644 --- a/previews/PR3883/packages/Juniper/index.html +++ b/previews/PR3883/packages/Juniper/index.html @@ -33,4 +33,4 @@ year="2018", publisher="Springer International Publishing", isbn="978-3-319-93031-2" -} +} diff --git a/previews/PR3883/packages/KNITRO/index.html b/previews/PR3883/packages/KNITRO/index.html index eccea06dc72..f8e262e6978 100644 --- a/previews/PR3883/packages/KNITRO/index.html +++ b/previews/PR3883/packages/KNITRO/index.html @@ -10,4 +10,4 @@ set_attribute(model, "algorithm", 4)

    Use with AMPL

    To use KNITRO with AmplNLWriter.jl, use KNITRO.amplexe:

    using JuMP
     import AmplNLWriter
     import KNITRO
    -model = Model(() -> AmplNLWriter.Optimizer(KNITRO.amplexe, ["outlev=3"]))

    Use with other packages

    A variety of packages extend KNITRO.jl to support other optimization modeling systems. These include:

    MathOptInterface API

    The Knitro optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    A list of available options is provided in the KNITRO reference manual.

    Low-level wrapper

    The complete C API can be accessed via KNITRO.KN_xx functions, where the names and arguments are identical to the C API.

    See the KNITRO documentation for details.

    As general rules when converting from Julia to C:

    • When KNITRO requires a Ptr{T} that holds one element, like double *, use a Ref{T}().
    • When KNITRO requires a Ptr{T} that holds multiple elements, use a Vector{T}.
    • When KNITRO requires a double, use Cdouble
    • When KNITRO requires an int, use Cint
    • When KNITRO requires a NULL, use C_NULL

    Extensive examples using the C wrapper can be found in examples/.

    Breaking changes

    KNITRO.jl v0.14.0 introduced a number of breaking changes to the low-level C API. The main changes were:

    1. removing Julia-specific functions like KN_set_param. Use the C API functions like KN_set_int_param and KN_set_double_param_by_name.
    2. removing intermediate methods that tried to make the C API more Julia-like. For example, we have removed the KN_add_var method that returned the index of the variable. There is now only the method from the C API.

    If you have trouble updating, please open a GitHub issue.

    Multi-threading

    Due to limitations in the interaction between Julia and C, KNITRO.jl disables multi-threading if the problem is nonlinear. This will override any options such as par_numthreads that you may have set.

    If you are using the low-level API, opt-in to enable multi-threading by calling KN_solve(model.env) instead of KN_solve(model), where model is the value returned by model = KN_new(). Note that calling KN_solve(model.env) is an advanced operation because it requires all callbacks you provide to be threadsafe.

    Read GitHub issue #93 for more details.

    +model = Model(() -> AmplNLWriter.Optimizer(KNITRO.amplexe, ["outlev=3"]))

    Use with other packages

    A variety of packages extend KNITRO.jl to support other optimization modeling systems. These include:

    MathOptInterface API

    The Knitro optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    A list of available options is provided in the KNITRO reference manual.

    Low-level wrapper

    The complete C API can be accessed via KNITRO.KN_xx functions, where the names and arguments are identical to the C API.

    See the KNITRO documentation for details.

    As general rules when converting from Julia to C:

    • When KNITRO requires a Ptr{T} that holds one element, like double *, use a Ref{T}().
    • When KNITRO requires a Ptr{T} that holds multiple elements, use a Vector{T}.
    • When KNITRO requires a double, use Cdouble
    • When KNITRO requires an int, use Cint
    • When KNITRO requires a NULL, use C_NULL

    Extensive examples using the C wrapper can be found in examples/.

    Breaking changes

    KNITRO.jl v0.14.0 introduced a number of breaking changes to the low-level C API. The main changes were:

    1. removing Julia-specific functions like KN_set_param. Use the C API functions like KN_set_int_param and KN_set_double_param_by_name.
    2. removing intermediate methods that tried to make the C API more Julia-like. For example, we have removed the KN_add_var method that returned the index of the variable. There is now only the method from the C API.

    If you have trouble updating, please open a GitHub issue.

    Multi-threading

    Due to limitations in the interaction between Julia and C, KNITRO.jl disables multi-threading if the problem is nonlinear. This will override any options such as par_numthreads that you may have set.

    If you are using the low-level API, opt-in to enable multi-threading by calling KN_solve(model.env) instead of KN_solve(model), where model is the value returned by model = KN_new(). Note that calling KN_solve(model.env) is an advanced operation because it requires all callbacks you provide to be threadsafe.

    Read GitHub issue #93 for more details.

    diff --git a/previews/PR3883/packages/Loraine/index.html b/previews/PR3883/packages/Loraine/index.html index 3ff1bc5dead..3e7b262dc56 100644 --- a/previews/PR3883/packages/Loraine/index.html +++ b/previews/PR3883/packages/Loraine/index.html @@ -37,4 +37,4 @@ www={https://hal.science/hal-04076509/} note={Preprint hal-04076509} year={2023} -}
    • 1https://www.youtube.com/watch?v=0D2wNf1lVrI
    +}
    • 1https://www.youtube.com/watch?v=0D2wNf1lVrI
    diff --git a/previews/PR3883/packages/MAiNGO/index.html b/previews/PR3883/packages/MAiNGO/index.html index 8df0b02adbb..d73770bb172 100644 --- a/previews/PR3883/packages/MAiNGO/index.html +++ b/previews/PR3883/packages/MAiNGO/index.html @@ -94,4 +94,4 @@ findMAiNGO(preferred=MAiNGO.C_API) # switch back to MAiNGO_jll findMAiNGO(preferred=MAiNGO.MAINGO_JLL)

    The findMAiNGO() function takes several optional arguments, which can be passed as keyword-arguments:

    • verbose: boolean, whether or not progress on finding MAiNGO is reported. (Default value: false)
    • preferred: either MAiNGO.MAINGOJLL or MAiNGO.CAPI, determines whether jll binaries or custom installation of MAiNGO is preferred. Note that the C-API is always preferred to the standalone version. If a custom standalone version should be used, set this value to C-API and pass an empty string as the capi argument (see next). (Default value: MAINGOJLL)
    • capi: string, path to C-API file. If set, this overrides the environment variable MAINGOLIB.
    • standalone: string, path to standalone executable file. If set, this overrides the environment variable MAINGO_EXEC.

    For example, to use the C-API at a new location, one could call:

    using MAiNGO
    -findMAiNGO(preferred=MAiNGO.C_API, c_api="path\\to\\c\\api\\shared_parser.dll")

    Currently working:

    • Integer and binary variables.
    • Affine, Quadratic and nonlinear constraints and objectives.
    • Operations: min,max,*,/,+,-,-(unary), exp,log,abs,sqrt,^
      • Other operations are easy to add if supported by MathOptInterface,ALE and MAiNGO.
    • Writing problem defined in JuMP syntax to an ALE problem.txt and calling MAiNGO.exe on a specified path.
    • Alternatively using a C-API to call MAiNGO.

    Restrictions compared to using the Python or C++ interface

    It is assumed that all variables are bounded. This interface assumes that integer variables are bounded between -1e6 and 1e6. For real variables these bounds are -1e8 and 1e8.

    Other functionality such as special support for growing datasets or MPI parallelization is not currently supported via this wrapper. Additionally, constraint formulations are simply passed from their representation in JuMP/MathOptInterface to MAiNGO. As such, there is no way to make use of advanced techniques such as defining constraints that are only used for the relaxations, using special relaxations for functions used in thermodynamics and process engineering or formulating reduced space formulations.

    Tests

    A subset of test cases for MathOptInterface solvers can be run by running the script ./test/runtests.jl. The current release was tested in the following combinations:

    • Julia 1.8.5 and MathOptInterface v1.18.0
    • Julia 1.9.4 and MathOptInterface v1.23.0.
    +findMAiNGO(preferred=MAiNGO.C_API, c_api="path\\to\\c\\api\\shared_parser.dll")

    Currently working:

    • Integer and binary variables.
    • Affine, Quadratic and nonlinear constraints and objectives.
    • Operations: min,max,*,/,+,-,-(unary), exp,log,abs,sqrt,^
      • Other operations are easy to add if supported by MathOptInterface,ALE and MAiNGO.
    • Writing problem defined in JuMP syntax to an ALE problem.txt and calling MAiNGO.exe on a specified path.
    • Alternatively using a C-API to call MAiNGO.

    Restrictions compared to using the Python or C++ interface

    It is assumed that all variables are bounded. This interface assumes that integer variables are bounded between -1e6 and 1e6. For real variables these bounds are -1e8 and 1e8.

    Other functionality such as special support for growing datasets or MPI parallelization is not currently supported via this wrapper. Additionally, constraint formulations are simply passed from their representation in JuMP/MathOptInterface to MAiNGO. As such, there is no way to make use of advanced techniques such as defining constraints that are only used for the relaxations, using special relaxations for functions used in thermodynamics and process engineering or formulating reduced space formulations.

    Tests

    A subset of test cases for MathOptInterface solvers can be run by running the script ./test/runtests.jl. The current release was tested in the following combinations:

    • Julia 1.8.5 and MathOptInterface v1.18.0
    • Julia 1.9.4 and MathOptInterface v1.23.0.
    diff --git a/previews/PR3883/packages/MadNLP/index.html b/previews/PR3883/packages/MadNLP/index.html index 916f2e60773..ac8f581c5c9 100644 --- a/previews/PR3883/packages/MadNLP/index.html +++ b/previews/PR3883/packages/MadNLP/index.html @@ -43,4 +43,4 @@ author={Shin, Sungho and Coffrin, Carleton and Sundar, Kaarthik and Zavala, Victor M}, journal={arXiv preprint arXiv:2010.02404}, year={2020} -}

    Supporting MadNLP.jl

    +}

    Supporting MadNLP.jl

    diff --git a/previews/PR3883/packages/Manopt/index.html b/previews/PR3883/packages/Manopt/index.html index d8449d2eb6b..a5c6af7bb48 100644 --- a/previews/PR3883/packages/Manopt/index.html +++ b/previews/PR3883/packages/Manopt/index.html @@ -30,4 +30,4 @@ TITLE = {Manifolds.jl: An Extensible Julia Framework for Data Analysis on Manifolds}, VOLUME = {49}, YEAR = {2023} -}

    as well. Note that all citations are in BibLaTeX format.

    Manopt.jl belongs to the Manopt family:

    Did you use Manopt.jl somewhere? Let us know! We'd love to collect those here as well.

    +}

    as well. Note that all citations are in BibLaTeX format.

    Manopt.jl belongs to the Manopt family:

    Did you use Manopt.jl somewhere? Let us know! We'd love to collect those here as well.

    diff --git a/previews/PR3883/packages/MathOptAI/index.html b/previews/PR3883/packages/MathOptAI/index.html index 286309f1dcb..89d1409b744 100644 --- a/previews/PR3883/packages/MathOptAI/index.html +++ b/previews/PR3883/packages/MathOptAI/index.html @@ -31,4 +31,4 @@ moai_SoftMax[7] moai_SoftMax[8] moai_SoftMax[9] - moai_SoftMax[10]

    Documentation

    Documentation is available at https://lanl-ansi.github.io/MathOptAI.jl.

    Getting help

    For help, questions, comments, and suggestions, please open a GitHub issue.

    Inspiration

    This project is mainly inspired by two existing projects:

    Other works, from which we took less inspiration, include:

    The 2024 paper of López-Flores et al. is an excellent summary of the state of the field at the time that we started development of MathOptAI.

    López-Flores, F.J., Ramírez-Márquez, C., Ponce-Ortega J.M. (2024). Process Systems Engineering Tools for Optimization of Trained Machine Learning Models: Comparative and Perspective. Industrial & Engineering Chemistry Research, 63(32), 13966-13979. DOI: 10.1021/acs.iecr.4c00632

    + moai_SoftMax[10]

    Documentation

    Documentation is available at https://lanl-ansi.github.io/MathOptAI.jl.

    Getting help

    For help, questions, comments, and suggestions, please open a GitHub issue.

    Inspiration

    This project is mainly inspired by two existing projects:

    Other works, from which we took less inspiration, include:

    The 2024 paper of López-Flores et al. is an excellent summary of the state of the field at the time that we started development of MathOptAI.

    López-Flores, F.J., Ramírez-Márquez, C., Ponce-Ortega J.M. (2024). Process Systems Engineering Tools for Optimization of Trained Machine Learning Models: Comparative and Perspective. Industrial & Engineering Chemistry Research, 63(32), 13966-13979. DOI: 10.1021/acs.iecr.4c00632

    diff --git a/previews/PR3883/packages/MathOptSymbolicAD/index.html b/previews/PR3883/packages/MathOptSymbolicAD/index.html index 220ac48c7b5..ec3c6e68182 100644 --- a/previews/PR3883/packages/MathOptSymbolicAD/index.html +++ b/previews/PR3883/packages/MathOptSymbolicAD/index.html @@ -18,4 +18,4 @@ optimize!(model)

    Background

    MathOptSymbolicAD is inspired by Hassan Hijazi's work on coin-or/gravity, a high-performance algebraic modeling language in C++.

    Hassan made the following observations:

    • For large scale models, symbolic differentiation is slower than other automatic differentiation techniques.
    • However, most large-scale nonlinear programs have a lot of structure.
    • Gravity asks the user to provide structure in the form of template constraints, where the user gives the symbolic form of the constraint as well as a set of data to convert from a symbolic form to the numerical form.
    • Instead of differentiating each constraint in its numerical form, we can compute one symbolic derivative of the constraint in symbolic form, and then plug in the data in to get the numerical derivative of each function.
    • As a final step, if users don't provide the structure, we can still infer it –perhaps with less accuracy–by comparing the expression tree of each constraint.

    The symbolic differentiation approach of Gravity works well when the problem is large with few unique constraints. For example, a model like:

    model = Model()
     @variable(model, 0 <= x[1:10_000] <= 1)
     @constraint(model, [i=1:10_000], sin(x[i]) <= 1)
    -@objective(model, Max, sum(x))

    is ideal, because although the Jacobian matrix has 10,000 rows, we can compute the derivative of sin(x[i]) as cos(x[i]), and then fill in the Jacobian by evaluating the derivative function instead of having to differentiation 10,000 expressions.

    The symbolic differentiation approach of Gravity works poorly if there are a large number of unique constraints in the model (which would require a lot of expressions to be symbolically differentiated), or if the nonlinear functions contain a large number of nonlinear terms (which would make the symbolic derivative expensive to compute).

    For more details, see Oscar's JuMP-dev 2022 talk, although note that the syntax has changed since the original recording.

    +@objective(model, Max, sum(x))

    is ideal, because although the Jacobian matrix has 10,000 rows, we can compute the derivative of sin(x[i]) as cos(x[i]), and then fill in the Jacobian by evaluating the derivative function instead of having to differentiation 10,000 expressions.

    The symbolic differentiation approach of Gravity works poorly if there are a large number of unique constraints in the model (which would require a lot of expressions to be symbolically differentiated), or if the nonlinear functions contain a large number of nonlinear terms (which would make the symbolic derivative expensive to compute).

    For more details, see Oscar's JuMP-dev 2022 talk, although note that the syntax has changed since the original recording.

    diff --git a/previews/PR3883/packages/MiniZinc/index.html b/previews/PR3883/packages/MiniZinc/index.html index 827a934bba7..7a86bb68841 100644 --- a/previews/PR3883/packages/MiniZinc/index.html +++ b/previews/PR3883/packages/MiniZinc/index.html @@ -53,4 +53,4 @@ @constraint(model, x in MOI.AllDifferent(3)) @objective(model, Max, sum(i * x[i] for i in 1:3)) optimize!(model) -@show value.(x)

    MathOptInterface API

    The MiniZinc Optimizer{T} supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    Set options using MOI.RawOptimizerAttribute in MOI or set_attribute in JuMP.

    MiniZinc.jl supports the following options:

    • model_filename::String = "": the location at which to write out the .mzn file during optimization. This option can be helpful during debugging. If left empty, a temporary file will be used instead.

    • MOI.SolutionLimit: set this option to a positive integer to return up to the limit number of solutions.

    +@show value.(x)

    MathOptInterface API

    The MiniZinc Optimizer{T} supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Options

    Set options using MOI.RawOptimizerAttribute in MOI or set_attribute in JuMP.

    MiniZinc.jl supports the following options:

    • model_filename::String = "": the location at which to write out the .mzn file during optimization. This option can be helpful during debugging. If left empty, a temporary file will be used instead.

    • MOI.SolutionLimit: set this option to a positive integer to return up to the limit number of solutions.

    diff --git a/previews/PR3883/packages/MosekTools/index.html b/previews/PR3883/packages/MosekTools/index.html index 42266cda3bf..c1b85deb884 100644 --- a/previews/PR3883/packages/MosekTools/index.html +++ b/previews/PR3883/packages/MosekTools/index.html @@ -7,4 +7,4 @@ using MosekTools model = Model(Mosek.Optimizer) set_attribute(model, "QUIET", true) -set_attribute(model, "INTPNT_CO_TOL_DFEAS", 1e-7)

    Options

    The parameter QUIET is a special parameter that when set to true disables all Mosek printing output.

    All other parameters can be found in the Mosek documentation.

    Note that the prefix MSK_IPAR_ (for integer parameters), MSK_DPAR_ (for floating point parameters) or MSK_SPAR_ (for string parameters) are optional. If they are not given, they are inferred from the type of the value. For example, in the example above, as 1e-7 is a floating point number, the parameters name used is MSK_DPAR_INTPNT_CO_TOL_DFEAS.

    +set_attribute(model, "INTPNT_CO_TOL_DFEAS", 1e-7)

    Options

    The parameter QUIET is a special parameter that when set to true disables all Mosek printing output.

    All other parameters can be found in the Mosek documentation.

    Note that the prefix MSK_IPAR_ (for integer parameters), MSK_DPAR_ (for floating point parameters) or MSK_SPAR_ (for string parameters) are optional. If they are not given, they are inferred from the type of the value. For example, in the example above, as 1e-7 is a floating point number, the parameters name used is MSK_DPAR_INTPNT_CO_TOL_DFEAS.

    diff --git a/previews/PR3883/packages/MultiObjectiveAlgorithms/index.html b/previews/PR3883/packages/MultiObjectiveAlgorithms/index.html index 5e4e42ab3ee..f4d4befd1d2 100644 --- a/previews/PR3883/packages/MultiObjectiveAlgorithms/index.html +++ b/previews/PR3883/packages/MultiObjectiveAlgorithms/index.html @@ -9,4 +9,4 @@ import MultiObjectiveAlgorithms as MOA model = JuMP.Model(() -> MOA.Optimizer(HiGHS.Optimizer)) set_attribute(model, MOA.Algorithm(), MOA.Dichotomy()) -set_attribute(model, MOA.SolutionLimit(), 4)

    Replace HiGHS.Optimizer with an optimizer capable of solving a single-objective instance of your optimization problem.

    You may set additional optimizer attributes, the supported attributes depend on the choice of solution algorithm.

    Algorithm

    Set the algorithm using the MOA.Algorithm() attribute.

    The value must be one of the algorithms supported by MOA:

    • MOA.Chalmet()
    • MOA.Dichotomy()
    • MOA.DominguezRios()
    • MOA.EpsilonConstraint()
    • MOA.Hierarchical()
    • MOA.KirlikSayin()
    • MOA.Lexicographic() [default]
    • MOA.TambyVanderpooten()

    Consult their docstrings for details.

    Other optimizer attributes

    There are a number of optimizer attributes supported by the algorithms in MOA.

    Each algorithm supports only a subset of the attributes. Consult the algorithm's docstring for details on which attributes it supports, and how it uses them in the solution process.

    • MOA.EpsilonConstraintStep()
    • MOA.LexicographicAllPermutations()
    • MOA.ObjectiveAbsoluteTolerance(index::Int)
    • MOA.ObjectivePriority(index::Int)
    • MOA.ObjectiveRelativeTolerance(index::Int)
    • MOA.ObjectiveWeight(index::Int)
    • MOA.SolutionLimit()
    • MOI.TimeLimitSec()
    +set_attribute(model, MOA.SolutionLimit(), 4)

    Replace HiGHS.Optimizer with an optimizer capable of solving a single-objective instance of your optimization problem.

    You may set additional optimizer attributes, the supported attributes depend on the choice of solution algorithm.

    Algorithm

    Set the algorithm using the MOA.Algorithm() attribute.

    The value must be one of the algorithms supported by MOA:

    • MOA.Chalmet()
    • MOA.Dichotomy()
    • MOA.DominguezRios()
    • MOA.EpsilonConstraint()
    • MOA.Hierarchical()
    • MOA.KirlikSayin()
    • MOA.Lexicographic() [default]
    • MOA.TambyVanderpooten()

    Consult their docstrings for details.

    Other optimizer attributes

    There are a number of optimizer attributes supported by the algorithms in MOA.

    Each algorithm supports only a subset of the attributes. Consult the algorithm's docstring for details on which attributes it supports, and how it uses them in the solution process.

    • MOA.EpsilonConstraintStep()
    • MOA.LexicographicAllPermutations()
    • MOA.ObjectiveAbsoluteTolerance(index::Int)
    • MOA.ObjectivePriority(index::Int)
    • MOA.ObjectiveRelativeTolerance(index::Int)
    • MOA.ObjectiveWeight(index::Int)
    • MOA.SolutionLimit()
    • MOI.TimeLimitSec()
    diff --git a/previews/PR3883/packages/NEOSServer/index.html b/previews/PR3883/packages/NEOSServer/index.html index 46b71239445..fb0445da547 100644 --- a/previews/PR3883/packages/NEOSServer/index.html +++ b/previews/PR3883/packages/NEOSServer/index.html @@ -27,4 +27,4 @@ results = neos_getFinalResults(server, job)

    Use with JuMP

    Use NEOSServer.jl with JuMP as follows:

    using JuMP, NEOSServer
     model = Model() do
         return NEOSServer.Optimizer(; email = "me@mydomain.com", solver = "Ipopt")
    -end

    Note: NEOSServer.Optimizer is limited to the following solvers:

    • "CPLEX"
    • "FICO-Xpress"
    • "Ipopt"
    • "Knitro"
    • "MOSEK"
    • "OCTERACT"
    • "SNOPT"

    NEOS Limits

    NEOS currently limits jobs to an 8 hour time limit, 3 GB of memory, and a 16 MB submission file. If your model exceeds these limits, NEOSServer.jl may be unable to return useful information to the user.

    +end

    Note: NEOSServer.Optimizer is limited to the following solvers:

    • "CPLEX"
    • "FICO-Xpress"
    • "Ipopt"
    • "Knitro"
    • "MOSEK"
    • "OCTERACT"
    • "SNOPT"

    NEOS Limits

    NEOS currently limits jobs to an 8 hour time limit, 3 GB of memory, and a 16 MB submission file. If your model exceeds these limits, NEOSServer.jl may be unable to return useful information to the user.

    diff --git a/previews/PR3883/packages/NLopt/index.html b/previews/PR3883/packages/NLopt/index.html index 866ba5d4d9e..9b02eef59f4 100644 --- a/previews/PR3883/packages/NLopt/index.html +++ b/previews/PR3883/packages/NLopt/index.html @@ -120,4 +120,4 @@ opt = Opt(:LD_MMA, 2) # Define problem solutions[i] = optimize(opt, rand(2)) -end

    Author

    This module was initially written by Steven G. Johnson, with subsequent contributions by several other authors (see the git history).

    +end

    Author

    This module was initially written by Steven G. Johnson, with subsequent contributions by several other authors (see the git history).

    diff --git a/previews/PR3883/packages/OSQP/index.html b/previews/PR3883/packages/OSQP/index.html index 352d40d39d5..47fb59b32f1 100644 --- a/previews/PR3883/packages/OSQP/index.html +++ b/previews/PR3883/packages/OSQP/index.html @@ -6,4 +6,4 @@

    OSQP.jl

    Build Status codecov.io

    OSQP.jl is a Julia wrapper for OSQP: the Operator Splitting QP Solver.

    License

    OSQP.jl is licensed under the Apache-2.0 license.

    The upstream solver, osqp/osqp is also licensed under the Apache-2.0 license.

    Installation

    Install OSQP.jl using the Julia package manager

    import Pkg
     Pkg.add("OSQP")

    Problem class

    The OSQP (Operator Splitting Quadratic Program) solver is a numerical optimization package for solving problems in the form

    minimize        0.5 x' P x + q' x
     
    -subject to      l <= A x <= u

    where x in R^n is the optimization variable. The objective function is defined by a positive semidefinite matrix P in S^n_+ and vector q in R^n. The linear constraints are defined by matrix A in R^{m x n} and vectors l in R^m U {-inf}^m, u in R^m U {+inf}^m.

    Documentation

    Detailed documentation is available at https://osqp.org/.

    +subject to l <= A x <= u

    where x in R^n is the optimization variable. The objective function is defined by a positive semidefinite matrix P in S^n_+ and vector q in R^n. The linear constraints are defined by matrix A in R^{m x n} and vectors l in R^m U {-inf}^m, u in R^m U {+inf}^m.

    Documentation

    Detailed documentation is available at https://osqp.org/.

    diff --git a/previews/PR3883/packages/Optim/index.html b/previews/PR3883/packages/Optim/index.html index eadfbbb6ca5..5830ad7ae5b 100644 --- a/previews/PR3883/packages/Optim/index.html +++ b/previews/PR3883/packages/Optim/index.html @@ -105,4 +105,4 @@ number = {24}, pages = {615}, doi = {10.21105/joss.00615} -} +} diff --git a/previews/PR3883/packages/PATHSolver/index.html b/previews/PR3883/packages/PATHSolver/index.html index 95711ce92ed..9c35731a910 100644 --- a/previews/PR3883/packages/PATHSolver/index.html +++ b/previews/PR3883/packages/PATHSolver/index.html @@ -165,4 +165,4 @@ 0.8 1.2

    Thread safety

    PATH is not thread-safe and there are no known work-arounds. Do not run it in parallel using Threads.@threads. See issue #62 for more details.

    Factorization methods

    By default, PATHSolver.jl will download the LUSOL shared library. To use LUSOL, set the following options:

    model = Model(PATHSolver.Optimizer)
     set_optimizer_attribute(model, "factorization_method", "blu_lusol")
    -set_optimizer_attribute(model, "factorization_library_name", PATHSolver.LUSOL_LIBRARY_PATH)

    To use factorization_method umfpack you will need the umfpack shared library that is available directly from the developers of that code for academic use.

    Manual installation

    By default PATHSolver.jl will download a copy of the libpath library. If you already have one installed and want to use that, set the PATH_JL_LOCATION environment variable to point to the libpath50.xx library.

    +set_optimizer_attribute(model, "factorization_library_name", PATHSolver.LUSOL_LIBRARY_PATH)

    To use factorization_method umfpack you will need the umfpack shared library that is available directly from the developers of that code for academic use.

    Manual installation

    By default PATHSolver.jl will download a copy of the libpath library. If you already have one installed and want to use that, set the PATH_JL_LOCATION environment variable to point to the libpath50.xx library.

    diff --git a/previews/PR3883/packages/Pajarito/index.html b/previews/PR3883/packages/Pajarito/index.html index d44345e51bc..9f68eb1a207 100644 --- a/previews/PR3883/packages/Pajarito/index.html +++ b/previews/PR3883/packages/Pajarito/index.html @@ -27,4 +27,4 @@ pages={249--293}, year={2020}, publisher={Springer} -}

    Note this paper describes a legacy MathProgBase version of Pajarito, which is available on the mathprogbase branch of this repository. Starting with version v0.8.0, Pajarito supports MathOptInterface instead of MathProgBase.

    +}

    Note this paper describes a legacy MathProgBase version of Pajarito, which is available on the mathprogbase branch of this repository. Starting with version v0.8.0, Pajarito supports MathOptInterface instead of MathProgBase.

    diff --git a/previews/PR3883/packages/ParametricOptInterface/index.html b/previews/PR3883/packages/ParametricOptInterface/index.html index 20f98f25471..75aedfaa65e 100644 --- a/previews/PR3883/packages/ParametricOptInterface/index.html +++ b/previews/PR3883/packages/ParametricOptInterface/index.html @@ -13,4 +13,4 @@ @objective(model, Min, 2x) optimize!(model) MOI.set(model, POI.ParameterValue(), p, 2.0) -optimize!(model)

    GSOC2020

    ParametricOptInterface began as a NumFOCUS sponsored Google Summer of Code (2020) project.

    +optimize!(model)

    GSOC2020

    ParametricOptInterface began as a NumFOCUS sponsored Google Summer of Code (2020) project.

    diff --git a/previews/PR3883/packages/Pavito/index.html b/previews/PR3883/packages/Pavito/index.html index 2c5cfd6d835..d59b73c87a0 100644 --- a/previews/PR3883/packages/Pavito/index.html +++ b/previews/PR3883/packages/Pavito/index.html @@ -13,4 +13,4 @@ "cont_solver" => optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0), ), -)

    The algorithm implemented by Pavito itself is relatively simple; most of the hard work is performed by the MILP solver passed as mip_solver and the NLP solver passed as cont_solver.

    The performance of Pavito depends on these two types of solvers.

    For better performance, you should use a commercial MILP solver such as CPLEX or Gurobi.

    Options

    The following optimizer attributes can set to a Pavito.Optimizer to modify its behavior:

    • log_level::Int Verbosity flag: 0 for quiet, higher for basic solve info
    • timeout::Float64 Time limit for algorithm (in seconds)
    • rel_gap::Float64 Relative optimality gap termination condition
    • mip_solver_drives::Bool Let MILP solver manage convergence ("branch and cut")
    • mip_solver::MOI.OptimizerWithAttributes MILP solver
    • cont_solver::MOI.OptimizerWithAttributes Continuous NLP solver

    Pavito is not yet numerically robust and may require tuning of parameters to improve convergence.

    If the default parameters don't work for you, please let us know by opening an issue.

    For improved Pavito performance, MILP solver integrality tolerance and feasibility tolerances should typically be tightened, for example to 1e-8.

    Bug reports and support

    Please report any issues via the GitHub issue tracker. All types of issues are welcome and encouraged; this includes bug reports, documentation typos, feature requests, etc. The Optimization (Mathematical) category on Discourse is appropriate for general discussion.

    +)

    The algorithm implemented by Pavito itself is relatively simple; most of the hard work is performed by the MILP solver passed as mip_solver and the NLP solver passed as cont_solver.

    The performance of Pavito depends on these two types of solvers.

    For better performance, you should use a commercial MILP solver such as CPLEX or Gurobi.

    Options

    The following optimizer attributes can set to a Pavito.Optimizer to modify its behavior:

    • log_level::Int Verbosity flag: 0 for quiet, higher for basic solve info
    • timeout::Float64 Time limit for algorithm (in seconds)
    • rel_gap::Float64 Relative optimality gap termination condition
    • mip_solver_drives::Bool Let MILP solver manage convergence ("branch and cut")
    • mip_solver::MOI.OptimizerWithAttributes MILP solver
    • cont_solver::MOI.OptimizerWithAttributes Continuous NLP solver

    Pavito is not yet numerically robust and may require tuning of parameters to improve convergence.

    If the default parameters don't work for you, please let us know by opening an issue.

    For improved Pavito performance, MILP solver integrality tolerance and feasibility tolerances should typically be tightened, for example to 1e-8.

    Bug reports and support

    Please report any issues via the GitHub issue tracker. All types of issues are welcome and encouraged; this includes bug reports, documentation typos, feature requests, etc. The Optimization (Mathematical) category on Discourse is appropriate for general discussion.

    diff --git a/previews/PR3883/packages/Percival/index.html b/previews/PR3883/packages/Percival/index.html index 42a5c5a9b3a..d6813ddce18 100644 --- a/previews/PR3883/packages/Percival/index.html +++ b/previews/PR3883/packages/Percival/index.html @@ -22,4 +22,4 @@ [1.0], [1.0], ) -output = percival(nlp, verbose = 1)

    Bug reports and discussions

    If you think you found a bug, feel free to open an issue. Focused suggestions and requests can also be opened as issues. Before opening a pull request, start an issue or a discussion on the topic, please.

    If you want to ask a question not suited for a bug report, feel free to start a discussion here. This forum is for general discussion about this repository and the JuliaSmoothOptimizers, so questions about any of our packages are welcome.

    +output = percival(nlp, verbose = 1)

    Bug reports and discussions

    If you think you found a bug, feel free to open an issue. Focused suggestions and requests can also be opened as issues. Before opening a pull request, start an issue or a discussion on the topic, please.

    If you want to ask a question not suited for a bug report, feel free to start a discussion here. This forum is for general discussion about this repository and the JuliaSmoothOptimizers, so questions about any of our packages are welcome.

    diff --git a/previews/PR3883/packages/PiecewiseLinearOpt/index.html b/previews/PR3883/packages/PiecewiseLinearOpt/index.html index 0c56dff43a8..7521b3824f3 100644 --- a/previews/PR3883/packages/PiecewiseLinearOpt/index.html +++ b/previews/PR3883/packages/PiecewiseLinearOpt/index.html @@ -41,4 +41,4 @@ (u, v) -> exp(u + v); method = :DisaggLogarithmic, ) -@objective(model, Min, z)

    Methods

    Supported univariate formulations:

    • Convex combination (:CC)
    • Multiple choice (:MC)
    • Native SOS2 branching (:SOS2)
    • Incremental (:Incremental)
    • Logarithmic (:Logarithmic; default)
    • Disaggregated Logarithmic (:DisaggLogarithmic)
    • Binary zig-zag (:ZigZag)
    • General integer zig-zag (:ZigZagInteger)

    Supported bivariate formulations for entire constraint:

    • Convex combination (:CC)
    • Multiple choice (:MC)
    • Disaggregated Logarithmic (:DisaggLogarithmic)

    Also, you can use any univariate formulation for bivariate functions as well. They will be used to impose two axis-aligned SOS2 constraints, along with the "6-stencil" formulation for the triangle selection portion of the constraint. See the associated paper for more details. In particular, the following are also acceptable bivariate formulation choices:

    • Native SOS2 branching (:SOS2)
    • Incremental (:Incremental)
    • Logarithmic (:Logarithmic)
    • Binary zig-zag (:ZigZag)
    • General integer zig-zag (:ZigZagInteger)
    +@objective(model, Min, z)

    Methods

    Supported univariate formulations:

    • Convex combination (:CC)
    • Multiple choice (:MC)
    • Native SOS2 branching (:SOS2)
    • Incremental (:Incremental)
    • Logarithmic (:Logarithmic; default)
    • Disaggregated Logarithmic (:DisaggLogarithmic)
    • Binary zig-zag (:ZigZag)
    • General integer zig-zag (:ZigZagInteger)

    Supported bivariate formulations for entire constraint:

    • Convex combination (:CC)
    • Multiple choice (:MC)
    • Disaggregated Logarithmic (:DisaggLogarithmic)

    Also, you can use any univariate formulation for bivariate functions as well. They will be used to impose two axis-aligned SOS2 constraints, along with the "6-stencil" formulation for the triangle selection portion of the constraint. See the associated paper for more details. In particular, the following are also acceptable bivariate formulation choices:

    • Native SOS2 branching (:SOS2)
    • Incremental (:Incremental)
    • Logarithmic (:Logarithmic)
    • Binary zig-zag (:ZigZag)
    • General integer zig-zag (:ZigZagInteger)
    diff --git a/previews/PR3883/packages/Plasmo/index.html b/previews/PR3883/packages/Plasmo/index.html index 278b585af22..9e591b3b978 100644 --- a/previews/PR3883/packages/Plasmo/index.html +++ b/previews/PR3883/packages/Plasmo/index.html @@ -50,4 +50,4 @@ volume = {125}, year = {2019}, doi = {10.1016/j.compchemeng.2019.03.009} -}

    A pre-print of this paper can be found here

    +}

    A pre-print of this paper can be found here

    diff --git a/previews/PR3883/packages/PolyJuMP/index.html b/previews/PR3883/packages/PolyJuMP/index.html index 67e77e46b16..0c99825b8a9 100644 --- a/previews/PR3883/packages/PolyJuMP/index.html +++ b/previews/PR3883/packages/PolyJuMP/index.html @@ -17,4 +17,4 @@ model = Model(optimizer_with_attributes( PolyJuMP.KKT.Optimizer, "solver" => HomotopyContinuation.SemialgebraicSetsHCSolver(), -))

    Documentation

    Documentation for PolyJuMP.jl is included in the documentation for SumOfSquares.jl.

    +))

    Documentation

    Documentation for PolyJuMP.jl is included in the documentation for SumOfSquares.jl.

    diff --git a/previews/PR3883/packages/ProxSDP/index.html b/previews/PR3883/packages/ProxSDP/index.html index aaf26c9822a..7895556abac 100644 --- a/previews/PR3883/packages/ProxSDP/index.html +++ b/previews/PR3883/packages/ProxSDP/index.html @@ -56,4 +56,4 @@ publisher = {Taylor & Francis}, doi = {10.1080/02331934.2020.1823387}, URL = {https://doi.org/10.1080/02331934.2020.1823387} -}

    The preprint version of the paper can be found here.

    Disclaimer

    • ProxSDP is a research software, therefore it should not be used in production.
    • Please open an issue if you find any problems, developers will try to fix and find alternatives.
    • There is no continuous development for 32-bit systems, the package should work, but might reach some issues.
    • ProxSDP assumes primal and dual feasibility.

    ROAD MAP

    • Support for exponential and power cones
    • Warm start
    +}

    The preprint version of the paper can be found here.

    Disclaimer

    • ProxSDP is a research software, therefore it should not be used in production.
    • Please open an issue if you find any problems, developers will try to fix and find alternatives.
    • There is no continuous development for 32-bit systems, the package should work, but might reach some issues.
    • ProxSDP assumes primal and dual feasibility.

    ROAD MAP

    • Support for exponential and power cones
    • Warm start
    diff --git a/previews/PR3883/packages/SCIP/index.html b/previews/PR3883/packages/SCIP/index.html index e40d252f25b..486279d5404 100644 --- a/previews/PR3883/packages/SCIP/index.html +++ b/previews/PR3883/packages/SCIP/index.html @@ -14,4 +14,4 @@ julia> Pkg.build("SCIP")

    Use with JuMP

    Use SCIP with JuMP as follows:

    using JuMP, SCIP
     model = Model(SCIP.Optimizer)
     set_attribute(model, "display/verblevel", 0)
    -set_attribute(model, "limits/gap", 0.05)

    Options

    See the SCIP documentation for a list of supported options.

    MathOptInterface API

    The SCIP optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Design considerations

    Wrapping the public API

    All of the public API methods are wrapped and available within the SCIP package. This includes the scip_*.h and pub_*.h headers that are collected in scip.h, as well as all default constraint handlers (cons_*.h.)

    The wrapped functions do not transform any data structures and work on the raw pointers (for example, SCIP* in C, Ptr{SCIP_} in Julia). Convenience wrapper functions based on Julia types are added as needed.

    Memory management

    Programming with SCIP requires dealing with variable and constraint objects that use reference counting for memory management.

    The SCIP.Optimizer wrapper type collects lists of SCIP_VAR* and SCIP_CONS* under the hood, and it releases all references when it is garbage collected itself (via finalize).

    When adding a variable (add_variable) or a constraint (add_linear_constraint), an integer index is returned. This index can be used to retrieve the SCIP_VAR* or SCIP_CONS* pointer via get_var and get_cons respectively.

    Supported nonlinear operators

    Supported operators in nonlinear expressions are as follows:

    • +
    • -
    • *
    • /
    • ^
    • sqrt
    • exp
    • log
    • abs
    • cos
    • sin
    +set_attribute(model, "limits/gap", 0.05)

    Options

    See the SCIP documentation for a list of supported options.

    MathOptInterface API

    The SCIP optimizer supports the following constraints and attributes.

    List of supported objective functions:

    List of supported variable types:

    List of supported constraint types:

    List of supported model attributes:

    Design considerations

    Wrapping the public API

    All of the public API methods are wrapped and available within the SCIP package. This includes the scip_*.h and pub_*.h headers that are collected in scip.h, as well as all default constraint handlers (cons_*.h.)

    The wrapped functions do not transform any data structures and work on the raw pointers (for example, SCIP* in C, Ptr{SCIP_} in Julia). Convenience wrapper functions based on Julia types are added as needed.

    Memory management

    Programming with SCIP requires dealing with variable and constraint objects that use reference counting for memory management.

    The SCIP.Optimizer wrapper type collects lists of SCIP_VAR* and SCIP_CONS* under the hood, and it releases all references when it is garbage collected itself (via finalize).

    When adding a variable (add_variable) or a constraint (add_linear_constraint), an integer index is returned. This index can be used to retrieve the SCIP_VAR* or SCIP_CONS* pointer via get_var and get_cons respectively.

    Supported nonlinear operators

    Supported operators in nonlinear expressions are as follows:

    • +
    • -
    • *
    • /
    • ^
    • sqrt
    • exp
    • log
    • abs
    • cos
    • sin
    diff --git a/previews/PR3883/packages/SCS/index.html b/previews/PR3883/packages/SCS/index.html index 606fbb20a14..0c9d51db34a 100644 --- a/previews/PR3883/packages/SCS/index.html +++ b/previews/PR3883/packages/SCS/index.html @@ -53,4 +53,4 @@ julia> SCS.is_available(SCS.GpuIndirectSolver) true

    The GpuIndirectSolver is available on Linux x86_64 platform only.

    Low-level wrapper

    SCS.jl provides a low-level interface to solve a problem directly, without interfacing through MathOptInterface.

    This is an advanced interface with a risk of incorrect usage. For new users, we recommend that you use the JuMP or Convex interfaces instead.

    SCS solves a problem of the form:

    minimize        1/2 * x' * P * x + c' * x
     subject to      A * x + s = b
    -                s in K

    where K is a product cone of:

    • zero cone
    • positive orthant { x | x ≥ 0 }
    • box cone { (t,x) | t*l ≤ x ≤ t*u}
    • second-order cone (SOC) { (t,x) | ||x||_2 ≤ t }
    • semi-definite cone (SDC) { X | X is psd }
    • exponential cone { (x,y,z) | y e^(x/y) ≤ z, y>0 }
    • power cone { (x,y,z) | x^a * y^(1-a) ≥ |z|, x ≥ 0, y ≥ 0 }
    • dual power cone { (u,v,w) | (u/a)^a * (v/(1-a))^(1-a) ≥ |w|, u ≥ 0, v ≥ 0 }.

    To solve this problem with SCS, call SCS.scs_solve; see the docstring for details.

    + s in K

    where K is a product cone of:

    • zero cone
    • positive orthant { x | x ≥ 0 }
    • box cone { (t,x) | t*l ≤ x ≤ t*u}
    • second-order cone (SOC) { (t,x) | ||x||_2 ≤ t }
    • semi-definite cone (SDC) { X | X is psd }
    • exponential cone { (x,y,z) | y e^(x/y) ≤ z, y>0 }
    • power cone { (x,y,z) | x^a * y^(1-a) ≥ |z|, x ≥ 0, y ≥ 0 }
    • dual power cone { (u,v,w) | (u/a)^a * (v/(1-a))^(1-a) ≥ |w|, u ≥ 0, v ≥ 0 }.

    To solve this problem with SCS, call SCS.scs_solve; see the docstring for details.

    diff --git a/previews/PR3883/packages/SDDP/index.html b/previews/PR3883/packages/SDDP/index.html index 2328ea8fe5c..cafa48eca6c 100644 --- a/previews/PR3883/packages/SDDP/index.html +++ b/previews/PR3883/packages/SDDP/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -
    +
    diff --git a/previews/PR3883/packages/SDPA/index.html b/previews/PR3883/packages/SDPA/index.html index 6928550ca80..5014c6fd011 100644 --- a/previews/PR3883/packages/SDPA/index.html +++ b/previews/PR3883/packages/SDPA/index.html @@ -13,4 +13,4 @@ set_attribute(model, "Mode", SDPA.PARAMETER_STABLE_BUT_SLOW)

    Note that the parameters are set in the order they are given, so you can set a mode and then modify parameters from this mode.

    using JuMP, SDPA
     model = Model(SDPA.Optimizer)
     set_attribute(model, "Mode", SDPA.PARAMETER_STABLE_BUT_SLOW)
    -set_attribute(model, "MaxIteration", 100)

    The choice of parameter mode has a large impact on the performance and stability of SDPA, and not necessarily in the way implied by the names of the modes; for example, PARAMETER_UNSTABLE_BUT_FAST can be more stable than the other modes for some problems. You should try each mode to see how it performs on your specific problem. See SDPA.jl#17 for more details.

    +set_attribute(model, "MaxIteration", 100)

    The choice of parameter mode has a large impact on the performance and stability of SDPA, and not necessarily in the way implied by the names of the modes; for example, PARAMETER_UNSTABLE_BUT_FAST can be more stable than the other modes for some problems. You should try each mode to see how it performs on your specific problem. See SDPA.jl#17 for more details.

    diff --git a/previews/PR3883/packages/SDPLR/index.html b/previews/PR3883/packages/SDPLR/index.html index c33d1b96d12..1c54fb8a5b0 100644 --- a/previews/PR3883/packages/SDPLR/index.html +++ b/previews/PR3883/packages/SDPLR/index.html @@ -50,4 +50,4 @@ sigma *= 2 end lambdaupdate = 0 -end +end diff --git a/previews/PR3883/packages/SDPNAL/index.html b/previews/PR3883/packages/SDPNAL/index.html index 66daf023411..3dc71e99235 100644 --- a/previews/PR3883/packages/SDPNAL/index.html +++ b/previews/PR3883/packages/SDPNAL/index.html @@ -18,4 +18,4 @@ '/path/to/SDPNALv1.0/solver:', ... '/path/to/SDPNALv1.0/solver_main_default:', ... '/path/to/SDPNALv1.0/util:', ... -% (...)

    If you have SDPT3 in addition to SDPNAL in the MATLAB path (that is, the toolbox/local/pathdef.m file) then you might have issues because both solvers define a validate function, and this might make SDPNAL call SDPT3's validate function instead of SDPT3's validate function.

    +% (...)

    If you have SDPT3 in addition to SDPNAL in the MATLAB path (that is, the toolbox/local/pathdef.m file) then you might have issues because both solvers define a validate function, and this might make SDPNAL call SDPT3's validate function instead of SDPT3's validate function.

    diff --git a/previews/PR3883/packages/SDPT3/index.html b/previews/PR3883/packages/SDPT3/index.html index e4e91bddf75..b1d55b196d3 100644 --- a/previews/PR3883/packages/SDPT3/index.html +++ b/previews/PR3883/packages/SDPT3/index.html @@ -29,4 +29,4 @@ julia> MATLAB.restoredefaultpath() -julia> MATLAB.mat"savepath" +julia> MATLAB.mat"savepath" diff --git a/previews/PR3883/packages/SeDuMi/index.html b/previews/PR3883/packages/SeDuMi/index.html index 3f9a7f3abd3..7e5bae32bb9 100644 --- a/previews/PR3883/packages/SeDuMi/index.html +++ b/previews/PR3883/packages/SeDuMi/index.html @@ -17,4 +17,4 @@ MATLAB.mat"install_sedumi" end -julia> MATLAB.mat"savepath" +julia> MATLAB.mat"savepath" diff --git a/previews/PR3883/packages/SumOfSquares/index.html b/previews/PR3883/packages/SumOfSquares/index.html index d45a6cf9376..572716fdc4b 100644 --- a/previews/PR3883/packages/SumOfSquares/index.html +++ b/previews/PR3883/packages/SumOfSquares/index.html @@ -4,4 +4,4 @@ gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash});

    SumOfSquares.jl

    Build Status codecov

    SumOfSquares.jl is a JuMP extension that, when used in conjunction with MultivariatePolynomial and PolyJuMP, implements a sum of squares reformulation for polynomial optimization.

    License

    SumOfSquares.jl is licensed under the MIT license.

    Installation

    Install SumOfSquares using Pkg.add:

    import Pkg
    -Pkg.add("SumOfSquares")

    Documentation

    See https://jump.dev/SumOfSquares.jl/stable for the most recently tagged version of the documentation.

    See https://jump.dev/SumOfSquares.jl/dev for the in-development version of the documentation.

    Presentations

    Some presentations on, or using, SumOfSquares (see blegat/SumOfSquaresSlides for the source code of the presentations):

    Citing

    See CITATION.bib.

    +Pkg.add("SumOfSquares")

    Documentation

    See https://jump.dev/SumOfSquares.jl/stable for the most recently tagged version of the documentation.

    See https://jump.dev/SumOfSquares.jl/dev for the in-development version of the documentation.

    Presentations

    Some presentations on, or using, SumOfSquares (see blegat/SumOfSquaresSlides for the source code of the presentations):

    Citing

    See CITATION.bib.

    diff --git a/previews/PR3883/packages/Tulip/index.html b/previews/PR3883/packages/Tulip/index.html index 83e9f02a2b4..cd4ac8cee83 100644 --- a/previews/PR3883/packages/Tulip/index.html +++ b/previews/PR3883/packages/Tulip/index.html @@ -28,4 +28,4 @@ language = {en}, url = {https://doi.org/10.1007/s12532-020-00200-8}, urldate = {2021-03-07}, -} +} diff --git a/previews/PR3883/packages/Xpress/index.html b/previews/PR3883/packages/Xpress/index.html index 4a3c974fd8a..1639b854ce0 100644 --- a/previews/PR3883/packages/Xpress/index.html +++ b/previews/PR3883/packages/Xpress/index.html @@ -58,4 +58,4 @@ @test termination_status(model) == MOI.OPTIMAL @test primal_status(model) == MOI.FEASIBLE_POINT @test value(x) == 1 -@test value(y) == 2

    Environment variables

    • XPRESS_JL_SKIP_LIB_CHECK: Used to skip build lib check as previously described.
    • XPRESS_JL_NO_INFO: Disable license info log.
    • XPRESS_JL_NO_DEPS_ERROR: Disable error when do deps.jl file is found.
    • XPRESS_JL_NO_AUTO_INIT: Disable automatic run of Xpress.initialize(). Specially useful for explicitly loading the dynamic library.
    • XPRESS_JL_LIBRARY: Provide a custom path to libxprs
    • XPAUTH_PATH: Provide a custom path to the license file

    C API

    The C API can be accessed via Xpress.Lib.XPRSxx functions, where the names and arguments are identical to the C API.

    See the Xpress documentation for details.

    Documentation

    For more information, consult the FICO optimizer manual.

    +@test value(y) == 2

    Environment variables

    • XPRESS_JL_SKIP_LIB_CHECK: Used to skip build lib check as previously described.
    • XPRESS_JL_NO_INFO: Disable license info log.
    • XPRESS_JL_NO_DEPS_ERROR: Disable error when do deps.jl file is found.
    • XPRESS_JL_NO_AUTO_INIT: Disable automatic run of Xpress.initialize(). Specially useful for explicitly loading the dynamic library.
    • XPRESS_JL_LIBRARY: Provide a custom path to libxprs
    • XPAUTH_PATH: Provide a custom path to the license file

    C API

    The C API can be accessed via Xpress.Lib.XPRSxx functions, where the names and arguments are identical to the C API.

    See the Xpress documentation for details.

    Documentation

    For more information, consult the FICO optimizer manual.

    diff --git a/previews/PR3883/packages/solvers/index.html b/previews/PR3883/packages/solvers/index.html index f15fe27c955..897283a160c 100644 --- a/previews/PR3883/packages/solvers/index.html +++ b/previews/PR3883/packages/solvers/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Introduction

    This section of the documentation contains brief documentation for some of the solvers that JuMP supports. The list of solvers is not exhaustive, but instead is intended to help you discover commonly used solvers.

    Affiliation

    Packages beginning with jump-dev/ are developed and maintained by the JuMP developers. In many cases, these packages wrap external solvers that are not developed by the JuMP developers and, while the Julia packages are all open-source, in some cases the solvers themselves are closed source commercial products.

    Packages that do not begin with jump-dev/ are developed independently. The developers of these packages requested or consented to the inclusion of their README contents in the JuMP documentation for the benefit of users.

    Adding new solvers

    Written a solver? Add it to this section of the JuMP documentation by making a pull request to the docs/packages.toml file.

    +

    Introduction

    This section of the documentation contains brief documentation for some of the solvers that JuMP supports. The list of solvers is not exhaustive, but instead is intended to help you discover commonly used solvers.

    Affiliation

    Packages beginning with jump-dev/ are developed and maintained by the JuMP developers. In many cases, these packages wrap external solvers that are not developed by the JuMP developers and, while the Julia packages are all open-source, in some cases the solvers themselves are closed source commercial products.

    Packages that do not begin with jump-dev/ are developed independently. The developers of these packages requested or consented to the inclusion of their README contents in the JuMP documentation for the benefit of users.

    Adding new solvers

    Written a solver? Add it to this section of the JuMP documentation by making a pull request to the docs/packages.toml file.

    diff --git a/previews/PR3883/release_notes/index.html b/previews/PR3883/release_notes/index.html index f391c04988f..35ff43a11c1 100644 --- a/previews/PR3883/release_notes/index.html +++ b/previews/PR3883/release_notes/index.html @@ -12,4 +12,4 @@ new_b = backend(model)
  • All usages of @SDconstraint are deprecated. The new syntax is @constraint(model, X >= Y, PSDCone()).
  • Creating a DenseAxisArray with a Number as an axis will now display a warning. This catches a common error in which users write @variable(model, x[length(S)]) instead of @variable(model, x[1:length(S)]).
  • The caching_mode argument to Model, for example, Model(caching_mode = MOIU.MANUAL) mode has been removed. For more control over the optimizer, use direct_model instead.
  • The previously deprecated lp_objective_perturbation_range and lp_rhs_perturbation_range functions have been removed. Use lp_sensitivity_report instead.
  • The .m fields of NonlinearExpression and NonlinearParameter have been renamed to .model.
  • Infinite variable bounds are now ignored. Thus, @variable(model, x <= Inf) will show has_upper_bound(x) == false. Previously, these bounds were passed through to the solvers which caused numerical issues for solvers expecting finite bounds.
  • The variable_type and constraint_type functions were removed. This should only affect users who previously wrote JuMP extensions. The functions can be deleted without consequence.
  • The internal functions moi_mode, moi_bridge_constraints, moi_add_constraint, and moi_add_to_function_constant are no longer exported.
  • The un-used method Containers.generate_container has been deleted.
  • The Containers API has been refactored, and _build_ref_sets is now public as Containers.build_ref_sets.
  • The parse_constraint_ methods for extending @constraint at parse time have been refactored in a breaking way. Consult the Extensions documentation for more details and examples.
  • Added

    • The TerminationStatusCode and ResultStatusCode enums are now exported by JuMP. Prefer termination_status(model) == OPTIMAL instead of == MOI.OPTIMAL, although the MOI. prefix way still works.
    • Copy a x::DenseAxisArray to an Array by calling Array(x).
    • NonlinearExpression is now a subtype of AbstractJuMPScalar
    • Constraints such as @constraint(model, x + 1 in MOI.Integer()) are now supported.
    • primal_feasibility_report now accepts a function as the first argument.
    • Scalar variables @variable(model, x[1:2] in MOI.Integer()) creates two variables, both of which are constrained to be in the set MOI.Integer.
    • Conic constraints can now be specified as inequalities under a different partial ordering. So @constraint(model, x - y in MOI.Nonnegatives()) can now be written as @constraint(model, x >= y, MOI.Nonnegatives()).
    • Names are now set for vectorized constraints.

    Fixed

    • Fixed a performance issue when show was called on a SparseAxisArray with a large number of elements.
    • Fixed a bug displaying barrier and simplex iterations in solution_summary.
    • Fixed a bug by implementing hash for DenseAxisArray and SparseAxisArray.
    • Names are now only set if the solver supports them. Previously, this prevented solvers such as Ipopt from being used with direct_model.
    • MutableArithmetics.Zero is converted into a 0.0 before being returned to the user. Previously, some calls to @expression would return the undocumented MutableArithmetics.Zero() object. One example is summing over an empty set @expression(model, sum(x[i] for i in 1:0)). You will now get 0.0 instead.
    • AffExpr and QuadExpr can now be used with == 0 instead of iszero. This fixes a number of issues relating to Julia standard libraries such as LinearAlgebra and SparseArrays.
    • Fixed a bug when registering a user-defined function with splatting.

    Other

    • The documentation is now available as a PDF.
    • The documentation now includes a full copy of the MathOptInterface documentation to make it easy to link concepts between the docs. (The MathOptInterface documentation has also been significantly improved.)
    • The documentation contains a large number of improvements and clarifications on a range of topics. Thanks to @sshin23, @DilumAluthge, and @jlwether.
    • The documentation is now built with Julia 1.6 instead of 1.0.
    • Various error messages have been improved to be more readable.

    Version 0.21.10 (September 4, 2021)

    Added

    • Added add_NL_expression
    • add_NL_xxx functions now support AffExpr and QuadExpr as terms

    Fixed

    • Fixed a bug in solution_summary
    • Fixed a bug in relax_integrality

    Other

    • Improved error message in lp_sensitivity_report

    Version 0.21.9 (August 1, 2021)

    Added

    • Containers now support arbitrary container types by passing the type to the container keyword and overloading Containers.container.
    • is_valid now supports nonlinear constraints
    • Added unsafe_backend for querying the inner-most optimizer of a JuMP model.
    • Nonlinear parameters now support the plural @NLparameters macro.
    • Containers (for example, DenseAxisArray) can now be used in vector-valued constraints.

    Other

    • Various improvements to the documentation.

    Version 0.21.8 (May 8, 2021)

    Added

    • The @constraint macro is now extendable in the same way as @variable.
    • AffExpr and QuadExpr can now be used in nonlinear macros.

    Fixed

    • Fixed a bug in lp_sensitivity_report.
    • Fixed an inference issue when creating empty SparseAxisArrays.

    Version 0.21.7 (April 12, 2021)

    Added

    • Added primal_feasibility_report, which can be used to check whether a primal point satisfies primal feasibility.
    • Added coefficient, which returns the coefficient associated with a variable in affine and quadratic expressions.
    • Added copy_conflict, which returns the IIS of an infeasible model.
    • Added solution_summary, which returns (and prints) a struct containing a summary of the solution.
    • Allow AbstractVector in vector constraints instead of just Vector.
    • Added latex_formulation(model) which returns an object representing the latex formulation of a model. Use print(latex_formulation(model)) to print the formulation as a string.
    • User-defined functions in nonlinear expressions are now automatically registered to aid quick model prototyping. However, a warning is printed to encourage the manual registration.
    • DenseAxisArray's now support broadcasting over multiple arrays.
    • Container indices can now be iterators of Base.SizeUnknown.

    Fixed

    • Fixed bug in rad2deg and deg2rad in nonlinear expressions.
    • Fixed a MethodError bug in Containers when forcing container type.
    • Allow partial slicing of a DenseAxisArray, resolving an issue from 2014.
    • Fixed a bug printing variable names in IJulia.
    • Ending an IJulia cell with model now prints a summary of the model (like in the REPL) not the latex formulation. Use print(model) to print the latex formulation.
    • Fixed a bug when copying models containing nested arrays.

    Other

    • Tutorials are now part of the documentation, and more refactoring has taken place.
    • Added JuliaFormatter added as a code formatter.
    • Added some precompilation statements to reduce initial latency.
    • Various improvements to error messages to make them more helpful.
    • Improved performance of value(::NonlinearExpression).
    • Improved performance of fix(::VariableRef).

    Version 0.21.6 (January 29, 2021)

    Added

    • Added support for skew symmetric variables via @variable(model, X[1:2, 1:2] in SkewSymmetricMatrixSpace()).
    • lp_sensitivity_report has been added which significantly improves the performance of querying the sensitivity summary of an LP. lp_objective_perturbation_range and lp_rhs_perturbation_range are deprecated.
    • Dual warm-starts are now supported with set_dual_start_value and dual_start_value.
    • (\in<tab>) can now be used in macros instead of = or in.
    • Use haskey(model::Model, key::Symbol) to check if a name key is registered in a model.
    • Added unregister(model::Model, key::Symbol) to unregister a name key from model.
    • Added callback_node_status for use in callbacks.
    • Added print_bridge_graph to visualize the bridging graph generated by MathOptInterface.
    • Improved error message for containers with duplicate indices.

    Fixed

    • Various fixes to pass tests on Julia 1.6.
    • Fixed a bug in the printing of nonlinear expressions in IJulia.
    • Fixed a bug when nonlinear expressions are passed to user-defined functions.
    • Some internal functions that were previously exported are now no longer exported.
    • Fixed a bug when relaxing a fixed binary variable.
    • Fixed a StackOverflowError that occurred when SparseAxisArrays had a large number of elements.
    • Removed an unnecessary type assertion in list_of_constraint_types.
    • Fixed a bug when copying models with registered expressions.

    Other

    • The documentation has been significantly overhauled. It now has distinct sections for the manual, API reference, and examples. The existing examples in /examples have now been moved to /docs/src/examples and rewritten using Literate.jl, and they are now included in the documentation.
    • JuliaFormatter has been applied to most of the codebase. This will continue to roll out over time, as we fix upstream issues in the formatter, and will eventually become compulsory.
    • The root cause of a large number of method invalidations has been resolved.
    • We switched continuous integration from Travis and Appveyor to GitHub Actions.

    Version 0.21.5 (September 18, 2020)

    Fixed

    • Fixed deprecation warnings
    • Throw DimensionMismatch for incompatibly sized functions and sets
    • Unify treatment of keys(x) on JuMP containers

    Version 0.21.4 (September 14, 2020)

    Added

    • Add debug info when adding unsupported constraints
    • Add relax_integrality for solving continuous relaxation
    • Allow querying constraint conflicts

    Fixed

    • Dispatch on Real for MOI.submit
    • Implement copy for CustomSet in tests
    • Don't export private macros
    • Fix invalid assertion in nonlinear
    • Error if constraint has NaN right-hand side
    • Improve speed of tests
    • Lots of work modularizing files in /test
    • Improve line numbers in macro error messages
    • Print nonlinear subexpressions
    • Various documentation updates
    • Dependency updates:
      • Datastructures 0.18
      • MathOptFormat v0.5
      • Prep for MathOptInterface 0.9.15

    Version 0.21.3 (June 18, 2020)

    • Added Special Order Sets (SOS1 and SOS2) to JuMP with default weights to ease the creation of such constraints (#2212).
    • Added functions simplex_iterations, barrier_iterations and node_count (#2201).
    • Added function reduced_cost (#2205).
    • Implemented callback_value for affine and quadratic expressions (#2231).
    • Support MutableArithmetics.Zero in objective and constraints (#2219).
    • Documentation improvements:
      • Mention tutorials in the docs (#2223).
      • Update COIN-OR links (#2242).
      • Explicit link to the documentation of MOI.FileFormats (#2253).
      • Typo fixes (#2261).
    • Containers improvements:
      • Fix Base.map for DenseAxisArray (#2235).
      • Throw BoundsError if number of indices is incorrect for DenseAxisArray and SparseAxisArray (#2240).
    • Extensibility improvements:
      • Implement a set_objective method fallback that redirects to set_objective_sense and set_objective_function (#2247).
      • Add parse_constraint method with arbitrary number of arguments (#2051).
      • Add parse_constraint_expr and parse_constraint_head (#2228).

    Version 0.21.2 (April 2, 2020)

    • Added relative_gap() to access MOI.RelativeGap() attribute (#2199).
    • Documentation fixes:
      • Added link to source for docstrings in the documentation (#2207).
      • Added docstring for @variables macro (#2216).
      • Typo fixes (#2177, #2184, #2182).
    • Implementation of methods for Base functions:
      • Implemented Base.empty! for JuMP.Model (#2198).
      • Implemented Base.conj for JuMP scalar types (#2209).

    Fixed

    • Fixed sum of expression with scalar product in macro (#2178).
    • Fixed writing of nonlinear models to MathOptFormat (#2181).
    • Fixed construction of empty SparseAxisArray (#2179).
    • Fixed constraint with zero function (#2188).

    Version 0.21.1 (Feb 18, 2020)

    • Improved the clarity of the with_optimizer deprecation warning.

    Version 0.21.0 (Feb 16, 2020)

    Breaking

    • Deprecated with_optimizer (#2090, #2084, #2141). You can replace with_optimizer by either nothing, optimizer_with_attributes or a closure:

      • replace with_optimizer(Ipopt.Optimizer) by Ipopt.Optimizer.
      • replace with_optimizer(Ipopt.Optimizer, max_cpu_time=60.0) by optimizer_with_attributes(Ipopt.Optimizer, "max_cpu_time" => 60.0).
      • replace with_optimizer(Gurobi.Optimizer, env) by () -> Gurobi.Optimizer(env).
      • replace with_optimizer(Gurobi.Optimizer, env, Presolve=0) by optimizer_with_attributes(() -> Gurobi.Optimizer(env), "Presolve" => 0).

      alternatively to optimizer_with_attributes, you can also set the attributes separately with set_optimizer_attribute.

    • Renamed set_parameter and set_parameters to set_optimizer_attribute and set_optimizer_attributes (#2150).

    • Broadcast should now be explicit inside macros. @SDconstraint(model, x >= 1) and @constraint(model, x + 1 in SecondOrderCone()) now throw an error instead of broadcasting 1 along the dimension of x (#2107).

    • @SDconstraint(model, x >= 0) is now equivalent to @constraint(model, x in PSDCone()) instead of @constraint(model, (x .- 0) in PSDCone()) (#2107).

    • The macros now create the containers with map instead of for loops, as a consequence, containers created by @expression can now have any element type and containers of constraint references now have concrete element types when possible. This fixes a long-standing issue where @expression could only be used to generate a collection of linear expressions. Now it works for quadratic expressions as well (#2070).

    • Calling deepcopy(::AbstractModel) now throws an error.

    • The constraint name is now printed in the model string (#2108).

    Added

    • Added support for solver-independent and solver-specific callbacks (#2101).
    • Added write_to_file and read_from_file, supported formats are CBF, LP, MathOptFormat, MPS and SDPA (#2114).
    • Added support for complementarity constraints (#2132).
    • Added support for indicator constraints (#2092).
    • Added support for querying multiple solutions with the result keyword (#2100).
    • Added support for constraining variables on creation (#2128).
    • Added method delete that deletes a vector of variables at once if it is supported by the underlying solver (#2135).
    • The arithmetic between JuMP expression has be refactored into the MutableArithmetics package (#2107).
    • Improved error on complex values in NLP (#1978).
    • Added an example of column generation (#2010).

    Fixed

    • Incorrect coefficients generated when using Symmetric variables (#2102)

    Version 0.20.1 (Oct 18, 2019)

    • Add sections on @variables and @constraints in the documentation (#2062).
    • Fixed product of sparse matrices for Julia v1.3 (#2063).
    • Added set_objective_coefficient to modify the coefficient of a linear term of the objective function (#2008).
    • Added set_time_limit_sec, unset_time_limit_sec and time_limit_sec to set and query the time limit for the solver in seconds (#2053).

    Version 0.20.0 (Aug 24, 2019)

    • Documentation updates.
    • Numerous bug fixes.
    • Better error messages (#1977, #1978, #1997, #2017).
    • Performance improvements (#1947, #2032).
    • Added LP sensitivity summary functions lp_objective_perturbation_range and lp_rhs_perturbation_range (#1917).
    • Added functions dual_objective_value, raw_status and set_parameter.
    • Added function set_objective_coefficient to modify the coefficient of a linear term of the objective (#2008).
    • Added functions set_normalized_rhs, normalized_rhs, and add_to_function_constant to modify and get the constant part of a constraint (#1935, #1960).
    • Added functions set_normalized_coefficient and normalized_coefficient to modify and get the coefficient of a linear term of a constraint (#1935, #1960).
    • Numerous other improvements in MOI 0.9, see the NEWS.md file of MOI for more details.

    Version 0.19.2 (June 8, 2019)

    • Fix a bug in derivatives that could arise in models with nested nonlinear subexpressions.

    Version 0.19.1 (May 12, 2019)

    • Usability and performance improvements.
    • Bug fixes.

    Version 0.19.0 (February 15, 2019)

    JuMP 0.19 contains significant breaking changes.

    Breaking

    • JuMP's abstraction layer for communicating with solvers changed from MathProgBase (MPB) to MathOptInterface (MOI). MOI addresses many longstanding design issues. (See @mlubin's slides from JuMP-dev 2018.) JuMP 0.19 is compatible only with solvers that have been updated for MOI. See the installation guide for a list of solvers that have and have not yet been updated.

    • Most solvers have been renamed to PackageName.Optimizer. For example, GurobiSolver() is now Gurobi.Optimizer.

    • Solvers are no longer added to a model via Model(solver = XXX(kwargs...)). Instead use Model(with_optimizer(XXX, kwargs...)). For example, Model(with_optimizer(Gurobi.Optimizer, OutputFlag=0)).

    • JuMP containers (for example, the objects returned by @variable) have been redesigned. Containers.SparseAxisArray replaces JuMPDict, JuMPArray was rewritten (inspired by AxisArrays) and renamed Containers.DenseAxisArray, and you can now request a container type with the container= keyword to the macros. See the corresponding documentation for more details.

    • The statuses returned by solvers have changed. See the possible status values here. The MOI statuses are much richer than the MPB statuses and can be used to distinguish between previously indistinguishable cases (for example, did the solver have a feasible solution when it stopped because of the time limit?).

    • Starting values are separate from result values. Use value to query the value of a variable in a solution. Use start_value and set_start_value to get and set an initial starting point provided to the solver. The solutions from previous solves are no longer automatically set as the starting points for the next solve.

    • The data structures for affine and quadratic expressions AffExpr and QuadExpr have changed. Internally, terms are stored in dictionaries instead of lists. Duplicate coefficients can no longer exist. Accessors and iteration methods have changed.

    • JuMPNLPEvaluator no longer includes the linear and quadratic parts of the model in the evaluation calls. These are now handled separately to allow NLP solvers that support various types of constraints.

    • JuMP solver-independent callbacks have been replaced by solver-specific callbacks. See your favorite solver for more details. (See the note below: No solver-specific callbacks are implemented yet.)

    • The norm() syntax is no longer recognized inside macros. Use the SecondOrderCone() set instead.

    • JuMP no longer performs automatic transformation between special quadratic forms and second-order cone constraints. Support for these constraint classes depends on the solver.

    • The symbols :Min and :Max are no longer used as optimization senses. Instead, JuMP uses the OptimizationSense enum from MathOptInterface. @objective(model, Max, ...), @objective(model, Min, ...), @NLobjective(model, Max, ...), and @objective(model, Min, ...) remain valid, but @objective(m, :Max, ...) is no longer accepted.

    • The sign conventions for duals has changed in some cases for consistency with conic duality (see the documentation). The shadow_price helper method returns duals with signs that match conventional LP interpretations of dual values as sensitivities of the objective value to relaxations of constraints.

    • @constraintref is no longer defined. Instead, create the appropriate container to hold constraint references manually. For example,

      constraints = Dict() # Optionally, specify types for improved performance.
       for i in 1:N
         constraints[i] = @constraint(model, ...)
      -end
    • The lowerbound, upperbound, and basename keyword arguments to the @variable macro have been renamed to lower_bound, upper_bound, and base_name, for consistency with JuMP's new style recommendations.

    • We rely on broadcasting syntax to apply accessors to collections of variables, for example, value.(x) instead of getvalue(x) for collections. (Use value(x) when x is a scalar object.)

    Added

    • Splatting (like f(x...)) is recognized in restricted settings in nonlinear expressions.

    • Support for deleting constraints and variables.

    • The documentation has been completely rewritten using docstrings and Documenter.

    • Support for modeling mixed conic and quadratic models (for example, conic models with quadratic objectives and bi-linear matrix inequalities).

    • Significantly improved support for modeling new types of constraints and for extending JuMP's macros.

    • Support for providing dual warm starts.

    • Improved support for accessing solver-specific attributes (for example, the irreducible inconsistent subsystem).

    • Explicit control of whether symmetry-enforcing constraints are added to PSD constraints.

    • Support for modeling exponential cones.

    • Significant improvements in internal code quality and testing.

    • Style and naming guidelines.

    • Direct mode and manual mode provide explicit control over when copies of a model are stored or regenerated. See the corresponding documentation.

    Regressions

    There are known regressions from JuMP 0.18 that will be addressed in a future release (0.19.x or later):

    • Performance regressions in model generation (issue). Please file an issue anyway if you notice a significant performance regression. We have plans to address a number of performance issues, but we might not be aware of all of them.

    • Fast incremental NLP solves are not yet reimplemented (issue).

    • We do not yet have an implementation of solver-specific callbacks.

    • The column generation syntax in @variable has been removed (that is, the objective, coefficients, and inconstraints keyword arguments). Support for column generation will be re-introduced in a future release.

    • The ability to solve the continuous relaxation (that is, via solve(model; relaxation = true)) is not yet reimplemented (issue).

    Version 0.18.5 (December 1, 2018)

    • Support views in some derivative evaluation functions.
    • Improved compatibility with PackageCompiler.

    Version 0.18.4 (October 8, 2018)

    • Fix a bug in model printing on Julia 0.7 and 1.0.

    Version 0.18.3 (October 1, 2018)

    • Add support for Julia v1.0 (Thanks @ExpandingMan)
    • Fix matrix expressions with quadratic functions (#1508)

    Version 0.18.2 (June 10, 2018)

    • Fix a bug in second-order derivatives when expressions are present (#1319)
    • Fix a bug in @constraintref (#1330)

    Version 0.18.1 (April 9, 2018)

    • Fix for nested tuple destructuring (#1193)
    • Preserve internal model when relaxation=true (#1209)
    • Minor bug fixes and updates for example

    Version 0.18.0 (July 27, 2017)

    • Drop support for Julia 0.5.
    • Update for ForwardDiff 0.5.
    • Minor bug fixes.

    Version 0.17.1 (June 9, 2017)

    • Use of constructconstraint! in @SDconstraint.
    • Minor bug fixes.

    Version 0.17.0 (May 27, 2017)

    • Breaking change: Mixing quadratic and conic constraints is no longer supported.
    • Breaking change: The getvariable and getconstraint functions are replaced by indexing on the corresponding symbol. For instance, to access the variable with name x, one should now write m[:x] instead of getvariable(m, :x). As a consequence, creating a variable and constraint with the same name now triggers a warning, and accessing one of them afterwards throws an error. This change is breaking only in the latter case.
    • Addition of the getobjectivebound function that mirrors the functionality of the MathProgBase getobjbound function except that it takes into account transformations performed by JuMP.
    • Minor bug fixes.

    The following changes are primarily of interest to developers of JuMP extensions:

    • The new syntax @constraint(model, expr in Cone) creates the constraint ensuring that expr is inside Cone. The Cone argument is passed to constructconstraint! which enables the call to the dispatched to an extension.
    • The @variable macro now calls constructvariable! instead of directly calling the Variable constructor. Extra arguments and keyword arguments passed to @variable are passed to constructvariable! which enables the call to be dispatched to an extension.
    • Refactor the internal function conicdata (used build the MathProgBase conic model) into smaller sub-functions to make these parts reusable by extensions.

    Version 0.16.2 (March 28, 2017)

    • Minor bug fixes and printing tweaks
    • Address deprecation warnings for Julia 0.6

    Version 0.16.1 (March 7, 2017)

    • Better support for AbstractArray in JuMP (Thanks @tkoolen)
    • Minor bug fixes

    Version 0.16.0 (February 23, 2017)

    • Breaking change: JuMP no longer has a mechanism for selecting solvers by default (the previous mechanism was flawed and incompatible with Julia 0.6). Not specifying a solver before calling solve() will result in an error.
    • Breaking change: User-defined functions are no longer global. The first argument to JuMP.register is now a JuMP Model object within whose scope the function will be registered. Calling JuMP.register without a Model now produces an error.
    • Breaking change: Use the new JuMP.fix method to fix a variable to a value or to update the value to which a variable is fixed. Calling setvalue on a fixed variable now results in an error in order to avoid silent behavior changes. (Thanks @joaquimg)
    • Nonlinear expressions now print out similarly to linear/quadratic expressions (useful for debugging!)
    • New category keyword to @variable. Used for specifying categories of anonymous variables.
    • Compatibility with Julia 0.6-dev.
    • Minor fixes and improvements (Thanks @cossio, @ccoffrin, @blegat)

    Version 0.15.1 (January 31, 2017)

    • Bugfix for @LinearConstraints and friends

    Version 0.15.0 (December 22, 2016)

    • Julia 0.5.0 is the minimum required version for this release.
    • Document support for BARON solver
    • Enable info callbacks in more states than before, for example, for recording solutions. New when argument to addinfocallback (#814, thanks @yeesian)
    • Improved support for anonymous variables. This includes new warnings for potentially confusing use of the traditional non-anonymous syntax:
      • When multiple variables in a model are given the same name
      • When non-symbols are used as names, for example, @variable(m, x[1][1:N])
    • Improvements in iterating over JuMP containers (#836, thanks @IssamT)
    • Support for writing variable names in .lp file output (Thanks @leethargo)
    • Support for querying duals to SDP problems (Thanks @blegat)
    • The comprehension syntax with curly braces sum{}, prod{}, and norm2{} has been deprecated in favor of Julia's native comprehension syntax sum(), prod() and norm() as previously announced. (For early adopters of the new syntax, norm2() was renamed to norm() without deprecation.)
    • Unit tests rewritten to use Base.Test instead of FactCheck
    • Improved support for operations with matrices of JuMP types (Thanks @ExpandingMan)
    • The syntax to halt a solver from inside a callback has changed from throw(CallbackAbort()) to return JuMP.StopTheSolver
    • Minor bug fixes

    Version 0.14.2 (December 12, 2016)

    • Allow singleton anonymous variables (includes bugfix)

    Version 0.14.1 (September 12, 2016)

    • More consistent handling of states in informational callbacks, includes a new when parameter to addinfocallback for specifying in which state an informational callback should be called.

    Version 0.14.0 (August 7, 2016)

    • Compatibility with Julia 0.5 and ForwardDiff 0.2
    • Support for "anonymous" variables, constraints, expressions, and parameters, for example, x = @variable(m, [1:N]) instead of @variable(m, x[1:N])
    • Support for retrieving constraints from a model by name via getconstraint
    • @NLconstraint now returns constraint references (as expected).
    • Support for vectorized expressions within lazy constraints
    • On Julia 0.5, parse new comprehension syntax sum(x[i] for i in 1:N if isodd(i)) instead of sum{ x[i], i in 1:N; isodd(i) }. The old syntax with curly braces will be deprecated in JuMP 0.15.
    • Now possible to provide nonlinear expressions as "raw" Julia Expr objects instead of using JuMP's nonlinear macros. This input format is useful for programmatically generated expressions.
    • s/Mathematical Programming/Mathematical Optimization/
    • Support for local cuts (Thanks to @madanim, Mehdi Madani)
    • Document Xpress interface developed by @joaquimg, Joaquim Dias Garcia
    • Minor bug and deprecation fixes (Thanks @odow, @jrevels)

    Version 0.13.2 (May 16, 2016)

    • Compatibility update for MathProgBase

    Version 0.13.1 (May 3, 2016)

    • Fix broken deprecation for registerNLfunction.

    Version 0.13.0 (April 29, 2016)

    • Most exported methods and macros have been renamed to avoid camelCase. See the list of changes here. There is a 1-1 mapping from the old names to the new, and it is safe to simply replace the names to update existing models.
    • Specify variable lower/upper bounds in @variable using the lowerbound and upperbound keyword arguments.
    • Change name printed for variable using the basename keyword argument to @variable.
    • New @variables macro allows multi-line declaration of groups of variables.
    • A number of solver methods previously available only through MathProgBase are now exposed directly in JuMP. The fix was recorded live.
    • Compatibility fixes with Julia 0.5.
    • The "end" indexing syntax is no longer supported within JuMPArrays which do not use 1-based indexing until upstream issues are resolved, see here.

    Version 0.12.2 (March 9, 2016)

    • Small fixes for nonlinear optimization

    Version 0.12.1 (March 1, 2016)

    • Fix a regression in slicing for JuMPArrays (when not using 1-based indexing)

    Version 0.12.0 (February 27, 2016)

    • The automatic differentiation functionality has been completely rewritten with a number of user-facing changes:
      • @defExpr and @defNLExpr now take the model as the first argument. The previous one-argument version of @defExpr is deprecated; all expressions should be named. For example, replace @defExpr(2x+y) with @defExpr(jump_model, my_expr, 2x+y).
      • JuMP no longer uses Julia's variable binding rules for efficiently re-solving a sequence of nonlinear models. Instead, we have introduced nonlinear parameters. This is a breaking change, so we have added a warning message when we detect models that may depend on the old behavior.
      • Support for user-defined functions integrated within nonlinear JuMP expressions.
    • Replaced iteration over AffExpr with Number-like scalar iteration; previous iteration behavior is now available via linearterms(::AffExpr).
    • Stopping the solver via throw(CallbackAbort()) from a callback no longer triggers an exception. Instead, solve() returns UserLimit status.
    • getDual() now works for conic problems (Thanks @emreyamangil.)

    Version 0.11.3 (February 4, 2016)

    • Bug-fix for problems with quadratic objectives and semidefinite constraints

    Version 0.11.2 (January 14, 2016)

    • Compatibility update for Mosek

    Version 0.11.1 (December 1, 2015)

    • Remove usage of @compat in tests.
    • Fix updating quadratic objectives for nonlinear models.

    Version 0.11.0 (November 30, 2015)

    • Julia 0.4.0 is the minimum required version for this release.
    • Fix for scoping semantics of index variables in sum{}. Index variables no longer leak into the surrounding scope.
    • Addition of the solve(m::Model, relaxation=true) keyword argument to solve the standard continuous relaxation of model m
    • The getConstraintBounds() method allows access to the lower and upper bounds of all constraints in a (nonlinear) model.
    • Update for breaking changes in MathProgBase

    Version 0.10.3 (November 20, 2015)

    • Fix a rare error when parsing quadratic expressions
    • Fix Variable() constructor with default arguments
    • Detect unrecognized keywords in solve()

    Version 0.10.2 (September 28, 2015)

    • Fix for deprecation warnings

    Version 0.10.1 (September 3, 2015)

    • Fixes for ambiguity warnings.
    • Fix for breaking change in precompilation syntax in Julia 0.4-pre

    Version 0.10.0 (August 31, 2015)

    • Support (on Julia 0.4 and later) for conditions in indexing @defVar and @addConstraint constructs, for example, @defVar(m, x[i=1:5,j=1:5; i+j >= 3])
    • Support for vectorized operations on Variables and expressions. See the documentation for details.
    • New getVar() method to access variables in a model by name
    • Support for semidefinite programming.
    • Dual solutions are now available for general nonlinear problems. You may call getDual on a reference object for a nonlinear constraint, and getDual on a variable object for Lagrange multipliers from active bounds.
    • Introduce warnings for two common performance traps: too many calls to getValue() on a collection of variables and use of the + operator in a loop to sum expressions.
    • Second-order cone constraints can be written directly with the norm() and norm2{} syntax.
    • Implement MathProgBase interface for querying Hessian-vector products.
    • Iteration over JuMPContainers is deprecated; instead, use the keys and values functions, and zip(keys(d),values(d)) for the old behavior.
    • @defVar returns Array{Variable,N} when each of N index sets are of the form 1:nᵢ.
    • Module precompilation: on Julia 0.4 and later, using JuMP is now much faster.

    Version 0.9.3 (August 11, 2015)

    • Fixes for FactCheck testing on julia v0.4.

    Version 0.9.2 (June 27, 2015)

    • Fix bug in @addConstraints.

    Version 0.9.1 (April 25, 2015)

    • Fix for Julia 0.4-dev.
    • Small infrastructure improvements for extensions.

    Version 0.9.0 (April 18, 2015)

    • Comparison operators for constructing constraints (for example, 2x >= 1) have been deprecated. Instead, construct the constraints explicitly in the @addConstraint macro to add them to the model, or in the @LinearConstraint macro to create a stand-alone linear constraint instance.
    • getValue() method implemented to compute the value of a nonlinear subexpression
    • JuMP is now released under the Mozilla Public License version 2.0 (was previously LGPL). MPL is a copyleft license which is less restrictive than LGPL, especially for embedding JuMP within other applications.
    • A number of performance improvements in ReverseDiffSparse for computing derivatives.
    • MathProgBase.getsolvetime(m) now returns the solution time reported by the solver, if available. (Thanks @odow, Oscar Dowson)
    • Formatting fix for LP format output. (Thanks @sbebo, Leonardo Taccari).

    Version 0.8.0 (February 17, 2015)

    • Nonlinear subexpressions now supported with the @defNLExpr macro.
    • SCS supported for solving second-order conic problems.
    • setXXXCallback family deprecated in favor of addXXXCallback.
    • Multiple callbacks of the same type can be registered.
    • Added support for informational callbacks via addInfoCallback.
    • A CallbackAbort exception can be thrown from callback to safely exit optimization.

    Version 0.7.4 (February 4, 2015)

    • Reduced costs and linear constraint duals are now accessible when quadratic constraints are present.
    • Two-sided nonlinear constraints are supported.
    • Methods for accessing the number of variables and constraints in a model are renamed.
    • New default procedure for setting initial values in nonlinear optimization: project zero onto the variable bounds.
    • Small bug fixes.

    Version 0.7.3 (January 14, 2015)

    • Fix a method ambiguity conflict with Compose.jl (cosmetic fix)

    Version 0.7.2 (January 9, 2015)

    • Fix a bug in sum(::JuMPDict)
    • Added the setCategory function to change a variables category (for example, continuous or binary)

    after construction, and getCategory to retrieve the variable category.

    Version 0.7.1 (January 2, 2015)

    • Fix a bug in parsing linear expressions in macros. Affects only Julia 0.4 and later.

    Version 0.7.0 (December 29, 2014)

    Linear/quadratic/conic programming

    • Breaking change: The syntax for column-wise model generation has been changed to use keyword arguments in @defVar.
    • On Julia 0.4 and later, variables and coefficients may be multiplied in any order within macros. That is, variable*coefficient is now valid syntax.
    • ECOS supported for solving second-order conic problems.

    Nonlinear programming

    • Support for skipping model generation when solving a sequence of nonlinear models with changing data.
    • Fix a memory leak when solving a sequence of nonlinear models.
    • The @addNLConstraint macro now supports the three-argument version to define sets of nonlinear constraints.
    • KNITRO supported as a nonlinear solver.
    • Speed improvements for model generation.
    • The @addNLConstraints macro supports adding multiple (groups of) constraints at once. Syntax is similar to @addConstraints.
    • Discrete variables allowed in nonlinear problems for solvers which support them (currently only KNITRO).

    General

    • Starting values for variables may now be specified with @defVar(m, x, start=value).
    • The setSolver function allows users to change the solver subsequent to model creation.
    • Support for "fixed" variables via the @defVar(m, x == 1) syntax.
    • Unit tests rewritten to use FactCheck.jl, improved testing across solvers.

    Version 0.6.3 (October 19, 2014)

    • Fix a bug in multiplying two AffExpr objects.

    Version 0.6.2 (October 11, 2014)

    • Further improvements and bug fixes for printing.
    • Fixed a bug in @defExpr.
    • Support for accessing expression graphs through the MathProgBase NLP interface.

    Version 0.6.1 (September 19, 2014)

    • Improvements and bug fixes for printing.

    Version 0.6.0 (September 9, 2014)

    • Julia 0.3.0 is the minimum required version for this release.
    • buildInternalModel(m::Model) added to build solver-level model in memory without optimizing.
    • Deprecate load_model_only keyword argument to solve.
    • Add groups of constraints with @addConstraints macro.
    • Unicode operators now supported, including for sum, for prod, and /
    • Quadratic constraints supported in @addConstraint macro.
    • Quadratic objectives supported in @setObjective macro.
    • MathProgBase solver-independent interface replaces Ipopt-specific interface for nonlinear problems
      • Breaking change: IpoptOptions no longer supported to specify solver options, use m = Model(solver=IpoptSolver(options...)) instead.
    • New solver interfaces: ECOS, NLopt, and nonlinear support for MOSEK
    • New option to control whether the lazy constraint callback is executed at each node in the B&B tree or just when feasible solutions are found
    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
    • Add support for index dependencies (for example, triangular indexing) in @defVar, @addConstraint, and @defExpr (for example, @defVar(m, x[i=1:10,j=i:10])).
      • This required some changes to the internal structure of JuMP containers, which may break code that explicitly stored JuMPDict objects.

    Version 0.5.8 (September 24, 2014)

    • Fix a bug with specifying solvers (affects Julia 0.2 only)

    Version 0.5.7 (September 5, 2014)

    • Fix a bug in printing models

    Version 0.5.6 (September 2, 2014)

    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
      • Breaking change: Syntax for Variable() constructor has changed (use of this interface remains discouraged)
    • Update for breaking changes in MathProgBase

    Version 0.5.5 (July 6, 2014)

    • Fix bug with problem modification: adding variables that did not appear in existing constraints or objective.

    Version 0.5.4 (June 19, 2014)

    • Update for breaking change in MathProgBase which reduces loading times for using JuMP
    • Fix error when MIPs not solved to optimality

    Version 0.5.3 (May 21, 2014)

    • Update for breaking change in ReverseDiffSparse

    Version 0.5.2 (May 9, 2014)

    • Fix compatibility with Julia 0.3 prerelease

    Version 0.5.1 (May 5, 2014)

    • Fix a bug in coefficient handling inside lazy constraints and user cuts

    Version 0.5.0 (May 2, 2014)

    • Support for nonlinear optimization with exact, sparse second-order derivatives automatically computed. Ipopt is currently the only solver supported.
    • getValue for AffExpr and QuadExpr
    • Breaking change: getSolverModel replaced by getInternalModel, which returns the internal MathProgBase-level model
    • Groups of constraints can be specified with @addConstraint (see documentation for details). This is not a breaking change.
    • dot(::JuMPDict{Variable},::JuMPDict{Variable}) now returns the corresponding quadratic expression.

    Version 0.4.1 (March 24, 2014)

    • Fix bug where change in objective sense was ignored when re-solving a model.
    • Fix issue with handling zero coefficients in AffExpr.

    Version 0.4.0 (March 10, 2014)

    • Support for SOS1 and SOS2 constraints.
    • Solver-independent callback for user heuristics.
    • dot and sum implemented for JuMPDict objects. Now you can say @addConstraint(m, dot(a,x) <= b).
    • Developers: support for extensions to JuMP. See definition of Model in src/JuMP.jl for more details.
    • Option to construct the low-level model before optimizing.

    Version 0.3.2 (February 17, 2014)

    • Improved model printing
      • Preliminary support for IJulia output

    Version 0.3.1 (January 30, 2014)

    • Documentation updates
    • Support for MOSEK
    • CPLEXLink renamed to CPLEX

    Version 0.3.0 (January 21, 2014)

    • Unbounded/infeasibility rays: getValue() will return the corresponding components of an unbounded ray when a model is unbounded, if supported by the selected solver. getDual() will return an infeasibility ray (Farkas proof) if a model is infeasible and the selected solver supports this feature.
    • Solver-independent callbacks for user generated cuts.
    • Use new interface for solver-independent QCQP.
    • setlazycallback renamed to setLazyCallback for consistency.

    Version 0.2.0 (December 15, 2013)

    Breaking

    • Objective sense is specified in setObjective instead of in the Model constructor.
    • lpsolver and mipsolver merged into single solver option.

    Added

    • Problem modification with efficient LP restarts and MIP warm-starts.
    • Relatedly, column-wise modeling now supported.
    • Solver-independent callbacks supported. Currently we support only a "lazy constraint" callback, which works with Gurobi, CPLEX, and GLPK. More callbacks coming soon.

    Version 0.1.2 (November 16, 2013)

    • Bug fixes for printing, improved error messages.
    • Allow AffExpr to be used in macros; for example, ex = y + z; @addConstraint(m, x + 2*ex <= 3)

    Version 0.1.1 (October 23, 2013)

    • Update for solver specification API changes in MathProgBase.

    Version 0.1.0 (October 3, 2013)

    • Initial public release.
    +end
  • The lowerbound, upperbound, and basename keyword arguments to the @variable macro have been renamed to lower_bound, upper_bound, and base_name, for consistency with JuMP's new style recommendations.

  • We rely on broadcasting syntax to apply accessors to collections of variables, for example, value.(x) instead of getvalue(x) for collections. (Use value(x) when x is a scalar object.)

  • Added

    • Splatting (like f(x...)) is recognized in restricted settings in nonlinear expressions.

    • Support for deleting constraints and variables.

    • The documentation has been completely rewritten using docstrings and Documenter.

    • Support for modeling mixed conic and quadratic models (for example, conic models with quadratic objectives and bi-linear matrix inequalities).

    • Significantly improved support for modeling new types of constraints and for extending JuMP's macros.

    • Support for providing dual warm starts.

    • Improved support for accessing solver-specific attributes (for example, the irreducible inconsistent subsystem).

    • Explicit control of whether symmetry-enforcing constraints are added to PSD constraints.

    • Support for modeling exponential cones.

    • Significant improvements in internal code quality and testing.

    • Style and naming guidelines.

    • Direct mode and manual mode provide explicit control over when copies of a model are stored or regenerated. See the corresponding documentation.

    Regressions

    There are known regressions from JuMP 0.18 that will be addressed in a future release (0.19.x or later):

    • Performance regressions in model generation (issue). Please file an issue anyway if you notice a significant performance regression. We have plans to address a number of performance issues, but we might not be aware of all of them.

    • Fast incremental NLP solves are not yet reimplemented (issue).

    • We do not yet have an implementation of solver-specific callbacks.

    • The column generation syntax in @variable has been removed (that is, the objective, coefficients, and inconstraints keyword arguments). Support for column generation will be re-introduced in a future release.

    • The ability to solve the continuous relaxation (that is, via solve(model; relaxation = true)) is not yet reimplemented (issue).

    Version 0.18.5 (December 1, 2018)

    • Support views in some derivative evaluation functions.
    • Improved compatibility with PackageCompiler.

    Version 0.18.4 (October 8, 2018)

    • Fix a bug in model printing on Julia 0.7 and 1.0.

    Version 0.18.3 (October 1, 2018)

    • Add support for Julia v1.0 (Thanks @ExpandingMan)
    • Fix matrix expressions with quadratic functions (#1508)

    Version 0.18.2 (June 10, 2018)

    • Fix a bug in second-order derivatives when expressions are present (#1319)
    • Fix a bug in @constraintref (#1330)

    Version 0.18.1 (April 9, 2018)

    • Fix for nested tuple destructuring (#1193)
    • Preserve internal model when relaxation=true (#1209)
    • Minor bug fixes and updates for example

    Version 0.18.0 (July 27, 2017)

    • Drop support for Julia 0.5.
    • Update for ForwardDiff 0.5.
    • Minor bug fixes.

    Version 0.17.1 (June 9, 2017)

    • Use of constructconstraint! in @SDconstraint.
    • Minor bug fixes.

    Version 0.17.0 (May 27, 2017)

    • Breaking change: Mixing quadratic and conic constraints is no longer supported.
    • Breaking change: The getvariable and getconstraint functions are replaced by indexing on the corresponding symbol. For instance, to access the variable with name x, one should now write m[:x] instead of getvariable(m, :x). As a consequence, creating a variable and constraint with the same name now triggers a warning, and accessing one of them afterwards throws an error. This change is breaking only in the latter case.
    • Addition of the getobjectivebound function that mirrors the functionality of the MathProgBase getobjbound function except that it takes into account transformations performed by JuMP.
    • Minor bug fixes.

    The following changes are primarily of interest to developers of JuMP extensions:

    • The new syntax @constraint(model, expr in Cone) creates the constraint ensuring that expr is inside Cone. The Cone argument is passed to constructconstraint! which enables the call to the dispatched to an extension.
    • The @variable macro now calls constructvariable! instead of directly calling the Variable constructor. Extra arguments and keyword arguments passed to @variable are passed to constructvariable! which enables the call to be dispatched to an extension.
    • Refactor the internal function conicdata (used build the MathProgBase conic model) into smaller sub-functions to make these parts reusable by extensions.

    Version 0.16.2 (March 28, 2017)

    • Minor bug fixes and printing tweaks
    • Address deprecation warnings for Julia 0.6

    Version 0.16.1 (March 7, 2017)

    • Better support for AbstractArray in JuMP (Thanks @tkoolen)
    • Minor bug fixes

    Version 0.16.0 (February 23, 2017)

    • Breaking change: JuMP no longer has a mechanism for selecting solvers by default (the previous mechanism was flawed and incompatible with Julia 0.6). Not specifying a solver before calling solve() will result in an error.
    • Breaking change: User-defined functions are no longer global. The first argument to JuMP.register is now a JuMP Model object within whose scope the function will be registered. Calling JuMP.register without a Model now produces an error.
    • Breaking change: Use the new JuMP.fix method to fix a variable to a value or to update the value to which a variable is fixed. Calling setvalue on a fixed variable now results in an error in order to avoid silent behavior changes. (Thanks @joaquimg)
    • Nonlinear expressions now print out similarly to linear/quadratic expressions (useful for debugging!)
    • New category keyword to @variable. Used for specifying categories of anonymous variables.
    • Compatibility with Julia 0.6-dev.
    • Minor fixes and improvements (Thanks @cossio, @ccoffrin, @blegat)

    Version 0.15.1 (January 31, 2017)

    • Bugfix for @LinearConstraints and friends

    Version 0.15.0 (December 22, 2016)

    • Julia 0.5.0 is the minimum required version for this release.
    • Document support for BARON solver
    • Enable info callbacks in more states than before, for example, for recording solutions. New when argument to addinfocallback (#814, thanks @yeesian)
    • Improved support for anonymous variables. This includes new warnings for potentially confusing use of the traditional non-anonymous syntax:
      • When multiple variables in a model are given the same name
      • When non-symbols are used as names, for example, @variable(m, x[1][1:N])
    • Improvements in iterating over JuMP containers (#836, thanks @IssamT)
    • Support for writing variable names in .lp file output (Thanks @leethargo)
    • Support for querying duals to SDP problems (Thanks @blegat)
    • The comprehension syntax with curly braces sum{}, prod{}, and norm2{} has been deprecated in favor of Julia's native comprehension syntax sum(), prod() and norm() as previously announced. (For early adopters of the new syntax, norm2() was renamed to norm() without deprecation.)
    • Unit tests rewritten to use Base.Test instead of FactCheck
    • Improved support for operations with matrices of JuMP types (Thanks @ExpandingMan)
    • The syntax to halt a solver from inside a callback has changed from throw(CallbackAbort()) to return JuMP.StopTheSolver
    • Minor bug fixes

    Version 0.14.2 (December 12, 2016)

    • Allow singleton anonymous variables (includes bugfix)

    Version 0.14.1 (September 12, 2016)

    • More consistent handling of states in informational callbacks, includes a new when parameter to addinfocallback for specifying in which state an informational callback should be called.

    Version 0.14.0 (August 7, 2016)

    • Compatibility with Julia 0.5 and ForwardDiff 0.2
    • Support for "anonymous" variables, constraints, expressions, and parameters, for example, x = @variable(m, [1:N]) instead of @variable(m, x[1:N])
    • Support for retrieving constraints from a model by name via getconstraint
    • @NLconstraint now returns constraint references (as expected).
    • Support for vectorized expressions within lazy constraints
    • On Julia 0.5, parse new comprehension syntax sum(x[i] for i in 1:N if isodd(i)) instead of sum{ x[i], i in 1:N; isodd(i) }. The old syntax with curly braces will be deprecated in JuMP 0.15.
    • Now possible to provide nonlinear expressions as "raw" Julia Expr objects instead of using JuMP's nonlinear macros. This input format is useful for programmatically generated expressions.
    • s/Mathematical Programming/Mathematical Optimization/
    • Support for local cuts (Thanks to @madanim, Mehdi Madani)
    • Document Xpress interface developed by @joaquimg, Joaquim Dias Garcia
    • Minor bug and deprecation fixes (Thanks @odow, @jrevels)

    Version 0.13.2 (May 16, 2016)

    • Compatibility update for MathProgBase

    Version 0.13.1 (May 3, 2016)

    • Fix broken deprecation for registerNLfunction.

    Version 0.13.0 (April 29, 2016)

    • Most exported methods and macros have been renamed to avoid camelCase. See the list of changes here. There is a 1-1 mapping from the old names to the new, and it is safe to simply replace the names to update existing models.
    • Specify variable lower/upper bounds in @variable using the lowerbound and upperbound keyword arguments.
    • Change name printed for variable using the basename keyword argument to @variable.
    • New @variables macro allows multi-line declaration of groups of variables.
    • A number of solver methods previously available only through MathProgBase are now exposed directly in JuMP. The fix was recorded live.
    • Compatibility fixes with Julia 0.5.
    • The "end" indexing syntax is no longer supported within JuMPArrays which do not use 1-based indexing until upstream issues are resolved, see here.

    Version 0.12.2 (March 9, 2016)

    • Small fixes for nonlinear optimization

    Version 0.12.1 (March 1, 2016)

    • Fix a regression in slicing for JuMPArrays (when not using 1-based indexing)

    Version 0.12.0 (February 27, 2016)

    • The automatic differentiation functionality has been completely rewritten with a number of user-facing changes:
      • @defExpr and @defNLExpr now take the model as the first argument. The previous one-argument version of @defExpr is deprecated; all expressions should be named. For example, replace @defExpr(2x+y) with @defExpr(jump_model, my_expr, 2x+y).
      • JuMP no longer uses Julia's variable binding rules for efficiently re-solving a sequence of nonlinear models. Instead, we have introduced nonlinear parameters. This is a breaking change, so we have added a warning message when we detect models that may depend on the old behavior.
      • Support for user-defined functions integrated within nonlinear JuMP expressions.
    • Replaced iteration over AffExpr with Number-like scalar iteration; previous iteration behavior is now available via linearterms(::AffExpr).
    • Stopping the solver via throw(CallbackAbort()) from a callback no longer triggers an exception. Instead, solve() returns UserLimit status.
    • getDual() now works for conic problems (Thanks @emreyamangil.)

    Version 0.11.3 (February 4, 2016)

    • Bug-fix for problems with quadratic objectives and semidefinite constraints

    Version 0.11.2 (January 14, 2016)

    • Compatibility update for Mosek

    Version 0.11.1 (December 1, 2015)

    • Remove usage of @compat in tests.
    • Fix updating quadratic objectives for nonlinear models.

    Version 0.11.0 (November 30, 2015)

    • Julia 0.4.0 is the minimum required version for this release.
    • Fix for scoping semantics of index variables in sum{}. Index variables no longer leak into the surrounding scope.
    • Addition of the solve(m::Model, relaxation=true) keyword argument to solve the standard continuous relaxation of model m
    • The getConstraintBounds() method allows access to the lower and upper bounds of all constraints in a (nonlinear) model.
    • Update for breaking changes in MathProgBase

    Version 0.10.3 (November 20, 2015)

    • Fix a rare error when parsing quadratic expressions
    • Fix Variable() constructor with default arguments
    • Detect unrecognized keywords in solve()

    Version 0.10.2 (September 28, 2015)

    • Fix for deprecation warnings

    Version 0.10.1 (September 3, 2015)

    • Fixes for ambiguity warnings.
    • Fix for breaking change in precompilation syntax in Julia 0.4-pre

    Version 0.10.0 (August 31, 2015)

    • Support (on Julia 0.4 and later) for conditions in indexing @defVar and @addConstraint constructs, for example, @defVar(m, x[i=1:5,j=1:5; i+j >= 3])
    • Support for vectorized operations on Variables and expressions. See the documentation for details.
    • New getVar() method to access variables in a model by name
    • Support for semidefinite programming.
    • Dual solutions are now available for general nonlinear problems. You may call getDual on a reference object for a nonlinear constraint, and getDual on a variable object for Lagrange multipliers from active bounds.
    • Introduce warnings for two common performance traps: too many calls to getValue() on a collection of variables and use of the + operator in a loop to sum expressions.
    • Second-order cone constraints can be written directly with the norm() and norm2{} syntax.
    • Implement MathProgBase interface for querying Hessian-vector products.
    • Iteration over JuMPContainers is deprecated; instead, use the keys and values functions, and zip(keys(d),values(d)) for the old behavior.
    • @defVar returns Array{Variable,N} when each of N index sets are of the form 1:nᵢ.
    • Module precompilation: on Julia 0.4 and later, using JuMP is now much faster.

    Version 0.9.3 (August 11, 2015)

    • Fixes for FactCheck testing on julia v0.4.

    Version 0.9.2 (June 27, 2015)

    • Fix bug in @addConstraints.

    Version 0.9.1 (April 25, 2015)

    • Fix for Julia 0.4-dev.
    • Small infrastructure improvements for extensions.

    Version 0.9.0 (April 18, 2015)

    • Comparison operators for constructing constraints (for example, 2x >= 1) have been deprecated. Instead, construct the constraints explicitly in the @addConstraint macro to add them to the model, or in the @LinearConstraint macro to create a stand-alone linear constraint instance.
    • getValue() method implemented to compute the value of a nonlinear subexpression
    • JuMP is now released under the Mozilla Public License version 2.0 (was previously LGPL). MPL is a copyleft license which is less restrictive than LGPL, especially for embedding JuMP within other applications.
    • A number of performance improvements in ReverseDiffSparse for computing derivatives.
    • MathProgBase.getsolvetime(m) now returns the solution time reported by the solver, if available. (Thanks @odow, Oscar Dowson)
    • Formatting fix for LP format output. (Thanks @sbebo, Leonardo Taccari).

    Version 0.8.0 (February 17, 2015)

    • Nonlinear subexpressions now supported with the @defNLExpr macro.
    • SCS supported for solving second-order conic problems.
    • setXXXCallback family deprecated in favor of addXXXCallback.
    • Multiple callbacks of the same type can be registered.
    • Added support for informational callbacks via addInfoCallback.
    • A CallbackAbort exception can be thrown from callback to safely exit optimization.

    Version 0.7.4 (February 4, 2015)

    • Reduced costs and linear constraint duals are now accessible when quadratic constraints are present.
    • Two-sided nonlinear constraints are supported.
    • Methods for accessing the number of variables and constraints in a model are renamed.
    • New default procedure for setting initial values in nonlinear optimization: project zero onto the variable bounds.
    • Small bug fixes.

    Version 0.7.3 (January 14, 2015)

    • Fix a method ambiguity conflict with Compose.jl (cosmetic fix)

    Version 0.7.2 (January 9, 2015)

    • Fix a bug in sum(::JuMPDict)
    • Added the setCategory function to change a variables category (for example, continuous or binary)

    after construction, and getCategory to retrieve the variable category.

    Version 0.7.1 (January 2, 2015)

    • Fix a bug in parsing linear expressions in macros. Affects only Julia 0.4 and later.

    Version 0.7.0 (December 29, 2014)

    Linear/quadratic/conic programming

    • Breaking change: The syntax for column-wise model generation has been changed to use keyword arguments in @defVar.
    • On Julia 0.4 and later, variables and coefficients may be multiplied in any order within macros. That is, variable*coefficient is now valid syntax.
    • ECOS supported for solving second-order conic problems.

    Nonlinear programming

    • Support for skipping model generation when solving a sequence of nonlinear models with changing data.
    • Fix a memory leak when solving a sequence of nonlinear models.
    • The @addNLConstraint macro now supports the three-argument version to define sets of nonlinear constraints.
    • KNITRO supported as a nonlinear solver.
    • Speed improvements for model generation.
    • The @addNLConstraints macro supports adding multiple (groups of) constraints at once. Syntax is similar to @addConstraints.
    • Discrete variables allowed in nonlinear problems for solvers which support them (currently only KNITRO).

    General

    • Starting values for variables may now be specified with @defVar(m, x, start=value).
    • The setSolver function allows users to change the solver subsequent to model creation.
    • Support for "fixed" variables via the @defVar(m, x == 1) syntax.
    • Unit tests rewritten to use FactCheck.jl, improved testing across solvers.

    Version 0.6.3 (October 19, 2014)

    • Fix a bug in multiplying two AffExpr objects.

    Version 0.6.2 (October 11, 2014)

    • Further improvements and bug fixes for printing.
    • Fixed a bug in @defExpr.
    • Support for accessing expression graphs through the MathProgBase NLP interface.

    Version 0.6.1 (September 19, 2014)

    • Improvements and bug fixes for printing.

    Version 0.6.0 (September 9, 2014)

    • Julia 0.3.0 is the minimum required version for this release.
    • buildInternalModel(m::Model) added to build solver-level model in memory without optimizing.
    • Deprecate load_model_only keyword argument to solve.
    • Add groups of constraints with @addConstraints macro.
    • Unicode operators now supported, including for sum, for prod, and /
    • Quadratic constraints supported in @addConstraint macro.
    • Quadratic objectives supported in @setObjective macro.
    • MathProgBase solver-independent interface replaces Ipopt-specific interface for nonlinear problems
      • Breaking change: IpoptOptions no longer supported to specify solver options, use m = Model(solver=IpoptSolver(options...)) instead.
    • New solver interfaces: ECOS, NLopt, and nonlinear support for MOSEK
    • New option to control whether the lazy constraint callback is executed at each node in the B&B tree or just when feasible solutions are found
    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
    • Add support for index dependencies (for example, triangular indexing) in @defVar, @addConstraint, and @defExpr (for example, @defVar(m, x[i=1:10,j=i:10])).
      • This required some changes to the internal structure of JuMP containers, which may break code that explicitly stored JuMPDict objects.

    Version 0.5.8 (September 24, 2014)

    • Fix a bug with specifying solvers (affects Julia 0.2 only)

    Version 0.5.7 (September 5, 2014)

    • Fix a bug in printing models

    Version 0.5.6 (September 2, 2014)

    • Add support for semicontinuous and semi-integer variables for those solvers that support them.
      • Breaking change: Syntax for Variable() constructor has changed (use of this interface remains discouraged)
    • Update for breaking changes in MathProgBase

    Version 0.5.5 (July 6, 2014)

    • Fix bug with problem modification: adding variables that did not appear in existing constraints or objective.

    Version 0.5.4 (June 19, 2014)

    • Update for breaking change in MathProgBase which reduces loading times for using JuMP
    • Fix error when MIPs not solved to optimality

    Version 0.5.3 (May 21, 2014)

    • Update for breaking change in ReverseDiffSparse

    Version 0.5.2 (May 9, 2014)

    • Fix compatibility with Julia 0.3 prerelease

    Version 0.5.1 (May 5, 2014)

    • Fix a bug in coefficient handling inside lazy constraints and user cuts

    Version 0.5.0 (May 2, 2014)

    • Support for nonlinear optimization with exact, sparse second-order derivatives automatically computed. Ipopt is currently the only solver supported.
    • getValue for AffExpr and QuadExpr
    • Breaking change: getSolverModel replaced by getInternalModel, which returns the internal MathProgBase-level model
    • Groups of constraints can be specified with @addConstraint (see documentation for details). This is not a breaking change.
    • dot(::JuMPDict{Variable},::JuMPDict{Variable}) now returns the corresponding quadratic expression.

    Version 0.4.1 (March 24, 2014)

    • Fix bug where change in objective sense was ignored when re-solving a model.
    • Fix issue with handling zero coefficients in AffExpr.

    Version 0.4.0 (March 10, 2014)

    • Support for SOS1 and SOS2 constraints.
    • Solver-independent callback for user heuristics.
    • dot and sum implemented for JuMPDict objects. Now you can say @addConstraint(m, dot(a,x) <= b).
    • Developers: support for extensions to JuMP. See definition of Model in src/JuMP.jl for more details.
    • Option to construct the low-level model before optimizing.

    Version 0.3.2 (February 17, 2014)

    • Improved model printing
      • Preliminary support for IJulia output

    Version 0.3.1 (January 30, 2014)

    • Documentation updates
    • Support for MOSEK
    • CPLEXLink renamed to CPLEX

    Version 0.3.0 (January 21, 2014)

    • Unbounded/infeasibility rays: getValue() will return the corresponding components of an unbounded ray when a model is unbounded, if supported by the selected solver. getDual() will return an infeasibility ray (Farkas proof) if a model is infeasible and the selected solver supports this feature.
    • Solver-independent callbacks for user generated cuts.
    • Use new interface for solver-independent QCQP.
    • setlazycallback renamed to setLazyCallback for consistency.

    Version 0.2.0 (December 15, 2013)

    Breaking

    • Objective sense is specified in setObjective instead of in the Model constructor.
    • lpsolver and mipsolver merged into single solver option.

    Added

    • Problem modification with efficient LP restarts and MIP warm-starts.
    • Relatedly, column-wise modeling now supported.
    • Solver-independent callbacks supported. Currently we support only a "lazy constraint" callback, which works with Gurobi, CPLEX, and GLPK. More callbacks coming soon.

    Version 0.1.2 (November 16, 2013)

    • Bug fixes for printing, improved error messages.
    • Allow AffExpr to be used in macros; for example, ex = y + z; @addConstraint(m, x + 2*ex <= 3)

    Version 0.1.1 (October 23, 2013)

    • Update for solver specification API changes in MathProgBase.

    Version 0.1.0 (October 3, 2013)

    • Initial public release.
    diff --git a/previews/PR3883/should_i_use/index.html b/previews/PR3883/should_i_use/index.html index 3071835651f..4a14935efb0 100644 --- a/previews/PR3883/should_i_use/index.html +++ b/previews/PR3883/should_i_use/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Should you use JuMP?

    JuMP is an algebraic modeling language for mathematical optimization written in the Julia language.

    This page explains when you should consider using JuMP, and importantly, when you should not use JuMP.

    When should you use JuMP?

    You should use JuMP if you have a constrained optimization problem that is formulated using the language of mathematical programming, that is, the problem has:

    • a set of real- or complex-valued decision variables
    • a scalar- or vector-valued real objective function
    • a set of constraints.

    Key reasons to use JuMP include:

    • User friendliness
    • Solver independence
      • JuMP uses a generic solver-independent interface provided by the MathOptInterface package, making it easy to change between a number of open-source and commercial optimization software packages ("solvers"). The Supported solvers section contains a table of the currently supported solvers.
    • Ease of embedding
      • JuMP itself is written purely in Julia. Solvers are the only binary dependencies.
      • JuMP provides automatic installation of most solvers.
      • Because it is embedded in a general-purpose programming language, JuMP makes it easy to solve optimization problems as part of a larger workflow, for example, inside a simulation, behind a web server, or as a subproblem in a decomposition algorithm. As a trade-off, JuMP's syntax is constrained by the syntax and functionality available in Julia.
      • JuMP is MPL licensed, meaning that it can be embedded in commercial software that complies with the terms of the license.
    • Speed
      • Benchmarking has shown that JuMP can create problems at similar speeds to special-purpose modeling languages such as AMPL.
      • JuMP communicates with most solvers in memory, avoiding the need to write intermediary files.
    • Access to advanced algorithmic techniques
      • JuMP supports efficient in-memory re-solves of models.
      • JuMP provides access to solver-independent and solver-dependent Callbacks.

    When should you not use JuMP?

    JuMP supports a broad range of optimization classes. However, there are still some that it doesn't support, or that are better supported by other software packages.

    You want to optimize a complicated Julia function

    Packages in Julia compose well. It's common for people to pick two unrelated packages and use them in conjunction to create novel behavior. JuMP isn't one of those packages.

    If you want to optimize an ordinary differential equation from DifferentialEquations.jl or tune a neural network from Flux.jl, consider using other packages such as:

    Black-box, derivative free, or unconstrained optimization

    JuMP does support nonlinear programs with constraints and objectives containing user-defined operators. However, the functions must be automatically differentiable, or need to provide explicit derivatives. (See User-defined operators for more information.)

    If your function is a black-box that is non-differentiable (for example, it is the output of a simulation written in C++), JuMP is not the right tool for the job. This also applies if you want to use a derivative free method.

    Even if your problem is differentiable, if it is unconstrained there is limited benefit (and downsides in the form of more overhead) to using JuMP over tools which are only concerned with function minimization.

    Alternatives to consider are:

    Disciplined convex programming

    JuMP does not support disciplined convex programming (DCP).

    Alternatives to consider are:

    Note

    Convex.jl is also built on MathOptInterface, and shares the same set of underlying solvers. However, you input problems differently, and Convex.jl checks that the problem is DCP.

    Stochastic programming

    JuMP requires deterministic input data.

    If you have stochastic input data, consider using a JuMP extension such as:

    Polyhedral computations

    JuMP does not provide tools for working with the polyhedron formed by the set of linear constraints.

    Alternatives to consider are:

    +

    Should you use JuMP?

    JuMP is an algebraic modeling language for mathematical optimization written in the Julia language.

    This page explains when you should consider using JuMP, and importantly, when you should not use JuMP.

    When should you use JuMP?

    You should use JuMP if you have a constrained optimization problem that is formulated using the language of mathematical programming, that is, the problem has:

    • a set of real- or complex-valued decision variables
    • a scalar- or vector-valued real objective function
    • a set of constraints.

    Key reasons to use JuMP include:

    • User friendliness
    • Solver independence
      • JuMP uses a generic solver-independent interface provided by the MathOptInterface package, making it easy to change between a number of open-source and commercial optimization software packages ("solvers"). The Supported solvers section contains a table of the currently supported solvers.
    • Ease of embedding
      • JuMP itself is written purely in Julia. Solvers are the only binary dependencies.
      • JuMP provides automatic installation of most solvers.
      • Because it is embedded in a general-purpose programming language, JuMP makes it easy to solve optimization problems as part of a larger workflow, for example, inside a simulation, behind a web server, or as a subproblem in a decomposition algorithm. As a trade-off, JuMP's syntax is constrained by the syntax and functionality available in Julia.
      • JuMP is MPL licensed, meaning that it can be embedded in commercial software that complies with the terms of the license.
    • Speed
      • Benchmarking has shown that JuMP can create problems at similar speeds to special-purpose modeling languages such as AMPL.
      • JuMP communicates with most solvers in memory, avoiding the need to write intermediary files.
    • Access to advanced algorithmic techniques
      • JuMP supports efficient in-memory re-solves of models.
      • JuMP provides access to solver-independent and solver-dependent Callbacks.

    When should you not use JuMP?

    JuMP supports a broad range of optimization classes. However, there are still some that it doesn't support, or that are better supported by other software packages.

    You want to optimize a complicated Julia function

    Packages in Julia compose well. It's common for people to pick two unrelated packages and use them in conjunction to create novel behavior. JuMP isn't one of those packages.

    If you want to optimize an ordinary differential equation from DifferentialEquations.jl or tune a neural network from Flux.jl, consider using other packages such as:

    Black-box, derivative free, or unconstrained optimization

    JuMP does support nonlinear programs with constraints and objectives containing user-defined operators. However, the functions must be automatically differentiable, or need to provide explicit derivatives. (See User-defined operators for more information.)

    If your function is a black-box that is non-differentiable (for example, it is the output of a simulation written in C++), JuMP is not the right tool for the job. This also applies if you want to use a derivative free method.

    Even if your problem is differentiable, if it is unconstrained there is limited benefit (and downsides in the form of more overhead) to using JuMP over tools which are only concerned with function minimization.

    Alternatives to consider are:

    Disciplined convex programming

    JuMP does not support disciplined convex programming (DCP).

    Alternatives to consider are:

    Note

    Convex.jl is also built on MathOptInterface, and shares the same set of underlying solvers. However, you input problems differently, and Convex.jl checks that the problem is DCP.

    Stochastic programming

    JuMP requires deterministic input data.

    If you have stochastic input data, consider using a JuMP extension such as:

    Polyhedral computations

    JuMP does not provide tools for working with the polyhedron formed by the set of linear constraints.

    Alternatives to consider are:

    diff --git a/previews/PR3883/tutorials/algorithms/benders_decomposition/index.html b/previews/PR3883/tutorials/algorithms/benders_decomposition/index.html index 712e29f9166..963d6509a54 100644 --- a/previews/PR3883/tutorials/algorithms/benders_decomposition/index.html +++ b/previews/PR3883/tutorials/algorithms/benders_decomposition/index.html @@ -66,7 +66,7 @@ Dual objective value : NaN * Work counters - Solve time (sec) : 1.92571e-03 + Solve time (sec) : 1.54161e-03 Simplex iterations : 15 Barrier iterations : -1 Node count : 1 @@ -417,4 +417,4 @@ (3, 6) => 1.0 (4, 6) => 1.0 (5, 8) => 4.0 - (6, 8) => 2.0

    which is the same as the monolithic solution (because sum(y) >= 1 in the monolithic solution):

    feasible_inplace_solution == monolithic_solution
    true
    + (6, 8) => 2.0

    which is the same as the monolithic solution (because sum(y) >= 1 in the monolithic solution):

    feasible_inplace_solution == monolithic_solution
    true
    diff --git a/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/e9c52a5b.svg b/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/49ed2924.svg similarity index 72% rename from previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/e9c52a5b.svg rename to previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/49ed2924.svg index f6009b10d19..7ddfd62346e 100644 --- a/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/e9c52a5b.svg +++ b/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/49ed2924.svg @@ -1,350 +1,350 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/288f43e8.svg b/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/8556e87d.svg similarity index 69% rename from previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/288f43e8.svg rename to previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/8556e87d.svg index 4c16ebdef49..9366a1cf221 100644 --- a/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/288f43e8.svg +++ b/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/8556e87d.svg @@ -1,516 +1,516 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/index.html b/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/index.html index abea8dceacf..e1fe37d41ce 100644 --- a/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/index.html +++ b/previews/PR3883/tutorials/algorithms/cutting_stock_column_generation/index.html @@ -118,8 +118,8 @@ Dual objective value : NaN * Work counters - Solve time (sec) : 5.04623e+00 - Simplex iterations : 20396 + Solve time (sec) : 5.03933e+00 + Simplex iterations : 20568 Barrier iterations : -1 Node count : 0

    However, there is a formulation that solves much faster, and that is to use a column generation scheme.

    Column generation theory

    The key insight for column generation is to recognize that feasible columns in the $x$ matrix of variables encode cutting patterns.

    For example, if we look only at the roll $j=1$, then a feasible solution is:

    • $x_{1,1} = 1$ (1 unit of piece #1)
    • $x_{13,1} = 1$ (1 unit of piece #13)
    • All other $x_{i,1} = 0$

    Another solution is

    • $x_{20,1} = 19$ (19 unit of piece #20)
    • All other $x_{i,1} = 0$

    Cutting patterns like $x_{1,1} = 1$ and $x_{2,1} = 1$ are infeasible because the combined length is greater than $W$.

    Since there are a finite number of ways that we could cut a roll into a valid cutting pattern, we could create a set of all possible cutting patterns $p = 1,\ldots,P$, with data $a_{i,p}$ indicating how many units of piece $i$ we cut in pattern $p$. Then, we can formulate our mixed-integer linear program as:

    \[\begin{align} @@ -189,7 +189,7 @@ return plot end -plot_patterns(data, patterns)Example block output

    The base problem

    Using the initial set of patterns, we can create and optimize our base model:

    model = Model(HiGHS.Optimizer)
    +plot_patterns(data, patterns)
    Example block output

    The base problem

    Using the initial set of patterns, we can create and optimize our base model:

    model = Model(HiGHS.Optimizer)
     set_silent(model)
     @variable(model, x[1:length(patterns)] >= 0, Int)
     @objective(model, Min, sum(x))
    @@ -213,7 +213,7 @@
       Dual objective value : NaN
     
     * Work counters
    -  Solve time (sec)   : 1.72853e-04
    +  Solve time (sec)   : 1.57595e-04
       Simplex iterations : 0
       Barrier iterations : -1
       Node count         : 0
    @@ -285,7 +285,7 @@
     [ Info: No new patterns, terminating the algorithm.

    We found lots of new patterns. Here's pattern 21:

    patterns[21]
    20-element SparseArrays.SparseVector{Int64, Int64} with 3 stored entries:
       [9 ]  =  1
       [13]  =  2
    -  [17]  =  1

    Let's have a look at the patterns now:

    plot_patterns(data, patterns)
    Example block output

    Looking at the solution

    Let's see how many of each column we need:

    solution = DataFrames.DataFrame([
    +  [17]  =  1

    Let's have a look at the patterns now:

    plot_patterns(data, patterns)
    Example block output

    Looking at the solution

    Let's see how many of each column we need:

    solution = DataFrames.DataFrame([
         (pattern = p, rolls = value(x_p)) for (p, x_p) in enumerate(x)
     ])
     filter!(row -> row.rolls > 0, solution)
    16×2 DataFrame
    Rowpatternrolls
    Int64Float64
    1138.0
    2244.0
    3330.0
    4210.5
    52210.2
    62314.65
    72423.1
    82511.25
    92621.35
    10284.3
    112919.55
    123011.25
    133117.45
    143336.0
    153411.4
    163541.0

    Since we solved a linear program, some of our columns have fractional solutions. We can create a integer feasible solution by rounding up the orders. This requires 341 rolls:

    sum(ceil.(Int, solution.rolls))
    341

    Alternatively, we can re-introduce the integrality constraints and resolve the problem:

    set_integer.(x)
    @@ -294,4 +294,4 @@
     solution = DataFrames.DataFrame([
         (pattern = p, rolls = value(x_p)) for (p, x_p) in enumerate(x)
     ])
    -filter!(row -> row.rolls > 0, solution)
    16×2 DataFrame
    Rowpatternrolls
    Int64Float64
    1138.0
    2244.0
    3330.0
    4211.0
    5229.0
    62319.0
    72419.0
    82513.0
    92617.0
    10282.0
    112919.0
    123013.0
    133118.0
    143336.0
    153415.0
    163541.0

    This now requires 334 rolls:

    sum(solution.rolls)
    333.99999999999994

    Note that this may not be the global minimum because we are not adding new columns during the solution of the mixed-integer problem model (an algorithm known as branch and price). Nevertheless, the column generation algorithm typically finds good integer feasible solutions to an otherwise intractable optimization problem.

    Next steps

    • Our objective function is to minimize the total number of rolls. What is the total length of waste? How does that compare to the total demand?
    • Writing the optimization algorithm is only part of the challenge. Can you develop a better way to communicate the solution to stakeholders?
    +filter!(row -> row.rolls > 0, solution)
    16×2 DataFrame
    Rowpatternrolls
    Int64Float64
    1138.0
    2244.0
    3330.0
    4211.0
    5229.0
    62319.0
    72419.0
    82513.0
    92617.0
    10282.0
    112919.0
    123013.0
    133118.0
    143336.0
    153415.0
    163541.0

    This now requires 334 rolls:

    sum(solution.rolls)
    333.99999999999994

    Note that this may not be the global minimum because we are not adding new columns during the solution of the mixed-integer problem model (an algorithm known as branch and price). Nevertheless, the column generation algorithm typically finds good integer feasible solutions to an otherwise intractable optimization problem.

    Next steps

    • Our objective function is to minimize the total number of rolls. What is the total length of waste? How does that compare to the total demand?
    • Writing the optimization algorithm is only part of the challenge. Can you develop a better way to communicate the solution to stakeholders?
    diff --git a/previews/PR3883/tutorials/algorithms/parallelism/index.html b/previews/PR3883/tutorials/algorithms/parallelism/index.html index 65cc28d65ea..7a9ad6f806e 100644 --- a/previews/PR3883/tutorials/algorithms/parallelism/index.html +++ b/previews/PR3883/tutorials/algorithms/parallelism/index.html @@ -129,4 +129,4 @@ 7.0 8.0 9.0 - 10.0

    Other types of parallelism

    GPU

    JuMP does not support GPU programming, and few solvers support execution on a GPU.

    Parallelism within the solver

    Many solvers use parallelism internally. For example, commercial solvers like Gurobi and CPLEX both parallelize the search in branch-and-bound. Solvers supporting internal parallelism will typically support the MOI.NumberOfThreads attribute, which you can set using set_attribute.

    + 10.0

    Other types of parallelism

    GPU

    JuMP does not support GPU programming, and few solvers support execution on a GPU.

    Parallelism within the solver

    Many solvers use parallelism internally. For example, commercial solvers like Gurobi and CPLEX both parallelize the search in branch-and-bound. Solvers supporting internal parallelism will typically support the MOI.NumberOfThreads attribute, which you can set using set_attribute.

    diff --git a/previews/PR3883/tutorials/algorithms/pdhg/index.html b/previews/PR3883/tutorials/algorithms/pdhg/index.html index 506e2703270..7ca37f67f50 100644 --- a/previews/PR3883/tutorials/algorithms/pdhg/index.html +++ b/previews/PR3883/tutorials/algorithms/pdhg/index.html @@ -314,7 +314,7 @@ c3 : [-1.93193e-06,2.50002e-01,1.50000e+00] * Work counters - Solve time (sec) : 2.27633e-01 + Solve time (sec) : 2.20415e-01 Barrier iterations : 8365

    But we could also have written:

    model = Model(Optimizer)
     @variable(model, x >= 0)
    @@ -352,7 +352,7 @@
         c2 : 1.50000e+00
     
     * Work counters
    -  Solve time (sec)   : 1.79601e-03
    +  Solve time (sec)   : 1.80006e-03
       Barrier iterations : 8365
     

    Other variations are also possible:

    model = Model(Optimizer)
     @variable(model, x[1:5] >= 0)
    @@ -390,6 +390,6 @@
         c4 : multiple constraints with the same name
     
     * Work counters
    -  Solve time (sec)   : 1.77312e-03
    +  Solve time (sec)   : 1.76716e-03
       Barrier iterations : 8365
    -

    Behind the scenes, JuMP and MathOptInterface reformulate the problem from the modeller's form into the standard form defined by our Optimizer.

    +

    Behind the scenes, JuMP and MathOptInterface reformulate the problem from the modeller's form into the standard form defined by our Optimizer.

    diff --git a/previews/PR3883/tutorials/algorithms/rolling_horizon/2d5113d5.svg b/previews/PR3883/tutorials/algorithms/rolling_horizon/3f125c99.svg similarity index 90% rename from previews/PR3883/tutorials/algorithms/rolling_horizon/2d5113d5.svg rename to previews/PR3883/tutorials/algorithms/rolling_horizon/3f125c99.svg index 4ef2a1370e1..550a9fd76c0 100644 --- a/previews/PR3883/tutorials/algorithms/rolling_horizon/2d5113d5.svg +++ b/previews/PR3883/tutorials/algorithms/rolling_horizon/3f125c99.svg @@ -1,80 +1,80 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/rolling_horizon/134fd116.svg b/previews/PR3883/tutorials/algorithms/rolling_horizon/5e7fb998.svg similarity index 87% rename from previews/PR3883/tutorials/algorithms/rolling_horizon/134fd116.svg rename to previews/PR3883/tutorials/algorithms/rolling_horizon/5e7fb998.svg index 92a01dc245e..0420771ee9f 100644 --- a/previews/PR3883/tutorials/algorithms/rolling_horizon/134fd116.svg +++ b/previews/PR3883/tutorials/algorithms/rolling_horizon/5e7fb998.svg @@ -1,360 +1,360 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/rolling_horizon/213f43dc.svg b/previews/PR3883/tutorials/algorithms/rolling_horizon/e87a99c5.svg similarity index 86% rename from previews/PR3883/tutorials/algorithms/rolling_horizon/213f43dc.svg rename to previews/PR3883/tutorials/algorithms/rolling_horizon/e87a99c5.svg index 1a9fa889be0..0519e761f4f 100644 --- a/previews/PR3883/tutorials/algorithms/rolling_horizon/213f43dc.svg +++ b/previews/PR3883/tutorials/algorithms/rolling_horizon/e87a99c5.svg @@ -1,118 +1,118 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/rolling_horizon/index.html b/previews/PR3883/tutorials/algorithms/rolling_horizon/index.html index 5571e228279..9acc5377c56 100644 --- a/previews/PR3883/tutorials/algorithms/rolling_horizon/index.html +++ b/previews/PR3883/tutorials/algorithms/rolling_horizon/index.html @@ -29,7 +29,7 @@ xticks = 0:12:total_time_length, xlabel = "Hours", ylabel = "MW", -)Example block output

    JuMP model

    We have all the information we need to create a JuMP model to solve a single window of our rolling horizon problem.

    As the optimizer, we use POI.Optimizer, which is part of ParametricOptInterface.jl. POI.Optimizer converts the Parameter decision variables into constants in the underlying optimization model, and it efficiently updates the solver in-place when we call set_parameter_value which avoids having to rebuild the problem each time we call optimize!.

    model = Model(() -> POI.Optimizer(HiGHS.Optimizer()))
    +)
    Example block output

    JuMP model

    We have all the information we need to create a JuMP model to solve a single window of our rolling horizon problem.

    As the optimizer, we use POI.Optimizer, which is part of ParametricOptInterface.jl. POI.Optimizer converts the Parameter decision variables into constants in the underlying optimization model, and it efficiently updates the solver in-place when we call set_parameter_value which avoids having to rebuild the problem each time we call optimize!.

    model = Model(() -> POI.Optimizer(HiGHS.Optimizer()))
     set_silent(model)
     @variables(model, begin
         0 <= r[1:optimization_window]
    @@ -118,4 +118,4 @@
         layout = (length(sol_windows), 1),
         size = (600, 800),
         margin = 3Plots.mm,
    -)
    Example block output

    We can re-use the function to plot the recovered solution of the full problem:

    plot_solution(sol_complete; offset = 0, xlabel = "Hour")
    Example block output

    Final remark

    ParametricOptInterface.jl offers an easy way to update the parameters of an optimization problem that will be solved several times, as in the rolling horizon implementation. It has the benefit of avoiding rebuilding the model each time we want to solve it with new information in a new window.

    +)Example block output

    We can re-use the function to plot the recovered solution of the full problem:

    plot_solution(sol_complete; offset = 0, xlabel = "Hour")
    Example block output

    Final remark

    ParametricOptInterface.jl offers an easy way to update the parameters of an optimization problem that will be solved several times, as in the rolling horizon implementation. It has the benefit of avoiding rebuilding the model each time we want to solve it with new information in a new window.

    diff --git a/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/38097785.svg b/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/165b2136.svg similarity index 80% rename from previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/38097785.svg rename to previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/165b2136.svg index 48a2f71889c..7cb3c3401da 100644 --- a/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/38097785.svg +++ b/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/165b2136.svg @@ -1,86 +1,86 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/dfd68138.svg b/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/a7fbb5cd.svg similarity index 80% rename from previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/dfd68138.svg rename to previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/a7fbb5cd.svg index be4f94d5dc8..0bc71c8ca67 100644 --- a/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/dfd68138.svg +++ b/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/a7fbb5cd.svg @@ -1,86 +1,86 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/index.html b/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/index.html index 3cb317015e6..134c65e073f 100644 --- a/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/index.html +++ b/previews/PR3883/tutorials/algorithms/tsp_lazy_constraints/index.html @@ -63,7 +63,7 @@ Found cycle of length 3 Found cycle of length 4 Found cycle of length 3 -Found cycle of length 5
    objective_value(iterative_model)
    340.1904657042393
    time_iterated
    0.0024085044860839844

    As a quick sanity check, we visualize the optimal tour to verify that no subtour is present:

    function plot_tour(X, Y, x)
    +Found cycle of length 5
    objective_value(iterative_model)
    340.1904657042393
    time_iterated
    0.0024101734161376953

    As a quick sanity check, we visualize the optimal tour to verify that no subtour is present:

    function plot_tour(X, Y, x)
         plot = Plots.plot()
         for (i, j) in selected_edges(x, size(x, 1))
             Plots.plot!([X[i], X[j]], [Y[i], Y[j]]; legend = false)
    @@ -71,7 +71,7 @@
         return plot
     end
     
    -plot_tour(X, Y, value.(iterative_model[:x]))
    Example block output

    Lazy constraint method

    A more sophisticated approach makes use of lazy constraints. To be more precise, we do this through the subtour_elimination_callback() below, which is only run whenever we encounter a new integer-feasible solution.

    lazy_model = build_tsp_model(d, n)
    +plot_tour(X, Y, value.(iterative_model[:x]))
    Example block output

    Lazy constraint method

    A more sophisticated approach makes use of lazy constraints. To be more precise, we do this through the subtour_elimination_callback() below, which is only run whenever we encounter a new integer-feasible solution.

    lazy_model = build_tsp_model(d, n)
     function subtour_elimination_callback(cb_data)
         status = callback_node_status(cb_data, lazy_model)
         if status != MOI.CALLBACK_NODE_STATUS_INTEGER
    @@ -94,4 +94,4 @@
         subtour_elimination_callback,
     )
     optimize!(lazy_model)
    @assert is_solved_and_feasible(lazy_model)
    -objective_value(lazy_model)
    340.1904657042393

    This finds the same optimal tour:

    plot_tour(X, Y, value.(lazy_model[:x]))
    Example block output

    Surprisingly, for this particular model with GLPK, the solution time is worse than the iterative method:

    time_lazy = solve_time(lazy_model)
    0.11385297775268555

    In most other cases and solvers, however, the lazy time should be faster than the iterative method.

    +objective_value(lazy_model)
    340.1904657042393

    This finds the same optimal tour:

    plot_tour(X, Y, value.(lazy_model[:x]))
    Example block output

    Surprisingly, for this particular model with GLPK, the solution time is worse than the iterative method:

    time_lazy = solve_time(lazy_model)
    0.11025500297546387

    In most other cases and solvers, however, the lazy time should be faster than the iterative method.

    diff --git a/previews/PR3883/tutorials/applications/optimal_power_flow/index.html b/previews/PR3883/tutorials/applications/optimal_power_flow/index.html index 9af8daa8c8a..e12b2210934 100644 --- a/previews/PR3883/tutorials/applications/optimal_power_flow/index.html +++ b/previews/PR3883/tutorials/applications/optimal_power_flow/index.html @@ -129,7 +129,7 @@ Objective value : 3.08784e+03 * Work counters - Solve time (sec) : 5.58996e-03 + Solve time (sec) : 5.66602e-03 Barrier iterations : 16
    objval_solution = round(objective_value(model); digits = 2)
     println("Objective value (feasible solution) : $(objval_solution)")
    Objective value (feasible solution) : 3087.84

    The solution's power generation (in rectangular form) and complex voltage values (in polar form using degrees) are:

    DataFrames.DataFrame(;
    @@ -215,7 +215,7 @@
       9   1.5653e+03   1.5641e+03  7.67e-04  2.80e-08  3.75e-06  5.96e-03  1.74e-02  4.38e-01
     ---------------------------------------------------------------------------------------------
     Terminated with status = solved
    -solve time =  529ms
    Test.@test is_solved_and_feasible(model; allow_almost = true)
    +solve time =  593ms
    Test.@test is_solved_and_feasible(model; allow_almost = true)
     sdp_relaxation_lower_bound = round(objective_value(model); digits = 2)
     println(
         "Objective value (W & V relax. lower bound): $sdp_relaxation_lower_bound",
    @@ -232,4 +232,4 @@
         Bus = 1:N,
         Magnitude = round.(abs.(value.(V)); digits = 2),
         AngleDeg = round.(rad2deg.(angle.(value.(V))); digits = 2),
    -)
    9×3 DataFrame
    RowBusMagnitudeAngleDeg
    Int64Float64Float64
    110.95-0.0
    220.843.76
    330.832.66
    440.85-1.22
    550.86-2.12
    660.860.93
    770.86-0.18
    880.861.14
    990.85-2.47

    For further information on exploiting sparsity see (Jabr, 2012).

    This relaxation has the advantage that we can work directly with complex voltages to extend the formulation, strengthen the relaxation and gain additional approximate information about the voltage variables.

    +)
    9×3 DataFrame
    RowBusMagnitudeAngleDeg
    Int64Float64Float64
    110.95-0.0
    220.843.76
    330.832.66
    440.85-1.22
    550.86-2.12
    660.860.93
    770.86-0.18
    880.861.14
    990.85-2.47

    For further information on exploiting sparsity see (Jabr, 2012).

    This relaxation has the advantage that we can work directly with complex voltages to extend the formulation, strengthen the relaxation and gain additional approximate information about the voltage variables.

    diff --git a/previews/PR3883/tutorials/applications/power_systems/3aed991e.svg b/previews/PR3883/tutorials/applications/power_systems/b171715f.svg similarity index 86% rename from previews/PR3883/tutorials/applications/power_systems/3aed991e.svg rename to previews/PR3883/tutorials/applications/power_systems/b171715f.svg index 7ffa428d337..215e24a0aee 100644 --- a/previews/PR3883/tutorials/applications/power_systems/3aed991e.svg +++ b/previews/PR3883/tutorials/applications/power_systems/b171715f.svg @@ -1,80 +1,80 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/power_systems/39f0cd07.svg b/previews/PR3883/tutorials/applications/power_systems/bc3c0452.svg similarity index 85% rename from previews/PR3883/tutorials/applications/power_systems/39f0cd07.svg rename to previews/PR3883/tutorials/applications/power_systems/bc3c0452.svg index b1f388874b8..4f6626c1397 100644 --- a/previews/PR3883/tutorials/applications/power_systems/39f0cd07.svg +++ b/previews/PR3883/tutorials/applications/power_systems/bc3c0452.svg @@ -1,43 +1,43 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/power_systems/2c4c5c3d.svg b/previews/PR3883/tutorials/applications/power_systems/c41a66da.svg similarity index 86% rename from previews/PR3883/tutorials/applications/power_systems/2c4c5c3d.svg rename to previews/PR3883/tutorials/applications/power_systems/c41a66da.svg index d9f0168dbf8..b6385dfcd8b 100644 --- a/previews/PR3883/tutorials/applications/power_systems/2c4c5c3d.svg +++ b/previews/PR3883/tutorials/applications/power_systems/c41a66da.svg @@ -1,78 +1,78 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/power_systems/index.html b/previews/PR3883/tutorials/applications/power_systems/index.html index 3c4894a0cce..5eb844dfa87 100644 --- a/previews/PR3883/tutorials/applications/power_systems/index.html +++ b/previews/PR3883/tutorials/applications/power_systems/index.html @@ -98,7 +98,7 @@ (c_g1_scale, sol.g[1], sol.g[2], sol.w, sol.wind_spill, sol.total_cost), ) end -print(string("elapsed time: ", time() - start, " seconds"))
    elapsed time: 0.13994312286376953 seconds
    c_g_scale_df
    26×6 DataFrame
    Rowscaledispatch_G1dispatch_G2dispatch_windspillage_windtotal_cost
    Float64Float64Float64Float64Float64Float64
    10.51000.0300.0200.00.065000.0
    20.61000.0300.0200.00.070000.0
    30.71000.0300.0200.00.075000.0
    40.81000.0300.0200.00.080000.0
    50.91000.0300.0200.00.085000.0
    61.01000.0300.0200.00.090000.0
    71.11000.0300.0200.00.095000.0
    81.21000.0300.0200.00.0100000.0
    91.31000.0300.0200.00.0105000.0
    101.41000.0300.0200.00.0110000.0
    111.51000.0300.0200.00.0115000.0
    121.61000.0300.0200.00.0120000.0
    131.71000.0300.0200.00.0125000.0
    141.81000.0300.0200.00.0130000.0
    151.91000.0300.0200.00.0135000.0
    162.0300.01000.0200.00.0140000.0
    172.1300.01000.0200.00.0141500.0
    182.2300.01000.0200.00.0143000.0
    192.3300.01000.0200.00.0144500.0
    202.4300.01000.0200.00.0146000.0
    212.5300.01000.0200.00.0147500.0
    222.6300.01000.0200.00.0149000.0
    232.7300.01000.0200.00.0150500.0
    242.8300.01000.0200.00.0152000.0
    252.9300.01000.0200.00.0153500.0
    263.0300.01000.0200.00.0155000.0

    Modifying the JuMP model in-place

    Note that in the previous exercise we entirely rebuilt the optimization model at every iteration of the internal loop, which incurs an additional computational burden. This burden can be alleviated if instead of re-building the entire model, we modify the constraints or objective function, as it shown in the example below.

    Compare the computing time in case of the above and below models.

    function solve_economic_dispatch_inplace(
    +print(string("elapsed time: ", time() - start, " seconds"))
    elapsed time: 0.13625788688659668 seconds
    c_g_scale_df
    26×6 DataFrame
    Rowscaledispatch_G1dispatch_G2dispatch_windspillage_windtotal_cost
    Float64Float64Float64Float64Float64Float64
    10.51000.0300.0200.00.065000.0
    20.61000.0300.0200.00.070000.0
    30.71000.0300.0200.00.075000.0
    40.81000.0300.0200.00.080000.0
    50.91000.0300.0200.00.085000.0
    61.01000.0300.0200.00.090000.0
    71.11000.0300.0200.00.095000.0
    81.21000.0300.0200.00.0100000.0
    91.31000.0300.0200.00.0105000.0
    101.41000.0300.0200.00.0110000.0
    111.51000.0300.0200.00.0115000.0
    121.61000.0300.0200.00.0120000.0
    131.71000.0300.0200.00.0125000.0
    141.81000.0300.0200.00.0130000.0
    151.91000.0300.0200.00.0135000.0
    162.0300.01000.0200.00.0140000.0
    172.1300.01000.0200.00.0141500.0
    182.2300.01000.0200.00.0143000.0
    192.3300.01000.0200.00.0144500.0
    202.4300.01000.0200.00.0146000.0
    212.5300.01000.0200.00.0147500.0
    222.6300.01000.0200.00.0149000.0
    232.7300.01000.0200.00.0150500.0
    242.8300.01000.0200.00.0152000.0
    252.9300.01000.0200.00.0153500.0
    263.0300.01000.0200.00.0155000.0

    Modifying the JuMP model in-place

    Note that in the previous exercise we entirely rebuilt the optimization model at every iteration of the internal loop, which incurs an additional computational burden. This burden can be alleviated if instead of re-building the entire model, we modify the constraints or objective function, as it shown in the example below.

    Compare the computing time in case of the above and below models.

    function solve_economic_dispatch_inplace(
         generators::Vector,
         wind,
         scenario,
    @@ -155,7 +155,7 @@
         scenario,
         0.5:0.1:3.0,
     )
    -print(string("elapsed time: ", time() - start, " seconds"))
    elapsed time: 0.1726670265197754 seconds

    For small models, adjusting specific constraints or the objective function is sometimes faster and sometimes slower than re-building the entire model. However, as the problem size increases, updating the model in-place is usually faster.

    inplace_df
    26×6 DataFrame
    Rowscaledispatch_G1dispatch_G2dispatch_windspillage_windtotal_cost
    Float64Float64Float64Float64Float64Float64
    10.51000.0300.0200.00.065000.0
    20.61000.0300.0200.00.070000.0
    30.71000.0300.0200.00.075000.0
    40.81000.0300.0200.00.080000.0
    50.91000.0300.0200.00.085000.0
    61.01000.0300.0200.00.090000.0
    71.11000.0300.0200.00.095000.0
    81.21000.0300.0200.00.0100000.0
    91.31000.0300.0200.00.0105000.0
    101.41000.0300.0200.00.0110000.0
    111.51000.0300.0200.00.0115000.0
    121.61000.0300.0200.00.0120000.0
    131.71000.0300.0200.00.0125000.0
    141.81000.0300.0200.00.0130000.0
    151.91000.0300.0200.00.0135000.0
    162.01000.0300.0200.00.0140000.0
    172.1300.01000.0200.00.0141500.0
    182.2300.01000.0200.00.0143000.0
    192.3300.01000.0200.00.0144500.0
    202.4300.01000.0200.00.0146000.0
    212.5300.01000.0200.00.0147500.0
    222.6300.01000.0200.00.0149000.0
    232.7300.01000.0200.00.0150500.0
    242.8300.01000.0200.00.0152000.0
    252.9300.01000.0200.00.0153500.0
    263.0300.01000.0200.00.0155000.0

    Inefficient usage of wind generators

    The economic dispatch problem does not perform commitment decisions and, thus, assumes that all generators must be dispatched at least at their minimum power output limit. This approach is not cost efficient and may lead to absurd decisions. For example, if $d = \sum_{i \in I} g^{\min}_{i}$, the wind power injection must be zero, that is, all available wind generation is spilled, to meet the minimum power output constraints on generators.

    In the following example, we adjust the total demand and observed how it affects wind spillage.

    demand_scale_df = DataFrames.DataFrame(;
    +print(string("elapsed time: ", time() - start, " seconds"))
    elapsed time: 0.17295002937316895 seconds

    For small models, adjusting specific constraints or the objective function is sometimes faster and sometimes slower than re-building the entire model. However, as the problem size increases, updating the model in-place is usually faster.

    inplace_df
    26×6 DataFrame
    Rowscaledispatch_G1dispatch_G2dispatch_windspillage_windtotal_cost
    Float64Float64Float64Float64Float64Float64
    10.51000.0300.0200.00.065000.0
    20.61000.0300.0200.00.070000.0
    30.71000.0300.0200.00.075000.0
    40.81000.0300.0200.00.080000.0
    50.91000.0300.0200.00.085000.0
    61.01000.0300.0200.00.090000.0
    71.11000.0300.0200.00.095000.0
    81.21000.0300.0200.00.0100000.0
    91.31000.0300.0200.00.0105000.0
    101.41000.0300.0200.00.0110000.0
    111.51000.0300.0200.00.0115000.0
    121.61000.0300.0200.00.0120000.0
    131.71000.0300.0200.00.0125000.0
    141.81000.0300.0200.00.0130000.0
    151.91000.0300.0200.00.0135000.0
    162.01000.0300.0200.00.0140000.0
    172.1300.01000.0200.00.0141500.0
    182.2300.01000.0200.00.0143000.0
    192.3300.01000.0200.00.0144500.0
    202.4300.01000.0200.00.0146000.0
    212.5300.01000.0200.00.0147500.0
    222.6300.01000.0200.00.0149000.0
    232.7300.01000.0200.00.0150500.0
    242.8300.01000.0200.00.0152000.0
    252.9300.01000.0200.00.0153500.0
    263.0300.01000.0200.00.0155000.0

    Inefficient usage of wind generators

    The economic dispatch problem does not perform commitment decisions and, thus, assumes that all generators must be dispatched at least at their minimum power output limit. This approach is not cost efficient and may lead to absurd decisions. For example, if $d = \sum_{i \in I} g^{\min}_{i}$, the wind power injection must be zero, that is, all available wind generation is spilled, to meet the minimum power output constraints on generators.

    In the following example, we adjust the total demand and observed how it affects wind spillage.

    demand_scale_df = DataFrames.DataFrame(;
         demand = Float64[],
         dispatch_G1 = Float64[],
         dispatch_G2 = Float64[],
    @@ -212,7 +212,7 @@
         ),
     )
     
    -Plots.plot(dispatch_plot, wind_plot)
    Example block output

    This particular drawback can be overcome by introducing binary decisions on the "on/off" status of generators. This model is called unit commitment and considered later in these notes.

    For further reading on the interplay between wind generation and the minimum power output constraints of generators, we refer interested readers to R. Baldick, "Wind and energy markets: a case study of Texas," IEEE Systems Journal, vol. 6, pp. 27-34, 2012.

    Unit commitment

    The Unit Commitment (UC) model can be obtained from ED model by introducing binary variable associated with each generator. This binary variable can attain two values: if it is "1," the generator is synchronized and, thus, can be dispatched, otherwise, that is, if the binary variable is "0," that generator is not synchronized and its power output is set to 0.

    To obtain the mathematical formulation of the UC model, we will modify the constraints of the ED model as follows:

    \[g^{\min}_{i} \cdot u_{t,i} \leq g_{i} \leq g^{\max}_{i} \cdot u_{t,i},\]

    where $u_{i} \in \{0,1\}.$ In this constraint, if $u_{i} = 0$, then $g_{i} = 0$. On the other hand, if $u_{i} = 1$, then $g^{min}_{i} \leq g_{i} \leq g^{max}_{i}$.

    For further reading on the UC problem we refer interested readers to G. Morales-Espana, J. M. Latorre, and A. Ramos, "Tight and Compact MILP Formulation for the Thermal Unit Commitment Problem," IEEE Transactions on Power Systems, vol. 28, pp. 4897-4908, 2013.

    In the following example we convert the ED model explained above to the UC model.

    function solve_unit_commitment(generators::Vector, wind, scenario)
    +Plots.plot(dispatch_plot, wind_plot)
    Example block output

    This particular drawback can be overcome by introducing binary decisions on the "on/off" status of generators. This model is called unit commitment and considered later in these notes.

    For further reading on the interplay between wind generation and the minimum power output constraints of generators, we refer interested readers to R. Baldick, "Wind and energy markets: a case study of Texas," IEEE Systems Journal, vol. 6, pp. 27-34, 2012.

    Unit commitment

    The Unit Commitment (UC) model can be obtained from ED model by introducing binary variable associated with each generator. This binary variable can attain two values: if it is "1," the generator is synchronized and, thus, can be dispatched, otherwise, that is, if the binary variable is "0," that generator is not synchronized and its power output is set to 0.

    To obtain the mathematical formulation of the UC model, we will modify the constraints of the ED model as follows:

    \[g^{\min}_{i} \cdot u_{t,i} \leq g_{i} \leq g^{\max}_{i} \cdot u_{t,i},\]

    where $u_{i} \in \{0,1\}.$ In this constraint, if $u_{i} = 0$, then $g_{i} = 0$. On the other hand, if $u_{i} = 1$, then $g^{min}_{i} \leq g_{i} \leq g^{max}_{i}$.

    For further reading on the UC problem we refer interested readers to G. Morales-Espana, J. M. Latorre, and A. Ramos, "Tight and Compact MILP Formulation for the Thermal Unit Commitment Problem," IEEE Transactions on Power Systems, vol. 28, pp. 4897-4908, 2013.

    In the following example we convert the ED model explained above to the UC model.

    function solve_unit_commitment(generators::Vector, wind, scenario)
         model = Model(HiGHS.Optimizer)
         set_silent(model)
         N = length(generators)
    @@ -325,7 +325,7 @@
         ),
     )
     
    -Plots.plot(commitment_plot, dispatch_plot)
    Example block output

    Nonlinear economic dispatch

    As a final example, we modify our economic dispatch problem in two ways:

    • The thermal cost function is user-defined
    • The output of the wind is only the square-root of the dispatch
    import Ipopt
    +Plots.plot(commitment_plot, dispatch_plot)
    Example block output

    Nonlinear economic dispatch

    As a final example, we modify our economic dispatch problem in two ways:

    • The thermal cost function is user-defined
    • The output of the wind is only the square-root of the dispatch
    import Ipopt
     
     """
         thermal_cost_function(g)
    @@ -395,4 +395,4 @@
         xlabel = "Cost",
         ylabel = "Dispatch [MW]",
         label = false,
    -)
    Example block output +)Example block output diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/2040fe83.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/2040fe83.svg deleted file mode 100644 index 9992abfdddb..00000000000 --- a/previews/PR3883/tutorials/applications/two_stage_stochastic/2040fe83.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/2e0b8dfe.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/2e0b8dfe.svg new file mode 100644 index 00000000000..3662f2549e1 --- /dev/null +++ b/previews/PR3883/tutorials/applications/two_stage_stochastic/2e0b8dfe.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/3ea6dc63.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/3ea6dc63.svg deleted file mode 100644 index b359dbda201..00000000000 --- a/previews/PR3883/tutorials/applications/two_stage_stochastic/3ea6dc63.svg +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/52aae8ac.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/52aae8ac.svg deleted file mode 100644 index ce90d908384..00000000000 --- a/previews/PR3883/tutorials/applications/two_stage_stochastic/52aae8ac.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/60389e63.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/60389e63.svg new file mode 100644 index 00000000000..40ed536fd6d --- /dev/null +++ b/previews/PR3883/tutorials/applications/two_stage_stochastic/60389e63.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/af4ea909.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/af4ea909.svg new file mode 100644 index 00000000000..cd88f9c258a --- /dev/null +++ b/previews/PR3883/tutorials/applications/two_stage_stochastic/af4ea909.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/b54f1361.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/b54f1361.svg deleted file mode 100644 index c81a90cea6b..00000000000 --- a/previews/PR3883/tutorials/applications/two_stage_stochastic/b54f1361.svg +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/e7af78cc.svg b/previews/PR3883/tutorials/applications/two_stage_stochastic/e7af78cc.svg new file mode 100644 index 00000000000..bf14e665a66 --- /dev/null +++ b/previews/PR3883/tutorials/applications/two_stage_stochastic/e7af78cc.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/applications/two_stage_stochastic/index.html b/previews/PR3883/tutorials/applications/two_stage_stochastic/index.html index 94c0d059402..0e738f8dc0e 100644 --- a/previews/PR3883/tutorials/applications/two_stage_stochastic/index.html +++ b/previews/PR3883/tutorials/applications/two_stage_stochastic/index.html @@ -18,7 +18,7 @@ d = sort!(rand(D, N)); Ω = 1:N P = fill(1 / N, N); -StatsPlots.histogram(d; bins = 20, label = "", xlabel = "Demand")Example block output

    JuMP model

    The implementation of our two-stage stochastic program in JuMP is:

    model = Model(HiGHS.Optimizer)
    +StatsPlots.histogram(d; bins = 20, label = "", xlabel = "Demand")
    Example block output

    JuMP model

    The implementation of our two-stage stochastic program in JuMP is:

    model = Model(HiGHS.Optimizer)
     set_silent(model)
     @variable(model, x >= 0)
     @variable(model, 0 <= y[ω in Ω] <= d[ω])
    @@ -38,37 +38,37 @@
     * Candidate solution (result #1)
       Primal status      : FEASIBLE_POINT
       Dual status        : FEASIBLE_POINT
    -  Objective value    : 5.65734e+02
    -  Objective bound    : 5.65734e+02
    -  Relative gap       : 8.03818e-16
    -  Dual objective value : 5.65734e+02
    +  Objective value    : 5.54445e+02
    +  Objective bound    : 5.54445e+02
    +  Relative gap       : 4.10092e-16
    +  Dual objective value : 5.54445e+02
     
     * Work counters
    -  Solve time (sec)   : 3.75032e-04
    +  Solve time (sec)   : 3.66211e-04
       Simplex iterations : 42
       Barrier iterations : 0
       Node count         : -1
    -

    The optimal number of pies to make is:

    value(x)
    210.8214463940363

    The distribution of total profit is:

    total_profit = [-2 * value(x) + value(z[ω]) for ω in Ω]
    100-element Vector{Float64}:
    - 359.35682874193185
    - 388.4494442068667
    - 410.3620621700761
    - 414.40001255101845
    - 415.92628346608467
    - 417.75240054598385
    - 433.9452073014721
    - 442.0345905939463
    - 446.80781618368474
    - 450.4954059960626
    +

    The optimal number of pies to make is:

    value(x)
    204.66024408244778

    The distribution of total profit is:

    total_profit = [-2 * value(x) + value(z[ω]) for ω in Ω]
    100-element Vector{Float64}:
    + 352.59092998480924
    + 354.5366973512387
    + 356.3306495091606
    + 369.1954471393269
    + 406.4976701860717
    + 416.4434735009804
    + 420.6681092567769
    + 421.3783420402592
    + 426.6142804492565
    + 427.09480794235856
        ⋮
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088
    - 632.4643391821088

    Let's plot it:

    """
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432
    + 613.9807322473432

    Let's plot it:

    """
         bin_distribution(x::Vector{Float64}, N::Int)
     
     A helper function that discretizes `x` into bins of width `N`.
    @@ -89,7 +89,7 @@
         label = "Expected profit (\$$(round(Int, μ)))",
         linewidth = 3,
     )
    -plot
    Example block output

    Risk measures

    A risk measure is a function which maps a random variable to a real number. Common risk measures include the mean (expectation), median, mode, and maximum. We need a risk measure to convert the distribution of second stage costs into a single number that can be optimized.

    Our model currently uses the expectation risk measure, but others are possible too. One popular risk measure is the conditional value at risk (CVaR).

    CVaR has a parameter $\gamma$, and it computes the expectation of the worst $\gamma$ fraction of outcomes.

    If we are maximizing, so that small outcomes are bad, the definition of CVaR is:

    \[CVaR_{\gamma}[Z] = \max\limits_{\xi} \;\; \xi - \frac{1}{\gamma}\mathbb{E}_\omega\left[(\xi - Z)_+\right]\]

    which can be formulated as the linear program:

    \[\begin{aligned} +plotExample block output

    Risk measures

    A risk measure is a function which maps a random variable to a real number. Common risk measures include the mean (expectation), median, mode, and maximum. We need a risk measure to convert the distribution of second stage costs into a single number that can be optimized.

    Our model currently uses the expectation risk measure, but others are possible too. One popular risk measure is the conditional value at risk (CVaR).

    CVaR has a parameter $\gamma$, and it computes the expectation of the worst $\gamma$ fraction of outcomes.

    If we are maximizing, so that small outcomes are bad, the definition of CVaR is:

    \[CVaR_{\gamma}[Z] = \max\limits_{\xi} \;\; \xi - \frac{1}{\gamma}\mathbb{E}_\omega\left[(\xi - Z)_+\right]\]

    which can be formulated as the linear program:

    \[\begin{aligned} CVaR_{\gamma}[Z] = \max\limits_{\xi, z_\omega} \;\; & \xi - \frac{1}{\gamma}\sum P_\omega z_\omega\\ & z_\omega \ge \xi - Z_\omega & \quad \forall \omega \\ & z_\omega \ge 0 & \quad \forall \omega. @@ -105,7 +105,7 @@ optimize!(model) @assert is_solved_and_feasible(model) return objective_value(model) -end

    CVaR (generic function with 1 method)

    When γ is 1.0, we compute the mean of the profit:

    cvar_10 = CVaR(total_profit, P; γ = 1.0)
    565.7343953351667
    Statistics.mean(total_profit)
    565.7343953351664

    As γ approaches 0.0, we compute the worst-case (minimum) profit:

    cvar_00 = CVaR(total_profit, P; γ = 0.0001)
    359.35682874193185
    minimum(total_profit)
    359.35682874193185

    By varying γ between 0 and 1 we can compute some trade-off of these two extremes:

    cvar_05 = CVaR(total_profit, P; γ = 0.5)
    501.2661211823924

    Let's plot these outcomes on our distribution:

    plot = StatsPlots.histogram(
    +end
    CVaR (generic function with 1 method)

    When γ is 1.0, we compute the mean of the profit:

    cvar_10 = CVaR(total_profit, P; γ = 1.0)
    554.4450633785054
    Statistics.mean(total_profit)
    554.4450633785053

    As γ approaches 0.0, we compute the worst-case (minimum) profit:

    cvar_00 = CVaR(total_profit, P; γ = 0.0001)
    352.59092998480924
    minimum(total_profit)
    352.59092998480924

    By varying γ between 0 and 1 we can compute some trade-off of these two extremes:

    cvar_05 = CVaR(total_profit, P; γ = 0.5)
    496.7810170223917

    Let's plot these outcomes on our distribution:

    plot = StatsPlots.histogram(
         total_profit;
         bins = bin_distribution(total_profit, 25),
         label = "",
    @@ -118,7 +118,7 @@
         label = ["γ = 1.0" "γ = 0.5" "γ = 0.0"],
         linewidth = 3,
     )
    -plot
    Example block output

    Risk averse sample average approximation

    Because CVaR can be formulated as a linear program, we can form a risk averse sample average approximation model by combining the two formulations:

    γ = 0.4
    +plot
    Example block output

    Risk averse sample average approximation

    Because CVaR can be formulated as a linear program, we can form a risk averse sample average approximation model by combining the two formulations:

    γ = 0.4
     model = Model(HiGHS.Optimizer)
     set_silent(model)
     @variable(model, x >= 0)
    @@ -130,7 +130,7 @@
     @constraint(model, [ω in Ω], z[ω] >= ξ - Z[ω])
     @objective(model, Max, -2x + ξ - 1 / γ * sum(P[ω] * z[ω] for ω in Ω))
     optimize!(model)
    -@assert is_solved_and_feasible(model)

    When $\gamma = 0.4$, the optimal number of pies to bake is:

    value(x)
    182.37091699999775

    The distribution of total profit is:

    risk_averse_total_profit = [value(-2x + Z[ω]) for ω in Ω]
    +@assert is_solved_and_feasible(model)

    When $\gamma = 0.4$, the optimal number of pies to bake is:

    value(x)
    181.29616299408465

    The distribution of total profit is:

    risk_averse_total_profit = [value(-2x + Z[ω]) for ω in Ω]
     bins = bin_distribution([total_profit; risk_averse_total_profit], 25)
     plot = StatsPlots.histogram(total_profit; label = "Expectation", bins = bins)
     StatsPlots.histogram!(
    @@ -140,4 +140,4 @@
         bins = bins,
         alpha = 0.5,
     )
    -plot
    Example block output

    Next steps

    • Try solving this problem for different numbers of samples and different distributions.
    • Refactor the example to avoid hard-coding the costs. What happens to the solution if the cost of disposing unsold pies increases?
    • Plot the optimal number of pies to make for different values of the risk aversion parameter $\gamma$. What is the relationship?
    +plotExample block output

    Next steps

    • Try solving this problem for different numbers of samples and different distributions.
    • Refactor the example to avoid hard-coding the costs. What happens to the solution if the cost of disposing unsold pies increases?
    • Plot the optimal number of pies to make for different values of the risk aversion parameter $\gamma$. What is the relationship?
    diff --git a/previews/PR3883/tutorials/applications/web_app/index.html b/previews/PR3883/tutorials/applications/web_app/index.html index 24f559f1467..1362ea7df84 100644 --- a/previews/PR3883/tutorials/applications/web_app/index.html +++ b/previews/PR3883/tutorials/applications/web_app/index.html @@ -88,4 +88,4 @@ "status" => "failure" "reason" => "missing lower_bound param"

    If we don't send a lower_bound that is a number, we get:

    send_request(Dict("lower_bound" => "1.2"))
    Dict{String, Any} with 2 entries:
       "status" => "failure"
    -  "reason" => "lower_bound is not a number"

    Finally, we can shutdown our HTTP server:

    close(server)
    [ Info: Server on 127.0.0.1:8080 closing

    Next steps

    For more complicated examples relating to HTTP servers, consult the HTTP.jl documentation.

    To see how you can integrate this with a larger JuMP model, read Design patterns for larger models.

    + "reason" => "lower_bound is not a number"

    Finally, we can shutdown our HTTP server:

    close(server)
    [ Info: Server on 127.0.0.1:8080 closing

    Next steps

    For more complicated examples relating to HTTP servers, consult the HTTP.jl documentation.

    To see how you can integrate this with a larger JuMP model, read Design patterns for larger models.

    diff --git a/previews/PR3883/tutorials/conic/arbitrary_precision/index.html b/previews/PR3883/tutorials/conic/arbitrary_precision/index.html index 628cd9f23bf..3f2b763b85a 100644 --- a/previews/PR3883/tutorials/conic/arbitrary_precision/index.html +++ b/previews/PR3883/tutorials/conic/arbitrary_precision/index.html @@ -37,7 +37,7 @@ Dual objective value : -6.42857e-01 * Work counters - Solve time (sec) : 5.63958e-01 + Solve time (sec) : 4.48528e-01 Barrier iterations : 5

    The value of each decision variable is a BigFloat:

    value.(x)
    2-element Vector{BigFloat}:
      0.4285714246558161076147072906813123533593766450416896337912086518811186790735189
    @@ -82,4 +82,4 @@
     * Work counters
     

    The optimal values are given in exact rational arithmetic:

    value.(x)
    2-element Vector{Rational{BigInt}}:
      1//6
    - 2//3
    objective_value(model)
    5//6
    value(c2)
    13//6
    + 2//3
    objective_value(model)
    5//6
    value(c2)
    13//6
    diff --git a/previews/PR3883/tutorials/conic/dualization/index.html b/previews/PR3883/tutorials/conic/dualization/index.html index 0fa311164df..727fa1113b8 100644 --- a/previews/PR3883/tutorials/conic/dualization/index.html +++ b/previews/PR3883/tutorials/conic/dualization/index.html @@ -53,12 +53,12 @@ ------------------------------------------------------------------ iter | pri res | dua res | gap | obj | scale | time (s) ------------------------------------------------------------------ - 0| 1.65e+01 1.60e-01 5.09e+01 -2.91e+01 1.00e-01 1.40e-04 - 50| 1.74e-08 2.70e-10 4.88e-08 -4.00e+00 1.00e-01 2.23e-04 + 0| 1.65e+01 1.60e-01 5.09e+01 -2.91e+01 1.00e-01 1.28e-04 + 50| 1.74e-08 2.70e-10 4.88e-08 -4.00e+00 1.00e-01 2.05e-04 ------------------------------------------------------------------ status: solved -timings: total: 2.24e-04s = setup: 4.41e-05s + solve: 1.80e-04s - lin-sys: 1.07e-05s, cones: 6.49e-05s, accel: 2.74e-06s +timings: total: 2.06e-04s = setup: 4.32e-05s + solve: 1.63e-04s + lin-sys: 1.09e-05s, cones: 5.87e-05s, accel: 2.95e-06s ------------------------------------------------------------------ objective = -4.000000 ------------------------------------------------------------------

    (There are five rows in the constraint matrix because SCS expects problems in geometric conic form, and so JuMP has reformulated the X, PSD variable constraint into the affine constraint X .+ 0 in PSDCone().)

    The solution we obtain is:

    value.(X)
    2×2 Matrix{Float64}:
    @@ -83,12 +83,12 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 1.23e+01  1.00e+00  2.73e+01 -9.03e+00  1.00e-01  1.29e-04
    -    50| 1.13e-07  1.05e-09  3.23e-07  4.00e+00  1.00e-01  2.10e-04
    +     0| 1.23e+01  1.00e+00  2.73e+01 -9.03e+00  1.00e-01  1.26e-04
    +    50| 1.13e-07  1.05e-09  3.23e-07  4.00e+00  1.00e-01  2.05e-04
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 2.11e-04s = setup: 4.49e-05s + solve: 1.66e-04s
    -	 lin-sys: 9.19e-06s, cones: 5.90e-05s, accel: 2.72e-06s
    +timings: total: 2.06e-04s = setup: 4.56e-05s + solve: 1.60e-04s
    +	 lin-sys: 8.97e-06s, cones: 5.76e-05s, accel: 2.66e-06s
     ------------------------------------------------------------------
     objective = 4.000000
     ------------------------------------------------------------------

    and the solution we obtain is:

    dual.(dual_c)
    2×2 Matrix{Float64}:
    @@ -113,12 +113,12 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 1.23e+01  1.00e+00  2.73e+01 -9.03e+00  1.00e-01  1.19e-04
    -    50| 1.13e-07  1.05e-09  3.23e-07  4.00e+00  1.00e-01  2.00e-04
    +     0| 1.23e+01  1.00e+00  2.73e+01 -9.03e+00  1.00e-01  1.16e-04
    +    50| 1.13e-07  1.05e-09  3.23e-07  4.00e+00  1.00e-01  1.96e-04
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 2.01e-04s = setup: 4.33e-05s + solve: 1.57e-04s
    -	 lin-sys: 9.23e-06s, cones: 5.95e-05s, accel: 2.87e-06s
    +timings: total: 1.97e-04s = setup: 3.94e-05s + solve: 1.58e-04s
    +	 lin-sys: 9.29e-06s, cones: 5.93e-05s, accel: 2.74e-06s
     ------------------------------------------------------------------
     objective = 4.000000
     ------------------------------------------------------------------

    The performance is the same as if we solved model_dual, and the correct solution is returned to X:

    value.(X)
    2×2 Matrix{Float64}:
    @@ -144,12 +144,12 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 1.65e+01  1.60e-01  5.09e+01 -2.91e+01  1.00e-01  1.45e-04
    -    50| 1.74e-08  2.70e-10  4.88e-08 -4.00e+00  1.00e-01  2.23e-04
    +     0| 1.65e+01  1.60e-01  5.09e+01 -2.91e+01  1.00e-01  1.55e-04
    +    50| 1.74e-08  2.70e-10  4.88e-08 -4.00e+00  1.00e-01  2.34e-04
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 2.24e-04s = setup: 5.55e-05s + solve: 1.69e-04s
    -	 lin-sys: 1.08e-05s, cones: 5.93e-05s, accel: 3.01e-06s
    +timings: total: 2.35e-04s = setup: 5.33e-05s + solve: 1.81e-04s
    +	 lin-sys: 1.08e-05s, cones: 5.93e-05s, accel: 3.03e-06s
     ------------------------------------------------------------------
     objective = -4.000000
     ------------------------------------------------------------------
    dual.(dual_c)
    2×2 Matrix{Float64}:
    @@ -185,12 +185,12 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 4.73e+00  1.00e+00  2.92e+00  1.23e+00  1.00e-01  1.68e-04
    -   150| 1.01e-04  3.07e-05  6.08e-05  1.33e+00  1.00e-01  7.56e-04
    +     0| 4.73e+00  1.00e+00  2.92e+00  1.23e+00  1.00e-01  1.32e-04
    +   150| 1.01e-04  3.07e-05  6.08e-05  1.33e+00  1.00e-01  7.05e-04
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 7.57e-04s = setup: 7.47e-05s + solve: 6.82e-04s
    -	 lin-sys: 9.52e-05s, cones: 4.09e-04s, accel: 3.61e-05s
    +timings: total: 7.06e-04s = setup: 6.48e-05s + solve: 6.41e-04s
    +	 lin-sys: 9.39e-05s, cones: 3.98e-04s, accel: 3.53e-05s
     ------------------------------------------------------------------
     objective = 1.333363
     ------------------------------------------------------------------
    set_optimizer(model, Dualization.dual_optimizer(SCS.Optimizer))
    @@ -212,12 +212,12 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 3.71e+01  1.48e+00  2.23e+02 -1.13e+02  1.00e-01  1.04e-04
    -   150| 1.57e-04  2.28e-05  2.08e-04 -1.33e+00  1.00e-01  6.84e-04
    +     0| 3.71e+01  1.48e+00  2.23e+02 -1.13e+02  1.00e-01  9.74e-05
    +   150| 1.57e-04  2.28e-05  2.08e-04 -1.33e+00  1.00e-01  6.74e-04
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 6.85e-04s = setup: 8.06e-05s + solve: 6.05e-04s
    -	 lin-sys: 9.98e-05s, cones: 4.02e-04s, accel: 2.20e-05s
    +timings: total: 6.75e-04s = setup: 7.41e-05s + solve: 6.01e-04s
    +	 lin-sys: 9.86e-05s, cones: 3.99e-04s, accel: 2.21e-05s
     ------------------------------------------------------------------
     objective = -1.333460
    -------------------------------------------------------------------

    For this problem, SCS reports that the primal has variables n: 11, constraints m: 24 and that the dual has variables n: 14, constraints m: 24. Therefore, we should probably use the primal formulation because it has fewer variables and the same number of constraints.

    When to use dual_optimizer

    Because it can make the problem larger or smaller, depending on the problem and the choice of solver, there is no definitive rule on when you should use dual_optimizer. However, you should try dual_optimizer if your conic optimization problem takes a long time to solve, or if you need to repeatedly solve similarly structured problems with different data. In some cases solving the dual instead of the primal can make a large difference.

    +------------------------------------------------------------------

    For this problem, SCS reports that the primal has variables n: 11, constraints m: 24 and that the dual has variables n: 14, constraints m: 24. Therefore, we should probably use the primal formulation because it has fewer variables and the same number of constraints.

    When to use dual_optimizer

    Because it can make the problem larger or smaller, depending on the problem and the choice of solver, there is no definitive rule on when you should use dual_optimizer. However, you should try dual_optimizer if your conic optimization problem takes a long time to solve, or if you need to repeatedly solve similarly structured problems with different data. In some cases solving the dual instead of the primal can make a large difference.

    diff --git a/previews/PR3883/tutorials/conic/ellipse_approx/1c6da16e.svg b/previews/PR3883/tutorials/conic/ellipse_approx/43c7637c.svg similarity index 57% rename from previews/PR3883/tutorials/conic/ellipse_approx/1c6da16e.svg rename to previews/PR3883/tutorials/conic/ellipse_approx/43c7637c.svg index eccf00a7c74..7b522ea1bb6 100644 --- a/previews/PR3883/tutorials/conic/ellipse_approx/1c6da16e.svg +++ b/previews/PR3883/tutorials/conic/ellipse_approx/43c7637c.svg @@ -1,2443 +1,2443 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/conic/ellipse_approx/cf8278dc.svg b/previews/PR3883/tutorials/conic/ellipse_approx/b4aed6d4.svg similarity index 57% rename from previews/PR3883/tutorials/conic/ellipse_approx/cf8278dc.svg rename to previews/PR3883/tutorials/conic/ellipse_approx/b4aed6d4.svg index 45d04d4126e..06d8d24b5f6 100644 --- a/previews/PR3883/tutorials/conic/ellipse_approx/cf8278dc.svg +++ b/previews/PR3883/tutorials/conic/ellipse_approx/b4aed6d4.svg @@ -1,2442 +1,2442 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/conic/ellipse_approx/index.html b/previews/PR3883/tutorials/conic/ellipse_approx/index.html index ba9b07ed7e5..03a1995cd66 100644 --- a/previews/PR3883/tutorials/conic/ellipse_approx/index.html +++ b/previews/PR3883/tutorials/conic/ellipse_approx/index.html @@ -36,7 +36,7 @@ c = :green, shape = :x, size = (600, 600), -)Example block output

    JuMP formulation

    Now let's build and the JuMP model. We'll compute $D$ and $c$ after the solve.

    model = Model(SCS.Optimizer)
    +)
    Example block output

    JuMP formulation

    Now let's build and the JuMP model. We'll compute $D$ and $c$ after the solve.

    model = Model(SCS.Optimizer)
     # We need to use a tighter tolerance for this example, otherwise the bounding
     # ellipse won't actually be bounding...
     set_attribute(model, "eps_rel", 1e-7)
    @@ -71,7 +71,7 @@
       Dual objective value : 5.08382e-03
     
     * Work counters
    -  Solve time (sec)   : 3.40963e-01
    +  Solve time (sec)   : 2.87603e-01
     

    Results

    After solving the model to optimality we can recover the solution in terms of $D$ and $c$:

    D = value.(Z)
    2×2 Matrix{Float64}:
       0.00755264  -0.0114233
      -0.0114233    0.0206963
    c = D \ value.(z)
    2-element Vector{Float64}:
    @@ -79,7 +79,7 @@
      -2.255547187078282

    We can check that each point lies inside the ellipsoid, by checking if the largest normalized radius is less than 1:

    largest_radius = maximum(map(x -> (x - c)' * D * (x - c), eachrow(S)))
    0.999891803944291

    Finally, overlaying the solution in the plot we see the minimal volume approximating ellipsoid:

    P = sqrt(D)
     q = -P * c
     data = [tuple(P \ [cos(θ) - q[1], sin(θ) - q[2]]...) for θ in 0:0.05:(2pi+0.05)]
    -Plots.plot!(plot, data; c = :crimson, label = nothing)
    Example block output

    Alternative formulations

    The formulation of model uses MOI.RootDetConeSquare. However, because SCS does not natively support this cone, JuMP automatically reformulates the problem into an equivalent problem that SCS does support. You can see the reformulation that JuMP chose using print_active_bridges:

    print_active_bridges(model)
     * Unsupported objective: MOI.VariableIndex
    +Plots.plot!(plot, data; c = :crimson, label = nothing)
    Example block output

    Alternative formulations

    The formulation of model uses MOI.RootDetConeSquare. However, because SCS does not natively support this cone, JuMP automatically reformulates the problem into an equivalent problem that SCS does support. You can see the reformulation that JuMP chose using print_active_bridges:

    print_active_bridges(model)
     * Unsupported objective: MOI.VariableIndex
      |  bridged by:
      |   MOIB.Objective.FunctionConversionBridge{Float64, MOI.ScalarAffineFunction{Float64}, MOI.VariableIndex}
      |  may introduce:
    @@ -259,7 +259,7 @@
     @objective(model, Max, 1 * t + 0)
     optimize!(model)
     Test.@test is_solved_and_feasible(model)
    -solve_time_1 = solve_time(model)
    0.34962659

    This formulation gives the much smaller graph:

    print_active_bridges(model)
     * Supported objective: MOI.ScalarAffineFunction{Float64}
    +solve_time_1 = solve_time(model)
    0.28776778799999997

    This formulation gives the much smaller graph:

    print_active_bridges(model)
     * Supported objective: MOI.ScalarAffineFunction{Float64}
      * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.Nonnegatives
      * Unsupported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.PositiveSemidefiniteConeTriangle
      |  bridged by:
    @@ -298,7 +298,7 @@
      |   |   |   |   * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.Nonnegatives
      |   * Supported variable: MOI.Reals

    The last bullet shows how JuMP reformulated the MOI.RootDetConeTriangle constraint by adding a mix of MOI.PositiveSemidefiniteConeTriangle and MOI.GeometricMeanCone constraints.

    Because SCS doesn't natively support the MOI.GeometricMeanCone, these constraints were further bridged using a MOI.Bridges.Constraint.GeoMeanToPowerBridge to a series of MOI.PowerCone constraints.

    However, there are many other ways that a MOI.GeometricMeanCone can be reformulated into something that SCS supports. Let's see what happens if we use remove_bridge to remove the MOI.Bridges.Constraint.GeoMeanToPowerBridge:

    remove_bridge(model, MOI.Bridges.Constraint.GeoMeanToPowerBridge)
     optimize!(model)
    -Test.@test is_solved_and_feasible(model)
    Test Passed

    This time, the solve took:

    solve_time_2 = solve_time(model)
    0.27875492300000004

    where previously it took

    solve_time_1
    0.34962659

    Why was the solve time different?

    print_active_bridges(model)
     * Supported objective: MOI.ScalarAffineFunction{Float64}
    +Test.@test is_solved_and_feasible(model)
    Test Passed

    This time, the solve took:

    solve_time_2 = solve_time(model)
    0.278028765

    where previously it took

    solve_time_1
    0.28776778799999997

    Why was the solve time different?

    print_active_bridges(model)
     * Supported objective: MOI.ScalarAffineFunction{Float64}
      * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.Nonnegatives
      * Unsupported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.PositiveSemidefiniteConeTriangle
      |  bridged by:
    @@ -342,4 +342,4 @@
      |   |   |   * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.SecondOrderCone
      |   |   * Supported constraint: MOI.VectorAffineFunction{Float64}-in-MOI.Nonnegatives
      |   |   * Supported variable: MOI.Reals
    - |   * Supported variable: MOI.Reals

    This time, JuMP used a MOI.Bridges.Constraint.GeoMeanBridge to reformulate the constraint into a set of MOI.RotatedSecondOrderCone constraints, which were further reformulated into a set of supported MOI.SecondOrderCone constraints.

    Since the two models are equivalent, we can conclude that for this particular model, the MOI.SecondOrderCone formulation is more efficient.

    In general though, the performance of a particular reformulation is problem- and solver-specific. Therefore, JuMP chooses to minimize the number of bridges in the default reformulation, leaving you to explore alternative formulations using the tools and techniques shown in this tutorial.

    + | * Supported variable: MOI.Reals

    This time, JuMP used a MOI.Bridges.Constraint.GeoMeanBridge to reformulate the constraint into a set of MOI.RotatedSecondOrderCone constraints, which were further reformulated into a set of supported MOI.SecondOrderCone constraints.

    Since the two models are equivalent, we can conclude that for this particular model, the MOI.SecondOrderCone formulation is more efficient.

    In general though, the performance of a particular reformulation is problem- and solver-specific. Therefore, JuMP chooses to minimize the number of bridges in the default reformulation, leaving you to explore alternative formulations using the tools and techniques shown in this tutorial.

    diff --git a/previews/PR3883/tutorials/conic/experiment_design/index.html b/previews/PR3883/tutorials/conic/experiment_design/index.html index e2a3c89dda9..8aaafc7ee55 100644 --- a/previews/PR3883/tutorials/conic/experiment_design/index.html +++ b/previews/PR3883/tutorials/conic/experiment_design/index.html @@ -99,4 +99,4 @@ 2.9157806299837166 2.67337566459234 2.735395012219622 - 0.3378388086258122 + 0.3378388086258122 diff --git a/previews/PR3883/tutorials/conic/introduction/index.html b/previews/PR3883/tutorials/conic/introduction/index.html index 9e257b8c78a..7eb3fd07299 100644 --- a/previews/PR3883/tutorials/conic/introduction/index.html +++ b/previews/PR3883/tutorials/conic/introduction/index.html @@ -6,4 +6,4 @@

    Introduction

    Conic programs are a class of convex nonlinear optimization problems which use cones to represent the nonlinearities. They have the form:

    \[\begin{align} & \min_{x \in \mathbb{R}^n} & f_0(x) \\ & \;\;\text{s.t.} & f_j(x) \in \mathcal{S}_j & \;\; j = 1 \ldots m -\end{align}\]

    Mixed-integer conic programs (MICPs) are extensions of conic programs in which some (or all) of the decision variables take discrete values.

    How to choose a solver

    JuMP supports a range of conic solvers, although support differs on what types of cones each solver supports. In the list of Supported solvers, "SOCP" denotes solvers supporting second-order cones and "SDP" denotes solvers supporting semidefinite cones. In addition, solvers such as SCS and Mosek have support for the exponential cone. Moreover, due to the bridging system in MathOptInterface, many of these solvers support a much wider range of exotic cones than they natively support. Solvers supporting discrete variables start with "(MI)" in the list of Supported solvers.

    Tip

    Duality plays a large role in solving conic optimization models. Depending on the solver, it can be more efficient to solve the dual instead of the primal. If performance is an issue, see the Dualization tutorial for more details.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    • The following tutorials are worked examples that present a problem in words, then formulate it in mathematics, and then solve it in JuMP. This usually involves some sort of visualization of the solution. Start here if you are new to JuMP.
    • The Modeling with cones tutorial contains a number of helpful reformulations and tricks you can use when modeling conic programs. Look here if you are stuck trying to formulate a problem as a conic program.
    • The remaining tutorials are less verbose and styled in the form of short code examples. These tutorials have less explanation, but may contain useful code snippets, particularly if they are similar to a problem you are trying to solve.
    +\end{align}\]

    Mixed-integer conic programs (MICPs) are extensions of conic programs in which some (or all) of the decision variables take discrete values.

    How to choose a solver

    JuMP supports a range of conic solvers, although support differs on what types of cones each solver supports. In the list of Supported solvers, "SOCP" denotes solvers supporting second-order cones and "SDP" denotes solvers supporting semidefinite cones. In addition, solvers such as SCS and Mosek have support for the exponential cone. Moreover, due to the bridging system in MathOptInterface, many of these solvers support a much wider range of exotic cones than they natively support. Solvers supporting discrete variables start with "(MI)" in the list of Supported solvers.

    Tip

    Duality plays a large role in solving conic optimization models. Depending on the solver, it can be more efficient to solve the dual instead of the primal. If performance is an issue, see the Dualization tutorial for more details.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    • The following tutorials are worked examples that present a problem in words, then formulate it in mathematics, and then solve it in JuMP. This usually involves some sort of visualization of the solution. Start here if you are new to JuMP.
    • The Modeling with cones tutorial contains a number of helpful reformulations and tricks you can use when modeling conic programs. Look here if you are stuck trying to formulate a problem as a conic program.
    • The remaining tutorials are less verbose and styled in the form of short code examples. These tutorials have less explanation, but may contain useful code snippets, particularly if they are similar to a problem you are trying to solve.
    diff --git a/previews/PR3883/tutorials/conic/logistic_regression/index.html b/previews/PR3883/tutorials/conic/logistic_regression/index.html index 53c59f5092f..9deb78599a4 100644 --- a/previews/PR3883/tutorials/conic/logistic_regression/index.html +++ b/previews/PR3883/tutorials/conic/logistic_regression/index.html @@ -109,4 +109,4 @@ )
    Number of non-zero components: 8 (out of 10 features)

    Extensions

    A direct extension would be to consider the sparse logistic regression with hard thresholding, which, on contrary to the soft version using a $\ell_1$ regularization, adds an explicit cardinality constraint in its formulation:

    \[\begin{aligned} \min_{\theta} & \; \sum_{i=1}^n \log(1 + \exp(-y_i \theta^\top x_i)) + \lambda \| \theta \|_2^2 \\ \text{subject to } & \quad \| \theta \|_0 <= k -\end{aligned}\]

    where $k$ is the maximum number of non-zero components in the vector $\theta$, and $\|.\|_0$ is the $\ell_0$ pseudo-norm:

    \[\| x\|_0 = \#\{i : \; x_i \neq 0\}\]

    The cardinality constraint $\|\theta\|_0 \leq k$ could be reformulated with binary variables. Thus the hard sparse regression problem could be solved by any solver supporting mixed integer conic problems.

    +\end{aligned}\]

    where $k$ is the maximum number of non-zero components in the vector $\theta$, and $\|.\|_0$ is the $\ell_0$ pseudo-norm:

    \[\| x\|_0 = \#\{i : \; x_i \neq 0\}\]

    The cardinality constraint $\|\theta\|_0 \leq k$ could be reformulated with binary variables. Thus the hard sparse regression problem could be solved by any solver supporting mixed integer conic problems.

    diff --git a/previews/PR3883/tutorials/conic/min_ellipse/1d7402ce.svg b/previews/PR3883/tutorials/conic/min_ellipse/42634a72.svg similarity index 88% rename from previews/PR3883/tutorials/conic/min_ellipse/1d7402ce.svg rename to previews/PR3883/tutorials/conic/min_ellipse/42634a72.svg index 2e6fcf04c70..c76ecc5acbd 100644 --- a/previews/PR3883/tutorials/conic/min_ellipse/1d7402ce.svg +++ b/previews/PR3883/tutorials/conic/min_ellipse/42634a72.svg @@ -1,53 +1,53 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/conic/min_ellipse/982b4ee4.svg b/previews/PR3883/tutorials/conic/min_ellipse/46ffd47b.svg similarity index 88% rename from previews/PR3883/tutorials/conic/min_ellipse/982b4ee4.svg rename to previews/PR3883/tutorials/conic/min_ellipse/46ffd47b.svg index 86ecec5780d..467d6d217f1 100644 --- a/previews/PR3883/tutorials/conic/min_ellipse/982b4ee4.svg +++ b/previews/PR3883/tutorials/conic/min_ellipse/46ffd47b.svg @@ -1,50 +1,50 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/conic/min_ellipse/index.html b/previews/PR3883/tutorials/conic/min_ellipse/index.html index 57adeb67d8d..c0021829613 100644 --- a/previews/PR3883/tutorials/conic/min_ellipse/index.html +++ b/previews/PR3883/tutorials/conic/min_ellipse/index.html @@ -46,7 +46,7 @@ for ellipse in ellipses plot_ellipse(plot, ellipse) end -plotExample block output

    Build the model

    Now let's build the model, using the change-of-variables = $P^2$ and P_q = $P q$. We'll recover the true value of P and q after the solve.

    model = Model(SCS.Optimizer)
    +plot
    Example block output

    Build the model

    Now let's build the model, using the change-of-variables = $P^2$ and P_q = $P q$. We'll recover the true value of P and q after the solve.

    model = Model(SCS.Optimizer)
     # We need to use a tighter tolerance for this example, otherwise the bounding
     # ellipse won't actually be bounding...
     set_attribute(model, "eps_rel", 1e-6)
    @@ -85,7 +85,7 @@
       Dual objective value : -4.04364e+00
     
     * Work counters
    -  Solve time (sec)   : 2.19265e-01
    +  Solve time (sec)   : 2.15027e-01
     

    Results

    After solving the model to optimality we can recover the solution in terms of $P$ and $q$:

    P = sqrt(value.(P²))
     q = P \ value.(P_q)
    2-element Vector{Float64}:
      -0.3964217693227084
    @@ -94,4 +94,4 @@
         [tuple(P \ [cos(θ) - q[1], sin(θ) - q[2]]...) for θ in 0:0.05:(2pi+0.05)];
         c = :crimson,
         label = nothing,
    -)
    Example block output +)Example block output diff --git a/previews/PR3883/tutorials/conic/quantum_discrimination/index.html b/previews/PR3883/tutorials/conic/quantum_discrimination/index.html index e826fb7b010..af547d1f37d 100644 --- a/previews/PR3883/tutorials/conic/quantum_discrimination/index.html +++ b/previews/PR3883/tutorials/conic/quantum_discrimination/index.html @@ -44,7 +44,7 @@ Dual objective value : 8.64062e-01 * Work counters - Solve time (sec) : 4.50027e-04 + Solve time (sec) : 4.29750e-04

    The probability of guessing correctly is:

    objective_value(model)
    0.8640614507314219

    When N = 2, there is a known analytical solution of:

    0.5 + 0.25 * sum(LinearAlgebra.svdvals(ρ[1] - ρ[2]))
    0.8640627582954737

    proving that we found the optimal solution.

    Finally, the optimal POVM is:

    solution = [value.(e) for e in E]
    2-element Vector{Matrix{ComplexF64}}:
      [0.9495721399750024 + 0.0im 0.03442451603977098 + 0.21609731371190505im; 0.03442451603977098 - 0.21609731371190505im 0.05042785512985496 + 0.0im]
      [0.05042785517602001 + 0.0im -0.03442451605312517 - 0.21609731370614843im; -0.03442451605312517 + 0.21609731370614843im 0.9495721400119357 + 0.0im]
    Tip

    Duality plays a large role in solving conic optimization models. Depending on the solver, it can be more efficient to solve the dual of this problem instead of the primal. If performance is an issue, see the Dualization tutorial for more details.

    Alternative formulation

    The formulation above includes N Hermitian matrices and a set of linear equality constraints. We can simplify the problem by replacing $E_N$ with $E_N = I - \sum\limits_{i=1}^{N-1} E_i$. This results in:

    model = Model(SCS.Optimizer)
    @@ -71,5 +71,5 @@
       Dual objective value : 8.64062e-01
     
     * Work counters
    -  Solve time (sec)   : 4.69924e-04
    -
    objective_value(model)
    0.8640596603179975
    + Solve time (sec) : 4.15363e-04 +
    objective_value(model)
    0.8640596603179975
    diff --git a/previews/PR3883/tutorials/conic/simple_examples/f3de8948.svg b/previews/PR3883/tutorials/conic/simple_examples/4697fce8.svg similarity index 79% rename from previews/PR3883/tutorials/conic/simple_examples/f3de8948.svg rename to previews/PR3883/tutorials/conic/simple_examples/4697fce8.svg index 8c4ef28faae..8aae1445e16 100644 --- a/previews/PR3883/tutorials/conic/simple_examples/f3de8948.svg +++ b/previews/PR3883/tutorials/conic/simple_examples/4697fce8.svg @@ -1,49 +1,49 @@ - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/conic/simple_examples/index.html b/previews/PR3883/tutorials/conic/simple_examples/index.html index 0b57e343297..39dc9da8875 100644 --- a/previews/PR3883/tutorials/conic/simple_examples/index.html +++ b/previews/PR3883/tutorials/conic/simple_examples/index.html @@ -179,7 +179,7 @@ ) end -example_minimum_distortion()Example block output

    Lovász numbers

    The Lovász number of a graph, also known as Lovász's theta-function, is a number that lies between two important and related numbers that are computationally hard to determine, namely the chromatic and clique numbers of the graph. It is possible however to efficient compute the Lovász number as the optimal value of a semidefinite program.

    Consider the pentagon graph:

         [5]
    +example_minimum_distortion()
    Example block output

    Lovász numbers

    The Lovász number of a graph, also known as Lovász's theta-function, is a number that lies between two important and related numbers that are computationally hard to determine, namely the chromatic and clique numbers of the graph. It is possible however to efficient compute the Lovász number as the optimal value of a semidefinite program.

    Consider the pentagon graph:

         [5]
         /   \
        /     \
      [1]     [4]
    @@ -242,4 +242,4 @@
         return
     end
     
    -example_robust_uncertainty_sets()
    +example_robust_uncertainty_sets() diff --git a/previews/PR3883/tutorials/conic/start_values/index.html b/previews/PR3883/tutorials/conic/start_values/index.html index 1baf1dd0f69..31ae4e2e213 100644 --- a/previews/PR3883/tutorials/conic/start_values/index.html +++ b/previews/PR3883/tutorials/conic/start_values/index.html @@ -52,12 +52,12 @@ ------------------------------------------------------------------ iter | pri res | dua res | gap | obj | scale | time (s) ------------------------------------------------------------------ - 0| 4.42e+01 1.00e+00 1.28e+02 -6.64e+01 1.00e-01 1.18e-04 - 75| 5.30e-07 2.63e-06 3.15e-07 -3.00e+00 1.00e-01 1.66e-04 + 0| 4.42e+01 1.00e+00 1.28e+02 -6.64e+01 1.00e-01 8.47e-05 + 75| 5.30e-07 2.63e-06 3.15e-07 -3.00e+00 1.00e-01 1.33e-04 ------------------------------------------------------------------ status: solved -timings: total: 1.67e-04s = setup: 4.16e-05s + solve: 1.26e-04s - lin-sys: 1.37e-05s, cones: 7.04e-06s, accel: 3.61e-06s +timings: total: 1.34e-04s = setup: 3.92e-05s + solve: 9.44e-05s + lin-sys: 1.35e-05s, cones: 6.93e-06s, accel: 3.70e-06s ------------------------------------------------------------------ objective = -2.999998 ------------------------------------------------------------------

    By looking at the log, we can see that SCS took 75 iterations to find the optimal solution. Now we set the optimal solution as our starting point:

    set_optimal_start_values(model)

    and we re-optimize:

    optimize!(model)
    ------------------------------------------------------------------
    @@ -76,11 +76,11 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 1.90e-05  1.56e-06  9.14e-05 -3.00e+00  1.00e-01  1.09e-04
    +     0| 1.90e-05  1.56e-06  9.14e-05 -3.00e+00  1.00e-01  8.41e-05
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 1.10e-04s = setup: 3.98e-05s + solve: 7.01e-05s
    -	 lin-sys: 8.21e-07s, cones: 1.50e-06s, accel: 3.00e-08s
    +timings: total: 8.53e-05s = setup: 3.88e-05s + solve: 4.65e-05s
    +	 lin-sys: 7.51e-07s, cones: 1.39e-06s, accel: 3.00e-08s
     ------------------------------------------------------------------
     objective = -3.000044
    -------------------------------------------------------------------

    Now the optimization terminates after 0 iterations because our starting point is already optimal.

    Caveats

    Some solvers do not support setting some parts of the starting solution, for example, they may support only set_start_value for variables.

    If you encounter an UnsupportedSupported attribute error for MOI.VariablePrimalStart, MOI.ConstraintPrimalStart, or MOI.ConstraintDualStart, comment out the corresponding part of the set_optimal_start_values function.

    +------------------------------------------------------------------

    Now the optimization terminates after 0 iterations because our starting point is already optimal.

    Caveats

    Some solvers do not support setting some parts of the starting solution, for example, they may support only set_start_value for variables.

    If you encounter an UnsupportedSupported attribute error for MOI.VariablePrimalStart, MOI.ConstraintPrimalStart, or MOI.ConstraintDualStart, comment out the corresponding part of the set_optimal_start_values function.

    diff --git a/previews/PR3883/tutorials/conic/tips_and_tricks/index.html b/previews/PR3883/tutorials/conic/tips_and_tricks/index.html index 44239bc54b3..0751c174700 100644 --- a/previews/PR3883/tutorials/conic/tips_and_tricks/index.html +++ b/previews/PR3883/tutorials/conic/tips_and_tricks/index.html @@ -172,4 +172,4 @@ @constraint(model, u == 0.5) optimize!(model) @assert is_solved_and_feasible(model) -value(t), 0.5 * log(LinearAlgebra.det(value.(X) ./ 0.5))
    (1.4979204481049098, 1.4978661010981238)

    Other Cones and Functions

    For other cones supported by JuMP, check out the MathOptInterface Manual.

    +value(t), 0.5 * log(LinearAlgebra.det(value.(X) ./ 0.5))
    (1.4979204481049098, 1.4978661010981238)

    Other Cones and Functions

    For other cones supported by JuMP, check out the MathOptInterface Manual.

    diff --git a/previews/PR3883/tutorials/getting_started/debugging/index.html b/previews/PR3883/tutorials/getting_started/debugging/index.html index 8688883c495..53201fc4038 100644 --- a/previews/PR3883/tutorials/getting_started/debugging/index.html +++ b/previews/PR3883/tutorials/getting_started/debugging/index.html @@ -24,4 +24,4 @@ julia> @profview foo(); # run once to trigger compilation. Ignore the output. -julia> @profview foo()

    This will open a flamegraph. The x-axis of the graph is time, so that wider bars take more time. The bars are stacked so that the foo() call is on the bottom, and subsequent calls within foo are stacked on top.

    Reading a flamegraph can take some experience, but if you click on a bar it will print the line number to the REPL. Hunt around until you find the widest bar that points to a line of code that you have written, then ask yourself if it makes sense for this line to be the bottleneck.

    If a wide bar points to code inside JuMP or a related Julia package, please open an issue on GitHub or post on the community forum.

    If @time foo() takes longer than a few minutes to run, then either make the problem smaller by using a smaller dataset, or do the following.

    1. Comment out everything in the function, then, line by line (or block by block):
    2. Un-comment some code and re-run @time foo()
    3. If the time increases by a lot (from seconds or minutes to hours), look for $O(N^2)$ or worse scaling behavior. Is there a better way to write the code that you are trying to execute?
    4. If the time increases by more than expected, but it still takes seconds or minutes to execute, use ProfileView to look for obvious bottlenecks.
    +julia> @profview foo()

    This will open a flamegraph. The x-axis of the graph is time, so that wider bars take more time. The bars are stacked so that the foo() call is on the bottom, and subsequent calls within foo are stacked on top.

    Reading a flamegraph can take some experience, but if you click on a bar it will print the line number to the REPL. Hunt around until you find the widest bar that points to a line of code that you have written, then ask yourself if it makes sense for this line to be the bottleneck.

    If a wide bar points to code inside JuMP or a related Julia package, please open an issue on GitHub or post on the community forum.

    If @time foo() takes longer than a few minutes to run, then either make the problem smaller by using a smaller dataset, or do the following.

    1. Comment out everything in the function, then, line by line (or block by block):
    2. Un-comment some code and re-run @time foo()
    3. If the time increases by a lot (from seconds or minutes to hours), look for $O(N^2)$ or worse scaling behavior. Is there a better way to write the code that you are trying to execute?
    4. If the time increases by more than expected, but it still takes seconds or minutes to execute, use ProfileView to look for obvious bottlenecks.
    diff --git a/previews/PR3883/tutorials/getting_started/design_patterns_for_larger_models/index.html b/previews/PR3883/tutorials/getting_started/design_patterns_for_larger_models/index.html index 9a156a25c87..4497cd819ca 100644 --- a/previews/PR3883/tutorials/getting_started/design_patterns_for_larger_models/index.html +++ b/previews/PR3883/tutorials/getting_started/design_patterns_for_larger_models/index.html @@ -520,4 +520,4 @@ ) @test x === nothing end -end
    Test.DefaultTestSet("KnapsackModel", Any[Test.DefaultTestSet("feasible_binary_knapsack", Any[], 5, false, false, true, 1.731619123853721e9, 1.731619123856128e9, false, "design_patterns_for_larger_models.md"), Test.DefaultTestSet("feasible_integer_knapsack", Any[], 5, false, false, true, 1.731619123856168e9, 1.731619123987157e9, false, "design_patterns_for_larger_models.md"), Test.DefaultTestSet("infeasible_binary_knapsack", Any[], 1, false, false, true, 1.731619123987206e9, 1.731619123989022e9, false, "design_patterns_for_larger_models.md")], 0, false, false, true, 1.731619123853682e9, 1.731619123989031e9, false, "design_patterns_for_larger_models.md")
    Tip

    Place these tests in a separate file test_knapsack_model.jl so that you can run the tests by adding include("test_knapsack_model.jl") to any file where needed.

    Next steps

    We've only briefly scratched the surface of ways to create and structure large JuMP models, so consider this tutorial a starting point, rather than a comprehensive list of all the possible ways to structure JuMP models. If you are embarking on a large project that uses JuMP, a good next step is to look at ways people have written large JuMP projects "in the wild."

    Here are some good examples (all co-incidentally related to energy):

    +end
    Test.DefaultTestSet("KnapsackModel", Any[Test.DefaultTestSet("feasible_binary_knapsack", Any[], 5, false, false, true, 1.731620404590437e9, 1.731620404592916e9, false, "design_patterns_for_larger_models.md"), Test.DefaultTestSet("feasible_integer_knapsack", Any[], 5, false, false, true, 1.731620404592958e9, 1.731620404720725e9, false, "design_patterns_for_larger_models.md"), Test.DefaultTestSet("infeasible_binary_knapsack", Any[], 1, false, false, true, 1.731620404720773e9, 1.731620404722398e9, false, "design_patterns_for_larger_models.md")], 0, false, false, true, 1.731620404590395e9, 1.731620404722406e9, false, "design_patterns_for_larger_models.md")
    Tip

    Place these tests in a separate file test_knapsack_model.jl so that you can run the tests by adding include("test_knapsack_model.jl") to any file where needed.

    Next steps

    We've only briefly scratched the surface of ways to create and structure large JuMP models, so consider this tutorial a starting point, rather than a comprehensive list of all the possible ways to structure JuMP models. If you are embarking on a large project that uses JuMP, a good next step is to look at ways people have written large JuMP projects "in the wild."

    Here are some good examples (all co-incidentally related to energy):

    diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_JuMP/index.html b/previews/PR3883/tutorials/getting_started/getting_started_with_JuMP/index.html index 865c4ba8648..2f1dc8a903f 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_JuMP/index.html +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_JuMP/index.html @@ -242,4 +242,4 @@ Model status : Optimal Simplex iterations: 4 Objective value : 4.9230769231e+00 -HiGHS run time : 0.00
    julia> @assert is_solved_and_feasible(vector_model)
    julia> objective_value(vector_model)4.923076923076922 +HiGHS run time : 0.00
    julia> @assert is_solved_and_feasible(vector_model)
    julia> objective_value(vector_model)4.923076923076922 diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/636b167a.svg b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/1a1f2b45.svg similarity index 82% rename from previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/636b167a.svg rename to previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/1a1f2b45.svg index 768885623fb..b7fcbf894fc 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/636b167a.svg +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/1a1f2b45.svg @@ -1,73 +1,73 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/a2c63921.svg b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/703210f8.svg similarity index 84% rename from previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/a2c63921.svg rename to previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/703210f8.svg index 3dc75e94510..f73a889ea40 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/a2c63921.svg +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/703210f8.svg @@ -1,62 +1,62 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/58ebee83.svg b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/a51d3326.svg similarity index 85% rename from previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/58ebee83.svg rename to previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/a51d3326.svg index 98c5aab0fa0..ea53842ebb7 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/58ebee83.svg +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/a51d3326.svg @@ -1,59 +1,59 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/index.html b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/index.html index c2820f7de8b..7d2acd93cc9 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/index.html +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_data_and_plotting/index.html @@ -14,7 +14,7 @@ csv_df.Height; xlabel = "Weight", ylabel = "Height", -)Example block output

    That doesn't look right. What happened? If you look at the dataframe above, it read Weight in as a String column because there are "NA" fields. Let's correct that, by telling CSV to consider "NA" as missing.

    csv_df = CSV.read(
    +)
    Example block output

    That doesn't look right. What happened? If you look at the dataframe above, it read Weight in as a String column because there are "NA" fields. Let's correct that, by telling CSV to consider "NA" as missing.

    csv_df = CSV.read(
         joinpath(DATA_DIR, "StarWars.csv"),
         DataFrames.DataFrame;
         missingstring = "NA",
    @@ -26,7 +26,7 @@
         ylabel = "Height",
         label = false,
         ylims = (0, 3),
    -)
    Example block output

    That looks better.

    Tip

    Read the CSV documentation for other parsing options.

    DataFrames.jl supports manipulation using functions similar to pandas. For example, split the dataframe into groups based on eye-color:

    by_eyecolor = DataFrames.groupby(csv_df, :Eyecolor)

    GroupedDataFrame with 7 groups based on key: Eyecolor

    First Group (5 rows): Eyecolor = "blue"
    RowNameGenderHeightWeightEyecolorHaircolorSkincolorHomelandBornDiedJediSpeciesWeapon
    String31String7Float64Float64?String15?String7?String15?String15String15String15String7String15String15
    1Anakin Skywalkermale1.8884.0blueblondfairTatooine41.9BBY4ABYjedihumanlightsaber
    2Luke Skywalkermale1.7277.0blueblondfairTatooine19BBYunk_diedjedihumanlightsaber
    3Qui-Gon Jinnmale1.9388.5bluebrownlightunk_planet92BBY32BBYjedihumanlightsaber
    4Sheev Palpatinemale1.7375.0blueredpaleNaboo82BBY10ABYno_jedihumanforce-lightning
    5Chewbaccamale2.28112.0bluebrownmissingKashyyyk200BBY25ABYno_jediwookieebowcaster

    Last Group (1 row): Eyecolor = "black"
    RowNameGenderHeightWeightEyecolorHaircolorSkincolorHomelandBornDiedJediSpeciesWeapon
    String31String7Float64Float64?String15?String7?String15?String15String15String15String7String15String15
    1Chief Chirpamale1.050.0blackgraybrownEndorunk_born4ABYno_jediewokspear

    Then recombine into a single dataframe based on a function operating over the split dataframes:

    eyecolor_count = DataFrames.combine(by_eyecolor) do df
    +)
    Example block output

    That looks better.

    Tip

    Read the CSV documentation for other parsing options.

    DataFrames.jl supports manipulation using functions similar to pandas. For example, split the dataframe into groups based on eye-color:

    by_eyecolor = DataFrames.groupby(csv_df, :Eyecolor)

    GroupedDataFrame with 7 groups based on key: Eyecolor

    First Group (5 rows): Eyecolor = "blue"
    RowNameGenderHeightWeightEyecolorHaircolorSkincolorHomelandBornDiedJediSpeciesWeapon
    String31String7Float64Float64?String15?String7?String15?String15String15String15String7String15String15
    1Anakin Skywalkermale1.8884.0blueblondfairTatooine41.9BBY4ABYjedihumanlightsaber
    2Luke Skywalkermale1.7277.0blueblondfairTatooine19BBYunk_diedjedihumanlightsaber
    3Qui-Gon Jinnmale1.9388.5bluebrownlightunk_planet92BBY32BBYjedihumanlightsaber
    4Sheev Palpatinemale1.7375.0blueredpaleNaboo82BBY10ABYno_jedihumanforce-lightning
    5Chewbaccamale2.28112.0bluebrownmissingKashyyyk200BBY25ABYno_jediwookieebowcaster

    Last Group (1 row): Eyecolor = "black"
    RowNameGenderHeightWeightEyecolorHaircolorSkincolorHomelandBornDiedJediSpeciesWeapon
    String31String7Float64Float64?String15?String7?String15?String15String15String15String7String15String15
    1Chief Chirpamale1.050.0blackgraybrownEndorunk_born4ABYno_jediewokspear

    Then recombine into a single dataframe based on a function operating over the split dataframes:

    eyecolor_count = DataFrames.combine(by_eyecolor) do df
         return DataFrames.nrow(df)
     end
    7×2 DataFrame
    RowEyecolorx1
    String15?Int64
    1blue5
    2brown8
    3bluegray1
    4missing2
    5yellow2
    6gold1
    7black1

    We can rename columns:

    DataFrames.rename!(eyecolor_count, :x1 => :count)
    7×2 DataFrame
    RowEyecolorcount
    String15?Int64
    1blue5
    2brown8
    3bluegray1
    4missing2
    5yellow2
    6gold1
    7black1

    Drop some missing rows:

    DataFrames.dropmissing!(eyecolor_count, :Eyecolor)
    6×2 DataFrame
    RowEyecolorcount
    String15Int64
    1blue5
    2brown8
    3bluegray1
    4yellow2
    5gold1
    6black1

    Then we can visualize the data:

    sort!(eyecolor_count, :count; rev = true)
     Plots.bar(
    @@ -35,7 +35,7 @@
         xlabel = "Eye color",
         ylabel = "Number of characters",
         label = false,
    -)
    Example block output

    Other Delimited Files

    We can also use the CSV.jl package to read any other delimited text file format.

    By default, CSV.File will try to detect a file's delimiter from the first 10 lines of the file.

    Candidate delimiters include ',', '\t', ' ', '|', ';', and ':'. If it can't auto-detect the delimiter, it will assume ','.

    Let's take the example of space separated data.

    ss_df = CSV.read(joinpath(DATA_DIR, "Cereal.txt"), DataFrames.DataFrame)
    23×10 DataFrame
    RowNameCupsCaloriesCarbsFatFiberPotassiumProteinSodiumSugars
    String31Float64Int64Float64Int64Float64Int64Int64Int64Int64
    1CapnCrunch0.7512012.020.035122012
    2CocoaPuffs1.011012.010.055118013
    3Trix1.011013.010.025114012
    4AppleJacks1.011011.001.030212514
    5CornChex1.011022.000.02522803
    6CornFlakes1.010021.001.03522902
    7Nut&Honey0.6712015.010.04021909
    8Smacks0.751109.011.04027015
    9MultiGrain1.010015.012.09022206
    10CracklinOat0.511010.034.016031407
    11GrapeNuts0.2511017.003.09031793
    12HoneyNutCheerios0.7511011.511.590325010
    13NutriGrain0.6714021.023.013032207
    14Product191.010020.001.04533203
    15TotalRaisinBran1.014015.014.0230319014
    16WheatChex0.6710017.013.011532303
    17Oatmeal0.513013.521.5120317010
    18Life0.6710012.022.09541506
    19Maypo1.010016.010.095403
    20QuakerOats0.510014.012.011041356
    21Muesli1.015016.033.0170415011
    22Cheerios1.2511017.022.010562901
    23SpecialK1.011016.001.05562303

    We can also specify the delimiter as follows:

    delim_df = CSV.read(
    +)
    Example block output

    Other Delimited Files

    We can also use the CSV.jl package to read any other delimited text file format.

    By default, CSV.File will try to detect a file's delimiter from the first 10 lines of the file.

    Candidate delimiters include ',', '\t', ' ', '|', ';', and ':'. If it can't auto-detect the delimiter, it will assume ','.

    Let's take the example of space separated data.

    ss_df = CSV.read(joinpath(DATA_DIR, "Cereal.txt"), DataFrames.DataFrame)
    23×10 DataFrame
    RowNameCupsCaloriesCarbsFatFiberPotassiumProteinSodiumSugars
    String31Float64Int64Float64Int64Float64Int64Int64Int64Int64
    1CapnCrunch0.7512012.020.035122012
    2CocoaPuffs1.011012.010.055118013
    3Trix1.011013.010.025114012
    4AppleJacks1.011011.001.030212514
    5CornChex1.011022.000.02522803
    6CornFlakes1.010021.001.03522902
    7Nut&Honey0.6712015.010.04021909
    8Smacks0.751109.011.04027015
    9MultiGrain1.010015.012.09022206
    10CracklinOat0.511010.034.016031407
    11GrapeNuts0.2511017.003.09031793
    12HoneyNutCheerios0.7511011.511.590325010
    13NutriGrain0.6714021.023.013032207
    14Product191.010020.001.04533203
    15TotalRaisinBran1.014015.014.0230319014
    16WheatChex0.6710017.013.011532303
    17Oatmeal0.513013.521.5120317010
    18Life0.6710012.022.09541506
    19Maypo1.010016.010.095403
    20QuakerOats0.510014.012.011041356
    21Muesli1.015016.033.0170415011
    22Cheerios1.2511017.022.010562901
    23SpecialK1.011016.001.05562303

    We can also specify the delimiter as follows:

    delim_df = CSV.read(
         joinpath(DATA_DIR, "Soccer.txt"),
         DataFrames.DataFrame;
         delim = "::",
    @@ -204,7 +204,7 @@
       Dual objective value : NaN
     
     * Work counters
    -  Solve time (sec)   : 6.40178e-03
    +  Solve time (sec)   : 6.81520e-03
       Simplex iterations : 26
       Barrier iterations : -1
       Node count         : 1
    @@ -236,4 +236,4 @@
      * Uganda
      * United Arab Emirates
      * United States
    - * Zimbabwe

    We need some passports, like New Zealand and the United States, which have widespread access to a large number of countries. However, we also need passports like North Korea which only have visa-free access to a very limited number of countries.

    Note

    We use value(x[c]) > 0.5 rather than value(x[c]) == 1 to avoid excluding solutions like x[c] = 0.99999 that are "1" to some tolerance.

    + * Zimbabwe

    We need some passports, like New Zealand and the United States, which have widespread access to a large number of countries. However, we also need passports like North Korea which only have visa-free access to a very limited number of countries.

    Note

    We use value(x[c]) > 0.5 rather than value(x[c]) == 1 to avoid excluding solutions like x[c] = 0.99999 that are "1" to some tolerance.

    diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_julia/index.html b/previews/PR3883/tutorials/getting_started/getting_started_with_julia/index.html index 49f6f0ff4f2..594d2b67555 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_julia/index.html +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_julia/index.html @@ -42,10 +42,10 @@ Closest candidates are: *(::Any, ::Any, ::Any, ::Any...) @ Base operators.jl:596 - *(::MutableArithmetics.Zero, ::Any) - @ MutableArithmetics ~/.julia/packages/MutableArithmetics/sjjl8/src/rewrite.jl:61 - *(::Any, ::MutableArithmetics.Zero) - @ MutableArithmetics ~/.julia/packages/MutableArithmetics/sjjl8/src/rewrite.jl:62 + *(::ChainRulesCore.NotImplemented, ::Any) + @ ChainRulesCore ~/.julia/packages/ChainRulesCore/6Pucz/src/tangent_arithmetic.jl:37 + *(::Any, ::ChainRulesCore.NotImplemented) + @ ChainRulesCore ~/.julia/packages/ChainRulesCore/6Pucz/src/tangent_arithmetic.jl:38 ...

    But multiplying transposes works:

    julia> b' * b61
    julia> b * b'2×2 Matrix{Int64}: 25 30 30 36

    Other common types

    Comments

    Although not technically a type, code comments begin with the # character:

    julia> 1 + 1  # This is a comment2

    Multiline comments begin with #= and end with =#:

    #=
    @@ -182,4 +182,4 @@
      0.5103924401614957
      0.9296414851080324

    The Package Manager is used to install packages that are not part of Julia's standard library.

    For example the following can be used to install JuMP,

    using Pkg
     Pkg.add("JuMP")

    For a complete list of registered Julia packages see the package listing at JuliaHub.

    From time to you may wish to use a Julia package that is not registered. In this case a git repository URL can be used to install the package.

    using Pkg
    -Pkg.add("https://github.com/user-name/MyPackage.jl.git")

    Package environments

    By default, Pkg.add will add packages to Julia's global environment. However, Julia also has built-in support for virtual environments.

    Activate a virtual environment with:

    import Pkg; Pkg.activate("/path/to/environment")

    You can see what packages are installed in the current environment with Pkg.status().

    Tip

    We strongly recommend you create a Pkg environment for each project that you create in Julia, and add only the packages that you need, instead of adding lots of packages to the global environment. The Pkg manager documentation has more information on this topic.

    +Pkg.add("https://github.com/user-name/MyPackage.jl.git")

    Package environments

    By default, Pkg.add will add packages to Julia's global environment. However, Julia also has built-in support for virtual environments.

    Activate a virtual environment with:

    import Pkg; Pkg.activate("/path/to/environment")

    You can see what packages are installed in the current environment with Pkg.status().

    Tip

    We strongly recommend you create a Pkg environment for each project that you create in Julia, and add only the packages that you need, instead of adding lots of packages to the global environment. The Pkg manager documentation has more information on this topic.

    diff --git a/previews/PR3883/tutorials/getting_started/getting_started_with_sets_and_indexing/index.html b/previews/PR3883/tutorials/getting_started/getting_started_with_sets_and_indexing/index.html index eed2b5da75d..ff4909f7033 100644 --- a/previews/PR3883/tutorials/getting_started/getting_started_with_sets_and_indexing/index.html +++ b/previews/PR3883/tutorials/getting_started/getting_started_with_sets_and_indexing/index.html @@ -219,4 +219,4 @@ ("Dunedin", "Auckland") => 1426 ("Auckland", "Christchurch") => 1071

    Then, we can create our model like so:

    model = Model()
     @variable(model, x[keys(routes)])
    -@objective(model, Min, sum(v * x[k] for (k, v) in routes))

    \[ 643 x_{("Auckland", "Wellington")} + 436 x_{("Wellington", "Christchurch")} + 790 x_{("Wellington", "Dunedin")} + 360 x_{("Christchurch", "Dunedin")} + 1426 x_{("Auckland", "Dunedin")} + 1426 x_{("Dunedin", "Auckland")} + 1071 x_{("Auckland", "Christchurch")} \]

    This has a number of benefits over the other approaches, including a compacter algebraic model and variables that are named in a more meaningful way.

    Tip

    If you're struggling to formulate a problem using the available syntax in JuMP, it's probably a sign that you should convert your data into a different form.

    Next steps

    The purpose of this tutorial was to show how JuMP does not have specialized syntax for set creation and manipulation. Instead, you should use the tools provided by Julia itself.

    This is both an opportunity and a challenge, because you are free to pick the syntax and data structures that best suit your problem, but for new users it can be daunting to decide which structure to use.

    Read through some of the other JuMP tutorials to get inspiration and ideas for how you can use Julia's syntax and data structures to your advantage.

    +@objective(model, Min, sum(v * x[k] for (k, v) in routes))

    \[ 643 x_{("Auckland", "Wellington")} + 436 x_{("Wellington", "Christchurch")} + 790 x_{("Wellington", "Dunedin")} + 360 x_{("Christchurch", "Dunedin")} + 1426 x_{("Auckland", "Dunedin")} + 1426 x_{("Dunedin", "Auckland")} + 1071 x_{("Auckland", "Christchurch")} \]

    This has a number of benefits over the other approaches, including a compacter algebraic model and variables that are named in a more meaningful way.

    Tip

    If you're struggling to formulate a problem using the available syntax in JuMP, it's probably a sign that you should convert your data into a different form.

    Next steps

    The purpose of this tutorial was to show how JuMP does not have specialized syntax for set creation and manipulation. Instead, you should use the tools provided by Julia itself.

    This is both an opportunity and a challenge, because you are free to pick the syntax and data structures that best suit your problem, but for new users it can be daunting to decide which structure to use.

    Read through some of the other JuMP tutorials to get inspiration and ideas for how you can use Julia's syntax and data structures to your advantage.

    diff --git a/previews/PR3883/tutorials/getting_started/introduction/index.html b/previews/PR3883/tutorials/getting_started/introduction/index.html index 4b2b3793672..f0aa8155b7c 100644 --- a/previews/PR3883/tutorials/getting_started/introduction/index.html +++ b/previews/PR3883/tutorials/getting_started/introduction/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-0RZ8X3D3D0', {'page_path': location.pathname + location.search + location.hash}); -

    Introduction

    The purpose of these "Getting started" tutorials is to teach new users the basics of Julia and JuMP.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    • The "Getting started with" tutorials are basic introductions to different aspects of JuMP and Julia. If you are new to JuMP and Julia, start by reading them in the following order:
    • Julia has a reputation for being "fast." Unfortunately, it is also easy to write slow Julia code. Performance tips contains a number of important tips on how to improve the performance of models you write in JuMP.
    • Design patterns for larger models is a more advanced tutorial that is aimed at users writing large JuMP models. It's in the "Getting started" section to give you an early preview of how JuMP makes it easy to structure larger models. If you are new to JuMP you may want to skip or briefly skim this tutorial, and come back to it once you have written a few JuMP models.
    +

    Introduction

    The purpose of these "Getting started" tutorials is to teach new users the basics of Julia and JuMP.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    • The "Getting started with" tutorials are basic introductions to different aspects of JuMP and Julia. If you are new to JuMP and Julia, start by reading them in the following order:
    • Julia has a reputation for being "fast." Unfortunately, it is also easy to write slow Julia code. Performance tips contains a number of important tips on how to improve the performance of models you write in JuMP.
    • Design patterns for larger models is a more advanced tutorial that is aimed at users writing large JuMP models. It's in the "Getting started" section to give you an early preview of how JuMP makes it easy to structure larger models. If you are new to JuMP you may want to skip or briefly skim this tutorial, and come back to it once you have written a few JuMP models.
    diff --git a/previews/PR3883/tutorials/getting_started/performance_tips/index.html b/previews/PR3883/tutorials/getting_started/performance_tips/index.html index c043d87c7dd..43dc39ae53d 100644 --- a/previews/PR3883/tutorials/getting_started/performance_tips/index.html +++ b/previews/PR3883/tutorials/getting_started/performance_tips/index.html @@ -37,4 +37,4 @@ └ Names registered in the model: none
    julia> @variable(model, x[1:3])3-element Vector{VariableRef}: x[1] x[2] - x[3]

    Here's what happens if we construct the expression outside the macro:

    julia> @allocated x[1] + x[2] + x[3]1232
    Info

    The @allocated measures how many bytes were allocated during the evaluation of an expression. Fewer is better.

    If we use the @expression macro, we get many fewer allocations:

    julia> @allocated @expression(model, x[1] + x[2] + x[3])672

    Disable string names

    By default, JuMP creates String names for variables and constraints and passes these to the solver. The benefit of passing names is that it improves the readability of log messages from the solver (for example, "variable x has invalid bounds" instead of "variable v1203 has invalid bounds"), but for larger models the overhead of passing names can be non-trivial.

    Disable the creation of String names by setting set_string_name = false in the @variable and @constraint macros, or by calling set_string_names_on_creation to disable all names for a particular model:

    julia> model = Model();
    julia> set_string_names_on_creation(model, false)
    julia> @variable(model, x)_[1]
    julia> @constraint(model, c, 2x <= 1)2 _[1] ≤ 1

    Note that this doesn't change how symbolic names and bindings are stored:

    julia> x_[1]
    julia> model[:x]_[1]
    julia> x === model[:x]true

    But you can no longer look up the variable by the string name:

    julia> variable_by_name(model, "x") === nothingtrue
    Info

    For more information on the difference between string names, symbolic names, and bindings, see String names, symbolic names, and bindings.

    + x[3]

    Here's what happens if we construct the expression outside the macro:

    julia> @allocated x[1] + x[2] + x[3]1232
    Info

    The @allocated measures how many bytes were allocated during the evaluation of an expression. Fewer is better.

    If we use the @expression macro, we get many fewer allocations:

    julia> @allocated @expression(model, x[1] + x[2] + x[3])672

    Disable string names

    By default, JuMP creates String names for variables and constraints and passes these to the solver. The benefit of passing names is that it improves the readability of log messages from the solver (for example, "variable x has invalid bounds" instead of "variable v1203 has invalid bounds"), but for larger models the overhead of passing names can be non-trivial.

    Disable the creation of String names by setting set_string_name = false in the @variable and @constraint macros, or by calling set_string_names_on_creation to disable all names for a particular model:

    julia> model = Model();
    julia> set_string_names_on_creation(model, false)
    julia> @variable(model, x)_[1]
    julia> @constraint(model, c, 2x <= 1)2 _[1] ≤ 1

    Note that this doesn't change how symbolic names and bindings are stored:

    julia> x_[1]
    julia> model[:x]_[1]
    julia> x === model[:x]true

    But you can no longer look up the variable by the string name:

    julia> variable_by_name(model, "x") === nothingtrue
    Info

    For more information on the difference between string names, symbolic names, and bindings, see String names, symbolic names, and bindings.

    diff --git a/previews/PR3883/tutorials/getting_started/sum_if/25f1d0dd.svg b/previews/PR3883/tutorials/getting_started/sum_if/2cf4c5ce.svg similarity index 51% rename from previews/PR3883/tutorials/getting_started/sum_if/25f1d0dd.svg rename to previews/PR3883/tutorials/getting_started/sum_if/2cf4c5ce.svg index 0a99796569a..2bde04d8d90 100644 --- a/previews/PR3883/tutorials/getting_started/sum_if/25f1d0dd.svg +++ b/previews/PR3883/tutorials/getting_started/sum_if/2cf4c5ce.svg @@ -1,55 +1,57 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/getting_started/sum_if/3e8eef6f.svg b/previews/PR3883/tutorials/getting_started/sum_if/3e8eef6f.svg deleted file mode 100644 index 862108e1c23..00000000000 --- a/previews/PR3883/tutorials/getting_started/sum_if/3e8eef6f.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/previews/PR3883/tutorials/getting_started/sum_if/a3ce4cb5.svg b/previews/PR3883/tutorials/getting_started/sum_if/a3ce4cb5.svg new file mode 100644 index 00000000000..043b7876214 --- /dev/null +++ b/previews/PR3883/tutorials/getting_started/sum_if/a3ce4cb5.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/getting_started/sum_if/index.html b/previews/PR3883/tutorials/getting_started/sum_if/index.html index ee02b6e92df..fbebae901a0 100644 --- a/previews/PR3883/tutorials/getting_started/sum_if/index.html +++ b/previews/PR3883/tutorials/getting_started/sum_if/index.html @@ -64,7 +64,7 @@ end nodes, edges, demand = build_random_graph(1_000, 2_000) -@elapsed build_naive_model(nodes, edges, demand)
    0.133838204

    A good way to benchmark is to measure the runtime across a wide range of input sizes. From our big-O analysis, we should expect that doubling the number of nodes and edges results in a 4x increase in the runtime.

    run_times = Float64[]
    +@elapsed build_naive_model(nodes, edges, demand)
    0.135362875

    A good way to benchmark is to measure the runtime across a wide range of input sizes. From our big-O analysis, we should expect that doubling the number of nodes and edges results in a 4x increase in the runtime.

    run_times = Float64[]
     factors = 1:10
     for factor in factors
         graph = build_random_graph(1_000 * factor, 5_000 * factor)
    @@ -73,7 +73,7 @@
     Plots.plot(; xlabel = "Factor", ylabel = "Runtime [s]")
     Plots.scatter!(factors, run_times; label = "Actual")
     a, b = hcat(ones(10), factors .^ 2) \ run_times
    -Plots.plot!(factors, a .+ b * factors .^ 2; label = "Quadratic fit")
    Example block output

    As expected, the runtimes demonstrate quadratic scaling: if we double the number of nodes and edges, the runtime increases by a factor of four.

    Caching

    We can improve our formulation by caching the list of incoming and outgoing nodes for each node n:

    out_nodes = Dict(n => Int[] for n in nodes)
    +Plots.plot!(factors, a .+ b * factors .^ 2; label = "Quadratic fit")
    Example block output

    As expected, the runtimes demonstrate quadratic scaling: if we double the number of nodes and edges, the runtime increases by a factor of four.

    Caching

    We can improve our formulation by caching the list of incoming and outgoing nodes for each node n:

    out_nodes = Dict(n => Int[] for n in nodes)
     in_nodes = Dict(n => Int[] for n in nodes)
     for (i, j) in edges
         push!(out_nodes[i], j)
    @@ -104,7 +104,7 @@
     end
     
     nodes, edges, demand = build_random_graph(1_000, 2_000)
    -@elapsed build_cached_model(nodes, edges, demand)
    0.183035548

    Analysis

    Now we can analyse the difference in runtime of the two formulations:

    run_times_naive = Float64[]
    +@elapsed build_cached_model(nodes, edges, demand)
    0.173878319

    Analysis

    Now we can analyse the difference in runtime of the two formulations:

    run_times_naive = Float64[]
     run_times_cached = Float64[]
     factors = 1:10
     for factor in factors
    @@ -118,4 +118,4 @@
     Plots.plot!(factors, a .+ b * factors .^ 2; label = "Quadratic fit")
     Plots.scatter!(factors, run_times_cached; label = "Cached")
     a, b = hcat(ones(10), factors) \ run_times_cached
    -Plots.plot!(factors, a .+ b * factors; label = "Linear fit")
    Example block output

    Even though the cached model needs to build in_nodes and out_nodes, it is asymptotically faster than the naïve model, scaling linearly with factor rather than quadratically.

    Lesson

    If you write code with sum-if type conditions, for example, @constraint(model, [a in set], sum(x[b] for b in list if condition(a, b)), you can improve the performance by caching the elements for which condition(a, b) is true.

    Finally, you should understand that this behavior is not specific to JuMP, and that it applies more generally to all computer programs you might write. (Python programs that use Pyomo or gurobipy would similarly benefit from this caching approach.)

    Understanding big-O notation and algorithmic complexity is a useful debugging skill to have, regardless of the type of program that you are writing.

    +Plots.plot!(factors, a .+ b * factors; label = "Linear fit")Example block output

    Even though the cached model needs to build in_nodes and out_nodes, it is asymptotically faster than the naïve model, scaling linearly with factor rather than quadratically.

    Lesson

    If you write code with sum-if type conditions, for example, @constraint(model, [a in set], sum(x[b] for b in list if condition(a, b)), you can improve the performance by caching the elements for which condition(a, b) is true.

    Finally, you should understand that this behavior is not specific to JuMP, and that it applies more generally to all computer programs you might write. (Python programs that use Pyomo or gurobipy would similarly benefit from this caching approach.)

    Understanding big-O notation and algorithmic complexity is a useful debugging skill to have, regardless of the type of program that you are writing.

    diff --git a/previews/PR3883/tutorials/getting_started/tolerances/index.html b/previews/PR3883/tutorials/getting_started/tolerances/index.html index 9e5d8d8aa42..1c6646acaa1 100644 --- a/previews/PR3883/tutorials/getting_started/tolerances/index.html +++ b/previews/PR3883/tutorials/getting_started/tolerances/index.html @@ -37,34 +37,34 @@ ------------------------------------------------------------------ iter | pri res | dua res | gap | obj | scale | time (s) ------------------------------------------------------------------ - 0| 2.00e+01 1.00e+00 2.00e+01 -9.98e+00 1.00e-01 3.45e-02 - 100| 6.92e-05 7.92e-05 7.33e-06 2.41e-05 1.00e-01 9.26e-02 + 0| 2.00e+01 1.00e+00 2.00e+01 -9.98e+00 1.00e-01 3.37e-02 + 100| 6.92e-05 7.92e-05 7.33e-06 2.41e-05 1.00e-01 9.14e-02 ------------------------------------------------------------------ status: solved -timings: total: 9.27e-02s = setup: 3.33e-02s + solve: 5.93e-02s - lin-sys: 4.98e-02s, cones: 2.15e-03s, accel: 8.16e-04s +timings: total: 9.15e-02s = setup: 3.26e-02s + solve: 5.89e-02s + lin-sys: 4.98e-02s, cones: 2.12e-03s, accel: 7.45e-04s ------------------------------------------------------------------ objective = 0.000024 ------------------------------------------------------------------

    SCS reports that it solved the problem to optimality:

    is_solved_and_feasible(model)
    true

    and that the solution for x[1] is nearly zero:

    value(x[1])
    2.04406873858532e-5

    However, the analytic solution for x[1] is:

    1 - n * ε / 2
    0.8479

    The answer is very wrong, and there is no indication from the solver that anything untoward happened. What's going on?

    One useful debugging tool is primal_feasibility_report:

    report = primal_feasibility_report(model)
    Dict{Any, Float64} with 8192 entries:
    -  x[7514] ≥ 0 => 2.01984e-5
    -  x[3864] ≥ 0 => 2.01984e-5
    -  x[1339] ≥ 0 => 1.71395e-5
    -  x[1266] ≥ 0 => 1.71395e-5
    -  x[2930] ≥ 0 => 1.8669e-5
    -  x[6859] ≥ 0 => 1.8669e-5
    -  x[2536] ≥ 0 => 2.01984e-5
    -  x[7910] ≥ 0 => 2.17278e-5
    -  x[5567] ≥ 0 => 2.17278e-5
    -  x[402] ≥ 0  => 1.40807e-5
    -  x[3996] ≥ 0 => 2.17278e-5
    -  x[6735] ≥ 0 => 1.8669e-5
    -  x[2034] ≥ 0 => 2.01984e-5
    -  x[4328] ≥ 0 => 1.8669e-5
    -  x[5151] ≥ 0 => 1.71395e-5
    -  x[2508] ≥ 0 => 1.8669e-5
    -  x[7643] ≥ 0 => 2.17278e-5
    -  x[3849] ≥ 0 => 1.56101e-5
    -  x[7576] ≥ 0 => 2.17278e-5
    +  x[1937] ≥ 0 => 1.56101e-5
    +  x[4665] ≥ 0 => 1.56101e-5
    +  x[1510] ≥ 0 => 1.8669e-5
    +  x[1942] ≥ 0 => 1.8669e-5
    +  x[5222] ≥ 0 => 1.71395e-5
    +  x[1622] ≥ 0 => 1.71395e-5
    +  x[2995] ≥ 0 => 1.8669e-5
    +  x[4153] ≥ 0 => 1.40807e-5
    +  x[7437] ≥ 0 => 1.71395e-5
    +  x[5072] ≥ 0 => 2.17278e-5
    +  x[7699] ≥ 0 => 1.71395e-5
    +  x[2316] ≥ 0 => 1.56101e-5
    +  x[6526] ≥ 0 => 2.17278e-5
    +  x[7207] ≥ 0 => 1.71395e-5
    +  x[7996] ≥ 0 => 2.32572e-5
    +  x[4856] ≥ 0 => 2.17278e-5
    +  x[3140] ≥ 0 => 1.56101e-5
    +  x[1221] ≥ 0 => 1.40807e-5
    +  x[6025] ≥ 0 => 1.71395e-5
       ⋮           => ⋮

    report is a dictionary which maps constraints to the violation. The largest violation is approximately 1e-5:

    maximum(values(report))
    6.92133754155444e-5

    This makes sense, because the default primal feasibility tolerance for SCS is 1e-4.

    Most of the entries are lower bound constraints on the variables. Here are all the variables which violate their lower bound:

    violated_variables = filter(xi -> value(xi) < 0, x)
    8178-element Vector{VariableRef}:
      x[4]
      x[6]
    @@ -104,14 +104,14 @@
     ------------------------------------------------------------------
      iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
     ------------------------------------------------------------------
    -     0| 2.00e+01  1.00e+00  2.00e+01 -9.98e+00  1.00e-01  3.35e-02
    -   250| 2.01e-02  2.85e-04  2.00e-02  3.01e-02  3.86e-01  1.82e-01
    -   500| 3.69e-04  5.93e-04  8.84e-05  8.48e-01  6.13e-01  3.33e-01
    -   550| 2.66e-06  6.58e-10  1.27e-05  8.48e-01  6.13e-01  3.63e-01
    +     0| 2.00e+01  1.00e+00  2.00e+01 -9.98e+00  1.00e-01  3.28e-02
    +   250| 2.01e-02  2.85e-04  2.00e-02  3.01e-02  3.86e-01  2.09e-01
    +   500| 3.69e-04  5.93e-04  8.84e-05  8.48e-01  6.13e-01  3.60e-01
    +   550| 2.66e-06  6.58e-10  1.27e-05  8.48e-01  6.13e-01  3.90e-01
     ------------------------------------------------------------------
     status:  solved
    -timings: total: 3.63e-01s = setup: 3.23e-02s + solve: 3.31e-01s
    -	 lin-sys: 2.70e-01s, cones: 1.15e-02s, accel: 6.57e-03s
    +timings: total: 3.90e-01s = setup: 3.17e-02s + solve: 3.58e-01s
    +	 lin-sys: 2.71e-01s, cones: 1.16e-02s, accel: 6.40e-03s
     ------------------------------------------------------------------
     objective = 0.847906
     ------------------------------------------------------------------
    @assert is_solved_and_feasible(model)
    @@ -166,4 +166,4 @@
     @variable(model, 0 <= x_capacity_MW <= 10^3)
     @constraint(model, 1.78e6 * x_capacity_MW <= 200e6)

    \[ 1780000 x\_capacity\_MW \leq 200000000 \]

    We can improve our model further by dividing the constraint by $10^6$ to change the units from dollars to million dollars.

    model = Model()
     @variable(model, 0 <= x_capacity_MW <= 10^3)
    -@constraint(model, 1.78 * x_capacity_MW <= 200)

    \[ 1.78 x\_capacity\_MW \leq 200 \]

    This problem is equivalent to the original problem, but it has much better problem scaling.

    As a general rule, to fix problem scaling you must simultaneously scale both variables and constraints. It is usually not sufficient to scale variables or constraints in isolation.

    +@constraint(model, 1.78 * x_capacity_MW <= 200)

    \[ 1.78 x\_capacity\_MW \leq 200 \]

    This problem is equivalent to the original problem, but it has much better problem scaling.

    As a general rule, to fix problem scaling you must simultaneously scale both variables and constraints. It is usually not sufficient to scale variables or constraints in isolation.

    diff --git a/previews/PR3883/tutorials/linear/basis/index.html b/previews/PR3883/tutorials/linear/basis/index.html index 24ac2e98085..0ec8b431408 100644 --- a/previews/PR3883/tutorials/linear/basis/index.html +++ b/previews/PR3883/tutorials/linear/basis/index.html @@ -60,9 +60,9 @@ ci => get_attribute(ci, MOI.ConstraintBasisStatus()) for ci in all_constraints(model; include_variable_in_set_constraints = false) )
    Dict{ConstraintRef{Model, C, ScalarShape} where C, MathOptInterface.BasisStatusCode} with 3 entries:
    -  c1 : 6 x + 8 y ≥ 100  => NONBASIC
       c2 : 7 x + 12 y ≥ 120 => NONBASIC
    -  c3 : x + y ≤ 20       => BASIC

    Thus, the basis is formed by x, y, and the slack associated with c3.

    A simple way to get the A matrix of an unstructured linear program is with lp_matrix_data:

    matrix = lp_matrix_data(model)
    +  c3 : x + y ≤ 20       => BASIC
    +  c1 : 6 x + 8 y ≥ 100  => NONBASIC

    Thus, the basis is formed by x, y, and the slack associated with c3.

    A simple way to get the A matrix of an unstructured linear program is with lp_matrix_data:

    matrix = lp_matrix_data(model)
     matrix.A
    3×3 SparseArrays.SparseMatrixCSC{Float64, Int64} with 6 stored entries:
      6.0   8.0   ⋅ 
      7.0  12.0   ⋅ 
    @@ -96,4 +96,4 @@
     @constraint(model, A * x == b)
     optimize!(model)
     degenerate_variables = filter(is_degenerate, all_variables(model))
    1-element Vector{VariableRef}:
    - x[1]

    The solution is degenerate because:

    value(x[1])
    -0.0

    and

    get_attribute(x[1], MOI.VariableBasisStatus())
    BASIC::BasisStatusCode = 0
    + x[1]

    The solution is degenerate because:

    value(x[1])
    -0.0

    and

    get_attribute(x[1], MOI.VariableBasisStatus())
    BASIC::BasisStatusCode = 0
    diff --git a/previews/PR3883/tutorials/linear/callbacks/index.html b/previews/PR3883/tutorials/linear/callbacks/index.html index 2c613dcdf32..a4d4a4dd963 100644 --- a/previews/PR3883/tutorials/linear/callbacks/index.html +++ b/previews/PR3883/tutorials/linear/callbacks/index.html @@ -166,4 +166,4 @@ Adding ScalarConstraint{AffExpr, MathOptInterface.LessThan{Float64}}(y - x, MathOptInterface.LessThan{Float64}(1.0)) Called from reason = 7 Called from reason = 1 -Called from reason = 2 +Called from reason = 2 diff --git a/previews/PR3883/tutorials/linear/cannery/index.html b/previews/PR3883/tutorials/linear/cannery/index.html index c832f41db19..0a23ff450cb 100644 --- a/previews/PR3883/tutorials/linear/cannery/index.html +++ b/previews/PR3883/tutorials/linear/cannery/index.html @@ -76,7 +76,7 @@ Dual objective value : 1.68000e+03 * Work counters - Solve time (sec) : 2.03609e-04 + Solve time (sec) : 2.03371e-04 Simplex iterations : 3 Barrier iterations : 0 Node count : -1 @@ -88,4 +88,4 @@ Seattle => New-York: 0.0 San-Diego => Chicago: 0.0 San-Diego => Topeka: 300.0 -San-Diego => New-York: 300.0 +San-Diego => New-York: 300.0 diff --git a/previews/PR3883/tutorials/linear/constraint_programming/index.html b/previews/PR3883/tutorials/linear/constraint_programming/index.html index 9c6ad620fdc..78c8b8de86b 100644 --- a/previews/PR3883/tutorials/linear/constraint_programming/index.html +++ b/previews/PR3883/tutorials/linear/constraint_programming/index.html @@ -97,4 +97,4 @@ value.(x)
    3-element Vector{Float64}:
      1.0
      1.0
    - 0.0
    + 0.0 diff --git a/previews/PR3883/tutorials/linear/diet/index.html b/previews/PR3883/tutorials/linear/diet/index.html index 8fd0ae678bb..0da652d732e 100644 --- a/previews/PR3883/tutorials/linear/diet/index.html +++ b/previews/PR3883/tutorials/linear/diet/index.html @@ -11,7 +11,7 @@ \min & \sum\limits_{f \in F} c_f x_f \\ \text{s.t.}\ \ & l_m \le \sum\limits_{f \in F} a_{m,f} x_f \le u_m, && \forall m \in M \\ & x_f \ge 0, && \forall f \in F. -\end{aligned}\]

    In the rest of this tutorial, we will create and solve this problem in JuMP, and learn what we should cook for dinner.

    Data

    First, we need some data for the problem. For this tutorial, we'll write CSV files to a temporary directory from Julia. If you have existing files, you could change the filenames to point to them instead.

    dir = mktempdir()
    "/tmp/jl_OwyLPR"

    The first file is a list of foods with their macro-nutrient profile:

    food_csv_filename = joinpath(dir, "diet_foods.csv")
    +\end{aligned}\]

    In the rest of this tutorial, we will create and solve this problem in JuMP, and learn what we should cook for dinner.

    Data

    First, we need some data for the problem. For this tutorial, we'll write CSV files to a temporary directory from Julia. If you have existing files, you could change the filenames to point to them instead.

    dir = mktempdir()
    "/tmp/jl_ApaJL2"

    The first file is a list of foods with their macro-nutrient profile:

    food_csv_filename = joinpath(dir, "diet_foods.csv")
     open(food_csv_filename, "w") do io
         write(
             io,
    @@ -103,7 +103,7 @@
       Dual objective value : 1.18289e+01
     
     * Work counters
    -  Solve time (sec)   : 2.03133e-04
    +  Solve time (sec)   : 2.02894e-04
       Simplex iterations : 6
       Barrier iterations : 0
       Node count         : -1
    @@ -142,8 +142,8 @@
       Dual objective value : 3.56146e+00
     
     * Work counters
    -  Solve time (sec)   : 1.60456e-04
    +  Solve time (sec)   : 1.57595e-04
       Simplex iterations : 0
       Barrier iterations : 0
       Node count         : -1
    -

    There exists no feasible solution to our problem. Looks like we're stuck eating ice cream for dinner.

    Next steps

    • You can delete a constraint using delete(model, dairy_constraint). Can you add a different constraint to provide a diet with less dairy?
    • Some food items (like hamburgers) are discrete. You can use set_integer to force a variable to take integer values. What happens to the solution if you do?
    +

    There exists no feasible solution to our problem. Looks like we're stuck eating ice cream for dinner.

    Next steps

    • You can delete a constraint using delete(model, dairy_constraint). Can you add a different constraint to provide a diet with less dairy?
    • Some food items (like hamburgers) are discrete. You can use set_integer to force a variable to take integer values. What happens to the solution if you do?
    diff --git a/previews/PR3883/tutorials/linear/facility_location/5de62185.svg b/previews/PR3883/tutorials/linear/facility_location/0cee6d7b.svg similarity index 79% rename from previews/PR3883/tutorials/linear/facility_location/5de62185.svg rename to previews/PR3883/tutorials/linear/facility_location/0cee6d7b.svg index 450d37381d4..caf9a572a62 100644 --- a/previews/PR3883/tutorials/linear/facility_location/5de62185.svg +++ b/previews/PR3883/tutorials/linear/facility_location/0cee6d7b.svg @@ -1,69 +1,69 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/facility_location/5c23b133.svg b/previews/PR3883/tutorials/linear/facility_location/6ab085da.svg similarity index 80% rename from previews/PR3883/tutorials/linear/facility_location/5c23b133.svg rename to previews/PR3883/tutorials/linear/facility_location/6ab085da.svg index a59079abd57..de24699b7fa 100644 --- a/previews/PR3883/tutorials/linear/facility_location/5c23b133.svg +++ b/previews/PR3883/tutorials/linear/facility_location/6ab085da.svg @@ -1,57 +1,57 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/facility_location/9bde3a39.svg b/previews/PR3883/tutorials/linear/facility_location/9fe6d5ff.svg similarity index 81% rename from previews/PR3883/tutorials/linear/facility_location/9bde3a39.svg rename to previews/PR3883/tutorials/linear/facility_location/9fe6d5ff.svg index 28cfdc7340c..337254e1a98 100644 --- a/previews/PR3883/tutorials/linear/facility_location/9bde3a39.svg +++ b/previews/PR3883/tutorials/linear/facility_location/9fe6d5ff.svg @@ -1,61 +1,61 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/facility_location/e66d5c8c.svg b/previews/PR3883/tutorials/linear/facility_location/ddddcc2e.svg similarity index 79% rename from previews/PR3883/tutorials/linear/facility_location/e66d5c8c.svg rename to previews/PR3883/tutorials/linear/facility_location/ddddcc2e.svg index 3d1fa6d2b29..94329264a0a 100644 --- a/previews/PR3883/tutorials/linear/facility_location/e66d5c8c.svg +++ b/previews/PR3883/tutorials/linear/facility_location/ddddcc2e.svg @@ -1,69 +1,69 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/facility_location/index.html b/previews/PR3883/tutorials/linear/facility_location/index.html index 303188377ce..f4da7956027 100644 --- a/previews/PR3883/tutorials/linear/facility_location/index.html +++ b/previews/PR3883/tutorials/linear/facility_location/index.html @@ -51,7 +51,7 @@ markersize = 6, markerstrokecolor = :red, markerstrokewidth = 2, -)Example block output

    JuMP implementation

    Create a JuMP model

    model = Model(HiGHS.Optimizer)
    +)
    Example block output

    JuMP implementation

    Create a JuMP model

    model = Model(HiGHS.Optimizer)
     set_silent(model)
     @variable(model, y[1:n], Bin);
     @variable(model, x[1:m, 1:n], Bin);
    @@ -94,7 +94,7 @@
         end
     end
     
    -p
    Example block output

    Capacitated facility location

    Problem formulation

    The capacitated variant introduces a capacity constraint on each facility, that is, clients have a certain level of demand to be served, while each facility only has finite capacity which cannot be exceeded.

    Specifically,

    • The demand of client $i$ is denoted by $a_{i} \geq 0$
    • The capacity of facility $j$ is denoted by $q_{j} \geq 0$

    The capacity constraints then write

    \[\begin{aligned} +pExample block output

    Capacitated facility location

    Problem formulation

    The capacitated variant introduces a capacity constraint on each facility, that is, clients have a certain level of demand to be served, while each facility only has finite capacity which cannot be exceeded.

    Specifically,

    • The demand of client $i$ is denoted by $a_{i} \geq 0$
    • The capacity of facility $j$ is denoted by $q_{j} \geq 0$

    The capacity constraints then write

    \[\begin{aligned} \sum_{i} a_{i} x_{i, j} &\leq q_{j} y_{j} && \forall j \in N \end{aligned}\]

    Note that, if $y_{j}$ is set to $0$, the capacity constraint above automatically forces $x_{i, j}$ to $0$.

    Thus, the capacitated facility location can be formulated as follows

    \[\begin{aligned} \min_{x, y} \ \ \ & @@ -126,7 +126,7 @@ markersize = q, markerstrokecolor = :red, markerstrokewidth = 2, -)Example block output

    JuMP implementation

    Create a JuMP model

    model = Model(HiGHS.Optimizer)
    +)
    Example block output

    JuMP implementation

    Create a JuMP model

    model = Model(HiGHS.Optimizer)
     set_silent(model)
     @variable(model, y[1:n], Bin);
     @variable(model, x[1:m, 1:n], Bin);
    @@ -169,4 +169,4 @@
         end
     end
     
    -p
    Example block output +pExample block output diff --git a/previews/PR3883/tutorials/linear/factory_schedule/0debf07b.svg b/previews/PR3883/tutorials/linear/factory_schedule/92045306.svg similarity index 85% rename from previews/PR3883/tutorials/linear/factory_schedule/0debf07b.svg rename to previews/PR3883/tutorials/linear/factory_schedule/92045306.svg index ef161570885..d734d99a2e2 100644 --- a/previews/PR3883/tutorials/linear/factory_schedule/0debf07b.svg +++ b/previews/PR3883/tutorials/linear/factory_schedule/92045306.svg @@ -1,81 +1,81 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/factory_schedule/66e5af17.svg b/previews/PR3883/tutorials/linear/factory_schedule/a24accc9.svg similarity index 78% rename from previews/PR3883/tutorials/linear/factory_schedule/66e5af17.svg rename to previews/PR3883/tutorials/linear/factory_schedule/a24accc9.svg index 698a572bdfc..3da21e6b62a 100644 --- a/previews/PR3883/tutorials/linear/factory_schedule/66e5af17.svg +++ b/previews/PR3883/tutorials/linear/factory_schedule/a24accc9.svg @@ -1,162 +1,162 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/factory_schedule/da6c3496.svg b/previews/PR3883/tutorials/linear/factory_schedule/b191ac09.svg similarity index 78% rename from previews/PR3883/tutorials/linear/factory_schedule/da6c3496.svg rename to previews/PR3883/tutorials/linear/factory_schedule/b191ac09.svg index 4a1d77851c2..5f89c852e49 100644 --- a/previews/PR3883/tutorials/linear/factory_schedule/da6c3496.svg +++ b/previews/PR3883/tutorials/linear/factory_schedule/b191ac09.svg @@ -1,160 +1,160 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/factory_schedule/index.html b/previews/PR3883/tutorials/linear/factory_schedule/index.html index 9cf7153ff3c..4bfeccea6dc 100644 --- a/previews/PR3883/tutorials/linear/factory_schedule/index.html +++ b/previews/PR3883/tutorials/linear/factory_schedule/index.html @@ -126,7 +126,7 @@ ylabel = "Production", legend = :topleft, color = ["#20326c" "#4063d8" "#a0b1ec"], -)Example block output

    Note that we don't have any unmet demand.

    What happens if demand increases?

    Let's run an experiment by increasing the demand by 50% in all time periods:

    demand_df.demand .*= 1.5
    12-element Vector{Float64}:
    +)
    Example block output

    Note that we don't have any unmet demand.

    What happens if demand increases?

    Let's run an experiment by increasing the demand by 50% in all time periods:

    demand_df.demand .*= 1.5
    12-element Vector{Float64}:
      180000.0
      150000.0
      195000.0
    @@ -146,7 +146,7 @@
         ylabel = "Production",
         legend = :topleft,
         color = ["#20326c" "#4063d8" "#a0b1ec"],
    -)
    Example block output

    Uh oh, we can't satisfy all of the demand.

    How sensitive is the solution to changes in variable cost?

    Let's run another experiment, this time seeing how the optimal objective value changes as we vary the variable costs of each factory.

    First though, let's reset the demand to it's original level:

    demand_df.demand ./= 1.5;

    For our experiment, we're going to scale the variable costs of both factories by a set of values from 0.0 to 1.5:

    scale_factors = 0:0.1:1.5
    0.0:0.1:1.5

    At a high level, we're going to loop over the scale factors for A, then the scale factors for B, rescale the input data, call our solve_factory_scheduling example, and then store the optimal objective value in the following cost matrix:

    cost = zeros(length(scale_factors), length(scale_factors));

    Because we're modifying factory_df in-place, we need to store the original variable costs in a new column:

    factory_df[!, :old_variable_cost] = copy(factory_df.variable_cost);

    Then, we need a function to scale the :variable_cost column for a particular factory by a value scale:

    function scale_variable_cost(df, factory, scale)
    +)
    Example block output

    Uh oh, we can't satisfy all of the demand.

    How sensitive is the solution to changes in variable cost?

    Let's run another experiment, this time seeing how the optimal objective value changes as we vary the variable costs of each factory.

    First though, let's reset the demand to it's original level:

    demand_df.demand ./= 1.5;

    For our experiment, we're going to scale the variable costs of both factories by a set of values from 0.0 to 1.5:

    scale_factors = 0:0.1:1.5
    0.0:0.1:1.5

    At a high level, we're going to loop over the scale factors for A, then the scale factors for B, rescale the input data, call our solve_factory_scheduling example, and then store the optimal objective value in the following cost matrix:

    cost = zeros(length(scale_factors), length(scale_factors));

    Because we're modifying factory_df in-place, we need to store the original variable costs in a new column:

    factory_df[!, :old_variable_cost] = copy(factory_df.variable_cost);

    Then, we need a function to scale the :variable_cost column for a particular factory by a value scale:

    function scale_variable_cost(df, factory, scale)
         rows = df.factory .== factory
         df[rows, :variable_cost] .=
             round.(Int, df[rows, :old_variable_cost] .* scale)
    @@ -163,4 +163,4 @@
         cost;
         xlabel = "Scale of factory A",
         ylabel = "Scale of factory B",
    -)
    Example block output

    What can you infer from the solution?

    Info

    The Power Systems tutorial explains a number of other ways you can structure a problem to perform a parametric analysis of the solution. In particular, you can use in-place modification to reduce the time it takes to build and solve the resulting models.

    +)Example block output

    What can you infer from the solution?

    Info

    The Power Systems tutorial explains a number of other ways you can structure a problem to perform a parametric analysis of the solution. In particular, you can use in-place modification to reduce the time it takes to build and solve the resulting models.

    diff --git a/previews/PR3883/tutorials/linear/finance/index.html b/previews/PR3883/tutorials/linear/finance/index.html index 23de80089d5..63ce9f8ee16 100644 --- a/previews/PR3883/tutorials/linear/finance/index.html +++ b/previews/PR3883/tutorials/linear/finance/index.html @@ -50,4 +50,4 @@ 1.0 -0.0 -0.0 - 0.0 + 0.0 diff --git a/previews/PR3883/tutorials/linear/geographic_clustering/index.html b/previews/PR3883/tutorials/linear/geographic_clustering/index.html index 101131c9709..e28b6733bae 100644 --- a/previews/PR3883/tutorials/linear/geographic_clustering/index.html +++ b/previews/PR3883/tutorials/linear/geographic_clustering/index.html @@ -135,4 +135,4 @@ 5 │ San Francisco, CA 0.837 37.7749 -122.419 3.0 6 │ El Paso, TX 0.674 31.7775 -106.442 3.0 -sum(group.population) = 9.261000000000001 +sum(group.population) = 9.261000000000001 diff --git a/previews/PR3883/tutorials/linear/introduction/index.html b/previews/PR3883/tutorials/linear/introduction/index.html index 028a7476cc3..291499adb9c 100644 --- a/previews/PR3883/tutorials/linear/introduction/index.html +++ b/previews/PR3883/tutorials/linear/introduction/index.html @@ -7,4 +7,4 @@ \min_{x \in \mathbb{R}^n} & \sum\limits_{i=1}^n c_i x_i \\ \;\;\text{s.t.} & l_j \le \sum\limits_{i=1}^n a_{ij} x_i \le u_j & j = 1 \ldots m \\ & l_i \le x_i \le u_i & i = 1 \ldots n. -\end{align}\]

    The most important thing to note is that all terms are of the form coefficient * variable, and that there are no nonlinear terms or multiplications between variables.

    Mixed-integer linear programs (MILPs) are extensions of linear programs in which some (or all) of the decision variables take discrete values.

    How to choose a solver

    Almost all solvers support linear programs; look for "LP" in the list of Supported solvers. However, fewer solvers support mixed-integer linear programs. Solvers supporting discrete variables start with "(MI)" in the list of Supported solvers.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    • The following tutorials are worked examples that present a problem in words, then formulate it in mathematics, and then solve it in JuMP. This usually involves some sort of visualization of the solution. Start here if you are new to JuMP.
    • The Tips and tricks tutorial contains a number of helpful reformulations and tricks you can use when modeling linear programs. Look here if you are stuck trying to formulate a problem as a linear program.
    • The Sensitivity analysis of a linear program tutorial explains how to create sensitivity reports like those produced by the Excel Solver.
    • The Callbacks tutorial explains how to write a variety of solver-independent callbacks. Look here if you want to write a callback.
    • The remaining tutorials are less verbose and styled in the form of short code examples. These tutorials have less explanation, but may contain useful code snippets, particularly if they are similar to a problem you are trying to solve.
    +\end{align}\]

    The most important thing to note is that all terms are of the form coefficient * variable, and that there are no nonlinear terms or multiplications between variables.

    Mixed-integer linear programs (MILPs) are extensions of linear programs in which some (or all) of the decision variables take discrete values.

    How to choose a solver

    Almost all solvers support linear programs; look for "LP" in the list of Supported solvers. However, fewer solvers support mixed-integer linear programs. Solvers supporting discrete variables start with "(MI)" in the list of Supported solvers.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    • The following tutorials are worked examples that present a problem in words, then formulate it in mathematics, and then solve it in JuMP. This usually involves some sort of visualization of the solution. Start here if you are new to JuMP.
    • The Tips and tricks tutorial contains a number of helpful reformulations and tricks you can use when modeling linear programs. Look here if you are stuck trying to formulate a problem as a linear program.
    • The Sensitivity analysis of a linear program tutorial explains how to create sensitivity reports like those produced by the Excel Solver.
    • The Callbacks tutorial explains how to write a variety of solver-independent callbacks. Look here if you want to write a callback.
    • The remaining tutorials are less verbose and styled in the form of short code examples. These tutorials have less explanation, but may contain useful code snippets, particularly if they are similar to a problem you are trying to solve.
    diff --git a/previews/PR3883/tutorials/linear/knapsack/index.html b/previews/PR3883/tutorials/linear/knapsack/index.html index 06d1be2af52..658776ddc9e 100644 --- a/previews/PR3883/tutorials/linear/knapsack/index.html +++ b/previews/PR3883/tutorials/linear/knapsack/index.html @@ -49,7 +49,7 @@ Dual objective value : NaN * Work counters - Solve time (sec) : 6.40631e-04 + Solve time (sec) : 5.87463e-04 Simplex iterations : 1 Barrier iterations : -1 Node count : 1 @@ -84,4 +84,4 @@ solve_knapsack_problem(; profit = profit, weight = weight, capacity = capacity)
    3-element Vector{Int64}:
      1
      4
    - 5

    We observe that the chosen items (1, 4, and 5) have the best profit to weight ratio in this particular example.

    Next steps

    Here are some things to try next:

    • Call the function with different data. What happens as the capacity increases?
    • What happens if the profit and weight vectors are different lengths?
    • Instead of creating a binary variable with Bin, we could have written @variable(model, 0 <= x[1:n] <= 1, Int). Verify that this formulation finds the same solution. What happens if we are allowed to take more than one of each item?
    + 5

    We observe that the chosen items (1, 4, and 5) have the best profit to weight ratio in this particular example.

    Next steps

    Here are some things to try next:

    • Call the function with different data. What happens as the capacity increases?
    • What happens if the profit and weight vectors are different lengths?
    • Instead of creating a binary variable with Bin, we could have written @variable(model, 0 <= x[1:n] <= 1, Int). Verify that this formulation finds the same solution. What happens if we are allowed to take more than one of each item?
    diff --git a/previews/PR3883/tutorials/linear/lp_sensitivity/index.html b/previews/PR3883/tutorials/linear/lp_sensitivity/index.html index 5f12d92d036..b1d30555559 100644 --- a/previews/PR3883/tutorials/linear/lp_sensitivity/index.html +++ b/previews/PR3883/tutorials/linear/lp_sensitivity/index.html @@ -40,11 +40,11 @@ c3 : 0.00000e+00 * Work counters - Solve time (sec) : 2.43187e-04 + Solve time (sec) : 2.57730e-04 Simplex iterations : 2 Barrier iterations : 0 Node count : -1 -

    Can you identify:

    • The objective coefficient of each variable?
    • The right-hand side of each constraint?
    • The optimal primal and dual solutions?

    Sensitivity reports

    Now let's call lp_sensitivity_report:

    report = lp_sensitivity_report(model)
    SensitivityReport{Float64}(Dict{ConstraintRef, Tuple{Float64, Float64}}(c1 : 6 x + 8 y ≥ 100 => (-4.0, 2.857142857142857), c2 : 7 x + 12 y ≥ 120 => (-3.3333333333333335, 4.666666666666667), y ≥ 0 => (-Inf, 1.25), z ≤ 1 => (-Inf, Inf), x ≥ 0 => (-Inf, 15.0), y ≤ 3 => (-1.75, Inf), c3 : x + y ≤ 20 => (-3.75, Inf)), Dict{VariableRef, Tuple{Float64, Float64}}(y => (-4.0, 0.5714285714285714), x => (-0.3333333333333333, 3.0), z => (-Inf, 1.0)))

    It returns a SensitivityReport object, which maps:

    • Every variable reference to a tuple (d_lo, d_hi)::Tuple{Float64,Float64}, explaining how much the objective coefficient of the corresponding variable can change by, such that the original basis remains optimal.
    • Every constraint reference to a tuple (d_lo, d_hi)::Tuple{Float64,Float64}, explaining how much the right-hand side of the corresponding constraint can change by, such that the basis remains optimal.

    Both tuples are relative, rather than absolute. So, given an objective coefficient of 1.0 and a tuple (-0.5, 0.5), the objective coefficient can range between 1.0 - 0.5 an 1.0 + 0.5.

    For example:

    report[x]
    (-0.3333333333333333, 3.0)

    indicates that the objective coefficient on x, that is, 12, can decrease by -0.333 or increase by 3.0 and the primal solution (15, 1.25) will remain optimal. In addition:

    report[c1]
    (-4.0, 2.857142857142857)

    means that the right-hand side of the c1 constraint (100), can decrease by 4 units, or increase by 2.85 units, and the primal solution (15, 1.25) will remain optimal.

    Variable sensitivity

    By themselves, the tuples aren't informative. Let's put them in context by collating a range of other information about a variable:

    function variable_report(xi)
    +

    Can you identify:

    • The objective coefficient of each variable?
    • The right-hand side of each constraint?
    • The optimal primal and dual solutions?

    Sensitivity reports

    Now let's call lp_sensitivity_report:

    report = lp_sensitivity_report(model)
    SensitivityReport{Float64}(Dict{ConstraintRef, Tuple{Float64, Float64}}(c1 : 6 x + 8 y ≥ 100 => (-4.0, 2.857142857142857), x ≥ 0 => (-Inf, 15.0), z ≤ 1 => (-Inf, Inf), y ≥ 0 => (-Inf, 1.25), c3 : x + y ≤ 20 => (-3.75, Inf), c2 : 7 x + 12 y ≥ 120 => (-3.3333333333333335, 4.666666666666667), y ≤ 3 => (-1.75, Inf)), Dict{VariableRef, Tuple{Float64, Float64}}(y => (-4.0, 0.5714285714285714), x => (-0.3333333333333333, 3.0), z => (-Inf, 1.0)))

    It returns a SensitivityReport object, which maps:

    • Every variable reference to a tuple (d_lo, d_hi)::Tuple{Float64,Float64}, explaining how much the objective coefficient of the corresponding variable can change by, such that the original basis remains optimal.
    • Every constraint reference to a tuple (d_lo, d_hi)::Tuple{Float64,Float64}, explaining how much the right-hand side of the corresponding constraint can change by, such that the basis remains optimal.

    Both tuples are relative, rather than absolute. So, given an objective coefficient of 1.0 and a tuple (-0.5, 0.5), the objective coefficient can range between 1.0 - 0.5 an 1.0 + 0.5.

    For example:

    report[x]
    (-0.3333333333333333, 3.0)

    indicates that the objective coefficient on x, that is, 12, can decrease by -0.333 or increase by 3.0 and the primal solution (15, 1.25) will remain optimal. In addition:

    report[c1]
    (-4.0, 2.857142857142857)

    means that the right-hand side of the c1 constraint (100), can decrease by 4 units, or increase by 2.85 units, and the primal solution (15, 1.25) will remain optimal.

    Variable sensitivity

    By themselves, the tuples aren't informative. Let's put them in context by collating a range of other information about a variable:

    function variable_report(xi)
         return (
             name = name(xi),
             lower_bound = has_lower_bound(xi) ? lower_bound(xi) : -Inf,
    @@ -71,4 +71,4 @@
     c1_report = constraint_report(c1)
    (name = "c1", value = 100.0, rhs = 100.0, slack = 0.0, shadow_price = -0.25, allowed_decrease = -4.0, allowed_increase = 2.857142857142857)

    That's a bit hard to read, so let's call this on every variable in the model and put things into a DataFrame:

    constraint_df = DataFrames.DataFrame(
         constraint_report(ci) for (F, S) in list_of_constraint_types(model) for
         ci in all_constraints(model, F, S) if F == AffExpr
    -)
    3×7 DataFrame
    Rownamevaluerhsslackshadow_priceallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64
    1c1100.0100.00.0-0.25-4.02.85714
    2c2120.0120.00.0-1.5-3.333334.66667
    3c316.2520.03.750.0-3.75Inf

    Analysis questions

    Now we can use these dataframes to ask questions of the solution.

    For example, we can find basic variables by looking for variables with a reduced cost of 0:

    basic = filter(row -> iszero(row.reduced_cost), variable_df)
    2×8 DataFrame
    Rownamelower_boundvalueupper_boundreduced_costobj_coefficientallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64Float64
    1x0.015.0Inf0.012.0-0.3333333.0
    2y0.01.253.00.020.0-4.00.571429

    and non-basic variables by looking for non-zero reduced costs:

    non_basic = filter(row -> !iszero(row.reduced_cost), variable_df)
    1×8 DataFrame
    Rownamelower_boundvalueupper_boundreduced_costobj_coefficientallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64Float64
    1z-Inf1.01.0-1.0-1.0-Inf1.0

    we can also find constraints that are binding by looking for zero slacks:

    binding = filter(row -> iszero(row.slack), constraint_df)
    2×7 DataFrame
    Rownamevaluerhsslackshadow_priceallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64
    1c1100.0100.00.0-0.25-4.02.85714
    2c2120.0120.00.0-1.5-3.333334.66667

    or non-zero shadow prices:

    binding2 = filter(row -> !iszero(row.shadow_price), constraint_df)
    2×7 DataFrame
    Rownamevaluerhsslackshadow_priceallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64
    1c1100.0100.00.0-0.25-4.02.85714
    2c2120.0120.00.0-1.5-3.333334.66667
    +)
    3×7 DataFrame
    Rownamevaluerhsslackshadow_priceallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64
    1c1100.0100.00.0-0.25-4.02.85714
    2c2120.0120.00.0-1.5-3.333334.66667
    3c316.2520.03.750.0-3.75Inf

    Analysis questions

    Now we can use these dataframes to ask questions of the solution.

    For example, we can find basic variables by looking for variables with a reduced cost of 0:

    basic = filter(row -> iszero(row.reduced_cost), variable_df)
    2×8 DataFrame
    Rownamelower_boundvalueupper_boundreduced_costobj_coefficientallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64Float64
    1x0.015.0Inf0.012.0-0.3333333.0
    2y0.01.253.00.020.0-4.00.571429

    and non-basic variables by looking for non-zero reduced costs:

    non_basic = filter(row -> !iszero(row.reduced_cost), variable_df)
    1×8 DataFrame
    Rownamelower_boundvalueupper_boundreduced_costobj_coefficientallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64Float64
    1z-Inf1.01.0-1.0-1.0-Inf1.0

    we can also find constraints that are binding by looking for zero slacks:

    binding = filter(row -> iszero(row.slack), constraint_df)
    2×7 DataFrame
    Rownamevaluerhsslackshadow_priceallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64
    1c1100.0100.00.0-0.25-4.02.85714
    2c2120.0120.00.0-1.5-3.333334.66667

    or non-zero shadow prices:

    binding2 = filter(row -> !iszero(row.shadow_price), constraint_df)
    2×7 DataFrame
    Rownamevaluerhsslackshadow_priceallowed_decreaseallowed_increase
    StringFloat64Float64Float64Float64Float64Float64
    1c1100.0100.00.0-0.25-4.02.85714
    2c2120.0120.00.0-1.5-3.333334.66667
    diff --git a/previews/PR3883/tutorials/linear/mip_duality/index.html b/previews/PR3883/tutorials/linear/mip_duality/index.html index b59e2f1cb75..97bebaea13a 100644 --- a/previews/PR3883/tutorials/linear/mip_duality/index.html +++ b/previews/PR3883/tutorials/linear/mip_duality/index.html @@ -113,4 +113,4 @@ g[2] ≤ 1000 w ≤ 200 dispatch[1] binary - dispatch[2] binary + dispatch[2] binary diff --git a/previews/PR3883/tutorials/linear/multi/index.html b/previews/PR3883/tutorials/linear/multi/index.html index 0eb6f6f15e3..e1a91fea5a8 100644 --- a/previews/PR3883/tutorials/linear/multi/index.html +++ b/previews/PR3883/tutorials/linear/multi/index.html @@ -118,7 +118,7 @@ INNER JOIN locations b ON a.type = 'origin' AND b.type = 'destination' """, -)
    SQLite.Query{false}(SQLite.Stmt(SQLite.DB("/home/runner/work/JuMP.jl/JuMP.jl/docs/build/tutorials/linear/multi.sqlite"), Base.RefValue{Ptr{SQLite.C.sqlite3_stmt}}(Ptr{SQLite.C.sqlite3_stmt} @0x0000000048689b88), Dict{Int64, Any}()), Base.RefValue{Int32}(100), [:origin, :destination], Type[Union{Missing, String}, Union{Missing, String}], Dict(:origin => 1, :destination => 2), Base.RefValue{Int64}(0))

    With a constraint that we cannot send more than 625 units between each pair:

    for r in Tables.rows(od_pairs)
    +)
    SQLite.Query{false}(SQLite.Stmt(SQLite.DB("/home/runner/work/JuMP.jl/JuMP.jl/docs/build/tutorials/linear/multi.sqlite"), Base.RefValue{Ptr{SQLite.C.sqlite3_stmt}}(Ptr{SQLite.C.sqlite3_stmt} @0x000000001da5d918), Dict{Int64, Any}()), Base.RefValue{Int32}(100), [:origin, :destination], Type[Union{Missing, String}, Union{Missing, String}], Dict(:origin => 1, :destination => 2), Base.RefValue{Int64}(0))

    With a constraint that we cannot send more than 625 units between each pair:

    for r in Tables.rows(od_pairs)
         @constraint(model, sum(x[r.origin, r.destination, :]) <= 625)
     end

    Solution

    Finally, we can optimize the model:

    optimize!(model)
     Test.@test is_solved_and_feasible(model)
    @@ -139,7 +139,7 @@
       Dual objective value : 2.25700e+05
     
     * Work counters
    -  Solve time (sec)   : 6.66380e-04
    +  Solve time (sec)   : 6.65426e-04
       Simplex iterations : 54
       Barrier iterations : 0
       Node count         : -1
    @@ -170,4 +170,4 @@
     PITT WIN    75   250    .
     PITT STL   400    25   200
     PITT FRE    .    450   100
    -PITT LAF   250   125    .
    +PITT LAF 250 125 . diff --git a/previews/PR3883/tutorials/linear/multi_commodity_network/index.html b/previews/PR3883/tutorials/linear/multi_commodity_network/index.html index 36a5f08af9b..298f018e93a 100644 --- a/previews/PR3883/tutorials/linear/multi_commodity_network/index.html +++ b/previews/PR3883/tutorials/linear/multi_commodity_network/index.html @@ -87,7 +87,7 @@ Dual objective value : 1.43228e+02 * Work counters - Solve time (sec) : 3.55721e-04 + Solve time (sec) : 3.24249e-04 Simplex iterations : 8 Barrier iterations : 0 Node count : -1 @@ -95,4 +95,4 @@ df_supply.x_supply = value.(df_supply.x_supply);

    and display the optimal solution for flows:

    DataFrames.select(
         filter!(row -> row.x_flow > 0.0, df_shipping),
         [:origin, :destination, :product, :x_flow],
    -)
    9×4 DataFrame
    Roworigindestinationproductx_flow
    StringStringStringFloat64
    1waikatoaucklandmilk10.0
    2waikatowellingtonmilk2.0
    3taurangaaucklandmilk2.0
    4taurangawaikatomilk2.0
    5christchurchaucklandmilk4.0
    6aucklandchristchurchkiwifruit4.0
    7waikatoaucklandkiwifruit20.0
    8waikatowellingtonkiwifruit2.0
    9taurangawaikatokiwifruit22.0
    +)
    9×4 DataFrame
    Roworigindestinationproductx_flow
    StringStringStringFloat64
    1waikatoaucklandmilk10.0
    2waikatowellingtonmilk2.0
    3taurangaaucklandmilk2.0
    4taurangawaikatomilk2.0
    5christchurchaucklandmilk4.0
    6aucklandchristchurchkiwifruit4.0
    7waikatoaucklandkiwifruit20.0
    8waikatowellingtonkiwifruit2.0
    9taurangawaikatokiwifruit22.0
    diff --git a/previews/PR3883/tutorials/linear/multi_objective_examples/index.html b/previews/PR3883/tutorials/linear/multi_objective_examples/index.html index 5c040fddf81..fab512ea5c7 100644 --- a/previews/PR3883/tutorials/linear/multi_objective_examples/index.html +++ b/previews/PR3883/tutorials/linear/multi_objective_examples/index.html @@ -29,7 +29,7 @@ Objective bound : [0.00000e+00,-9.00000e+00] * Work counters - Solve time (sec) : 1.24788e-03 + Solve time (sec) : 1.15585e-03
    for i in 1:result_count(model)
         @assert is_solved_and_feasible(model; result = i)
         print(i, ": z = ", round.(Int, objective_value(model; result = i)), " | ")
    @@ -62,7 +62,7 @@
       Objective bound    : [6.00000e+00,7.00000e+00]
     
     * Work counters
    -  Solve time (sec)   : 7.71403e-03
    +  Solve time (sec)   : 7.40194e-03
     
    for i in 1:result_count(model)
         @assert is_solved_and_feasible(model; result = i)
         print(i, ": z = ", round.(Int, objective_value(model; result = i)), " | ")
    @@ -115,7 +115,7 @@
       Objective bound    : [8.00000e+00,4.00000e+00]
     
     * Work counters
    -  Solve time (sec)   : 5.27501e-03
    +  Solve time (sec)   : 5.33414e-03
     
    for i in 1:result_count(model)
         @assert is_solved_and_feasible(model; result = i)
         print(i, ": z = ", round.(Int, objective_value(model; result = i)), " | ")
    @@ -129,4 +129,4 @@
     end
    1: z = [8, 9] | Path: 1->2 2->4 4->6
     2: z = [10, 7] | Path: 1->2 2->5 5->6
     3: z = [11, 5] | Path: 1->2 2->6
    -4: z = [13, 4] | Path: 1->3 3->4 4->6
    +4: z = [13, 4] | Path: 1->3 3->4 4->6 diff --git a/previews/PR3883/tutorials/linear/multi_objective_knapsack/03994a8f.svg b/previews/PR3883/tutorials/linear/multi_objective_knapsack/507cefa3.svg similarity index 83% rename from previews/PR3883/tutorials/linear/multi_objective_knapsack/03994a8f.svg rename to previews/PR3883/tutorials/linear/multi_objective_knapsack/507cefa3.svg index e2701f5ef3f..1a677ae92a5 100644 --- a/previews/PR3883/tutorials/linear/multi_objective_knapsack/03994a8f.svg +++ b/previews/PR3883/tutorials/linear/multi_objective_knapsack/507cefa3.svg @@ -1,55 +1,55 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/multi_objective_knapsack/45db6708.svg b/previews/PR3883/tutorials/linear/multi_objective_knapsack/81966ccb.svg similarity index 87% rename from previews/PR3883/tutorials/linear/multi_objective_knapsack/45db6708.svg rename to previews/PR3883/tutorials/linear/multi_objective_knapsack/81966ccb.svg index 9b15ffb0f9d..52e6b433f48 100644 --- a/previews/PR3883/tutorials/linear/multi_objective_knapsack/45db6708.svg +++ b/previews/PR3883/tutorials/linear/multi_objective_knapsack/81966ccb.svg @@ -1,53 +1,53 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/multi_objective_knapsack/index.html b/previews/PR3883/tutorials/linear/multi_objective_knapsack/index.html index d54de299ad5..e745cf23c2c 100644 --- a/previews/PR3883/tutorials/linear/multi_objective_knapsack/index.html +++ b/previews/PR3883/tutorials/linear/multi_objective_knapsack/index.html @@ -25,7 +25,7 @@ xlabel = "Profit", ylabel = "Desire", legend = false, -)Example block output

    The goal of the bi-objective knapsack problem is to choose a subset which maximizes both objectives.

    JuMP formulation

    Our JuMP formulation is a direct translation of the mathematical formulation:

    model = Model()
    +)
    Example block output

    The goal of the bi-objective knapsack problem is to choose a subset which maximizes both objectives.

    JuMP formulation

    Our JuMP formulation is a direct translation of the mathematical formulation:

    model = Model()
     @variable(model, x[1:N], Bin)
     @constraint(model, sum(weight[i] * x[i] for i in 1:N) <= capacity)
     @expression(model, profit_expr, sum(profit[i] * x[i] for i in 1:N))
    @@ -50,7 +50,7 @@
       Objective bound    : [9.55000e+02,9.83000e+02]
     
     * Work counters
    -  Solve time (sec)   : 9.65729e-02
    +  Solve time (sec)   : 9.75149e-02
     

    There are 9 solutions available. We can also use result_count to see how many solutions are available:

    result_count(model)
    9

    Accessing multiple solutions

    Access the nine different solutions in the model using the result keyword to solution_summary, value, and objective_value:

    solution_summary(model; result = 5)
    * Solver : MOA[algorithm=MultiObjectiveAlgorithms.EpsilonConstraint, optimizer=HiGHS]
     
     * Status
    @@ -77,7 +77,7 @@
         Plots.annotate!(y[1] - 1, y[2], (i, 10))
     end
     ideal_point = objective_bound(model)
    -Plots.scatter!([ideal_point[1]], [ideal_point[2]]; label = "Ideal point")
    Example block output

    Visualizing the objective space lets the decision maker choose a solution that suits their personal preferences. For example, result #7 is close to the maximum value of profit, but offers significantly higher desirability compared with solutions #8 and #9.

    The set of items that are chosen in solution #7 are:

    items_chosen = [i for i in 1:N if value(x[i]; result = 7) > 0.9]
    11-element Vector{Int64}:
    +Plots.scatter!([ideal_point[1]], [ideal_point[2]]; label = "Ideal point")
    Example block output

    Visualizing the objective space lets the decision maker choose a solution that suits their personal preferences. For example, result #7 is close to the maximum value of profit, but offers significantly higher desirability compared with solutions #8 and #9.

    The set of items that are chosen in solution #7 are:

    items_chosen = [i for i in 1:N if value(x[i]; result = 7) > 0.9]
    11-element Vector{Int64}:
       1
       2
       3
    @@ -88,4 +88,4 @@
      11
      15
      16
    - 17

    Next steps

    MultiObjectiveAlgorithms.jl implements a number of different algorithms. Try solving the same problem using MOA.Dichotomy(). Does it find the same solution?

    + 17

    Next steps

    MultiObjectiveAlgorithms.jl implements a number of different algorithms. Try solving the same problem using MOA.Dichotomy(). Does it find the same solution?

    diff --git a/previews/PR3883/tutorials/linear/n-queens/index.html b/previews/PR3883/tutorials/linear/n-queens/index.html index 4b10f63acd3..672f8f17052 100644 --- a/previews/PR3883/tutorials/linear/n-queens/index.html +++ b/previews/PR3883/tutorials/linear/n-queens/index.html @@ -23,4 +23,4 @@ 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 - 0 1 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 diff --git a/previews/PR3883/tutorials/linear/network_flows/index.html b/previews/PR3883/tutorials/linear/network_flows/index.html index 960e5be61ff..5047e8b43c9 100644 --- a/previews/PR3883/tutorials/linear/network_flows/index.html +++ b/previews/PR3883/tutorials/linear/network_flows/index.html @@ -91,4 +91,4 @@ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/3b80eb12.svg b/previews/PR3883/tutorials/linear/piecewise_linear/04fcb52f.svg similarity index 85% rename from previews/PR3883/tutorials/linear/piecewise_linear/3b80eb12.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/04fcb52f.svg index ddca8804263..59f8bb2a526 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/3b80eb12.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/04fcb52f.svg @@ -1,44 +1,44 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/d07b667d.svg b/previews/PR3883/tutorials/linear/piecewise_linear/11d4e316.svg similarity index 84% rename from previews/PR3883/tutorials/linear/piecewise_linear/d07b667d.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/11d4e316.svg index 77de021a48a..145bd8af089 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/d07b667d.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/11d4e316.svg @@ -1,65 +1,65 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/774ec400.svg b/previews/PR3883/tutorials/linear/piecewise_linear/2c380a25.svg similarity index 85% rename from previews/PR3883/tutorials/linear/piecewise_linear/774ec400.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/2c380a25.svg index d745b5aaac4..1a62e505467 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/774ec400.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/2c380a25.svg @@ -1,46 +1,46 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/db234900.svg b/previews/PR3883/tutorials/linear/piecewise_linear/33288e92.svg similarity index 80% rename from previews/PR3883/tutorials/linear/piecewise_linear/db234900.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/33288e92.svg index 51297887481..fda6315fae4 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/db234900.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/33288e92.svg @@ -1,63 +1,63 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/03885d79.svg b/previews/PR3883/tutorials/linear/piecewise_linear/42fa819d.svg similarity index 86% rename from previews/PR3883/tutorials/linear/piecewise_linear/03885d79.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/42fa819d.svg index de467a6ed3c..7bd2a6d8fd7 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/03885d79.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/42fa819d.svg @@ -1,50 +1,50 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/81c47fc0.svg b/previews/PR3883/tutorials/linear/piecewise_linear/44b22d67.svg similarity index 78% rename from previews/PR3883/tutorials/linear/piecewise_linear/81c47fc0.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/44b22d67.svg index 44467423344..41f2d97095e 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/81c47fc0.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/44b22d67.svg @@ -1,60 +1,60 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/6e263b52.svg b/previews/PR3883/tutorials/linear/piecewise_linear/5cd3b58f.svg similarity index 92% rename from previews/PR3883/tutorials/linear/piecewise_linear/6e263b52.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/5cd3b58f.svg index df332df1e42..2c4d732650d 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/6e263b52.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/5cd3b58f.svg @@ -1,63 +1,63 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/06001372.svg b/previews/PR3883/tutorials/linear/piecewise_linear/619333d3.svg similarity index 82% rename from previews/PR3883/tutorials/linear/piecewise_linear/06001372.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/619333d3.svg index 02300805d7a..5290ee5fd55 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/06001372.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/619333d3.svg @@ -1,48 +1,48 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/ae105088.svg b/previews/PR3883/tutorials/linear/piecewise_linear/9b872596.svg similarity index 82% rename from previews/PR3883/tutorials/linear/piecewise_linear/ae105088.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/9b872596.svg index dcb56f26c38..6232a741237 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/ae105088.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/9b872596.svg @@ -1,61 +1,61 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/97e726a7.svg b/previews/PR3883/tutorials/linear/piecewise_linear/a6799ee2.svg similarity index 81% rename from previews/PR3883/tutorials/linear/piecewise_linear/97e726a7.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/a6799ee2.svg index d2cee0a2ce8..0f6c638c782 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/97e726a7.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/a6799ee2.svg @@ -1,45 +1,45 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/2fab6f90.svg b/previews/PR3883/tutorials/linear/piecewise_linear/ae929f6d.svg similarity index 86% rename from previews/PR3883/tutorials/linear/piecewise_linear/2fab6f90.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/ae929f6d.svg index 7348802a3bd..5ce15e1b164 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/2fab6f90.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/ae929f6d.svg @@ -1,43 +1,43 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/60abc362.svg b/previews/PR3883/tutorials/linear/piecewise_linear/c3fb6531.svg similarity index 94% rename from previews/PR3883/tutorials/linear/piecewise_linear/60abc362.svg rename to previews/PR3883/tutorials/linear/piecewise_linear/c3fb6531.svg index 754d57129f8..29682a9cba0 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/60abc362.svg +++ b/previews/PR3883/tutorials/linear/piecewise_linear/c3fb6531.svg @@ -1,48 +1,48 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/linear/piecewise_linear/index.html b/previews/PR3883/tutorials/linear/piecewise_linear/index.html index 188216eff45..40ffeec5461 100644 --- a/previews/PR3883/tutorials/linear/piecewise_linear/index.html +++ b/previews/PR3883/tutorials/linear/piecewise_linear/index.html @@ -7,11 +7,11 @@ import HiGHS import Plots

    Minimizing a convex function (outer approximation)

    If the function you are approximating is convex, and you want to minimize "down" onto it, then you can use an outer approximation.

    For example, $f(x) = x^2$ is a convex function:

    f(x) = x^2
     ∇f(x) = 2 * x
    -plot = Plots.plot(f, -2:0.01:2; ylims = (-0.5, 4), label = false, width = 3)
    Example block output

    Because $f$ is convex, we know that for any $x_k$, we have: $f(x) \ge f(x_k) + \nabla f(x_k) \cdot (x - x_k)$

    for x_k in -2:1:2  ## Tip: try changing the number of points x_k
    +plot = Plots.plot(f, -2:0.01:2; ylims = (-0.5, 4), label = false, width = 3)
    Example block output

    Because $f$ is convex, we know that for any $x_k$, we have: $f(x) \ge f(x_k) + \nabla f(x_k) \cdot (x - x_k)$

    for x_k in -2:1:2  ## Tip: try changing the number of points x_k
         g = x -> f(x_k) + ∇f(x_k) * (x - x_k)
         Plots.plot!(plot, g, -2:0.01:2; color = :red, label = false, width = 3)
     end
    -plot
    Example block output

    We can use these tangent planes as constraints in our model to create an outer approximation of the function. As we add more planes, the error between the true function and the piecewise linear outer approximation decreases.

    Here is the model in JuMP:

    function outer_approximate_x_squared(x̄)
    +plot
    Example block output

    We can use these tangent planes as constraints in our model to create an outer approximation of the function. As we add more planes, the error between the true function and the piecewise linear outer approximation decreases.

    Here is the model in JuMP:

    function outer_approximate_x_squared(x̄)
         f(x) = x^2
         ∇f(x) = 2x
         model = Model(HiGHS.Optimizer)
    @@ -29,7 +29,7 @@
         ȳ = outer_approximate_x_squared(x̄)
         Plots.scatter!(plot, [x̄], [ȳ]; label = false, color = :black)
     end
    -plot
    Example block output
    Note

    This formulation does not work if we want to maximize y.

    Maximizing a concave function (outer approximation)

    The outer approximation also works if we want to maximize "up" into a concave function.

    f(x) = log(x)
    +plot
    Example block output
    Note

    This formulation does not work if we want to maximize y.

    Maximizing a concave function (outer approximation)

    The outer approximation also works if we want to maximize "up" into a concave function.

    f(x) = log(x)
     ∇f(x) = 1 / x
     X = 0.1:0.1:1.6
     plot = Plots.plot(
    @@ -44,7 +44,7 @@
         g = x -> f(x_k) + ∇f(x_k) * (x - x_k)
         Plots.plot!(plot, g, X; color = :red, label = false, width = 3)
     end
    -plot
    Example block output

    Here is the model in JuMP:

    function outer_approximate_log(x̄)
    +plot
    Example block output

    Here is the model in JuMP:

    function outer_approximate_log(x̄)
         f(x) = log(x)
         ∇f(x) = 1 / x
         model = Model(HiGHS.Optimizer)
    @@ -62,18 +62,18 @@
         ȳ = outer_approximate_log(x̄)
         Plots.scatter!(plot, [x̄], [ȳ]; label = false, color = :black)
     end
    -plot
    Example block output
    Note

    This formulation does not work if we want to minimize y.

    Minimizing a convex function (inner approximation)

    Instead of creating an outer approximation, we can also create an inner approximation. For example, given $f(x) = x^2$, we may want to approximate the true function by the red piecewise linear function:

    f(x) = x^2
    +plot
    Example block output
    Note

    This formulation does not work if we want to minimize y.

    Minimizing a convex function (inner approximation)

    Instead of creating an outer approximation, we can also create an inner approximation. For example, given $f(x) = x^2$, we may want to approximate the true function by the red piecewise linear function:

    f(x) = x^2
     x̂ = -2:0.8:2  ## Tip: try changing the number of points in x̂
     plot = Plots.plot(f, -2:0.01:2; ylims = (-0.5, 4), label = false, linewidth = 3)
     Plots.plot!(plot, f, x̂; label = false, color = :red, linewidth = 3)
    -plot
    Example block output

    To do so, we represent the decision variables $(x, y)$ by the convex combination of a set of discrete points $\{x_k, y_k\}_{k=1}^K$:

    \[\begin{aligned} +plotExample block output

    To do so, we represent the decision variables $(x, y)$ by the convex combination of a set of discrete points $\{x_k, y_k\}_{k=1}^K$:

    \[\begin{aligned} x = \sum\limits_{k=1}^K \lambda_k x_k \\ y = \sum\limits_{k=1}^K \lambda_k y_k \\ \sum\limits_{k=1}^K \lambda_k = 1 \\ \lambda_k \ge 0, k=1,\ldots,k \\ \end{aligned}\]

    The feasible region of the convex combination actually allows any $(x, y)$ point inside this shaded region:

    I = [1, 2, 3, 4, 5, 6, 1]
     Plots.plot!(x̂[I], f.(x̂[I]); fill = (0, 0, "#f004"), width = 0, label = false)
    -plot
    Example block output

    Thus, this formulation does not work if we want to maximize $y$.

    Here is the model in JuMP:

    function inner_approximate_x_squared(x̄)
    +plot
    Example block output

    Thus, this formulation does not work if we want to maximize $y$.

    Here is the model in JuMP:

    function inner_approximate_x_squared(x̄)
         f(x) = x^2
         ∇f(x) = 2x
         x̂ = -2:0.8:2  ## Tip: try changing the number of points in x̂
    @@ -96,13 +96,13 @@
         ȳ = inner_approximate_x_squared(x̄)
         Plots.scatter!(plot, [x̄], [ȳ]; label = false, color = :black)
     end
    -plot
    Example block output

    Maximizing a convex function (inner approximation)

    The inner approximation also works if we want to maximize "up" into a concave function.

    f(x) = log(x)
    +plot
    Example block output

    Maximizing a convex function (inner approximation)

    The inner approximation also works if we want to maximize "up" into a concave function.

    f(x) = log(x)
     x̂ = 0.1:0.5:1.6  ## Tip: try changing the number of points in x̂
     plot = Plots.plot(f, 0.1:0.01:1.6; label = false, linewidth = 3)
     Plots.plot!(x̂, f.(x̂); linewidth = 3, color = :red, label = false)
     I = [1, 2, 3, 4, 1]
     Plots.plot!(x̂[I], f.(x̂[I]); fill = (0, 0, "#f004"), width = 0, label = false)
    -plot
    Example block output

    Here is the model in JuMP:

    function inner_approximate_log(x̄)
    +plot
    Example block output

    Here is the model in JuMP:

    function inner_approximate_log(x̄)
         f(x) = log(x)
         x̂ = 0.1:0.5:1.6  ## Tip: try changing the number of points in x̂
         ŷ = f.(x̂)
    @@ -124,13 +124,13 @@
         ȳ = inner_approximate_log(x̄)
         Plots.scatter!(plot, [x̄], [ȳ]; label = false, color = :black)
     end
    -plot
    Example block output

    Piecewise linear approximation

    If the model is non-convex (or non-concave), then we cannot use an outer approximation, and the inner approximation allows a solution far from the true function. For example, for $f(x) = sin(x)$, we have:

    f(x) = sin(x)
    +plot
    Example block output

    Piecewise linear approximation

    If the model is non-convex (or non-concave), then we cannot use an outer approximation, and the inner approximation allows a solution far from the true function. For example, for $f(x) = sin(x)$, we have:

    f(x) = sin(x)
     plot = Plots.plot(f, 0:0.01:2π; label = false)
     x̂ = range(; start = 0, stop = 2π, length = 7)
     Plots.plot!(x̂, f.(x̂); linewidth = 3, color = :red, label = false)
     I = [1, 5, 6, 7, 3, 2, 1]
     Plots.plot!(x̂[I], f.(x̂[I]); fill = (0, 0, "#f004"), width = 0, label = false)
    -plot
    Example block output

    We can force the inner approximation to stay on the red line by adding the constraint λ in SOS2(). The SOS2 set is a Special Ordered Set of Type 2, and it ensures that at most two elements of λ can be non-zero, and if they are, that they must be adjacent. This prevents the model from taking a convex combination of points 1 and 5 to end up on the lower boundary of the shaded red area.

    Here is the model in JuMP:

    function piecewise_linear_sin(x̄)
    +plot
    Example block output

    We can force the inner approximation to stay on the red line by adding the constraint λ in SOS2(). The SOS2 set is a Special Ordered Set of Type 2, and it ensures that at most two elements of λ can be non-zero, and if they are, that they must be adjacent. This prevents the model from taking a convex combination of points 1 and 5 to end up on the lower boundary of the shaded red area.

    Here is the model in JuMP:

    function piecewise_linear_sin(x̄)
         f(x) = sin(x)
         # Tip: try changing the number of points in x̂
         x̂ = range(; start = 0, stop = 2π, length = 7)
    @@ -155,4 +155,4 @@
         ȳ = piecewise_linear_sin(x̄)
         Plots.scatter!(plot, [x̄], [ȳ]; label = false, color = :black)
     end
    -plot
    Example block output +plotExample block output diff --git a/previews/PR3883/tutorials/linear/sudoku/index.html b/previews/PR3883/tutorials/linear/sudoku/index.html index 3b3523f0468..06f225d49ef 100644 --- a/previews/PR3883/tutorials/linear/sudoku/index.html +++ b/previews/PR3883/tutorials/linear/sudoku/index.html @@ -93,4 +93,4 @@ 7 1 3 9 2 4 8 5 6 9 6 1 5 3 7 2 8 4 2 8 7 4 1 9 6 3 5 - 3 4 5 2 8 6 1 7 9

    Which is the same as we found before:

    sol == csp_sol
    true
    + 3 4 5 2 8 6 1 7 9

    Which is the same as we found before:

    sol == csp_sol
    true
    diff --git a/previews/PR3883/tutorials/linear/tips_and_tricks/index.html b/previews/PR3883/tutorials/linear/tips_and_tricks/index.html index 0b95db7c6ef..e85256975b2 100644 --- a/previews/PR3883/tutorials/linear/tips_and_tricks/index.html +++ b/previews/PR3883/tutorials/linear/tips_and_tricks/index.html @@ -70,4 +70,4 @@ y == sum(ŷ[i] * λ[i] for i in 1:N) sum(λ) == 1 λ in SOS2() - end)(x + λ[1] + 0.5 λ[2] - 0.5 λ[4] - λ[5] - 1.5 λ[6] - 2 λ[7] = 0, y - λ[1] - 0.25 λ[2] - 0.25 λ[4] - λ[5] - 2.25 λ[6] - 4 λ[7] = 0, λ[1] + λ[2] + λ[3] + λ[4] + λ[5] + λ[6] + λ[7] = 1, [λ[1], λ[2], λ[3], λ[4], λ[5], λ[6], λ[7]] ∈ MathOptInterface.SOS2{Float64}([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])) + end)(x + λ[1] + 0.5 λ[2] - 0.5 λ[4] - λ[5] - 1.5 λ[6] - 2 λ[7] = 0, y - λ[1] - 0.25 λ[2] - 0.25 λ[4] - λ[5] - 2.25 λ[6] - 4 λ[7] = 0, λ[1] + λ[2] + λ[3] + λ[4] + λ[5] + λ[6] + λ[7] = 1, [λ[1], λ[2], λ[3], λ[4], λ[5], λ[6], λ[7]] ∈ MathOptInterface.SOS2{Float64}([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])) diff --git a/previews/PR3883/tutorials/linear/transp/index.html b/previews/PR3883/tutorials/linear/transp/index.html index 58dedc71094..40dcf7b46e1 100644 --- a/previews/PR3883/tutorials/linear/transp/index.html +++ b/previews/PR3883/tutorials/linear/transp/index.html @@ -74,4 +74,4 @@ end
    solve_transportation_problem (generic function with 1 method)

    Solution

    Let's solve and view the solution:

    solve_transportation_problem(data)
            FRA    DET    LAN    WIN    STL    FRE    LAF
     GARY      .      .      .      .  300.0 1100.0      .
     CLEV      .      .  600.0      . 1000.0      . 1000.0
    -PITT  900.0 1200.0      .  400.0  400.0      .      .
    +PITT 900.0 1200.0 . 400.0 400.0 . . diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/a4bf0e74.svg b/previews/PR3883/tutorials/nonlinear/classifiers/011c4738.svg similarity index 62% rename from previews/PR3883/tutorials/nonlinear/classifiers/a4bf0e74.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/011c4738.svg index 3be2b8941a3..8b4cdd66077 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/a4bf0e74.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/011c4738.svg @@ -1,543 +1,543 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/32a4e5ef.svg b/previews/PR3883/tutorials/nonlinear/classifiers/11ef2d78.svg similarity index 63% rename from previews/PR3883/tutorials/nonlinear/classifiers/32a4e5ef.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/11ef2d78.svg index aea25b18aa0..dac5696b0cc 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/32a4e5ef.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/11ef2d78.svg @@ -1,551 +1,551 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/27207c09.svg b/previews/PR3883/tutorials/nonlinear/classifiers/13aac46f.svg similarity index 72% rename from previews/PR3883/tutorials/nonlinear/classifiers/27207c09.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/13aac46f.svg index 637aa089be5..05a2a611a2d 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/27207c09.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/13aac46f.svg @@ -1,142 +1,142 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/729ee2e4.svg b/previews/PR3883/tutorials/nonlinear/classifiers/1c0a1f6b.svg similarity index 69% rename from previews/PR3883/tutorials/nonlinear/classifiers/729ee2e4.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/1c0a1f6b.svg index b4521c4ace2..08a3dbc8abe 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/729ee2e4.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/1c0a1f6b.svg @@ -1,20913 +1,20913 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/422e11f8.svg b/previews/PR3883/tutorials/nonlinear/classifiers/2076085a.svg similarity index 62% rename from previews/PR3883/tutorials/nonlinear/classifiers/422e11f8.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/2076085a.svg index 3a6b84458c0..151f2d9a239 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/422e11f8.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/2076085a.svg @@ -1,550 +1,550 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/bbed3495.svg b/previews/PR3883/tutorials/nonlinear/classifiers/944e7683.svg similarity index 61% rename from previews/PR3883/tutorials/nonlinear/classifiers/bbed3495.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/944e7683.svg index 846f75cbea6..4f81520ce96 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/bbed3495.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/944e7683.svg @@ -1,1042 +1,1042 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/ae78bd87.svg b/previews/PR3883/tutorials/nonlinear/classifiers/c114f723.svg similarity index 73% rename from previews/PR3883/tutorials/nonlinear/classifiers/ae78bd87.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/c114f723.svg index d85b717d43d..b26e32ff523 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/ae78bd87.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/c114f723.svg @@ -1,143 +1,143 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/b8219642.svg b/previews/PR3883/tutorials/nonlinear/classifiers/e3458f44.svg similarity index 62% rename from previews/PR3883/tutorials/nonlinear/classifiers/b8219642.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/e3458f44.svg index 6f3ef5410d3..65a33722684 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/b8219642.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/e3458f44.svg @@ -1,544 +1,544 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/492869a0.svg b/previews/PR3883/tutorials/nonlinear/classifiers/fa31df97.svg similarity index 62% rename from previews/PR3883/tutorials/nonlinear/classifiers/492869a0.svg rename to previews/PR3883/tutorials/nonlinear/classifiers/fa31df97.svg index 41f037426bd..e56d68f2e82 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/492869a0.svg +++ b/previews/PR3883/tutorials/nonlinear/classifiers/fa31df97.svg @@ -1,543 +1,543 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/classifiers/index.html b/previews/PR3883/tutorials/nonlinear/classifiers/index.html index e52f8bd16db..8b05352ec3c 100644 --- a/previews/PR3883/tutorials/nonlinear/classifiers/index.html +++ b/previews/PR3883/tutorials/nonlinear/classifiers/index.html @@ -20,9 +20,9 @@ color = :white, size = (600, 600), legend = false, -)Example block output

    We want to split the points into two distinct sets on either side of a dividing line. We'll then label each point depending on which side of the line it happens to fall. Based on the labels of the point, we'll show how to create a classifier using a JuMP model. We can then test how well our classifier reproduces the original labels and the boundary between them.

    Let's make a line to divide the points into two sets by defining a gradient and a constant:

    w_0, g_0 = [5, 3], 8
    +)
    Example block output

    We want to split the points into two distinct sets on either side of a dividing line. We'll then label each point depending on which side of the line it happens to fall. Based on the labels of the point, we'll show how to create a classifier using a JuMP model. We can then test how well our classifier reproduces the original labels and the boundary between them.

    Let's make a line to divide the points into two sets by defining a gradient and a constant:

    w_0, g_0 = [5, 3], 8
     line(v::AbstractArray; w = w_0, g = g_0) = w' * v - g
    -line(x::Real; w = w_0, g = g_0) = -(w[1] * x - g) / w[2];

    Julia's multiple dispatch feature allows us to define the vector and single-variable form of the line function under the same name.

    Let's add this to the plot:

    Plots.plot!(plot, line; linewidth = 5)
    Example block output

    Now we label the points relative to which side of the line they are. It is numerically useful to have the labels +1 and -1 for the upcoming JuMP formulation.

    labels = ifelse.(line.(eachrow(P)) .>= 0, 1, -1)
    +line(x::Real; w = w_0, g = g_0) = -(w[1] * x - g) / w[2];

    Julia's multiple dispatch feature allows us to define the vector and single-variable form of the line function under the same name.

    Let's add this to the plot:

    Plots.plot!(plot, line; linewidth = 5)
    Example block output

    Now we label the points relative to which side of the line they are. It is numerically useful to have the labels +1 and -1 for the upcoming JuMP formulation.

    labels = ifelse.(line.(eachrow(P)) .>= 0, 1, -1)
     Plots.scatter!(
         plot,
         P[:, 1],
    @@ -30,7 +30,7 @@
         shape = ifelse.(labels .== 1, :cross, :xcross),
         markercolor = ifelse.(labels .== 1, :blue, :crimson),
         markersize = 8,
    -)
    Example block output

    Our goal is to show we can reconstruct the line from just the points and the labels.

    Formulation: linear support vector machine

    A classifier known as the linear support vector machine (SVM) looks for the affine function $L(p) = w^\top p - g$ that satisfies $L(p) < 0$ for all points $p$ with a label -1 and $L(p) \ge 0$ for all points $p$ with a label +1.

    The linearly constrained quadratic program that implements this is:

    \[\begin{aligned} +)Example block output

    Our goal is to show we can reconstruct the line from just the points and the labels.

    Formulation: linear support vector machine

    A classifier known as the linear support vector machine (SVM) looks for the affine function $L(p) = w^\top p - g$ that satisfies $L(p) < 0$ for all points $p$ with a label -1 and $L(p) \ge 0$ for all points $p$ with a label +1.

    The linearly constrained quadratic program that implements this is:

    \[\begin{aligned} \min_{w \in \mathbb{R}^n, \; g \in \mathbb{R}, \; y \in \mathbb{R}^m} \quad & \frac{1}{2} w^\top w + C \; \sum_{i=1}^m y_i \\ \text{subject to } \quad & D \cdot (P w - g) + y \geq \mathbf{1} \\ & y \ge 0. @@ -59,7 +59,7 @@ │ ├ AffExpr in MOI.GreaterThan{Float64}: 100 │ └ VariableRef in MOI.GreaterThan{Float64}: 100 └ Names registered in the model - └ :g, :w, :y, Main.classifier)

    With the solution, we can ask: was the value of the penalty constant "sufficiently large" for this data set? This can be judged in part by the range of the slack variables. If the slack is too large, then we need to increase the penalty constant.

    Let's plot the solution and check how we did:

    Plots.plot!(plot, classifier; linewidth = 5, linestyle = :dashdotdot)
    Example block output

    We find that we have recovered the dividing line from just the information of the points and their labels.

    Nonseparable classes of points

    Now, what if the point sets are not cleanly separable by a line (or a hyperplane in higher dimensions)? Does this still work? Let's repeat the process, but this time we will simulate nonseparable classes of points by intermingling a few nearby points across the previously used line.

    nearby_indices = abs.(line.(eachrow(P))) .< 1.1
    +  └ :g, :w, :y, Main.classifier)

    With the solution, we can ask: was the value of the penalty constant "sufficiently large" for this data set? This can be judged in part by the range of the slack variables. If the slack is too large, then we need to increase the penalty constant.

    Let's plot the solution and check how we did:

    Plots.plot!(plot, classifier; linewidth = 5, linestyle = :dashdotdot)
    Example block output

    We find that we have recovered the dividing line from just the information of the points and their labels.

    Nonseparable classes of points

    Now, what if the point sets are not cleanly separable by a line (or a hyperplane in higher dimensions)? Does this still work? Let's repeat the process, but this time we will simulate nonseparable classes of points by intermingling a few nearby points across the previously used line.

    nearby_indices = abs.(line.(eachrow(P))) .< 1.1
     labels_new = ifelse.(nearby_indices, -labels, labels)
     model, classifier = solve_SVM_classifier(P, labels_new)
     plot = Plots.scatter(
    @@ -79,7 +79,7 @@
         markercolor = ifelse.(labels_new .== 1, :blue, :crimson),
         markersize = 8,
     )
    -Plots.plot!(plot, classifier; linewidth = 5, linestyle = :dashdotdot)
    Example block output

    So our JuMP formulation still produces a classifier, but it mis-classifies some of the nonseparable points.

    We can find out which points are contributing to the shape of the line by looking at the dual values of the affine constraints and comparing them to the penalty constant $C$:

    affine_cons = all_constraints(model, AffExpr, MOI.GreaterThan{Float64})
    +Plots.plot!(plot, classifier; linewidth = 5, linestyle = :dashdotdot)
    Example block output

    So our JuMP formulation still produces a classifier, but it mis-classifies some of the nonseparable points.

    We can find out which points are contributing to the shape of the line by looking at the dual values of the affine constraints and comparing them to the penalty constant $C$:

    affine_cons = all_constraints(model, AffExpr, MOI.GreaterThan{Float64})
     active_cons = findall(isapprox.(dual.(affine_cons), C_0; atol = 0.001))
     findall(nearby_indices) ⊆ active_cons
    true

    The last statement tells us that our nonseparable points are actively contributing to how the classifier is defined. The remaining points are of interest and are highlighted:

    P_active = P[setdiff(active_cons, findall(nearby_indices)), :]
     Plots.scatter!(
    @@ -89,7 +89,7 @@
         shape = :hexagon,
         markersize = 8,
         markeropacity = 0.5,
    -)
    Example block output

    Advanced: duality and the kernel method

    We now consider an alternative formulation for a linear SVM by solving the dual problem.

    The dual program

    The dual of the linear SVM program is also a linearly constrained quadratic program:

    \[\begin{aligned} +)Example block output

    Advanced: duality and the kernel method

    We now consider an alternative formulation for a linear SVM by solving the dual problem.

    The dual program

    The dual of the linear SVM program is also a linearly constrained quadratic program:

    \[\begin{aligned} \min_{u \in \mathbb{R}^m} \quad & \frac{1}{2} u^\top D P P^\top D u - \; \mathbf{1}^\top u \\ \text{subject to } \quad & \mathbf{1}^\top D u = 0 \\ & 0 \leq u \leq C\mathbf{1}. @@ -108,7 +108,7 @@ classifier(x) = line(x; w = w, g = g) return classifier end

    solve_dual_SVM_classifier (generic function with 1 method)

    We recover the line gradient vector $w$ through setting $w = P^\top D u$, and the line constant $g$ as the dual value of the single affine constraint.

    The dual problem has fewer variables and fewer constraints, so in many cases it may be simpler to solve the dual form.

    We can check that the dual form has recovered a classifier:

    classifier = solve_dual_SVM_classifier(P, labels)
    -Plots.plot!(plot, classifier; linewidth = 5, linestyle = :dash)
    Example block output

    The kernel method

    Linear SVM techniques are not limited to finding separating hyperplanes in the original space of the dataset. One could first transform the training data under a nonlinear mapping, apply our method, then map the hyperplane back into original space.

    The actual data describing the point set is held in a matrix $P$, but looking at the dual program we see that what actually matters is the Gram matrix $P P^\top$, expressing a pairwise comparison (an inner-product) between each point vector. It follows that any mapping of the point set only needs to be defined at the level of pairwise maps between points. Such maps are known as kernel functions:

    \[k \; : \; \mathbb{R}^n \times \mathbb{R}^n \; \rightarrow \mathbb{R}, \qquad +Plots.plot!(plot, classifier; linewidth = 5, linestyle = :dash)Example block output

    The kernel method

    Linear SVM techniques are not limited to finding separating hyperplanes in the original space of the dataset. One could first transform the training data under a nonlinear mapping, apply our method, then map the hyperplane back into original space.

    The actual data describing the point set is held in a matrix $P$, but looking at the dual program we see that what actually matters is the Gram matrix $P P^\top$, expressing a pairwise comparison (an inner-product) between each point vector. It follows that any mapping of the point set only needs to be defined at the level of pairwise maps between points. Such maps are known as kernel functions:

    \[k \; : \; \mathbb{R}^n \times \mathbb{R}^n \; \rightarrow \mathbb{R}, \qquad (s, t) \mapsto \left< \Phi(s), \Phi(t) \right>\]

    where the right-hand side applies some transformation $\Phi : \mathbb{R}^n \rightarrow \mathbb{R}^{n'}$ followed by an inner-product in that image space.

    In practice, we can avoid having $\Phi$ explicitly given but instead define a kernel function directly between pairs of vectors. This change to using a kernel function without knowing the map is called the kernel method (or sometimes, the kernel trick).

    Classifier using a Gaussian kernel

    We will demonstrate the application of a Gaussian or radial basis function kernel:

    \[k(s, t) = \exp\left( -\mu \lVert s - t \rVert^2_2 \right)\]

    for some positive parameter $\mu$.

    k_gauss(s::Vector, t::Vector; μ = 0.5) = exp(-μ * LinearAlgebra.norm(s - t)^2)
    k_gauss (generic function with 1 method)

    Given a matrix of points expressed row-wise and a kernel, the next function returns the transformed matrix $K$ that replaces $P P^\top$:

    function pairwise_transform(kernel::Function, P::Matrix{T}) where {T}
         m, n = size(P)
         K = zeros(T, m, m)
    @@ -151,7 +151,7 @@
         markersize = ifelse.(labels .== 1, 4, 2),
         size = (600, 600),
         legend = false,
    -)
    Example block output

    Is the technique capable of generating a distinctly nonlinear surface? Let's solve the Gaussian kernel based quadratic problem with these parameters:

    classifier = solve_kernel_SVM_classifier(k_gauss, B, labels; C = 1e5, μ = 10.0)
    +)
    Example block output

    Is the technique capable of generating a distinctly nonlinear surface? Let's solve the Gaussian kernel based quadratic problem with these parameters:

    classifier = solve_kernel_SVM_classifier(k_gauss, B, labels; C = 1e5, μ = 10.0)
     grid = [[x, y] for x in 0:0.01:2, y in 0:0.01:2]
     grid_pos = [Tuple(g) for g in grid if classifier(g) >= 0]
    -Plots.scatter!(plot, grid_pos; markersize = 0.2)
    Example block output

    We find that the kernel method can perform well as a nonlinear classifier.

    The result has a fairly strong dependence on the choice of parameters, with larger values of $\mu$ allowing for a more complex boundary while smaller values lead to a smoother boundary for the classifier. Determining a better performing kernel function and choice of parameters is covered by the process of cross-validation with respect to the dataset, where different testing, training and tuning sets are used to validate the best choice of parameters against a statistical measure of error.

    +Plots.scatter!(plot, grid_pos; markersize = 0.2)Example block output

    We find that the kernel method can perform well as a nonlinear classifier.

    The result has a fairly strong dependence on the choice of parameters, with larger values of $\mu$ allowing for a more complex boundary while smaller values lead to a smoother boundary for the classifier. Determining a better performing kernel function and choice of parameters is covered by the process of cross-validation with respect to the dataset, where different testing, training and tuning sets are used to validate the best choice of parameters against a statistical measure of error.

    diff --git a/previews/PR3883/tutorials/nonlinear/complementarity/index.html b/previews/PR3883/tutorials/nonlinear/complementarity/index.html index f1d6cbd3664..3d73e1c7040 100644 --- a/previews/PR3883/tutorials/nonlinear/complementarity/index.html +++ b/previews/PR3883/tutorials/nonlinear/complementarity/index.html @@ -142,4 +142,4 @@ 60.0 59.99999999999994 60.68493150684928 - 110.68493150684935 + 110.68493150684935 diff --git a/previews/PR3883/tutorials/nonlinear/introduction/index.html b/previews/PR3883/tutorials/nonlinear/introduction/index.html index 480fa4572aa..3e622566531 100644 --- a/previews/PR3883/tutorials/nonlinear/introduction/index.html +++ b/previews/PR3883/tutorials/nonlinear/introduction/index.html @@ -7,4 +7,4 @@ \min_{x \in \mathbb{R}^n} & f_0(x) \\ \;\;\text{s.t.} & l_j \le f_j(x) \le u_j & j = 1 \ldots m \\ & l_i \le x_i \le u_i & i = 1 \ldots n. -\end{align}\]

    Mixed-integer nonlinear linear programs (MINLPs) are extensions of nonlinear programs in which some (or all) of the decision variables take discrete values.

    How to choose a solver

    JuMP supports a range of nonlinear solvers; look for "NLP" in the list of Supported solvers. However, very few solvers support mixed-integer nonlinear linear programs. Solvers supporting discrete variables start with "(MI)" in the list of Supported solvers.

    If the only nonlinearities in your model are quadratic terms (that is, multiplication between two decision variables), you can also use second-order cone solvers, which are indicated by "SOCP." In most cases, these solvers are restricted to convex quadratic problems and will error if you pass a nonconvex quadratic function; however, Gurobi has the ability to solve nonconvex quadratic terms.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    +\end{align}\]

    Mixed-integer nonlinear linear programs (MINLPs) are extensions of nonlinear programs in which some (or all) of the decision variables take discrete values.

    How to choose a solver

    JuMP supports a range of nonlinear solvers; look for "NLP" in the list of Supported solvers. However, very few solvers support mixed-integer nonlinear linear programs. Solvers supporting discrete variables start with "(MI)" in the list of Supported solvers.

    If the only nonlinearities in your model are quadratic terms (that is, multiplication between two decision variables), you can also use second-order cone solvers, which are indicated by "SOCP." In most cases, these solvers are restricted to convex quadratic problems and will error if you pass a nonconvex quadratic function; however, Gurobi has the ability to solve nonconvex quadratic terms.

    How these tutorials are structured

    Having a high-level overview of how this part of the documentation is structured will help you know where to look for certain things.

    diff --git a/previews/PR3883/tutorials/nonlinear/nested_problems/index.html b/previews/PR3883/tutorials/nonlinear/nested_problems/index.html index 730067ad347..e4560e23268 100644 --- a/previews/PR3883/tutorials/nonlinear/nested_problems/index.html +++ b/previews/PR3883/tutorials/nonlinear/nested_problems/index.html @@ -64,7 +64,7 @@ Dual objective value : 0.00000e+00 * Work counters - Solve time (sec) : 5.02303e-01 + Solve time (sec) : 4.93202e-01 Barrier iterations : 32

    The optimal objective value is:

    objective_value(model)
    -418983.48680640775

    and the optimal upper-level decision variables $x$ are:

    value.(x)
    2-element Vector{Float64}:
      154.97862337234338
    @@ -127,8 +127,8 @@
       Dual objective value : 0.00000e+00
     
     * Work counters
    -  Solve time (sec)   : 1.93317e-01
    +  Solve time (sec)   : 1.92988e-01
       Barrier iterations : 32
     

    an we can check we get the same objective value:

    objective_value(model)
    -418983.48680640775

    and upper-level decision variable $x$:

    value.(x)
    2-element Vector{Float64}:
      154.97862337234338
    - 180.0096143098799
    + 180.0096143098799 diff --git a/previews/PR3883/tutorials/nonlinear/operator_ad/index.html b/previews/PR3883/tutorials/nonlinear/operator_ad/index.html index 16dee2efd55..7a94f0f6e16 100644 --- a/previews/PR3883/tutorials/nonlinear/operator_ad/index.html +++ b/previews/PR3883/tutorials/nonlinear/operator_ad/index.html @@ -205,4 +205,4 @@ di_rosenbrock(; backend = DifferentiationInterface.AutoForwardDiff())
    2-element Vector{Float64}:
      0.9999999999999899
    - 0.9999999999999792
    + 0.9999999999999792 diff --git a/previews/PR3883/tutorials/nonlinear/portfolio/db4e55a6.svg b/previews/PR3883/tutorials/nonlinear/portfolio/6f1e4109.svg similarity index 79% rename from previews/PR3883/tutorials/nonlinear/portfolio/db4e55a6.svg rename to previews/PR3883/tutorials/nonlinear/portfolio/6f1e4109.svg index 787522a222d..8708c10a2b8 100644 --- a/previews/PR3883/tutorials/nonlinear/portfolio/db4e55a6.svg +++ b/previews/PR3883/tutorials/nonlinear/portfolio/6f1e4109.svg @@ -1,581 +1,581 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/portfolio/index.html b/previews/PR3883/tutorials/nonlinear/portfolio/index.html index 68dba81f051..1b08b53e7a8 100644 --- a/previews/PR3883/tutorials/nonlinear/portfolio/index.html +++ b/previews/PR3883/tutorials/nonlinear/portfolio/index.html @@ -72,7 +72,7 @@ Dual objective value : 4.52688e+04 * Work counters - Solve time (sec) : 3.04794e-03 + Solve time (sec) : 3.03197e-03 Barrier iterations : 11

    The optimal allocation of our assets is:

    value.(x)
    3-element Vector{Float64}:
      497.045529849864
    @@ -103,7 +103,7 @@
       Objective bound    : [5.78303e-09,-7.37159e+01]
     
     * Work counters
    -  Solve time (sec)   : 2.18273e-01
    +  Solve time (sec)   : 2.09560e-01
     

    The algorithm found 50 different solutions. Let's plot them to see how they differ:

    objective_space = Plots.hline(
         [scalar_return];
         label = "Single-objective solution",
    @@ -135,4 +135,4 @@
         ylabel = "Investment (\$)",
         title = "Decision space",
     )
    -Plots.plot(objective_space, decision_space; layout = (2, 1), size = (600, 600))
    Example block output

    Perhaps our trade-off wasn't so bad after all. Our original solution corresponded to picking a solution #17. If we buy more SEHI, we can increase the return, but the variance also increases. If we buy less SEHI, such as a solution like #5 or #6, then we can achieve the corresponding return without deploying all of our capital. We should also note that at no point should we buy WMT.

    +Plots.plot(objective_space, decision_space; layout = (2, 1), size = (600, 600))Example block output

    Perhaps our trade-off wasn't so bad after all. Our original solution corresponded to picking a solution #17. If we buy more SEHI, we can increase the return, but the variance also increases. If we buy less SEHI, such as a solution like #5 or #6, then we can achieve the corresponding return without deploying all of our capital. We should also note that at no point should we buy WMT.

    diff --git a/previews/PR3883/tutorials/nonlinear/querying_hessians/index.html b/previews/PR3883/tutorials/nonlinear/querying_hessians/index.html index 284ba6c567e..aeaedd4fd6c 100644 --- a/previews/PR3883/tutorials/nonlinear/querying_hessians/index.html +++ b/previews/PR3883/tutorials/nonlinear/querying_hessians/index.html @@ -168,4 +168,4 @@ 2.82843 2.82843

    Compare that to the analytic solution:

    y = value.(x)
     [2y[1] 0; 2y[1]+2y[2] 2y[1]+2y[2]]
    2×2 Matrix{Float64}:
      1.58072  0.0
    - 2.82843  2.82843
    + 2.82843 2.82843 diff --git a/previews/PR3883/tutorials/nonlinear/rocket_control/6fef5492.svg b/previews/PR3883/tutorials/nonlinear/rocket_control/cc2e1628.svg similarity index 89% rename from previews/PR3883/tutorials/nonlinear/rocket_control/6fef5492.svg rename to previews/PR3883/tutorials/nonlinear/rocket_control/cc2e1628.svg index b4017b1056b..4865ed02895 100644 --- a/previews/PR3883/tutorials/nonlinear/rocket_control/6fef5492.svg +++ b/previews/PR3883/tutorials/nonlinear/rocket_control/cc2e1628.svg @@ -1,130 +1,130 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/rocket_control/index.html b/previews/PR3883/tutorials/nonlinear/rocket_control/index.html index 56cd936ae1f..5c6a6bf71e7 100644 --- a/previews/PR3883/tutorials/nonlinear/rocket_control/index.html +++ b/previews/PR3883/tutorials/nonlinear/rocket_control/index.html @@ -48,7 +48,7 @@ Dual objective value : 4.66547e+00 * Work counters - Solve time (sec) : 1.96887e-01 + Solve time (sec) : 1.91580e-01 Barrier iterations : 24

    Finally, we plot the solution:

    function plot_trajectory(y; kwargs...)
         return Plots.plot(
    @@ -66,4 +66,4 @@
         plot_trajectory(x_v; ylabel = "Velocity"),
         plot_trajectory(u_t; ylabel = "Thrust");
         layout = (2, 2),
    -)
    Example block output

    Next steps

    • Experiment with different values for the constants. How does the solution change? In particular, what happens if you change T_max?
    • The dynamical equations use rectangular integration for the right-hand side terms. Modify the equations to use the Trapezoidal rule instead. (As an example, x_v[t-1] would become 0.5 * (x_v[t-1] + x_v[t]).) Is there a difference?
    +)Example block output

    Next steps

    • Experiment with different values for the constants. How does the solution change? In particular, what happens if you change T_max?
    • The dynamical equations use rectangular integration for the right-hand side terms. Modify the equations to use the Trapezoidal rule instead. (As an example, x_v[t-1] would become 0.5 * (x_v[t-1] + x_v[t]).) Is there a difference?
    diff --git a/previews/PR3883/tutorials/nonlinear/simple_examples/index.html b/previews/PR3883/tutorials/nonlinear/simple_examples/index.html index 77377327e88..08746b4ce47 100644 --- a/previews/PR3883/tutorials/nonlinear/simple_examples/index.html +++ b/previews/PR3883/tutorials/nonlinear/simple_examples/index.html @@ -181,4 +181,4 @@ z ≥ 0 Objective value: 0.32699283491387243 x = 0.32699283491387243 -y = 0.2570658388068964 +y = 0.2570658388068964 diff --git a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/6e83781f.svg b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/10cd4d7a.svg similarity index 88% rename from previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/6e83781f.svg rename to previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/10cd4d7a.svg index 664fa9883a0..0d03376acf3 100644 --- a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/6e83781f.svg +++ b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/10cd4d7a.svg @@ -1,97 +1,97 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/d413215e.svg b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/6a49d815.svg similarity index 87% rename from previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/d413215e.svg rename to previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/6a49d815.svg index c2bdb8ac348..c40177efdf1 100644 --- a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/d413215e.svg +++ b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/6a49d815.svg @@ -1,48 +1,48 @@ - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/92c535be.svg b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/9d7cfd7d.svg similarity index 88% rename from previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/92c535be.svg rename to previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/9d7cfd7d.svg index 91f594c308d..131ecee26ff 100644 --- a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/92c535be.svg +++ b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/9d7cfd7d.svg @@ -1,182 +1,182 @@ - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/index.html b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/index.html index f2b26425652..3f510a12f35 100644 --- a/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/index.html +++ b/previews/PR3883/tutorials/nonlinear/space_shuttle_reentry_trajectory/index.html @@ -221,7 +221,7 @@ layout = grid(3, 2), linewidth = 2, size = (700, 700), -)Example block output
    function q(h, v, a)
    +)
    Example block output
    function q(h, v, a)
         ρ(h) = ρ₀ * exp(-h / hᵣ)
         qᵣ(h, v) = 17700 * √ρ(h) * (0.0001 * v)^3.07
         qₐ(a) = c₀ + c₁ * rad2deg(a) + c₂ * rad2deg(a)^2 + c₃ * rad2deg(a)^3
    @@ -255,7 +255,7 @@
         layout = grid(3, 1),
         linewidth = 2,
         size = (700, 700),
    -)
    Example block output
    plot(
    +)
    Example block output
    plot(
         rad2deg.(value.(ϕ)),
         rad2deg.(value.(θ)),
         value.(scaled_h);
    @@ -265,4 +265,4 @@
         xlabel = "Longitude (deg)",
         ylabel = "Latitude (deg)",
         zlabel = "Altitude (100,000 ft)",
    -)
    Example block output +)Example block output diff --git a/previews/PR3883/tutorials/nonlinear/tips_and_tricks/index.html b/previews/PR3883/tutorials/nonlinear/tips_and_tricks/index.html index aa325aec0bb..12cee34a2d2 100644 --- a/previews/PR3883/tutorials/nonlinear/tips_and_tricks/index.html +++ b/previews/PR3883/tutorials/nonlinear/tips_and_tricks/index.html @@ -69,4 +69,4 @@ @assert is_solved_and_feasible(model) Test.@test objective_value(model) ≈ √3 atol = 1e-4 Test.@test value.(x) ≈ [1.0, 1.0] atol = 1e-4 -println("Memoized approach: function_calls = $(function_calls)")
    Memoized approach: function_calls = 22

    Compared to the naive approach, the memoized approach requires half as many function evaluations.

    +println("Memoized approach: function_calls = $(function_calls)")
    Memoized approach: function_calls = 22

    Compared to the naive approach, the memoized approach requires half as many function evaluations.

    diff --git a/previews/PR3883/tutorials/nonlinear/user_defined_hessians/index.html b/previews/PR3883/tutorials/nonlinear/user_defined_hessians/index.html index bca5bd08a1a..f6c61aa91b2 100644 --- a/previews/PR3883/tutorials/nonlinear/user_defined_hessians/index.html +++ b/previews/PR3883/tutorials/nonlinear/user_defined_hessians/index.html @@ -39,6 +39,6 @@ Dual solution : * Work counters - Solve time (sec) : 3.71480e-02 + Solve time (sec) : 3.66640e-02 Barrier iterations : 14 - + diff --git a/previews/PR3883/tutorials/transitioning/transitioning_from_matlab/index.html b/previews/PR3883/tutorials/transitioning/transitioning_from_matlab/index.html index dd066d00dfa..0978b941228 100644 --- a/previews/PR3883/tutorials/transitioning/transitioning_from_matlab/index.html +++ b/previews/PR3883/tutorials/transitioning/transitioning_from_matlab/index.html @@ -58,7 +58,7 @@ 6 1.1746e-09 -1.2507e-09 2.43e-09 1.59e-16 6.59e-17 2.83e-10 3.87e-10 9.90e-01 --------------------------------------------------------------------------------------------- Terminated with status = solved -solve time = 684μs

    The exclamation mark here is a Julia-ism that means the function is modifying its argument, model.

    Querying solution status

    After the optimization is done, you should check for the solution status to see what solution (if any) the solver found.

    Like YALMIP and CVX, JuMP provides a solver-independent way to check it, via the command:

    is_solved_and_feasible(model)
    true

    If the return value is false, you should investigate with termination_status, primal_status, and raw_status, See Solutions for more details on how to query and interpret solution statuses.

    Extracting variables

    Like YALMIP, but unlike CVX, with JuMP you need to explicitly ask for the value of your variables after optimization is done, with the function call value(x) to obtain the value of variable x.

    value.(m[1][1, 1])
    0.0

    A subtlety is that, unlike YALMIP, the function value is only defined for scalars. For vectors and matrices you need to use Julia broadcasting: value.(v).

    value.(m[1])
    3×3 Matrix{Float64}:
    +solve time =  694μs

    The exclamation mark here is a Julia-ism that means the function is modifying its argument, model.

    Querying solution status

    After the optimization is done, you should check for the solution status to see what solution (if any) the solver found.

    Like YALMIP and CVX, JuMP provides a solver-independent way to check it, via the command:

    is_solved_and_feasible(model)
    true

    If the return value is false, you should investigate with termination_status, primal_status, and raw_status, See Solutions for more details on how to query and interpret solution statuses.

    Extracting variables

    Like YALMIP, but unlike CVX, with JuMP you need to explicitly ask for the value of your variables after optimization is done, with the function call value(x) to obtain the value of variable x.

    value.(m[1][1, 1])
    0.0

    A subtlety is that, unlike YALMIP, the function value is only defined for scalars. For vectors and matrices you need to use Julia broadcasting: value.(v).

    value.(m[1])
    3×3 Matrix{Float64}:
      0.0  0.0  0.0
      0.0  0.0  0.0
      0.0  0.0  0.0

    There is also a specialized function for extracting the value of the objective, objective_value(model), which is useful if your objective doesn't have a convenient expression.

    objective_value(model)
    -5.999999998825352

    Dual variables

    Like YALMIP and CVX, JuMP allows you to recover the dual variables. In order to do that, the simplest method is to name the constraint you're interested in, for example, @constraint(model, bob, sum(v) == 1) and then, after the optimzation is done, call dual(bob). See Duality for more details.

    Reformulating problems

    Perhaps the biggest difference between JuMP and YALMIP and CVX is how far the package is willing to go in reformulating the problems you give to it.

    CVX is happy to reformulate anything it can, even using approximations if your solver cannot handle the problem.

    YALMIP will only do exact reformulations, but is still fairly adventurous, for example, being willing to reformulate a nonlinear objective in terms of conic constraints.

    JuMP does no such thing: it only reformulates objectives into objectives, and constraints into constraints, and is fairly conservative at that. As a result, you might need to do some reformulations manually, for which a good guide is the Modeling with cones tutorial.

    Vectorization

    In MATLAB, it is absolutely essential to "vectorize" your code to obtain acceptable performance. This is because MATLAB is a slow interpreted language, which sends your commands to fast libraries. When you "vectorize" your code you are minimizing the MATLAB part of the work and sending it to the fast libraries instead.

    There's no such duality with Julia.

    Everything you write and most libraries you use will compile down to LLVM, so "vectorization" has no effect.

    For example, if you are writing a linear program in MATLAB and instead of the usual constraints = [v >= 0] you write:

    for i = 1:n
    @@ -157,4 +157,4 @@
         x = randn(d, 1) + 1i * randn(d, 1);
         y = x * x';
         rho = y / trace(y);
    -end
    +end