-
Notifications
You must be signed in to change notification settings - Fork 121
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
(WIP) Allow variables to carry constraints, custom variable types #313
Closed
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ericphanson
force-pushed
the
custom_variable
branch
from
August 21, 2019 12:25
1c21c02
to
b1fa741
Compare
Something like this might be nice to hook into MOI's constrained variables (http://www.juliaopt.org/MathOptInterface.jl/stable/apireference/#MathOptInterface.add_constrained_variable), once #330 is done. |
This was referenced Jan 14, 2020
Continued in #358 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Remaining things to do:
This PR introduces an
AbstractVariable{T}
type with a corresponding interface. User-defined types can implement the interface to have custom variable types which can be dispatched on in user-code. The interface consists ofvalue
,value!
: get or set the numeric value of the variable.value
should returnnothing
when no numeric value is set.vexity
,vexity!
: get or set thevexity
of the variable. Thevexity
should beAffineVexity()
unless the variable has beenfix!
'd, in which case it isConstVexity()
.sign
,vartype
, andconstraints
: get theSign
,VarType
(a new enum, for binary, integer, or continuous variables), numeric type, and a (possibly empty) vector of constraints which are to be applied to any problem in which the variable is used.Optionally, also users can also implement
sign!
,vartype!
, andadd_constraint!
to allow users to modify those values or add a constraint to a list of constraints which are applied to any problem in which the variable is used.Subtypes of
AbstractVariable
are expected to have fields (orgetproperty
overloads) forhead
,id_hash
andsize
, as those are expected of allAbstractExpr
's. Future work could be to clarify theAbstractExpr
interface. Moreover,AbstractVariable
's need to add themselves to Convex's global registrar of variables, and set their own hash. This sounds confusing but I will add several examples to the docs. Moreover, subtypingAbstractVariable
is definitely not necessary for casual use (we got this far without it anyway!).The type parameter
T
gives theeltype
of the variable. This allows variables which accept e.g.BigFloats
to be created, instead of implicitly assuming variables are allFloat64
. TheProblem
companion to this change is #289.The venerable
Variable
is the first user of this interface. The newconstraints
andvartype
methods lets us finish what we started in #299: getting rid ofsets
. The problem withsets
is that it tried to serve several orthogonal purposes simultaneously while at the same time, it wasn't always very clear what you could put in there that would have an effect.sets
was populated by:fixed
to indicate a variable was constant; this was changed in Allow callingfix!
twice in a row #299 by using thevexity
to indicate constantness.sets
was also used to add one particular constraint to a variable: semidefiniteness. This is replaced by the much more flexibleconstraints
(andadd_constraint!
) method. Now, aVariable
can carry around arbitrary constraints which automatically get applied to any problem the variable is in, just like:semidefinite
insets
did.sets
was finally used to indicate if a variable was binary, integer, or continuous. This was replaced byvartype
which uses an enum. I prefer the enum because it makes clear what the possible choices are, whereas when entering symbols, it wasn't immediately obvious (e.g.:bin
or:binary
?)What is the benefit? One nice thing you can do now is
Then later,
p = probabilityvector(3)
can be used like any other variable, but the constraints of having non-negative entries which add to 1 will be automatically applied to any problem it is used in. This allows very simple implementations of DSLs.The introduction of
AbstractVariable
allows more ambitious extensions as well. Since custom types can subtypeAbstractVariable
, variables can be used in dispatch, or even be used as callable types. Continuing with the probability example, let's say I often use my probability vectors for getting the expectation value of other variables, and I want to use function notation for this. I could defineAnd then I can use the new type freely in Convex problems. E.g.
I've been experimenting with a similar DSL for quantum information theory in https://github.com/ericphanson/QuantumSDPs.jl.
These changes should be entirely non-breaking (as long as user code was not dipping into
Variable
fields too much). I re-implemented the old constructors that accept symbols forset
, and translate them to the new variable type. (These could be deprecated at some point). Many of the internals changes are simply changing e.g.x.sign
tosign(x)
, to use the interface instead.Lines 310-312 of
variables.jl
contain the core logic change; instead of adding constraints for hardcoded symbols that correspond to constraints, we just apply each constraint given inconstraints(x)
. Most of the lines of code changed are new constructors, fallback constructors for the oldset
behavior, and tests for the constructors.