Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototyping custom model/optimizer #535

Merged
merged 13 commits into from
Jun 7, 2021
Merged

Prototyping custom model/optimizer #535

merged 13 commits into from
Jun 7, 2021

Conversation

guimarqu
Copy link
Contributor

@guimarqu guimarqu commented May 26, 2021

First implementation for the custom model/optimizer.

At the moment it's not possible to replace the Formulation by a custom one because it requires much more work.

@guimarqu
Copy link
Contributor Author

guimarqu commented May 28, 2021

@laradicp I wasn't working when direct mode was deactivated, so I made some modifications.

However, I don't think it's a good solution because I think we should build the mapping custom model decision -> VarId once (at the beginning).

It's more difficult than I thought. We must figure out how we can build this relation custom model decision -> VarId knowing that the user can only give a relation between custom model decision and JuMP.VariableRef.

My first idea was to use MOI.VariableIndex -> VarId from Optimizer.varids but we don't have access to the optimizer in the run! method of the custom optimizer. Therefore, I tried to move Optimizer.varids into Env , but it breaks everything (circular dep Env & MathProg). (now it works because the env arg of create_formulation is not typed anymore.

Project.toml Outdated Show resolved Hide resolved
Project.toml Outdated Show resolved Hide resolved
@guimarqu guimarqu marked this pull request as ready for review June 2, 2021 17:40
@guimarqu
Copy link
Contributor Author

guimarqu commented Jun 2, 2021

Tests are ok

test/interfaces/model.jl Outdated Show resolved Hide resolved
test/interfaces/model.jl Outdated Show resolved Hide resolved
@rrsadykov
Copy link
Collaborator

I find this organization strange. You have subproblem formulation, inside you have optimizer, which itself has AbstractFormulation inside (I think that AbstractFormulation should be renamed to AbstractModel). It would be much simpler to directly have an AbstractModel as a subproblem formulation.

In specify! instead giving solver, we may define directly a model. For me it should be something like

mutable struct KnapsackLibModel <: Coluna.AbstractModel
    master::Coluna.MathProg.Formulation
    nbitems::Int
    costs::Vector{Float64}
    weights::Vector{Float64}
    capacity::Float64
    job_to_jumpvar::Dict{Int, JuMP.VariableRef}
end

function setmaster!(knap_model::KnapsackLibModel, master::Coluna.MathProg.Formulation)
    knap_model.master = master
end

struct KnapsackAlgorithm <: Coluna.AbstractOptimisationAlgorithm
end

function Coluna.Algorithm.run!(
    algo::KnapsackAlgorithm, env::Coluna.Env, model::KnapsackLibModel,
    input::Coluna.Algorithm.OptimizationInput)
    costs = -[Coluna.MathProg.getcurcost(model.master, _getvarid(model.master, env, job_to_jump_var[j])) for j in 1:length(opt.model.costs)]
    ...
    for j in selected
        push!(varids, _getvarid(model.master, env, job_to_jump_var[j]))
        push!(varvals, 1)
    end
    ...

end

....

coluna = JuMP.optimizer_with_attributes(
    Coluna.Optimizer,
    "params" => CL.Params(solver = TreeSearchAlgorithm(
        conqueralg=ColCutGenConquer(
            colgen=ColumnGeneration(pricing_prob_solve_alg=KnapsackAlgorithm())
        )
    )),
    "default_optimizer" => GLPK.Optimizer
)

model = BlockModel(coluna; direct_model = true)
@variable(model, x[m in data.machines, j in data.jobs], Bin)
@constraint(model, 
    sp[j in data.jobs], sum(x[m,j] for m in data.machines) == 1
)
@objective(model, Min,
    sum(data.cost[j,m]*x[m,j] for m in data.machines, j in data.jobs)
)

@axis(M, data.machines)
@dantzig_wolfe_decomposition(model, dec, M)

sp = getsubproblems(dec)
for m in M
    knp_model = KnapsackModel(length(data.jobs))
    setcapacity!(knp_model, data.capacity[m])
    for j in data.jobs
        setweight!(knp_model, j, data.weight[j,m])
        setcost!(knp_model, j, data.cost[j,m])
        map!(knp_model, j, x[m,j])
        #here you need to say that x[m,j] is an implicit representative variable
    end
    specify!(sp[m], model = knp_model) 
end

We may define AbstractCustomSpModel <: AbstractModel for which function setmaster! should be defined. So Coluna will call this function if it sees an AbstractCustomSpModel.

There is also a functionality missing, which allows us to say that a certain variable is implicit representative.

Concerning setup variables, I think they should should be managed automatically by Coluna

@rrsadykov
Copy link
Collaborator

rrsadykov commented Jun 3, 2021

Ok, may be sp. setup variables should also be managed by the user. So we may have something like

@variable(model, setup[m in data.machines], Int)
...
set_setup_var!(knp_model[m], setup[m])
...
specify!(sp[m], model = knp_model, setupvar = setup[m]) 

With the knowledge of setup variable, the user can check whether a certain solution has a negative reduced cost. Here setup vars may be defined automatically by Coluna, but set_setup_var!() function still should be called in the beginning.

@guimarqu
Copy link
Contributor Author

guimarqu commented Jun 7, 2021

Follow up in #537

@guimarqu guimarqu requested a review from rrsadykov June 7, 2021 11:42
@rrsadykov
Copy link
Collaborator

Ok for me. Why the tests do not pass?

@guimarqu
Copy link
Contributor Author

guimarqu commented Jun 7, 2021

Because we need to release a new version of BlockDecomposition

@guimarqu guimarqu merged commit ea80081 into release-0.4.0 Jun 7, 2021
@guimarqu guimarqu deleted the custom_model_ex branch June 7, 2021 12:54
guimarqu added a commit that referenced this pull request Jun 14, 2021
* dev branch to prepare release of 0.4.0

* Move storage & records in ColunaBase (#507)

* Renaming in storage (#509)

* RecordContainer -> RecordWrapper

* state -> record

* rename lot of things, remove getters of Storage not used by Algorithms

* Storage -> StorageUnitWrapper

* Deletion of `AbstractData`  (#510)

* RecordContainer -> RecordWrapper

* state -> record

* rename lot of things, remove getters of Storage not used by Algorithms

* start removing AbstractData structs

* tests ok

* getunit -> getstorageunit;  StorageDict -> Storage

* fix docstring

* Bijection StorageUnit -> Record (#518)

* Bijection StorageUnit -> Record

* address Ruslan's comments

* Implementation of column generation stages  (#525)

* Implementation of column generation stages (for example, heuristic and exact stage)

* Update after conversation with Guillaume + stabilization correction

* Simplification for ColCutGenConquer

* Some more modifs due to Guillaume comments

* Counting the number of exact calls when testing the pricing stages (#530)

* Add bound callback tests (#532)

* add bound callback tests

* include bound callback in runtests

* fix test

* Apply suggestions from code review

Co-authored-by: Guillaume Marques <guillaume.marques@protonmail.com>

* add comment

* Apply suggestions from code review

Co-authored-by: Guillaume Marques <guillaume.marques@protonmail.com>

Co-authored-by: Guillaume Marques <guillaume.marques@protonmail.com>

* Vector of optimizers in `Formulation` (#534)

* vector of optimizers in formulation

* solver_id -> optimizer_id

* add Manifest

* update Manifest

* remove Manifest because does not work

* changes

* rm files

* address Ruslan's comment

* Update src/MathProg/optimizerwrappers.jl

Co-authored-by: Vitor Nesello <vitornesello@gmail.com>

* add Manifest

* change ci

* remove ci change

* rm Manifest

Co-authored-by: Vitor Nesello <vitornesello@gmail.com>

* UnitsUsageDict -> UnitsUsage (#522)

* UnitsUsageDict -> UnitsAccess

* wip

* improve

* tests ok

* Custom data for variables and constraints (#495)

* draft for support of customer data

* custom data in solution

* custom data for cut callback

* computecoeff

* store custom data of solutions in manager

* add Manifest

* rm Manifest

* Support to custom cuts over custom data assigned to columns with new test

* tests ok

Co-authored-by: Artur Alves Pessoa <artur.a.pessoa@gmail.com>

* Prototyping custom model/optimizer (#535)

* Start example

* wip draft

* continue

* add map

* works with caching optimizer

* varids in Env

* wrong result

* multiply costs by -1

* fix scaling

* Apply suggestions from code review

* Update test/interfaces/model.jl

Co-authored-by: Lara Pontes <laradicp@gmail.com>

* Follow up of "custom data" (#538)

* add AbstractCustomData and set/get inc_val

* fix bugs

* remove duplicate methods

* delete unnecessary prefixes and fix some bugs

* revert some changes and update docstring

* custom information for dw sp (#542)

* docstring for restricted master heuristic (#543)

* docstring for restricted master heuristic

* Update src/Algorithm/conquer.jl

* Refactoring `ObjValues` & `OptimizationState` (#544)

* clean + doc

* move doc from objvalues to optstate; tests of objvalues; update ci

* update

* update branching priorioty deprecated method

* tests ok

* tests ok

* tests ok

* delete duplicated tests

Co-authored-by: Ruslan Sadykov <41117501+rrsadykov@users.noreply.github.com>
Co-authored-by: Artur Pessoa <artur.a.pessoa@gmail.com>
Co-authored-by: Lara di Cavalcanti Pontes <34425678+laradicp@users.noreply.github.com>
Co-authored-by: Vitor Nesello <vitornesello@gmail.com>
Co-authored-by: Lara Pontes <laradicp@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants