Skip to content

Target a slowdown in exploration performances #70

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

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ConstraintDomains"
uuid = "5800fd60-8556-4464-8d61-84ebf7a0bedb"
authors = ["Jean-François Baffier"]
version = "0.3.15"
version = "0.4.0"

[deps]
ConstraintCommons = "e37357d9-0691-492f-a822-e5ea6a920954"
Expand All @@ -11,7 +11,7 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
TestItems = "1c621080-faea-4a02-84b6-bbd5e436b8fe"

[compat]
ConstraintCommons = "0.2"
ConstraintCommons = "0.2, 0.3"
Intervals = "1"
PatternFolds = "0.2"
StatsBase = "0.34"
Expand Down
85 changes: 51 additions & 34 deletions src/explore.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
struct ExploreSettings
mutable struct ExploreSettings
complete_search_limit::Int
max_samplings::Int
search::Symbol
Expand Down Expand Up @@ -34,30 +34,53 @@ settings = ExploreSettings(domains, search = :complete)
"""
function ExploreSettings(
domains;
complete_search_limit = 10^6,
max_samplings = sum(domain_size, domains; init = 0),
search = :flexible,
solutions_limit = floor(Int, sqrt(max_samplings)),
complete_search_limit=10^6,
max_samplings=sum(domain_size, domains; init=0),
search=:flexible,
solutions_limit=floor(Int, sqrt(max_samplings)),
)
return ExploreSettings(complete_search_limit, max_samplings, search, solutions_limit)
end

struct ExplorerState{T}
abstract type AbstractExplorerState end

struct CompleteExplorerState{N,T} <: AbstractExplorerState
best::Vector{T}
solutions::Vector{NTuple{N,T}}
non_solutions::Vector{NTuple{N,T}}

CompleteExplorerState{N,T}() where {N,T} = new{N,T}(Vector{T}(), Vector{NTuple{N,T}}(), Vector{NTuple{N,T}}())
end

function explorer_state(domains, ::Val{:complete})
return CompleteExplorerState{length(domains),Union{map(eltype, domains)...}}()
end

struct PartialExplorerState{T} <: AbstractExplorerState
best::Vector{T}
solutions::Set{Vector{T}}
non_solutions::Set{Vector{T}}

ExplorerState{T}() where {T} = new{T}([], Set{Vector{T}}(), Set{Vector{T}}())
PartialExplorerState{T}() where {T} = new{T}(Vector{T}(), Set{Vector{T}}(), Set{Vector{T}}())
end
function explorer_state(domains, ::Val{:partial})
return PartialExplorerState{Union{map(eltype, domains)...}}()
end

ExplorerState(domains) = ExplorerState{Union{map(eltype, domains)...}}()

mutable struct Explorer{F1<:Function,D<:AbstractDomain,F2<:Union{Function,Nothing},T}
mutable struct Explorer{F1<:Function,D<:AbstractDomain,F2<:Union{Function,Nothing},S<:AbstractExplorerState}
concepts::Dict{Int,Tuple{F1,Vector{Int}}}
domains::Dict{Int,D}
objective::F2
settings::ExploreSettings
state::ExplorerState{T}
state::S

function Explorer(concepts, domains, objective, settings, state)
F1 = isempty(concepts) ? Function : typeof(concepts).parameters[2].parameters[1]
D = isempty(domains) ? AbstractDomain : typeof(domains).parameters[2]
F2 = typeof(objective)
S = typeof(state)
return new{F1,D,F2,S}(concepts, domains, objective, settings, state)
end
end

"""
Expand Down Expand Up @@ -85,16 +108,16 @@ explorer = Explorer(concepts, domains, objective)
function Explorer(
concepts,
domains,
objective = nothing;
settings = ExploreSettings(domains),
objective=nothing;
settings=ExploreSettings(domains),
)
F1 = isempty(concepts) ? Function : Union{map(c -> typeof(c[1]), concepts)...}
D = isempty(domains) ? AbstractDomain : Union{map(typeof, domains)...}
F2 = typeof(objective)
T = isempty(domains) ? Real : Union{map(eltype, domains)...}
if settings.search == :flexible
settings.search = settings.max_samplings < settings.complete_search_limit ? :complete : :partial
end
state = explorer_state(domains, Val(settings.search))
d_c = Dict(enumerate(concepts))
d_d = Dict(enumerate(domains))
return Explorer{F1,D,F2,T}(d_c, d_d, objective, settings, ExplorerState{T}())
return Explorer(d_c, d_d, objective, settings, state)
end

function Explorer()
Expand Down Expand Up @@ -124,7 +147,7 @@ key = push!(explorer, (sum, [1, 2]))
```
"""
function Base.push!(explorer::Explorer, concept::Tuple{Function,Vector{Int}})
max_key = maximum(keys(explorer.concepts); init = 0)
max_key = maximum(keys(explorer.concepts); init=0)
explorer.concepts[max_key+1] = concept
return max_key + 1
end
Expand Down Expand Up @@ -171,7 +194,7 @@ key = push!(explorer, domain([1, 2, 3]))
```
"""
function Base.push!(explorer::Explorer, domain::AbstractDomain)
max_key = maximum(keys(explorer.domains); init = 0)
max_key = maximum(keys(explorer.domains); init=0)
explorer.domains[max_key+1] = domain
return max_key + 1
end
Expand Down Expand Up @@ -219,21 +242,20 @@ set!(explorer, x -> sum(x))
"""
set!(explorer::Explorer, objective::Function) = explorer.objective = objective

function update_exploration!(explorer, f, c, search = explorer.settings.search)
function update_exploration!(explorer, f, c, search=explorer.settings.search)
solutions = explorer.state.solutions
non_sltns = explorer.state.non_solutions
obj = explorer.objective
sl = search == :complete ? Inf : explorer.settings.solutions_limit

cv = collect(c)
if f(cv)
if f(c)
if length(solutions) < sl
push!(solutions, cv)
push!(solutions, c)
obj !== nothing && (explorer.state.best = argmin(obj, solutions))
end
else
if length(non_sltns) < sl
push!(non_sltns, cv)
push!(non_sltns, c)
end
end
return nothing
Expand Down Expand Up @@ -261,7 +283,7 @@ function _explore!(explorer, f, ::Val{:partial};)
end

function _explore!(explorer, f, ::Val{:complete})
C = Base.Iterators.product(map(d -> get_domain(d), explorer.domains |> values)...)
C = Base.Iterators.product(Iterators.map(d -> get_domain(d), explorer.domains |> values)...)
foreach(c -> update_exploration!(explorer, f, c, :complete), C)
return nothing
end
Expand Down Expand Up @@ -293,12 +315,7 @@ function explore!(explorer::Explorer)
f(isempty(vars) ? x : @view x[vars]) for
(f, vars) in explorer.concepts |> values
])
s = explorer.settings
search = s.search
if search == :flexible
search = s.max_samplings < s.complete_search_limit ? :complete : :partial
end
return _explore!(explorer, c, Val(search))
return _explore!(explorer, c, Val(explorer.settings.search))
end


Expand All @@ -322,7 +339,7 @@ domains = [domain([1, 2, 3]), domain([4, 5, 6])]
solutions, non_solutions = explore(domains, allunique)
```
"""
function explore(domains, concept; settings = ExploreSettings(domains), parameters...)
function explore(domains, concept; settings=ExploreSettings(domains), parameters...)
f = x -> concept(x; parameters...)
explorer = Explorer([(f, Vector{Int}())], domains; settings)
explore!(explorer)
Expand All @@ -346,5 +363,5 @@ end
@test length(X) == factorial(4)
@test length(X̅) == 4^4 - factorial(4)

explorer = ConstraintDomains.Explorer()
explorer = ConstraintDomains.Explorer([(allunique, 1:4)], domains)
end
Loading