Iterating using Channel

i have some problems in replacing the deprecated function produce()with Channel()in this code:

function scan_maker(A)
    m = JuMP.Model(solver=ClpSolver(PrimalTolerance=1e-3, DualTolerance=1e-3, InfeasibleReturn=1, PresolveType=1))
    # m = Model(solver=GurobiSolver())
    level = size(A, 2)
    v = zeros(Int, level)
    ub = zeros(Int, level)
    lb = zeros(Int, level)

    @variable(m, x[1:level])
    @constraint(m, con, A*x.>=0)

    function setc(c)
        for i = 1:size(A, 1)
            m.linconstr[i].lb = float(c[i])
        end
    end
    
    function scan()
        i = 1
        init = 1
        while i > 0
            if i >= init
                @objective(m, Max, x[i])
                res = JuMP.solve(m, suppress_warnings=true)
                if res==:Optimal || res==:Unbounded
                    ub[i] = round(Int, getvalue(x[i]))
                    setobjectivesense(m, :Min)
                    res = JuMP.solve(m, suppress_warnings=true)
                    @assert res==:Optimal || res==:Unbounded
                    lb[i] = round(Int, getvalue(x[i]))

                    v[i] = lb[i]
                    init += 1
                else
                    @assert res==:Infeasible
                    i -= 1
                    continue
                end
            elseif v[i] < ub[i]
                v[i] += 1
            else
                setupperbound(x[i], Inf)
                setlowerbound(x[i], -Inf)
                init -= 1
                i -= 1
                continue
            end

            if i >= level
                produce(v)
                continue
            else
                setupperbound(x[i], v[i])
                setlowerbound(x[i], v[i])
                i += 1
            end
        end
    end
    
    return setc, scan
end

i have tried to put c::Channel as an argument of the function scan()and change produce(v)with put!(c,v) the function was compiled but when i want to call the functions for example:

julia> A=[2 2;1 1;4 3]
3×2 Array{Int64,2}:
 2  2
 1  1
 4  3
julia> B=[2;3;7]
3-element Array{Int64,1}:
 2
 3
 7
julia> a,b=scan_maker(A)
(getfield(Main, Symbol("#setc#3")){Array{Int64,2},Model}([2 2; 1 1; 4 3], Feasibility problem with:
 * 3 linear constraints
 * 2 variables
Solver is Clp), getfield(Main, Symbol("#scan#4")){Model,Int64,Array{Int64,1},Array{Int64,1},Array{Int64,1},Array{Variable,1}}(Feasibility problem with:
 * 3 linear constraints
 * 2 variables
Solver is Clp, 2, [0, 0], [0, 0], [0, 0], x[i] ∀ i ∈ {1,2}))

julia> a(B)            # i'm calling the new function which is supposed to return nothing and it's working

julia> mychannel=Channel((channel_arg) -> b( pwd(), channel_arg))          # defining a Channel
Channel{Any}(sz_max:0,sz_curr:0)

julia> b(mychannel)
ERROR: MethodError: no method matching (::getfield(Main, Symbol("#scan#4")){Model,Int64,Array{Int64,1},Array{Int64,1},Array{Int64,1},Array{Variable,1}})(::String, ::Channel{Any})
Stacktrace:
 [1] check_channel_state at ./channels.jl:117 [inlined]
 [2] put! at ./channels.jl:273 [inlined]
 [3] push! at ./channels.jl:312 [inlined]
 [4] (::getfield(Main, Symbol("#scan#4")){Model,Int64,Array{Int64,1},Array{Int64,1},Array{Int64,1},Array{Variable,1}})(::Channel{Any}) at ./REPL[3]:50
 [5] top-level scope at REPL[20]:1

when i call the function scan i get that error above, i don’t know how to deal with this.
The output should be something like this:

v = [-1, 6]
v = [0, 4]
v = [1, 2] 

(Hello and welcome!)

It is not really clear what you did exactly, but your approach should work. Here is a minimal example demonstrating it:

function scan_maker(n)
    function scan(c::Channel)
        for i in 1:n
            put!(c, i)
        end

        close(c)
    end
    return scan
end
julia> scan = scan_maker(5)
scan (generic function with 1 method)

julia> chan = Channel(scan)
Channel{Any}(sz_max:0,sz_curr:1)

julia> for i in chan
           @show i
       end
i = 1
i = 2
i = 3
i = 4
i = 5

Judging from the error message that you get, your first problem comes from the creation of the channel:

mychannel=Channel((channel_arg) -> b( pwd(), channel_arg))

should be something else, perhaps simply

mychannel=Channel(b)

but it’s difficult to be sure without seeing the modified scan_maker code that you actually used to produce b

2 Likes

the modification was in scan function like this

function scan(c::Channel)
i = 1
        init = 1
        while i > 0
            if i >= init
                @objective(m, Max, x[i])
                res = JuMP.solve(m, suppress_warnings=true)
                if res==:Optimal || res==:Unbounded
                    ub[i] = round(Int, getvalue(x[i]))
                    setobjectivesense(m, :Min)
                    res = JuMP.solve(m, suppress_warnings=true)
                    @assert res==:Optimal || res==:Unbounded
                    lb[i] = round(Int, getvalue(x[i]))

                    v[i] = lb[i]
                    init += 1
                else
                    @assert res==:Infeasible
                    i -= 1
                    continue
                end
            elseif v[i] < ub[i]
                v[i] += 1
            else
                setupperbound(x[i], Inf)
                setlowerbound(x[i], -Inf)
                init -= 1
                i -= 1
                continue
            end

            if i >= level
                put!(c, v)
                close(c)
                continue
            else
                setupperbound(x[i], v[i])
                setlowerbound(x[i], v[i])
                i += 1
            end
        end
    end

an now i have tried to create a Channel by simply doing the same thing : mychannel=Channel(b) i get this one : Channel{Any}(sz_max:0,sz_curr:1) and when i call the function after by b(mychannel)the code compiles non stop without giving me anything :
julia> b(mychannel)

Could you please post a complete example of what you did? And if you can, reduce you problem to something minimal like I did in my earlier post: for example, Jump probably has nothing to do with you problem, and you could just keep the logic of your code, but not actually call Jump.

There is a relatively complete list of advice that you might find useful to express your problem in a way that will help us help you more effectively: PSA: make it easier to help you

By the way, did you try the example I gave you? Did it work?

1 Like

in general i put c::Channel as an argument of function scan and changed produce(v) with take!(c,v) and the i closed using close(c) .
your entire approach works now except one problem is that i don’t get all the outputs, when i do :

julia> chnl=Channel(b)
Channel{Any}(sz_max:0,sz_curr:1)

julia> for i in chnl
       @show i
       end
i = [-2, 6]

as you can see i get only one output at the time i’m supposed to get 5 outputs like this :

v = [-2, 6]
v = [-1, 6]
v = [0, 4]
v = [1, 4]
v = [2, 2]

Again, please post runnable code exhibiting the bad behavior you encounter: it is often not particularly easy to debug code, but it gets very hard when you don’t even know what code you’re debugging :wink:

That being said, if the code with which you obtain only one result (instead of 5) is the one you posted above, one mistake in it is that you close the channel as soon as you write in it

            if i >= level
                put!(c, v)
                close(c)
                continue
            else
                 # ...

You should put all results in the channel, and only close it at the end of the calculation

2 Likes

yes you are right, i didn’t know that i was cloing the channel right after the calculation i should’ve close it after the end of the loop , i have compared the outputs that i get using Channeland the ones when i use @show, they are similar.