-
Notifications
You must be signed in to change notification settings - Fork 3
New: GraphProblem #115
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
New: GraphProblem #115
Changes from all commits
38453cc
cb9d9ec
13148ab
0489a41
2d3cd57
2a1957c
0830c5d
8229c19
25225cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,18 +6,22 @@ version = "0.1.1" | |||||
| [deps] | ||||||
| BitBasis = "50ba71b6-fa0f-514d-ae9a-0916efc90dcf" | ||||||
| DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" | ||||||
| Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" | ||||||
| Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" | ||||||
| InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" | ||||||
| MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078" | ||||||
| PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" | ||||||
| Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" | ||||||
|
|
||||||
| [compat] | ||||||
| BitBasis = "0.9" | ||||||
| DocStringExtensions = "0.9" | ||||||
| Documenter = "1.8.0" | ||||||
| Graphs = "1" | ||||||
| InteractiveUtils = "1" | ||||||
| MLStyle = "0.4" | ||||||
| PrettyTables = "2" | ||||||
| Printf = "1.11.0" | ||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please only specify the first nonzero digit in deps. |
||||||
| julia = "1.10" | ||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| [extras] | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| """ | ||
| $TYPEDEF | ||
|
|
||
| The open pit mining problem. | ||
| This problem can be solved in polynomial time with the pseudoflow algorithm. | ||
|
|
||
| Positional arguments | ||
| ------------------------------- | ||
| * `rewards` is a matrix of rewards. | ||
| * `blocks` are the locations of the blocks. | ||
|
|
||
| Example | ||
| ----------------------------------- | ||
| ```jldoctest; setup=:(using GenericTensorNetworks) | ||
| julia> rewards = [-4 -7 -7 -17 -7 -26; | ||
| 0 39 -7 -7 -4 0; | ||
| 0 0 1 8 0 0; | ||
| 0 0 0 0 0 0; | ||
| 0 0 0 0 0 0; | ||
| 0 0 0 0 0 0]; | ||
|
|
||
| julia> gp = GenericTensorNetwork(OpenPitMining(rewards)); | ||
|
|
||
| julia> res = solve(gp, SingleConfigMax())[] | ||
| (21.0, ConfigSampler{12, 1, 1}(111000100000))ₜ | ||
|
|
||
| julia> is_valid_mining(rewards, res.c.data) | ||
| true | ||
|
|
||
| julia> print_mining(rewards, res.c.data) | ||
| -4 -7 -7 -17 -7 -26 | ||
| ◼ 39 -7 -7 -4 ◼ | ||
| ◼ ◼ 1 8 ◼ ◼ | ||
| ◼ ◼ ◼ ◼ ◼ ◼ | ||
| ◼ ◼ ◼ ◼ ◼ ◼ | ||
| ◼ ◼ ◼ ◼ ◼ ◼ | ||
| ``` | ||
|
|
||
| You will the the mining is printed as green in an colored REPL. | ||
| """ | ||
| struct OpenPitMining{ET} <: ConstraintSatisfactionProblem{ET} | ||
| rewards::Matrix{ET} | ||
| blocks::Vector{Tuple{Int,Int}} # non-zero locations | ||
| function OpenPitMining(rewards::Matrix{ET}, blocks::Vector{Tuple{Int,Int}}) where ET | ||
| for (i, j) in blocks | ||
| checkbounds(rewards, i, j) | ||
| end | ||
| new{ET}(rewards, blocks) | ||
| end | ||
| end | ||
| function OpenPitMining(rewards::Matrix{ET}) where ET | ||
| # compute block locations | ||
| blocks = Tuple{Int,Int}[] | ||
| for i=1:size(rewards, 1), j=i:size(rewards,2)-i+1 | ||
| push!(blocks, (i,j)) | ||
| end | ||
| OpenPitMining(rewards, blocks) | ||
| end | ||
|
|
||
| flavors(::Type{<:OpenPitMining}) = [0, 1] | ||
| function set_weights(c::OpenPitMining, get_weights) | ||
| rewards = copy(c.rewards) | ||
| for (w, b) in zip(get_weights, c.blocks) | ||
| rewards[b...] = w | ||
| end | ||
| OpenPitMining(rewards, c.blocks) | ||
| end | ||
|
|
||
| """ | ||
| is_valid_mining(rewards::AbstractMatrix, config) | ||
|
|
||
| Return true if `config` (a boolean mask for the feasible region) is a valid mining of `rewards`. | ||
| """ | ||
| function is_valid_mining(rewards::AbstractMatrix, config) | ||
| blocks = get_blocks(rewards) | ||
| assign = Dict(zip(blocks, config)) | ||
| for block in blocks | ||
| if block[1] != 1 && !iszero(assign[block]) | ||
| if iszero(assign[(block[1]-1, block[2]-1)]) || | ||
| iszero(assign[(block[1]-1, block[2])]) || | ||
| iszero(assign[(block[1]-1, block[2]+1)]) | ||
| return false | ||
| end | ||
| end | ||
| end | ||
| return true | ||
| end | ||
| function get_blocks(rewards) | ||
| blocks = Tuple{Int,Int}[] | ||
| for i=1:size(rewards, 1), j=i:size(rewards,2)-i+1 | ||
| push!(blocks, (i,j)) | ||
| end | ||
| return blocks | ||
| end | ||
|
|
||
| """ | ||
| print_mining(rewards::AbstractMatrix, config) | ||
|
|
||
| Printing the mining solution in a colored REPL. | ||
| """ | ||
| function print_mining(rewards::AbstractMatrix{T}, config) where T | ||
| k = 0 | ||
| for i=1:size(rewards, 1) | ||
| for j=1:size(rewards, 2) | ||
| if j >= i && j <= size(rewards,2)-i+1 | ||
| k += 1 | ||
| if T <: Integer | ||
| str = Printf.@sprintf " %6i " rewards[i,j] | ||
| else | ||
| str = Printf.@sprintf " %6.2F " rewards[i,j] | ||
| end | ||
| if iszero(config[k]) | ||
| printstyled(str; color = :red) | ||
| else | ||
| printstyled(str; color = :green) | ||
| end | ||
| else | ||
| str = Printf.@sprintf " %6s " "◼" | ||
| printstyled(str; color = :black) | ||
| end | ||
| end | ||
| println() | ||
| end | ||
| end | ||
|
|
||
| function _open_pit_mining_branching!(rewards::AbstractMatrix{T}, mask::AbstractMatrix{Bool}, setmask::AbstractMatrix{Bool}, idx::Int) where T | ||
| # find next | ||
| idx < 1 && return zero(T) | ||
| i, j = divrem(idx-1, size(mask, 2)) .+ 1 # row-wise! | ||
| while i > j || size(mask, 1)-i+1 < j || setmask[i, j] # skip not allowed or already decided | ||
| idx -= 1 | ||
| idx < 1 && return zero(T) | ||
| i, j = divrem(idx-1, size(mask, 2)) .+ 1 # row-wise! | ||
| end | ||
| if rewards[i, j] < 0 # do not mine! | ||
| setmask[i, j] = true | ||
| return _open_pit_mining_branching!(rewards, mask, setmask, idx-1) | ||
| else | ||
| _mask = copy(mask) | ||
| _setmask = copy(setmask) | ||
| # CASE 1: try mine current block | ||
| # set mask | ||
| reward0 = set_recur!(mask, setmask, rewards, i, j) | ||
| reward1 = _open_pit_mining_branching!(rewards, mask, setmask, idx-1) + reward0 | ||
|
|
||
| # CASE 1: try do not mine current block | ||
| # unset mask | ||
| _setmask[i, j] = true | ||
| reward2 = _open_pit_mining_branching!(rewards, _mask, _setmask, idx-1) | ||
|
|
||
| # choose the right branch | ||
| if reward2 > reward1 | ||
| copyto!(mask, _mask) | ||
| copyto!(setmask, _setmask) | ||
| return reward2 | ||
| else | ||
| return reward1 | ||
| end | ||
| end | ||
| end | ||
|
|
||
| function set_recur!(mask, setmask, rewards::AbstractMatrix{T}, i, j) where T | ||
| reward = zero(T) | ||
| for k=1:i | ||
| start = max(1, j-(i-k)) | ||
| stop = min(size(mask, 2), j+(i-k)) | ||
| @inbounds for l=start:stop | ||
| if !setmask[k,l] | ||
| mask[k,l] = true | ||
| setmask[k,l] = true | ||
| reward += rewards[k,l] | ||
| end | ||
| end | ||
| end | ||
| return reward | ||
| end | ||
|
|
||
| """ | ||
| open_pit_mining_branching(rewards::AbstractMatrix) | ||
|
|
||
| Solve the open pit mining problem with the naive branching algorithm. | ||
| NOTE: open pit mining can be solved in polynomial time, but this one runs in exponential time. | ||
| """ | ||
| function open_pit_mining_branching(rewards::AbstractMatrix{T}) where T | ||
| idx = length(rewards) | ||
| mask = falses(size(rewards)) | ||
| rewards = _open_pit_mining_branching!(rewards, mask, falses(size(rewards)), idx) | ||
| return rewards, mask | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -200,6 +200,16 @@ end | |
| Base.getindex(::UnitWeight, i) = 1 | ||
| Base.size(w::UnitWeight) = (w.n,) | ||
|
|
||
| """ | ||
| UnitWeight <: AbstractVector{Int} | ||
|
|
||
| The unit weight vector of length `n`. | ||
| """ | ||
| struct ZeroWeight <: AbstractVector{Int} | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove |
||
| n::Int | ||
| end | ||
| Base.getindex(::ZeroWeight, i) = 0 | ||
| Base.size(w::ZeroWeight) = (w.n,) | ||
| """ | ||
| energy_terms(problem::AbstractProblem) -> Vector{LocalConstraint} | ||
|
|
||
|
|
@@ -248,3 +258,4 @@ include("Factoring.jl") | |
| include("Matching.jl") | ||
| include("MaximalIS.jl") | ||
| include("Paintshop.jl") | ||
| include("OpenPitMining.jl") | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This dependency is not needed.