Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Major change for creating individuals and population #43

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
592858a
Started improving code writing.
tpdsantos Feb 19, 2020
48ba05a
Continued improving code
tpdsantos Feb 20, 2020
192c283
Continued improving code
tpdsantos Feb 21, 2020
50484fd
continued improving code
tpdsantos Feb 22, 2020
1e5a3b2
Continued improving code
tpdsantos Feb 23, 2020
cee890d
Continued improving code
tpdsantos Feb 24, 2020
8991a18
Continued improving code
tpdsantos Feb 25, 2020
b9d23cb
Continued improving code
tpdsantos Feb 26, 2020
743ac27
Continued improving code
tpdsantos Feb 27, 2020
44dbce5
Continued improving code
tpdsantos Feb 27, 2020
7beca54
wrote documentation for every major function created. Also updated RE…
tpdsantos Feb 29, 2020
ea16587
Continued improving code
tpdsantos Mar 4, 2020
aa51096
Fixed bug regarding type inference in the crossover function created …
tpdsantos Mar 4, 2020
eb55c7d
Created function to present results
tpdsantos Mar 5, 2020
0e01bcd
Continued improving code
tpdsantos Mar 8, 2020
67ae404
minor aesthetic changes
tpdsantos Mar 8, 2020
dcc379f
Merge pull request #1 from tpdsantos/general
tpdsantos Mar 8, 2020
0a6bb64
added inbounds in most of the low-level functions
tpdsantos Mar 8, 2020
61cc3a3
minor aesthetic changes
tpdsantos Mar 8, 2020
678b498
started creating ways to communicate with external programs
tpdsantos Mar 9, 2020
d20633d
added first prototype for communication with external programs
tpdsantos Mar 10, 2020
6414627
introduced functionality for external programs in the ga function
tpdsantos Mar 10, 2020
d96186e
Fixed piping communication
tpdsantos Mar 13, 2020
c840ff3
Increased piping performance
tpdsantos Mar 15, 2020
268072e
Started mesing around with clusters
tpdsantos Mar 18, 2020
e177889
Finished running external programs in a cluster
tpdsantos Mar 23, 2020
9eefe91
Merge pull request #2 from tpdsantos/general
tpdsantos Mar 23, 2020
97d539d
minor revisions
tpdsantos Mar 25, 2020
545b121
introduced file with backup strategies
tpdsantos Mar 27, 2020
7cdac16
minor revisions
tpdsantos Mar 27, 2020
907936f
Fixed bugs
tpdsantos Mar 27, 2020
0f7ac0a
minor revisions
tpdsantos Apr 1, 2020
16bb48a
added a function to help set up local computer or clusters for parall…
tpdsantos Apr 1, 2020
e88dd28
improved documentation
tpdsantos Apr 1, 2020
a7be461
Reduced the use of the objective function
tpdsantos Apr 6, 2020
62ba6a5
updates
tpdsantos Jun 21, 2020
0e44d01
minor changes in function documentations
tpdsantos Jan 13, 2021
30c6491
minor changes to function documentations
tpdsantos Jan 13, 2021
d400bed
Added initialization function
tpdsantos Jan 19, 2021
4317816
had forgotten to export ext_init function
tpdsantos Jan 19, 2021
9405af5
minor modifications on memory allocations
tpdsantos Feb 5, 2021
eca2086
added test for parallel code
tpdsantos Feb 5, 2021
46168a8
minor changes
tpdsantos Feb 5, 2021
6f5e11d
Fixed memory allocation bug
tpdsantos Feb 5, 2021
9b707cb
Created structure for GA output
tpdsantos Feb 12, 2021
56604a1
Merge pull request #3 from tpdsantos/backup
tpdsantos Feb 19, 2021
10c7bc4
Started implementing boundary functionalities
tpdsantos Feb 19, 2021
d9aa448
simplified boundary evaluation
tpdsantos Feb 20, 2021
e1cc8b1
tests on how to maximize warmup efficiency
tpdsantos Feb 22, 2021
98e5009
Added backup support for boundary values
tpdsantos Mar 1, 2021
24eb81e
fixed bug in mutate function
tpdsantos Mar 3, 2021
2faa82a
Improved boundary checks
tpdsantos Mar 9, 2021
13eeb3d
Merge pull request #4 from tpdsantos/bounds
tpdsantos Mar 17, 2021
bd44dd9
minor changes
tpdsantos Mar 24, 2021
1ba9433
Create CITATION.cff
tpdsantos Feb 18, 2023
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
8 changes: 8 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cff-version: 0.0.1
authors:
- family-names: Santos
given-names: Tiago
orcid: https://orcid.org/0000-0003-2463-2881
title: "Evolutionary.jl"
version: 0.0.2
date-released: 2020-05-22
4 changes: 4 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ uuid = "86b6b26d-c046-49b6-aa0b-5f0f74682bd6"
version = "0.2.0"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
DistributedArrays = "aaf54ef3-cdf8-58ed-94cc-d582ad619b94"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

Expand Down
143 changes: 141 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,152 @@ pkg> add https://github.com/wildart/Evolutionary.jl.git#v0.2.0

## Functionalities

#### Algorithms

### Creating Chromossomes

There are three types of genes that can be used for optimization, the `BinaryGene`, the `IntegerGene` and the `FloatGene`.


#### `BinaryGene`

A `BinaryGene` contains simply a boolean value. It can be created in two ways:

```julia
# option 1
gene = BinaryGene(true)
# option 2
gene = BinaryGene()
```

The first way sets the initial value to `true`, while the second case sets the initial value to a random boolean value.


#### `IntegerGene`

A `IntegerGene` is a container for a `BitVector` that is used to determine the integer number using base-2 binary arithmetic. To create a `IntegerGene`:

```julia
# option 1
gene = IntegerGene(BitVector(undef, 3), :FM)
# option 2
gene = IntegerGene(BitVector(undef, 3))
# option 3
gene = IntegerGene(3)

int_number = bin(gene)
```

The first one sets a `BitVector` with three elements and sets the Flip Mutation as the mutation algorithm for this gene. The second one sets the Flip Mutation as the default mutation algorithm. The last creates a random `BitVector` with length 3 and the Flip Mutation as the default mutation algorithm. To know all the mutation algorithms implemented and their corresponding symbols, as well as more information about these functions, just type `?IntegerGene` in the command prompt. The function `bin` is a function created to convert the `BitVector` into an integer number using base-2 binary arithmetic.


#### `FloatGene`

A `FloatGene` is a gene that is comprised by real numbers. Can have one or more values, so you can combine all real valued variables in a single `FloatGene`. There are several ways to create a `FloatGene`, so let's name a few:

```julia
# option 1
gene = FloatGene(values, ranges; m ::Int = 20)
# option 2
gene = FloatGene(values, range; m ::Int = 20)
# option 3
gene = FloatGene(value, range; m ::Int = 20)
# option 4
gene = FloatGene(values; m ::Int = 20)
# option 5
gene = FloatGene(value; m ::Int = 20)
# option 6
gene = FloatGene(n)
```

Plural `values` and `ranges` mean vector, while singular `value` and `range` mean scalar. In options 4 and 5, both `range` and `ranges` are created randomly, according to the size of `value` or `values`. Option 6 creates random variables and random ranges of size `n`.


### Running the Genetic Algorithm

Now that we know how to create genes, we need to create a population and an objective function to run our genetic algorithm.

#### Example 1

In this example we want to find the index of a vector associated to the midpoint of said vector. Given:

```julia
x = 0.0:0.01:10
```

We want to find the index that corresponds to the value `5.0`. First let's create our chromossome, which in this case will comprise of one `IntegerGene`:

```julia
gene = IntegerGene(4)
chromossome = [gene]
```

**NOTE:** when dealing with integer numbers, make sure the length of your vector is big enough to embrace the possible value. In this case, for a vector of length 4, the maximum integer value is 16, so our expected result can be represented by this vector.

Our objective function could be something like:

```julia
function objfun(chrom ::Vector{<:AbstractGene})
ind = bin(chrom[1])
return abs( x[ind] - (x[end]-x[1]) / 2 )
end
```

Now we have to choose the crossover and selection algorithms:

```julia
Crossover(:SPX) # single point crossover
Selection(:RWS) # roulette wheel selection
```

And now we can run our genetic algorithm:

```julia
N = 100 # population size
ga(objfun, chromossome, N)
```

If you couldn't get the right result, you can increase the population size or increase the number of iterations. The optional arguments are well explained if you go to the command prompt and type `?ga`.


#### Example 2

Using the same vector `x`, now we want to determine the midpoint of said vector, which will be a real number. In that case:

```julia
gene = FloatGene(1.0) # random range value
chromossome = [gene]
```

Now our objective function will be slightly different:

```julia
function objfun(chrom ::Vector{<:AbstractGene})
return abs(chrom.value[1] - (x[end] - x[1]) / 2)
end
```

After choosing crossover and selection algorithms:

```julia
Crossover(:SPX) # single point crossover
Selection(:RWS) # roulette wheel selection
```

We run the genetic algorithm in the same way:

```julia
N = 100
ga(objfun, chromossome, N)
```


### Algorithms

- (μ/ρ(+/,)λ)-SA-ES
- (μ/μ_I,λ)-CMA-ES
- Genetic Algorithms (GA)

#### Operators
### Operators

- Mutations
- (an)isotropic mutation (for ES)
Expand Down
146 changes: 80 additions & 66 deletions src/Evolutionary.jl
Original file line number Diff line number Diff line change
@@ -1,83 +1,97 @@

module Evolutionary
using Random
export Strategy, strategy, inverse, mutationwrapper,
# ES mutations
isotropic, anisotropic, isotropicSigma, anisotropicSigma,
# GA mutations
flip, domainrange, inversion, insertion, swap2, scramble, shifting,
# ES recombinations
average, marriage, averageSigma1, averageSigmaN,
# GA recombinations
singlepoint, twopoint, uniform,
discrete, waverage, intermediate, line,
pmx, ox1, cx, ox2, pos,
# GA selections
ranklinear, uniformranking, roulette, sus, tournament, truncation,
# Optimization methods
es, cmaes, ga

const Strategy = Dict{Symbol,Any}
const Individual = Union{Vector, Matrix, Function, Nothing}

# Wrapping function for strategy
function strategy(; kwargs...)
result = Dict{Symbol,Any}()
for (k, v) in kwargs
result[k] = v
end
return result

using Random, Base.Threads
using Distributed
using DistributedArrays, DistributedArrays.SPMD
using Printf
using Dates

export
# Optimization methods
es, cmaes, ga,
# Constants
GAVector, Individual, AbstractGene

####################################################################

"""
Abstract Type that represents all types of genes supported.
"""
abstract type AbstractGene end

const Strategy = Dict{Symbol,Any}

const Individual = Vector{AbstractGene}

const GAVector = Union{T, BitVector} where T <: Vector

####################################################################

# Wrapping function for strategy
function strategy(; kwargs...)
result = Dict{Symbol,Any}()
for (k, v) in kwargs
result[k] = v
end
return result
end

# Inverse function for reversing optimization direction
function inverseFunc(f::Function)
function fitnessFunc(x::T) where {T <: Vector}
return 1.0/(f(x)+eps())
end
return fitnessFunc
# Inverse function for reversing optimization direction
function inverseFunc(f::Function)
function fitnessFunc(x::T) where {T <: Vector}
return 1.0/(f(x)+eps())
end
return fitnessFunc
end

# Obtain individual
function getIndividual(init::Individual, N::Int)
if isa(init, Vector)
@assert length(init) == N "Dimensionality of initial population must be $(N)"
individual = init
elseif isa(init, Matrix)
@assert size(init, 1) == N "Dimensionality of initial population must be $(N)"
populationSize = size(init, 2)
individual = init[:, 1]
elseif isa(init, Function) # Creation function
individual = init(N)
else
individual = ones(N)
end
return individual
# Obtain individual
function getIndividual(init::Individual, N::Int)
if isa(init, Vector)
@assert length(init) == N "Dimensionality of initial population must be $(N)"
individual = init
elseif isa(init, Matrix)
@assert size(init, 1) == N "Dimensionality of initial population must be $(N)"
populationSize = size(init, 2)
individual = init[:, 1]
elseif isa(init, Function) # Creation function
individual = init(N)
else
individual = ones(N)
end
return individual
end

# Collecting interim values
function keep(interim, v, vv, col)
if interim
if !haskey(col, v)
col[v] = typeof(vv)[]
end
push!(col[v], vv)
# Collecting interim values
function keep(interim, v, vv, col)
if interim
if !haskey(col, v)
col[v] = typeof(vv)[]
end
push!(col[v], vv)
end
end

# General Structures
include("structs.jl")

# ES & GA recombination functions
include("recombinations.jl")

# ES & GA recombination functions
include("recombinations.jl")
# ES & GA mutation functions
include("mutations.jl")

# ES & GA mutation functions
include("mutations.jl")
# GA selection functions
include("selections.jl")

# GA selection functions
include("selections.jl")
# Evolution Strategy
include("es.jl")
include("cmaes.jl")

# Evolution Strategy
include("es.jl")
include("cmaes.jl")
# Backup functions
include("backup.jl")

# Genetic Algorithms
include("ga.jl")
# Genetic Algorithms
include("ga.jl")

end
Loading