JuliaNLSolvers / Optim.jl

Optimization functions for Julia
Other
1.11k stars 217 forks source link

Promotion of Int Vectors? #576

Closed iwelch closed 4 years ago

iwelch commented 6 years ago
julia> using Optim

julia> myfun(x)= (x[1]-2)^2 + (x[2]-3)^2 + ((x[1]-2)*(x[2]-3))^2;

julia> td = TwiceDifferentiable(myfun, [ 3, 3 ]; autodiff = :forward);
ERROR: InexactError()

Not a big deal, but it would probably make sense to avoid InexactErrors in these situations---especially because the value itself will be ignored, too, me thinks, but am not sure.

pkofod commented 6 years ago

Not a big deal, but it would probably make sense to avoid InexactErrors in these situations---especially because the value itself will be ignored, too, me thinks, but am not sure.

We might consider it. Arguably, an integer input is a mistake, as the methods we cover do not work with integers, so we can handle it by converting it to Float64. But what if you also provide bounds? And they're Float32, should we then assume the users meant Float32 or Float64 (that the initial point is then given as since integers are converted to Float64?)... It's just becomes a mess if we want to keep things flexible, and that's why I'd much rather teach people about the type system in Julia rather than guess what they mean all the time.

mohamed82008 commented 6 years ago

I think promote_type should work well in this case. If the result is still an Integer, it can default to Float64.

pkofod commented 6 years ago

I know we can do it like that, I’m only wondering if it’s worth the hassle from our side, when really the user should be telling US what they want us to do. As I said, I mmiggt be open to it, but I’m not convinced right now.

iwelch commented 6 years ago

I think you should promote whenever there is no chance that the user meant something else by it. So, I would not promote if an argument could be either the number of variables (Int) or a starting value (Float). I would promote if there is no such risk. if a user sets a starting value of 0, instead of 0.0, which is mathematically correct, of course, it should be fine.

my opinion is partly based on the fact that the error is not very descriptive. I know what "InexactError" is of course, but some will stumble over it. if you have an entry check like

@assert( eltype(x_init) == Float, "the initial point must be of type Float, not type $(eltype(x_init))")

it would be fine, too. But InexactError??

anriseth commented 6 years ago

Good warnings and error messages are important. I would prefer to let users do things I haven't considered myself, however, and maybe there are situations in the future where someone do want to optimise over integers (if they implement an integer programming algorithm)

Making assumptions on what the user really has in mind becomes increasingly complicated and error prone when you take into consideration arbitrary types. For example, we support complex numbers, so assuming 3 should be 3.0, rather than 3.0 + 0*im will ignore the imaginary axis by mistake.

iwelch commented 6 years ago

this sort of ambiguity is indeed a good argument against this promotion.

the counter argument is: what are the chances that a user means 3.0+0*im vs 3.0?

if integer algorithms would be supported, this would indeed be terrible. I think this argument is convincing--better not to promote. I would improve on the error message with the @assert, though.

pkofod commented 6 years ago

the counter argument is: what are the chances that a user means 3.0+0*im vs 3.0?

I agree, 99.99% of users mean Float64(0) if they write 0. It's just that if you want to promote integers to double floats, you have to make sure that it works everywhere or the users will really be confused. And all that checking and handling is more work and more maintenance, more testing and so on, so as I said: the easiest thing for Optim.jl is to let the users provide the correct types.

However, as I also said earlier. I'm open to handling it like this, it's just not my personal priority to work on it. Maybe later, or maybe someone else gets around to implementing it.

iwelch commented 6 years ago

jut got bit again. can you guess what did this?

julia> optimize( rosenbrock, [10,20], [-100,-100], [100,100], Fminbox{NelderMead}() )
ERROR: No default objective type for Optim.Fminbox{Optim.NelderMead}() and (rosenbrock, [10, 20], [-100, -100]).
Stacktrace:
 [1] optimize at /Users/ivo/.julia/v0.6/Optim/src/multivariate/optimize/interface.jl:80 [inlined]
 [2] optimize(::Function, ::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,1}, ::Optim.Fminbox{Optim.NelderMead}, ::Optim.Options{Float64,Void}) at /Users/ivo/.julia/v0.6/Optim/src/multivariate/optimize/interface.jl:77 (repeats 2 times)

yes, it is that the lower and upper bounds are integers. the error messages were completely baffling.

pkofod commented 6 years ago

Well, maybe I can easily do something about that, but yes, the error message is a bit weird.