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

[Bridges] add IntegerToZeroOneBridge #2205

Merged
merged 5 commits into from
Jul 2, 2023
Merged

[Bridges] add IntegerToZeroOneBridge #2205

merged 5 commits into from
Jul 2, 2023

Conversation

odow
Copy link
Member

@odow odow commented Jun 12, 2023

Closes #2202

Basic

  • Create a new file in src/Bridges/XXX/bridges
  • Define the bridge, following existing examples. The name of the bridge
    struct must end in Bridge
  • Check if your bridge can be a subtype of MOI.Bridges.Constraint.SetMapBridge
  • Define a new const that is a SingleBridgeOptimizer wrapping the
    new bridge. The name of the const must be the name of the bridge, less
    the Bridge suffix
  • include the file in src/Bridges/XXX/bridges/XXX.jl
  • If the bridge should be enabled by default, add the bridge to
    add_all_bridges at the bottom of src/Bridges/XXX/XXX.jl

Tests

  • Create a new file in the appropriate subdirectory of tests/Bridges/XXX
  • Use MOI.Bridges.runtests to test various inputs and outputs of the
    bridge
  • If, after opening the pull request to add the bridge, some lines are not
    covered by the tests, add additional bridge-specific tests to cover the
    untested lines.

Documentation

  • Add a docstring which uses the same template as existing bridges.
  • Add the docstring to docs/src/submodules/Bridges/list_of_bridges.md

Final touch

If the bridge depends on run-time values of other variables and constraints in
the model:

  • Implement MOI.Utilities.needs_final_touch(::Bridge)
  • Implement MOI.Utilities.final_touch(::Bridge, ::MOI.ModelLike)
  • Ensure that final_touch can be called multiple times in a row

ret = MOI.Utilities.get_bounds(model, T, bridge.x)
if ret === bridge.last_bounds
return nothing # final_touch already called
elseif ret[1] == typemin(T) || ret[2] == typemax(T)
Copy link
Member

@blegat blegat Jun 13, 2023

Choose a reason for hiding this comment

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

We should probably have a utility for that shared with SplitInterval and other bridges doing this like is_infinity. In Interval we take care of Int where we never one to consider no bound while we don't do it here. At least it would make sure we are consistent

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't understand the SplitInterval reference. The SplitInterval bridge doesn't rely on a finite domain, it works with one-sided intervals. In comparison, we can't bridge an open set to ZeroOne (unless we pick a big M and do a 20 or 30 bit expansion?).

push!(bridge.y, y)
push!(f.terms, MOI.ScalarAffineTerm(-(T(2)^(i - 1)), y))
end
bridge.ci = MOI.add_constraint(model, f, MOI.EqualTo{T}(lb))
Copy link
Member

Choose a reason for hiding this comment

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

The variable bridge spirit would be to substitute x. Here it seems to be a bad idea because it x is a big sum.
This is like bridge a constrained variables x in Int by first adding the variable free and constraining it, then functionizing it and then slack bridge and then variable bridge for the slack. I'm wondering if there could be a nice way to implement this as a variable bridge but defaulting it to be used like that while allowing the user to have x be substituted as well.

Copy link
Member

Choose a reason for hiding this comment

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

Could you just drop a comment that it would more naturally be implemented as a variable bridge but we don't want to substitute every occurence of x so that's why we do it as a constraint bridge ?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm wondering if there could be a nice way to implement this as a variable bridge

That would only be necessary for a solver supports only binary variables and not real. We don't really have any current examples, although @ccoffrin might be interested for future quantum annealing formulations. (They have some pretty specific structure restrictions though, which mean doing it naively might be the wrong thing to do.)

@odow odow force-pushed the od/integer-to-zeroone branch from fbb830b to 5fcee87 Compare June 22, 2023 23:05
@odow
Copy link
Member Author

odow commented Jun 23, 2023

Is there anything else to do here?

@odow odow merged commit dab02e5 into master Jul 2, 2023
@odow odow deleted the od/integer-to-zeroone branch July 2, 2023 23:37
@odow odow mentioned this pull request Jul 2, 2023
3 tasks
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.

IntegerToZeroOne bridge
3 participants