jump-dev / MiniZinc.jl

A Julia interface to the MiniZinc constraint modeling language
https://www.minizinc.org/
MIT License
18 stars 4 forks source link

`InexactError: trunc(Int64, -Inf)` in `_variable_info` #67

Closed LebedevRI closed 5 months ago

LebedevRI commented 5 months ago

This is julia 1.10.3 + up-to-date packages.

(@v1.10) pkg> st
Status `~/.julia/environments/v1.10/Project.toml`
  [861a8166] Combinatorics v1.0.2
  [86223c79] Graphs v1.11.0
  [87dc4568] HiGHS v1.9.0
  [7073ff75] IJulia v1.24.2
  [b6b21f68] Ipopt v1.6.2
  [4076af6c] JuMP v1.22.1
  [a7f392d2] MiniZinc v0.3.8

This does not happen with HiGHS. I suspect the reproducer can be trimmed significantly.

using Combinatorics
using JuMP
import HiGHS
import MiniZinc

function main()
    NUM_OUTPUT_CONTACTS = 3
    NUM_OUTPUT_CONTACT_NAMES = ["Common", "A", "B"]
    NUM_DEVICE_CONTACTS = 2
    NUM_DEVICE_CONTACT_NAMES = ["-", "+"]
    NUM_INPUT_DEVICES = 3

    NUM_SWITCHES = 3
    NUM_SWITCH_CONTACTS = 1+11 # first contact is "self"

    CONTACT_NAMES = Vector{String}() # Name of i'th each contact
    CONTACT_LOOKUP = Dict{String,Dict}() # Index of the given contact, deep
    begin
        GROUP = "Sense"
        CONTACT_LOOKUP[GROUP] = Dict{String,Int}()
        for i in 1:NUM_OUTPUT_CONTACTS
            NAME = GROUP * " " * NUM_OUTPUT_CONTACT_NAMES[i]
            push!(CONTACT_NAMES, NAME)
            CONTACT_LOOKUP[GROUP][NUM_OUTPUT_CONTACT_NAMES[i]] = length(CONTACT_NAMES)
        end
    end
    begin
        GROUP = "Device"
        CONTACT_LOOKUP[GROUP] = Dict{Int,Dict{String,Int}}()
        for i in 1:NUM_INPUT_DEVICES
            CONTACT_LOOKUP[GROUP][i] = Dict{String,Int}()
            for j in 1:NUM_DEVICE_CONTACTS
                NAME = GROUP * " " * string(i) * " pole " * NUM_DEVICE_CONTACT_NAMES[j]
                push!(CONTACT_NAMES, NAME)
                CONTACT_LOOKUP[GROUP][i][NUM_DEVICE_CONTACT_NAMES[j]] = length(CONTACT_NAMES)
            end
        end
    end
    begin
        GROUP = "Switch"
        CONTACT_LOOKUP[GROUP] = Dict{Int,Dict{Int,Int}}()
        for i in 1:NUM_SWITCHES
            CONTACT_LOOKUP[GROUP][i] = Dict{Int,Int}()
            for j in 1:NUM_SWITCH_CONTACTS
                NAME = GROUP * " " * string(i) * " contact " * string(j) * (j == 1 ? " (self)" : "")
                push!(CONTACT_NAMES, NAME)
                CONTACT_LOOKUP[GROUP][i][j] = length(CONTACT_NAMES)
            end
        end
    end
    NUM_CONTACTS_TOTAL = length(CONTACT_NAMES)

    CONTACT_INDEXES = Dict{String,Int}() # Index of the given contact
    for i in 1:NUM_CONTACTS_TOTAL
        CONTACT_INDEXES[CONTACT_NAMES[i]] = i
    end

    INTERESTING_STATES = Set()
    for a in 1:NUM_INPUT_DEVICES
        for b in 1:NUM_INPUT_DEVICES
            for (pole,otherpole) in permutations(NUM_DEVICE_CONTACT_NAMES)
                STATE = Set()
                for d in zip((a,b),("A", "B"))
                    push!(STATE, ("Device " * string(d[1]) * " pole " * pole, "Sense " * first(NUM_OUTPUT_CONTACT_NAMES)))
                    push!(STATE, ("Device " * string(d[1]) * " pole " * otherpole, "Sense " * d[2]))
                    if a == b
                        break
                    end
                end
                push!(INTERESTING_STATES, STATE)
            end
        end        
    end  
    NUM_KEYFRAMES = length(INTERESTING_STATES)

    #model = Model(HiGHS.Optimizer);
    model = Model(() -> MiniZinc.Optimizer{Float64}("highs"))

    @variable(model, HardWires[1:NUM_CONTACTS_TOTAL, 1:NUM_CONTACTS_TOTAL], Bin)
    @constraints(model, begin
        # Hard-wiring graph is symmetrical
        [i=1:NUM_CONTACTS_TOTAL, j=1:NUM_CONTACTS_TOTAL], (HardWires[i,j] == HardWires[j,i])
        # Connections should never be hard-wired to themselves (they are themselves)
        [i=1:NUM_CONTACTS_TOTAL], HardWires[i,i] == 0
    end);

    @variable(model, 1 <= SwitchPosition[1:NUM_KEYFRAMES, 1:NUM_SWITCHES] <= NUM_SWITCH_CONTACTS, Int)

    @variable(model, Reachability[1:NUM_KEYFRAMES, 1:NUM_CONTACTS_TOTAL, 1:NUM_CONTACTS_TOTAL], Bin)

    @constraints(model, begin
        # Graph is symmetrical
        #[k=1:NUM_KEYFRAMES, i=1:NUM_CONTACTS_TOTAL, j=1:NUM_CONTACTS_TOTAL], (Reachability[k,i,j] == Reachability[k,j,i] := true)
        [k=1:NUM_KEYFRAMES, i=1:NUM_CONTACTS_TOTAL, j=1:NUM_CONTACTS_TOTAL], HardWires[i,j] --> {Reachability[k,i,j] == true}
    end);

    print(model)
    optimize!(model)
    @show convert.(Bool, value.(HardWires))
end

main()
InexactError: trunc(Int64, -Inf)

Stacktrace:
  [1] trunc
    @ ./float.jl:905 [inlined]
  [2] ceil
    @ ./float.jl:384 [inlined]
  [3] _variable_info(model::MathOptInterface.Utilities.GenericModel{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, MiniZinc.ModelFunctionConstraints{Float64}}, x::MathOptInterface.VariableIndex)
    @ MiniZinc ~/.julia/packages/MiniZinc/S9TPM/src/write.jl:38
  [4] (::MiniZinc.var"#3#4"{MathOptInterface.Utilities.GenericModel{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, MiniZinc.ModelFunctionConstraints{Float64}}})(x::MathOptInterface.VariableIndex)
    @ MiniZinc ./none:0
  [5] iterate
    @ ./generator.jl:47 [inlined]
  [6] _all(f::Base.var"#384#386", itr::Base.Generator{Vector{MathOptInterface.VariableIndex}, MiniZinc.var"#3#4"{MathOptInterface.Utilities.GenericModel{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, MiniZinc.ModelFunctionConstraints{Float64}}}}, ::Colon)
    @ Base ./reduce.jl:1297
  [7] all
    @ ./reduce.jl:1283 [inlined]
  [8] Dict(kv::Base.Generator{Vector{MathOptInterface.VariableIndex}, MiniZinc.var"#3#4"{MathOptInterface.Utilities.GenericModel{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, MiniZinc.ModelFunctionConstraints{Float64}}}})
    @ Base ./dict.jl:111
  [9] _write_variables(io::IOStream, model::MathOptInterface.Utilities.GenericModel{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, MiniZinc.ModelFunctionConstraints{Float64}})
    @ MiniZinc ~/.julia/packages/MiniZinc/S9TPM/src/write.jl:45
 [10] write(io::IOStream, model::MathOptInterface.Utilities.GenericModel{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, MiniZinc.ModelFunctionConstraints{Float64}})
    @ MiniZinc ~/.julia/packages/MiniZinc/S9TPM/src/write.jl:512
 [11] #20
    @ ~/.julia/packages/MiniZinc/S9TPM/src/optimize.jl:75 [inlined]
 [12] open(::MiniZinc.var"#20#22"{MiniZinc.Optimizer{Float64}}, ::String, ::Vararg{String}; kwargs::@Kwargs{})
    @ Base ./io.jl:396
 [13] open(::Function, ::String, ::String)
    @ Base ./io.jl:393
 [14] _run_minizinc(dest::MiniZinc.Optimizer{Float64})
    @ MiniZinc ~/.julia/packages/MiniZinc/S9TPM/src/optimize.jl:74
 [15] optimize!(dest::MiniZinc.Optimizer{Float64}, src::MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}})
    @ MiniZinc ~/.julia/packages/MiniZinc/S9TPM/src/optimize.jl:210
 [16] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MiniZinc.Optimizer{Float64}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}})
    @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/2CULs/src/Utilities/cachingoptimizer.jl:316
 [17] optimize!
    @ ~/.julia/packages/MathOptInterface/2CULs/src/Bridges/bridge_optimizer.jl:380 [inlined]
 [18] optimize!
    @ ~/.julia/packages/MathOptInterface/2CULs/src/MathOptInterface.jl:85 [inlined]
 [19] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{MiniZinc.Optimizer{Float64}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}})
    @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/2CULs/src/Utilities/cachingoptimizer.jl:316
 [20] optimize!(model::Model; ignore_optimize_hook::Bool, _differentiation_backend::MathOptInterface.Nonlinear.SparseReverseMode, kwargs::@Kwargs{})
    @ JuMP ~/.julia/packages/JuMP/Gwn88/src/optimizer_interface.jl:457
 [21] optimize!
    @ ~/.julia/packages/JuMP/Gwn88/src/optimizer_interface.jl:409 [inlined]
 [22] main()
    @ Main ./In[67]:98
 [23] top-level scope
    @ In[67]:102
odow commented 5 months ago

Here's a simpler reproducible example.

julia> using JuMP

julia> import HiGHS

julia> import MiniZinc

julia> model = Model(() -> MiniZinc.Optimizer{Float64}("highs"))
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: MiniZinc

julia> @variable(model, x, Bin)
x

julia> optimize!(model)
ERROR: InexactError: trunc(Int64, -Inf)
Stacktrace:
  [1] trunc
    @ ./float.jl:905 [inlined]
  [2] ceil
    @ ./float.jl:384 [inlined]
  [3] _variable_info(model::MathOptInterface.Utilities.GenericModel{…}, x::MathOptInterface.VariableIndex)
    @ MiniZinc ~/.julia/packages/MiniZinc/S9TPM/src/write.jl:38
  [4] (::MiniZinc.var"#3#4"{MathOptInterface.Utilities.GenericModel{…}})(x::MathOptInterface.VariableIndex)
    @ MiniZinc ./none:0
  [5] iterate
    @ ./generator.jl:47 [inlined]

I'll push a fix.

LebedevRI commented 5 months ago

@odow thank you for taking a look!

odow commented 5 months ago

See #68

LebedevRI commented 5 months ago

@odow thank you!