Jump.jl: modeling with SI units (via Unitful.jl)

Created on 19 Jun 2018  路  3Comments  路  Source: jump-dev/JuMP.jl

Something that has been mentioned before in passing and might be worth discussing down the track: allow modeling with SI units using https://github.com/ajkeller34/Unitful.jl. It may be fairly trivial, I'm not sure.

DifferentialEquations.jl seems to allow this, for example here.

GPKit is a geometric programming toolkit in Python and it supports specification of units and automatically does dimensional analysis to convert or verify units in expressions/constraints. From the GPKit docs, an example of a variable declaration:

# Declare a variable, z, with units of meters, and a description
z = Variable("z", "m", "A variable called z with units of meters")

and a simple model:

# consider a block with dimensions x, y, z less than 1
# constrain surface area less than 1.0 m^2
x = Variable("x", "m")
y = Variable("y", "m")
z = Variable("z", "m")
S = Variable("S", 1.0, "m^2")
c = (2*x*y + 2*x*z + 2*y*z <= S)

(There are other ideas we could borrow from GPKit to make JuMP even more user friendly. I like the little solution tables it can print after a solve.)

enhancement extensions printing

Most helpful comment

You can do this by extending the @variable macro as follows

using JuMP
using Unitful
m = Model()
function unitvar(vref::JuMP.VariableRef, u::Unitful.FreeUnits)
    JuMP.GenericAffExpr(0.0 * u, vref => 1.0 * u)
end
struct Unit
    u::Unitful.FreeUnits
end
struct UnitVariable <: JuMP.AbstractVariable
    v::JuMP.ScalarVariable
    u::Unitful.FreeUnits
end
function JuMP.buildvariable(_error::Function, info::JuMP.VariableInfo, u::Unit)
    UnitVariable(JuMP.ScalarVariable(info), u.u)
end
function JuMP.addvariable(m::Model, v::UnitVariable, name::String="")
    vref = JuMP.addvariable(m, v.v, name)
    # add bridge to `m.moibackend` if its does not support constraints with Unitful coefficients
    unitvar(vref, v.u)
end
@variable m v Unit(u"m")
@show v + 2v + 1u"m" # -> 3.0 m v + 1.0 m

To support adding constraints such as @constraint m 2v + 1 <= 2 , you can simply create a constraint bridge that transforms constraints with functions of Unitful coefficient type to constraints where the coefficients are the values of the unitful quantities (note that you need https://github.com/JuliaOpt/MathOptInterface.jl/issues/397 to be is fixed for it to work with JuMP in non-Direct mode though).

Both the new constraint bridge and the @variable macro extension would fit nicely into a JuMP extension.
The extension would work nicely with other extension since you don't need to define a new model constructor or define a solvehook.

By the way this could be a nice example for the extensions doc don't you think ?

All 3 comments

You can do this by extending the @variable macro as follows

using JuMP
using Unitful
m = Model()
function unitvar(vref::JuMP.VariableRef, u::Unitful.FreeUnits)
    JuMP.GenericAffExpr(0.0 * u, vref => 1.0 * u)
end
struct Unit
    u::Unitful.FreeUnits
end
struct UnitVariable <: JuMP.AbstractVariable
    v::JuMP.ScalarVariable
    u::Unitful.FreeUnits
end
function JuMP.buildvariable(_error::Function, info::JuMP.VariableInfo, u::Unit)
    UnitVariable(JuMP.ScalarVariable(info), u.u)
end
function JuMP.addvariable(m::Model, v::UnitVariable, name::String="")
    vref = JuMP.addvariable(m, v.v, name)
    # add bridge to `m.moibackend` if its does not support constraints with Unitful coefficients
    unitvar(vref, v.u)
end
@variable m v Unit(u"m")
@show v + 2v + 1u"m" # -> 3.0 m v + 1.0 m

To support adding constraints such as @constraint m 2v + 1 <= 2 , you can simply create a constraint bridge that transforms constraints with functions of Unitful coefficient type to constraints where the coefficients are the values of the unitful quantities (note that you need https://github.com/JuliaOpt/MathOptInterface.jl/issues/397 to be is fixed for it to work with JuMP in non-Direct mode though).

Both the new constraint bridge and the @variable macro extension would fit nicely into a JuMP extension.
The extension would work nicely with other extension since you don't need to define a new model constructor or define a solvehook.

By the way this could be a nice example for the extensions doc don't you think ?

By the way this could be a nice example for the extensions doc don't you think ?

Yes. This is ridiculous. Hooray for a good abstraction.

Could be fun to try with https://github.com/IainNZ/RationalSimplex.jl too.

Was this page helpful?
0 / 5 - 0 ratings