Would you please help me that how I can collect some NLexpressions in a loop?
I Want to keep k8 and k9 for all i=1:10 as scenarios. It means in the end of the loop, Q equal to collection of k8 and k9 under each scenario ( i ). I couldn't define a matrix and put each pair of k8 and k9 in that as an element. with considering Q the code doesn't work as well.
Many thanks for your kindly help.
using JuMP,CPUTime, Distributions, Ipopt,Juniper,Cplex
n1=1; #the least of scenarios
N=4; #number of scenarios
M=20; #number of sampling
landa=0.01;
E=0.05
T0=0;
T1=2;
T2=2;
gam2=1; gam1=1;
a1=0.5; a2=0.1; a3=50; ap=25;
c0=10;
Zn=zeros(N, 4)
Q=0;
for i in n1:N
C1=rand(100:100:300);
sig=rand(0.5:0.5:2);
f(x) = cdf(Normal(0, 1), x);
#---------------------------------------------------------------------------
ALT= Model(optimizer_with_attributes(Juniper.Optimizer, "nl_solver"=>optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0),
"mip_solver"=>optimizer_with_attributes(Cplex.Optimizer, "logLevel" => 0),"registered_functions" =>[Juniper.register( :f, 1, f; autodiff = true)])
);
# variables-----------------------------------------------------------------
JuMP.register(ALT, :f, 1, f; autodiff = true);
#variable(ALT, h >= 0.001);
#variable(ALT, L >= 0.000001);
#variable(ALT, n>=2, Int);
#---------------------------------------------------------------------------
#NLexpression(ALT,k1,h/(1-f(L-sig*sqrt(n))+f(-L - sig*sqrt(n)))); # HARL1
#NLexpression(ALT,k2,(1-(1+landa*h)*exp(-landa*h))/(landa*(1-exp(-landa*h)))); #to
#NLexpression(ALT,k3,E*n+T1*gam1+T2*gam2);
#NLexpression(ALT,k8,(C1*(k1-k2+k3)));# depend on scenario
#NLexpression(ALT,k9,(((a1+a2*n)/h)*(k1)));#depend on scenario
Q=Q+k8+k9;
#-----------------------------------------------------------------------
end
You have a couple of issues in your code.
Why are you creating a new model every loop? You cannot aggregate expressions across models like you do with Q=Q+k8+k9
You cannot add nonlinear expressions like Q=Q+k8+k9. All nonlinear expressions must occur inside macros
In general, you are not limited to the specific syntax of JuMP. You can use any Julia data structures to help. In the code below, I just push expressions into a vec
I haven't tested, so there might be typos etc, but this should point you in the right direction:
using JuMP, Distributions
E, landa, T1, T2, gam1, gam2, a1, a2 = 0.05, 0.01, 2, 2, 1, 1, 0.5, 0.1
ALT = Model()
f(x) = cdf(Normal(0, 1), x)
JuMP.register(ALT, :f, 1, f; autodiff = true)
#variable(ALT, h >= 0.001)
#variable(ALT, L >= 0.000001)
#variable(ALT, n >= 2, Int)
k8, k9 = Any[], Any[]
for i in 1:4
C1 = rand(100:100:300)
sig = rand(0.5:0.5:2)
k1 = #NLexpression(ALT, h / (1 - f(L - sig * sqrt(n)) + f(-L - sig * sqrt(n))))
k2 = #NLexpression(ALT, (1 - (1 + landa * h) * exp(-landa * h)) / (landa * (1 - exp(-landa * h))))
k3 = #NLexpression(ALT, E * n + T1 * gam1 + T2 * gam2)
push!(k8, #NLexpression(ALT, C1 * (k1 - k2 + k3))
push!(k9, #NLexpression(ALT, k9, (a1 + a2 * n) / h * k1)
end
Q = #NLexpression(ALT, sum(k for k in k8) + sum(k for k in k9))
Related
This is my Julia code to simulate data and sample from a Turing.jl model:
using LinearAlgebra, Distributions, StatsBase
using Turing, FillArrays, DynamicHMC, LabelledArrays
using NNlib, GLM
using CSV, DataFrames
function generate_hmnl_data(R::Int=100, S::Int=30, C::Int=3,
Theta::Array{Float64, 2}=ones(2, 4),
Sigma::Array{Float64, 2}=Matrix(Diagonal(fill(0.1, 4))))
K = size(Theta, 2)
G = size(Theta, 1)
Y = Array{Int64}(undef, R, S)
X = randn(R, S, C, K)
Z = Array{Float64}(undef, G, R)
Z[1, :] .= 1
if G > 1
Z[2:G, :] = randn(R * (G-1))
end
Beta = Array{Float64}(undef, K, R)
for r in 1:R
println(Z[:, r])
println(Theta)
Beta[:, r] = rand(MvNormal(Theta' * Z[:, r], Sigma))
for s in 1:S
Y[r, s] = sample(1:C, Weights(exp.(X[r, s, :, :] * Beta[:, r])))
end
end
return (R=R, S=S, C=C, K=K, G=G, Y=Y, X=X, Z=Z,
beta_true=Beta, Theta_true=Theta, Sigma_true=Sigma)
end
d1 = generate_hmnl_data()
#model function hmnl(G::Int, Y::Matrix{Int64}, X::Array{Float64}, Z::Matrix{Float64})
R, S, C, K = size(X)
Theta = zeros(K, G)
for k in 1:K
for g in 1:G
Theta[k, g] ~ Normal(0, 10)
end
end
Sigma ~ InverseWishart(K, diagm(ones(K)))
Beta = zeros(K, R)
println(eltype(Beta))
for r in 1:R
Beta[:, r] ~ MvNormal(Theta * Z[:, r], Sigma)
println(typeof(Beta[:, r]))
for s in 1:S
beta_r = copy(Beta[:, r])
beta_r = convert(Vector{Float64}, beta_r)
ut_rs = X[r, s, :, :] * beta_r
v = softmax(ut_rs)
Y[r, s] ~ Categorical(v)
end
end
end
sampler = HMC(.05, 10)
test_mod = hmnl(d1.G, d1.Y, d1.X, d1.Z)
chains = sample(test_mod, sampler, 1_000)
I get this error when I try to sample from the model: MethodError: no method matching float(::Type{Any}). The sampling statement Beta[:, r] ~ MvNormal(Theta * Z[:, r], Sigma) changes Beta[:, r] to type Vector{Any}.
I have tried
beta_r = copy(Beta[:, r])
beta_r = convert(Vector{Float64}, beta_r)
ut_rs = X[r, s, :, :] * beta_r
But then I get this error instead:
ERROR: TypeError: in typeassert, expected Float64, got a value of type ForwardDiff.Dual{Nothing, Float64, 12}
So it's messing with Turing AD somehow. I'm new to Turing and can't understand the right way to do this.
I'm reposting an answer from Tor Fjelde (https://github.com/torfjelde) which I received on Github. For Turing to work you need to ensure types in your model can be inferred. I wasn't doing that. https://turing.ml/v0.22/docs/using-turing/performancetips#ensure-that-types-in-your-model-can-be-inferred
This function worked:
#model function hmnl(G::Int, Y::Matrix{Int64}, X::Array{Float64}, Z::Matrix{Float64}, ::Type{T} = Float64) where {T}
R, S, C, K = size(X)
Theta = zeros(T, K, G)
for k in 1:K
for g in 1:G
Theta[k, g] ~ Normal(0, 10)
end
end
Sigma ~ InverseWishart(K, diagm(ones(K)))
Beta = zeros(T, K, R)
println(eltype(Beta))
for r in 1:R
Beta[:, r] ~ MvNormal(Theta * Z[:, r], Sigma)
println(typeof(Beta[:, r]))
for s in 1:S
ut_rs = X[r, s, :, :] * Beta[:, r]
v = softmax(ut_rs)
Y[r, s] ~ Categorical(v)
end
end
end
I am trying to minimize a nonlinear function with nonlinear inequality constraints with NLopt and JuMP.
In my test code below, I am minimizing a function with a known global minima.
Local optimizers such as LD_MMA fails to find this global minima, so I am trying to use global optimizers of NLopt that allow nonlinear inequality constraintes.
However, when I check my termination status, it says “termination_status(model) = MathOptInterface.OTHER_ERROR”. I am not sure which part of my code to check for this error.
What could be the cause?
I am using JuMP since in the future I plan to use other solvers such as KNITRO as well, but should I rather use the NLopt syntax?
Below is my code:
# THIS IS A CODE TO SOLVE FOR THE TOYMODEL
# THE EQUILIBRIUM IS CHARACTERIZED BY A NONLINEAR SYSTEM OF ODEs OF INCREASING FUCTIONS B(x) and S(y)
# THE GOAL IS TO APPROXIMATE B(x) and S(y) WITH POLYNOMIALS
# FIND THE POLYNOMIAL COEFFICIENTS THAT MINIMIZE THE LEAST SQUARES OF THE EQUILIBRIUM EQUATIONS
# load packages
using Roots, NLopt, JuMP
# model primitives and other parameters
k = .5 # equal split
d = 1 # degree of polynomial
nparam = 2*d+2 # number of parameters to estimate
m = 10 # number of grids
m -= 1
vGrid = range(0,1,m) # discretize values
c1 = 0 # lower bound for B'() and S'()
c2 = 2 # lower and upper bounds for offers
c3 = 1 # lower and upper bounds for the parameters to be estimated
# objective function to be minimized
function obj(α::T...) where {T<:Real}
# split parameters
αb = α[1:d+1] # coefficients for B(x)
αs = α[d+2:end] # coefficients for S(y)
# define B(x), B'(x), S(y), and S'(y)
B(v) = sum([αb[i] * v .^ (i-1) for i in 1:d+1])
B1(v) = sum([αb[i] * (i-1) * v ^ (i-2) for i in 2:d+1])
S(v) = sum([αs[i] * v .^ (i-1) for i in 1:d+1])
S1(v) = sum([αs[i] * (i-1) * v ^ (i-2) for i in 2:d+1])
# the equilibrium is characterized by the following first order conditions
#FOCb(y) = B(k * y * S1(y) + S(y)) - S(y)
#FOCs(x) = S(- (1-k) * (1-x) * B1(x) + B(x)) - B(x)
function FOCb(y)
sy = S(y)
binv = find_zero(q -> B(q) - sy, (-c2, c2))
return k * y * S1(y) + sy - binv
end
function FOCs(x)
bx = B(x)
sinv = find_zero(q -> S(q) - bx, (-c2, c2))
return (1-k) * (1-x) * B1(x) - B(x) + sinv
end
# evaluate the FOCs at each grid point and return the sum of squares
Eb = [FOCb(y) for y in vGrid]
Es = [FOCs(x) for x in vGrid]
E = [Eb; Es]
return E' * E
end
# this is the actual global minimum
αa = [1/12, 2/3, 1/4, 2/3]
obj(αa...)
# do optimization
model = Model(NLopt.Optimizer)
set_optimizer_attribute(model, "algorithm", :GN_ISRES)
#variable(model, -c3 <= α[1:nparam] <= c3)
#NLconstraint(model, [j = 1:m], sum(α[i] * (i-1) * vGrid[j] ^ (i-2) for i in 2:d+1) >= c1) # B should be increasing
#NLconstraint(model, [j = 1:m], sum(α[d+1+i] * (i-1) * vGrid[j] ^ (i-2) for i in 2:d+1) >= c1) # S should be increasing
register(model, :obj, nparam, obj, autodiff=true)
#NLobjective(model, Min, obj(α...))
println("")
println("Initial values:")
for i in 1:nparam
set_start_value(α[i], αa[i]+rand()*.1)
println(start_value(α[i]))
end
JuMP.optimize!(model)
println("")
#show termination_status(model)
#show objective_value(model)
println("")
println("Solution:")
sol = [value(α[i]) for i in 1:nparam]
My output:
Initial values:
0.11233072522513032
0.7631843020124309
0.3331559403539963
0.7161240026812674
termination_status(model) = MathOptInterface.OTHER_ERROR
objective_value(model) = 0.19116585196576466
Solution:
4-element Vector{Float64}:
0.11233072522513032
0.7631843020124309
0.3331559403539963
0.7161240026812674
I answered on the Julia forum: https://discourse.julialang.org/t/mathoptinterface-other-error-when-trying-to-use-isres-of-nlopt-through-jump/87420/2.
Posting my answer for posterity:
You have multiple issues:
range(0,1,m) should be range(0,1; length = m) (how did this work otherwise?) This is true for Julia 1.6. The range(start, stop, length) method was added for Julia v1.8
Sometimes your objective function errors because the root doesn't exist. If I run with Ipopt, I get
ERROR: ArgumentError: The interval [a,b] is not a bracketing interval.
You need f(a) and f(b) to have different signs (f(a) * f(b) < 0).
Consider a different bracket or try fzero(f, c) with an initial guess c.
Here's what I would do:
using JuMP
import Ipopt
import Roots
function main()
k, d, c1, c2, c3, m = 0.5, 1, 0, 2, 1, 10
nparam = 2 * d + 2
m -= 1
vGrid = range(0, 1; length = m)
function obj(α::T...) where {T<:Real}
αb, αs = α[1:d+1], α[d+2:end]
B(v) = sum(αb[i] * v^(i-1) for i in 1:d+1)
B1(v) = sum(αb[i] * (i-1) * v^(i-2) for i in 2:d+1)
S(v) = sum(αs[i] * v^(i-1) for i in 1:d+1)
S1(v) = sum(αs[i] * (i-1) * v^(i-2) for i in 2:d+1)
function FOCb(y)
sy = S(y)
binv = Roots.fzero(q -> B(q) - sy, zero(T))
return k * y * S1(y) + sy - binv
end
function FOCs(x)
bx = B(x)
sinv = Roots.fzero(q -> S(q) - bx, zero(T))
return (1-k) * (1-x) * B1(x) - B(x) + sinv
end
return sum(FOCb(x)^2 + FOCs(x)^2 for x in vGrid)
end
αa = [1/12, 2/3, 1/4, 2/3]
model = Model(Ipopt.Optimizer)
#variable(model, -c3 <= α[i=1:nparam] <= c3, start = αa[i]+ 0.1 * rand())
#constraints(model, begin
[j = 1:m], sum(α[i] * (i-1) * vGrid[j]^(i-2) for i in 2:d+1) >= c1
[j = 1:m], sum(α[d+1+i] * (i-1) * vGrid[j]^(i-2) for i in 2:d+1) >= c1
end)
register(model, :obj, nparam, obj; autodiff = true)
#NLobjective(model, Min, obj(α...))
optimize!(model)
print(solution_summary(model))
return value.(α)
end
main()
I am trying to implement a simple line-search algorithm in Julia. I am new to Julia programming, so I am learning it on the go. I'd like to ask for some help, if possible, to correct an error while running the code.
Source code.
using LinearAlgebra
function bracket_minimum(f, x = 0, s = 1e-2, k = 2.0)
a, fa = x, f(x)
b, fb = x + s, f(x + s)
if(fb > fa)
a, b = b, a
fa, fb = fb, fa
s = -s
end
while(true)
c, fc = b + s, f(b + s)
if(fb < fc)
return a < c ? (a, c) : (c, a)
else
a, fa, b, fb = b, fb, c, fc
s *= k
end
end
end
function bisection(f, a₀, b₀, ϵ)
function D(f,a)
# Approximate the first derivative using central differences
h = 0.001
return (f(a + h) - f(a - h))/(2 * h)
end
a = a₀
b = b₀
while((b - a) > ϵ)
c = (a + b)/2.0
if D(f,c) > 0
b = c
else
a = c
end
end
return (a,b)
end
function line_search(f::Function, x::Vector{Float64}, d::Vector{Float64})
println("Hello")
objective = α -> f(x + α*d)
a, b = bracket_minimum(objective)
α = bisection(objective, a, b, 1e-5)
return α, x + α*d
end
f(x) = sin(x[1] * x[2]) + exp(x[2] + x[3]) - x[3]
x = [1,2,3]
d = [0, -1, -1]
α, x_min = line_search(f, x, d)
I am getting a Linear algebraic error, so I think I must not be passing vectors correctly or perhaps I am not doing scalar-vector multiplication correctly. But, I was having a hard-time figuring out. If I step through the code, it fails on the function call line_search(f,x,d) and does not even enter inside the function body.
Error description.
ERROR: MethodError: no method matching *(::Tuple{Float64,Float64}, ::Array{Int64,1})
Closest candidates are:
*(::Any, ::Any, ::Any, ::Any...) at operators.jl:538
*(::Adjoint{var"#s828",var"#s8281"} where var"#s8281"<:(AbstractArray{T,1} where T) where var"#s828"<:Number, ::AbstractArray{var"#s827",1} where var"#s827"<:Number) at C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\LinearAlgebra\src\adjtrans.jl:283
*(::Transpose{T,var"#s828"} where var"#s828"<:(AbstractArray{T,1} where T), ::AbstractArray{T,1}) where T<:Real at C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.5\LinearAlgebra\src\adjtrans.jl:284
Here is a fix in the code (I have cleaned up several stylistic things, but the key problem that your bisection returned a tuple not a value - I have changed it to return the center of the bracketing interval):
function bracket_minimum(f, x = 0.0, s = 1e-2, k = 2.0)
a, fa = x, f(x)
b, fb = x + s, f(x + s)
if fb > fa
a, b = b, a
fa, fb = fb, fa
s = -s
end
while true
s *= k
c, fc = b + s, f(b + s)
if fb < fc
return minmax(a, c)
else
a, fa, b, fb = b, fb, c, fc
end
end
end
function bisection(f, a₀, b₀, ϵ)
function D(f, a)
# Approximate the first derivative using central differences
h = 0.001
return (f(a + h) - f(a - h)) / (2 * h)
end
a = a₀
b = b₀
while (b - a) > ϵ
c = (a + b) / 2.0
if D(f, c) > 0
b = c
else
a = c
end
end
return (a + b) / 2 # this was changed
end
function line_search(f::Function, x::Vector{Float64}, d::Vector{Float64})
#assert length(x) == length(d)
objective(α) = f(x .+ α .* d)
a, b = bracket_minimum(objective)
α = bisection(objective, a, b, 1e-5)
return α, x .+ α .* d
end
f(x) = sin(x[1] * x[2]) + exp(x[2] + x[3]) - x[3]
x = [1.0, 2.0, 3.0]
d = [0.0, -1.0, -1.0]
α, x_min = line_search(f, x, d)
I was not commenting on the algorithm, as I assume you are writing this as a programming exercise and you are not trying to write the fastest and most robust algorithm.
I am trying to reproduce this model - the code in the tutorial is for an old version of JuMP/Julia and does not run.
However, when I try to add the constraint:
#constraint(model, con, c[i = 1:N] .== ( ((1 - τ) * (1 - l[i]) .* w[i]) + e[i]))
I get the error Unexpected assignment in expression 'c[i = 1:N]'.
Here is the reprex:
using Random
using Distributions
using JuMP
using Ipopt
Random.seed!(123)
N = 1000
γ = 0.5
τ = 0.2
ϵ = rand(Normal(0, 1), N)
wage = rand(Normal(10, 1), N)
consumption = (γ * (1 - τ) * wage) + (γ * ϵ)
leisure = (1 - γ) .+ (( 1 - γ) * ϵ) ./ (( 1 - τ ) * wage)
model = Model(Ipopt.Optimizer)
#variable(model, c[i = 1:N] >= 0)
#variable(model, 0 <= l[i = 1:N] <= 1)
#constraint(model, con, c[i = 1:N] .== ( ((1 - τ) * (1 - l[i]) .* w[i]) + e[i]))
#NLobjective(model, Max, sum(γ *log(c[i]) + (1-γ)*log(l[i]) for i in 1:N ) )
Does anyone know why this is being thrown and how to fix it?
Any and all help appreciated!
Running Julia 1.5.1
With the c[i = 1:N] in JuMP yo can only define variables.
With the constraints one way you could do is just:
w = wage # not in your code
e = ϵ # not in your code
#constraint(model, con[i = 1:N], c[i] == ( ((1 - τ) * (1 - l[i]) .* w[i]) + e[i]))
Przemyslaw's answer is a good one. If you want to stick with the vectorized syntax, you can go
N = 1_000
e = rand(N)
w = rand(N)
τ = 0.2
model = Model()
#variable(model, c[i = 1:N] >= 0)
#variable(model, 0 <= l[i = 1:N] <= 1)
#constraint(model, c .== (1 - τ) .* (1 .- l) .* w .+ e)
Here is the JuMP documentation for constraints https://jump.dev/JuMP.jl/stable/constraints
I'm trying to maximize the function by x[1], x[2]:
(a - 1) * x[1] * c + (a - 1) * x[2] * b * d
Where a, b, c, d are known positive constants and
0 < x[1] < 1, 0 < x[2] < 1,
x[1] + x[2] = 1
Using NlcOptim, I did:
solver_1 <- function(a, b, c, d){
obj = function(x){
return((a - 1) * x[1] * c + (a - 1) * x[2] * b * d )
}
con = function(x){
f = NULL
f = rbind(f, x[1] + x[2] - 1)
return(list(ceq = f, c = NULL))
}
x0 = c(1, 0)
solnl(x0, objfun = obj, confun = con)
}
solver_1(1.2, 5.2, 0.8, 0.1)
But it gives me:
Error in if (norm(H, "I") == 0) { : missing value where TRUE/FALSE needed
Does anyone know what I'm doing wrong?
Using an optimization package is massive overkill.
Either by following up on the comment of #Roland and doing some elementary calculus, or using the corner point theorem of linear programming, your objective function is optimized when x[1] = 0 and x[2] = 1 or vice versa. Thus you only have to evaluated two constant expressions in a,b,c,d and pick the larger of the two:
max(c*(a-1), b*d*(a-1))
For any a other than 1, which is larger will be determined by whether or not c > a*b