|
1 | | -struct ExploreSettings |
| 1 | +mutable struct ExploreSettings |
2 | 2 | complete_search_limit::Int |
3 | 3 | max_samplings::Int |
4 | 4 | search::Symbol |
@@ -42,22 +42,52 @@ function ExploreSettings( |
42 | 42 | return ExploreSettings(complete_search_limit, max_samplings, search, solutions_limit) |
43 | 43 | end |
44 | 44 |
|
45 | | -struct ExplorerState{T} |
| 45 | +abstract type AbstractExplorerState end |
| 46 | + |
| 47 | +struct CompleteExplorerState{N,T} <: AbstractExplorerState |
| 48 | + best::Vector{T} |
| 49 | + solutions::Vector{NTuple{N,T}} |
| 50 | + non_solutions::Vector{NTuple{N,T}} |
| 51 | + |
| 52 | + CompleteExplorerState{N,T}() where {N,T} = |
| 53 | + new{N,T}(Vector{T}(), Vector{NTuple{N,T}}(), Vector{NTuple{N,T}}()) |
| 54 | +end |
| 55 | + |
| 56 | +function explorer_state(domains, ::Val{:complete}) |
| 57 | + return CompleteExplorerState{length(domains),Union{map(eltype, domains)...}}() |
| 58 | +end |
| 59 | + |
| 60 | +struct PartialExplorerState{T} <: AbstractExplorerState |
46 | 61 | best::Vector{T} |
47 | 62 | solutions::Set{Vector{T}} |
48 | 63 | non_solutions::Set{Vector{T}} |
49 | 64 |
|
50 | | - ExplorerState{T}() where {T} = new{T}([], Set{Vector{T}}(), Set{Vector{T}}()) |
| 65 | + PartialExplorerState{T}() where {T} = |
| 66 | + new{T}(Vector{T}(), Set{Vector{T}}(), Set{Vector{T}}()) |
| 67 | +end |
| 68 | +function explorer_state(domains, ::Val{:partial}) |
| 69 | + return PartialExplorerState{Union{map(eltype, domains)...}}() |
51 | 70 | end |
52 | 71 |
|
53 | | -ExplorerState(domains) = ExplorerState{Union{map(eltype, domains)...}}() |
54 | | - |
55 | | -mutable struct Explorer{F1<:Function,D<:AbstractDomain,F2<:Union{Function,Nothing},T} |
| 72 | +mutable struct Explorer{ |
| 73 | + F1<:Function, |
| 74 | + D<:AbstractDomain, |
| 75 | + F2<:Union{Function,Nothing}, |
| 76 | + S<:AbstractExplorerState, |
| 77 | +} |
56 | 78 | concepts::Dict{Int,Tuple{F1,Vector{Int}}} |
57 | 79 | domains::Dict{Int,D} |
58 | 80 | objective::F2 |
59 | 81 | settings::ExploreSettings |
60 | | - state::ExplorerState{T} |
| 82 | + state::S |
| 83 | + |
| 84 | + function Explorer(concepts, domains, objective, settings, state) |
| 85 | + F1 = isempty(concepts) ? Function : typeof(concepts).parameters[2].parameters[1] |
| 86 | + D = isempty(domains) ? AbstractDomain : typeof(domains).parameters[2] |
| 87 | + F2 = typeof(objective) |
| 88 | + S = typeof(state) |
| 89 | + return new{F1,D,F2,S}(concepts, domains, objective, settings, state) |
| 90 | + end |
61 | 91 | end |
62 | 92 |
|
63 | 93 | """ |
@@ -88,13 +118,14 @@ function Explorer( |
88 | 118 | objective = nothing; |
89 | 119 | settings = ExploreSettings(domains), |
90 | 120 | ) |
91 | | - F1 = isempty(concepts) ? Function : Union{map(c -> typeof(c[1]), concepts)...} |
92 | | - D = isempty(domains) ? AbstractDomain : Union{map(typeof, domains)...} |
93 | | - F2 = typeof(objective) |
94 | | - T = isempty(domains) ? Real : Union{map(eltype, domains)...} |
| 121 | + if settings.search == :flexible |
| 122 | + settings.search = |
| 123 | + settings.max_samplings < settings.complete_search_limit ? :complete : :partial |
| 124 | + end |
| 125 | + state = explorer_state(domains, Val(settings.search)) |
95 | 126 | d_c = Dict(enumerate(concepts)) |
96 | 127 | d_d = Dict(enumerate(domains)) |
97 | | - return Explorer{F1,D,F2,T}(d_c, d_d, objective, settings, ExplorerState{T}()) |
| 128 | + return Explorer(d_c, d_d, objective, settings, state) |
98 | 129 | end |
99 | 130 |
|
100 | 131 | function Explorer() |
@@ -225,15 +256,14 @@ function update_exploration!(explorer, f, c, search = explorer.settings.search) |
225 | 256 | obj = explorer.objective |
226 | 257 | sl = search == :complete ? Inf : explorer.settings.solutions_limit |
227 | 258 |
|
228 | | - cv = collect(c) |
229 | | - if f(cv) |
| 259 | + if f(c) |
230 | 260 | if length(solutions) < sl |
231 | | - push!(solutions, cv) |
| 261 | + push!(solutions, c) |
232 | 262 | obj !== nothing && (explorer.state.best = argmin(obj, solutions)) |
233 | 263 | end |
234 | 264 | else |
235 | 265 | if length(non_sltns) < sl |
236 | | - push!(non_sltns, cv) |
| 266 | + push!(non_sltns, c) |
237 | 267 | end |
238 | 268 | end |
239 | 269 | return nothing |
@@ -261,7 +291,9 @@ function _explore!(explorer, f, ::Val{:partial};) |
261 | 291 | end |
262 | 292 |
|
263 | 293 | function _explore!(explorer, f, ::Val{:complete}) |
264 | | - C = Base.Iterators.product(map(d -> get_domain(d), explorer.domains |> values)...) |
| 294 | + C = Base.Iterators.product( |
| 295 | + Iterators.map(d -> get_domain(d), explorer.domains |> values)..., |
| 296 | + ) |
265 | 297 | foreach(c -> update_exploration!(explorer, f, c, :complete), C) |
266 | 298 | return nothing |
267 | 299 | end |
@@ -293,12 +325,7 @@ function explore!(explorer::Explorer) |
293 | 325 | f(isempty(vars) ? x : @view x[vars]) for |
294 | 326 | (f, vars) in explorer.concepts |> values |
295 | 327 | ]) |
296 | | - s = explorer.settings |
297 | | - search = s.search |
298 | | - if search == :flexible |
299 | | - search = s.max_samplings < s.complete_search_limit ? :complete : :partial |
300 | | - end |
301 | | - return _explore!(explorer, c, Val(search)) |
| 328 | + return _explore!(explorer, c, Val(explorer.settings.search)) |
302 | 329 | end |
303 | 330 |
|
304 | 331 |
|
|
346 | 373 | @test length(X) == factorial(4) |
347 | 374 | @test length(X̅) == 4^4 - factorial(4) |
348 | 375 |
|
349 | | - explorer = ConstraintDomains.Explorer() |
| 376 | + explorer = ConstraintDomains.Explorer([(allunique, 1:4)], domains) |
350 | 377 | end |
0 commit comments