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

@mustimplement to highlight APIs #699

Merged
merged 3 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
RandomNumbers = "e6cf234a-135c-5ec9-84dd-332b85af5143"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
Expand Down
2 changes: 1 addition & 1 deletion src/Algorithm/Algorithm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import TimerOutputs

using ..Coluna, ..ColunaBase, ..MathProg

using Crayons, DynamicSparseArrays, Logging, Parameters, Printf, Statistics
using Crayons, DynamicSparseArrays, Logging, Parameters, Printf, Random, Statistics

const TO = TimerOutputs
const DS = DataStructures
Expand Down
40 changes: 8 additions & 32 deletions src/Algorithm/branching/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,11 @@ getdescription(candidate::AbstractBranchingCandidate) =
## Note: Branching candidates must be created in the BranchingRule algorithm so they do not need
## a generic constructor.

function get_lhs(c::AbstractBranchingCandidate)
@warn "get_lhs(::$(typeof(c))) not implemented."
return nothing
end

function get_local_id(c::AbstractBranchingCandidate)
@warn "get_local_id(::$(typeof(c))) not implemented."
return nothing
end

function get_children(c::AbstractBranchingCandidate)
@warn "get_children(::$(typeof(c))) not implemented."
return nothing
end

function set_children!(c::AbstractBranchingCandidate, children)
@warn "set_children!(::$(typeof(c)), children) not implemented."
return nothing
end

function get_parent(c::AbstractBranchingCandidate)
@warn "get_parent(::$(typeof(c))) not implemented."
return nothing
end
@mustimplement "BranchingCandidate" get_lhs(c::AbstractBranchingCandidate)
@mustimplement "BranchingCandidate" get_local_id(c::AbstractBranchingCandidate)
@mustimplement "BranchingCandidate" get_children(c::AbstractBranchingCandidate)
@mustimplement "BranchingCandidate" set_children!(c::AbstractBranchingCandidate, children)
@mustimplement "BranchingCandidate" get_parent(c::AbstractBranchingCandidate)

# TODO: this method should not generate the children of the tree search algorithm.
# However, AbstractBranchingCandidate should implement an interface to retrieve data to
Expand All @@ -49,10 +30,7 @@ This method generates the children of a node described by `branching_candidate`.
Make sure that this method returns an object the same type as the second argument of
`set_children!(candiate, children)`.
"""
function generate_children!(c::AbstractBranchingCandidate, env, reform, parent)
@warn "generate_children!(::$(typeof(c)), ::$(typeof(env)), ::$(typeof(reform)), ::$(typeof(parent))) not implemented."
return nothing
end
@mustimplement "BranchingCandidate" generate_children!(c::AbstractBranchingCandidate, env, reform, parent)

############################################################################################
# Selection Criteria of branching candidates
Expand All @@ -71,17 +49,15 @@ abstract type AbstractSelectionCriterion end

Sort branching candidates according to the selection criterion and remove excess ones.
"""
select_candidates!(::Vector{C}, selection::AbstractSelectionCriterion, ::Int) where {C <: AbstractBranchingCandidate} =
error("select_candidates! not defined for branching selection rule $(typeof(selection)).")

@mustimplement "BranchingSelection" select_candidates!(::Vector{<:AbstractBranchingCandidate}, selection::AbstractSelectionCriterion, ::Int)

############################################################################################
# Branching score
############################################################################################

abstract type AbstractBranchingScore end

compute_score(::AbstractBranchingScore, candidate) = nothing
@mustimplement "BranchingScore" compute_score(::AbstractBranchingScore, candidate)

############################################################################################
# BranchingRuleAlgorithm
Expand Down
43 changes: 8 additions & 35 deletions src/Algorithm/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ abstract type AbstractAlgorithm end
run!(algo::AbstractAlgorithm, env, model, input)
Runs an algorithm.
"""
function run!(algo::AbstractAlgorithm, env::Env, model::AbstractModel, input)
error("run!(::$(typeof(algo)), ::$(typeof(env)), ::$(typeof(model)), ::$(typeof(input))) not implemented.")
end
@mustimplement "Algorithm" run!(algo::AbstractAlgorithm, env::Env, model::AbstractModel, input)

# TODO: remove this method.
# We currently need it because we give to the parent algorithm the responsability of recording
Expand Down Expand Up @@ -54,20 +52,9 @@ in the input so that it is not obtained each time the conquer algorithm runs.
"""
abstract type AbstractConquerInput end

function get_node(i::AbstractConquerInput)
@warn "get_node(::$(typeof(i))) not implemented."
return nothing
end

function get_units_to_restore(i::AbstractConquerInput)
@warn "get_units_to_restore(::$(typeof(i))) not implemented."
return nothing
end

function run_conquer(i::AbstractConquerInput)
@warn "run_conquer(::$(typeof(i))) not implemented."
return nothing
end
@mustimplement "ConquerInput" get_node(i::AbstractConquerInput)
@mustimplement "ConquerInput" get_units_to_restore(i::AbstractConquerInput)
@mustimplement "ConquerInput" run_conquer(i::AbstractConquerInput)

"""
AbstractConquerAlgorithm
Expand All @@ -83,13 +70,7 @@ abstract type AbstractConquerAlgorithm <: AbstractAlgorithm end
# conquer algorithms are always manager algorithms (they manage storing and restoring units)
ismanager(algo::AbstractConquerAlgorithm) = true

function run!(algo::AbstractConquerAlgorithm, env::Env, reform::Reformulation, input::AbstractConquerInput)
algotype = typeof(algo)
error(string("Method run! which takes as parameters Reformulation and ConquerInput ",
"is not implemented for algorithm $algotype.")
)
end

@mustimplement "ConquerAlgorithm" run!(::AbstractConquerAlgorithm, ::Env, ::Reformulation, ::AbstractConquerInput)

# this function is needed in strong branching (to have a better screen logging)
isverbose(algo::AbstractConquerAlgorithm) = false
Expand All @@ -107,15 +88,8 @@ Contains the parent node in the search tree for which children should be generat
"""
abstract type AbstractDivideInput end

function get_parent(i::AbstractDivideInput)
@warn "get_parent(::$(typeof(i))) not implemented."
return nothing
end

function get_opt_state(i::AbstractDivideInput)
@warn "get_opt_state(::$(typeof(i))) not implemented."
return nothing
end
@mustimplement "DivideInput" get_parent(i::AbstractDivideInput)
@mustimplement "DivideInput" get_opt_state(i::AbstractDivideInput)

"""
Output of a divide algorithm used by the tree search algorithm.
Expand All @@ -137,8 +111,7 @@ abstract type AbstractDivideAlgorithm <: AbstractAlgorithm end
# divide algorithms are always manager algorithms (they manage storing and restoring units)
ismanager(algo::AbstractDivideAlgorithm) = true

run!(algo::AbstractDivideAlgorithm, ::Env, model::AbstractModel, input::AbstractDivideInput) =
error("Method run! in not defined for divide algorithm $(typeof(algo)), model $(typeof(model)), and input $(typeof(input)).")
@mustimplement "DivideAlgorithm" run!(::AbstractDivideAlgorithm, ::Env, ::AbstractModel, ::AbstractDivideInput)

# this function is needed to check whether the best primal solution should be copied to the node optimization state
exploits_primal_solutions(algo::AbstractDivideAlgorithm) = false
Expand Down
74 changes: 22 additions & 52 deletions src/Algorithm/treesearch/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,45 @@ abstract type AbstractExploreStrategy end
abstract type AbstractNode end

"Returns the type of search space depending on the tree-search algorithm and its parameters."
search_space_type(::AbstractAlgorithm) = nothing
@mustimplement "TreeSearch" search_space_type(::AbstractAlgorithm)

"Creates and returns the search space of a tree search algorithm, its model, and its input."
function new_space(::Type{SearchSpaceType}, alg, model, input) where SearchSpaceType <: AbstractSearchSpace
@warn "new_space(::Type{$SearchSpaceType}, ::$(typeof(alg)), ::$(typeof(model)), ::$(typeof(input))) not implemented."
return nothing
end
@mustimplement "TreeSearch" new_space(::Type{<:AbstractSearchSpace}, alg, model, input)

"Creates and returns the root node of a search space."
function new_root(sp::AbstractSearchSpace, input)
@warn "new_root(::$(typeof(sp)), ::$(typeof(input))) not implemented."
return nothing
end
@mustimplement "TreeSearch" new_root(::AbstractSearchSpace, input)

"Returns the root node of the tree to which the node belongs."
get_root(::AbstractNode) = nothing
@mustimplement "Node" get_root(::AbstractNode)

"Returns the parent of a node; `nothing` if the node is the root."
get_parent(::AbstractNode) = nothing
@mustimplement "Node" get_parent(::AbstractNode)

"Returns the priority of the node depending on the explore strategy."
get_priority(::AbstractExploreStrategy, ::AbstractNode) = nothing
@mustimplement "Node" get_priority(::AbstractExploreStrategy, ::AbstractNode)

##### Addition methods for the node interface (needed by conquer)
"Returns an `OptimizationState` that contains best bounds and solutions at the node."
get_opt_state(::AbstractNode) = nothing # conquer, divide
@mustimplement "Node" get_opt_state(::AbstractNode) # conquer, divide

"Returns a `Records` that allows to restore the state of the formulation at this node."
get_records(::AbstractNode) = nothing # conquer
@mustimplement "Node" get_records(::AbstractNode) # conquer

"Returns a `String` to display the branching constraint."
get_branch_description(::AbstractNode) = nothing # printer
@mustimplement "Node" get_branch_description(::AbstractNode) # printer

"Returns `true` is the node is root; `false` otherwise."
isroot(::AbstractNode) = nothing # BaB implementation
@mustimplement "Node" isroot(::AbstractNode) # BaB implementation

# TODO; remove untreated_nodes
"Evaluate and generate children. This method has a specific implementation for Coluna."
function children(sp, n, env, untreated_nodes)
@warn "children(::$(typeof(sp)), ::$(typeof(n)), ::$(typeof(env)), untreated_nodes) not implemented."
return nothing
end
@mustimplement "TreeSearch" children(sp, n, env, untreated_nodes)

"Returns true if stopping criteria are met; false otherwise."
function stop(sp::AbstractSearchSpace)
@warn "stop($(typeof(sp))) not implemented."
return nothing
end
@mustimplement "TreeSearch" stop(::AbstractSearchSpace)

"Returns the output of the tree search algorithm."
tree_search_output(::AbstractSearchSpace, untreated_nodes) = nothing
@mustimplement "TreeSearch" tree_search_output(::AbstractSearchSpace, untreated_nodes)

############################################################################################
# Tree search interface for Coluna algorithms
Expand All @@ -73,58 +61,40 @@ abstract type AbstractColunaSearchSpace <: AbstractSearchSpace end
# Additional methods to implement to use the tree search algorithms together with Coluna's
# algorithms.
"Returns the previous node explored by the tree search algorithm."
get_previous(s::AbstractColunaSearchSpace) = nothing
@mustimplement "ColunaSearchSpace" get_previous(s::AbstractColunaSearchSpace)

"Sets the previous node explored by the tree search algorithm."
set_previous!(s::AbstractColunaSearchSpace, previous) = nothing
@mustimplement "ColunaSearchSpace" set_previous!(s::AbstractColunaSearchSpace, previous)

"Returns the conquer algorithm."
function get_conquer(sp::AbstractColunaSearchSpace)
@warn "get_conquer(::$(typeof(sp))) not implemented."
return nothing
end
@mustimplement "ColunaSearchSpace" get_conquer(sp::AbstractColunaSearchSpace)

"Returns the divide algorithm."
function get_divide(sp::AbstractColunaSearchSpace)
@warn "get_divide(::$(typeof(sp))) not implemented."
return nothing
end
@mustimplement "ColunaSearchSpace" get_divide(sp::AbstractColunaSearchSpace)

"Returns the reformulation that will be passed to an algorithm."
function get_reformulation(s::AbstractColunaSearchSpace)
@warn "get_reformulation(::$(typeof(s))) not implemented."
return nothing
end
@mustimplement "ColunaSearchSpace" get_reformulation(s::AbstractColunaSearchSpace)

"""
Returns the input that will be passed to an algorithm.
The input can be built from information contained in a search space and a node.
"""
function get_input(a::AbstractAlgorithm, s::AbstractColunaSearchSpace, n::AbstractNode)
@warn "get_input(::$(typeof(a)), ::$(typeof(s)), ::$(typeof(n))) not implemented."
return nothing
end
@mustimplement "ColunaSearchSpace" get_input(a::AbstractAlgorithm, s::AbstractColunaSearchSpace, n::AbstractNode)

"""
Methods to perform operations before the tree search algorithm evaluates a node (`current`).
This is useful to restore the state of the formulation for instance.
"""
function node_change!(previous::AbstractNode, current::AbstractNode, space::AbstractColunaSearchSpace, untreated_nodes)
@warn "node_change!(::$(typeof(previous)), $(typeof(current)), $(typeof(space)), $(typeof(untreated_nodes))) not implemented."
return nothing
end
@mustimplement "ColunaSearchSpace" node_change!(previous::AbstractNode, current::AbstractNode, space::AbstractColunaSearchSpace, untreated_nodes)

"""
Methods to perform operations after the conquer algorithms.
It receives the output of the conquer algorithm.
"""
after_conquer!(::AbstractColunaSearchSpace, current, output) = nothing
@mustimplement "ColunaSearchSpace" after_conquer!(::AbstractColunaSearchSpace, current, output)

"Creates and returns the children of a node associated to a search space."
function new_children(sp::AbstractColunaSearchSpace, candidates, n::AbstractNode)
@warn "new_children(::$(typeof(sp)), ::$(typeof(candidates)), ::$(typeof(n))) not implemented."
return nothing
end
@mustimplement "ColunaSearchSpace" new_children(sp::AbstractColunaSearchSpace, candidates, n::AbstractNode)

# Implementation of the `children` method for the `AbstractColunaSearchSpace` algorithm.
function children(space::AbstractColunaSearchSpace, current::AbstractNode, env, untreated_nodes)
Expand Down
40 changes: 7 additions & 33 deletions src/Algorithm/treesearch/printer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,11 @@
"Super type to dispatch on file printer methods."
abstract type AbstractFilePrinter end

function new_file_printer(T::Type{<:AbstractFilePrinter}, alg)
@warn "new_file_printer(::$(typeof(T)), alg) not implemented."
return nothing
end

function filename(f::AbstractFilePrinter)
@warn "filename(::$(typeof(f))) not implemented."
return nothing
end

function init_tree_search_file!(f::AbstractFilePrinter)
@warn "init_tree_search_file!(::$(typeof(f))) not implemented."
return nothing
end

function print_node_in_tree_search_file!(f::AbstractFilePrinter, node, sp, env)
@warn "print_node_in_tree_search_file!(::$(typeof(f)), ::$(typeof(node)), ::$(typeof(sp)), ::$(typeof(env))) not implemented."
return nothing
end

function close_tree_search_file!(f::AbstractFilePrinter)
@warn "close_tree_search_file!(::$(typeof(f))) not implemented."
return nothing
end
@mustimplement "FilePrinter" new_file_printer(::Type{<:AbstractFilePrinter}, alg)
@mustimplement "FilePrinter" filename(::AbstractFilePrinter)
@mustimplement "FilePrinter" init_tree_search_file!(::AbstractFilePrinter)
@mustimplement "FilePrinter" print_node_in_tree_search_file!(::AbstractFilePrinter, node, space, env)
@mustimplement "FilePrinter" close_tree_search_file!(::AbstractFilePrinter)

############################################################################################
# Log printer API (on stdin)
Expand All @@ -37,15 +18,8 @@ end
"Super type to dispatch on log printer method."
abstract type AbstractLogPrinter end

function new_log_printer(T::Type{<:AbstractLogPrinter})
@warn "new_log_printer(::Type{$T}) not implemented."
return
end

function print_log(l::AbstractLogPrinter, sp, node, env, nb_untreated_nodes)
@warn "print_log $(typeof(l)) not implemented."
return
end
@mustimplement "LogPrinter" new_log_printer(::Type{<:AbstractLogPrinter})
@mustimplement "LogPrinter" print_log(::AbstractLogPrinter, space, node, env, nb_untreated_nodes)

############################################################################################
# File & log printer search space.
Expand Down
6 changes: 5 additions & 1 deletion src/Algorithm/utilities/helpers.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
############################################################################################
#
############################################################################################

is_cont_var(form, var_id) = getperenkind(form, var_id) == Continuous
is_int_val(val, tol) = abs(round(val) - val) < tol
dist_to_int(val) = min(val - floor(val), ceil(val) - val)
dist_to_int(val) = min(val - floor(val), ceil(val) - val)
6 changes: 5 additions & 1 deletion src/ColunaBase/ColunaBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module ColunaBase

using ..Coluna

using DynamicSparseArrays, MathOptInterface, TimerOutputs, RandomNumbers
using DynamicSparseArrays, MathOptInterface, TimerOutputs, RandomNumbers, Random

const MOI = MathOptInterface
const TO = TimerOutputs
Expand Down Expand Up @@ -40,6 +40,10 @@ export UnitType,
export NewStorage, NewStorageUnitManager, AbstractNewStorageUnit, AbstractNewRecord, new_storage_unit,
new_record, record_type, storage_unit_type, restore_from_record!, create_record

# mustimplement.jl
export @mustimplement

include("mustimplement.jl")
include("interface.jl")
include("nestedenum.jl")
include("solsandbounds.jl")
Expand Down
Loading