Error code for GLPK and SigmoidalProgramming

I’m trying to use Sigmoidal Programming to solve an optimization problem which is minimize (sum of concave functions) subject to linear constraints.
When I input problem = LinearSP(fs, dfs, z, A, b) it seems to read and create the problem correctly. The output after executing this line is

LinearSP(Function[var"#1#2"{Int64}(1), var"#1#2"{Int64}(2), var"#1#2"{Int64}(3), var"#1#2"{Int64}(4), var"#1#2"{Int64}(5), var"#1#2"{Int64}(6), var"#1#2"{Int64}(7), var"#1#2"{Int64}(8), var"#1#2"{Int64}(9), var"#1#2"{Int64}(10), var"#1#2"{Int64}(11), var"#1#2"{Int64}(12), var"#1#2"{Int64}(13), var"#1#2"{Int64}(14), var"#1#2"{Int64}(15), var"#1#2"{Int64}(16), var"#1#2"{Int64}(17), var"#1#2"{Int64}(18), var"#1#2"{Int64}(19), var"#1#2"{Int64}(20)], Function[var"#3#4"{Int64}(1), var"#3#4"{Int64}(2), var"#3#4"{Int64}(3), var"#3#4"{Int64}(4), var"#3#4"{Int64}(5), var"#3#4"{Int64}(6), var"#3#4"{Int64}(7), var"#3#4"{Int64}(8), var"#3#4"{Int64}(9), var"#3#4"{Int64}(10), var"#3#4"{Int64}(11), var"#3#4"{Int64}(12), var"#3#4"{Int64}(13), var"#3#4"{Int64}(14), var"#3#4"{Int64}(15), var"#3#4"{Int64}(16), var"#3#4"{Int64}(17), var"#3#4"{Int64}(18), var"#3#4"{Int64}(19), var"#3#4"{Int64}(20)], [-Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf, -Inf], [1.0 1.0 … 1.0 1.0; 1.0 1.0 … 0.0 0.0; … ; -0.0 -0.0 … -0.3 -0.0; -0.0 -0.0 … 0.3 1.0], [1.0, Inf, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, -0.5, Inf, -0.0, -0.0, -0.0, -0.0, -0.0], Matrix{Float64}(undef, 0, 20), Float64[])

However, when I try to solve it, using the code mentioned in the git repo,

pq, bestnodes, lbs, ubs = solve_sp(l, u, problem)

# the best node found yet is the top node on the priority queue
node = dequeue!(pq)
# println("best node has node.ub = $(node.ub) and solution $(node.x)")

# lbs and ubs record the upper and lower bounds on the optimal value
# found at each iteration
println("lbs: ",lbs)
println("ubs: ",ubs)

It throws the following error.

┌ Warning: The GLPK constants have been renamed from `GLPK.XXX` to `GLPK.GLP_XXX` in order to better match the C API. For example, `GLPK.MSG_OFF` is now `GLPK.GLP_MSG_OFF`. Support for the old constants will be removed in a future release.
└ @ GLPK C:\Users\user\.julia\packages\GLPK\JpN1q\src\MOI_wrapper\deprecated_constants.jl:19
MethodError: no method matching ^(::Float64, ::Vector{Float64})
Closest candidates are:
  ^(::Number, ::Missing) at missing.jl:124
  ^(::T, ::Rational) where T<:AbstractFloat at rational.jl:482
  ^(::AbstractFloat, ::ForwardDiff.Dual{Ty}) where Ty at C:\Users\user\.julia\packages\ForwardDiff\vXysl\src\dual.jl:145
  ...

Stacktrace:
 [1] (::var"#1#2"{Int64})(x::Float64)
   @ Main .\In[6]:2
 [2] macro expansion
   @ C:\Users\user\.julia\packages\MutableArithmetics\0Y9ZS\src\rewrite.jl:279 [inlined]
 [3] macro expansion
   @ C:\Users\user\.julia\packages\JuMP\qhoVb\src\macros.jl:440 [inlined]
 [4] model_problem(l::Vector{Float64}, u::Vector{Float64}, w::Vector{Float64}, problem::LinearSP, m::JuMP.Model)
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:91
 [5] model_problem(l::Vector{Float64}, u::Vector{Float64}, w::Vector{Float64}, problem::LinearSP)
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:71
 [6] SigmoidalProgramming.Node(l::Vector{Float64}, u::Vector{Float64}, problem::LinearSP, init_x::Type; kwargs::Base.Pairs{Symbol, Float64, Tuple{Symbol}, NamedTuple{(:TOL,), Tuple{Float64}}})
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:209
 [7] solve_sp(l::Vector{Float64}, u::Vector{Float64}, problem::LinearSP, init_x::Type; TOL::Float64, maxiters::Int64, verbose::Int64, maxiters_noimprovement::Float64)
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:250
 [8] solve_sp (repeats 2 times)
   @ C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:247 [inlined]
 [9] top-level scope
   @ In[8]:1

I cannot figure out what the error is or how to solve this error. Can anyone help me out?

Do you have a reproducible example? This just looks like a bug.

It looks like GitHub - madeleineudell/SigmoidalProgramming.jl: Julia Package for Sigmoidal Programming hasn’t been updated in a number of years, so I wouldn’t expect this to get fixed unless you download and edit the code yourself.

I ran the following example given in the git repo.

## Let's solve a random problem
using SigmoidalProgramming
using Random
import DataStructures: dequeue!

# problem data
Random.seed!(4)
nvar = 200
nconstr = 40

l = -rand(nvar)
u = rand(nvar)
A = rand(nconstr, nvar)
b = rand(nconstr)
z = zeros(nvar)
fs = fill(logistic, nvar)
dfs = fill(logistic_prime, nvar)
problem = LinearSP(fs, dfs, z, A, b)

# branch and bound
pq, bestnodes, lbs, ubs = solve_sp(l, u, problem)

node = dequeue!(pq)
# println("best node has node.ub = $(node.ub) and solution $(node.x)")
println("lbs: ",lbs)
println("ubs: ",ubs)

And it did solve. It gave the output,

found solution within tolerance 0.05930552174513082 in 1 iterations
lbs: [101.87364005822803]
ubs: [101.93294557997316]

So, I’m assuming that the library works. The error is creeping out of something else, but I don’t know what.

I think the issue originates in defining functions in list. The fs and dfs passed in the example are of function type whereas what I was passing was something else. I’m still trying to figure it out.
More about the issue: Another community post : )

I got as far as defining the functions as fs(x::Number, b::Number) = x^b and dfs(x::Number, b::Number) = b*x^(b-1) but I don’t know how to fill them in a vector or specific length. What I eventually want is a vector\list like [c1.f1 c2.f2 c3.f3…cn.fn] where ci is cost and fi is fs defined here. I also expect another error here that since b is a parameter I define earlier, and use it in this code, I want to just pass in b, but it’s not a number and I suspect it throwing up error.

Kindly let me know how to get around this. Any help is deeply appreciated!

The GLPK warning is unrelated to the MethodError, it’s related to the package being old and using an old version of GLPK.jl that prints that warning.

The MethodError is telling you that there’s no existing ^ method for a float and vector, so you can’t do 3.5^[1.2, 6.7]. You really should post runnable code, not fragments, that causes the error in one place so it’s easier for readers to follow, but there’s enough across the two posts for me to guess that you’re using the example’s b, which is a 20-length vector, so x^b will fail. If you need b to be a scalar, you need to change that. If you want to do elementwise operations on a vector, do x .^ b.

1 Like

Extremely sorry for this, I’m new to this I did not know and thought the issues were separate. I changed x^b to x .^ b and it shows another error.

MethodError: no method matching -(::JuMP.VariableRef, ::Vector{Float64})
Closest candidates are:
  -(::Union{MathOptInterface.VectorAffineFunction{T}, MathOptInterface.VectorOfVariables, MathOptInterface.VectorQuadraticFunction{T}}, ::Vector{T}) where T at C:\Users\user\.julia\packages\MathOptInterface\YDdD3\src\Utilities\functions.jl:2121
  -(::Union{MathOptInterface.ScalarAffineFunction{T}, MathOptInterface.ScalarQuadraticFunction{T}}, ::T) where T at C:\Users\user\.julia\packages\MathOptInterface\YDdD3\src\Utilities\functions.jl:1725
  -(::StaticArraysCore.StaticArray, ::AbstractArray) at C:\Users\user\.julia\packages\StaticArrays\4uslg\src\linalg.jl:18
  ...

Stacktrace:
  [1] sub_mul(a::JuMP.VariableRef, b::Vector{Float64})
    @ MutableArithmetics C:\Users\user\.julia\packages\MutableArithmetics\0Y9ZS\src\MutableArithmetics.jl:33
  [2] operate(::typeof(MutableArithmetics.sub_mul), ::JuMP.VariableRef, ::Vector{Float64})
    @ MutableArithmetics C:\Users\user\.julia\packages\MutableArithmetics\0Y9ZS\src\interface.jl:131
  [3] operate_fallback!(::MutableArithmetics.NotMutable, ::typeof(MutableArithmetics.sub_mul), ::JuMP.VariableRef, ::Vector{Float64})
    @ MutableArithmetics C:\Users\user\.julia\packages\MutableArithmetics\0Y9ZS\src\interface.jl:428
  [4] operate!(op::typeof(MutableArithmetics.sub_mul), x::JuMP.VariableRef, args::Vector{Float64})
    @ MutableArithmetics C:\Users\user\.julia\packages\MutableArithmetics\0Y9ZS\src\rewrite.jl:83
  [5] macro expansion
    @ C:\Users\user\.julia\packages\MutableArithmetics\0Y9ZS\src\rewrite.jl:279 [inlined]
  [6] macro expansion
    @ C:\Users\user\.julia\packages\JuMP\qhoVb\src\macros.jl:440 [inlined]
  [7] model_problem(l::Vector{Float64}, u::Vector{Float64}, w::Vector{Float64}, problem::LinearSP, m::JuMP.Model)
    @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:91
  [8] model_problem(l::Vector{Float64}, u::Vector{Float64}, w::Vector{Float64}, problem::LinearSP)
    @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:71
  [9] SigmoidalProgramming.Node(l::Vector{Float64}, u::Vector{Float64}, problem::LinearSP, init_x::Type; kwargs::Base.Pairs{Symbol, Float64, Tuple{Symbol}, NamedTuple{(:TOL,), Tuple{Float64}}})
    @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:209
 [10] solve_sp(l::Vector{Float64}, u::Vector{Float64}, problem::LinearSP, init_x::Type; TOL::Float64, maxiters::Int64, verbose::Int64, maxiters_noimprovement::Float64)
    @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:250
 [11] solve_sp (repeats 2 times)
    @ C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:247 [inlined]
 [12] top-level scope
    @ In[22]:1

I’m attaching the .jl file of the the code for simplicity. Hope that would help.
Julia_test.jl (2.5 KB)
Here is the corresponding data file. The extension is changed to .jl so I could upload it. To use it, one would need to change it back to .mps
data.mps (5.8 KB)
Thanks again <3

I suppose that means the package only works with scalar functions. The docs seem to imply this, though the example is not very clear e.g. logistic does not depend on i. You could try changing those anonymous functions so they don’t operate on b. First thought is you could index a scalar out of it like b[i], as you did coeffs[i], but those vectors likely have different length and it’s not apparent how meaningful those functions would be.

I suppose that means the package only works with scalar functions.

I think this is the answer.

But also, given the fact that SigmoidalProgramming.jl has no tests:

it looks like the package was mostly research code and never intended for widespread usage.

@Benny
b is a parameter in my problem. So someone at the start specifies what b should be [usually observed by past data and estimated, different organizations can have different b], and the program will run with that b. The length of coeff is same as number of variables because it specifies cost associated with that variable. I can create a vector of b and solve it I think. My functions are scalar and depend on just x.

@odow
Yes, the package is basically an algorithm described in a 2015 paper authored by Byod and Udell during their time at Stanford. The paper was on sigmoidal programming. I’m trying to use the algorithm for one of academic the problems that I have. I still don’t understand what the issue is. I’m very new to Julia so could you let me know what changes should I make and where? And where can I read more about basic data structures in Julia?

This is the latest file I have. It still has errors while solving, not sure where they originate from now.
Sigmoid_steady_1.8.jl (2.7 KB)

DomainError with -Inf:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.

Stacktrace:
 [1] throw_exp_domainerror(x::Float64)
   @ Base.Math .\math.jl:37
 [2] ^(x::Float64, y::Float64)
   @ Base.Math .\math.jl:1008
 [3] (::var"#71#72"{Int64})(x::Float64)
   @ Main .\In[100]:2
 [4] (::SigmoidalProgramming.var"#1#2"{var"#71#72"{Int64}, var"#73#74"{Int64}, Float64})(w::Float64)
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:18
 [5] find_w(f::var"#71#72"{Int64}, df::var"#73#74"{Int64}, l::Float64, u::Float64, z::Float64)
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:19
 [6] SigmoidalProgramming.Node(l::Vector{Float64}, u::Vector{Float64}, problem::LinearSP, init_x::Type; kwargs::Base.Pairs{Symbol, Float64, Tuple{Symbol}, NamedTuple{(:TOL,), Tuple{Float64}}})
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:207
 [7] solve_sp(l::Vector{Float64}, u::Vector{Float64}, problem::LinearSP, init_x::Type; TOL::Float64, maxiters::Int64, verbose::Int64, maxiters_noimprovement::Float64)
   @ SigmoidalProgramming C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:250
 [8] solve_sp (repeats 2 times)
   @ C:\Users\user\.julia\packages\SigmoidalProgramming\kLcUj\src\sp.jl:247 [inlined]
 [9] top-level scope
   @ In[103]:1

If I include x^y with (x+0im)^y, Complex(x)^y it shows another error since I guess sigmoid is not built to handle complex functions. Please help!
: )

If you’re running into another error, you should include it for clarity. If you’re trying to keep your posts from getting too long with multiple stacktraces, you can put each of them in their own Hide Details blocks. When you write a post, click the gear icon (settings) and click the Hide Details button to create the block. The text will only be shown when you click the arrow to the left of the title in the post. You should still limit the amount of text in each block, but this is good for multiple code blocks or stacktraces that don’t need to all be visible at once.

Write a title here

You can hide this text by clicking the arrow again.

As for your DomainError, it’s just saying that the complex outputs should start with complex inputs, and that’ll happen with negative bases and non-integer exponents. An atypical detail is that the DomainError is saying your base was -Inf, so at some point your functions are run with x set at -Inf. I’m betting that’s being set in the package, not by you. If you explicitly post your changes to your anonymous functions to accommodate complex operations and the error that results, maybe readers can spot an easy fix. But it’s also likely that the package is not flexible enough as is for complex numbers, and there would not be anything anyone can do besides further developing the package. It appears someone did do that a few years ago to update the 2015 paper’s code, I can only speculate it was for their own research. There are other issues with your code, but it’s probably better to figure out if the package can run your problem correctly before getting into performance tips.

Aside: I did spot a possible typo, you assign very different things to b in your script, b = fill(0.8, states*actions) then vcat(u,-l). Did you intend those to be different variables?

1 Like

@Benny
Thanks for your help! I did correct the typo of b. I followed a different approach where I copied example from git repo and changed one parameter at a time. It works for my case except 1 operation. I cannot seem to add coefficients to objective function.

#Defining objective functions
fs1 = fill(x -> (x)^b, nvar)             #Need to fill with cost coefficients
dfs1 = fill(x -> b/x^(1-b), nvar)        #Need to fill with cost coefficients

fs = [x -> fs1[i]*coeffs[i] for i=1:(states*actions)]
dfs = [x -> dfs1[i]*coeffs[i] for i=1:(states*actions)]

If I use fs1 and dfs1 in the sigmoidal programming LinearSP object, it works and gives me solution. But If I use fs and dfs instead it gives me error that var and float64 cannot be multiplied. There is no matching method.
I’m attaching the .jl file. Kindly let me know how to go about with this.
Thank you for all the help! I seriously appreciate it.
Steady_state_EoS.jl (2.6 KB)

I don’t really understand your intended coefficients, but the error is clear. fs1/dfs1 are each a vector filled with 1 anonymous function repeatedly. So when you index it fs1[i]/dfs1[i], you get that anonymous function. Multiplying a function by a number isn’t meaningful so nobody made a method for it. You probably meant to execute the function like fs1[i](some_input) but I don’t know what input you intended.