Skip to content

Commit de5391c

Browse files
authored
Enhance the accuracy of the GA (#14)
* Enhance the accuracy of the GA * Tests, doc * Tests errors * Compat and tag new version v0.0.3 * Coverage
1 parent 9365b05 commit de5391c

File tree

9 files changed

+112
-57
lines changed

9 files changed

+112
-57
lines changed

Manifest.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
8686
deps = ["Mmap"]
8787
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"
8888

89+
[[Dictionaries]]
90+
deps = ["Indexing", "Random"]
91+
git-tree-sha1 = "73ddbf30bc6488a72c4a7a05b54f21b59c6c74fb"
92+
uuid = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
93+
version = "0.3.6"
94+
8995
[[DiffResults]]
9096
deps = ["StaticArrays"]
9197
git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805"
@@ -130,6 +136,12 @@ version = "0.10.14"
130136
deps = ["Random"]
131137
uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"
132138

139+
[[Indexing]]
140+
deps = ["Test"]
141+
git-tree-sha1 = "0cf3ac621cd74b1d03af0cc4275f680b2070a5cc"
142+
uuid = "313cdc1a-70c2-5d6a-ae34-0150d3930a38"
143+
version = "1.1.0"
144+
133145
[[InteractiveUtils]]
134146
deps = ["Markdown"]
135147
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
name = "CompositionalNetworks"
22
uuid = "4b67e4b5-442d-4ef5-b760-3f5df3a57537"
33
authors = ["Jean-François Baffier"]
4-
version = "0.0.2"
4+
version = "0.0.3"
55

66
[deps]
77
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
88
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
9+
Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
910
Evolutionary = "86b6b26d-c046-49b6-aa0b-5f0f74682bd6"
1011
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
1112
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1213

1314
[compat]
1415
CSV = "0.8"
1516
DataFrames = "0.22"
17+
Dictionaries = "0.3"
1618
Evolutionary = "0.7"
1719
OrderedCollections = "1.3"
1820
julia = "1.5"

src/CompositionalNetworks.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module CompositionalNetworks
22

33
# Imports
4-
import Evolutionary: GA, tournament, singlepoint, flip, optimize, minimizer, rouletteinv, minimizer
4+
import Evolutionary: GA, tournament, singlepoint, flip, optimize, minimizer, Options, summary, trace, rouletteinv
55
import Random: bitrand, falses
66
import OrderedCollections: LittleDict
77
import DataFrames: DataFrame, Not
88
import CSV: CSV
9+
import Dictionaries: Dictionary, set!
910

1011
# Exports utilities
1112
export lazy, lazy_param, csv2space

src/genetic.jl

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Generate a pôpulation of weigths (individuals) for the genetic algorithm weigth
44
"""
55
function _generate_population(icn, pop_size)
66
population = Vector{BitVector}()
7-
foreach(_ -> push!(population, _generate_weights(icn)), 1:pop_size)
7+
foreach(_ -> push!(population, falses(_nbits(icn))), 1:pop_size)
88
return population
99
end
1010

@@ -18,44 +18,42 @@ function _loss(X, X_sols, icn, weigths, metric)
1818
end
1919

2020
"""
21-
_single_point(v1::T, v2::T, icn) where {T <: AbstractVector}
22-
_flip(recombinant::T, icn) where {T <: BitVector}
23-
Meta functions that add individuals a viability check in `Evolutionary.singlepoint` and `Evolutionary.flip`.
24-
"""
25-
function _single_point(v1::T, v2::T, icn) where {T <: AbstractVector}
26-
while true
27-
c1, c2 = singlepoint(v1, v2)
28-
_is_viable(icn, c1) && _is_viable(icn, c2) && (return c1, c2)
29-
end
30-
end
31-
function _flip(recombinant::T, icn) where {T <: BitVector}
32-
c = deepcopy(recombinant)
33-
while true
34-
flip(c)
35-
_is_viable(icn, c) && (recombinant = c: break)
36-
end
37-
end
38-
39-
"""
40-
_optimize!(icn, X, X_sols; ga = GA(), metric = hamming, pop_size = 200)
21+
_optimize!(icn, X, X_sols; metric = hamming, pop_size = 200)
4122
Optimize and set the weigths of an ICN with a given set of configuration `X` and solutions `X_sols`.
4223
"""
43-
function _optimize!(icn, X, X_sols; ga = GA(), metric = hamming, pop_size = 200)
24+
function _optimize!(icn, X, X_sols; metric=hamming, pop_size=200, iter=100)
4425
fitness = weigths -> _loss(X, X_sols, icn, weigths, metric)
4526

46-
_viable_single_point = (v1, v2) -> _single_point(v1, v2, icn)
47-
_viable_flip = v -> _flip(v, icn)
4827
_icn_ga = GA(
49-
populationSize = pop_size,
50-
crossoverRate = 0.4,
51-
epsilon = 0.03,
52-
selection = rouletteinv,
53-
crossover = _viable_single_point,
54-
mutation = _viable_flip,
55-
mutationRate = 0.8
28+
populationSize=pop_size,
29+
crossoverRate=0.8,
30+
epsilon=0.05,
31+
selection=tournament(2),
32+
crossover=singlepoint,
33+
mutation=flip,
34+
mutationRate=1.0
5635
)
5736

5837
pop = _generate_population(icn, pop_size)
59-
res = optimize(fitness, pop, _icn_ga)
38+
res = optimize(fitness, pop, _icn_ga, Options(iterations=iter))
6039
_weigths!(icn, minimizer(res))
6140
end
41+
42+
"""
43+
optimize!(icn, X, X_sols, global_iter, local_iter; metric=hamming, popSize=100)
44+
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.
45+
"""
46+
47+
function optimize!(icn, X, X_sols, global_iter, local_iter; metric=hamming, popSize=100)
48+
results = Dictionary{BitVector,Int}()
49+
@info "Starting optimization of weights"
50+
for i in 1:global_iter
51+
@info "Iteration $i"
52+
_optimize!(icn, X, X_sols; iter = local_iter, metric = metric, pop_size = popSize)
53+
_incsert!(results, _weigths(icn))
54+
end
55+
best = rand(findall(x -> x == maximum(results), results))
56+
_weigths!(icn, best)
57+
@info show_composition(icn) best results
58+
return best, results
59+
end

src/icn.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,18 @@ end
154154
Return the regularization value of an ICN weights, which is proportional to the normalized number of operations selected in the icn layers.
155155
"""
156156
function regularization(icn)
157+
Σmax = 0
157158
Σop = 0
158159
_start = 0
159160
_end = 0
160161
for layer in _layers(icn)
161162
l = _length(layer)
162163
_start = _end + 1
163164
_end += _exclu(layer) ? _nbits_exclu(layer) : l
164-
Σop += _selected_size(layer, @view _weigths(icn)[_start:_end])
165+
if !_exclu(layer)
166+
Σop += _selected_size(layer, @view _weigths(icn)[_start:_end])
167+
Σmax += _length(layer)
168+
end
165169
end
166-
return Σop / (_length(icn) + 1)
170+
return Σop / (Σmax + 1)
167171
end

src/layer.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ function _generate_inclusive_operations(predicate, bits)
6666
end
6767
return ind
6868
end
69+
# function _generate_inclusive_operations(predicate, bits)
70+
# ind = falses(bits)
71+
# s = Set(1:bits)
72+
# r = rand(1:bits)
73+
# for i in 1:r
74+
# ind[pop!(s,rand(s))] = true
75+
# end
76+
# return ind
77+
# end
6978
function _generate_exclusive_operation(max_op_number)
7079
op = rand(1:max_op_number)
7180
return _as_bitvector(op, max_op_number)

src/utils.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,7 @@ function _reduce_symbols(symbols, sep, parenthesis = true)
6868
str = reduce((x,y) -> "$y$sep$x", symbols)
6969
return parenthesis ? "[$str]" : str
7070
end
71+
72+
function _incsert!(d::Dictionary, ind)
73+
set!(d, ind, isassigned(d, ind) ? d[ind] + 1 : 1)
74+
end

test/icn.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# # Test with manually weighted ICN
22

3-
icn = ICN(nvars = 4, dom_size = 4, param = 2)
3+
icn = ICN(nvars=4, dom_size=4, param=2)
44
show_layers(icn)
55
icn.weigths = vcat(trues(18), falses(6))
66

@@ -14,13 +14,16 @@ v = [1,2,4,3]
1414

1515
## Test GA
1616

17-
X_sol = csv2space("../data/csv/complete_ad-4-4.csv"; filter = :solutions)
17+
X_sol = csv2space("../data/csv/complete_ad-4-4.csv"; filter=:solutions)
1818
@test hamming([1,2,3,3], X_sol) == 1
1919

2020
X = csv2space("../data/csv/complete_ad-4-4.csv")
21-
icn = ICN(nvars = 4, dom_size = 4, param = 0)
21+
icn = ICN(nvars=4, dom_size=4)
2222

2323
CN._optimize!(icn, X, X_sol)
2424
@test CN._is_viable(icn)
2525
err = compose(icn)
2626
@test err([1,2,3,3]) > 0.0
27+
@info show_composition(icn)
28+
29+
CN.optimize!(icn, X, X_sol, 10, 100)

test/layers.jl

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ funcs = Dict(
5656
],
5757
)
5858

59-
for (f, results) in funcs, (key, vals) in enumerate(data)
60-
@test f(vals.first) == results[key]
61-
foreach(i -> f(i, vals.first), vals.first)
59+
for (f, results) in funcs
6260
@info f
61+
for (key, vals) in enumerate(data)
62+
@test f(vals.first) == results[key]
63+
foreach(i -> f(i, vals.first), vals.first)
64+
end
6365
end
6466

6567
# Test transformations with parameter
@@ -90,20 +92,26 @@ funcs_param = Dict(
9092
],
9193
)
9294

93-
for (f, results) in funcs_param, (key, vals) in enumerate(data)
94-
@test f(vals.first, vals.second) == results[key]
95-
foreach(i -> f(i, vals.first, vals.second), vals.first)
95+
for (f, results) in funcs_param
9696
@info f
97+
for (key, vals) in enumerate(data)
98+
@test f(vals.first, vals.second) == results[key]
99+
foreach(i -> f(i, vals.first, vals.second), vals.first)
100+
end
97101
end
98102

99103
# arithmetic layer
104+
@info CN._ar_sum
100105
@test CN._ar_sum(map(p -> p.first, data)) == [2, 7, 5, 6, 4]
106+
@info CN._ar_prod
101107
@test CN._ar_prod(map(p -> p.first, data)) == [1, 10, 6, 8, 3]
102108

103109
# aggregation layer
110+
@info CN._ag_sum
104111
@test CN._ag_sum(data[1].first) == 15
105112
@test CN._ag_sum(data[2].first) == 9
106113

114+
@info CN._ag_count_positive
107115
@test CN._ag_count_positive(data[1].first) == 5
108116
@test CN._ag_count_positive(data[2].first) == 5
109117
@test CN._ag_count_positive([1, 0, 1, 0, 1]) == 3
@@ -116,8 +124,11 @@ funcs = [
116124
]
117125

118126
# test no param/vars
119-
for (f, results) in funcs, (key, vals) in enumerate(data)
120-
@test f(vals.first) == results[key]
127+
for (f, results) in funcs
128+
@info f
129+
for (key, vals) in enumerate(data)
130+
@test f(vals.first) == results[key]
131+
end
121132
end
122133

123134
funcs_param = [
@@ -126,8 +137,11 @@ funcs_param = [
126137
CN._co_param_minus_val => [0, 5],
127138
]
128139

129-
for (f, results) in funcs_param, (key, vals) in enumerate(data)
130-
@test f(vals.first, vals.second[1]) == results[key]
140+
for (f, results) in funcs_param
141+
@info f
142+
for (key, vals) in enumerate(data)
143+
@test f(vals.first, vals.second[1]) == results[key]
144+
end
131145
end
132146

133147
funcs_vars = [
@@ -136,23 +150,31 @@ funcs_vars = [
136150
CN._co_vars_minus_val => [2, 0],
137151
]
138152

139-
for (f, results) in funcs_vars, (key, vals) in enumerate(data)
140-
@test f(vals.first, vals.second[2]) == results[key]
153+
for (f, results) in funcs_vars
154+
@info f
155+
for (key, vals) in enumerate(data)
156+
@test f(vals.first, vals.second[2]) == results[key]
157+
end
141158
end
142159

143-
144160
funcs_param_dom = [
145161
CN._co_euclidian_param => [3.5, 2.0],
146162
]
147163

148-
for (f, results) in funcs_param_dom, (key, vals) in enumerate(data)
149-
@test f(vals.first, vals.second[1], vals.second[2]) results[key]
164+
for (f, results) in funcs_param_dom
165+
@info f
166+
for (key, vals) in enumerate(data)
167+
@test f(vals.first, vals.second[1], vals.second[2]) results[key]
168+
end
150169
end
151170

152171
funcs_dom = [
153-
CN._co_euclidian => [8/3, 2.0],
172+
CN._co_euclidian => [8 / 3, 2.0],
154173
]
155174

156-
for (f, results) in funcs_dom, (key, vals) in enumerate(data)
157-
@test f(vals.first, vals.second[2]) results[key]
175+
for (f, results) in funcs_dom
176+
@info f
177+
for (key, vals) in enumerate(data)
178+
@test f(vals.first, vals.second[2]) results[key]
179+
end
158180
end

0 commit comments

Comments
 (0)