Trouble Defining Variable

I’ve been working to create an updated version of this repo, which uses JuMP, GLPK and Julia to perform a linear optimization. I think I’ve correctly updated the bulk of it (replacing @setObjective with objective type things), but I’ve hit a snag on defining a variable. I’m going to post a few key lines here, but my full colab notebook is posted here.

error is:

UndefVarError: i not defined

Stacktrace:
 [1] macro expansion
   @ ~/.julia/packages/MutableArithmetics/0Y9ZS/src/rewrite.jl:279 [inlined]
 [2] macro expansion
   @ ~/.julia/packages/JuMP/klrjG/src/macros.jl:676 [inlined]
 [3] one_lineup_Type_4(skaters::DataFrame, goalies::DataFrame, lineups::Matrix{Int64}, num_overlap::Int64, num_skaters::Int64, num_goalies::Int64, centers::Vector{Int64}, wingers::Vector{Int64}, defenders::Vector{Int64}, num_teams::Int64, skaters_teams::Matrix{Int64}, goalie_opponents::Matrix{Int64}, team_lines::Matrix{Int64}, num_lines::Int64, P1_info::Matrix{Int64})
   @ Main ./In[102]:424
 [4] create_lineups(num_lineups::Int64, num_overlap::Int64, path_skaters::String, path_goalies::String, formulation::typeof(one_lineup_Type_4), path_to_output::String)
   @ Main ./In[102]:803
 [5] top-level scope
   @ In[102]:873
 [6] eval
   @ ./boot.jl:368 [inlined]
 [7] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
   @ Base ./loading.jl:1428

I’m new to debugging but that lead me to lines 424 and 803 respectively, which are

function one_lineup_Type_4(skaters, goalies, lineups, num_overlap, num_skaters, num_goalies, centers, wingers, defenders, num_teams, skaters_teams, goalie_opponents, team_lines, num_lines, P1_info)
    m = Model(solver=GLPKSolverMIP())

and

create_lineups(num_lineups, num_overlap, path_skaters, path_goalies, formulation, path_to_output)

I’m at a bit of a loss on how to debug this; I’ve banged on this all day and made no progress, so any advice on how to debug this kind of thing would be very helpful. The maintainer of the repo doesn’t seem to have added anything and others have hit the same snag according to the issues page, so I half wonder if it’s something in those function blocks that’s now dated, but I can’t find it.

and the full block of 420 if it’s helpful:

# This is a function that creates one lineup using the Type 4 formulation from the paper
function one_lineup_Type_4(skaters, goalies, lineups, num_overlap, num_skaters, num_goalies, centers, wingers, defenders, num_teams, skaters_teams, goalie_opponents, team_lines, num_lines, P1_info)
    m = Model(with_optimizer(GLPK.Optimizer))


    # Variable for skaters in lineup
    @variable(m, skaters_lineup[i=1:num_skaters], Bin)

    # Variable for goalie in lineup
    @variable(m, goalies_lineup[i=1:num_goalies], Bin)


    # One goalie constraint
    @constraint(m, sum(goalies_lineup[i], i=1:num_goalies) == 1)

    # Eight Skaters constraint
    @constraint(m, sum(skaters_lineup[i], i=1:num_skaters) == 8)

    # between 2 and 3 centers
    @constraint(m, sum(centers[i]*skaters_lineup[i], i=1:num_skaters) <= 3)
    @constraint(m, 2 <= sum(centers[i]*skaters_lineup[i], i=1:num_skaters))

    # between 3 and 4 wingers
    @constraint(m, sum(wingers[i]*skaters_lineup[i], i=1:num_skaters) <= 4)
    @constraint(m, 3<=sum(wingers[i]*skaters_lineup[i], i=1:num_skaters))

    # between 2 and 3 defenders
    @constraint(m, 2 <= sum(defenders[i]*skaters_lineup[i], i=1:num_skaters))
    @constraint(m, sum(defenders[i]*skaters_lineup[i], i=1:num_skaters) <= 3)

    # Financial Constraint
    @constraint(m, sum(skaters[i,:Salary]*skaters_lineup[i], i=1:num_skaters) + sum(goalies[i,:Salary]*goalies_lineup[i], i=1:num_goalies) <= 50000)


    # exactly 3 different teams for the 8 skaters constraint
    @variable(m, used_team[i=1:num_teams], Bin)
    @constraint(m, constr[i=1:num_teams], used_team[i] <= sum(skaters_teams[t, i]*skaters_lineup[t], t=1:num_skaters))
    @constraint(m, constr[i=1:num_teams], sum(skaters_teams[t, i]*skaters_lineup[t], t=1:num_skaters) <= 6*used_team[i])
    @constraint(m, sum(used_team[i], i=1:num_teams) == 3)


    # No goalies going against skaters
    @constraint(m, constr[i=1:num_goalies], 6*goalies_lineup[i] + sum(goalie_opponents[k, i]*skaters_lineup[k], k=1:num_skaters)<=6)


    # Must have at least one complete line in each lineup
    @variable(m, line_stack[i=1:num_lines], Bin)
    @constraint(m, constr[i=1:num_lines], 3*line_stack[i] <= sum(team_lines[k,i]*skaters_lineup[k], k=1:num_skaters))
    @constraint(m, sum(line_stack[i], i=1:num_lines) >= 1)


    # Must have at least 2 lines with at least two people
    @variable(m, line_stack2[i=1:num_lines], Bin)
    @constraint(m, constr[i=1:num_lines], 2*line_stack2[i] <= sum(team_lines[k,i]*skaters_lineup[k], k=1:num_skaters))
    @constraint(m, sum(line_stack2[i], i=1:num_lines) >= 2)



    # The defenders must be on Power Play 1
    @constraint(m, sum(sum(defenders[i]*P1_info[i,j]*skaters_lineup[i], i=1:num_skaters), j=1:num_teams) ==  sum(defenders[i]*skaters_lineup[i], i=1:num_skaters))


    # Overlap Constraint
    @constraint(m, constr[i=1:size(lineups)[2]], sum(lineups[j,i]*skaters_lineup[j], j=1:num_skaters) + sum(lineups[num_skaters+j,i]*goalies_lineup[j], j=1:num_goalies) <= num_overlap)



    # Objective
    @objective(m, Max, sum(skaters[i,:Projection]*skaters_lineup[i], i=1:num_skaters) + sum(goalies[i,:Projection]*goalies_lineup[i], i=1:num_goalies) )


    # Solve the integer programming problem
    println("Solving Problem...")
    @printf("\n")
    status = solve(m);


    # Puts the output of one lineup into a format that will be used later
    if status==:Optimal
        skaters_lineup_copy = Array{Int}(undef, 0)
        for i=1:num_skaters
            if getValue(skaters_lineup[i]) >= 0.9 && getValue(skaters_lineup[i]) <= 1.1
                skaters_lineup_copy = vcat(skaters_lineup_copy, fill(1,1))
            else
                skaters_lineup_copy = vcat(skaters_lineup_copy, fill(0,1))
            end
        end
        for i=1:num_goalies
            if getValue(goalies_lineup[i]) >= 0.9 && getValue(goalies_lineup[i]) <= 1.1
                skaters_lineup_copy = vcat(skaters_lineup_copy, fill(1,1))
            else
                skaters_lineup_copy = vcat(skaters_lineup_copy, fill(0,1))
            end
        end
        return(skaters_lineup_copy)
    end
end

Focussing on frame [3] of the stacktrace, and looking at line 424 of cell In[102]:

    # One goalie constraint
    @constraint(m, sum(goalies_lineup[i], i=1:num_goalies) == 1)

Maybe you meant sum(goalies_lineup[i] for i = 1:num_goalies)? Or even better, sum(goalies_lineup[1:num_goalies]), or if length(goalies_lineup) == num_goalies, simply sum(goalies_lineup).


In general, it might be easier if you broke up your code across more cells, instead of having cells over eight-hundred lines long. E.g., put each function in its own cell.

3 Likes

thanks for the advice, you’re right, I should break the thing up; query:

I guess I thought that the [I] worked as a saved namespace kind of like you can in python, seems that isn’t the case, that did solve the line there, but of course it’s now repeating on down the code e.g. breaking on

   # between 2 and 3 centers
    @constraint(m, sum(centers[i]*skaters_lineup[i], i=1:num_skaters) <= 3)
    @constraint(m, 2 <= sum(centers[i]*skaters_lineup[i], i=1:num_skaters))

so what’s the right way to pull in a variable there? the point is to set the constraint to 3 or fewer centers, and test each option, but it seems I need to pull in the variable somewhere…

The syntax is sum(expr for i = set), not sum(expr, i = set).

So you need sum(centers[i]*skaters_lineup[i] for i=1:num_skaters).

1 Like

thank you for that, made that change through out the block and it seems to be working.