Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "CompositionalNetworks"
uuid = "4b67e4b5-442d-4ef5-b760-3f5df3a57537"
authors = ["Jean-François Baffier"]
version = "0.1.0"
version = "0.1.1"

[deps]
ConstraintDomains = "5800fd60-8556-4464-8d61-84ebf7a0bedb"
Expand Down
48 changes: 26 additions & 22 deletions src/comparison.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,69 @@
_co_identity(x::Number)
Identity function. Already defined in Julia as `identity`, specialized for scalars in the `comparison` layer.
"""
_co_identity(x) = identity(x)
_co_identity(x; param=nothing, dom_size=0, nvars=0) = identity(x)

"""
_co_abs_diff_val_param(x, param)
Return the absolute difference between `x` and `param`.
"""
_co_abs_diff_val_param(x, param) = abs(x - param)
_co_abs_diff_val_param(x; param, dom_size=0, nvars=0) = abs(x - param)

"""
_co_val_minus_param(x, param)
_co_param_minus_val(x, param)
Return the difference `x - param` (resp. `param - x`) if positive, `0.0` otherwise.
"""
_co_val_minus_param(x, param) = max(0.0, x - param)
_co_param_minus_val(x, param) = max(0.0, param - x)
_co_val_minus_param(x; param, dom_size=0, nvars=0) = max(0.0, x - param)
_co_param_minus_val(x; param, dom_size=0, nvars=0) = max(0.0, param - x)

"""
_co_euclidian_param(x, param, ds)
_co_euclidian(x, ds)
Compute an euclidian norm with domain size `ds`, possibly weigthed by `param`, on a scalar.
"""
_co_euclidian_param(x, param, ds) = x == param ? 0.0 : (1.0 + abs(x - param) \ ds)
_co_euclidian(x, ds) = _co_euclidian_param(x, 0.0, ds)
function _co_euclidian_param(x; param, dom_size, nvars=0)
return x == param ? 0.0 : (1.0 + abs(x - param) \ dom_size)
end
function _co_euclidian(x; param=nothing, dom_size, nvars=0)
return _co_euclidian_param(x; param=0.0, dom_size=dom_size)
end

"""
_co_abs_diff_val_vars(x, nvars)
Return the absolute difference between `x` and the number of variables `nvars`.
"""
_co_abs_diff_val_vars(x, nvars) = abs(x - nvars)
_co_abs_diff_val_vars(x; param=nothing, dom_size=0, nvars) = abs(x - nvars)

"""
_co_val_minus_vars(x, nvars)
_co_vars_minus_val(x, nvars)
Return the difference `x - nvars` (resp. `nvars - x`) if positive, `0.0` otherwise, where `nvars` denotes the numbers of variables.
"""
_co_val_minus_vars(x, nvars) = _co_val_minus_param(x, nvars)
_co_vars_minus_val(x, nvars) = _co_param_minus_val(x, nvars)
_co_val_minus_vars(x; param=nothing, dom_size=0, nvars) = _co_val_minus_param(x; param=nvars)
_co_vars_minus_val(x; param=nothing, dom_size=0, nvars) = _co_param_minus_val(x; param=nvars)

"""
comparison_layer(nvars, dom_size, param = nothing)
Generate the layer of transformations functions of the ICN. Iff `param` value is set, also includes all the parametric transformation with that value.
"""
function comparison_layer(nvars, dom_size, param = nothing)
comparisons = LittleDict{Symbol, Function}(
function comparison_layer(param=false)
comparisons = LittleDict{Symbol,Function}(
:identity => _co_identity,
:euclidian => (x -> _co_euclidian(x, dom_size)),
:abs_diff_val_vars => (x -> _co_abs_diff_val_vars(x, nvars)),
:val_minus_vars => (x -> _co_val_minus_vars(x, nvars)),
:vars_minus_val => (x -> _co_vars_minus_val(x, nvars)),
:euclidian => _co_euclidian,
:abs_diff_val_vars => _co_abs_diff_val_vars,
:val_minus_vars => _co_val_minus_vars,
:vars_minus_val => _co_vars_minus_val,
)

if !isnothing(param)
comparisons_param = LittleDict{Symbol, Function}(
:abs_diff_val_param => (x -> _co_abs_diff_val_param(x, param)),
:val_minus_param => (x -> _co_val_minus_param(x, param)),
:param_minus_val => (x -> _co_param_minus_val(x, param)),
:euclidian_param => (x -> _co_euclidian_param(x, param, dom_size)),
if param
comparisons_param = LittleDict{Symbol,Function}(
:abs_diff_val_param => _co_abs_diff_val_param,
:val_minus_param => _co_val_minus_param,
:param_minus_val => _co_param_minus_val,
:euclidian_param => _co_euclidian_param,
)
comparisons = LittleDict{Symbol, Function}(union(comparisons, comparisons_param))
comparisons = LittleDict{Symbol,Function}(union(comparisons, comparisons_param))
end

return Layer(comparisons, true)
Expand Down
14 changes: 8 additions & 6 deletions src/genetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ end
_loss(X, X_sols, icn, weigths, metric)
Compute the loss of `icn`.
"""
function _loss(X, X_sols, icn, weigths, metric)
function _loss(X, X_sols, icn, weigths, metric, dom_size, param)
f = compose(icn, weigths)
return sum(x -> abs(f(x) - metric(x, X_sols)), X) + regularization(icn)
return (sum(x -> abs(f(x; param = param, dom_size = dom_size) - metric(x, X_sols)), X) + regularization(icn))
end

"""
_optimize!(icn, X, X_sols; metric = hamming, pop_size = 200)
Optimize and set the weigths of an ICN with a given set of configuration `X` and solutions `X_sols`.
"""
function _optimize!(icn, X, X_sols; metric=hamming, pop_size=200, iter=100)
fitness = weigths -> _loss(X, X_sols, icn, weigths, metric)
function _optimize!(icn, X, X_sols, dom_size, param=nothing; metric=hamming, pop_size=200, iter=100)
fitness = weigths -> _loss(X, X_sols, icn, weigths, metric, dom_size, param)

_icn_ga = GA(
populationSize=pop_size,
Expand All @@ -44,12 +44,14 @@ end
Optimize and set the weigths of an ICN with a given set of configuration `X` and solutions `X_sols`. The best weigths among `global_iter` will be set.
"""

function optimize!(icn, X, X_sols, global_iter, local_iter; metric=hamming, popSize=100)
function optimize!(icn, X, X_sols, global_iter, local_iter, dom_size, param=nothing; metric=hamming, popSize=100)
results = Dictionary{BitVector,Int}()
@info "Starting optimization of weights"
for i in 1:global_iter
@info "Iteration $i"
_optimize!(icn, X, X_sols; iter = local_iter, metric = metric, pop_size = popSize)
_optimize!(icn, X, X_sols, dom_size, param;
iter=local_iter, metric=metric, pop_size=popSize
)
_incsert!(results, _weigths(icn))
end
best = rand(findall(x -> x == maximum(results), results))
Expand Down
18 changes: 9 additions & 9 deletions src/icn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ mutable struct ICN
comparison::Layer
weigths::BitVector

function ICN(; nvars, dom_size,
param=nothing,
function ICN(;
param=false,
tr_layer=transformation_layer(param),
ar_layer=arithmetic_layer(),
ag_layer=aggregation_layer(),
co_layer=comparison_layer(nvars, dom_size, param),
co_layer=comparison_layer(param),
)
w = _generate_weights([tr_layer, ar_layer, ag_layer, co_layer])
new(tr_layer, ar_layer, ag_layer, co_layer, w)
Expand Down Expand Up @@ -91,7 +91,7 @@ _generate_weights(icn::ICN) = _generate_weights(_layers(icn))
Internal function called by `compose` and `show_composition`.
"""
function _compose(icn::ICN)
!_is_viable(icn) && (return (_ -> typemax(Float64)), [])
!_is_viable(icn) && (return ((x; param=nothing, dom_size=0) -> typemax(Float64)), [])

funcs = Vector{Vector{Function}}()
symbols = Vector{Vector{Symbol}}()
Expand Down Expand Up @@ -124,7 +124,7 @@ function _compose(icn::ICN)
end

l = length(funcs[1])
composition = x -> fill(x, l) .|> funcs[1] |> funcs[2][1] |> funcs[3][1] |> funcs[4][1]
composition = (x; param=nothing, dom_size) -> fill(x, l) .|> map(f -> (y -> f(y; param=param)), funcs[1]) |> funcs[2][1] |> funcs[3][1] |> (y -> funcs[4][1](y; param=param, dom_size=dom_size, nvars=length(x)))
return composition, symbols
end

Expand All @@ -133,20 +133,20 @@ end
compose(icn, weights)
Return a function composed by some of the operations of a given ICN. Can be applied to any vector of variables. If `weights` are given, will assign to `icn`.
"""
function compose(icn::ICN; action = :composition)
function compose(icn::ICN; action=:composition)
return action == :symbols ? _compose(icn)[2] : _compose(icn)[1]
end
function compose(icn, weigths; action = :composition)
function compose(icn, weigths; action=:composition)
_weigths!(icn, weigths)
compose(icn; action = action)
compose(icn; action=action)
end

"""
show_composition(icn)
Return the composition (weights) of an ICN.
"""
function show_composition(icn)
symbs = compose(icn, action = :symbols)
symbs = compose(icn, action=:symbols)
aux = map(s -> _reduce_symbols(s, ", ", length(s) > 1), symbs)
return _reduce_symbols(aux, " ∘ ", false)
end
Expand Down
21 changes: 10 additions & 11 deletions src/learn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ end
)
Create an ICN, optimize it, and return its composition.
"""
function learn_compose(X, X_sols; nvars, dom_size, param=nothing,
function learn_compose(X, X_sols, dom_size, param=nothing;
global_iter=10, local_iter=100, metric=hamming, popSize=200,
action=:composition
)
icn = ICN(nvars=nvars, dom_size=dom_size, param=param)
optimize!(icn, X, X_sols, global_iter, local_iter; metric=metric, popSize=200)
icn = ICN(param=!isnothing(param))
optimize!(icn, X, X_sols, global_iter, local_iter, dom_size, param; metric=metric, popSize=200)
@info show_composition(icn)

return compose(icn, action=action)
Expand All @@ -52,13 +52,12 @@ function explore_learn_compose(concept; domains, param=nothing,
search=:complete, global_iter=10, local_iter=100, metric=hamming, popSize=200,
action=:composition,
)
dom_size = maximum(_length, domains)
if search == :complete
X_sols, X = _complete_search_space(domains, concept)
union!(X, X_sols)
return learn_compose(X, X_sols;
nvars=length(domains), dom_size=maximum(_length, domains),
local_iter=local_iter, global_iter=global_iter, param=param,
action=action)
return learn_compose(X, X_sols, dom_size, param;
local_iter=local_iter, global_iter=global_iter, action=action)
end
end

Expand All @@ -67,10 +66,10 @@ function _compose_to_string(symbols, name)
tr_length = length(symbols[1])

CN = "CompositionalNetworks."
tr = _reduce_symbols(symbols[1], ", "; prefix = CN * "_tr_")
ar = _reduce_symbols(symbols[2], ", ", false; prefix = CN * "_ar_")
ag = _reduce_symbols(symbols[3], ", ", false; prefix = CN * "_ag_")
co = _reduce_symbols(symbols[4], ", ", false; prefix = CN * "_co_")
tr = _reduce_symbols(symbols[1], ", "; prefix=CN * "_tr_")
ar = _reduce_symbols(symbols[2], ", ", false; prefix=CN * "_ar_")
ag = _reduce_symbols(symbols[3], ", ", false; prefix=CN * "_ag_")
co = _reduce_symbols(symbols[4], ", ", false; prefix=CN * "_co_")

julia_string = """
$name = x -> fill(x, $tr_length) .|> $tr |> $ar |> $ag |> $co
Expand Down
60 changes: 30 additions & 30 deletions src/transformation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
_tr_identity(x)
Identity function. Already defined in Julia as `identity`, specialized for vectors and scalars.
"""
_tr_identity(x) = identity(x)
_tr_identity(i, x) = identity(i)
_tr_identity(x; param=nothing) = identity(x)
_tr_identity(i, x; param=nothing) = identity(i)

"""
_tr_count_eq(i, x)
_tr_count_eq_right(i, x)
_tr_count_eq_left(i, x)
Count the number of elements equal to `x[i]` (optionally to the right/left of `x[i]`). Extended method to vector `x` are generated.
"""
_tr_count_eq(i, x) = count(y -> x[i] == y, x) - 1
_tr_count_eq_right(i, x) = _tr_count_eq(1, @view x[i:end])
_tr_count_eq_left(i, x) = _tr_count_eq(i, @view x[1:i])
_tr_count_eq(i, x; param=nothing) = count(y -> x[i] == y, x) - 1
_tr_count_eq_right(i, x; param=nothing) = _tr_count_eq(1, @view x[i:end])
_tr_count_eq_left(i, x; param=nothing) = _tr_count_eq(i, @view x[1:i])

# Generating vetorized versions
lazy(_tr_count_eq, _tr_count_eq_left, _tr_count_eq_right)
Expand All @@ -28,12 +28,12 @@ lazy(_tr_count_eq, _tr_count_eq_left, _tr_count_eq_right)
_tr_count_l_right(i, x)
Count the number of elements greater/lesser than `x[i]` (optionally to the left/right of `x[i]`). Extended method to vector with sig `(x)` are generated.
"""
_tr_count_greater(i, x) = count(y -> x[i] < y, x)
_tr_count_lesser(i, x) = count(y -> x[i] > y, x)
_tr_count_g_left(i, x) = _tr_count_greater(i, @view x[1:i])
_tr_count_l_left(i, x) = _tr_count_lesser(i, @view x[1:i])
_tr_count_g_right(i, x) = _tr_count_greater(1, @view x[i:end])
_tr_count_l_right(i, x) = _tr_count_lesser(1, @view x[i:end])
_tr_count_greater(i, x; param=nothing) = count(y -> x[i] < y, x)
_tr_count_lesser(i, x; param=nothing) = count(y -> x[i] > y, x)
_tr_count_g_left(i, x; param=nothing) = _tr_count_greater(i, @view x[1:i])
_tr_count_l_left(i, x; param=nothing) = _tr_count_lesser(i, @view x[1:i])
_tr_count_g_right(i, x; param=nothing) = _tr_count_greater(1, @view x[i:end])
_tr_count_l_right(i, x; param=nothing) = _tr_count_lesser(1, @view x[i:end])

# Generating vetorized versions
lazy(_tr_count_greater, _tr_count_g_left, _tr_count_g_right)
Expand All @@ -45,9 +45,9 @@ lazy(_tr_count_lesser, _tr_count_l_left, _tr_count_l_right)
_tr_count_g_param(i, x, param)
Count the number of elements equal to (resp. lesser/greater than) `x[i] + param`. Extended method to vector with sig `(x, param)` are generated.
"""
_tr_count_eq_param(i, x, param) = count(y -> y == x[i] + param, x)
_tr_count_l_param(i, x, param) = count(y -> y < x[i] + param, x)
_tr_count_g_param(i, x, param) = count(y -> y > x[i] + param, x)
_tr_count_eq_param(i, x; param) = count(y -> y == x[i] + param, x)
_tr_count_l_param(i, x; param) = count(y -> y < x[i] + param, x)
_tr_count_g_param(i, x; param) = count(y -> y > x[i] + param, x)

# Generating vetorized versions
lazy_param(_tr_count_eq_param, _tr_count_l_param, _tr_count_g_param)
Expand All @@ -56,7 +56,7 @@ lazy_param(_tr_count_eq_param, _tr_count_l_param, _tr_count_g_param)
_tr_count_bounding_param(i, x, param)
Count the number of elements bounded (not strictly) by `x[i]` and `x[i] + param`. An extended method to vector with sig `(x, param)` is generated.
"""
_tr_count_bounding_param(i, x, param) = count(y -> x[i] ≤ y ≤ x[i] + param, x)
_tr_count_bounding_param(i, x; param) = count(y -> x[i] ≤ y ≤ x[i] + param, x)

# Generating vetorized versions
lazy_param(_tr_count_bounding_param)
Expand All @@ -66,8 +66,8 @@ lazy_param(_tr_count_bounding_param)
_tr_param_minus_val(i, x, param)
Return the difference `x[i] - param` (resp. `param - x[i]`) if positive, `0.0` otherwise. Extended method to vector with sig `(x, param)` are generated.
"""
_tr_val_minus_param(i, x, param) = max(0, x[i] - param)
_tr_param_minus_val(i, x, param) = max(0, param - x[i])
_tr_val_minus_param(i, x; param) = max(0, x[i] - param)
_tr_param_minus_val(i, x; param) = max(0, param - x[i])

# Generating vetorized versions
lazy_param(_tr_val_minus_param, _tr_param_minus_val)
Expand All @@ -77,9 +77,9 @@ lazy_param(_tr_val_minus_param, _tr_param_minus_val)
_tr_contiguous_vals_minus_rev(i, x)
Return the difference `x[i] - x[i + 1]` (resp. `x[i + 1] - x[i]`) if positive, `0.0` otherwise. Extended method to vector with sig `(x)` are generated.
"""
_tr_contiguous_vals_minus(i, x) = length(x) == i ? 0 : _tr_val_minus_param(i, x, x[i + 1])
function _tr_contiguous_vals_minus_rev(i, x)
return length(x) == i ? 0 : _tr_param_minus_val(i, x, x[i + 1])
_tr_contiguous_vals_minus(i, x; param=nothing) = length(x) == i ? 0 : _tr_val_minus_param(i, x; param=x[i + 1])
function _tr_contiguous_vals_minus_rev(i, x; param=nothing)
return length(x) == i ? 0 : _tr_param_minus_val(i, x; param=x[i + 1])
end
# Generating vetorized versions
lazy(_tr_contiguous_vals_minus, _tr_contiguous_vals_minus_rev)
Expand All @@ -89,8 +89,8 @@ lazy(_tr_contiguous_vals_minus, _tr_contiguous_vals_minus_rev)
transformation_layer(param = nothing)
Generate the layer of transformations functions of the ICN. Iff `param` value is set, also includes all the parametric transformation with that value.
"""
function transformation_layer(param = nothing)
transformations = LittleDict{Symbol, Function}(
function transformation_layer(param=false)
transformations = LittleDict{Symbol,Function}(
:identity => _tr_identity,
:count_eq => _tr_count_eq,
:count_eq_left => _tr_count_eq_left,
Expand All @@ -105,14 +105,14 @@ function transformation_layer(param = nothing)
:contiguous_vals_minus_rev => _tr_contiguous_vals_minus_rev,
)

if !isnothing(param)
transformations_param = LittleDict{Symbol, Function}(
:count_eq_param => ((x...) -> _tr_count_eq_param(x..., param)),
:count_l_param => ((x...) -> _tr_count_l_param(x..., param)),
:count_g_param => ((x...) -> _tr_count_g_param(x..., param)),
:count_bounding_param => ((x...) -> _tr_count_bounding_param(x..., param)),
:val_minus_param => ((x...) -> _tr_val_minus_param(x..., param)),
:param_minus_val => ((x...) -> _tr_param_minus_val(x..., param)),
if param
transformations_param = LittleDict{Symbol,Function}(
:count_eq_param => _tr_count_eq_param,
:count_l_param => _tr_count_l_param,
:count_g_param => _tr_count_g_param,
:count_bounding_param => _tr_count_bounding_param,
:val_minus_param => _tr_val_minus_param,
:param_minus_val => _tr_param_minus_val,
)
transformations = LittleDict(union(transformations, transformations_param))
end
Expand Down
Loading