Skip to content

Commit a095e27

Browse files
Merge pull request #451 from SciML/faq
Add an FAQ page
2 parents 92f75c9 + a60388e commit a095e27

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

docs/pages.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pages = ["index.md",
1212
"API/solve.md",
1313
"API/optimization_solution.md",
1414
"API/modelingtoolkit.md",
15+
"API/FAQ.md",
1516
],
1617
"Optimizer Packages" => [
1718
"BlackBoxOptim.jl" => "optimization_packages/blackboxoptim.md",

docs/src/API/FAQ.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Frequently Asked Questions
2+
3+
## The Solver Seems to Violate Constraints During the Optimization, Causing `DomainError`s, What Can I Do About That?
4+
5+
During the optimization, optimizers use slack variables to relax the solution to the constraints. Because of this,
6+
there is no guarentee that for an arbitrary optimizer the steps will all satisfy the constraints during the
7+
optimization. In many cases, this can cause one's objective function code throw a `DomainError` if it is evaluated
8+
outside of its acceptable zone. For example, `log(-1)` gives:
9+
10+
```
11+
julia> log(-1)
12+
ERROR: DomainError with -1.0:
13+
log will only return a complex result if called with a complex argument. Try log(Complex(x)).
14+
```
15+
16+
To handle this, one should not assume that the variables will always satisfy the constraints on each step. There
17+
are three general ways to handle this better:
18+
19+
1. Use NaNMath.jl
20+
2. Process variables before domain-restricted calls
21+
3. Use a domain transformation
22+
23+
NaNMath.jl gives alternative implementations of standard math functions like `log` and `sqrt` in forms that do not
24+
throw `DomainError`s but rather return `NaN`s. The optimizers will be able to handle the NaNs gracefully and recover,
25+
allowing for many of these cases to be solved without further modification. Note that this is done [internally in
26+
JuMP.jl, and thus if a case is working with JuMP and not Optimization.jl
27+
](https://discourse.julialang.org/t/optimizationmoi-ipopt-violating-inequality-constraint/92608/) this may be the
28+
reason for the difference.
29+
30+
Alternatively, one can pre-process the values directly. For example, `log(abs(x))` is guaranteed to work. If one does
31+
this, there are two things to make note of. One is that the solution will not be transformed, and thus the transformation
32+
should be applied on `sol.u` as well. I.e., the solution could fine an optima for `x = -2`, and one should manually
33+
change this to `x = 2` if the `abs` version is used within the objective function. Note that many functions for this will
34+
introduce a disocontinuity in the derivative which can effect the optimization process.
35+
36+
Finally and relatedly, one can write the optimization with domain transformations in order to allow the optimization to
37+
take place in the full real set. For example, instead of optimizing `x in [0,Inf]`, one can optimize `exp(x) in [0,Inf]`
38+
and thus `x in [-Inf, Inf]` is allowed without any bounds. To do this, you would simply add the transformations to the
39+
top of the objective function:
40+
41+
```julia
42+
function my_objective(u)
43+
x = exp(u[1])
44+
# ... use x
45+
end
46+
```
47+
48+
When the optimization is done, `sol.u[1]` will be `exp(x)` and thus `log(sol.u[1])` will be the optimal value for `x`.
49+
There exist packages in the Julia ecosystem which make it easier to keep track of these domain transformations and their
50+
inverses for more general domains. See [TransformVariables.jl](https://github.com/tpapp/TransformVariables.jl) and
51+
[Bijectors.jl](https://github.com/TuringLang/Bijectors.jl) for high level interfaces for this.
52+
53+
While this can allow an optimization with constraints to be rewritten as one without constraints, note that this can change
54+
the numerical properties of the solve which can either improve or decrease the numerical stability in a case-by-case
55+
basis. Thus while a solution, one should be aware that it could make the optimization more difficult in some cases.
56+
57+
## What are the advantages and disadvantages of using the ModelingToolkit.jl or other symbolic interfaces (JuMP)?
58+
59+
The purely numerical function interfaces of Optimization.jl has its pros and cons. The major pro of the direct
60+
Optimization.jl interface is that it can take arbitrary Julia programs. If you have an optimization defined over a
61+
program, like a Neural ODE or something that calls out to web servers, then these advanced setups rarely work within
62+
specialized symbolic environments for optimization. Direct usage of Optimization.jl is thus the preferred route for
63+
this kind of problem, and is the popular choice in the Julia ecosystem for these cases due to the simplicity of use.
64+
65+
However, symbolic interfaces are smart, and they may know more than you for how to make this optimization faster.
66+
And symbolic interfaces are willing to do "tedious work" in order to make the optimization more efficient. For
67+
example, the ModelingToolkit integration with Optimization.jl will do many simplifications when `structural_simplify`
68+
is called. One of them is tearing on the constraints. To understand the tearing process, assume that we had
69+
nonlinear constraints of the form:
70+
71+
```julia
72+
0 ~ u1 - sin(u5) * h,
73+
0 ~ u2 - cos(u1),
74+
0 ~ u3 - hypot(u1, u2),
75+
0 ~ u4 - hypot(u2, u3),
76+
```
77+
78+
If these were the constraints, one can write `u1 = sin(u5) * h` and substitute `u1` for this value in the objective
79+
function. If this is done, then `u1` does not need to be solved for, the optimization has one less state variable and
80+
one less constraint. One can continue this process all the way to a bunch of functions:
81+
82+
```julia
83+
u1 = f1(u5)
84+
u2 = f2(u1)
85+
u3 = f3(u1, u2)
86+
u4 = f4(u2, u3)
87+
```
88+
89+
and thus if the objective function was the function of these 5 variables and 4 constraints, ModelingToolkit.jl will
90+
transform it into system of 1 variable with no constraints, allowing unconstrained optimization on a smaller system.
91+
This will both be faster and numerically easier.
92+
93+
[JuMP.jl](https://jump.dev/JuMP.jl/stable/) is another symbolic interface. While it does not include these tearing
94+
and symbolic simplification passes, it does include the ability to specialize the solution process. For example,
95+
it can treat linear optimization problems, quadratic optimization problem, convex optimization problems, etc.
96+
in specific ways that are more efficient than a general nonlinear interface. For more information on the types of
97+
special solves that are allowed with JuMP, see [this page](https://jump.dev/JuMP.jl/stable/installation/#Supported-solvers).

0 commit comments

Comments
 (0)