diff --git a/src/algorithm/NSGAII.jl b/src/algorithm/NSGAII.jl new file mode 100644 index 0000000..8eaa718 --- /dev/null +++ b/src/algorithm/NSGAII.jl @@ -0,0 +1,61 @@ +using Dates + +mutable struct NSGAII <: Algorithm + problem::Problem + populationSize::Int + numberOfEvaluations::Int + + foundSolutions::Vector + + termination::Termination + mutation::MutationOperator + crossover::CrossoverOperator + + solver::EvolutionaryAlgorithm + + dominanceComparator::Function + + function NSGAII() + algorithm = new() + algorithm.solver = EvolutionaryAlgorithm() + algorithm.solver.name = "NSGA-II" + + algorithm.dominanceComparator = compareForDominance + return algorithm + end +end + +function nsgaII(nsgaII::NSGAII) + solver = nsgaII.solver + + solver.problem = nsgaII.problem + solver.populationSize = nsgaII.populationSize + solver.offspringPopulationSize = nsgaII.populationSize + + solver.solutionsCreation = DefaultSolutionsCreation((problem = solver.problem, numberOfSolutionsToCreate = solver.populationSize)) + + solver.evaluation = SequentialEvaluation((problem = solver.problem, )) + + solver.termination = nsgaII.termination + solver.variation = CrossoverAndMutationVariation(solver.offspringPopulationSize, nsgaII.crossover, nsgaII.mutation) + + solver.replacement = RankingAndDensityEstimatorReplacement(nsgaII.dominanceComparator) + + solver.selection = BinaryTournamentSelection(solver.variation.matingPoolSize, compareRankingAndCrowdingDistance) + + return evolutionaryAlgorithm(solver) +end + +function optimize(algorithm::NSGAII) + algorithm.foundSolutions = nsgaII(algorithm) + + return Nothing +end + +function name(nsgaII::NSGAII) + return name(nsgaII.solver) +end + +function getObservable(nsgaII::NSGAII) + return getObservable(nsgaII.solver) +end \ No newline at end of file diff --git a/src/algorithm/algorithm.jl b/src/algorithm/algorithm.jl deleted file mode 100644 index 355e2e4..0000000 --- a/src/algorithm/algorithm.jl +++ /dev/null @@ -1,136 +0,0 @@ -using Dates - -mutable struct EvolutionaryAlgorithm <: Algorithm - name::String - problem::Problem - populationSize::Int - offspringPopulationSize::Int - - foundSolutions::Vector - - solutionsCreation::SolutionsCreation - evaluation::Evaluation - termination::Termination - selection::Selection - variation::Variation - replacement::Replacement - - observable::Observable - - status::Dict - - function EvolutionaryAlgorithm() - x = new() - x.name = "EA" - x.observable = Observable("EA observable") - return return x - end -end - -function getObservable(algorithm::EvolutionaryAlgorithm) - return algorithm.observable -end - -function evolutionaryAlgorithm(ea::EvolutionaryAlgorithm) - startingTime = Dates.now() - - population = ea.solutionsCreation.create(ea.solutionsCreation.parameters) - population = ea.evaluation.evaluate(population, ea.evaluation.parameters) - - evaluations = length(population) - ea.status = Dict("EVALUATIONS" => evaluations, "POPULATION" => population, "COMPUTING_TIME" => (Dates.now() - startingTime)) - - notify(ea.observable, ea.status) - - while !ea.termination.isMet(ea.status, ea.termination.parameters) - matingPool = ea.selection.select(population, ea.selection.parameters) - - offspringPopulation = ea.variation.variate(population, matingPool, ea.variation.parameters) - offspringPopulation = ea.evaluation.evaluate(offspringPopulation, ea.evaluation.parameters) - - population = ea.replacement.replace(population, offspringPopulation, ea.replacement.parameters) - - evaluations += length(offspringPopulation) - ea.status["EVALUATIONS"] = evaluations - ea.status["POPULATION"] = population - ea.status["COMPUTING_TIME"] = Dates.now() - startingTime - - notify(ea.observable, ea.status) - end - - foundSolutions = population - return foundSolutions -end - -function optimize(algorithm::EvolutionaryAlgorithm) - algorithm.foundSolutions = evolutionaryAlgorithm(algorithm) - - return Nothing -end - -function name(algorithm::EvolutionaryAlgorithm) - return algorithm.name -end - - -################################# - -mutable struct NSGAII <: Algorithm - problem::Problem - populationSize::Int - numberOfEvaluations::Int - - foundSolutions::Vector - - termination::Termination - mutation::MutationOperator - crossover::CrossoverOperator - - solver::EvolutionaryAlgorithm - - dominanceComparator::Function - - function NSGAII() - algorithm = new() - algorithm.solver = EvolutionaryAlgorithm() - algorithm.solver.name = "NSGA-II" - - algorithm.dominanceComparator = compareForDominance - return algorithm - end -end - -function nsgaII(nsgaII::NSGAII) - solver = nsgaII.solver - - solver.problem = nsgaII.problem - solver.populationSize = nsgaII.populationSize - solver.offspringPopulationSize = nsgaII.populationSize - - solver.solutionsCreation = DefaultSolutionsCreation((problem = solver.problem, numberOfSolutionsToCreate = solver.populationSize)) - - solver.evaluation = SequentialEvaluation((problem = solver.problem, )) - - solver.termination = nsgaII.termination - solver.variation = CrossoverAndMutationVariation((offspringPopulationSize = solver.offspringPopulationSize, crossover = nsgaII.crossover, mutation = nsgaII.mutation)) - - solver.replacement = RankingAndDensityEstimatorReplacement((dominanceComparator = nsgaII.dominanceComparator, )) - - solver.selection = BinaryTournamentSelection((matingPoolSize = solver.variation.matingPoolSize, comparator = compareRankingAndCrowdingDistance)) - - return evolutionaryAlgorithm(solver) -end - -function optimize(algorithm::NSGAII) - algorithm.foundSolutions = nsgaII(algorithm) - - return Nothing -end - -function name(nsgaII::NSGAII) - return name(nsgaII.solver) -end - -function getObservable(nsgaII::NSGAII) - return getObservable(nsgaII.solver) -end \ No newline at end of file diff --git a/src/algorithm/evolutionaryAlgorithm.jl b/src/algorithm/evolutionaryAlgorithm.jl new file mode 100644 index 0000000..7c4f8cf --- /dev/null +++ b/src/algorithm/evolutionaryAlgorithm.jl @@ -0,0 +1,74 @@ +using Dates + +mutable struct EvolutionaryAlgorithm <: Algorithm + name::String + problem::Problem + populationSize::Int + offspringPopulationSize::Int + + foundSolutions::Vector + + solutionsCreation::SolutionsCreation + evaluation::Evaluation + termination::Termination + selection::Selection + variation::Variation + replacement::Replacement + + observable::Observable + + status::Dict + + function EvolutionaryAlgorithm() + x = new() + x.name = "Evolutionary algorithm" + x.observable = Observable("EvolutionaryAlgorithm observable") + return return x + end +end + +function getObservable(algorithm::EvolutionaryAlgorithm) + return algorithm.observable +end + +function evolutionaryAlgorithm(ea::EvolutionaryAlgorithm) + startingTime = Dates.now() + + population = create(ea.solutionsCreation) + population = evaluate(population, ea.evaluation) + + evaluations = length(population) + ea.status = Dict("EVALUATIONS" => evaluations, "POPULATION" => population, "COMPUTING_TIME" => (Dates.now() - startingTime)) + + notify(ea.observable, ea.status) + + while !isMet(ea.status, ea.termination) + matingPool = select(population, ea.selection) + + offspringPopulation = variate(population, matingPool, ea.variation) + offspringPopulation = evaluate(offspringPopulation, ea.evaluation) + + population = replace_(population, offspringPopulation, ea.replacement) + + evaluations += length(offspringPopulation) + ea.status["EVALUATIONS"] = evaluations + ea.status["POPULATION"] = population + ea.status["COMPUTING_TIME"] = Dates.now() - startingTime + + notify(ea.observable, ea.status) + end + + foundSolutions = population + return foundSolutions +end + +function optimize(algorithm::EvolutionaryAlgorithm) + algorithm.foundSolutions = evolutionaryAlgorithm(algorithm) + + return Nothing +end + +function name(algorithm::EvolutionaryAlgorithm) + return algorithm.name +end + diff --git a/src/algorithm/localSearch.jl b/src/algorithm/localSearch.jl index 21ceb69..eec00e0 100644 --- a/src/algorithm/localSearch.jl +++ b/src/algorithm/localSearch.jl @@ -4,6 +4,10 @@ mutable struct LocalSearch <: Algorithm numberOfIterations::Int mutation::MutationOperator foundSolution::Solution + + function LocalSearch(startingSolution, problem, numberOfIterations, mutation) + return new(startingSolution, problem, numberOfIterations, mutation, copySolution(startingSolution)) + end end function optimize(algorithm::LocalSearch)::Solution @@ -14,7 +18,7 @@ function optimize(algorithm::LocalSearch)::Solution for _ in 1:numberOfIterations mutatedSolution = copySolution(algorithm.startingSolution) - mutatedSolution.variables = mutate(mutatedSolution.variables, mutation) + mutatedSolution = mutate(mutatedSolution, mutation) mutatedSolution = evaluate(mutatedSolution, problem) @@ -23,7 +27,7 @@ function optimize(algorithm::LocalSearch)::Solution end end - algorithm.foundSolution = foundSolution + algorithm.foundSolution = currentSolution return currentSolution end diff --git a/src/metajul.jl b/src/metajul.jl index 2582df6..a766560 100644 --- a/src/metajul.jl +++ b/src/metajul.jl @@ -69,6 +69,9 @@ include("component/evolutionaryAlgorithm/replacement.jl") export normalizeObjectives, distanceBasedSubsetSelection include("util/utils.jl") +export Observable, EvaluationObserver +include("util/observer.jl") + export BinaryProblem, ContinuousProblem, constrainedProblem export addObjective, addVariable, addConstraint, createSolution, evaluate, setName, name export bounds @@ -88,5 +91,8 @@ include("problem/multiObjective/kursawe.jl") include("problem/multiObjective/ZDT.jl") include("problem/multiObjective/oneZeroMax.jl") +export LocalSearch +export optimize +include("algorithm/localSearch.jl") end # module metajul diff --git a/test/algorithm/localSearchTest.jl b/test/algorithm/localSearchTest.jl new file mode 100644 index 0000000..ef3e105 --- /dev/null +++ b/test/algorithm/localSearchTest.jl @@ -0,0 +1,29 @@ +function localSearchIsProperlyInitialized() + problem = schaffer() + startingSolution = createSolution(problem) + numberOfIterations = 10 + mutation = PolynomialMutation(1.0 / numberOfVariables(problem), 20.0, problem.bounds) + + algorithm = LocalSearch(startingSolution, problem, numberOfIterations, mutation) + + return problem == algorithm.problem && numberOfIterations == algorithm.numberOfIterations && mutation == algorithm.mutation && startingSolution == algorithm.startingSolution +end + +function localSearchWithZeroIterationsReturnsTheStartingSolution() + problem = schaffer() + startingSolution = createSolution(problem) + numberOfIterations = 0 + mutation = UniformMutation(0.01, 20.0, problem.bounds) + + algorithm = LocalSearch(startingSolution, problem, numberOfIterations, mutation) + optimize(algorithm) + + return startingSolution == algorithm.foundSolution +end + + +@testset "Constraint handling functions tests" begin + @test localSearchIsProperlyInitialized() + @test localSearchWithZeroIterationsReturnsTheStartingSolution() +end + diff --git a/test/runtests.jl b/test/runtests.jl index d15d2b1..3bde7dd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -78,3 +78,11 @@ problemTests = [ for testProgram in problemTests include(testProgram) end + +algorithmTests = [ + "algorithm/localSearchTest.jl", +] + +for testProgram in algorithmTests + include(testProgram) +end