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

[Utilities] maintain order of variables in default_copy_to #2495

Merged
merged 10 commits into from
Jun 21, 2024

Conversation

odow
Copy link
Member

@odow odow commented May 3, 2024

This PR is an investigation of what we would need to implement to close #2493. It is still very rough around the edges; I need to clean it up and profile for performance, but as a demo, the case from #2493 now works:

julia> main()
NAME
ROWS
 N  OBJ
COLUMNS
    x         OBJ       1
    y         OBJ       1
RHS
RANGES
BOUNDS
 FR bounds    x
 LO bounds    y         0
 PL bounds    y
ENDATA

TODOs

@odow
Copy link
Member Author

odow commented May 3, 2024

So this, somewhat surprisingly, didn't break any tests. I don't know if that is a good thing or a bad thing... I guess it's because we're completely agnostic to the ordering of columns, so we always use index_map.

@odow
Copy link
Member Author

odow commented May 4, 2024

Okay there are a few failures to look at in solver-tests.

@odow odow force-pushed the od/ordered-variables branch from 3c92105 to 73f3f52 Compare May 29, 2024 03:29
@odow odow force-pushed the od/ordered-variables branch from 73f3f52 to 401e9db Compare June 12, 2024 22:33
@odow
Copy link
Member Author

odow commented Jun 12, 2024

using Revise
import MathOptInterface as MOI
function build_src(M, N, p)
    src = MOI.Utilities.Model{Float64}()
    x = MOI.add_variables(src, N)
    indices = unique(rand(1:N, round(Int, p * N)))
    ci = MOI.add_constraint.(src, x[indices], MOI.GreaterThan(0.0))
    indices = unique(rand(1:N, round(Int, p * N)))
    ci = MOI.add_constraint.(src, x[indices], MOI.LessThan(1.0))
    for _ in 1:M
        i = rand(1:N)
        indices = i:min(N, i + 10)
        MOI.add_constraint(
            src,
            MOI.VectorOfVariables(x[indices]),
            MOI.SecondOrderCone(length(indices)),
        )
    end
    return src
end

julia> src = build_src(500_000, 1_000_000, 0.5)
MOIU.Model{Float64}
├ ObjectiveSense: FEASIBILITY_SENSE
├ ObjectiveFunctionType: MOI.ScalarAffineFunction{Float64}
├ NumberOfVariables: 1000000
└ NumberOfConstraints: 1287703
  ├ MOI.VectorOfVariables in MOI.SecondOrderCone: 500000
  ├ MOI.VariableIndex in MOI.GreaterThan{Float64}: 393979
  └ MOI.VariableIndex in MOI.LessThan{Float64}: 393724

master

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.415108 seconds (2.18 M allocations: 468.760 MiB, 7.19% gc time)

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.462140 seconds (2.18 M allocations: 485.807 MiB, 7.48% gc time)

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.292704 seconds (2.18 M allocations: 485.807 MiB)

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.426020 seconds (2.18 M allocations: 468.760 MiB, 8.28% gc time)

This PR

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.684707 seconds (3.15 M allocations: 598.370 MiB, 9.53% gc time)

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.691145 seconds (3.15 M allocations: 598.370 MiB, 8.83% gc time)

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.664689 seconds (3.15 M allocations: 598.370 MiB, 8.72% gc time)

julia> dest = MOI.Utilities.Model{Float64}(); GC.gc(); @time MOI.copy_to(dest, src);
  1.805403 seconds (3.15 M allocations: 598.370 MiB, 8.82% gc time)

So things are a little slower, but that is as could be expected.

A few hundred ms slowdown for really large problems (10^6 variables and constraints) seems reasonable to ensure that we get ordered variables.

@odow odow changed the title WIP: [Utilities] maintain order of variables in default_copy_to [Utilities] maintain order of variables in default_copy_to Jun 12, 2024
@odow
Copy link
Member Author

odow commented Jun 12, 2024

@odow
Copy link
Member Author

odow commented Jun 12, 2024

So there are a bunch of solver-test failures that look problematic.

@odow
Copy link
Member Author

odow commented Jun 12, 2024

Let's just see how many are because of this PR: https://github.com/jump-dev/MathOptInterface.jl/actions/runs/9491359380

@odow
Copy link
Member Author

odow commented Jun 13, 2024

I think a bunch might be because of #2508

@odow odow mentioned this pull request Jun 13, 2024
@odow odow force-pushed the od/ordered-variables branch from 1409c2d to 00b22bf Compare June 13, 2024 03:13
@odow
Copy link
Member Author

odow commented Jun 13, 2024

@odow
Copy link
Member Author

odow commented Jun 13, 2024

OSQP failure is unrelated: osqp/OSQP.jl#126

@odow
Copy link
Member Author

odow commented Jun 14, 2024

The DSDP failure is suspicious: test_conic_SecondOrderCone_out_of_order

I assume it's because the variables are out of order, so we end up bridging it with some slack variables, which increases the problem size. Previously, we would have added the constraint as a variable, permuting the original variable order.

@blegat
Copy link
Member

blegat commented Jun 20, 2024

I assume it's because the variables are out of order, so we end up bridging it with some slack variables, which increases the problem size. Previously, we would have added the constraint as a variable, permuting the original variable order.

Yes, I think we can ignore it

@odow
Copy link
Member Author

odow commented Jun 20, 2024

My discussion with @blegat after the developer call is: this seems reasonable. There might be performance edge cases we haven't considered, but this is really a single sort, so it likely isn't the bottleneck. Fixing the order of variables is more important.

@odow odow merged commit ad45651 into master Jun 21, 2024
16 checks passed
@odow odow deleted the od/ordered-variables branch June 21, 2024 23:26
@odow
Copy link
Member Author

odow commented Jun 24, 2024

So I didn't run solver-tests after removing the dead code.

BilevelJuMP was using _try_constrain_variables_on_creation:

https://github.com/joaquimg/BilevelJuMP.jl/blob/954467f72a93b3cd37b2846971dfbfd458019af8/src/moi_utilities.jl#L70

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.

Order of columns during copy_to
2 participants