From f173387e4b5ed04f385320363c55e5d600e87c00 Mon Sep 17 00:00:00 2001 From: Azzaare Date: Sun, 8 Jun 2025 10:04:41 +0900 Subject: [PATCH 1/6] fix rebase --- Project.toml | 5 + ext/MetaheuristicsExt/MetaheuristicsExt.jl | 148 +++++++++++++++++++++ src/CompositionalNetworks.jl | 2 +- src/configuration.jl | 4 + src/icn.jl | 21 ++- src/layers/aggregation.jl | 4 +- src/learn_and_explore.jl | 2 +- src/optimizer.jl | 9 ++ test/runtests.jl | 6 +- 9 files changed, 187 insertions(+), 14 deletions(-) create mode 100644 ext/MetaheuristicsExt/MetaheuristicsExt.jl diff --git a/Project.toml b/Project.toml index 43cae80..c012b2f 100644 --- a/Project.toml +++ b/Project.toml @@ -18,14 +18,17 @@ Unrolled = "9602ed7d-8fef-5bc8-8597-8f21381861e8" [weakdeps] Evolutionary = "86b6b26d-c046-49b6-aa0b-5f0f74682bd6" LocalSearchSolvers = "2b10edaa-728d-4283-ac71-07e312d6ccf3" +Metaheuristics = "bcdb8e00-2c21-11e9-3065-2b553b22f898" [extensions] GeneticExt = "Evolutionary" LocalSearchSolversExt = "LocalSearchSolvers" +MetaheuristicsExt = "Metaheuristics" [compat] LocalSearchSolvers = "0.4" Evolutionary = "0.11" +Metaheuristics = "3" ConstraintCommons = "0.3" ConstraintDomains = "0.4" Dictionaries = "0.4" @@ -42,6 +45,7 @@ julia = "1.10" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" Evolutionary = "86b6b26d-c046-49b6-aa0b-5f0f74682bd6" LocalSearchSolvers = "2b10edaa-728d-4283-ac71-07e312d6ccf3" +Metaheuristics = "bcdb8e00-2c21-11e9-3065-2b553b22f898" ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" Memoization = "6fafb56a-5788-4b4e-91ca-c0cea6611c73" @@ -57,6 +61,7 @@ test = [ "Evolutionary", "LocalSearchSolvers", "Memoization", + "Metaheuristics", "Test", "TestItemRunner", "ThreadPools", diff --git a/ext/MetaheuristicsExt/MetaheuristicsExt.jl b/ext/MetaheuristicsExt/MetaheuristicsExt.jl new file mode 100644 index 0000000..e3cbfc7 --- /dev/null +++ b/ext/MetaheuristicsExt/MetaheuristicsExt.jl @@ -0,0 +1,148 @@ +module MetaheuristicsExt + +import CompositionalNetworks: + CompositionalNetworks, AbstractICN, Configurations, manhattan, + hamming +import CompositionalNetworks: MetaheuristicsOptimizer, apply!, weights_bias, regularization +import CompositionalNetworks: evaluate, solutions +import Metaheuristics: Metaheuristics, minimizer, GA, Algorithm, BitArraySpace + +function generate_population(icn, pop_size; vect = []) + population = Vector{BitVector}() + if isempty(vect) + foreach(_ -> push!(population, falses(length(icn.weights))), 1:pop_size) + else + foreach(_ -> push!(population, vect), 1:pop_size) + end + return population +end + +function CompositionalNetworks.MetaheuristicsOptimizer(backend; + maxiters = 400, + maxtime = 500, + extra_functions = Dict(), + bounds = nothing +) + + if backend isa Metaheuristics.Algorithm{<:GA} + extra_functions[:generate_population] = generate_population + end + + return MetaheuristicsOptimizer(maxiters, maxtime, backend, bounds, extra_functions) +end + + +function CompositionalNetworks.optimize!( + icn::T, + configurations::Configurations, + # dom_size, + metric_function::Union{Function, Vector{Function}}, + optimizer_config::MetaheuristicsOptimizer; + samples = nothing, + memoize = false, + parameters... +) where {T <: AbstractICN} + + # @info icn.weights + + # inplace = zeros(dom_size, 18) + solution_iter = solutions(configurations) + non_solutions = solutions(configurations; non_solutions = true) + solution_vector = [i.x for i in solution_iter] + + function fitness(w) + weights_validity = apply!(icn, w) + + a = if metric_function isa Function + metric_function( + icn, + configurations, + solution_vector; + weights_validity = weights_validity, + parameters... + ) + else + minimum( + met -> met( + icn, + configurations, + solution_vector; + weights_validity = weights_validity, + parameters... + ), + metric_function + ) + end + + b = weights_bias(w) + c = regularization(icn) + + function new_regularization(icn::AbstractICN) + start = 1 + count = 0 + total = 0 + for (i, layer) in enumerate(icn.layers) + if !layer.mutex + ran = start:(start + icn.weightlen[i] - 1) + op = findall(icn.weights[ran]) + max_op = ran .- (start - 1) + total += (sum(op) / sum(max_op)) + count += 1 + end + start += icn.weightlen[i] + end + return total / count + end + + d = sum(findall(icn.weights)) / + (length(icn.weights) * (length(icn.weights) + 1) / 2) + + e = new_regularization(icn) + + # @info "Lot of things" a b c d e + #= + println(""" + sum: $a + weights bias: $b + regularization: $c + new reg: $e + thread: $(Threads.threadid()) + """) =# + + return a + b + c + end + + + #= + _icn_ga = GA(; + populationSize = optimizer_config.pop_size, + crossoverRate = 0.8, + epsilon = 0.05, + selection = tournament(4), + crossover = SPX, + mutation = flip, + mutationRate = 1.0 + ) + =# + + # pop = generate_population(icn, optimizer_config.pop_size) + bounds = optimizer_config.bounds + + bounds = if isnothing(bounds) + if optimizer_config.backend isa Metaheuristics.Algorithm{<:GA} + BitSpacedArray(length(icn.weights)) + end + else + optimizer_config.bounds + end + + r = Metaheuristics.optimize( + fitness, + optimizer_config.bounds, + optimizer_config.backend + ) + validity = apply!(icn, Metaheuristics.minimizer(r)) + return icn => validity +end + +end diff --git a/src/CompositionalNetworks.jl b/src/CompositionalNetworks.jl index a225c57..01edebe 100644 --- a/src/CompositionalNetworks.jl +++ b/src/CompositionalNetworks.jl @@ -14,7 +14,7 @@ import Unrolled: @unroll # SECTION - Exports export hamming, minkowski, manhattan, weights_bias -export AbstractOptimizer, GeneticOptimizer, LocalSearchOptimizer, optimize! +export AbstractOptimizer, GeneticOptimizer, LocalSearchOptimizer, optimize!, MetaheuristicsOptimizer export generate_configurations, explore_learn export AbstractLayer, Transformation, Aggregation, LayerCore, Arithmetic, Comparison, SimpleFilter, diff --git a/src/configuration.jl b/src/configuration.jl index 6e98fdb..36e3f4b 100644 --- a/src/configuration.jl +++ b/src/configuration.jl @@ -8,6 +8,10 @@ struct NonSolution <: AbstractSolution x::Any end +struct UnknownSolution <: AbstractSolution + x::Any +end + const Configuration{T} = T where {T <: AbstractSolution} # alias const Configurations{N} = Set{<:Configuration} diff --git a/src/icn.jl b/src/icn.jl index c71dc33..a7b2280 100644 --- a/src/icn.jl +++ b/src/icn.jl @@ -67,7 +67,7 @@ function generate_new_valid_weights!(icn::T) where {T <: AbstractICN} nothing end -function apply!(icn::AbstractICN, weights::BitVector)::Bool +function apply!(icn::AbstractICN, weights::AbstractVector{Bool})::Bool icn.weights .= weights return check_weights_validity(icn, weights) end @@ -106,6 +106,13 @@ function evaluate( end end +evaluate( + icn::AbstractICN, + config::AbstractVector; + weights_validity = true, + parameters... +) = evaluate(icn, UnknownSolution(config); weights_validity = weights_validity, parameters...) + function evaluate( icns::Vector{<:AbstractICN}, config::Configuration; @@ -168,7 +175,7 @@ function evaluate(icn::Nothing, config::Configuration) end =# -(icn::AbstractICN)(weights::BitVector) = apply!(icn, weights) +(icn::AbstractICN)(weights::AbstractVector{Bool}) = apply!(icn, weights) (icn::AbstractICN)(config::Configuration) = evaluate(icn, config) struct ICN{S} <: AbstractICN where {S <: Union{AbstractVector{<:AbstractLayer}, Nothing}} @@ -179,11 +186,11 @@ struct ICN{S} <: AbstractICN where {S <: Union{AbstractVector{<:AbstractLayer}, weightlen::AbstractVector{Int} constants::Dict function ICN(; - weights = BitVector[], - parameters = Symbol[], - layers = [Transformation, Arithmetic, Aggregation, Comparison], - connection = UInt32[1, 2, 3, 4], - constants = Dict() + weights = AbstractVector{Bool}[], + parameters = Symbol[], + layers = [Transformation, Arithmetic, Aggregation, Comparison], + connection = UInt32[1, 2, 3, 4], + constants = Dict() ) len = [length(layer.fn) for layer in layers] diff --git a/src/layers/aggregation.jl b/src/layers/aggregation.jl index 0cfaf68..0162cac 100644 --- a/src/layers/aggregation.jl +++ b/src/layers/aggregation.jl @@ -6,8 +6,8 @@ const Aggregation = LayerCore( sum = :((x) -> sum(x)), count_positive = :((x) -> count(i -> i > 0, x)), count_op_val = :((x; val, op) -> count(i -> op(i, val), x)), - maximum = :((x) -> isempty(x) ? typemax(eltype(x)) : maximum(x)), - minimum = :((x) -> isempty(x) ? typemax(eltype(x)) : minimum(x)) + # maximum = :((x) -> isempty(x) ? typemax(eltype(x)) : maximum(x)), + # minimum = :((x) -> isempty(x) ? typemax(eltype(x)) : minimum(x)) ) ) diff --git a/src/learn_and_explore.jl b/src/learn_and_explore.jl index 92ee378..f7f1452 100644 --- a/src/learn_and_explore.jl +++ b/src/learn_and_explore.jl @@ -48,7 +48,7 @@ function explore_learn( configurations = generate_configurations(concept, domains; parameters...) end - icn.constants[:dom_size] = maximum(length, domains) + icn.constants[:dom_size] = maximum(x -> maximum(x.domain) - minimum(x.domain) + 1, domains) icn.constants[:numvars] = length(domains) return optimize!( diff --git a/src/optimizer.jl b/src/optimizer.jl index de4bb31..2af2053 100644 --- a/src/optimizer.jl +++ b/src/optimizer.jl @@ -77,6 +77,15 @@ end )[2] end +# SECTION - Metaheuristics Extension +struct MetaheuristicsOptimizer <: AbstractOptimizer + maxiters::Int64 + maxtime::Float64 + backend + bounds + extra_functions::Dict{Symbol, Function} +end + # SECTION - CBLSOptimizer Extension struct LocalSearchOptimizer <: AbstractOptimizer options::Any diff --git a/test/runtests.jl b/test/runtests.jl index 457a2a8..0acff18 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,8 +7,8 @@ using Test using TestItemRunner @testset "Package tests: ConstraintCommons" begin - # include("Aqua.jl") - # include("ExplicitImports.jl") - # include("JET.jl") + include("Aqua.jl") + include("ExplicitImports.jl") + include("JET.jl") include("TestItemRunner.jl") end From 1f92ef169e24c12e2e2318f775ddc7e8a113346b Mon Sep 17 00:00:00 2001 From: Azzaare Date: Sun, 8 Jun 2025 10:27:31 +0900 Subject: [PATCH 2/6] Added a TODO for @Varlad --- src/optimizer.jl | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/optimizer.jl b/src/optimizer.jl index 2af2053..a5b39bb 100644 --- a/src/optimizer.jl +++ b/src/optimizer.jl @@ -81,11 +81,55 @@ end struct MetaheuristicsOptimizer <: AbstractOptimizer maxiters::Int64 maxtime::Float64 - backend - bounds + backend::Any + bounds::Any extra_functions::Dict{Symbol, Function} end +@testitem "Metaheuristics" tags=[:extension] default_imports=false begin + import CompositionalNetworks: + Transformation, Arithmetic, Aggregation, Comparison, ICN, + SimpleFilter + import CompositionalNetworks: GeneticOptimizer, explore_learn + import ConstraintDomains: domain + import Metaheuristics + import Test: @test + + test_icn = ICN(; + parameters = [:dom_size, :numvars, :val], + layers = [Transformation, Arithmetic, Aggregation, Comparison], + connection = [1, 2, 3, 4] + ) + + function allunique_val(x; val) + for i in 1:(length(x) - 1) + for j in (i + 1):length(x) + if x[i] == x[j] + if x[i] != val + return false + end + end + end + end + return true + end + + function allunique_vals(x; vals) + for i in 1:(length(x) - 1) + for j in (i + 1):length(x) + if x[i] == x[j] + if !(x[i] in vals) + return false + end + end + end + end + return true + end + + #TODO - Add tests @VarLad +end + # SECTION - CBLSOptimizer Extension struct LocalSearchOptimizer <: AbstractOptimizer options::Any From 88e50dbb7c0ae9d8e7643a4de1e70f65bffda4c8 Mon Sep 17 00:00:00 2001 From: Chetan Vardhan Date: Tue, 10 Jun 2025 07:10:55 +0000 Subject: [PATCH 3/6] fix typo --- ext/MetaheuristicsExt/MetaheuristicsExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/MetaheuristicsExt/MetaheuristicsExt.jl b/ext/MetaheuristicsExt/MetaheuristicsExt.jl index e3cbfc7..ab439f6 100644 --- a/ext/MetaheuristicsExt/MetaheuristicsExt.jl +++ b/ext/MetaheuristicsExt/MetaheuristicsExt.jl @@ -130,7 +130,7 @@ function CompositionalNetworks.optimize!( bounds = if isnothing(bounds) if optimizer_config.backend isa Metaheuristics.Algorithm{<:GA} - BitSpacedArray(length(icn.weights)) + BitArraySpace(length(icn.weights)) end else optimizer_config.bounds From 3534a21848d64784764edd23a4135812da654ab8 Mon Sep 17 00:00:00 2001 From: Chetan Vardhan Date: Tue, 10 Jun 2025 07:30:39 +0000 Subject: [PATCH 4/6] fix another typo --- ext/MetaheuristicsExt/MetaheuristicsExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/MetaheuristicsExt/MetaheuristicsExt.jl b/ext/MetaheuristicsExt/MetaheuristicsExt.jl index ab439f6..84a1468 100644 --- a/ext/MetaheuristicsExt/MetaheuristicsExt.jl +++ b/ext/MetaheuristicsExt/MetaheuristicsExt.jl @@ -138,7 +138,7 @@ function CompositionalNetworks.optimize!( r = Metaheuristics.optimize( fitness, - optimizer_config.bounds, + bounds, optimizer_config.backend ) validity = apply!(icn, Metaheuristics.minimizer(r)) From 9bc2077c2a5071565a9e8ce9707d97435073557c Mon Sep 17 00:00:00 2001 From: Chetan Vardhan Date: Tue, 10 Jun 2025 07:57:31 +0000 Subject: [PATCH 5/6] add metaheuristics test --- src/optimizer.jl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/optimizer.jl b/src/optimizer.jl index a5b39bb..5dfa161 100644 --- a/src/optimizer.jl +++ b/src/optimizer.jl @@ -97,7 +97,7 @@ end test_icn = ICN(; parameters = [:dom_size, :numvars, :val], - layers = [Transformation, Arithmetic, Aggregation, Comparison], + layers = [SimpleFilter, Transformation, Arithmetic, Aggregation, Comparison], connection = [1, 2, 3, 4] ) @@ -127,7 +127,14 @@ end return true end - #TODO - Add tests @VarLad + @test explore_learn( + [domain([1, 2, 3, 4]) for i in 1:4], + allunique_val, + MetaheuristicsOptimizer(GA()), # use whatever optimizer here as provided by Metaheuristics.jl, I'm using GA + icn = test_icn, + val = 3 + )[2] + end # SECTION - CBLSOptimizer Extension From 27eae90b7272678a003931cebfedf3502ac4629c Mon Sep 17 00:00:00 2001 From: Azzaare Date: Wed, 11 Jun 2025 12:29:33 +0900 Subject: [PATCH 6/6] Fix tests import and format --- ext/MetaheuristicsExt/MetaheuristicsExt.jl | 3 --- src/CompositionalNetworks.jl | 3 ++- src/icn.jl | 17 ++++++++++------- src/layer.jl | 2 +- src/layers/aggregation.jl | 4 +--- src/learn_and_explore.jl | 3 ++- src/optimizer.jl | 5 ++--- 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/ext/MetaheuristicsExt/MetaheuristicsExt.jl b/ext/MetaheuristicsExt/MetaheuristicsExt.jl index 84a1468..98fc199 100644 --- a/ext/MetaheuristicsExt/MetaheuristicsExt.jl +++ b/ext/MetaheuristicsExt/MetaheuristicsExt.jl @@ -23,7 +23,6 @@ function CompositionalNetworks.MetaheuristicsOptimizer(backend; extra_functions = Dict(), bounds = nothing ) - if backend isa Metaheuristics.Algorithm{<:GA} extra_functions[:generate_population] = generate_population end @@ -31,7 +30,6 @@ function CompositionalNetworks.MetaheuristicsOptimizer(backend; return MetaheuristicsOptimizer(maxiters, maxtime, backend, bounds, extra_functions) end - function CompositionalNetworks.optimize!( icn::T, configurations::Configurations, @@ -112,7 +110,6 @@ function CompositionalNetworks.optimize!( return a + b + c end - #= _icn_ga = GA(; populationSize = optimizer_config.pop_size, diff --git a/src/CompositionalNetworks.jl b/src/CompositionalNetworks.jl index 01edebe..d844ea9 100644 --- a/src/CompositionalNetworks.jl +++ b/src/CompositionalNetworks.jl @@ -14,7 +14,8 @@ import Unrolled: @unroll # SECTION - Exports export hamming, minkowski, manhattan, weights_bias -export AbstractOptimizer, GeneticOptimizer, LocalSearchOptimizer, optimize!, MetaheuristicsOptimizer +export AbstractOptimizer, GeneticOptimizer, LocalSearchOptimizer, optimize!, + MetaheuristicsOptimizer export generate_configurations, explore_learn export AbstractLayer, Transformation, Aggregation, LayerCore, Arithmetic, Comparison, SimpleFilter, diff --git a/src/icn.jl b/src/icn.jl index a7b2280..15c53c1 100644 --- a/src/icn.jl +++ b/src/icn.jl @@ -106,12 +106,15 @@ function evaluate( end end -evaluate( +function evaluate( icn::AbstractICN, config::AbstractVector; weights_validity = true, parameters... -) = evaluate(icn, UnknownSolution(config); weights_validity = weights_validity, parameters...) +) + evaluate( + icn, UnknownSolution(config); weights_validity = weights_validity, parameters...) +end function evaluate( icns::Vector{<:AbstractICN}, @@ -186,11 +189,11 @@ struct ICN{S} <: AbstractICN where {S <: Union{AbstractVector{<:AbstractLayer}, weightlen::AbstractVector{Int} constants::Dict function ICN(; - weights = AbstractVector{Bool}[], - parameters = Symbol[], - layers = [Transformation, Arithmetic, Aggregation, Comparison], - connection = UInt32[1, 2, 3, 4], - constants = Dict() + weights = AbstractVector{Bool}[], + parameters = Symbol[], + layers = [Transformation, Arithmetic, Aggregation, Comparison], + connection = UInt32[1, 2, 3, 4], + constants = Dict() ) len = [length(layer.fn) for layer in layers] diff --git a/src/layer.jl b/src/layer.jl index a492ba4..93225fc 100644 --- a/src/layer.jl +++ b/src/layer.jl @@ -7,7 +7,7 @@ struct LayerCore <: AbstractLayer mutex::Bool argtype::Pair fnexprs::NamedTuple{ - names, T} where {names, T <: Tuple{Vararg{<:Union{Symbol, JLFunction}}}} + names, T} where {names, T <: Tuple{Vararg{Union{Symbol, JLFunction}}}} fn::NamedTuple{names, T} where {names, T <: Tuple{Vararg{Function}}} function LayerCore(name::Symbol, mutex::Bool, Q::Pair, fnexprs) fnexprs = map(x -> JLFunction(x), fnexprs) diff --git a/src/layers/aggregation.jl b/src/layers/aggregation.jl index 0162cac..6ec89f6 100644 --- a/src/layers/aggregation.jl +++ b/src/layers/aggregation.jl @@ -5,9 +5,7 @@ const Aggregation = LayerCore( ( sum = :((x) -> sum(x)), count_positive = :((x) -> count(i -> i > 0, x)), - count_op_val = :((x; val, op) -> count(i -> op(i, val), x)), - # maximum = :((x) -> isempty(x) ? typemax(eltype(x)) : maximum(x)), - # minimum = :((x) -> isempty(x) ? typemax(eltype(x)) : minimum(x)) + count_op_val = :((x; val, op) -> count(i -> op(i, val), x)) # maximum = :((x) -> isempty(x) ? typemax(eltype(x)) : maximum(x)), # minimum = :((x) -> isempty(x) ? typemax(eltype(x)) : minimum(x)) ) ) diff --git a/src/learn_and_explore.jl b/src/learn_and_explore.jl index f7f1452..a68670d 100644 --- a/src/learn_and_explore.jl +++ b/src/learn_and_explore.jl @@ -48,7 +48,8 @@ function explore_learn( configurations = generate_configurations(concept, domains; parameters...) end - icn.constants[:dom_size] = maximum(x -> maximum(x.domain) - minimum(x.domain) + 1, domains) + icn.constants[:dom_size] = maximum( + x -> maximum(x.domain) - minimum(x.domain) + 1, domains) icn.constants[:numvars] = length(domains) return optimize!( diff --git a/src/optimizer.jl b/src/optimizer.jl index 5dfa161..4c6f431 100644 --- a/src/optimizer.jl +++ b/src/optimizer.jl @@ -90,9 +90,9 @@ end import CompositionalNetworks: Transformation, Arithmetic, Aggregation, Comparison, ICN, SimpleFilter - import CompositionalNetworks: GeneticOptimizer, explore_learn + import CompositionalNetworks: MetaheuristicsOptimizer, explore_learn import ConstraintDomains: domain - import Metaheuristics + import Metaheuristics: GA import Test: @test test_icn = ICN(; @@ -134,7 +134,6 @@ end icn = test_icn, val = 3 )[2] - end # SECTION - CBLSOptimizer Extension