Skip to content
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

Enh/options #110

Merged
merged 21 commits into from
Oct 14, 2018
Merged

Enh/options #110

merged 21 commits into from
Oct 14, 2018

Conversation

kalmarek
Copy link
Collaborator

@kalmarek kalmarek commented Sep 26, 2018

Would be great if someone could test it on the MOI side;

I took a simple route of extracting the Direct/Indirect type from options in optimize! (as it was done in MPB), but that could be easily changed to Optimizer (and SCSMathProgModel) parametrized by the type

Edit by mlubin@: Closes #94

@blegat
Copy link
Member

blegat commented Sep 26, 2018

I tried the tests with the Direct option:

diff --git a/test/MOIWrapper.jl b/test/MOIWrapper.jl
index 84aa941..2999cd1 100644
--- a/test/MOIWrapper.jl
+++ b/test/MOIWrapper.jl
@@ -14,7 +14,7 @@ MOIU.@model(SCSModelData,
             (MOI.ScalarAffineFunction,),
             (MOI.VectorOfVariables,),
             (MOI.VectorAffineFunction,))
-const optimizer = MOIU.CachingOptimizer(SCSModelData{Float64}(), SCS.Optimizer())
+const optimizer = MOIU.CachingOptimizer(SCSModelData{Float64}(), SCS.Optimizer(linear_solver=SCS.Direct))
 
 # linear9test needs 1e-3 with SCS < 2.0 and 5e-1 with SCS 2.0
 # linear2test needs 1e-4

and it passes all the tests while showing Lin-sys: sparse-direct in the log

@kalmarek
Copy link
Collaborator Author

btw. if tests fail on SCS-2.* because of instability You may always set alpha=1.9 and acceleration_lookback=1 to bring back the old behaviour

@kalmarek
Copy link
Collaborator Author

The whole code would be much cleaner if SCS(set_default_settings) wouldn't require the whole SCSData, but operate directly on SCSSettings. Any particular reason for this choice @bodono ?

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.

Thanks for making this update. Some comments below.

@@ -282,7 +284,15 @@ function MOI.optimize!(optimizer::Optimizer)
objconstant = optimizer.data.objconstant
c = optimizer.data.c
optimizer.data = nothing # Allows GC to free optimizer.data before A is loaded to SCS
sol = SCS_solve(SCS.Indirect, m, n, A, b, c, cone.f, cone.l, cone.qa, cone.sa, cone.ep, cone.ed, cone.p)

T = SCS.Indirect # the default method
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Please use a more descriptive variable name than T. Maybe linear_solver_method or just linear_solver.

src/c_wrapper.jl Outdated
end

for param in keys(opts)
# when dropping support for 0.6 could be replaced with setproperty!
Copy link
Member

Choose a reason for hiding this comment

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

What could be replaced exactly? To make sure this happens, you could use a VERSION if/else.

src/types.jl Outdated
@@ -37,7 +37,7 @@ SCSMatrix(m::ManagedSCSMatrix) =
SCSMatrix(pointer(m.values), pointer(m.rowval), pointer(m.colptr), m.m, m.n)


struct SCSSettings
mutable struct SCSSettings
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this change is valid. SCSSettings needs to mirror the C struct in order for the ccalls to be correct. mutable structs can't be used to mirror C structs AFAIK.

# linear9test needs 1e-3 with SCS < 2.0 and 5e-1 with SCS 2.0
# linear2test needs 1e-4
const config = MOIT.TestConfig(atol=1e-4, rtol=1e-4)
# linear9test needs 1e-3 with SCS < 2.0 and 5e-1 with SCS 2.0
Copy link
Member

@mlubin mlubin Sep 26, 2018

Choose a reason for hiding this comment

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

Why do we care about tolerances for an SCS version that we don't use anymore? (Not needed in the comment.)

Copy link
Member

Choose a reason for hiding this comment

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

The tolerance needed for SCS < 2.0 is mentionned to show that this is a regression

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 unlikely that this code will handle SCS < 2.0 in the future, so this isn't the right place to discuss regressions.

src/types.jl Outdated
@@ -37,7 +37,7 @@ SCSMatrix(m::ManagedSCSMatrix) =
SCSMatrix(pointer(m.values), pointer(m.rowval), pointer(m.colptr), m.m, m.n)


struct SCSSettings
mutable struct SCSSettings
normalize::Int # boolean, heuristic data rescaling: 1
Copy link
Member

Choose a reason for hiding this comment

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

Please update these comments to reflect that the default parameters are set by SCS_set_default_settings! (i.e., remove the values because we have no way to make sure they are correct).

src/c_wrapper.jl Outdated
@@ -86,6 +100,11 @@ end
# Take Ref{}s because SCS might modify the structs
for (T, lib) in zip([SCS.Direct, SCS.Indirect], [SCS.direct, SCS.indirect])
@eval begin

function SCS_set_default_settings!(::Type{$T}, data::Ref{SCSData})
Copy link
Member

Choose a reason for hiding this comment

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

Naming nit: The name implies modification, so JuMP style recommends dropping the ! from the name (http://www.juliaopt.org/JuMP.jl/latest/style.html#Use-of-!-1). This is also consistent with SCS_init, SCS_solve, and SCS_finish.

end
@testset "Continuous linear problems" begin
# AlmostSuccess for linear9 with SCS 2
MOIT.contlineartest(MOIB.SplitInterval{Float64}(optimizer), config, ["linear9"])
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reasonable parameter setting that gets linear9 passing?

Copy link
Member

Choose a reason for hiding this comment

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

We need to set tolerance to 5e-1 last time I tested but it seems a bit restrictive to set it for all tests.
linear9test(optimizer, MOIT.TestConfig(atol=0.5, rtol=0.5) could be run separately in the line below

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

 SCS.Optimizer(linear_solver=T, eps=1e-8))
 config = MOIT.TestConfig(atol=1e-5)

passes MOIT.contlineartest(MOIB.SplitInterval{Float64}(optimizer), config) with both Direct and Indirect solver;

btw. You need to add some tests for passing options to SCS.Optimizer. only playing with this allowed me to catch missing ; in the argument list.

Choose a reason for hiding this comment

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

I think I just ran into the same issue where SCS.Optimizer does not accept solver options.

@kalmarek
Copy link
Collaborator Author

if user supplies a wrong kwarg it will result in

SCSSettings(SCS.Indirect, eps=1e-12, epps=0.1)
ERROR: MethodError: no method matching _SCS_user_settings(::SCS.SCSSettings; epps=0.1, eps=1.0e-12)
Closest candidates are:
  _SCS_user_settings(::Any; normalize, scale, rho_x, max_iters, eps, alpha, cg_rate, verbose, warm_start, acceleration_lookback) at /home/kalmar/.julia/v0.6/SCS/src/types.jl:70 got unsupported keyword argument "epps"
....

I think it is informative enough

@mlubin
Copy link
Member

mlubin commented Sep 27, 2018

I think it is informative enough

Not really, see the style discussion here. Please at least add a TODO to improve the error message.

@bodono
Copy link
Contributor

bodono commented Sep 27, 2018

The whole code would be much cleaner if SCS(set_default_settings) wouldn't require the whole SCSData, but operate directly on SCSSettings. Any particular reason for this choice @bodono ?

I don't think there is a particularly good reason for that choice, and it should probably just take the settings struct, but changing it now would be breaking.

@kalmarek
Copy link
Collaborator Author

I think it is informative enough

Not really, see the style discussion here. Please at least add a TODO to improve the error message.

is try ... catch MethodError error("You probably supplied unrecognized option to SCS.Optimizer ") acceptable?

@kalmarek
Copy link
Collaborator Author

@bodono It'd be great if it could be changed the next release, but it's definitely not critical

@mlubin
Copy link
Member

mlubin commented Sep 27, 2018

is try ... catch MethodError error("You probably supplied unrecognized option to SCS.Optimizer ") acceptable?

  1. You can't catch specific error types. You have to catch all errors, check the type, and rethrow if it's not what you expected.

  2. This is not convincingly better than the MethodError you showed because it hides the name of the incorrect option.

@kalmarek
Copy link
Collaborator Author

julia> SCSSettings(SCS.Indirect, epps=0.1, e=0.3, eps=1e-12)
ERROR: ArgumentError: Unrecognized options passed to the SCSSolver: epps, e
Stacktrace:
....

src/types.jl Outdated
catch err
if err isa MethodError
SCS_kwargs = fieldnames(default_settings[])
kwargs = [err.args[1][i*2-1] for i in 1:(length(err.args[1]) ÷ 2)]
Copy link
Member

Choose a reason for hiding this comment

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

There are a number of ways that this code could stop working unintentionally, so please add tests. The structure of err could be changed across Julia versions or _SCS_user_settings could be changed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can @test_throws ArgumentError ... against misspelled options, but that's it.
_SCS_user_settings is an internal function, it won't change beyond our control (btw. why is SCSSettings exported? I had always assumed that user is not supposed to construct it?)

I'd use the standard MethodError which actually tells exactly which options were not recognized, but that clashes with the style guide. What are Your suggestions on handling this?

Copy link
Member

Choose a reason for hiding this comment

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

I can @test_throws ArgumentError ... against misspelled options, but that's it.

That would make good tests :)

it won't change beyond our control

yes but when we change it we might forget to change MOIWrapper.jl.

m = MathProgBase.ConicModel(s)
MathProgBase.loadproblem!(m, -obj, A, rowub, [(:NonNeg,1:3)],[(:NonNeg,1:5)])

@test_throws ArgumentError MathProgBase.optimize!(m)
Copy link
Member

Choose a reason for hiding this comment

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

Is there some way to test the text of the error message? That's pretty important in this case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Yes, @test_throws is probably not the way to do it. It may need a try/catch where you test the error message inside the catch and test that the catch block executed.

@ccoffrin
Copy link

ccoffrin commented Sep 28, 2018

Just as a general comment. There were some fairly big changes in the algorithm's performance since the last version. The change in the default behavior led my CI to hang indefinitely while waiting for SCS to converge.

In the end adding the parameter acceleration_lookback=1 resolved the issue. However, I don't think I would have been able to figure this out without Miles' assistance.

@kalmarek
Copy link
Collaborator Author

@ccoffrin its a known issue: cvxgrp/scs#93
the new (unreleased) version 2.1.0 in https://github.com/cvxgrp/scs/tree/2.1.0 tries to use L1 cost which alleviates the problem, but not fully;

alpha=1.9, acceleration_lookback=1 reverses SCS to pre-2.0 behaviour

update the attained precision
add "eps=1e-7" to SCSSolver which tests MPBWrapper codepaths responsible 
for cleaning options
@blegat blegat mentioned this pull request Sep 30, 2018
@kalmarek
Copy link
Collaborator Author

kalmarek commented Oct 8, 2018

I separated the option checking into sanatize_SCS_options function, there is no parsing of exceptions anymore (which was tad fragile);

please have a look again

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.

5 participants