Skip to content

Implement TimeLimit #808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 7, 2019
Merged

Implement TimeLimit #808

merged 10 commits into from
Aug 7, 2019

Conversation

remi-garcia
Copy link
Contributor

@remi-garcia remi-garcia commented Aug 1, 2019

Implement TimeLimit using the example of Silent #695

Note: for the tests I used Integers TimeLimit because I didn't know the right way to @test a float value

Copy link
Member

@odow odow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the default time limit be nothing? I don't think it should be 0.

I would expect it to be nothing unless set, like warm starts are.

@remi-garcia
Copy link
Contributor Author

I'll set it to nothing, I don't know why but I though 0 was the usual default value while in CPLEX it is 1e+75.

@codecov-io
Copy link

codecov-io commented Aug 1, 2019

Codecov Report

Merging #808 into master will decrease coverage by 3.34%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #808      +/-   ##
==========================================
- Coverage   94.21%   90.86%   -3.35%     
==========================================
  Files          59       66       +7     
  Lines        6892     7441     +549     
==========================================
+ Hits         6493     6761     +268     
- Misses        399      680     +281
Impacted Files Coverage Δ
src/Utilities/cachingoptimizer.jl 92.48% <ø> (ø) ⬆️
src/Test/UnitTests/attributes.jl 100% <100%> (ø) ⬆️
src/attributes.jl 85.71% <100%> (+0.17%) ⬆️
src/Utilities/sets.jl 25% <0%> (-75%) ⬇️
src/Bridges/lazy_bridge_optimizer.jl 65.16% <0%> (-32.27%) ⬇️
src/Bridges/bridge_optimizer.jl 62.21% <0%> (-29.61%) ⬇️
src/Bridges/Constraint/single_bridge_optimizer.jl 44.44% <0%> (-15.56%) ⬇️
src/Bridges/Constraint/det.jl 96.38% <0%> (-2.35%) ⬇️
src/Bridges/Constraint/geomean.jl 98.33% <0%> (-1.67%) ⬇️
src/Utilities/functions.jl 94.52% <0%> (-0.82%) ⬇️
... and 22 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f01367a...ecefba8. Read the comment docs.

Copy link
Member

@mlubin mlubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests do not check that the solver returns the TIME_LIMIT status when the time limit is hit. This is actually pretty challenging to do correctly because some solvers could solve a tiny problem very fast and return OPTIMAL before checking the time limit. However, it's worth a try or a TODO.

@remi-garcia
Copy link
Contributor Author

I made the following changes:
TimeLimit -> TimeLimitSec
Default value: 0 -> nothing
Tests: == -> isapprox
Tests: # -> #.0

TODO:

The tests do not check that the solver returns the TIME_LIMIT status when the time limit is hit. This is actually pretty challenging to do correctly because some solvers could solve a tiny problem very fast and return OPTIMAL before checking the time limit. However, it's worth a try or a TODO.

@remi-garcia
Copy link
Contributor Author

I made the following changes:

  • timelimitsec() -> time_limit_sec()
  • isapprox(., 0.0) -> . == 0.0
  • isapprox(., 1.0) -> . ≈ 1.0
  • English corrections and small changes

Still TODO:

The tests do not check that the solver returns the TIME_LIMIT status when the time limit is hit. This is actually pretty challenging to do correctly because some solvers could solve a tiny problem very fast and return OPTIMAL before checking the time limit. However, it's worth a try or a TODO.

Copy link
Member

@mlubin mlubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good now.
The TODO part could be left in the code as a TODO or in a new issue. However, it is extremely likely that if we do not have a test for returning the TIME_LIMIT status, one or more solvers will not implement this correctly.

@@ -14,6 +14,7 @@ end
# `UniversalFallback` needed for `MOI.Silent`
mock = MOIU.MockOptimizer(MOIU.UniversalFallback(MOIU.Model{Float64}()))
MOI.set(mock, MOI.Silent(), true)
MOI.set(mock, MOI.TimeLimitSec(), nothing)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default value, so why is the set needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be remove. My bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, removing that line breaks. nothing is the default value but I didn't set it in first place. I put that line back for now.
I don't know how to set a default value, and I think Silent() default value isn't set too. I'll be looking into it soon.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What breaks? This needs to be resolved before we can merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When get() is used on TimeLimitSec() instead of returning nothing as default value it throws an error. That happened in src/Test/UnitTests/attributes.jl:
KeyError: key MathOptInterface.TimeLimitSec() not found

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have to make changes in src/Utilities/mockoptimizer.jl to set default values

Indeed, this requires the internal model to always support TimeLimitSec. You can either not set the default (like it is currently done for Silent) or only set it in case the internal model supports it (you can check that with supports).
I would rather do the first option (not setting the default) as the other behavior is somewhat weird, setting the optimizer attributes of ModelLike passed to MockOptimizer is a rather suprising behavior

Copy link
Contributor Author

@remi-garcia remi-garcia Aug 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would be strange to put default value is in docs but not testing for it because it's not implemented in MOI side.
I had issues with the use of supports since it returns an error instead of false for Silent() and TimeLimitSec():
https://github.com/JuliaOpt/MathOptInterface.jl/blob/ab2d0f05205a81c3848f9f1d870b75332b1bddd2/src/attributes.jl#L155-L169

To be honest I don't know how to solve that without some important changes as this bad try catch I did in last push.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not implemented in MOI side

MockOptimizer is just a utility for testing so I don't think it is an issul if it does not have the default values for Silent and TimeLimitSec.
If new optimizer attributes are defined outside of MOI, MockOptimizer won't be able to have the right default values. It's case is a bit specific since it supports any optimizer attributes (when used with UniversalFallback), even some that may not defined in MOI. But it actually completely ignores their value.
That's not the case for solvers that only support specific attributes, take their value into account and should have the correct default values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is: if I remove default from MockOptimizer then MOI can't have a test to check if Optimizers implement defaults correctly. If I didn't understand that well then I don't see why MockOptimizer should have this feature but if I'm right then I believe this feature is quite important.

I'll push without the default values.

Copy link
Member

@blegat blegat Aug 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I remove default from MockOptimizer then MOI can't have a test to check if Optimizers implement defaults correctly.

You can set the attribute's value to its default before running the tests as it is done for Silent here:
https://github.com/JuliaOpt/MathOptInterface.jl/blob/42cdc3454cdb88345da0adb9cce2a57497c2fad4/test/Test/unit.jl#L15-L16
Of course actual solvers shouldn't do that but for the MockOptimizer it's ok to mock the test

@remi-garcia
Copy link
Contributor Author

remi-garcia commented Aug 1, 2019

I'll add a TODO in the code for now but I'm not sure where is the right place to add it since I didn't find any other test for Termination status.

@odow
Copy link
Member

odow commented Aug 6, 2019

Looking good @remi-garcia. Sorry for the back and forth on the default options.

@remi-garcia
Copy link
Contributor Author

I'm actually learning so much doing this so I really don't mind. Thank you for taking so much time helping me with this PR.

@mlubin mlubin merged commit 0775536 into jump-dev:master Aug 7, 2019
@remi-garcia remi-garcia deleted the timelimit branch August 7, 2019 10:02
@frapac
Copy link
Contributor

frapac commented Aug 13, 2019

@remi-garcia Thanks for implementing this! Just a quick question: does the time limit concerns the CPU time passed in the solver, or the real time?

@blegat
Copy link
Member

blegat commented Aug 13, 2019

I think it would be better to use the CPU time passed in the solver

@remi-garcia
Copy link
Contributor Author

I should have precise that in docs, sorry.
From my perspective it was real time since I wanted it to replace CPX_PARAM_TILIM for CPLEX.

Maybe we should precise that in /src/attributes.jl and duplicate it for CPU time. Or as CPLEX we could have a second parameter with 2 values CPUTime and RealTime.

@blegat
Copy link
Member

blegat commented Aug 13, 2019

For Mosek, it's unclear if it's CPUTime or REALTime (see https://docs.mosek.com/8.1/rmosek/parameters.html#mosek.dparam.optimizer_max_time).
cc @ulfworsoe

@mlubin
Copy link
Member

mlubin commented Aug 13, 2019

I understood the limit as wall clock time (real time). We need to clarify this in the docs.

I'm not sure how essential it is to have a second solver-independent option with a CPU time limit, that's a bit esoteric.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants