From e2111f34b64c7a7692cfcacf9236208b580e60b2 Mon Sep 17 00:00:00 2001 From: Azzaare Date: Mon, 5 Aug 2024 06:22:58 +0000 Subject: [PATCH 1/5] Fixes for tests --- Project.toml | 6 +++--- src/ConstraintDomains.jl | 12 ++++++------ src/continuous.jl | 2 +- src/general.jl | 4 ++-- test/Aqua.jl | 12 ++++-------- test/ExplicitImports.jl | 3 +++ test/JET.jl | 3 +++ test/runtests.jl | 9 ++++++++- 8 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 test/ExplicitImports.jl create mode 100644 test/JET.jl diff --git a/Project.toml b/Project.toml index deea278..6a452b5 100644 --- a/Project.toml +++ b/Project.toml @@ -5,7 +5,6 @@ version = "0.3.12" [deps] ConstraintCommons = "e37357d9-0691-492f-a822-e5ea6a920954" -Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" Intervals = "d8418881-c3e1-53bb-8760-2df7ec849ed5" PatternFolds = "c18a7f1d-76ad-4ce4-950d-5419b888513b" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" @@ -13,7 +12,6 @@ TestItems = "1c621080-faea-4a02-84b6-bbd5e436b8fe" [compat] ConstraintCommons = "0.2" -Dictionaries = "0.4" Intervals = "1" PatternFolds = "0.2" StatsBase = "0.34" @@ -23,8 +21,10 @@ julia = "1.8" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a" [targets] -test = ["Aqua", "Test", "TestItemRunner"] +test = ["Aqua", "ExplicitImports", "JET", "Test", "TestItemRunner"] diff --git a/src/ConstraintDomains.jl b/src/ConstraintDomains.jl index 04a608e..efcefb9 100644 --- a/src/ConstraintDomains.jl +++ b/src/ConstraintDomains.jl @@ -1,19 +1,19 @@ module ConstraintDomains # SECTION - Imports -using ConstraintCommons -using Dictionaries -using PatternFolds -using StatsBase -using TestItems +import ConstraintCommons: ConstraintCommons, δ_extrema +# import Dictionaries +import PatternFolds: PatternFolds, Interval, Closed +import StatsBase: sample +import TestItems: @testitem # Exports export AbstractDomain export ContinuousDomain export DiscreteDomain -# export DiscreteSet # not defined export ExploreSettings export RangeDomain +export SetDomain export add! export delete! diff --git a/src/continuous.jl b/src/continuous.jl index fa42182..c631c2b 100644 --- a/src/continuous.jl +++ b/src/continuous.jl @@ -27,7 +27,7 @@ domain(intervals::Vector{I}) where {I<:Interval} = Intervals(intervals) Base.length(itv::Intervals) Return the sum of the length of each interval in `itv`. """ -Base.length(itv::Intervals) = sum(size, get_domain(itv); init = 0) +Base.length(itv::Intervals) = sum(size, get_domain(itv); init=0) """ Base.rand(itv::Intervals) diff --git a/src/general.jl b/src/general.jl index a63b006..2f30dc1 100644 --- a/src/general.jl +++ b/src/general.jl @@ -13,7 +13,7 @@ Extends `Base.convert` for domains. """ function Base.convert(::Type{Intervals}, d::RangeDomain{T}) where {T<:Real} a, b = extrema(get_domain(d)) - return domain(Float64(a) .. Float64(b)) + return domain(Interval{T,Closed,Closed}(a, b)) end function Base.convert(::Type{RangeDomain}, d::Intervals{T}) where {T<:Real} @@ -23,6 +23,6 @@ function Base.convert(::Type{RangeDomain}, d::Intervals{T}) where {T<:Real} return domain(a:b) end -function Base.convert(::Type{RangeDomain}, d::SetDomain{T}) where {T<:Integer} +function Base.convert(::Type{RangeDomain}, d::SetDomain) return domain(collect(get_domain(d))) end diff --git a/test/Aqua.jl b/test/Aqua.jl index 06b8cb1..4ab57d0 100644 --- a/test/Aqua.jl +++ b/test/Aqua.jl @@ -1,14 +1,10 @@ @testset "Aqua.jl" begin - import Aqua - import ConstraintDomains - import Dictionaries - # TODO: Fix the broken tests and remove the `broken = true` flag Aqua.test_all( ConstraintDomains; - ambiguities = (broken = true,), - deps_compat = false, - piracies = (broken = false,), + ambiguities=(broken=true,), + deps_compat=false, + piracies=(broken=false,), ) @testset "Ambiguities: ConstraintDomains" begin @@ -22,7 +18,7 @@ @testset "Dependencies compatibility (no extras)" begin Aqua.test_deps_compat( ConstraintDomains; - check_extras = false, # ignore = [:Random] + check_extras=false, ) end end diff --git a/test/ExplicitImports.jl b/test/ExplicitImports.jl new file mode 100644 index 0000000..c6c9908 --- /dev/null +++ b/test/ExplicitImports.jl @@ -0,0 +1,3 @@ +@testset "Look for Explicit Imports" begin + @test check_no_implicit_imports(ConstraintDomains) === nothing +end diff --git a/test/JET.jl b/test/JET.jl new file mode 100644 index 0000000..471a9cc --- /dev/null +++ b/test/JET.jl @@ -0,0 +1,3 @@ +@testset "Code linting (JET.jl)" begin + JET.test_package(ConstraintDomains; target_defined_modules=true) +end diff --git a/test/runtests.jl b/test/runtests.jl index decf9df..6029b07 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,7 +1,14 @@ +using ConstraintDomains + +using Aqua +using ExplicitImports +using JET using Test using TestItemRunner -@testset "Package tests: ConstraintDomains" begin +@testset "Package tests: ConstraintCommons" begin include("Aqua.jl") + include("ExplicitImports.jl") + include("JET.jl") include("TestItemRunner.jl") end From 6042ba7abb793897f4836450a2c52c8325af143f Mon Sep 17 00:00:00 2001 From: Azzaare Date: Mon, 5 Aug 2024 06:42:17 +0000 Subject: [PATCH 2/5] Fix format --- src/continuous.jl | 2 +- test/Aqua.jl | 11 ++++------- test/JET.jl | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/continuous.jl b/src/continuous.jl index c631c2b..fa42182 100644 --- a/src/continuous.jl +++ b/src/continuous.jl @@ -27,7 +27,7 @@ domain(intervals::Vector{I}) where {I<:Interval} = Intervals(intervals) Base.length(itv::Intervals) Return the sum of the length of each interval in `itv`. """ -Base.length(itv::Intervals) = sum(size, get_domain(itv); init=0) +Base.length(itv::Intervals) = sum(size, get_domain(itv); init = 0) """ Base.rand(itv::Intervals) diff --git a/test/Aqua.jl b/test/Aqua.jl index 4ab57d0..6c67b57 100644 --- a/test/Aqua.jl +++ b/test/Aqua.jl @@ -2,9 +2,9 @@ # TODO: Fix the broken tests and remove the `broken = true` flag Aqua.test_all( ConstraintDomains; - ambiguities=(broken=true,), - deps_compat=false, - piracies=(broken=false,), + ambiguities = (broken = true,), + deps_compat = false, + piracies = (broken = false,), ) @testset "Ambiguities: ConstraintDomains" begin @@ -16,9 +16,6 @@ end @testset "Dependencies compatibility (no extras)" begin - Aqua.test_deps_compat( - ConstraintDomains; - check_extras=false, - ) + Aqua.test_deps_compat(ConstraintDomains; check_extras = false) end end diff --git a/test/JET.jl b/test/JET.jl index 471a9cc..28ceb34 100644 --- a/test/JET.jl +++ b/test/JET.jl @@ -1,3 +1,3 @@ @testset "Code linting (JET.jl)" begin - JET.test_package(ConstraintDomains; target_defined_modules=true) + JET.test_package(ConstraintDomains; target_defined_modules = true) end From d48492a14a40b8342287d8167cf693a12c818ab6 Mon Sep 17 00:00:00 2001 From: Jean-Francois Baffier Date: Mon, 5 Aug 2024 15:55:53 +0900 Subject: [PATCH 3/5] Update Project.toml --- Project.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 6a452b5..fce5441 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ConstraintDomains" uuid = "5800fd60-8556-4464-8d61-84ebf7a0bedb" authors = ["Jean-François Baffier"] -version = "0.3.12" +version = "0.3.13" [deps] ConstraintCommons = "e37357d9-0691-492f-a822-e5ea6a920954" @@ -15,7 +15,6 @@ ConstraintCommons = "0.2" Intervals = "1" PatternFolds = "0.2" StatsBase = "0.34" -TestItemRunner = "0.2, 1" TestItems = "0.1, 1" julia = "1.8" From 33266b9ea27832bd0f343bceec782532acf0b915 Mon Sep 17 00:00:00 2001 From: Jean-Francois Baffier Date: Fri, 4 Oct 2024 13:26:15 +0900 Subject: [PATCH 4/5] Make an Explorer to prepare a JuMP interface and broader search space exploration (#60) * New Explorer structure * Makes the explorer adaptive * Updates for ConstraintExplorer * Fix in explore * Format * Update ci.yml --- .github/workflows/ci.yml | 1 - src/ConstraintDomains.jl | 5 +- src/common.jl | 3 + src/continuous.jl | 1 - src/explore.jl | 139 ++++++++++++++++++++++++++++++++------- src/general.jl | 2 +- 6 files changed, 122 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb19ab3..957dfee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,6 @@ jobs: fail-fast: false matrix: version: - - "1.8" - "1" # automatically expands to the latest stable 1.x release of Julia - "pre" os: diff --git a/src/ConstraintDomains.jl b/src/ConstraintDomains.jl index efcefb9..f094b03 100644 --- a/src/ConstraintDomains.jl +++ b/src/ConstraintDomains.jl @@ -2,7 +2,6 @@ module ConstraintDomains # SECTION - Imports import ConstraintCommons: ConstraintCommons, δ_extrema -# import Dictionaries import PatternFolds: PatternFolds, Interval, Closed import StatsBase: sample import TestItems: @testitem @@ -11,7 +10,7 @@ import TestItems: @testitem export AbstractDomain export ContinuousDomain export DiscreteDomain -export ExploreSettings +export Explorer, ExploreSettings export RangeDomain export SetDomain @@ -19,7 +18,7 @@ export add! export delete! export domain export domain_size -export explore +export explore, explore! export generate_parameters export get_domain export intersect_domains diff --git a/src/common.jl b/src/common.jl index c577bb1..93e68a9 100644 --- a/src/common.jl +++ b/src/common.jl @@ -98,6 +98,9 @@ function Base.string(D::Vector{<:AbstractDomain}) end Base.string(d::AbstractDomain) = replace(string(d.domain), " " => "") +merge_domains(::EmptyDomain, d::D) where {D<:AbstractDomain} = d +merge_domains(d::D, ::EmptyDomain) where {D<:AbstractDomain} = d + ## SECTION - Test Items @testitem "EmptyDomain" tags = [:domains, :empty] begin ed = domain() diff --git a/src/continuous.jl b/src/continuous.jl index fa42182..b02ec11 100644 --- a/src/continuous.jl +++ b/src/continuous.jl @@ -114,7 +114,6 @@ function intersect_domains( return Intervals(new_itvls) end - """ Base.size(i::I) where {I <: Interval} diff --git a/src/explore.jl b/src/explore.jl index 5607d88..db47eab 100644 --- a/src/explore.jl +++ b/src/explore.jl @@ -19,48 +19,137 @@ Settings for the exploration of a search space composed by a collection of domai function ExploreSettings( domains; complete_search_limit = 10^6, - max_samplings = sum(domain_size, domains), + 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} + best::Vector{T} + solutions::Set{Vector{T}} + non_solutions::Set{Vector{T}} + + ExplorerState{T}() where {T} = new{T}([], Set{Vector{T}}(), Set{Vector{T}}()) +end + +ExplorerState(domains) = ExplorerState{Union{map(eltype, domains)...}}() + +mutable struct Explorer{F1<:Function,D<:AbstractDomain,F2<:Union{Function,Nothing},T} + concepts::Dict{Int,Tuple{F1,Vector{Int}}} + domains::Dict{Int,D} + objective::F2 + settings::ExploreSettings + state::ExplorerState{T} + + function Explorer( + concepts, + 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)...} + d_c = Dict(enumerate(concepts)) + d_d = Dict(enumerate(domains)) + return new{F1,D,F2,T}(d_c, d_d, objective, settings, ExplorerState{T}()) + end +end + +function Explorer() + concepts = Vector{Tuple{Function,Vector{Int}}}() + domains = Vector{AbstractDomain}() + objective = nothing + settings = ExploreSettings(domains) + return Explorer(concepts, domains, objective; settings) +end + +function Base.push!(explorer::Explorer, concept::Tuple{Function,Vector{Int}}) + max_key = maximum(keys(explorer.concepts); init = 0) + explorer.concepts[max_key+1] = concept + return max_key + 1 +end + +function delete_concept!(explorer::Explorer, key::Int) + delete!(explorer.concepts, key) + return nothing +end + +function Base.push!(explorer::Explorer, domain::AbstractDomain) + max_key = maximum(keys(explorer.domains); init = 0) + explorer.domains[max_key+1] = domain + return max_key + 1 +end + +function delete_domain!(explorer::Explorer, key::Int) + delete!(explorer.domains, key) + return nothing +end + +set!(explorer::Explorer, objective::Function) = explorer.objective = objective + +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 length(solutions) < sl + push!(solutions, cv) + obj !== nothing && (explorer.state.best = argmin(obj, solutions)) + end + else + if length(non_sltns) < sl + push!(non_sltns, cv) + end + end + return nothing +end + """ _explore(args...) Internals of the `explore` function. Behavior is automatically adjusted on the kind of exploration: `:flexible`, `:complete`, `:partial`. """ -function _explore(domains, f, s, ::Val{:partial}) - solutions = Set{Vector{Int}}() - non_sltns = Set{Vector{Int}}() +function _explore!(explorer, f, ::Val{:partial}) + sl = explorer.settings.solutions_limit + ms = explorer.settings.max_samplings - sl = s.solutions_limit + solutions = explorer.state.solutions + non_sltns = explorer.state.non_solutions + domains = explorer.domains |> values - for _ = 1:s.max_samplings + for _ = 1:ms length(solutions) ≥ sl && length(non_sltns) ≥ sl && break config = map(rand, domains) - c = f(config) ? solutions : non_sltns - length(c) < sl && push!(c, config) + update_exploration!(explorer, f, config) end - return solutions, non_sltns + return nothing end -function _explore(domains, f, ::ExploreSettings, ::Val{:complete}) - solutions = Set{Vector{Int}}() - non_sltns = Set{Vector{Int}}() - - configurations = Base.Iterators.product(map(d -> get_domain(d), domains)...) - foreach( - c -> (cv = collect(c); push!(f(cv) ? solutions : non_sltns, cv)), - configurations, - ) - return solutions, non_sltns +function _explore!(explorer, f, ::Val{:complete}) + C = Base.Iterators.product(map(d -> get_domain(d), explorer.domains |> values)...) + foreach(c -> update_exploration!(explorer, f, c, :complete), C) + return nothing end -function _explore(domains, f, s, ::Val{:flexible}) - search = s.max_samplings < s.complete_search_limit ? :complete : :partial - return _explore(domains, f, s, Val(search)) +function explore!(explorer::Explorer) + c = + x -> all([ + 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)) end """ @@ -78,7 +167,9 @@ Beware that if the density of the solutions in the search space is low, `solutio """ function explore(domains, concept; settings = ExploreSettings(domains), parameters...) f = x -> concept(x; parameters...) - return _explore(domains, f, settings, Val(settings.search)) + explorer = Explorer([(f, Vector{Int}())], domains; settings) + explore!(explorer) + return explorer.state.solutions, explorer.state.non_solutions end ## SECTION - Test Items @@ -87,4 +178,6 @@ end X, X̅ = explore(domains, allunique) @test length(X) == factorial(4) @test length(X̅) == 4^4 - factorial(4) + + explorer = ConstraintDomains.Explorer() end diff --git a/src/general.jl b/src/general.jl index 2f30dc1..0bd7759 100644 --- a/src/general.jl +++ b/src/general.jl @@ -16,7 +16,7 @@ function Base.convert(::Type{Intervals}, d::RangeDomain{T}) where {T<:Real} return domain(Interval{T,Closed,Closed}(a, b)) end -function Base.convert(::Type{RangeDomain}, d::Intervals{T}) where {T<:Real} +function Base.convert(::Type{RangeDomain}, d::Intervals) i = get_domain(d)[1] a = Int(i.first) b = Int(i.last) From 34691001ca90d19b46cc27cf685bb03d9ed0d81c Mon Sep 17 00:00:00 2001 From: Jean-Francois Baffier Date: Fri, 4 Oct 2024 13:27:36 +0900 Subject: [PATCH 5/5] Update Project.toml --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index fce5441..d177f44 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ConstraintDomains" uuid = "5800fd60-8556-4464-8d61-84ebf7a0bedb" authors = ["Jean-François Baffier"] -version = "0.3.13" +version = "0.3.14" [deps] ConstraintCommons = "e37357d9-0691-492f-a822-e5ea6a920954" @@ -16,7 +16,7 @@ Intervals = "1" PatternFolds = "0.2" StatsBase = "0.34" TestItems = "0.1, 1" -julia = "1.8" +julia = "1.10" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"