import JuMPChance, Distributions m = JuMPChance.ChanceModel() JuMPChance.@indepnormal(m, x, mean=0, var=1) JuMP.@variable(m, z) JuMP.@objective(m, Min, z) JuMP.@constraint(m, z*x >= -1, with_probability=0.95) JuMP.solve(m, method=:Reformulate, silent=true) isapprox( JuMP.getvalue(z), -1/Distributions.quantile(Distributions.Normal(0,1),0.95) ) macro indepnormal(m, x, mean, var) m, x, mean, var end m, x, mean, var = @indepnormal(m, x, mean=1, var=1) quote $x = IndepNormal($m,$mean,$var,$(string(x))) end m = esc(m) mean = esc(mean.args[2]) var = esc(var.args[2]) quote $(esc(x)) = IndepNormal($m,$mean,$var,$(string(x))) end m, x, mean, var = @indepnormal(m, ω[i=1:4,j=1:3], mean=1, var=1) @show m @show x @show mean @show var; dump(x) quote $x = IndepNormal($m,$mean,$var,$(string(x))) end ############################################################################### # buildrefsets # Unexported. Takes as input an object representing a name, associated index # sets, and conditions on those sets, for example # buildrefsets(:(x[i=1:3,[:red,:blue]],k=S; i+k <= 6)) # Used internally in macros to build JuMPContainers and constraints. Returns # refcall: Expr to reference a particular element, e.g. :(x[i,j,k]) # idxvars: Index names used in referencing, e.g.g {:i,:j,:k} # idxsets: Index sets for indexing, e.g. {1:3, [:red,:blue], S} # idxpairs: Vector of IndexPair # condition: Expr containing any condition present for indexing # Note in particular that it does not actually evaluate the condition, and so # it returns just the cartesian product of possible indices. refcall, idxvars, idxsets, idxpairs, condition = JuMP.buildrefsets(x) @show refcall @show idxvars @show idxsets @show idxpairs @show condition; varname = JuMP.getname(x) varstr = :(string($(string(varname)),"[")) for idxvar in idxvars push!(varstr.args,:(string($(esc(idxvar))))) push!(varstr.args,",") end deleteat!(varstr.args,length(varstr.args)) push!(varstr.args,"]") varstr ############################################################################### # getloopedcode # Unexported. Takes a bit of code and corresponding looping information and # returns that code nested in corresponding loops, along with preceding code # to construct an appropriate container. Input is: # c: symbolic representation of name and appropriate indexing sets, if # any. E.g. :(myvar) or :(x[i=1:3,[:red,:blue]]) # code: inner loop code kernel to be nested in the loops # condition: a boolean expression to be evaluated before each kernel. # If none, pass :(). # idxvars: As defined for buildrefsets # idxsets: As defined for buildrefsets # idxpairs: As defined for buildrefsets # sym: A symbol or expression containing the element type of the # resulting container, e.g. :AffExpr or :Variable variable = gensym() code = :( $(refcall) = IndepNormal($m, $mean, $var, $varstr ) ) JuMP.getloopedcode(variable, code, condition, idxvars, idxsets, idxpairs, :IndepNormal) using Base.Meta # for `quot` macro variable(args...) args end args = @variable(m, x >= 0) m = esc(args[1]) var = args[2].args[2] lb = 0 ub = Inf t = quot(:Default) quotvarname = quot(JuMP.getname(var)) escvarname = esc(JuMP.getname(var)) value = NaN variablecall = :( constructvariable!($m, $JuMP._error, $lb, $ub, $t, string($quotvarname), $value) ) code = :($variable = $variablecall) code = quote $code registervar($m, $quotvarname, $variable) $escvarname = $variable end JuMP.assert_validmodel(m, code) args = @variable(m, x[1:N,1:N], Symmetric, Poly(X)) var = args[2] variable = gensym() quotvarname = quot(JuMP.getname(var)) escvarname = esc(JuMP.getname(var)) refcall, idxvars, idxsets, idxpairs, condition = JuMP.buildrefsets(var, variable) @show refcall @show idxvars @show idxsets @show idxpairs @show condition; x = Matrix{...}(N, N) for i in 1:N for j in 1:N x[i,j] = x[j,i] = constructvariable!(m, Poly(X), msg -> error("In @variable(m, x[1:N,1:N], Symmetric, Poly(X)): ", msg), -Inf, Inf, :Cont, "", NaN ) end end macro constraint(args...) args end args = @constraint(m, a*x <= 5) @show m = args[1] @show x = args[2] @show extra = args[3:end]; m = esc(m) # Two formats: # - @constraint(m, a*x <= 5) # - @constraint(m, myref[a=1:5], a*x <= 5) # Canonicalize the arguments c = length(extra) == 1 ? x : gensym() x = length(extra) == 1 ? extra[1] : x @show c @show x variable = gensym() quotvarname = quot(JuMP.getname(c)) escvarname = esc(JuMP.getname(c)); refcall, idxvars, idxsets, idxpairs, condition = JuMP.buildrefsets(c, variable) (sense,vectorized) = JuMP._canonicalize_sense(x.args[1]) lhs = :($(x.args[2]) - $(x.args[3])) addconstr = (vectorized ? :addVectorizedConstraint : :addconstraint) newaff, parsecode = JuMP.parseExprToplevel(lhs, :q) constraintcall = :($addconstr($m, constructconstraint!($newaff,$(quot(sense))))) code = quote q = zero(AffExpr) $parsecode $(refcall) = $constraintcall end JuMP.assert_validmodel(m, quote $(JuMP.getloopedcode(variable, code, condition, idxvars, idxsets, idxpairs, :ConstraintRef)) $(quote registercon($m, $quotvarname, $variable) $escvarname = $variable end) end) function solve(m::Model; suppress_warnings=false, ignore_solve_hook=(m.solvehook===nothing), relaxation=false, kwargs...) # If the user or an extension has provided a solve hook, call # that instead of solving the model ourselves if !ignore_solve_hook return m.solvehook(m; suppress_warnings=suppress_warnings, kwargs...)::Symbol end # [...] end