Lazyconstraint not defined using GLPK solver callbacks

Hello! Sorry about the newb question, but I have an issue setting lazy constraint.

I follow the example here but don’t have access to licensed solvers so I use the GLPK solver instead of the Gurobi solver by applying the following two commands:
using GLPK and m=Model(with_optimizer(GLPK.Optimizer))

It seems that the functions are not in scope, and I get the following error messages:
LoadError: LoadError: UndefVarError: @lazyconstraint not defined
If I comment out “@lazyconstraint”, I get the following error message:
LoadError: UndefVarError: addlazycallback not defined

Because of these errors I attempted to check if my packages are correctly installed. If I run
(v1.3) pkg> test GLPK I get the output below, where specifically there is an error in the GLPK\HjJiX\test\MOI_callbacks.jl:1 file.

How do I fix this problem? Thank you for your time and attention!

(v1.3) pkg> test GLPK
   Testing GLPK
 Resolving package versions...
    Status `C:\Users\espenhs\AppData\Local\Temp\jl_hTU9s6\Manifest.toml`
  [6e4b80f9] BenchmarkTools v0.4.3
  [b99e7846] BinaryProvider v0.5.8
  [523fee87] CodecBzip2 v0.6.0
  [944b1d66] CodecZlib v0.6.0
  [60bf3e95] GLPK v0.12.1
  [cd3eb016] HTTP v0.8.8
  [83e8ac13] IniFile v0.5.0
  [682c06a0] JSON v0.21.0
  [7d188eb4] JSONSchema v0.2.0
  [b8f27783] MathOptInterface v0.9.9
  [739be429] MbedTLS v0.7.0
  [d8a4904e] MutableArithmetics v0.2.2
  [bac558e1] OrderedCollections v1.1.0
  [69de0a69] Parsers v0.3.10
  [3bb67fe8] TranscodingStreams v0.9.5
  [2a0f44e3] Base64  [`@stdlib/Base64`]
  [ade2ca70] Dates  [`@stdlib/Dates`]
  [8ba89e20] Distributed  [`@stdlib/Distributed`]
  [b77e0a4c] InteractiveUtils  [`@stdlib/InteractiveUtils`]
  [8f399da3] Libdl  [`@stdlib/Libdl`]
  [37e2e46d] LinearAlgebra  [`@stdlib/LinearAlgebra`]
  [56ddb016] Logging  [`@stdlib/Logging`]
  [d6f4376e] Markdown  [`@stdlib/Markdown`]
  [a63ad114] Mmap  [`@stdlib/Mmap`]
  [de0858da] Printf  [`@stdlib/Printf`]
  [9a3f8284] Random  [`@stdlib/Random`]
  [ea8e919c] SHA  [`@stdlib/SHA`]
  [9e88b42a] Serialization  [`@stdlib/Serialization`]
  [6462fe0b] Sockets  [`@stdlib/Sockets`]
  [2f01184e] SparseArrays  [`@stdlib/SparseArrays`]
  [10745b16] Statistics  [`@stdlib/Statistics`]
  [8dfed614] Test  [`@stdlib/Test`]
  [4ec0a83e] Unicode  [`@stdlib/Unicode`]
Test Summary: | Pass  Total
C API         |  163    163
MathOptInterface: Error During Test at C:\Users\espenhs\.julia\packages\GLPK\HjJiX\test\runtests.jl:20
  Got exception outside of a @test
  LoadError: ArgumentError: Package Random not found in current path:
  - Run `import Pkg; Pkg.add("Random")` to install the Random package.

  Stacktrace:
   [1] require(::Module, ::Symbol) at .\loading.jl:887
   [2] include at .\boot.jl:328 [inlined]
   [3] include_relative(::Module, ::String) at .\loading.jl:1105
   [4] include(::Module, ::String) at .\Base.jl:31
   [5] include(::String) at .\client.jl:424
   [6] top-level scope at C:\Users\espenhs\.julia\packages\GLPK\HjJiX\test\runtests.jl:22
   [7] top-level scope at D:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.3\Test\src\Test.jl:1107
   [8] top-level scope at C:\Users\espenhs\.julia\packages\GLPK\HjJiX\test\runtests.jl:21
   [9] include at .\boot.jl:328 [inlined]
   [10] include_relative(::Module, ::String) at .\loading.jl:1105
   [11] include(::Module, ::String) at .\Base.jl:31
   [12] include(::String) at .\client.jl:424
   [13] top-level scope at none:6
   [14] eval(::Module, ::Any) at .\boot.jl:330
   [15] exec_options(::Base.JLOptions) at .\client.jl:263
   [16] _start() at .\client.jl:460
  in expression starting at C:\Users\espenhs\.julia\packages\GLPK\HjJiX\test\MOI_callbacks.jl:1

Test Summary:             | Pass  Error  Broken  Total
MathOptInterface          | 1834      1       1   1836
  Unit Tests              |  782                   782
  Linear tests            |  511                   511
  Linear Conic tests      |  135                   135
  Integer Linear tests    |   75                    75
  ModelLike tests         |  246              1    247
  Parameter setting       |    4                     4
  Issue #79               |    2                     2
  Issue #70               |    6                     6
  Infeasible bounds       |    1                     1
  RawParameter            |   15                    15
  TimeLimitSec issue #110 |    4                     4
  RelativeGap             |    2                     2
  Extra name tests        |   15                    15
  Issue #102              |    2                     2
  Issue #116              |    3                     3
  Default parameters      |    4                     4
  Duplicate names         |   20                    20
  Duals with equal bounds |    2                     2
  PR #121                 |    3                     3
  Non-ascii names         |    2                     2
ERROR: LoadError: Some tests did not pass: 1834 passed, 0 failed, 1 errored, 1 broken.
in expression starting at C:\Users\espenhs\.julia\packages\GLPK\HjJiX\test\runtests.jl:20
ERROR: Package GLPK errored during testing```

Generic callbacks were dropped, so the example you’re using is out of date.

I’ll take a little deeper look to see if I can provide an alternate solution.

Update: Maybe not anymore

2nd Update: Looks like there is an example for you in the current master branch of JuMP.

1 Like

Yes, callbacks will be part of the next release of JuMP. You can use ] add JuMP#master if you want to try them out before then!

Note that the documentation you linked to is out-of-date. Here’s the current documentation: https://www.juliaopt.org/JuMP.jl/stable/

I have a PR to fix the failing tests: https://github.com/JuliaOpt/GLPK.jl/pull/127

1 Like

Thank you for your responses, they were super helpful! I have gotten the example to run, but my own code does not seem to want to run the callback function. The test for lazy_called fails, as the callback function is never called. I thus have to ask, is there any special condition that must be fulfilled for callback function to be called? My interpretation is that it should be always called after a call to optimize!, as we then may wish to add extra constraints to the solution. The JuMP callback example in the master branch seems to do it this way as far as I can see, where multiple conditions are checked manually to see if new constraints should be added to the solution.

My actual code somewhat complex but I have not been able to break it down to a level where I can make callbacks run successfully. My code is like so (pretty much exactly like the example found here of which you are the author @odow , but it still does not run the callbacks):

using JuMP  # JuMP v.0.20.3, aka the master branch as of 2020-02.07 (and not the latest release)
using GLPK
using Random
using Test

function foo()
    # Prepare JuMP model
    model = Model(GLPK.Optimizer)
    @variable(model, 0 <=pgen1 <= 100)
    @variable(model, 0 <=pgen2 <= 100)
    #@constraint(m, pgen1+pgen2==100)
    @objective(model, Max, 5*pgen1+1.2*pgen2)
    lazy_called = false
    function my_callback_function(cb_data)  # callback for preventive constraints
        lazy_called = true
        print("Entered callback function. ")
        TOL = 1e-6
        con = @build_constraint(pgen1 <= 80)
        MOI.submit(model, MOI.LazyConstraint(cb_data), con)
    end

    # Set lazy constraint, run optimization and perform tests
    MOI.set(model, MOI.LazyConstraintCallback(), my_callback_function)
    optimize!(model)
    
    @test termination_status(model) == MOI.OPTIMAL
    @test primal_status(model) == MOI.FEASIBLE_POINT
    @test lazy_called
end

foo()

Yes, integer or binary variables must be present in the model. The lazy constraint callback modifies a branch-and-bound procedure. If all variables are continuous, branch-and-bound won’t run, hence the callback will not be called.

1 Like