-
-
Notifications
You must be signed in to change notification settings - Fork 399
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
Add the constructvariable!/variabletype functions #1029
Conversation
This allows extensions to use the @variable macro to create other types of variables
Cool. I like the first syntax FWIW. Could also be |
It's hard to keep track of what the |
I think this needs to be done in conjunction with #692 @variable(m, x[i,j] in Int for i in I, j in J if cond(i,j))
@variable(m, x[i,j] in [l, u] for i in I, j in J if cond(i,j))
@variable(m, x[i,j] in {0} | [l, u] for i in I, j in J if cond(i,j))
@variable(m, x[i,j] >= 0 in Poly(X) for i in I, j in J if cond(i,j)) |
#692 is going to need a discussion at the developers meetup, and I'm not super convinced about it. |
Codecov Report
@@ Coverage Diff @@
## master #1029 +/- ##
==========================================
- Coverage 90.56% 88.57% -1.99%
==========================================
Files 18 18
Lines 4610 4500 -110
==========================================
- Hits 4175 3986 -189
- Misses 435 514 +79
Continue to review full report at Codecov.
|
I have added a developer documentation of @odow I also like the |
src/macros.jl
Outdated
# passed to `constructvariable!`. | ||
# * The keyword arguments start, objective, inconstraints, coefficients, basename, lowerbound, upperbound, category may not be passed as is to | ||
# `constructvariable!` since they may be altered by the parsing of `expr` and we may need to pass it pointwise if it is a container since | ||
# `constructvariable!` is called separately for each variable of the container. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you give a trivial, e.g. @variable(m, x >= 0)
and nontrivial example, e.g., @variable(m, x[1:N,1:N], SDP, Poly())
of how the macro creates calls to constructvariable!
?
src/macros.jl
Outdated
|
||
variabletype(m::Model, t::Symbol) = variabletype(m, Val{t}) | ||
function constructvariable!(m::Model, t::Symbol; extra_kwargs...) | ||
constructvariable!(m, Val{t}; extra_kwargs...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm slightly worried about the overhead in dynamic dispatch here if we're creating 1,000,000 :Cont
variables in a loop. Are there any performance regressions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there might be since the method called cannot be determined only be the type of the arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about creating the Val{:Cont}
(etc) types inside the macro when the variable category is known?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we might as well modify category
directly. The whole point of this method is to support specifying a Symbol
in extra
but I start to think that this is not a good idea. In PolyJuMP for example since I will create the Poly
type I might just as well ask to give Poly
instead of :Poly
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't see a need to support symbols outside of the keyword arguments. Either @variable(m, x, Int)
or @variable(m, x, category=:Int)
.
src/macros.jl
Outdated
@@ -856,8 +842,7 @@ variable_error(args, str) = error("In @variable($(join(args,","))): ", str) | |||
# * The `SDP` and `Symmetric` positional arguments in `extra` will not be passed to `constructvariable!`. Instead, | |||
# * the `Symmetric` argument will check that the container is symmetric and only allocate one variable for each pair of non-diagonal entries. | |||
# * the `SDP` argument will do the same as `Symmetric` but in addition it will specify that the variables created belongs to the SDP cone in the `varCones` field of the model. | |||
# Moreover, if a category is passed in `extra` not as a symbol (e.g. `Bin` instead of `:Bin`), it will be transformed to a symbol before being | |||
# passed to `constructvariable!`. | |||
# Moreover, if a category is passed in `extra`, it will be passed using the `category` keyword to `constructvariable!`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you list the "special" categories that we recognize?
src/macros.jl
Outdated
# if isdefined(Core, :Inference) | ||
# however, since there could be symbols in extra, which are only thansformed with Val after, the type could be not inferrable | ||
vartype = :( variabletype($m, $(extra...)) ) | ||
if isdefined(Core, :Inference) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this kosher?
The |
I'd rather have |
Looks pretty good to me, thanks for addressing all the comments. Could you check for performance regressions by running |
I had a big 0.5x performance penalty because I was passing
|
Does the new change to positional arguments mean that anyone who implements |
No you can implement the second version without these 3 arguments. |
Is that explained somewhere in the comments? |
Now it is :) |
Seems good now, but tests are failing. |
I use the @variable x[i=1:0] == i will be a container of @variable x[i=1:0] == 0 will be a container of |
Why would the type of the variable depend on the value of the bounds? |
For example for polynomials, for |
@blegat, that syntax isn't very consistent with how we use |
Sorry I meant |
Still |
I could do @variable(m, p, Poly(X))
@variable(m, p, SOSPoly(x)) equivalent to @variable(m, p >= 0, SOSPoly(x)) -> instead of @variable(m, p >= 0, Poly(X)) What do you prefer then:
|
The first option is much simpler and preferable unless there's a good reason for the second option. |
I have implemented the first option in 088c84b :) |
To make sure I'm understanding things, you will implement implement |
Yes exactly :) (although technically it will be |
Ok, makes sense. It would be nice if we removed |
Final request before merging. Could you add a test that implements a trivial extension and calls, e.g., |
I'll merge this tomorrow if there are no further objections. @joehuchette |
Can we hold off merging for a day or two, until I can review in detail? |
@joehuchette, sure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
const EMPTYSTRING = "" | ||
|
||
variable_error(args, str) = error("In @variable($(join(args,","))): ", str) | ||
|
||
# @variable(m, expr, extra...; kwargs...) | ||
# where `extra` is a list of extra positional arguments and `extra_kwargs` is a list of keyword arguments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra_kwargs
--> kwargs
This allows extensions to use the @variable macro to create other types
of variables. For example, in PolyJuMP, we could add the syntax
where X is the vector of monomials