From 9cadc6852952738c76482a47fb0436dbbe0995f7 Mon Sep 17 00:00:00 2001 From: Antonio Date: Fri, 4 Feb 2022 11:01:25 +0100 Subject: [PATCH] jMetalPy v1.5.7 (#91) * Add solution generator and evaluator for SA (#67) * Add warm startup for SA using population_generator. * Revert evaluator parametrization in SA. * Working on implementing a IntegerFloatSolution class * Update nsgaiii.py (#70) removed obsolete import * Fix conflict in file smpsorp_zdt4.py * Add new implementation of quality indicators. All of them receive a numpy array as a parameter instead of a list of solutions. * Refactor quality indicators. All of them receive as a parameter a numpy array instead of a list of solutions * Add file ZDT1.pf in the test folder (to be use to test quality indicators) * Feature/mixed solution (#73) * Working on implementing a IntegerFloatSolution class * Add unit test cases for class IntegerFloatProblem * Add class NMMin * Add class IntegerFloatSBXCrossover * Add test cases for SBXCrossover * Still working on implementing an approach for the IntegerFloatSolution class * Add user defined exceptiones in file checking.py * Working on the implementation of class CompositeSolution * Workon on class CompositeSolution * Class CompositeMutation implemented and tested * Fix a bug in class Neighborhood * Class CompositeCrossover implemented and tested * Add class * Add class * Rename file * Add problem ZDT1Modified * Add examples with NSGA-II * Add NSGA-II examples * Optimize imports * Minor changes * Changes on attribute name Co-authored-by: Yebisu * Minor changes * Release v1.5.4 * Updating the MOEAD and variants examples * Minor changes * Add problem UF1 * Fix bug in ibea. * Refactor crossover and mutation operators * Refactor crossover and mutation operators * New minor version 1.5.5 * Adapt CXCrossover and ScrambleMutation to TSP (#80) * Added new minor version * Removed SyntaxWarning for with literals * Changed typing of frequency to int * Minor changes * Use of linters for catching errors and formatters to fix style * fix IntegerProblem cannot get upper bound value bug (#86) * optimise deepcopy for list (#87) * Added logging * Update __init__.py (#92) Export `RouletteWheelSelection` Co-authored-by: Antonio * Minor changes * Python version 3.7 * Minor changes * Optimize imports * Minor changes * removing depricated functions (#118) * Fix #115 * fixing kursawe's function kursawe's f2 function must go through all variables * evaluate function for zdt6 class zdt6's f1 function is different from the others zdt functions * Fix style * Replace Travis with Github Actions * setup.py deprecated in favor of setup.cfg * Add develop branch for triggering options * Replace build badge Co-authored-by: Yevhenii Semendiak <32543098+YevheniiSemendiak@users.noreply.github.com> Co-authored-by: ajnebro Co-authored-by: Marvin Steijaert Co-authored-by: benhid Co-authored-by: Sizhe Yuen Co-authored-by: Antonio J. Nebro Co-authored-by: Yevhenii Semendiak Co-authored-by: Lingpho Co-authored-by: Wojciech Lewicki Co-authored-by: root Co-authored-by: Arysson Oliveira <51703579+ASdOliveira@users.noreply.github.com> Co-authored-by: Isabela <63879870+isabelagabriely@users.noreply.github.com> --- .github/workflows/ci.yml | 36 ++ .github/workflows/release.yml | 31 ++ .gitignore | 5 +- .travis.yml | 6 - Makefile | 36 +- README.md | 17 +- docs/source/conf.py | 1 + examples/experiment/comparison.py | 32 +- examples/experiment/statistical_analysis.py | 87 ++-- examples/multiobjective/gde3/dynamic_gde3.py | 10 +- .../gde3/gde3_spark_evaluator.py | 14 +- examples/multiobjective/gde3/gde3_zdt1.py | 28 +- examples/multiobjective/gde3/ggde3_zdt2.py | 22 +- examples/multiobjective/hype/hype_zdt1.py | 32 +- examples/multiobjective/ibea/ibea_zdt1.py | 26 +- examples/multiobjective/mocell/mocell_zdt1.py | 28 +- examples/multiobjective/moead/moead_dtlz2.py | 28 +- .../moead/moead_iepsilon_lircmop1.py | 26 +- examples/multiobjective/moead/moead_lz09.py | 26 +- .../multiobjective/moead/moeaddra_lz09.py | 31 +- .../nsgaii/distributed_nsgaii_with_dask.py | 13 +- .../distributed_nsgaii_with_dask_evaluator.py | 17 +- ...distributed_nsgaii_with_spark_evaluator.py | 16 +- .../nsgaii/dynamic_nsgaii_solving_fda2.py | 8 +- ...sgaii_solving_zdt2_with_reference_point.py | 43 +- ...ii_defining_schaffer_problem_on_the_fly.py | 33 +- ...ii_defining_srinivas_problem_on_the_fly.py | 47 +-- .../nsgaii/nsgaii_solving_3D_problem.py | 24 +- .../nsgaii/nsgaii_solving_binary_problem.py | 14 +- ...ii_solving_constrained_srinivas_problem.py | 24 +- .../nsgaii_solving_mixed_encoding_problem.py | 31 +- examples/multiobjective/nsgaii/nsgaii_ssp.py | 159 ++++++-- .../nsgaii/nsgaii_standard_settings.py | 28 +- ...andard_settings_with_real_time_plotting.py | 39 +- .../nsgaii/nsgaii_steady_state.py | 27 +- ...ii_steady_state_with_real_time_plotting.py | 44 ++- ...llel_nsgaii_with_multiprocess_evaluator.py | 17 +- .../multiobjective/nsgaiii/nsgaiii_dtlz2.py | 32 +- .../omopso/omopso_spark_evaluator.py | 25 +- examples/multiobjective/omopso/omopso_zdt1.py | 28 +- .../multiobjective/preferences/ggde3_zdt2.py | 39 +- .../random_search/random_search_zdt1.py | 23 +- .../multiobjective/smpso/dynamic_smpso.py | 16 +- .../smpso/smpso_schaffer_on_the_fly.py | 20 +- .../smpso/smpso_spark_evaluator.py | 22 +- .../multiobjective/smpso/smpso_srinivas.py | 23 +- .../smpso/smpso_srinivas_on_the_fly.py | 34 +- examples/multiobjective/smpso/smpso_zdt4.py | 23 +- examples/multiobjective/smpso/smpsorp_zdt4.py | 52 +-- examples/multiobjective/spea2/gspea2_zdt1.py | 24 +- examples/multiobjective/spea2/spea2_dtlz1.py | 24 +- examples/multiobjective/spea2/spea2_zdt1.py | 24 +- .../evolution_strategy_binary.py | 14 +- .../evolution_strategy_float.py | 14 +- .../evolution_strategy_permutation.py | 27 ++ .../gde3/gde3_single_objective.py | 18 +- .../generational_genetic_algorithm_binary.py | 25 +- .../generational_genetic_algorithm_float.py | 18 +- .../generational_genetic_algorithm_tsp.py | 22 +- .../steady_state_genetic_algorithm.py | 161 ++++++-- ...genetic_algorithm_with_knapsack_problem.py | 18 +- .../local_search/local_search_binary.py | 23 +- .../local_search/local_search_float.py | 24 +- .../nsgaii/nsgaii_single_objective_binary.py | 14 +- .../nsgaii/nsgaii_single_objective_float.py | 16 +- .../simulated_annealing_binary.py | 22 +- .../simulated_annealing_float.py | 20 +- .../simulated_annealing_permutation.py | 24 ++ jmetal/__init__.py | 28 +- jmetal/algorithm/multiobjective/gde3.py | 80 ++-- jmetal/algorithm/multiobjective/hype.py | 56 +-- jmetal/algorithm/multiobjective/ibea.py | 57 +-- jmetal/algorithm/multiobjective/mocell.py | 54 +-- jmetal/algorithm/multiobjective/moead.py | 143 ++++--- jmetal/algorithm/multiobjective/nsgaii.py | 136 ++++--- jmetal/algorithm/multiobjective/nsgaiii.py | 108 ++--- jmetal/algorithm/multiobjective/omopso.py | 55 ++- .../algorithm/multiobjective/random_search.py | 25 +- jmetal/algorithm/multiobjective/smpso.py | 136 +++---- jmetal/algorithm/multiobjective/spea2.py | 47 ++- .../singleobjective/evolution_strategy.py | 39 +- .../singleobjective/genetic_algorithm.py | 53 +-- .../algorithm/singleobjective/local_search.py | 29 +- .../singleobjective/simulated_annealing.py | 34 +- jmetal/algorithm/test/ittest_algorithm.py | 12 +- jmetal/config.py | 15 +- jmetal/core/algorithm.py | 80 ++-- jmetal/core/observer.py | 9 +- jmetal/core/operator.py | 21 +- jmetal/core/problem.py | 72 ++-- jmetal/core/quality_indicator.py | 46 ++- jmetal/core/solution.py | 80 ++-- jmetal/core/test/test_observable.py | 17 +- jmetal/core/test/test_operator.py | 27 +- jmetal/core/test/test_problem.py | 14 +- jmetal/core/test/test_quality_indicator.py | 42 +- jmetal/core/test/test_solution.py | 50 +-- jmetal/lab/experiment.py | 370 ++++++++++-------- jmetal/lab/statistical_test/apv_procedures.py | 115 +++--- jmetal/lab/statistical_test/bayesian.py | 42 +- .../lab/statistical_test/critical_distance.py | 134 ++++--- jmetal/lab/statistical_test/functions.py | 195 +++++---- jmetal/lab/visualization/__init__.py | 5 +- jmetal/lab/visualization/chord_plot.py | 325 ++++++++++----- jmetal/lab/visualization/interactive.py | 114 +++--- jmetal/lab/visualization/plotting.py | 85 ++-- jmetal/lab/visualization/posterior.py | 89 ++--- jmetal/lab/visualization/streaming.py | 52 ++- jmetal/logger.py | 29 ++ jmetal/operator/__init__.py | 58 ++- jmetal/operator/crossover.py | 83 ++-- jmetal/operator/mutation.py | 89 +++-- jmetal/operator/selection.py | 92 ++--- jmetal/operator/test/test_crossover.py | 78 ++-- jmetal/operator/test/test_mutation.py | 46 ++- jmetal/operator/test/test_selection.py | 28 +- jmetal/problem/__init__.py | 26 +- jmetal/problem/multiobjective/constrained.py | 41 +- jmetal/problem/multiobjective/dtlz.py | 97 ++--- jmetal/problem/multiobjective/fda.py | 59 ++- jmetal/problem/multiobjective/lircmop.py | 153 ++++---- jmetal/problem/multiobjective/lz09.py | 110 +++--- .../multiobjective/test/test_constrained.py | 4 +- .../multiobjective/test/test_unconstrained.py | 13 +- .../problem/multiobjective/test/test_zdt.py | 23 +- jmetal/problem/multiobjective/uf.py | 23 +- .../problem/multiobjective/unconstrained.py | 109 +++--- jmetal/problem/multiobjective/zdt.py | 58 +-- jmetal/problem/singleobjective/knapsack.py | 28 +- .../singleobjective/test/test_knapsack.py | 21 +- .../test/test_unconstrained.py | 4 +- jmetal/problem/singleobjective/tsp.py | 19 +- .../problem/singleobjective/unconstrained.py | 33 +- jmetal/util/aggregative_function.py | 5 +- jmetal/util/archive.py | 56 ++- jmetal/util/ckecking.py | 13 +- jmetal/util/comparator.py | 46 +-- jmetal/util/density_estimator.py | 51 ++- jmetal/util/distance.py | 25 +- jmetal/util/evaluator.py | 23 +- jmetal/util/generator.py | 12 +- jmetal/util/neighborhood.py | 84 ++-- jmetal/util/observable.py | 3 +- jmetal/util/observer.py | 127 +++--- jmetal/util/point.py | 3 - jmetal/util/ranking.py | 39 +- jmetal/util/replacement.py | 22 +- jmetal/util/solution.py | 24 +- jmetal/util/termination_criterion.py | 13 +- jmetal/util/test/test_aggregativefunction.py | 3 +- jmetal/util/test/test_archive.py | 48 +-- jmetal/util/test/test_checking.py | 12 +- jmetal/util/test/test_comparator.py | 86 ++-- jmetal/util/test/test_constraint_handling.py | 17 +- jmetal/util/test/test_density_estimator.py | 73 ++-- jmetal/util/test/test_distance.py | 9 +- jmetal/util/test/test_evaluator.py | 5 +- jmetal/util/test/test_neighborhood.py | 25 +- jmetal/util/test/test_point.py | 3 +- jmetal/util/test/test_ranking.py | 62 ++- jmetal/util/test/test_replacement.py | 130 +++--- mypy.ini | 12 + pyproject.toml | 17 + setup.cfg | 59 ++- setup.py | 55 +-- 165 files changed, 4172 insertions(+), 3380 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .travis.yml create mode 100644 examples/singleobjective/evolution_strategy/evolution_strategy_permutation.py create mode 100644 examples/singleobjective/simulated_annealing/simulated_annealing_permutation.py create mode 100644 jmetal/logger.py create mode 100644 mypy.ini create mode 100644 pyproject.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..0877a905 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + workflow_dispatch: + push: + branches: + - main + - develop + pull_request: + branches: + - main + - develop + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + py: [ 3.9, 3.8, 3.7 ] + steps: + - uses: actions/checkout@v2 + - name: Install Python ${{ matrix.py }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.py }} + - name: Get full Python version + shell: bash + run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") + - name: Install dependencies + shell: bash + run: | + python -m pip install --upgrade pip + python -m pip install -e .[test] + - name: Run unittest + shell: bash + run: python -m unittest discover -q \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..725843c5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,31 @@ +name: release + +on: + push: + tags: + - '*.*.*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Get full Python version + shell: bash + run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") + - name: Build project for distribution + shell: bash + run: | + python -m pip install -q build + python -m build + - name: Create Release + uses: ncipollo/release-action@v1 + with: + artifacts: "dist/*" + token: ${{ secrets.GITHUB_TOKEN }} + draft: false + prerelease: steps.check-version.outputs.prerelease == 'true' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9ab22dc7..958121ef 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,5 @@ dask-worker-space # osx .DS_Store -# R -.RData -.Rhistory +# Github codespaces +pythonenv3.8 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2ef73b4c..00000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: python -python: '3.6' -install: - - python setup.py install - - pip install mockito PyHamcrest -script: python -m unittest discover diff --git a/Makefile b/Makefile index e650b479..1bcd80bb 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,20 @@ -# Minimal makefile for Sphinx documentation -# +install: + @python setup.py build install -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = jMetalPy -SOURCEDIR = docs/source -BUILDDIR = build +install-dependencies: + @python -m pip install -e .[all] -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +clean: + @rm -rf build dist .eggs *.egg-info + @find . -type d -name '.mypy_cache' -exec rm -rf {} + + @find . -type d -name '__pycache__' -exec rm -rf {} + -.PHONY: help Makefile +black: clean + @isort --profile black jmetal/ examples/ + @black jmetal/ examples/ -# "make github" option to build gh-pages -github: - @make html - @cp -a $(BUILDDIR)/html/. docs - @rm -r $(BUILDDIR) +lint: + @mypy jmetal/ examples/ --show-error-codes -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +tests: + @python -m unittest discover -q \ No newline at end of file diff --git a/README.md b/README.md index ae4391e8..250c59d3 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ ![jMetalPy](docs/source/jmetalpy.png) -[![Build Status](https://img.shields.io/travis/jMetal/jMetalPy/master.svg?style=flat-square)](https://travis-ci.org/jMetal/jMetalPy) -[![Documentation](https://img.shields.io/badge/docs-online-success?style=flat-square)](https://jmetal.github.io/jMetalPy/index.html) -[![PyPI License](https://img.shields.io/pypi/l/jMetalPy.svg?style=flat-square)]() -[![PyPI version](https://img.shields.io/pypi/v/jMetalPy.svg?style=flat-square)]() -[![PyPI Python version](https://img.shields.io/pypi/pyversions/jMetalPy.svg?style=flat-square)]() +[![CI](https://github.com/jMetal/jMetalPy/actions/workflows/ci.yml/badge.svg)](https://github.com/jMetal/jMetalPy/actions/workflows/ci.yml) +[![PyPI Python version](https://img.shields.io/pypi/pyversions/jMetalPy.svg)]() +[![DOI](https://img.shields.io/badge/DOI-10.1016%2Fj.swevo.2019.100598-blue)](https://doi.org/10.1016/j.swevo.2019.100598) +[![PyPI License](https://img.shields.io/pypi/l/jMetalPy.svg)]() +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) A paper introducing jMetalPy is available at: https://doi.org/10.1016/j.swevo.2019.100598 @@ -43,7 +43,7 @@ pip install "jmetalpy[core]" Other supported commands are listed next: ```console -pip install "jmetalpy[docs]" # Install requirements for building docs +pip install "jmetalpy[dev]" # Install requirements for development pip install "jmetalpy[distributed]" # Install requirements for parallel/distributed computing pip install "jmetalpy[complete]" # Install all requirements ``` @@ -100,7 +100,7 @@ plot_front.plot(front, label='NSGAII-ZDT1', filename='NSGAII-ZDT1', format='png' Pareto front approximation ## Features -The current release of jMetalPy (v1.5.5) contains the following components: +The current release of jMetalPy (v1.5.7) contains the following components: * Algorithms: local search, genetic algorithm, evolution strategy, simulated annealing, random search, NSGA-II, NSGA-III, SMPSO, OMOPSO, MOEA/D, MOEA/D-DRA, MOEA/D-IEpsilon, GDE3, SPEA2, HYPE, IBEA. Preference articulation-based algorithms (G-NSGA-II, G-GDE3, G-SPEA2, SMPSO/RP); Dynamic versions of NSGA-II, SMPSO, and GDE3. * Parallel computing based on Apache Spark and Dask. @@ -118,9 +118,12 @@ The current release of jMetalPy (v1.5.5) contains the following components: ## Changelog +* [v1.5.7] Use of linters for catching errors and formatters to fix style, minor bug fixes. +* [v1.5.6] Removed warnings when using Python 3.8. * [v1.5.5] Minor bug fixes. * [v1.5.4] Refactored quality indicators to accept numpy array as input parameter. * [v1.5.4] Added [CompositeSolution](https://github.com/jMetal/jMetalPy/blob/master/jmetal/core/solution.py#L111) class to support mixed combinatorial problems. [#69](https://github.com/jMetal/jMetalPy/issues/69) ## License + This project is licensed under the terms of the MIT - see the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 2de98813..2ce056bb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -2,6 +2,7 @@ import os import sys + sys.path.insert(0, os.path.abspath('../../')) # -- Project information ----------------------------------------------------- diff --git a/examples/experiment/comparison.py b/examples/experiment/comparison.py index 5b654d7a..5924b935 100644 --- a/examples/experiment/comparison.py +++ b/examples/experiment/comparison.py @@ -21,12 +21,13 @@ def configure_experiment(problems: dict, n_run: int): problem=problem, population_size=100, offspring_population_size=100, - mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, - distribution_index=20), + mutation=PolynomialMutation( + probability=1.0 / problem.number_of_variables, distribution_index=20 + ), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ), - algorithm_tag='NSGAII', + algorithm_tag="NSGAII", problem_tag=problem_tag, run=run, ) @@ -38,9 +39,9 @@ def configure_experiment(problems: dict, n_run: int): population_size=100, cr=0.5, f=0.5, - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ), - algorithm_tag='GDE3', + algorithm_tag="GDE3", problem_tag=problem_tag, run=run, ) @@ -50,12 +51,13 @@ def configure_experiment(problems: dict, n_run: int): algorithm=SMPSO( problem=problem, swarm_size=100, - mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, - distribution_index=20), + mutation=PolynomialMutation( + probability=1.0 / problem.number_of_variables, distribution_index=20 + ), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ), - algorithm_tag='SMPSO', + algorithm_tag="SMPSO", problem_tag=problem_tag, run=run, ) @@ -64,12 +66,12 @@ def configure_experiment(problems: dict, n_run: int): return jobs -if __name__ == '__main__': +if __name__ == "__main__": # Configure the experiments - jobs = configure_experiment(problems={'ZDT1': ZDT1(), 'ZDT2': ZDT2(), 'ZDT3': ZDT3()}, n_run=25) + jobs = configure_experiment(problems={"ZDT1": ZDT1(), "ZDT2": ZDT2(), "ZDT3": ZDT3()}, n_run=25) # Run the study - output_directory = 'data' + output_directory = "data" experiment = Experiment(output_dir=output_directory, jobs=jobs) experiment.run() @@ -77,6 +79,6 @@ def configure_experiment(problems: dict, n_run: int): # Generate summary file generate_summary_from_experiment( input_dir=output_directory, - reference_fronts='resources/reference_front', - quality_indicators=[GenerationalDistance(), EpsilonIndicator(), HyperVolume([1.0, 1.0])] + reference_fronts="resources/reference_front", + quality_indicators=[GenerationalDistance(), EpsilonIndicator(), HyperVolume([1.0, 1.0])], ) diff --git a/examples/experiment/statistical_analysis.py b/examples/experiment/statistical_analysis.py index a1691676..3830dcb1 100644 --- a/examples/experiment/statistical_analysis.py +++ b/examples/experiment/statistical_analysis.py @@ -1,68 +1,75 @@ -from jmetal.lab.experiment import generate_boxplot, generate_latex_tables, compute_mean_indicator, compute_wilcoxon +from jmetal.lab.experiment import ( + compute_mean_indicator, + compute_wilcoxon, + generate_boxplot, + generate_latex_tables, +) from jmetal.lab.statistical_test.bayesian import * from jmetal.lab.statistical_test.functions import * from jmetal.lab.visualization import CDplot, plot_posterior -if __name__ == '__main__': +if __name__ == "__main__": # Generate Median & IQR tables - generate_latex_tables(filename='QualityIndicatorSummary.csv') + generate_latex_tables(filename="QualityIndicatorSummary.csv") # Generate boxplots - generate_boxplot(filename='QualityIndicatorSummary.csv') + generate_boxplot(filename="QualityIndicatorSummary.csv") # Wilcoxon - compute_wilcoxon(filename='QualityIndicatorSummary.csv') + compute_wilcoxon(filename="QualityIndicatorSummary.csv") # Statistical lab - avg = compute_mean_indicator(filename='QualityIndicatorSummary.csv', indicator_name='HV') + avg = compute_mean_indicator(filename="QualityIndicatorSummary.csv", indicator_name="HV") print(avg) # Non-parametric test - print('-------- Sign Test --------') - print(sign_test(avg[['NSGAII', 'SMPSO']])) - print('-------- Friedman Test --------') + print("-------- Sign Test --------") + print(sign_test(avg[["NSGAII", "SMPSO"]])) + print("-------- Friedman Test --------") print(friedman_test(avg)) - print('-------- Friedman Aligned Rank Test --------') + print("-------- Friedman Aligned Rank Test --------") print(friedman_aligned_rank_test(avg)) - print('-------- Quade Test --------') + print("-------- Quade Test --------") print(quade_test(avg)) # Post-hoc tests - print('-------- Friedman Post-Hoc Test --------') - z, p_val, adj_pval = friedman_ph_test(avg, control=0, apv_procedure='Bonferroni') - print('z values \n', z) - print('p-values \n', p_val) - print('adjusted p-values \n', adj_pval) - print('-------- Friedman Aligned Rank Post-Hoc Test --------') - z, p_val, adj_pval = friedman_aligned_ph_test(avg, apv_procedure='Shaffer') - print('z values \n', z) - print('p-values \n', p_val) - print('adjusted p-values \n', adj_pval) - print('-------- QuadeTest Post-Hoc Test --------') - z, p_val, adj_pval = quade_ph_test(avg, apv_procedure='Holm') - print('z values \n', z) - print('p-values \n', p_val) - print('adjusted p-values \n', adj_pval) + print("-------- Friedman Post-Hoc Test --------") + z, p_val, adj_pval = friedman_ph_test(avg, control=0, apv_procedure="Bonferroni") + print("z values \n", z) + print("p-values \n", p_val) + print("adjusted p-values \n", adj_pval) + print("-------- Friedman Aligned Rank Post-Hoc Test --------") + z, p_val, adj_pval = friedman_aligned_ph_test(avg, apv_procedure="Shaffer") + print("z values \n", z) + print("p-values \n", p_val) + print("adjusted p-values \n", adj_pval) + print("-------- QuadeTest Post-Hoc Test --------") + z, p_val, adj_pval = quade_ph_test(avg, apv_procedure="Holm") + print("z values \n", z) + print("p-values \n", p_val) + print("adjusted p-values \n", adj_pval) # Plot critical distance CDplot(avg.T, alpha=0.15, higher_is_better=True) - print('-------- Bayesian Sign Test --------') - bst, DProcess = bayesian_sign_test(avg[['NSGAII', 'SMPSO']], rope_limits=[-0.002, 0.002], - prior_strength=0.5, return_sample=True) - plot_posterior(DProcess, higher_is_better=True, alg_names=['NSGAII', 'SMPSO']) + print("-------- Bayesian Sign Test --------") + bst, DProcess = bayesian_sign_test( + avg[["NSGAII", "SMPSO"]], rope_limits=[-0.002, 0.002], prior_strength=0.5, return_sample=True + ) + plot_posterior(DProcess, higher_is_better=True, alg_names=["NSGAII", "SMPSO"]) - print('Pr(NSGAII < SMPSO) = %.3f' % bst[0]) - print('Pr(NSGAII ~= SMPSO) = %.3f' % bst[1]) - print('Pr(NSGAII > SMPSO) = %.3f' % bst[2]) + print("Pr(NSGAII < SMPSO) = %.3f" % bst[0]) + print("Pr(NSGAII ~= SMPSO) = %.3f" % bst[1]) + print("Pr(NSGAII > SMPSO) = %.3f" % bst[2]) - print('-------- Bayesian Signed Rank Test --------') - bst, DProcess = bayesian_signed_rank_test(avg[['NSGAII', 'SMPSO']], rope_limits=[-0.002, 0.002], - prior_strength=0.5, return_sample=True) - plot_posterior(DProcess, higher_is_better=True, alg_names=['NSGAII', 'SMPSO']) + print("-------- Bayesian Signed Rank Test --------") + bst, DProcess = bayesian_signed_rank_test( + avg[["NSGAII", "SMPSO"]], rope_limits=[-0.002, 0.002], prior_strength=0.5, return_sample=True + ) + plot_posterior(DProcess, higher_is_better=True, alg_names=["NSGAII", "SMPSO"]) - print('Pr(NSGAII < SMPSO) = %.3f' % bst[0]) - print('Pr(NSGAII ~= SMPSO) = %.3f' % bst[1]) - print('Pr(NSGAII > SMPSO) = %.3f' % bst[2]) + print("Pr(NSGAII < SMPSO) = %.3f" % bst[0]) + print("Pr(NSGAII ~= SMPSO) = %.3f" % bst[1]) + print("Pr(NSGAII > SMPSO) = %.3f" % bst[2]) diff --git a/examples/multiobjective/gde3/dynamic_gde3.py b/examples/multiobjective/gde3/dynamic_gde3.py index cd92568f..ccf4478a 100644 --- a/examples/multiobjective/gde3/dynamic_gde3.py +++ b/examples/multiobjective/gde3/dynamic_gde3.py @@ -1,10 +1,10 @@ from jmetal.algorithm.multiobjective.gde3 import DynamicGDE3 from jmetal.problem.multiobjective.fda import FDA2 from jmetal.util.observable import TimeCounter -from jmetal.util.observer import WriteFrontToFileObserver, PlotFrontToFileObserver +from jmetal.util.observer import PlotFrontToFileObserver, WriteFrontToFileObserver from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = FDA2() time_counter = TimeCounter(delay=1) @@ -16,10 +16,10 @@ population_size=100, cr=0.5, f=0.5, - termination_criterion=StoppingByEvaluations(max_evaluations=500) + termination_criterion=StoppingByEvaluations(max_evaluations=500), ) - algorithm.observable.register(observer=PlotFrontToFileObserver('dynamic_front_vis')) - algorithm.observable.register(observer=WriteFrontToFileObserver('dynamic_front')) + algorithm.observable.register(observer=PlotFrontToFileObserver("dynamic_front_vis")) + algorithm.observable.register(observer=WriteFrontToFileObserver("dynamic_front")) algorithm.run() diff --git a/examples/multiobjective/gde3/gde3_spark_evaluator.py b/examples/multiobjective/gde3/gde3_spark_evaluator.py index 7f47ca66..b2a489e3 100644 --- a/examples/multiobjective/gde3/gde3_spark_evaluator.py +++ b/examples/multiobjective/gde3/gde3_spark_evaluator.py @@ -4,7 +4,7 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() algorithm = GDE3( @@ -13,16 +13,16 @@ cr=0.5, f=0.5, termination_criterion=StoppingByEvaluations(max_evaluations=100), - population_evaluator=SparkEvaluator() + population_evaluator=SparkEvaluator(), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(front, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(front, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(front, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm (continuous problem): {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/gde3/gde3_zdt1.py b/examples/multiobjective/gde3/gde3_zdt1.py index 4b7bfcca..7a45eea9 100644 --- a/examples/multiobjective/gde3/gde3_zdt1.py +++ b/examples/multiobjective/gde3/gde3_zdt1.py @@ -1,27 +1,25 @@ from jmetal.algorithm.multiobjective.gde3 import GDE3 from jmetal.problem import ZDT1 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByKeyboard -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") - algorithm = GDE3( - problem=problem, - population_size=100, - cr=0.5, - f=0.5, - termination_criterion=StoppingByKeyboard() - ) + algorithm = GDE3(problem=problem, population_size=100, cr=0.5, f=0.5, termination_criterion=StoppingByKeyboard()) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/gde3/ggde3_zdt2.py b/examples/multiobjective/gde3/ggde3_zdt2.py index ed3564cf..305b2de9 100644 --- a/examples/multiobjective/gde3/ggde3_zdt2.py +++ b/examples/multiobjective/gde3/ggde3_zdt2.py @@ -1,12 +1,16 @@ from jmetal.algorithm.multiobjective.gde3 import GDE3 from jmetal.problem import ZDT2 from jmetal.util.comparator import GDominanceComparator -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT2() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT2.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT2.pf") max_evaluations = 25000 reference_point = [0.2, 0.5] @@ -17,16 +21,16 @@ cr=0.5, f=0.5, termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=GDominanceComparator(reference_point) + dominance_comparator=GDominanceComparator(reference_point), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/hype/hype_zdt1.py b/examples/multiobjective/hype/hype_zdt1.py index 6c10153f..30e6b206 100644 --- a/examples/multiobjective/hype/hype_zdt1.py +++ b/examples/multiobjective/hype/hype_zdt1.py @@ -1,16 +1,24 @@ from jmetal.algorithm.multiobjective.hype import HYPE from jmetal.core.solution import FloatSolution -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") - reference_point = FloatSolution([0], [1], problem.number_of_objectives, ) - reference_point.objectives = [1., 1.] # Mandatory for HYPE + reference_point = FloatSolution( + [0], + [1], + problem.number_of_objectives, + ) + reference_point.objectives = [1.0, 1.0] # Mandatory for HYPE algorithm = HYPE( problem=problem, @@ -19,16 +27,16 @@ offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(25000) + termination_criterion=StoppingByEvaluations(25000), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/ibea/ibea_zdt1.py b/examples/multiobjective/ibea/ibea_zdt1.py index ad2b71ad..8aa67710 100644 --- a/examples/multiobjective/ibea/ibea_zdt1.py +++ b/examples/multiobjective/ibea/ibea_zdt1.py @@ -1,30 +1,34 @@ from jmetal.algorithm.multiobjective.ibea import IBEA -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") algorithm = IBEA( problem=problem, - kappa=1., + kappa=1.0, population_size=100, offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/mocell/mocell_zdt1.py b/examples/multiobjective/mocell/mocell_zdt1.py index 617b72d1..dded32ae 100644 --- a/examples/multiobjective/mocell/mocell_zdt1.py +++ b/examples/multiobjective/mocell/mocell_zdt1.py @@ -1,16 +1,18 @@ -from jmetal.util.solution_list import print_function_values_to_file, print_variables_to_file - from jmetal.algorithm.multiobjective.mocell import MOCell -from jmetal.operator import SBXCrossover, PolynomialMutation -from jmetal.problem import ZDT1 +from jmetal.operator import PolynomialMutation, SBXCrossover +from jmetal.problem import ZDT1, ZDT4 from jmetal.util.archive import CrowdingDistanceArchive from jmetal.util.neighborhood import C9 -from jmetal.util.solution import read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT4.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 25000 algorithm = MOCell( @@ -20,16 +22,16 @@ archive=CrowdingDistanceArchive(100), mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/moead/moead_dtlz2.py b/examples/multiobjective/moead/moead_dtlz2.py index 8770b47b..3a493985 100644 --- a/examples/multiobjective/moead/moead_dtlz2.py +++ b/examples/multiobjective/moead/moead_dtlz2.py @@ -1,14 +1,18 @@ from jmetal.algorithm.multiobjective.moead import MOEAD -from jmetal.core.quality_indicator import HyperVolume, InvertedGenerationalDistance -from jmetal.operator import PolynomialMutation, DifferentialEvolutionCrossover +from jmetal.core.quality_indicator import HyperVolume +from jmetal.operator import DifferentialEvolutionCrossover, PolynomialMutation from jmetal.problem import DTLZ2 from jmetal.util.aggregative_function import Tschebycheff -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = DTLZ2() - problem.reference_front = read_solutions(filename='resources/reference_front/DTLZ2.3D.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/DTLZ2.3D.pf") max_evaluations = 50000 @@ -21,8 +25,8 @@ neighbor_size=20, neighbourhood_selection_probability=0.9, max_number_of_replaced_solutions=2, - weight_files_path='resources/MOEAD_weights', - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + weight_files_path="resources/MOEAD_weights", + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() @@ -32,9 +36,9 @@ print("Hypervolume: " + str(hypervolume.compute([front[i].objectives for i in range(len(front))]))) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/moead/moead_iepsilon_lircmop1.py b/examples/multiobjective/moead/moead_iepsilon_lircmop1.py index 3f517a11..53f565a7 100644 --- a/examples/multiobjective/moead/moead_iepsilon_lircmop1.py +++ b/examples/multiobjective/moead/moead_iepsilon_lircmop1.py @@ -1,14 +1,18 @@ from jmetal.algorithm.multiobjective.moead import MOEADIEpsilon -from jmetal.operator import PolynomialMutation, DifferentialEvolutionCrossover +from jmetal.operator import DifferentialEvolutionCrossover, PolynomialMutation from jmetal.problem.multiobjective.lircmop import LIRCMOP2 from jmetal.util.aggregative_function import Tschebycheff -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = LIRCMOP2() - problem.reference_front = read_solutions(filename='resources/reference_front/LIRCMOP2.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/LIRCMOP2.pf") max_evaluations = 300000 @@ -21,17 +25,17 @@ neighbor_size=20, neighbourhood_selection_probability=0.9, max_number_of_replaced_solutions=2, - weight_files_path='resources/MOEAD_weights', - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + weight_files_path="resources/MOEAD_weights", + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/moead/moead_lz09.py b/examples/multiobjective/moead/moead_lz09.py index e0bf3c10..d85ad0bc 100644 --- a/examples/multiobjective/moead/moead_lz09.py +++ b/examples/multiobjective/moead/moead_lz09.py @@ -1,14 +1,18 @@ from jmetal.algorithm.multiobjective.moead import MOEAD -from jmetal.operator import PolynomialMutation, DifferentialEvolutionCrossover +from jmetal.operator import DifferentialEvolutionCrossover, PolynomialMutation from jmetal.problem import LZ09_F2 from jmetal.util.aggregative_function import Tschebycheff -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = LZ09_F2() - problem.reference_front = read_solutions(filename='resources/reference_front/LZ09_F2.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/LZ09_F2.pf") max_evaluations = 150000 @@ -21,17 +25,17 @@ neighbor_size=20, neighbourhood_selection_probability=0.9, max_number_of_replaced_solutions=2, - weight_files_path='resources/MOEAD_weights', - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + weight_files_path="resources/MOEAD_weights", + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/moead/moeaddra_lz09.py b/examples/multiobjective/moead/moeaddra_lz09.py index ea0aba9d..565bed72 100644 --- a/examples/multiobjective/moead/moeaddra_lz09.py +++ b/examples/multiobjective/moead/moeaddra_lz09.py @@ -1,15 +1,18 @@ from jmetal.algorithm.multiobjective.moead import MOEAD_DRA -from jmetal.operator import PolynomialMutation, DifferentialEvolutionCrossover -from jmetal.problem import LZ09_F2 +from jmetal.core.quality_indicator import HyperVolume +from jmetal.operator import DifferentialEvolutionCrossover, PolynomialMutation from jmetal.problem.multiobjective.uf import UF1 from jmetal.util.aggregative_function import Tschebycheff -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -from jmetal.core.quality_indicator import HyperVolume, InvertedGenerationalDistance -if __name__ == '__main__': +if __name__ == "__main__": problem = UF1() - problem.reference_front = read_solutions(filename='resources/reference_front/UF1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/UF1.pf") max_evaluations = 300000 @@ -22,8 +25,8 @@ neighbor_size=20, neighbourhood_selection_probability=0.9, max_number_of_replaced_solutions=2, - weight_files_path='resources/MOEAD_weights', - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + weight_files_path="resources/MOEAD_weights", + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() @@ -33,11 +36,9 @@ print("Hypervolume: " + str(hypervolume.compute([front[i].objectives for i in range(len(front))]))) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') - + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask.py b/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask.py index 1b266b51..3311519a 100644 --- a/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask.py +++ b/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask.py @@ -10,14 +10,14 @@ Distributed (asynchronous) version of NSGA-II using Dask. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() # setup Dask client client = Client(LocalCluster(n_workers=24)) ncores = sum(client.ncores().values()) - print(f'{ncores} cores available') + print(f"{ncores} cores available") # creates the algorithm max_evaluations = 25000 @@ -29,13 +29,12 @@ crossover=SBXCrossover(probability=1.0, distribution_index=20), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), number_of_cores=ncores, - client=client + client=client, ) algorithm.run() front = algorithm.get_result() - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) - + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask_evaluator.py b/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask_evaluator.py index 4230b469..a249de28 100644 --- a/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask_evaluator.py +++ b/examples/multiobjective/nsgaii/distributed_nsgaii_with_dask_evaluator.py @@ -1,5 +1,5 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem.multiobjective.zdt import ZDT1Modified from jmetal.util.evaluator import DaskEvaluator from jmetal.util.solution import print_function_values_to_file, print_variables_to_file @@ -8,7 +8,7 @@ """ Distributed (synchronous) version of NSGA-II using Dask. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() max_evaluations = 100 @@ -20,17 +20,16 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), population_evaluator=DaskEvaluator(), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/distributed_nsgaii_with_spark_evaluator.py b/examples/multiobjective/nsgaii/distributed_nsgaii_with_spark_evaluator.py index 1d585d24..eef1b5d7 100644 --- a/examples/multiobjective/nsgaii/distributed_nsgaii_with_spark_evaluator.py +++ b/examples/multiobjective/nsgaii/distributed_nsgaii_with_spark_evaluator.py @@ -1,5 +1,5 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem.multiobjective.zdt import ZDT1Modified from jmetal.util.evaluator import SparkEvaluator from jmetal.util.solution import print_function_values_to_file, print_variables_to_file @@ -9,7 +9,7 @@ Distributed (synchronous) version of NSGA-II using Apache Spark. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() max_evaluations = 100 @@ -21,16 +21,16 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), population_evaluator=SparkEvaluator(), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/dynamic_nsgaii_solving_fda2.py b/examples/multiobjective/nsgaii/dynamic_nsgaii_solving_fda2.py index 6ba30bc3..b61a7db1 100644 --- a/examples/multiobjective/nsgaii/dynamic_nsgaii_solving_fda2.py +++ b/examples/multiobjective/nsgaii/dynamic_nsgaii_solving_fda2.py @@ -5,7 +5,7 @@ from jmetal.util.observer import PlotFrontToFileObserver, WriteFrontToFileObserver from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = FDA2() time_counter = TimeCounter(delay=1) @@ -19,10 +19,10 @@ offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) - algorithm.observable.register(observer=PlotFrontToFileObserver('dynamic_front_vis')) - algorithm.observable.register(observer=WriteFrontToFileObserver('dynamic_front')) + algorithm.observable.register(observer=PlotFrontToFileObserver("dynamic_front_vis")) + algorithm.observable.register(observer=WriteFrontToFileObserver("dynamic_front")) algorithm.run() diff --git a/examples/multiobjective/nsgaii/gnsgaii_solving_zdt2_with_reference_point.py b/examples/multiobjective/nsgaii/gnsgaii_solving_zdt2_with_reference_point.py index b84dd8e1..00ec58fa 100644 --- a/examples/multiobjective/nsgaii/gnsgaii_solving_zdt2_with_reference_point.py +++ b/examples/multiobjective/nsgaii/gnsgaii_solving_zdt2_with_reference_point.py @@ -1,10 +1,14 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.lab.visualization import Plot, InteractivePlot -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.lab.visualization import InteractivePlot, Plot +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT2 from jmetal.util.comparator import GDominanceComparator from jmetal.util.observer import ProgressBarObserver, VisualizerObserver -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file, read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations """ @@ -12,9 +16,9 @@ reference point = [0.2, 0.5]. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT2() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT2.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT2.pf") reference_point = [0.2, 0.5] @@ -26,30 +30,37 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), dominance_comparator=GDominanceComparator(reference_point), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.observable.register(observer=ProgressBarObserver(max=max_evaluations)) algorithm.observable.register( - observer=VisualizerObserver(reference_front=problem.reference_front, reference_point=reference_point)) + observer=VisualizerObserver(reference_front=problem.reference_front, reference_point=reference_point) + ) algorithm.run() front = algorithm.get_result() # Plot front - plot_front = Plot(title='Pareto front approximation. Problem: ' + problem.get_name(), - reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = Plot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Plot interactive front - plot_front = InteractivePlot(title='Pareto front approximation. Problem: ' + problem.get_name(), - reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = InteractivePlot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.' + algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_defining_schaffer_problem_on_the_fly.py b/examples/multiobjective/nsgaii/nsgaii_defining_schaffer_problem_on_the_fly.py index 7c0a8a51..c0cec9b3 100644 --- a/examples/multiobjective/nsgaii/nsgaii_defining_schaffer_problem_on_the_fly.py +++ b/examples/multiobjective/nsgaii/nsgaii_defining_schaffer_problem_on_the_fly.py @@ -1,15 +1,19 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII from jmetal.core.problem import OnTheFlyFloatProblem -from jmetal.operator import SBXCrossover, PolynomialMutation -from jmetal.util.solution import get_non_dominated_solutions, read_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.operator import PolynomialMutation, SBXCrossover +from jmetal.util.solution import ( + get_non_dominated_solutions, + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations """ Program to configure and run the NSGA-II algorithm configured with standard settings. """ -if __name__ == '__main__': +if __name__ == "__main__": # Defining problem Schaffer on the fly def f1(x: [float]): return x[0] * x[0] @@ -18,13 +22,9 @@ def f2(x: [float]): return (x[0] - 2) * (x[0] - 2) problem = OnTheFlyFloatProblem() - problem \ - .set_name('Schaffer') \ - .add_variable(-10000.0, 10000.0) \ - .add_function(f1) \ - .add_function(f2) + problem.set_name("Schaffer").add_variable(-10000.0, 10000.0).add_function(f1).add_function(f2) - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -33,17 +33,16 @@ def f2(x: [float]): offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = get_non_dominated_solutions(algorithm.get_result()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_defining_srinivas_problem_on_the_fly.py b/examples/multiobjective/nsgaii/nsgaii_defining_srinivas_problem_on_the_fly.py index a017bfcd..b9b90ad2 100644 --- a/examples/multiobjective/nsgaii/nsgaii_defining_srinivas_problem_on_the_fly.py +++ b/examples/multiobjective/nsgaii/nsgaii_defining_srinivas_problem_on_the_fly.py @@ -1,42 +1,44 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII from jmetal.core.problem import OnTheFlyFloatProblem -from jmetal.operator import SBXCrossover, PolynomialMutation -from jmetal.util.solution import get_non_dominated_solutions, read_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.operator import PolynomialMutation, SBXCrossover +from jmetal.util.solution import ( + get_non_dominated_solutions, + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations """ Program to configure and run the NSGA-II algorithm configured with standard settings. """ -if __name__ == '__main__': +if __name__ == "__main__": # Defining problem Srinivas on the fly def f1(x: [float]): return 2.0 + (x[0] - 2.0) * (x[0] - 2.0) + (x[1] - 1.0) * (x[1] - 1.0) - def f2(x: [float]): return 9.0 * x[0] - (x[1] - 1.0) * (x[1] - 1.0) - def c1(x: [float]): return 1.0 - (x[0] * x[0] + x[1] * x[1]) / 225.0 - def c2(x: [float]): return (3.0 * x[1] - x[0]) / 10.0 - 1.0 - - problem = OnTheFlyFloatProblem() \ - .set_name('Srinivas') \ - .add_variable(-20.0, 20.0) \ - .add_variable(-20.0, 20.0) \ - .add_function(f1) \ - .add_function(f2) \ - .add_constraint(c1) \ + problem = ( + OnTheFlyFloatProblem() + .set_name("Srinivas") + .add_variable(-20.0, 20.0) + .add_variable(-20.0, 20.0) + .add_function(f1) + .add_function(f2) + .add_constraint(c1) .add_constraint(c2) + ) - problem.reference_front = read_solutions(filename='resources/reference_front/Srinivas.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/Srinivas.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -45,17 +47,16 @@ def c2(x: [float]): offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = get_non_dominated_solutions(algorithm.get_result()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_solving_3D_problem.py b/examples/multiobjective/nsgaii/nsgaii_solving_3D_problem.py index c8dcb7bd..23f105aa 100644 --- a/examples/multiobjective/nsgaii/nsgaii_solving_3D_problem.py +++ b/examples/multiobjective/nsgaii/nsgaii_solving_3D_problem.py @@ -1,13 +1,17 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import DTLZ2 from jmetal.util.comparator import DominanceComparator -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file, read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = DTLZ2() - problem.reference_front = read_solutions(filename='resources/reference_front/DTLZ2.3D.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/DTLZ2.3D.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -17,16 +21,16 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=DominanceComparator() + dominance_comparator=DominanceComparator(), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_solving_binary_problem.py b/examples/multiobjective/nsgaii/nsgaii_solving_binary_problem.py index 73bacf7f..37a567fb 100644 --- a/examples/multiobjective/nsgaii/nsgaii_solving_binary_problem.py +++ b/examples/multiobjective/nsgaii/nsgaii_solving_binary_problem.py @@ -9,7 +9,7 @@ multiobjective version of the ONE_MAX problem where the numbers of 1s and 0s have to be maximized at the same time. """ -if __name__ == '__main__': +if __name__ == "__main__": binary_string_length = 512 problem = OneZeroMax(binary_string_length) @@ -20,16 +20,16 @@ offspring_population_size=100, mutation=BitFlipMutation(probability=1.0 / binary_string_length), crossover=SPXCrossover(probability=1.0), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_solving_constrained_srinivas_problem.py b/examples/multiobjective/nsgaii/nsgaii_solving_constrained_srinivas_problem.py index 180a5f53..a41bcfb9 100644 --- a/examples/multiobjective/nsgaii/nsgaii_solving_constrained_srinivas_problem.py +++ b/examples/multiobjective/nsgaii/nsgaii_solving_constrained_srinivas_problem.py @@ -1,13 +1,17 @@ from jmetal.algorithm.multiobjective import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import Srinivas from jmetal.util.comparator import DominanceComparator -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Srinivas() - problem.reference_front = read_solutions(filename='resources/reference_front/Srinivas.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/Srinivas.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -17,16 +21,16 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=DominanceComparator() + dominance_comparator=DominanceComparator(), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_solving_mixed_encoding_problem.py b/examples/multiobjective/nsgaii/nsgaii_solving_mixed_encoding_problem.py index b859d11d..96b5d65d 100644 --- a/examples/multiobjective/nsgaii/nsgaii_solving_mixed_encoding_problem.py +++ b/examples/multiobjective/nsgaii/nsgaii_solving_mixed_encoding_problem.py @@ -1,13 +1,16 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation, IntegerPolynomialMutation +from jmetal.operator import IntegerPolynomialMutation, PolynomialMutation, SBXCrossover from jmetal.operator.crossover import CompositeCrossover, IntegerSBXCrossover from jmetal.operator.mutation import CompositeMutation from jmetal.problem.multiobjective.unconstrained import MixedIntegerFloatProblem -from jmetal.util.solution import get_non_dominated_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.util.solution import ( + get_non_dominated_solutions, + print_function_values_to_file, + print_variables_to_file, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = MixedIntegerFloatProblem(10, 10, 100, -100, -1000, 1000) max_evaluations = 25000 @@ -16,18 +19,22 @@ population_size=100, offspring_population_size=100, mutation=CompositeMutation([IntegerPolynomialMutation(0.01, 20), PolynomialMutation(0.01, 20.0)]), - crossover=CompositeCrossover([IntegerSBXCrossover(probability=1.0, distribution_index=20), - SBXCrossover(probability=1.0, distribution_index=20)]), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + crossover=CompositeCrossover( + [ + IntegerSBXCrossover(probability=1.0, distribution_index=20), + SBXCrossover(probability=1.0, distribution_index=20), + ] + ), + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = get_non_dominated_solutions(algorithm.get_result()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.' + algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_ssp.py b/examples/multiobjective/nsgaii/nsgaii_ssp.py index 7e40df07..97a1f477 100644 --- a/examples/multiobjective/nsgaii/nsgaii_ssp.py +++ b/examples/multiobjective/nsgaii/nsgaii_ssp.py @@ -4,23 +4,138 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": C = 300500 - W = [2902, 5235, 357, 6058, 4846, 8280, 1295, 181, 3264, - 7285, 8806, 2344, 9203, 6806, 1511, 2172, 843, 4697, - 3348, 1866, 5800, 4094, 2751, 64, 7181, 9167, 5579, - 9461, 3393, 4602, 1796, 8174, 1691, 8854, 5902, 4864, - 5488, 1129, 1111, 7597, 5406, 2134, 7280, 6465, 4084, - 8564, 2593, 9954, 4731, 1347, 8984, 5057, 3429, 7635, - 1323, 1146, 5192, 6547, 343, 7584, 3765, 8660, 9318, - 5098, 5185, 9253, 4495, 892, 5080, 5297, 9275, 7515, - 9729, 6200, 2138, 5480, 860, 8295, 8327, 9629, 4212, - 3087, 5276, 9250, 1835, 9241, 1790, 1947, 8146, 8328, - 973, 1255, 9733, 4314, 6912, 8007, 8911, 6802, 5102, - 5451, 1026, 8029, 6628, 8121, 5509, 3603, 6094, 4447, - 683, 6996, 3304, 3130, 2314, 7788, 8689, 3253, 5920, - 3660, 2489, 8153, 2822, 6132, 7684, 3032, 9949, 59, - 6669, 6334] + W = [ + 2902, + 5235, + 357, + 6058, + 4846, + 8280, + 1295, + 181, + 3264, + 7285, + 8806, + 2344, + 9203, + 6806, + 1511, + 2172, + 843, + 4697, + 3348, + 1866, + 5800, + 4094, + 2751, + 64, + 7181, + 9167, + 5579, + 9461, + 3393, + 4602, + 1796, + 8174, + 1691, + 8854, + 5902, + 4864, + 5488, + 1129, + 1111, + 7597, + 5406, + 2134, + 7280, + 6465, + 4084, + 8564, + 2593, + 9954, + 4731, + 1347, + 8984, + 5057, + 3429, + 7635, + 1323, + 1146, + 5192, + 6547, + 343, + 7584, + 3765, + 8660, + 9318, + 5098, + 5185, + 9253, + 4495, + 892, + 5080, + 5297, + 9275, + 7515, + 9729, + 6200, + 2138, + 5480, + 860, + 8295, + 8327, + 9629, + 4212, + 3087, + 5276, + 9250, + 1835, + 9241, + 1790, + 1947, + 8146, + 8328, + 973, + 1255, + 9733, + 4314, + 6912, + 8007, + 8911, + 6802, + 5102, + 5451, + 1026, + 8029, + 6628, + 8121, + 5509, + 3603, + 6094, + 4447, + 683, + 6996, + 3304, + 3130, + 2314, + 7788, + 8689, + 3253, + 5920, + 3660, + 2489, + 8153, + 2822, + 6132, + 7684, + 3032, + 9949, + 59, + 6669, + 6334, + ] problem = SubsetSum(C, W) @@ -30,16 +145,16 @@ offspring_population_size=100, mutation=BitFlipMutation(probability=0.5), crossover=SPXCrossover(probability=0.8), - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_standard_settings.py b/examples/multiobjective/nsgaii/nsgaii_standard_settings.py index 1c711c03..cd0e3bef 100644 --- a/examples/multiobjective/nsgaii/nsgaii_standard_settings.py +++ b/examples/multiobjective/nsgaii/nsgaii_standard_settings.py @@ -1,18 +1,21 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 -from jmetal.util.solution import get_non_dominated_solutions, read_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.util.solution import ( + get_non_dominated_solutions, + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations - """ Program to configure and run the NSGA-II algorithm configured with standard settings. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -21,17 +24,16 @@ offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = get_non_dominated_solutions(algorithm.get_result()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_standard_settings_with_real_time_plotting.py b/examples/multiobjective/nsgaii/nsgaii_standard_settings_with_real_time_plotting.py index bd968147..9a3af9c1 100644 --- a/examples/multiobjective/nsgaii/nsgaii_standard_settings_with_real_time_plotting.py +++ b/examples/multiobjective/nsgaii/nsgaii_standard_settings_with_real_time_plotting.py @@ -1,19 +1,22 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.lab.visualization import Plot, InteractivePlot -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.lab.visualization import InteractivePlot, Plot +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 from jmetal.util.observer import ProgressBarObserver, VisualizerObserver -from jmetal.util.solution import read_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations """ Program to configure and run the NSGA-II algorithm configured with standard settings. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -22,7 +25,7 @@ offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.observable.register(observer=ProgressBarObserver(max=max_evaluations)) @@ -32,17 +35,25 @@ front = algorithm.get_result() # Plot front - plot_front = Plot(title='Pareto front approximation. Problem: ' + problem.get_name(), reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = Plot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Plot interactive front - plot_front = InteractivePlot(title='Pareto front approximation. Problem: ' + problem.get_name(), reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = InteractivePlot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) \ No newline at end of file + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_steady_state.py b/examples/multiobjective/nsgaii/nsgaii_steady_state.py index 2101c506..3bc62fac 100644 --- a/examples/multiobjective/nsgaii/nsgaii_steady_state.py +++ b/examples/multiobjective/nsgaii/nsgaii_steady_state.py @@ -1,17 +1,21 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 -from jmetal.util.solution import get_non_dominated_solutions, read_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.util.solution import ( + get_non_dominated_solutions, + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations """ Program to configure and run a steady-state version of the NSGA-II algorithm (configured with standard settings). """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -20,17 +24,16 @@ offspring_population_size=1, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = get_non_dominated_solutions(algorithm.get_result()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/nsgaii_steady_state_with_real_time_plotting.py b/examples/multiobjective/nsgaii/nsgaii_steady_state_with_real_time_plotting.py index 17304b10..57f10a0a 100644 --- a/examples/multiobjective/nsgaii/nsgaii_steady_state_with_real_time_plotting.py +++ b/examples/multiobjective/nsgaii/nsgaii_steady_state_with_real_time_plotting.py @@ -1,10 +1,13 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII from jmetal.lab.visualization import InteractivePlot, Plot -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 from jmetal.util.observer import ProgressBarObserver, VisualizerObserver -from jmetal.util.solution import read_solutions, print_function_values_to_file, \ - print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations """ @@ -12,9 +15,9 @@ update frequency is set to 100 evaluations. """ -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 25000 algorithm = NSGAII( @@ -23,32 +26,37 @@ offspring_population_size=1, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.observable.register(observer=ProgressBarObserver(max=max_evaluations)) algorithm.observable.register( - observer=VisualizerObserver(reference_front=problem.reference_front, display_frequency=100)) + observer=VisualizerObserver(reference_front=problem.reference_front, display_frequency=100) + ) algorithm.run() front = algorithm.get_result() # Plot front - plot_front = Plot(title='Pareto front approximation. Problem: ' + problem.get_name(), - reference_front=problem.reference_front, - axis_labels=problem.obj_labels) + plot_front = Plot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Plot interactive front - plot_front = InteractivePlot(title='Pareto front approximation. Problem: ' + problem.get_name(), - reference_front=problem.reference_front, - axis_labels=problem.obj_labels) + plot_front = InteractivePlot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.' + algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaii/parallel_nsgaii_with_multiprocess_evaluator.py b/examples/multiobjective/nsgaii/parallel_nsgaii_with_multiprocess_evaluator.py index eb7f4615..7ac9ff58 100644 --- a/examples/multiobjective/nsgaii/parallel_nsgaii_with_multiprocess_evaluator.py +++ b/examples/multiobjective/nsgaii/parallel_nsgaii_with_multiprocess_evaluator.py @@ -1,11 +1,11 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem.multiobjective.zdt import ZDT1Modified from jmetal.util.evaluator import MultiprocessEvaluator from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() max_evaluations = 100 @@ -17,17 +17,16 @@ offspring_population_size=10, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) - - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/nsgaiii/nsgaiii_dtlz2.py b/examples/multiobjective/nsgaiii/nsgaiii_dtlz2.py index 1ffb9059..18376aeb 100644 --- a/examples/multiobjective/nsgaiii/nsgaiii_dtlz2.py +++ b/examples/multiobjective/nsgaiii/nsgaiii_dtlz2.py @@ -1,12 +1,20 @@ -from jmetal.algorithm.multiobjective.nsgaiii import NSGAIII, UniformReferenceDirectionFactory -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.algorithm.multiobjective.nsgaiii import ( + NSGAIII, + UniformReferenceDirectionFactory, +) +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import DTLZ2 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + get_non_dominated_solutions, + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = DTLZ2() - problem.reference_front = read_solutions(filename='resources/reference_front/DTLZ2.3D.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/DTLZ2.3D.pf") max_evaluations = 25000 @@ -16,16 +24,16 @@ reference_directions=UniformReferenceDirectionFactory(3, n_points=91), mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=30), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() - front = algorithm.get_result() + front = get_non_dominated_solutions(algorithm.get_result()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/omopso/omopso_spark_evaluator.py b/examples/multiobjective/omopso/omopso_spark_evaluator.py index 16b52115..b7de85ab 100644 --- a/examples/multiobjective/omopso/omopso_spark_evaluator.py +++ b/examples/multiobjective/omopso/omopso_spark_evaluator.py @@ -4,12 +4,16 @@ from jmetal.problem.multiobjective.zdt import ZDT1Modified from jmetal.util.archive import CrowdingDistanceArchive from jmetal.util.evaluator import SparkEvaluator -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file, read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") mutation_probability = 1.0 / problem.number_of_variables max_evaluations = 100 @@ -19,8 +23,9 @@ swarm_size=swarm_size, epsilon=0.0075, uniform_mutation=UniformMutation(probability=mutation_probability, perturbation=0.5), - non_uniform_mutation=NonUniformMutation(mutation_probability, perturbation=0.5, - max_iterations=max_evaluations / swarm_size), + non_uniform_mutation=NonUniformMutation( + mutation_probability, perturbation=0.5, max_iterations=max_evaluations / swarm_size + ), leaders=CrowdingDistanceArchive(10), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), swarm_evaluator=SparkEvaluator(), @@ -30,9 +35,9 @@ front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(front, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(front, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(front, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/omopso/omopso_zdt1.py b/examples/multiobjective/omopso/omopso_zdt1.py index 9bf19f5a..98ecaf88 100644 --- a/examples/multiobjective/omopso/omopso_zdt1.py +++ b/examples/multiobjective/omopso/omopso_zdt1.py @@ -3,13 +3,16 @@ from jmetal.operator.mutation import NonUniformMutation from jmetal.problem import ZDT1 from jmetal.util.archive import CrowdingDistanceArchive -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file -from jmetal.util.solution import read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") mutation_probability = 1.0 / problem.number_of_variables max_evaluations = 25000 @@ -20,19 +23,20 @@ swarm_size=swarm_size, epsilon=0.0075, uniform_mutation=UniformMutation(probability=mutation_probability, perturbation=0.5), - non_uniform_mutation=NonUniformMutation(mutation_probability, perturbation=0.5, - max_iterations=int(max_evaluations / swarm_size)), + non_uniform_mutation=NonUniformMutation( + mutation_probability, perturbation=0.5, max_iterations=int(max_evaluations / swarm_size) + ), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/preferences/ggde3_zdt2.py b/examples/multiobjective/preferences/ggde3_zdt2.py index 76ded1e6..2457ee4f 100644 --- a/examples/multiobjective/preferences/ggde3_zdt2.py +++ b/examples/multiobjective/preferences/ggde3_zdt2.py @@ -1,15 +1,18 @@ -from jmetal.util.solutions import read_solutions, print_function_values_to_file, print_variables_to_file -from jmetal.util.solutions.comparator import GDominanceComparator - from jmetal.algorithm.multiobjective.gde3 import GDE3 -from jmetal.lab.visualization import Plot, InteractivePlot +from jmetal.lab.visualization import InteractivePlot, Plot from jmetal.problem import ZDT2 from jmetal.util.observer import VisualizerObserver +from jmetal.util.solutions import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) +from jmetal.util.solutions.comparator import GDominanceComparator from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT2() - problem.reference_front = read_solutions(filename='resources/reference_front/{}.pf'.format(problem.get_name())) + problem.reference_front = read_solutions(filename="resources/reference_front/{}.pf".format(problem.get_name())) max_evaluations = 25000 reference_point = [0.2, 0.5] @@ -20,26 +23,32 @@ cr=0.5, f=0.5, termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=GDominanceComparator(reference_point) + dominance_comparator=GDominanceComparator(reference_point), ) - algorithm.observable.register(observer=VisualizerObserver(reference_front=problem.reference_front, reference_point=reference_point)) + algorithm.observable.register( + observer=VisualizerObserver(reference_front=problem.reference_front, reference_point=reference_point) + ) algorithm.run() front = algorithm.get_result() # Plot front - plot_front = Plot(plot_title='Pareto front approximation', reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = Plot( + plot_title="Pareto front approximation", reference_front=problem.reference_front, axis_labels=problem.obj_labels + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Plot interactive front - plot_front = InteractivePlot(plot_title='Pareto front approximation', reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = InteractivePlot( + plot_title="Pareto front approximation", reference_front=problem.reference_front, axis_labels=problem.obj_labels + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) \ No newline at end of file + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/random_search/random_search_zdt1.py b/examples/multiobjective/random_search/random_search_zdt1.py index 8d7a3106..d6270efe 100644 --- a/examples/multiobjective/random_search/random_search_zdt1.py +++ b/examples/multiobjective/random_search/random_search_zdt1.py @@ -1,25 +1,28 @@ from jmetal.algorithm.multiobjective.random_search import RandomSearch from jmetal.problem import ZDT1 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 1000 algorithm = RandomSearch( - problem=problem, - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + problem=problem, termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/dynamic_smpso.py b/examples/multiobjective/smpso/dynamic_smpso.py index 7cfb6ecf..d90186bb 100644 --- a/examples/multiobjective/smpso/dynamic_smpso.py +++ b/examples/multiobjective/smpso/dynamic_smpso.py @@ -3,14 +3,10 @@ from jmetal.problem.multiobjective.fda import FDA2 from jmetal.util.archive import CrowdingDistanceArchive from jmetal.util.observable import TimeCounter -<<<<<<< HEAD from jmetal.util.observer import PlotFrontToFileObserver, WriteFrontToFileObserver -======= - ->>>>>>> master from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = FDA2() time_counter = TimeCounter(delay=15) @@ -23,10 +19,14 @@ swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) - algorithm.observable.register(observer=PlotFrontToFileObserver('dynamic_front_vis')) - algorithm.observable.register(observer=WriteFrontToFileObserver('dynamic_front')) + algorithm.observable.register(observer=PlotFrontToFileObserver("dynamic_front_vis")) + algorithm.observable.register(observer=WriteFrontToFileObserver("dynamic_front")) algorithm.run() + + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/smpso_schaffer_on_the_fly.py b/examples/multiobjective/smpso/smpso_schaffer_on_the_fly.py index 39a61cc3..9fb8d4d9 100644 --- a/examples/multiobjective/smpso/smpso_schaffer_on_the_fly.py +++ b/examples/multiobjective/smpso/smpso_schaffer_on_the_fly.py @@ -5,7 +5,7 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": # Defining problem Schaffer on the fly def f1(x: [float]): @@ -15,11 +15,7 @@ def f2(x: [float]): return (x[0] - 2) * (x[0] - 2) problem = OnTheFlyFloatProblem() - problem \ - .set_name('Schaffer') \ - .add_variable(-10000.0, 10000.0) \ - .add_function(f1) \ - .add_function(f2) + problem.set_name("Schaffer").add_variable(-10000.0, 10000.0).add_function(f1).add_function(f2) max_evaluations = 25000 @@ -28,16 +24,16 @@ def f2(x: [float]): swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/smpso_spark_evaluator.py b/examples/multiobjective/smpso/smpso_spark_evaluator.py index fd790a2c..41da0db4 100644 --- a/examples/multiobjective/smpso/smpso_spark_evaluator.py +++ b/examples/multiobjective/smpso/smpso_spark_evaluator.py @@ -1,16 +1,18 @@ from examples.multiobjective.zdt1_modified import ZDT1Modified - from jmetal.algorithm.multiobjective.smpso import SMPSO from jmetal.operator import PolynomialMutation from jmetal.util.archive import CrowdingDistanceArchive from jmetal.util.evaluator import SparkEvaluator -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file -from jmetal.util.solution import read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1Modified() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 100 algorithm = SMPSO( @@ -26,9 +28,9 @@ front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(front, 'VAR.'+ algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(front, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(front, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/smpso_srinivas.py b/examples/multiobjective/smpso/smpso_srinivas.py index 5480245e..2f0deb1b 100644 --- a/examples/multiobjective/smpso/smpso_srinivas.py +++ b/examples/multiobjective/smpso/smpso_srinivas.py @@ -2,13 +2,16 @@ from jmetal.operator import PolynomialMutation from jmetal.problem import Srinivas from jmetal.util.archive import CrowdingDistanceArchive -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file -from jmetal.util.solution import read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Srinivas() - problem.reference_front = read_solutions(filename='resources/reference_front/Srinivas.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/Srinivas.pf") max_evaluations = 25000 algorithm = SMPSO( @@ -16,16 +19,16 @@ swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/smpso_srinivas_on_the_fly.py b/examples/multiobjective/smpso/smpso_srinivas_on_the_fly.py index 0083df06..d8176440 100644 --- a/examples/multiobjective/smpso/smpso_srinivas_on_the_fly.py +++ b/examples/multiobjective/smpso/smpso_srinivas_on_the_fly.py @@ -5,32 +5,30 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": # Defining problem Srinivas on the fly def f1(x: [float]): return 2.0 + (x[0] - 2.0) * (x[0] - 2.0) + (x[1] - 1.0) * (x[1] - 1.0) - def f2(x: [float]): return 9.0 * x[0] - (x[1] - 1.0) * (x[1] - 1.0) - def c1(x: [float]): return 1.0 - (x[0] * x[0] + x[1] * x[1]) / 225.0 - def c2(x: [float]): return (3.0 * x[1] - x[0]) / 10.0 - 1.0 - - problem = OnTheFlyFloatProblem() \ - .set_name('Srinivas') \ - .add_variable(-20.0, 20.0) \ - .add_variable(-20.0, 20.0) \ - .add_function(f1) \ - .add_function(f2) \ - .add_constraint(c1) \ + problem = ( + OnTheFlyFloatProblem() + .set_name("Srinivas") + .add_variable(-20.0, 20.0) + .add_variable(-20.0, 20.0) + .add_function(f1) + .add_function(f2) + .add_constraint(c1) .add_constraint(c2) + ) max_evaluations = 25000 algorithm = SMPSO( @@ -38,16 +36,16 @@ def c2(x: [float]): swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/smpso_zdt4.py b/examples/multiobjective/smpso/smpso_zdt4.py index 19c77523..c3171693 100644 --- a/examples/multiobjective/smpso/smpso_zdt4.py +++ b/examples/multiobjective/smpso/smpso_zdt4.py @@ -2,13 +2,16 @@ from jmetal.operator import PolynomialMutation from jmetal.problem import ZDT4 from jmetal.util.archive import CrowdingDistanceArchive -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file -from jmetal.util.solution import read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT4() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT4.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT4.pf") max_evaluations = 25000 algorithm = SMPSO( @@ -16,16 +19,16 @@ swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/smpso/smpsorp_zdt4.py b/examples/multiobjective/smpso/smpsorp_zdt4.py index e2f4c7d0..053ab52c 100644 --- a/examples/multiobjective/smpso/smpsorp_zdt4.py +++ b/examples/multiobjective/smpso/smpsorp_zdt4.py @@ -1,22 +1,23 @@ -from jmetal.lab.visualization import Plot, InteractivePlot -from jmetal.util.observer import ProgressBarObserver, VisualizerObserver -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file, read_solutions - -from jmetal.util.termination_criterion import StoppingByEvaluations - from jmetal.algorithm.multiobjective.smpso import SMPSORP +from jmetal.lab.visualization import InteractivePlot, Plot from jmetal.operator import PolynomialMutation -from jmetal.problem import ZDT4, ZDT1 +from jmetal.problem import ZDT1 from jmetal.util.archive import CrowdingDistanceArchiveWithReferencePoint +from jmetal.util.observer import VisualizerObserver +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) +from jmetal.util.termination_criterion import StoppingByEvaluations - -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") swarm_size = 100 - reference_point = [[0.1, 0.8],[0.6, 0.1]] + reference_point = [[0.1, 0.8], [0.6, 0.1]] archives_with_reference_points = [] for point in reference_point: @@ -31,29 +32,36 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), reference_points=reference_point, leaders=archives_with_reference_points, - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.observable.register( - observer=VisualizerObserver(reference_front=problem.reference_front, reference_point=reference_point)) + observer=VisualizerObserver(reference_front=problem.reference_front, reference_point=reference_point) + ) algorithm.run() front = algorithm.get_result() # Plot front - plot_front = Plot(title='Pareto front approximation. Problem: ' + problem.get_name(), - reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = Plot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Plot interactive front - plot_front = InteractivePlot(title='Pareto front approximation. Problem: ' + problem.get_name(), - reference_front=problem.reference_front, axis_labels=problem.obj_labels) + plot_front = InteractivePlot( + title="Pareto front approximation. Problem: " + problem.get_name(), + reference_front=problem.reference_front, + axis_labels=problem.obj_labels, + ) plot_front.plot(front, label=algorithm.label, filename=algorithm.get_name()) # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.' + algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/spea2/gspea2_zdt1.py b/examples/multiobjective/spea2/gspea2_zdt1.py index d2bd2441..3a5c3bce 100644 --- a/examples/multiobjective/spea2/gspea2_zdt1.py +++ b/examples/multiobjective/spea2/gspea2_zdt1.py @@ -1,13 +1,17 @@ from jmetal.algorithm.multiobjective.spea2 import SPEA2 -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 from jmetal.util.comparator import GDominanceComparator -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file, read_solutions +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") reference_point = [0.4, 0.6] @@ -19,16 +23,16 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=GDominanceComparator(reference_point) + dominance_comparator=GDominanceComparator(reference_point), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/spea2/spea2_dtlz1.py b/examples/multiobjective/spea2/spea2_dtlz1.py index 1f58a3b4..9650d7bb 100644 --- a/examples/multiobjective/spea2/spea2_dtlz1.py +++ b/examples/multiobjective/spea2/spea2_dtlz1.py @@ -1,12 +1,16 @@ from jmetal.algorithm.multiobjective.spea2 import SPEA2 -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import DTLZ2 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = DTLZ2() - problem.reference_front = read_solutions(filename='resources/reference_front/DTLZ2.3D.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/DTLZ2.3D.pf") max_evaluations = 20000 algorithm = SPEA2( @@ -15,16 +19,16 @@ offspring_population_size=20, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.'+ algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/multiobjective/spea2/spea2_zdt1.py b/examples/multiobjective/spea2/spea2_zdt1.py index 1f010bff..24d6ae86 100644 --- a/examples/multiobjective/spea2/spea2_zdt1.py +++ b/examples/multiobjective/spea2/spea2_zdt1.py @@ -1,12 +1,16 @@ from jmetal.algorithm.multiobjective.spea2 import SPEA2 -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem import ZDT1 -from jmetal.util.solution import read_solutions, print_function_values_to_file, print_variables_to_file +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = ZDT1() - problem.reference_front = read_solutions(filename='resources/reference_front/ZDT1.pf') + problem.reference_front = read_solutions(filename="resources/reference_front/ZDT1.pf") max_evaluations = 20000 algorithm = SPEA2( @@ -15,16 +19,16 @@ offspring_population_size=40, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.label) - print_variables_to_file(front, 'VAR.' + algorithm.label) + print_function_values_to_file(front, "FUN." + algorithm.label) + print_variables_to_file(front, "VAR." + algorithm.label) - print(f'Algorithm: ${algorithm.get_name()}') - print(f'Problem: ${problem.get_name()}') - print(f'Computing time: ${algorithm.total_computing_time}') + print(f"Algorithm: {algorithm.get_name()}") + print(f"Problem: {problem.get_name()}") + print(f"Computing time: {algorithm.total_computing_time}") diff --git a/examples/singleobjective/evolution_strategy/evolution_strategy_binary.py b/examples/singleobjective/evolution_strategy/evolution_strategy_binary.py index a6766639..17416f27 100644 --- a/examples/singleobjective/evolution_strategy/evolution_strategy_binary.py +++ b/examples/singleobjective/evolution_strategy/evolution_strategy_binary.py @@ -3,7 +3,7 @@ from jmetal.problem import OneMax from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = OneMax(number_of_bits=512) algorithm = EvolutionStrategy( @@ -12,14 +12,14 @@ lambda_=10, mutation=BitFlipMutation(probability=1.0 / problem.number_of_bits), elitist=True, - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() result = algorithm.get_result() - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Solution: ' + str(result.variables[0])) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm: " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Solution: " + str(result.variables[0])) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/evolution_strategy/evolution_strategy_float.py b/examples/singleobjective/evolution_strategy/evolution_strategy_float.py index 3a1c3833..3e8bb3de 100644 --- a/examples/singleobjective/evolution_strategy/evolution_strategy_float.py +++ b/examples/singleobjective/evolution_strategy/evolution_strategy_float.py @@ -3,7 +3,7 @@ from jmetal.problem import Sphere from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Sphere(number_of_variables=10) algorithm = EvolutionStrategy( @@ -12,14 +12,14 @@ lambda_=10, elitist=True, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables), - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() result = algorithm.get_result() - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Solution: ' + str(result.variables[0])) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm: " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Solution: " + str(result.variables[0])) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/evolution_strategy/evolution_strategy_permutation.py b/examples/singleobjective/evolution_strategy/evolution_strategy_permutation.py new file mode 100644 index 00000000..87586a43 --- /dev/null +++ b/examples/singleobjective/evolution_strategy/evolution_strategy_permutation.py @@ -0,0 +1,27 @@ +from jmetal.algorithm.singleobjective.evolution_strategy import EvolutionStrategy +from jmetal.operator.mutation import PermutationSwapMutation +from jmetal.problem.singleobjective.tsp import TSP +from jmetal.util.termination_criterion import StoppingByTime + +if __name__ == "__main__": + problem = TSP(instance="resources/TSP_instances/kroA100.tsp") + + print(f"Solving TSP problem with {problem.number_of_cities} cities.") + + algorithm = EvolutionStrategy( + problem=problem, + mu=1, + lambda_=10, + mutation=PermutationSwapMutation(1.0 / problem.number_of_cities), + elitist=False, + termination_criterion=StoppingByTime(10), + ) + + algorithm.run() + result = algorithm.get_result() + + print(f"Algorithm: {algorithm.get_name()}") + print(f"Solution: {result.variables}") + print(f"The shortest path length: {result.objectives[0]}") + print(f"Computing time: {algorithm.total_computing_time}") + print(f"Number of evaluations: {algorithm.evaluations}") diff --git a/examples/singleobjective/gde3/gde3_single_objective.py b/examples/singleobjective/gde3/gde3_single_objective.py index 1ecd2743..b30f496e 100644 --- a/examples/singleobjective/gde3/gde3_single_objective.py +++ b/examples/singleobjective/gde3/gde3_single_objective.py @@ -3,24 +3,20 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Rastrigin(10) algorithm = GDE3( - problem=problem, - population_size=100, - cr=0.5, - f=0.5, - termination_criterion=StoppingByEvaluations(50000) + problem=problem, population_size=100, cr=0.5, f=0.5, termination_criterion=StoppingByEvaluations(100000) ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.' + algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(front, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(front, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(front, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm (continuous problem): " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_binary.py b/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_binary.py index d205175a..e19a6869 100644 --- a/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_binary.py +++ b/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_binary.py @@ -1,26 +1,29 @@ from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm -from jmetal.operator import BitFlipMutation, SPXCrossover, BinaryTournamentSelection +from jmetal.operator import BinaryTournamentSelection, BitFlipMutation, SPXCrossover from jmetal.problem import OneMax +from jmetal.util.observer import PrintObjectivesObserver from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': - problem = OneMax(number_of_bits=1024) +if __name__ == "__main__": + problem = OneMax(number_of_bits=512) algorithm = GeneticAlgorithm( problem=problem, - population_size=100, - offspring_population_size=100, + population_size=40, + offspring_population_size=40, mutation=BitFlipMutation(1.0 / problem.number_of_bits), crossover=SPXCrossover(1.0), selection=BinaryTournamentSelection(), - termination_criterion=StoppingByEvaluations(max_evaluations=20000) + termination_criterion=StoppingByEvaluations(max_evaluations=20000), ) + algorithm.observable.register(observer=PrintObjectivesObserver(100)) + algorithm.run() result = algorithm.get_result() - print('Algorithm: {}'.format(algorithm.get_name())) - print('Problem: {}'.format(problem.get_name())) - print('Solution: ' + result.get_binary_string()) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: {}'.format(algorithm.total_computing_time)) + print("Algorithm: {}".format(algorithm.get_name())) + print("Problem: {}".format(problem.get_name())) + print("Solution: " + result.get_binary_string()) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: {}".format(algorithm.total_computing_time)) diff --git a/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_float.py b/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_float.py index e3aff749..54d96508 100644 --- a/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_float.py +++ b/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_float.py @@ -3,24 +3,24 @@ from jmetal.problem.singleobjective.unconstrained import Rastrigin from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Rastrigin(10) algorithm = GeneticAlgorithm( problem=problem, population_size=100, - offspring_population_size=100, + offspring_population_size=1, mutation=PolynomialMutation(1.0 / problem.number_of_variables, 20.0), - crossover=SBXCrossover(0.9, 20.0), + crossover=SBXCrossover(0.9, 5.0), selection=BinaryTournamentSelection(), - termination_criterion=StoppingByEvaluations(max_evaluations=500000) + termination_criterion=StoppingByEvaluations(max_evaluations=100000), ) algorithm.run() result = algorithm.get_result() - print('Algorithm: {}'.format(algorithm.get_name())) - print('Problem: {}'.format(problem.get_name())) - print('Solution: {}'.format(result.variables)) - print('Fitness: {}'.format(result.objectives[0])) - print('Computing time: {}'.format(algorithm.total_computing_time)) + print("Algorithm: {}".format(algorithm.get_name())) + print("Problem: {}".format(problem.get_name())) + print("Solution: {}".format(result.variables)) + print("Fitness: {}".format(result.objectives[0])) + print("Computing time: {}".format(algorithm.total_computing_time)) diff --git a/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_tsp.py b/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_tsp.py index e0b076ee..dc087149 100644 --- a/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_tsp.py +++ b/examples/singleobjective/genetic_algorithm/generational_genetic_algorithm_tsp.py @@ -8,10 +8,10 @@ from jmetal.util.ranking import FastNonDominatedRanking from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': - problem = TSP(instance='resources/TSP_instances/kroA100.tsp') +if __name__ == "__main__": + problem = TSP(instance="resources/TSP_instances/kroA100.tsp") - print('Cities: ', problem.number_of_variables) + print("Cities: ", problem.number_of_variables) algorithm = GeneticAlgorithm( problem=problem, @@ -20,16 +20,16 @@ mutation=PermutationSwapMutation(1.0 / problem.number_of_variables), crossover=PMXCrossover(0.8), selection=BinaryTournamentSelection( - MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()])), - termination_criterion=StoppingByEvaluations(max_evaluations=2500000) + MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) + ), + termination_criterion=StoppingByEvaluations(max_evaluations=2500000), ) algorithm.run() result = algorithm.get_result() - print('Algorithm: {}'.format(algorithm.get_name())) - print('Problem: {}'.format(problem.get_name())) - print('Solution: {}'.format(result.variables)) - print('Fitness: {}'.format(result.objectives[0])) - print('Computing time: {}'.format(algorithm.total_computing_time)) + print("Algorithm: {}".format(algorithm.get_name())) + print("Problem: {}".format(problem.get_name())) + print("Solution: {}".format(result.variables)) + print("Fitness: {}".format(result.objectives[0])) + print("Computing time: {}".format(algorithm.total_computing_time)) diff --git a/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm.py b/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm.py index e2337f19..4d4a49f1 100644 --- a/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm.py +++ b/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm.py @@ -1,25 +1,140 @@ from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm -from jmetal.operator import SPXCrossover, BitFlipMutation, BinaryTournamentSelection +from jmetal.operator import BinaryTournamentSelection, BitFlipMutation, SPXCrossover from jmetal.problem.singleobjective.unconstrained import SubsetSum from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": C = 300500 - W = [2902, 5235, 357, 6058, 4846, 8280, 1295, 181, 3264, - 7285, 8806, 2344, 9203, 6806, 1511, 2172, 843, 4697, - 3348, 1866, 5800, 4094, 2751, 64, 7181, 9167, 5579, - 9461, 3393, 4602, 1796, 8174, 1691, 8854, 5902, 4864, - 5488, 1129, 1111, 7597, 5406, 2134, 7280, 6465, 4084, - 8564, 2593, 9954, 4731, 1347, 8984, 5057, 3429, 7635, - 1323, 1146, 5192, 6547, 343, 7584, 3765, 8660, 9318, - 5098, 5185, 9253, 4495, 892, 5080, 5297, 9275, 7515, - 9729, 6200, 2138, 5480, 860, 8295, 8327, 9629, 4212, - 3087, 5276, 9250, 1835, 9241, 1790, 1947, 8146, 8328, - 973, 1255, 9733, 4314, 6912, 8007, 8911, 6802, 5102, - 5451, 1026, 8029, 6628, 8121, 5509, 3603, 6094, 4447, - 683, 6996, 3304, 3130, 2314, 7788, 8689, 3253, 5920, - 3660, 2489, 8153, 2822, 6132, 7684, 3032, 9949, 59, - 6669, 6334] + W = [ + 2902, + 5235, + 357, + 6058, + 4846, + 8280, + 1295, + 181, + 3264, + 7285, + 8806, + 2344, + 9203, + 6806, + 1511, + 2172, + 843, + 4697, + 3348, + 1866, + 5800, + 4094, + 2751, + 64, + 7181, + 9167, + 5579, + 9461, + 3393, + 4602, + 1796, + 8174, + 1691, + 8854, + 5902, + 4864, + 5488, + 1129, + 1111, + 7597, + 5406, + 2134, + 7280, + 6465, + 4084, + 8564, + 2593, + 9954, + 4731, + 1347, + 8984, + 5057, + 3429, + 7635, + 1323, + 1146, + 5192, + 6547, + 343, + 7584, + 3765, + 8660, + 9318, + 5098, + 5185, + 9253, + 4495, + 892, + 5080, + 5297, + 9275, + 7515, + 9729, + 6200, + 2138, + 5480, + 860, + 8295, + 8327, + 9629, + 4212, + 3087, + 5276, + 9250, + 1835, + 9241, + 1790, + 1947, + 8146, + 8328, + 973, + 1255, + 9733, + 4314, + 6912, + 8007, + 8911, + 6802, + 5102, + 5451, + 1026, + 8029, + 6628, + 8121, + 5509, + 3603, + 6094, + 4447, + 683, + 6996, + 3304, + 3130, + 2314, + 7788, + 8689, + 3253, + 5920, + 3660, + 2489, + 8153, + 2822, + 6132, + 7684, + 3032, + 9949, + 59, + 6669, + 6334, + ] problem = SubsetSum(C, W) @@ -30,14 +145,14 @@ mutation=BitFlipMutation(probability=0.1), crossover=SPXCrossover(probability=0.8), selection=BinaryTournamentSelection(), - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() subset = algorithm.get_result() - print('Algorithm: {}'.format(algorithm.get_name())) - print('Problem: {}'.format(problem.get_name())) - print('Solution: {}'.format(subset.variables)) - print('Fitness: {}'.format(subset.objectives[0])) - print('Computing time: {}'.format(algorithm.total_computing_time)) + print("Algorithm: {}".format(algorithm.get_name())) + print("Problem: {}".format(problem.get_name())) + print("Solution: {}".format(subset.variables)) + print("Fitness: {}".format(subset.objectives[0])) + print("Computing time: {}".format(algorithm.total_computing_time)) diff --git a/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm_with_knapsack_problem.py b/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm_with_knapsack_problem.py index a8dd133d..d2b2ae12 100644 --- a/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm_with_knapsack_problem.py +++ b/examples/singleobjective/genetic_algorithm/steady_state_genetic_algorithm_with_knapsack_problem.py @@ -1,10 +1,10 @@ from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm -from jmetal.operator import SPXCrossover, BitFlipMutation, BinaryTournamentSelection +from jmetal.operator import BinaryTournamentSelection, BitFlipMutation, SPXCrossover from jmetal.problem.singleobjective.knapsack import Knapsack from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': - problem = Knapsack(from_file=True, filename='resources/Knapsack_instances/KnapsackInstance_50_0_0.kp') +if __name__ == "__main__": + problem = Knapsack(from_file=True, filename="resources/Knapsack_instances/KnapsackInstance_50_0_0.kp") algorithm = GeneticAlgorithm( problem=problem, @@ -13,15 +13,15 @@ mutation=BitFlipMutation(probability=0.1), crossover=SPXCrossover(probability=0.8), selection=BinaryTournamentSelection(), - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() subset = algorithm.get_result() - print('Algorithm: {}'.format(algorithm.get_name())) - print('Problem: {}'.format(problem.get_name())) - print('Solution: {}'.format(subset.variables)) - print('Fitness: {}'.format(-subset.objectives[0])) - print('Computing time: {}'.format(algorithm.total_computing_time)) + print("Algorithm: {}".format(algorithm.get_name())) + print("Problem: {}".format(problem.get_name())) + print("Solution: {}".format(subset.variables)) + print("Fitness: {}".format(-subset.objectives[0])) + print("Computing time: {}".format(algorithm.total_computing_time)) print(f"Problem Maximum Capacity: {problem.capacity}") diff --git a/examples/singleobjective/local_search/local_search_binary.py b/examples/singleobjective/local_search/local_search_binary.py index cb4ec22f..72e2000d 100644 --- a/examples/singleobjective/local_search/local_search_binary.py +++ b/examples/singleobjective/local_search/local_search_binary.py @@ -1,28 +1,31 @@ from jmetal.algorithm.singleobjective.local_search import LocalSearch from jmetal.operator import BitFlipMutation from jmetal.problem import OneMax +from jmetal.util.observer import PrintObjectivesObserver from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': - problem = OneMax(number_of_bits=1024) +if __name__ == "__main__": + problem = OneMax(number_of_bits=512) max_evaluations = 10000 algorithm = LocalSearch( problem=problem, mutation=BitFlipMutation(probability=1.0 / problem.number_of_bits), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) + algorithm.observable.register(observer=PrintObjectivesObserver(100)) + algorithm.run() result = algorithm.get_result() # Save results to file - print_function_values_to_file(result, 'FUN.'+ algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(result, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(result, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(result, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Solution: ' + result.get_binary_string()) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm: " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Solution: " + result.get_binary_string()) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/local_search/local_search_float.py b/examples/singleobjective/local_search/local_search_float.py index 73db5a24..f658cb37 100644 --- a/examples/singleobjective/local_search/local_search_float.py +++ b/examples/singleobjective/local_search/local_search_float.py @@ -1,29 +1,29 @@ from jmetal.algorithm.singleobjective.local_search import LocalSearch from jmetal.operator import PolynomialMutation -from jmetal.problem.singleobjective.unconstrained import Sphere +from jmetal.problem.singleobjective.unconstrained import Rastrigin from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': - problem = Sphere(10) +if __name__ == "__main__": + problem = Rastrigin(10) - max_evaluations = 1000000 + max_evaluations = 100000 algorithm = LocalSearch( problem=problem, mutation=PolynomialMutation(1.0 / problem.number_of_variables, 20.0), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() result = algorithm.get_result() # Save results to file - print_function_values_to_file(result, 'FUN.'+ algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(result, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(result, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(result, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Solution: ' + str(result.variables)) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm: " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Solution: " + str(result.variables)) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/nsgaii/nsgaii_single_objective_binary.py b/examples/singleobjective/nsgaii/nsgaii_single_objective_binary.py index 587ba1ce..06502129 100644 --- a/examples/singleobjective/nsgaii/nsgaii_single_objective_binary.py +++ b/examples/singleobjective/nsgaii/nsgaii_single_objective_binary.py @@ -5,7 +5,7 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": binary_string_length = 512 problem = OneMax(binary_string_length) @@ -18,16 +18,16 @@ mutation=BitFlipMutation(probability=1.0 / binary_string_length), crossover=SPXCrossover(probability=1.0), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=DominanceComparator() + dominance_comparator=DominanceComparator(), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.'+ algorithm.get_name()+"-"+problem.get_name()) - print_variables_to_file(front, 'VAR.' + algorithm.get_name()+"-"+problem.get_name()) + print_function_values_to_file(front, "FUN." + algorithm.get_name() + "-" + problem.get_name()) + print_variables_to_file(front, "VAR." + algorithm.get_name() + "-" + problem.get_name()) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm (continuous problem): " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/nsgaii/nsgaii_single_objective_float.py b/examples/singleobjective/nsgaii/nsgaii_single_objective_float.py index 3679a6d4..25ce2386 100644 --- a/examples/singleobjective/nsgaii/nsgaii_single_objective_float.py +++ b/examples/singleobjective/nsgaii/nsgaii_single_objective_float.py @@ -1,11 +1,11 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII -from jmetal.operator import SBXCrossover, PolynomialMutation +from jmetal.operator import PolynomialMutation, SBXCrossover from jmetal.problem.singleobjective.unconstrained import Rastrigin from jmetal.util.comparator import DominanceComparator from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Rastrigin(10) max_evaluations = 50000 @@ -16,16 +16,16 @@ mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20.0), crossover=SBXCrossover(probability=0.9, distribution_index=20.0), termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), - dominance_comparator=DominanceComparator() + dominance_comparator=DominanceComparator(), ) algorithm.run() front = algorithm.get_result() # Save results to file - print_function_values_to_file(front, 'FUN.'+ algorithm.get_name()+"-"+problem.get_name()) - print_variables_to_file(front, 'VAR.' + algorithm.get_name()+"-"+problem.get_name()) + print_function_values_to_file(front, "FUN." + algorithm.get_name() + "-" + problem.get_name()) + print_variables_to_file(front, "VAR." + algorithm.get_name() + "-" + problem.get_name()) - print('Algorithm (continuous problem): ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm (continuous problem): " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/simulated_annealing/simulated_annealing_binary.py b/examples/singleobjective/simulated_annealing/simulated_annealing_binary.py index 7320448e..1f89b618 100644 --- a/examples/singleobjective/simulated_annealing/simulated_annealing_binary.py +++ b/examples/singleobjective/simulated_annealing/simulated_annealing_binary.py @@ -4,26 +4,26 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': - problem = OneMax(number_of_bits=1024) +if __name__ == "__main__": + problem = OneMax(number_of_bits=512) - max_evaluations = 20000 + max_evaluations = 10000 algorithm = SimulatedAnnealing( problem=problem, mutation=BitFlipMutation(probability=1.0 / problem.number_of_bits), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() result = algorithm.get_result() # Save results to file - print_function_values_to_file(result, 'FUN.'+ algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(result, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(result, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(result, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Solution: ' + result.get_binary_string()) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm: " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Solution: " + result.get_binary_string()) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/simulated_annealing/simulated_annealing_float.py b/examples/singleobjective/simulated_annealing/simulated_annealing_float.py index 23b40432..2383bc2a 100644 --- a/examples/singleobjective/simulated_annealing/simulated_annealing_float.py +++ b/examples/singleobjective/simulated_annealing/simulated_annealing_float.py @@ -4,26 +4,26 @@ from jmetal.util.solution import print_function_values_to_file, print_variables_to_file from jmetal.util.termination_criterion import StoppingByEvaluations -if __name__ == '__main__': +if __name__ == "__main__": problem = Rastrigin(10) - max_evaluations = 250000 + max_evaluations = 100000 algorithm = SimulatedAnnealing( problem=problem, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20.0), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() result = algorithm.get_result() # Save results to file - print_function_values_to_file(result, 'FUN.'+ algorithm.get_name() + "." + problem.get_name()) - print_variables_to_file(result, 'VAR.' + algorithm.get_name() + "." + problem.get_name()) + print_function_values_to_file(result, "FUN." + algorithm.get_name() + "." + problem.get_name()) + print_variables_to_file(result, "VAR." + algorithm.get_name() + "." + problem.get_name()) - print('Algorithm: ' + algorithm.get_name()) - print('Problem: ' + problem.get_name()) - print('Solution: ' + str(result.variables[0])) - print('Fitness: ' + str(result.objectives[0])) - print('Computing time: ' + str(algorithm.total_computing_time)) + print("Algorithm: " + algorithm.get_name()) + print("Problem: " + problem.get_name()) + print("Solution: " + str(result.variables[0])) + print("Fitness: " + str(result.objectives[0])) + print("Computing time: " + str(algorithm.total_computing_time)) diff --git a/examples/singleobjective/simulated_annealing/simulated_annealing_permutation.py b/examples/singleobjective/simulated_annealing/simulated_annealing_permutation.py new file mode 100644 index 00000000..f9349ffe --- /dev/null +++ b/examples/singleobjective/simulated_annealing/simulated_annealing_permutation.py @@ -0,0 +1,24 @@ +from jmetal.algorithm.singleobjective.simulated_annealing import SimulatedAnnealing +from jmetal.operator import ScrambleMutation +from jmetal.problem import TSP +from jmetal.util.termination_criterion import StoppingByTime + +if __name__ == "__main__": + problem = TSP(instance="resources/TSP_instances/kroA100.tsp") + + print(f"Solving TSP problem with {problem.number_of_cities} cities.") + + algorithm = SimulatedAnnealing( + problem=problem, + mutation=ScrambleMutation(probability=1.0 / problem.number_of_cities), + termination_criterion=StoppingByTime(max_seconds=10), + ) + + algorithm.run() + result = algorithm.get_result() + + print(f"Algorithm: {algorithm.get_name()}") + print(f"Solution: {result.variables}") + print(f"The shortest path length: {str(result.objectives[0])}") + print(f"Computing time: {str(algorithm.total_computing_time)}") + print(f"Problem evaluations: {str(algorithm.evaluations)}") diff --git a/jmetal/__init__.py b/jmetal/__init__.py index 70baa3db..14edc3c1 100644 --- a/jmetal/__init__.py +++ b/jmetal/__init__.py @@ -1,25 +1,7 @@ -import logging +from jmetal import algorithm, core, operator, problem +from jmetal.logger import configure_logging -from jmetal import algorithm -from jmetal import core -from jmetal import operator -from jmetal import problem +configure_logging() -__all__ = ['core', 'algorithm', 'operator', 'problem'] - -logger = logging.getLogger('jmetal') -logger.setLevel(logging.INFO) - -# create a file handler -file_handler = logging.FileHandler('jmetalpy.log', delay=True) -file_handler.setLevel(logging.INFO) -stream_handler = logging.StreamHandler() - -# create a logging format -formatter = logging.Formatter('%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s') -file_handler.setFormatter(formatter) -stream_handler.setFormatter(formatter) - -# add the handlers to the logger -logger.addHandler(file_handler) -logger.addHandler(stream_handler) +__all__ = ["core", "algorithm", "operator", "problem"] +__version__ = "1.5.7" diff --git a/jmetal/algorithm/multiobjective/gde3.py b/jmetal/algorithm/multiobjective/gde3.py index 7dd1da69..3a2ed64a 100644 --- a/jmetal/algorithm/multiobjective/gde3.py +++ b/jmetal/algorithm/multiobjective/gde3.py @@ -1,36 +1,39 @@ -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.config import store -from jmetal.core.algorithm import EvolutionaryAlgorithm, DynamicAlgorithm -from jmetal.core.problem import Problem, DynamicProblem +from jmetal.core.algorithm import DynamicAlgorithm, EvolutionaryAlgorithm +from jmetal.core.problem import DynamicProblem, Problem from jmetal.core.solution import FloatSolution -from jmetal.operator import DifferentialEvolutionCrossover, RankingAndCrowdingDistanceSelection +from jmetal.operator import ( + DifferentialEvolutionCrossover, + RankingAndCrowdingDistanceSelection, +) from jmetal.operator.selection import DifferentialEvolutionSelection from jmetal.util.comparator import Comparator, DominanceComparator from jmetal.util.evaluator import Evaluator from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') +S = TypeVar("S") R = List[S] class GDE3(EvolutionaryAlgorithm[FloatSolution, FloatSolution]): - - def __init__(self, - problem: Problem, - population_size: int, - cr: float, - f: float, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - k: float = 0.5, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = store.default_comparator): + def __init__( + self, + problem: Problem, + population_size: int, + cr: float, + f: float, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + k: float = 0.5, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = store.default_comparator, + ): super(GDE3, self).__init__( - problem=problem, - population_size=population_size, - offspring_population_size=population_size) + problem=problem, population_size=population_size, offspring_population_size=population_size + ) self.dominance_comparator = dominance_comparator self.selection_operator = DifferentialEvolutionSelection() self.crossover_operator = DifferentialEvolutionCrossover(cr, f, k) @@ -57,7 +60,7 @@ def reproduction(self, mating_pool: List[S]) -> List[S]: for solution in self.solutions: self.crossover_operator.current_individual = solution - parents = mating_pool[first_parent_index:first_parent_index + 3] + parents = mating_pool[first_parent_index : first_parent_index + 3] first_parent_index += 3 offspring_population.append(self.crossover_operator.execute(parents)[0]) @@ -96,24 +99,33 @@ def get_result(self) -> List[FloatSolution]: return self.solutions def get_name(self) -> str: - return 'GDE3' + return "GDE3" class DynamicGDE3(GDE3, DynamicAlgorithm): - - def __init__(self, - problem: DynamicProblem, - population_size: int, - cr: float, - f: float, - termination_criterion: TerminationCriterion, - k: float = 0.5, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = DominanceComparator()): + def __init__( + self, + problem: DynamicProblem, + population_size: int, + cr: float, + f: float, + termination_criterion: TerminationCriterion, + k: float = 0.5, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = DominanceComparator(), + ): super(DynamicGDE3, self).__init__( - problem, population_size, cr, f, termination_criterion, k, - population_generator, population_evaluator, dominance_comparator) + problem, + population_size, + cr, + f, + termination_criterion, + k, + population_generator, + population_evaluator, + dominance_comparator, + ) self.completed_iterations = 0 diff --git a/jmetal/algorithm/multiobjective/hype.py b/jmetal/algorithm/multiobjective/hype.py index 4fc997ec..fb732904 100644 --- a/jmetal/algorithm/multiobjective/hype.py +++ b/jmetal/algorithm/multiobjective/hype.py @@ -1,36 +1,36 @@ -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm from jmetal.config import store -from jmetal.core.operator import Mutation, Crossover +from jmetal.core.operator import Crossover, Mutation from jmetal.core.problem import Problem from jmetal.core.solution import Solution from jmetal.operator import BinaryTournamentSelection from jmetal.operator.selection import RankingAndFitnessSelection -from jmetal.util.comparator import Comparator -from jmetal.util.comparator import SolutionAttributeComparator +from jmetal.util.comparator import Comparator, SolutionAttributeComparator from jmetal.util.evaluator import Evaluator from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") class HYPE(GeneticAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - reference_point: Solution, - population_size: int, - offspring_population_size: int, - mutation: Mutation, - crossover: Crossover, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = store.default_comparator): - """ This is an implementation of the Hypervolume Estimation Algorithm for Multi-objective Optimization + def __init__( + self, + problem: Problem, + reference_point: Solution, + population_size: int, + offspring_population_size: int, + mutation: Mutation, + crossover: Crossover, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = store.default_comparator, + ): + """This is an implementation of the Hypervolume Estimation Algorithm for Multi-objective Optimization proposed in: * J. Bader and E. Zitzler. HypE: An Algorithm for Fast Hypervolume-Based Many-Objective @@ -49,10 +49,11 @@ def __init__(self, """ selection = BinaryTournamentSelection( - comparator=SolutionAttributeComparator(key='fitness', lowest_is_best=False)) - self.ranking_fitness = RankingAndFitnessSelection(population_size, - dominance_comparator=dominance_comparator, - reference_point=reference_point) + comparator=SolutionAttributeComparator(key="fitness", lowest_is_best=False) + ) + self.ranking_fitness = RankingAndFitnessSelection( + population_size, dominance_comparator=dominance_comparator, reference_point=reference_point + ) self.reference_point = reference_point self.dominance_comparator = dominance_comparator @@ -65,13 +66,14 @@ def __init__(self, selection=selection, termination_criterion=termination_criterion, population_evaluator=population_evaluator, - population_generator=population_generator + population_generator=population_generator, ) def evaluate(self, population: List[S]): population = self.population_evaluator.evaluate(population, self.problem) - population = self.ranking_fitness.compute_hypervol_fitness_values(population, self.reference_point, - len(population)) + population = self.ranking_fitness.compute_hypervol_fitness_values( + population, self.reference_point, len(population) + ) return population def replacement(self, population: List[S], offspring_population: List[S]) -> List[List[S]]: @@ -82,4 +84,4 @@ def get_result(self) -> R: return self.solutions def get_name(self) -> str: - return 'HYPE' + return "HYPE" diff --git a/jmetal/algorithm/multiobjective/ibea.py b/jmetal/algorithm/multiobjective/ibea.py index 12ca0d30..818abd9a 100644 --- a/jmetal/algorithm/multiobjective/ibea.py +++ b/jmetal/algorithm/multiobjective/ibea.py @@ -1,10 +1,10 @@ -from typing import TypeVar, List +from typing import List, TypeVar import numpy as np from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm from jmetal.config import store -from jmetal.core.operator import Mutation, Crossover +from jmetal.core.operator import Crossover, Mutation from jmetal.core.problem import Problem from jmetal.core.quality_indicator import EpsilonIndicator from jmetal.operator import BinaryTournamentSelection @@ -13,23 +13,24 @@ from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") class IBEA(GeneticAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - population_size: int, - offspring_population_size: int, - mutation: Mutation, - crossover: Crossover, - kappa: float, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator): - """ Epsilon IBEA implementation as described in + def __init__( + self, + problem: Problem, + population_size: int, + offspring_population_size: int, + mutation: Mutation, + crossover: Crossover, + kappa: float, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + ): + """Epsilon IBEA implementation as described in * Zitzler, Eckart, and Simon Künzli. "Indicator-based selection in multiobjective search." In International Conference on Parallel Problem Solving from Nature, pp. 832-842. Springer, @@ -50,7 +51,8 @@ def __init__(self, """ selection = BinaryTournamentSelection( - comparator=SolutionAttributeComparator(key='fitness', lowest_is_best=False)) + comparator=SolutionAttributeComparator(key="fitness", lowest_is_best=False) + ) self.kappa = kappa super(IBEA, self).__init__( @@ -62,17 +64,18 @@ def __init__(self, selection=selection, termination_criterion=termination_criterion, population_evaluator=population_evaluator, - population_generator=population_generator + population_generator=population_generator, ) def compute_fitness_values(self, population: List[S], kappa: float) -> List[S]: for i in range(len(population)): - population[i].attributes['fitness'] = 0 + population[i].attributes["fitness"] = 0 for j in range(len(population)): if j != i: - population[i].attributes['fitness'] += -np.exp( - -EpsilonIndicator([population[i].objectives]).compute([population[j].objectives]) / self.kappa) + population[i].attributes["fitness"] += -np.exp( + -EpsilonIndicator([population[i].objectives]).compute([population[j].objectives]) / self.kappa + ) return population def create_initial_solutions(self) -> List[S]: @@ -87,12 +90,16 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis join_population = self.compute_fitness_values(join_population, self.kappa) while join_population_size > self.population_size: - current_fitnesses = [individual.attributes['fitness'] for individual in join_population] + current_fitnesses = [individual.attributes["fitness"] for individual in join_population] index_worst = current_fitnesses.index(min(current_fitnesses)) for i in range(join_population_size): - join_population[i].attributes['fitness'] += np.exp( - - EpsilonIndicator([join_population[i].objectives]).compute([join_population[index_worst].objectives]) / self.kappa) + join_population[i].attributes["fitness"] += np.exp( + -EpsilonIndicator([join_population[i].objectives]).compute( + [join_population[index_worst].objectives] + ) + / self.kappa + ) join_population.pop(index_worst) join_population_size = join_population_size - 1 @@ -103,4 +110,4 @@ def get_result(self) -> R: return self.solutions def get_name(self) -> str: - return 'Epsilon-IBEA' + return "Epsilon-IBEA" diff --git a/jmetal/algorithm/multiobjective/mocell.py b/jmetal/algorithm/multiobjective/mocell.py index fd6c282f..cb19458a 100644 --- a/jmetal/algorithm/multiobjective/mocell.py +++ b/jmetal/algorithm/multiobjective/mocell.py @@ -1,10 +1,10 @@ import copy from functools import cmp_to_key -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm from jmetal.config import store -from jmetal.core.operator import Mutation, Crossover, Selection +from jmetal.core.operator import Crossover, Mutation, Selection from jmetal.core.problem import Problem from jmetal.operator import BinaryTournamentSelection from jmetal.util.archive import BoundedArchive @@ -16,8 +16,8 @@ from jmetal.util.ranking import FastNonDominatedRanking, Ranking from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: MOCell @@ -28,21 +28,22 @@ class MOCell(GeneticAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - population_size: int, - neighborhood: Neighborhood, - archive: BoundedArchive, - mutation: Mutation, - crossover: Crossover, - selection: Selection = BinaryTournamentSelection( - MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()])), - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = store.default_comparator): + def __init__( + self, + problem: Problem, + population_size: int, + neighborhood: Neighborhood, + archive: BoundedArchive, + mutation: Mutation, + crossover: Crossover, + selection: Selection = BinaryTournamentSelection( + MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) + ), + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = store.default_comparator, + ): """ MOCEll implementation as described in: @@ -61,7 +62,7 @@ def __init__(self, selection=selection, termination_criterion=termination_criterion, population_evaluator=population_evaluator, - population_generator=population_generator + population_generator=population_generator, ) self.dominance_comparator = dominance_comparator self.neighborhood = neighborhood @@ -69,8 +70,7 @@ def __init__(self, self.current_individual = 0 self.current_neighbors = [] - self.comparator = MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()]) + self.comparator = MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) def init_progress(self) -> None: super().init_progress() @@ -99,10 +99,10 @@ def reproduction(self, mating_population: List[S]) -> List[S]: number_of_parents_to_combine = self.crossover_operator.get_number_of_parents() if len(mating_population) % number_of_parents_to_combine != 0: - raise Exception('Wrong number of parents') + raise Exception("Wrong number of parents") offspring_population = self.crossover_operator.execute(mating_population) - self.mutation_operator.execute(offspring_population[0]) + offspring_population[0] = self.mutation_operator.execute(offspring_population[0]) return [offspring_population[0]] @@ -111,7 +111,7 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis if result == 1: # the offspring individual dominates the current one population[self.current_individual] = offspring_population[0] - self.archive.add(offspring_population[0]) + self.archive.add(copy.deepcopy(offspring_population[0])) elif result == 0: # the offspring and current individuals are non-dominated new_individual = offspring_population[0] @@ -127,7 +127,7 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis self.current_neighbors.sort(key=cmp_to_key(self.comparator.compare)) worst_solution = self.current_neighbors[-1] - self.archive.add(new_individual) + self.archive.add(copy.deepcopy(new_individual)) if worst_solution != new_individual: population[self.current_individual] = new_individual @@ -137,4 +137,4 @@ def get_result(self) -> R: return self.archive.solution_list def get_name(self) -> str: - return 'MOCell' + return "MOCell" diff --git a/jmetal/algorithm/multiobjective/moead.py b/jmetal/algorithm/multiobjective/moead.py index c2e39669..5fbd6328 100644 --- a/jmetal/algorithm/multiobjective/moead.py +++ b/jmetal/algorithm/multiobjective/moead.py @@ -1,7 +1,7 @@ import copy import random from math import ceil -from typing import TypeVar, List, Generator +from typing import Generator, List, TypeVar import numpy as np @@ -11,33 +11,40 @@ from jmetal.core.problem import Problem from jmetal.operator import DifferentialEvolutionCrossover, NaryRandomSolutionSelection from jmetal.util.aggregative_function import AggregativeFunction -from jmetal.util.constraint_handling import feasibility_ratio, \ - overall_constraint_violation_degree, is_feasible +from jmetal.util.constraint_handling import ( + feasibility_ratio, + is_feasible, + overall_constraint_violation_degree, +) from jmetal.util.density_estimator import CrowdingDistance from jmetal.util.evaluator import Evaluator from jmetal.util.neighborhood import WeightVectorNeighborhood from jmetal.util.ranking import FastNonDominatedRanking -from jmetal.util.termination_criterion import TerminationCriterion, StoppingByEvaluations +from jmetal.util.termination_criterion import ( + StoppingByEvaluations, + TerminationCriterion, +) -S = TypeVar('S') +S = TypeVar("S") R = List[S] class MOEAD(GeneticAlgorithm): - - def __init__(self, - problem: Problem, - population_size: int, - mutation: Mutation, - crossover: DifferentialEvolutionCrossover, - aggregative_function: AggregativeFunction, - neighbourhood_selection_probability: float, - max_number_of_replaced_solutions: int, - neighbor_size: int, - weight_files_path: str, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator): + def __init__( + self, + problem: Problem, + population_size: int, + mutation: Mutation, + crossover: DifferentialEvolutionCrossover, + aggregative_function: AggregativeFunction, + neighbourhood_selection_probability: float, + max_number_of_replaced_solutions: int, + neighbor_size: int, + weight_files_path: str, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + ): """ :param max_number_of_replaced_solutions: (eta in Zhang & Li paper). :param neighbourhood_selection_probability: Probability of mating with a solution in the neighborhood rather @@ -52,7 +59,7 @@ def __init__(self, selection=NaryRandomSolutionSelection(2), population_evaluator=population_evaluator, population_generator=population_generator, - termination_criterion=termination_criterion + termination_criterion=termination_criterion, ) self.max_number_of_replaced_solutions = max_number_of_replaced_solutions self.fitness_function = aggregative_function @@ -60,7 +67,7 @@ def __init__(self, number_of_weight_vectors=population_size, neighborhood_size=neighbor_size, weight_vector_size=problem.number_of_objectives, - weights_path=weight_files_path + weights_path=weight_files_path, ) self.neighbourhood_selection_probability = neighbourhood_selection_probability self.permutation = None @@ -81,7 +88,7 @@ def selection(self, population: List[S]): self.current_subproblem = self.permutation.get_next_value() self.neighbor_type = self.choose_neighbor_type() - if self.neighbor_type == 'NEIGHBOR': + if self.neighbor_type == "NEIGHBOR": neighbors = self.neighbourhood.get_neighbors(self.current_subproblem, population) mating_population = self.selection_operator.execute(neighbors) else: @@ -128,7 +135,7 @@ def update_current_subproblem_neighborhood(self, new_solution, population): return population def generate_permutation_of_neighbors(self, subproblem_id): - if self.neighbor_type == 'NEIGHBOR': + if self.neighbor_type == "NEIGHBOR": neighbors = self.neighbourhood.get_neighborhood()[subproblem_id] permuted_array = copy.deepcopy(neighbors.tolist()) else: @@ -140,30 +147,49 @@ def choose_neighbor_type(self): rnd = random.random() if rnd < self.neighbourhood_selection_probability: - neighbor_type = 'NEIGHBOR' + neighbor_type = "NEIGHBOR" else: - neighbor_type = 'POPULATION' + neighbor_type = "POPULATION" return neighbor_type def get_name(self): - return 'MOEAD' + return "MOEAD" def get_result(self): return self.solutions class MOEAD_DRA(MOEAD): - def __init__(self, problem, population_size, mutation, crossover, aggregative_function, - neighbourhood_selection_probability, max_number_of_replaced_solutions, neighbor_size, - weight_files_path, termination_criterion=store.default_termination_criteria, - population_generator=store.default_generator, population_evaluator=store.default_evaluator): - super(MOEAD_DRA, self).__init__(problem, population_size, mutation, crossover, aggregative_function, - neighbourhood_selection_probability, max_number_of_replaced_solutions, - neighbor_size, weight_files_path, - termination_criterion=termination_criterion, - population_generator=population_generator, - population_evaluator=population_evaluator) + def __init__( + self, + problem, + population_size, + mutation, + crossover, + aggregative_function, + neighbourhood_selection_probability, + max_number_of_replaced_solutions, + neighbor_size, + weight_files_path, + termination_criterion=store.default_termination_criteria, + population_generator=store.default_generator, + population_evaluator=store.default_evaluator, + ): + super(MOEAD_DRA, self).__init__( + problem, + population_size, + mutation, + crossover, + aggregative_function, + neighbourhood_selection_probability, + max_number_of_replaced_solutions, + neighbor_size, + weight_files_path, + termination_criterion=termination_criterion, + population_generator=population_generator, + population_evaluator=population_evaluator, + ) self.saved_values = [] self.utility = [1.0 for _ in range(population_size)] @@ -205,7 +231,7 @@ def selection(self, population: List[S]): self.neighbor_type = self.choose_neighbor_type() - if self.neighbor_type == 'NEIGHBOR': + if self.neighbor_type == "NEIGHBOR": neighbors = self.neighbourhood.get_neighbors(self.current_subproblem, population) mating_population = self.selection_operator.execute(neighbors) else: @@ -216,7 +242,7 @@ def selection(self, population: List[S]): return mating_population def get_name(self): - return 'MOEAD-DRA' + return "MOEAD-DRA" def __utility_function(self): for i in range(len(self.solutions)): @@ -251,19 +277,21 @@ def __tour_selection(self, depth): class MOEADIEpsilon(MOEAD): - def __init__(self, - problem: Problem, - population_size: int, - mutation: Mutation, - crossover: DifferentialEvolutionCrossover, - aggregative_function: AggregativeFunction, - neighbourhood_selection_probability: float, - max_number_of_replaced_solutions: int, - neighbor_size: int, - weight_files_path: str, - termination_criterion: TerminationCriterion = StoppingByEvaluations(300000), - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator): + def __init__( + self, + problem: Problem, + population_size: int, + mutation: Mutation, + crossover: DifferentialEvolutionCrossover, + aggregative_function: AggregativeFunction, + neighbourhood_selection_probability: float, + max_number_of_replaced_solutions: int, + neighbor_size: int, + weight_files_path: str, + termination_criterion: TerminationCriterion = StoppingByEvaluations(300000), + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + ): """ :param max_number_of_replaced_solutions: (eta in Zhang & Li paper). :param neighbourhood_selection_probability: Probability of mating with a solution in the neighborhood rather @@ -281,7 +309,7 @@ def __init__(self, weight_files_path=weight_files_path, population_evaluator=population_evaluator, population_generator=population_generator, - termination_criterion=termination_criterion + termination_criterion=termination_criterion, ) self.constraints = [] self.epsilon_k = 0 @@ -298,8 +326,9 @@ def init_progress(self) -> None: # for i in range(self.population_size): # self.constraints[i] = get_overall_constraint_violation_degree(self.permutation[i]) - self.constraints = [overall_constraint_violation_degree(self.solutions[i]) - for i in range(0, self.population_size)] + self.constraints = [ + overall_constraint_violation_degree(self.solutions[i]) for i in range(0, self.population_size) + ] sorted(self.constraints) self.epsilon_zero = abs(self.constraints[int(ceil(0.05 * self.population_size))]) @@ -378,8 +407,9 @@ def update_external_archive(self): crowding_distance = CrowdingDistance() while len(first_rank_solutions) > self.population_size: crowding_distance.compute_density_estimator(first_rank_solutions) - first_rank_solutions = sorted(first_rank_solutions, key=lambda x: x.attributes['crowding_distance'], - reverse=True) + first_rank_solutions = sorted( + first_rank_solutions, key=lambda x: x.attributes["crowding_distance"], reverse=True + ) first_rank_solutions.pop() self.archive = [] @@ -391,7 +421,6 @@ def get_result(self): class Permutation: - def __init__(self, length: int): self.counter = 0 self.length = length diff --git a/jmetal/algorithm/multiobjective/nsgaii.py b/jmetal/algorithm/multiobjective/nsgaii.py index 5606bdeb..98eff541 100644 --- a/jmetal/algorithm/multiobjective/nsgaii.py +++ b/jmetal/algorithm/multiobjective/nsgaii.py @@ -1,27 +1,30 @@ import time -from typing import TypeVar, List, Generator +from typing import Generator, List, TypeVar try: import dask - from distributed import as_completed, Client + from distributed import Client, as_completed except ImportError: pass from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm from jmetal.config import store -from jmetal.core.algorithm import DynamicAlgorithm, Algorithm -from jmetal.core.operator import Mutation, Crossover, Selection -from jmetal.core.problem import Problem, DynamicProblem +from jmetal.core.algorithm import Algorithm, DynamicAlgorithm +from jmetal.core.operator import Crossover, Mutation, Selection +from jmetal.core.problem import DynamicProblem, Problem from jmetal.operator import BinaryTournamentSelection +from jmetal.util.comparator import Comparator, DominanceComparator, MultiComparator from jmetal.util.density_estimator import CrowdingDistance from jmetal.util.evaluator import Evaluator from jmetal.util.ranking import FastNonDominatedRanking -from jmetal.util.replacement import RankingAndDensityEstimatorReplacement, RemovalPolicyType -from jmetal.util.comparator import DominanceComparator, Comparator, MultiComparator +from jmetal.util.replacement import ( + RankingAndDensityEstimatorReplacement, + RemovalPolicyType, +) from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: NSGA-II @@ -33,20 +36,21 @@ class NSGAII(GeneticAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - population_size: int, - offspring_population_size: int, - mutation: Mutation, - crossover: Crossover, - selection: Selection = BinaryTournamentSelection( - MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()])), - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = store.default_comparator): + def __init__( + self, + problem: Problem, + population_size: int, + offspring_population_size: int, + mutation: Mutation, + crossover: Crossover, + selection: Selection = BinaryTournamentSelection( + MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) + ), + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = store.default_comparator, + ): """ NSGA-II implementation as described in @@ -75,12 +79,12 @@ def __init__(self, selection=selection, termination_criterion=termination_criterion, population_evaluator=population_evaluator, - population_generator=population_generator + population_generator=population_generator, ) self.dominance_comparator = dominance_comparator def replacement(self, population: List[S], offspring_population: List[S]) -> List[List[S]]: - """ This method joins the current and offspring populations to produce the population of the next generation + """This method joins the current and offspring populations to produce the population of the next generation by applying the ranking and crowding distance selection. :param population: Parent population. @@ -99,24 +103,25 @@ def get_result(self) -> R: return self.solutions def get_name(self) -> str: - return 'NSGAII' + return "NSGAII" class DynamicNSGAII(NSGAII[S, R], DynamicAlgorithm): - - def __init__(self, - problem: DynamicProblem[S], - population_size: int, - offspring_population_size: int, - mutation: Mutation, - crossover: Crossover, - selection: Selection = BinaryTournamentSelection( - MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()])), - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: DominanceComparator = DominanceComparator()): + def __init__( + self, + problem: DynamicProblem[S], + population_size: int, + offspring_population_size: int, + mutation: Mutation, + crossover: Crossover, + selection: Selection = BinaryTournamentSelection( + MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) + ), + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: DominanceComparator = DominanceComparator(), + ): super(DynamicNSGAII, self).__init__( problem=problem, population_size=population_size, @@ -127,7 +132,8 @@ def __init__(self, population_evaluator=population_evaluator, population_generator=population_generator, termination_criterion=termination_criterion, - dominance_comparator=dominance_comparator) + dominance_comparator=dominance_comparator, + ) self.completed_iterations = 0 self.start_computing_time = 0 self.total_computing_time = 0 @@ -148,7 +154,7 @@ def update_progress(self): def stopping_condition_is_met(self): if self.termination_criterion.is_met: observable_data = self.get_observable_data() - observable_data['TERMINATION_CRITERIA_IS_MET'] = True + observable_data["TERMINATION_CRITERIA_IS_MET"] = True self.observable.notify_all(**observable_data) self.restart() @@ -158,19 +164,20 @@ def stopping_condition_is_met(self): class DistributedNSGAII(Algorithm[S, R]): - - def __init__(self, - problem: Problem, - population_size: int, - mutation: Mutation, - crossover: Crossover, - number_of_cores: int, - client, - selection: Selection = BinaryTournamentSelection( - MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()])), - termination_criterion: TerminationCriterion = store.default_termination_criteria, - dominance_comparator: DominanceComparator = DominanceComparator()): + def __init__( + self, + problem: Problem, + population_size: int, + mutation: Mutation, + crossover: Crossover, + number_of_cores: int, + client, + selection: Selection = BinaryTournamentSelection( + MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) + ), + termination_criterion: TerminationCriterion = store.default_termination_criteria, + dominance_comparator: DominanceComparator = DominanceComparator(), + ): super(DistributedNSGAII, self).__init__() self.problem = problem self.population_size = population_size @@ -197,10 +204,12 @@ def stopping_condition_is_met(self) -> bool: def get_observable_data(self) -> dict: ctime = time.time() - self.start_computing_time - return {'PROBLEM': self.problem, - 'EVALUATIONS': self.evaluations, - 'SOLUTIONS': self.get_result(), - 'COMPUTING_TIME': ctime} + return { + "PROBLEM": self.problem, + "EVALUATIONS": self.evaluations, + "SOLUTIONS": self.get_result(), + "COMPUTING_TIME": ctime, + } def init_progress(self) -> None: self.evaluations = self.number_of_cores @@ -216,7 +225,7 @@ def update_progress(self): self.observable.notify_all(**observable_data) def run(self): - """ Execute the algorithm. """ + """Execute the algorithm.""" self.start_computing_time = time.time() create_solution = dask.delayed(self.problem.create_solution) @@ -273,8 +282,9 @@ def run(self): mating_population.append(solution) # Reproduction and evaluation - new_task = self.client.submit(reproduction, mating_population, self.problem, - self.crossover_operator, self.mutation_operator) + new_task = self.client.submit( + reproduction, mating_population, self.problem, self.crossover_operator, self.mutation_operator + ) task_pool.add(new_task) # update progress @@ -296,7 +306,7 @@ def get_result(self) -> R: return self.solutions def get_name(self) -> str: - return 'dNSGA-II' + return "dNSGA-II" def reproduction(mating_population: List[S], problem, crossover_operator, mutation_operator) -> S: diff --git a/jmetal/algorithm/multiobjective/nsgaiii.py b/jmetal/algorithm/multiobjective/nsgaiii.py index 1b8de042..a3fb1216 100644 --- a/jmetal/algorithm/multiobjective/nsgaiii.py +++ b/jmetal/algorithm/multiobjective/nsgaiii.py @@ -1,5 +1,5 @@ -from abc import abstractmethod, ABC -from typing import TypeVar, List +from abc import ABC, abstractmethod +from typing import List, TypeVar import numpy as np from numpy.linalg import LinAlgError @@ -7,7 +7,7 @@ from jmetal.algorithm.multiobjective.nsgaii import NSGAII from jmetal.config import store -from jmetal.core.operator import Mutation, Crossover, Selection +from jmetal.core.operator import Crossover, Mutation, Selection from jmetal.core.problem import Problem from jmetal.operator import BinaryTournamentSelection from jmetal.util.comparator import Comparator, MultiComparator @@ -17,8 +17,8 @@ from jmetal.util.ranking import FastNonDominatedRanking from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: NSGA-III @@ -30,7 +30,6 @@ class ReferenceDirectionFactory(ABC): - def __init__(self, n_dim: int, scaling=None) -> None: self.n_dim = n_dim self.scaling = scaling @@ -50,7 +49,6 @@ def _compute(self): class UniformReferenceDirectionFactory(ReferenceDirectionFactory): - def __init__(self, n_dim: int, scaling=None, n_points: int = None, n_partitions: int = None) -> None: super().__init__(n_dim, scaling) if n_points is not None: @@ -77,8 +75,7 @@ def __uniform_reference_directions(self, ref_dirs, ref_dir, n_partitions: int, b else: for i in range(beta + 1): ref_dir[depth] = 1.0 * i / (1.0 * n_partitions) - self.__uniform_reference_directions(ref_dirs, np.copy(ref_dir), n_partitions, beta - i, - depth + 1) + self.__uniform_reference_directions(ref_dirs, np.copy(ref_dir), n_partitions, beta - i, depth + 1) @staticmethod def get_partition_closest_to_points(n_points, n_dim): @@ -100,7 +97,7 @@ def get_n_points(n_partitions, n_dim): def get_extreme_points(F, n_objs, ideal_point, extreme_points=None): - """ Calculate the Achievement Scalarization Function which is used for the extreme point decomposition. """ + """Calculate the Achievement Scalarization Function which is used for the extreme point decomposition.""" asf = np.eye(n_objs) asf[asf == 0] = 1e6 @@ -122,7 +119,7 @@ def get_extreme_points(F, n_objs, ideal_point, extreme_points=None): def get_nadir_point(extreme_points, ideal_point, worst_point, worst_of_front, worst_of_population): - """ Calculate the axis intersects for a set of individuals and its extremes (construct hyperplane). """ + """Calculate the axis intersects for a set of individuals and its extremes (construct hyperplane).""" try: # find the intercepts using gaussian elimination M = extreme_points - ideal_point @@ -181,7 +178,7 @@ def niching(pop: List[S], n_remaining: int, niche_count, niche_of_individuals, d # add the selected individual to the survivors mask[next_ind] = False - pop[next_ind].attributes['is_closest'] = is_closest + pop[next_ind].attributes["is_closest"] = is_closest survivors.append(int(next_ind)) # increase the corresponding niche count @@ -191,7 +188,7 @@ def niching(pop: List[S], n_remaining: int, niche_count, niche_of_individuals, d def associate_to_niches(F, niches, ideal_point, nadir_point, utopian_epsilon: float = 0.0): - """ Associate each solution to a reference point. """ + """Associate each solution to a reference point.""" utopian_point = ideal_point - utopian_epsilon denom = nadir_point - utopian_point @@ -230,26 +227,27 @@ def compute_niche_count(n_niches: int, niche_of_individuals): class NSGAIII(NSGAII): - - def __init__(self, - reference_directions, - problem: Problem, - mutation: Mutation, - crossover: Crossover, - population_size: int = None, - selection: Selection = BinaryTournamentSelection( - MultiComparator([FastNonDominatedRanking.get_comparator(), - CrowdingDistance.get_comparator()])), - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = store.default_comparator): + def __init__( + self, + reference_directions, + problem: Problem, + mutation: Mutation, + crossover: Crossover, + population_size: int = None, + selection: Selection = BinaryTournamentSelection( + MultiComparator([FastNonDominatedRanking.get_comparator(), CrowdingDistance.get_comparator()]) + ), + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = store.default_comparator, + ): self.reference_directions = reference_directions.compute() if not population_size: population_size = len(self.reference_directions) if self.reference_directions.shape[1] != problem.number_of_objectives: - raise Exception('Dimensionality of reference points must be equal to the number of objectives') + raise Exception("Dimensionality of reference points must be equal to the number of objectives") super(NSGAIII, self).__init__( problem=problem, @@ -261,7 +259,7 @@ def __init__(self, termination_criterion=termination_criterion, population_evaluator=population_evaluator, population_generator=population_generator, - dominance_comparator=dominance_comparator + dominance_comparator=dominance_comparator, ) self.extreme_points = None @@ -269,7 +267,7 @@ def __init__(self, self.worst_point = np.full(self.problem.number_of_objectives, -np.inf) def replacement(self, population: List[S], offspring_population: List[S]) -> List[S]: - """ Implements NSGA-III environmental selection based on reference points as described in: + """Implements NSGA-III environmental selection based on reference points as described in: * Deb, K., & Jain, H. (2014). An Evolutionary Many-Objective Optimization Algorithm Using Reference-Point-Based Nondominated Sorting Approach, @@ -290,20 +288,24 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis fronts, non_dominated = ranking.ranked_sublists, ranking.get_subfront(0) # find the extreme points for normalization - self.extreme_points = get_extreme_points(F=np.array([s.objectives for s in non_dominated]), - n_objs=self.problem.number_of_objectives, - ideal_point=self.ideal_point, - extreme_points=self.extreme_points) + self.extreme_points = get_extreme_points( + F=np.array([s.objectives for s in non_dominated]), + n_objs=self.problem.number_of_objectives, + ideal_point=self.ideal_point, + extreme_points=self.extreme_points, + ) # find the intercepts for normalization and do backup if gaussian elimination fails worst_of_population = np.max(F, axis=0) worst_of_front = np.max(np.array([s.objectives for s in non_dominated]), axis=0) - nadir_point = get_nadir_point(extreme_points=self.extreme_points, - ideal_point=self.ideal_point, - worst_point=self.worst_point, - worst_of_population=worst_of_population, - worst_of_front=worst_of_front) + nadir_point = get_nadir_point( + extreme_points=self.extreme_points, + ideal_point=self.ideal_point, + worst_point=self.worst_point, + worst_of_population=worst_of_population, + worst_of_front=worst_of_front, + ) # consider only the population until we come to the splitting front pop = np.concatenate(ranking.ranked_sublists) @@ -318,10 +320,9 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis last_front = np.array(fronts[-1]) # associate individuals to niches - niche_of_individuals, dist_to_niche = associate_to_niches(F=F, - niches=self.reference_directions, - ideal_point=self.ideal_point, - nadir_point=nadir_point) + niche_of_individuals, dist_to_niche = associate_to_niches( + F=F, niches=self.reference_directions, ideal_point=self.ideal_point, nadir_point=nadir_point + ) # if we need to select individuals to survive if len(pop) > self.population_size: @@ -333,15 +334,18 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis # if some individuals already survived else: until_last_front = np.concatenate(fronts[:-1]) - niche_count = compute_niche_count(len(self.reference_directions), - niche_of_individuals[until_last_front]) + niche_count = compute_niche_count( + len(self.reference_directions), niche_of_individuals[until_last_front] + ) n_remaining = self.population_size - len(until_last_front) - S_idx = niching(pop=pop[last_front], - n_remaining=n_remaining, - niche_count=niche_count, - niche_of_individuals=niche_of_individuals[last_front], - dist_to_niche=dist_to_niche[last_front]) + S_idx = niching( + pop=pop[last_front], + n_remaining=n_remaining, + niche_count=niche_count, + niche_of_individuals=niche_of_individuals[last_front], + dist_to_niche=dist_to_niche[last_front], + ) survivors_idx = np.concatenate((until_last_front, last_front[S_idx].tolist())) pop = pop[survivors_idx] @@ -349,11 +353,11 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis return list(pop) def get_result(self): - """ Return only non dominated solutions.""" + """Return only non dominated solutions.""" ranking = FastNonDominatedRanking(self.dominance_comparator) ranking.compute_ranking(self.solutions, k=self.population_size) return ranking.get_subfront(0) def get_name(self) -> str: - return 'NSGAIII' + return "NSGAIII" diff --git a/jmetal/algorithm/multiobjective/omopso.py b/jmetal/algorithm/multiobjective/omopso.py index fb07555e..3e4d930f 100644 --- a/jmetal/algorithm/multiobjective/omopso.py +++ b/jmetal/algorithm/multiobjective/omopso.py @@ -1,7 +1,7 @@ import random from copy import copy from math import sqrt -from typing import TypeVar, List, Optional +from typing import List, Optional, TypeVar import numpy @@ -17,7 +17,7 @@ from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -R = TypeVar('R') +R = TypeVar("R") """ .. module:: OMOPSO @@ -29,18 +29,19 @@ class OMOPSO(ParticleSwarmOptimization): - - def __init__(self, - problem: FloatProblem, - swarm_size: int, - uniform_mutation: UniformMutation, - non_uniform_mutation: NonUniformMutation, - leaders: Optional[BoundedArchive], - epsilon: float, - termination_criterion: TerminationCriterion, - swarm_generator: Generator = store.default_generator, - swarm_evaluator: Evaluator = store.default_evaluator): - """ This class implements the OMOPSO algorithm as described in + def __init__( + self, + problem: FloatProblem, + swarm_size: int, + uniform_mutation: UniformMutation, + non_uniform_mutation: NonUniformMutation, + leaders: Optional[BoundedArchive], + epsilon: float, + termination_criterion: TerminationCriterion, + swarm_generator: Generator = store.default_generator, + swarm_evaluator: Evaluator = store.default_evaluator, + ): + """This class implements the OMOPSO algorithm as described in todo Update this reference * SMPSO: A new PSO-based metaheuristic for multi-objective optimization @@ -52,9 +53,7 @@ def __init__(self, :param swarm_size: Size of the swarm. :param leaders: Archive for leaders. """ - super(OMOPSO, self).__init__( - problem=problem, - swarm_size=swarm_size) + super(OMOPSO, self).__init__(problem=problem, swarm_size=swarm_size) self.swarm_generator = swarm_generator self.swarm_evaluator = swarm_evaluator @@ -102,7 +101,7 @@ def initialize_global_best(self, swarm: List[FloatSolution]) -> None: def initialize_particle_best(self, swarm: List[FloatSolution]) -> None: for particle in swarm: - particle.attributes['local_best'] = copy(particle) + particle.attributes["local_best"] = copy(particle) def initialize_velocity(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): @@ -111,7 +110,7 @@ def initialize_velocity(self, swarm: List[FloatSolution]) -> None: def update_velocity(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): - best_particle = copy(swarm[i].attributes['local_best']) + best_particle = copy(swarm[i].attributes["local_best"]) best_global = self.select_global_best() r1 = round(random.uniform(self.r1_min, self.r1_max), 1) @@ -121,9 +120,11 @@ def update_velocity(self, swarm: List[FloatSolution]) -> None: w = round(random.uniform(self.weight_min, self.weight_max), 1) for var in range(swarm[i].number_of_variables): - self.speed[i][var] = w * self.speed[i][var] \ - + (c1 * r1 * (best_particle.variables[var] - swarm[i].variables[var])) \ - + (c2 * r2 * (best_global.variables[var] - swarm[i].variables[var])) + self.speed[i][var] = ( + w * self.speed[i][var] + + (c1 * r1 * (best_particle.variables[var] - swarm[i].variables[var])) + + (c2 * r2 * (best_global.variables[var] - swarm[i].variables[var])) + ) def update_position(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): @@ -147,11 +148,9 @@ def update_global_best(self, swarm: List[FloatSolution]) -> None: def update_particle_best(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): - flag = self.dominance_comparator.compare( - swarm[i], - swarm[i].attributes['local_best']) + flag = self.dominance_comparator.compare(swarm[i], swarm[i].attributes["local_best"]) if flag != 1: - swarm[i].attributes['local_best'] = copy(swarm[i]) + swarm[i].attributes["local_best"] = copy(swarm[i]) def perturbation(self, swarm: List[FloatSolution]) -> None: self.non_uniform_mutation.set_current_iteration(self.evaluations / self.swarm_size) @@ -210,11 +209,11 @@ def update_progress(self) -> None: self.leaders.compute_density_estimator() observable_data = self.get_observable_data() - observable_data['SOLUTIONS'] = self.epsilon_archive.solution_list + observable_data["SOLUTIONS"] = self.epsilon_archive.solution_list self.observable.notify_all(**observable_data) def get_result(self) -> List[FloatSolution]: return self.epsilon_archive.solution_list def get_name(self) -> str: - return 'OMOPSO' + return "OMOPSO" diff --git a/jmetal/algorithm/multiobjective/random_search.py b/jmetal/algorithm/multiobjective/random_search.py index 867167a8..364eaf8a 100644 --- a/jmetal/algorithm/multiobjective/random_search.py +++ b/jmetal/algorithm/multiobjective/random_search.py @@ -1,5 +1,5 @@ import time -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.config import store from jmetal.core.algorithm import Algorithm @@ -7,8 +7,8 @@ from jmetal.util.archive import NonDominatedSolutionsArchive from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: RamdomSearch @@ -20,10 +20,9 @@ class RandomSearch(Algorithm[S, R]): - - def __init__(self, - problem: Problem[S], - termination_criterion: TerminationCriterion = store.default_termination_criteria): + def __init__( + self, problem: Problem[S], termination_criterion: TerminationCriterion = store.default_termination_criteria + ): super().__init__() self.problem = problem self.termination_criterion = termination_criterion @@ -33,8 +32,12 @@ def __init__(self, def get_observable_data(self) -> dict: ctime = time.time() - self.start_computing_time - return {'PROBLEM': self.problem, 'EVALUATIONS': self.evaluations, 'SOLUTIONS': self.get_result(), - 'COMPUTING_TIME': ctime} + return { + "PROBLEM": self.problem, + "EVALUATIONS": self.evaluations, + "SOLUTIONS": self.get_result(), + "COMPUTING_TIME": ctime, + } def create_initial_solutions(self) -> List[S]: return [self.problem.create_solution()] @@ -66,8 +69,8 @@ def get_result(self) -> List[S]: return self.archive.solution_list def get_name(self) -> str: - return 'Random Search' + return "Random Search" @property def label(self) -> str: - return f'{self.get_name()}.{self.problem.get_name()}' \ No newline at end of file + return f"{self.get_name()}.{self.problem.get_name()}" diff --git a/jmetal/algorithm/multiobjective/smpso.py b/jmetal/algorithm/multiobjective/smpso.py index 4e50d914..f76394dc 100644 --- a/jmetal/algorithm/multiobjective/smpso.py +++ b/jmetal/algorithm/multiobjective/smpso.py @@ -2,22 +2,22 @@ import threading from copy import copy from math import sqrt -from typing import TypeVar, List, Optional +from typing import List, Optional, TypeVar import numpy from jmetal.config import store -from jmetal.core.algorithm import ParticleSwarmOptimization, DynamicAlgorithm +from jmetal.core.algorithm import DynamicAlgorithm, ParticleSwarmOptimization from jmetal.core.operator import Mutation -from jmetal.core.problem import FloatProblem, DynamicProblem +from jmetal.core.problem import DynamicProblem, FloatProblem from jmetal.core.solution import FloatSolution -from jmetal.util.archive import BoundedArchive, ArchiveWithReferencePoint +from jmetal.util.archive import ArchiveWithReferencePoint, BoundedArchive from jmetal.util.comparator import DominanceComparator from jmetal.util.evaluator import Evaluator from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -R = TypeVar('R') +R = TypeVar("R") """ .. module:: SMPSO @@ -29,16 +29,17 @@ class SMPSO(ParticleSwarmOptimization): - - def __init__(self, - problem: FloatProblem, - swarm_size: int, - mutation: Mutation, - leaders: Optional[BoundedArchive], - termination_criterion: TerminationCriterion = store.default_termination_criteria, - swarm_generator: Generator = store.default_generator, - swarm_evaluator: Evaluator = store.default_evaluator): - """ This class implements the SMPSO algorithm as described in + def __init__( + self, + problem: FloatProblem, + swarm_size: int, + mutation: Mutation, + leaders: Optional[BoundedArchive], + termination_criterion: TerminationCriterion = store.default_termination_criteria, + swarm_generator: Generator = store.default_generator, + swarm_evaluator: Evaluator = store.default_evaluator, + ): + """This class implements the SMPSO algorithm as described in * SMPSO: A new PSO-based metaheuristic for multi-objective optimization * MCDM 2009. DOI: ``_. @@ -52,9 +53,7 @@ def __init__(self, :param mutation: Mutation operator (see :py:mod:`jmetal.operator.mutation`). :param leaders: Archive for leaders. """ - super(SMPSO, self).__init__( - problem=problem, - swarm_size=swarm_size) + super(SMPSO, self).__init__(problem=problem, swarm_size=swarm_size) self.swarm_generator = swarm_generator self.swarm_evaluator = swarm_evaluator self.termination_criterion = termination_criterion @@ -78,8 +77,10 @@ def __init__(self, self.dominance_comparator = DominanceComparator() self.speed = numpy.zeros((self.swarm_size, self.problem.number_of_variables), dtype=float) - self.delta_max, self.delta_min = numpy.empty(problem.number_of_variables), \ - numpy.empty(problem.number_of_variables) + self.delta_max, self.delta_min = ( + numpy.empty(problem.number_of_variables), + numpy.empty(problem.number_of_variables), + ) def create_initial_solutions(self) -> List[FloatSolution]: return [self.swarm_generator.new(self.problem) for _ in range(self.swarm_size)] @@ -96,7 +97,7 @@ def initialize_global_best(self, swarm: List[FloatSolution]) -> None: def initialize_particle_best(self, swarm: List[FloatSolution]) -> None: for particle in swarm: - particle.attributes['local_best'] = copy(particle) + particle.attributes["local_best"] = copy(particle) def initialize_velocity(self, swarm: List[FloatSolution]) -> None: for i in range(self.problem.number_of_variables): @@ -106,7 +107,7 @@ def initialize_velocity(self, swarm: List[FloatSolution]) -> None: def update_velocity(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): - best_particle = copy(swarm[i].attributes['local_best']) + best_particle = copy(swarm[i].attributes["local_best"]) best_global = self.select_global_best() r1 = round(random.uniform(self.r1_min, self.r1_max), 1) @@ -117,15 +118,17 @@ def update_velocity(self, swarm: List[FloatSolution]) -> None: wmin = self.min_weight for var in range(swarm[i].number_of_variables): - self.speed[i][var] = \ - self.__velocity_constriction( - self.__constriction_coefficient(c1, c2) * - ((self.__inertia_weight(wmax) - * self.speed[i][var]) - + (c1 * r1 * (best_particle.variables[var] - swarm[i].variables[var])) - + (c2 * r2 * (best_global.variables[var] - swarm[i].variables[var])) - ), - self.delta_max, self.delta_min, var) + self.speed[i][var] = self.__velocity_constriction( + self.__constriction_coefficient(c1, c2) + * ( + (self.__inertia_weight(wmax) * self.speed[i][var]) + + (c1 * r1 * (best_particle.variables[var] - swarm[i].variables[var])) + + (c2 * r2 * (best_global.variables[var] - swarm[i].variables[var])) + ), + self.delta_max, + self.delta_min, + var, + ) def update_position(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): @@ -148,11 +151,9 @@ def update_global_best(self, swarm: List[FloatSolution]) -> None: def update_particle_best(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): - flag = self.dominance_comparator.compare( - swarm[i], - swarm[i].attributes['local_best']) + flag = self.dominance_comparator.compare(swarm[i], swarm[i].attributes["local_best"]) if flag != 1: - swarm[i].attributes['local_best'] = copy(swarm[i]) + swarm[i].attributes["local_best"] = copy(swarm[i]) def perturbation(self, swarm: List[FloatSolution]) -> None: for i in range(self.swarm_size): @@ -208,26 +209,27 @@ def update_progress(self) -> None: self.leaders.compute_density_estimator() observable_data = self.get_observable_data() - observable_data['SOLUTIONS'] = self.leaders.solution_list + observable_data["SOLUTIONS"] = self.leaders.solution_list self.observable.notify_all(**observable_data) def get_result(self) -> List[FloatSolution]: return self.leaders.solution_list def get_name(self) -> str: - return 'SMPSO' + return "SMPSO" class DynamicSMPSO(SMPSO, DynamicAlgorithm): - - def __init__(self, - problem: DynamicProblem[FloatSolution], - swarm_size: int, - mutation: Mutation, - leaders: BoundedArchive, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - swarm_generator: Generator = store.default_generator, - swarm_evaluator: Evaluator = store.default_evaluator): + def __init__( + self, + problem: DynamicProblem[FloatSolution], + swarm_size: int, + mutation: Mutation, + leaders: BoundedArchive, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + swarm_generator: Generator = store.default_generator, + swarm_evaluator: Evaluator = store.default_evaluator, + ): super(DynamicSMPSO, self).__init__( problem=problem, swarm_size=swarm_size, @@ -235,7 +237,8 @@ def __init__(self, leaders=leaders, termination_criterion=termination_criterion, swarm_generator=swarm_generator, - swarm_evaluator=swarm_evaluator) + swarm_evaluator=swarm_evaluator, + ) self.completed_iterations = 0 def restart(self) -> None: @@ -264,7 +267,7 @@ def update_progress(self): def stopping_condition_is_met(self): if self.termination_criterion.is_met: observable_data = self.get_observable_data() - observable_data['termination_criterion_is_met'] = True + observable_data["termination_criterion_is_met"] = True self.observable.notify_all(**observable_data) self.restart() @@ -273,17 +276,18 @@ def stopping_condition_is_met(self): class SMPSORP(SMPSO): - - def __init__(self, - problem: FloatProblem, - swarm_size: int, - mutation: Mutation, - reference_points: List[List[float]], - leaders: List[ArchiveWithReferencePoint], - termination_criterion: TerminationCriterion, - swarm_generator: Generator = store.default_generator, - swarm_evaluator: Evaluator = store.default_evaluator): - """ This class implements the SMPSORP algorithm. + def __init__( + self, + problem: FloatProblem, + swarm_size: int, + mutation: Mutation, + reference_points: List[List[float]], + leaders: List[ArchiveWithReferencePoint], + termination_criterion: TerminationCriterion, + swarm_generator: Generator = store.default_generator, + swarm_evaluator: Evaluator = store.default_evaluator, + ): + """This class implements the SMPSORP algorithm. :param problem: The problem to solve. :param swarm_size: @@ -298,7 +302,8 @@ def __init__(self, leaders=None, swarm_generator=swarm_generator, swarm_evaluator=swarm_evaluator, - termination_criterion=termination_criterion) + termination_criterion=termination_criterion, + ) self.leaders = leaders self.reference_points = reference_points self.lock = threading.Lock() @@ -357,7 +362,7 @@ def update_progress(self) -> None: leader.compute_density_estimator() observable_data = self.get_observable_data() - observable_data['REFERENCE_POINT'] = self.get_reference_point() + observable_data["REFERENCE_POINT"] = self.get_reference_point() self.observable.notify_all(**observable_data) def update_reference_point(self, new_reference_points: list): @@ -381,22 +386,21 @@ def get_result(self) -> List[FloatSolution]: return result def get_name(self) -> str: - return 'SMPSO/RP' + return "SMPSO/RP" def _change_reference_point(algorithm: SMPSORP): - """ Auxiliar function to read new reference points from the keyboard for the SMPSO/RP algorithm - """ + """Auxiliar function to read new reference points from the keyboard for the SMPSO/RP algorithm""" number_of_reference_points = len(algorithm.reference_points) number_of_objectives = algorithm.problem.number_of_objectives while True: - print(f'Enter {number_of_reference_points}-points of dimension {number_of_objectives}: ') + print(f"Enter {number_of_reference_points}-points of dimension {number_of_objectives}: ") read = [float(x) for x in input().split()] # Update reference points reference_points = [] for i in range(0, len(read), number_of_objectives): - reference_points.append(read[i:i + number_of_objectives]) + reference_points.append(read[i : i + number_of_objectives]) algorithm.update_reference_point(reference_points) diff --git a/jmetal/algorithm/multiobjective/spea2.py b/jmetal/algorithm/multiobjective/spea2.py index 5b7dea5f..2f952fbc 100644 --- a/jmetal/algorithm/multiobjective/spea2.py +++ b/jmetal/algorithm/multiobjective/spea2.py @@ -1,8 +1,8 @@ -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.algorithm.singleobjective.genetic_algorithm import GeneticAlgorithm from jmetal.config import store -from jmetal.core.operator import Mutation, Crossover +from jmetal.core.operator import Crossover, Mutation from jmetal.core.problem import Problem from jmetal.operator import BinaryTournamentSelection from jmetal.util.comparator import Comparator, MultiComparator @@ -10,11 +10,14 @@ from jmetal.util.evaluator import Evaluator from jmetal.util.generator import Generator from jmetal.util.ranking import StrengthRanking -from jmetal.util.replacement import RankingAndDensityEstimatorReplacement, RemovalPolicyType +from jmetal.util.replacement import ( + RankingAndDensityEstimatorReplacement, + RemovalPolicyType, +) from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: SPEA2 @@ -33,25 +36,27 @@ class SPEA2(GeneticAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - population_size: int, - offspring_population_size: int, - mutation: Mutation, - crossover: Crossover, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator, - dominance_comparator: Comparator = store.default_comparator): + def __init__( + self, + problem: Problem, + population_size: int, + offspring_population_size: int, + mutation: Mutation, + crossover: Crossover, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + dominance_comparator: Comparator = store.default_comparator, + ): """ :param problem: The problem to solve. :param population_size: Size of the population. :param mutation: Mutation operator (see :py:mod:`jmetal.operator.mutation`). :param crossover: Crossover operator (see :py:mod:`jmetal.operator.crossover`). """ - multi_comparator = MultiComparator([StrengthRanking.get_comparator(), - KNearestNeighborDensityEstimator.get_comparator()]) + multi_comparator = MultiComparator( + [StrengthRanking.get_comparator(), KNearestNeighborDensityEstimator.get_comparator()] + ) selection = BinaryTournamentSelection(comparator=multi_comparator) super(SPEA2, self).__init__( @@ -63,12 +68,12 @@ def __init__(self, selection=selection, termination_criterion=termination_criterion, population_evaluator=population_evaluator, - population_generator=population_generator + population_generator=population_generator, ) self.dominance_comparator = dominance_comparator def replacement(self, population: List[S], offspring_population: List[S]) -> List[List[S]]: - """ This method joins the current and offspring populations to produce the population of the next generation + """This method joins the current and offspring populations to produce the population of the next generation by applying the ranking and crowding distance selection. :param population: Parent population. @@ -87,4 +92,4 @@ def get_result(self) -> R: return self.solutions def get_name(self) -> str: - return 'SPEA2' + return "SPEA2" diff --git a/jmetal/algorithm/singleobjective/evolution_strategy.py b/jmetal/algorithm/singleobjective/evolution_strategy.py index 2f52a543..0dbe81ca 100644 --- a/jmetal/algorithm/singleobjective/evolution_strategy.py +++ b/jmetal/algorithm/singleobjective/evolution_strategy.py @@ -1,16 +1,16 @@ from copy import copy -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.core.algorithm import EvolutionaryAlgorithm from jmetal.core.operator import Mutation from jmetal.core.problem import Problem +from jmetal.util.constraint_handling import overall_constraint_violation_degree from jmetal.util.evaluator import Evaluator, SequentialEvaluator from jmetal.util.generator import Generator, RandomGenerator from jmetal.util.termination_criterion import TerminationCriterion -from jmetal.util.constraint_handling import overall_constraint_violation_degree -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: evolutionary_algorithm @@ -22,20 +22,18 @@ class EvolutionStrategy(EvolutionaryAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - mu: int, - lambda_: int, - elitist: bool, - mutation: Mutation, - termination_criterion: TerminationCriterion, - population_generator: Generator = RandomGenerator(), - population_evaluator: Evaluator = SequentialEvaluator()): - super(EvolutionStrategy, self).__init__( - problem=problem, - population_size=mu, - offspring_population_size=lambda_) + def __init__( + self, + problem: Problem, + mu: int, + lambda_: int, + elitist: bool, + mutation: Mutation, + termination_criterion: TerminationCriterion, + population_generator: Generator = RandomGenerator(), + population_evaluator: Evaluator = SequentialEvaluator(), + ): + super(EvolutionStrategy, self).__init__(problem=problem, population_size=mu, offspring_population_size=lambda_) self.mu = mu self.lambda_ = lambda_ self.elitist = elitist @@ -49,8 +47,7 @@ def __init__(self, self.observable.register(termination_criterion) def create_initial_solutions(self) -> List[S]: - return [self.population_generator.new(self.problem) - for _ in range(self.population_size)] + return [self.population_generator.new(self.problem) for _ in range(self.population_size)] def evaluate(self, solution_list: List[S]): return self.population_evaluator.evaluate(solution_list, self.problem) @@ -91,4 +88,4 @@ def get_result(self) -> R: return self.solutions[0] def get_name(self) -> str: - return 'Elitist evolution Strategy' + return "Elitist evolution Strategy" diff --git a/jmetal/algorithm/singleobjective/genetic_algorithm.py b/jmetal/algorithm/singleobjective/genetic_algorithm.py index 8216625d..a6fb650e 100644 --- a/jmetal/algorithm/singleobjective/genetic_algorithm.py +++ b/jmetal/algorithm/singleobjective/genetic_algorithm.py @@ -1,15 +1,15 @@ -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.config import store from jmetal.core.algorithm import EvolutionaryAlgorithm -from jmetal.core.operator import Mutation, Crossover, Selection +from jmetal.core.operator import Crossover, Mutation, Selection from jmetal.core.problem import Problem from jmetal.util.evaluator import Evaluator from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: genetic_algorithm @@ -20,21 +20,21 @@ class GeneticAlgorithm(EvolutionaryAlgorithm[S, R]): - - def __init__(self, - problem: Problem, - population_size: int, - offspring_population_size: int, - mutation: Mutation, - crossover: Crossover, - selection: Selection, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - population_generator: Generator = store.default_generator, - population_evaluator: Evaluator = store.default_evaluator): + def __init__( + self, + problem: Problem, + population_size: int, + offspring_population_size: int, + mutation: Mutation, + crossover: Crossover, + selection: Selection, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + population_generator: Generator = store.default_generator, + population_evaluator: Evaluator = store.default_evaluator, + ): super(GeneticAlgorithm, self).__init__( - problem=problem, - population_size=population_size, - offspring_population_size=offspring_population_size) + problem=problem, population_size=population_size, offspring_population_size=offspring_population_size + ) self.mutation_operator = mutation self.crossover_operator = crossover self.selection_operator = selection @@ -45,16 +45,17 @@ def __init__(self, self.termination_criterion = termination_criterion self.observable.register(termination_criterion) - self.mating_pool_size = \ - self.offspring_population_size * \ - self.crossover_operator.get_number_of_parents() // self.crossover_operator.get_number_of_children() + self.mating_pool_size = ( + self.offspring_population_size + * self.crossover_operator.get_number_of_parents() + // self.crossover_operator.get_number_of_children() + ) if self.mating_pool_size < self.crossover_operator.get_number_of_children(): self.mating_pool_size = self.crossover_operator.get_number_of_children() def create_initial_solutions(self) -> List[S]: - return [self.population_generator.new(self.problem) - for _ in range(self.population_size)] + return [self.population_generator.new(self.problem) for _ in range(self.population_size)] def evaluate(self, population: List[S]): return self.population_evaluator.evaluate(population, self.problem) @@ -75,7 +76,7 @@ def reproduction(self, mating_population: List[S]) -> List[S]: number_of_parents_to_combine = self.crossover_operator.get_number_of_parents() if len(mating_population) % number_of_parents_to_combine != 0: - raise Exception('Wrong number of parents') + raise Exception("Wrong number of parents") offspring_population = [] for i in range(0, self.offspring_population_size, number_of_parents_to_combine): @@ -98,10 +99,10 @@ def replacement(self, population: List[S], offspring_population: List[S]) -> Lis population.sort(key=lambda s: s.objectives[0]) - return population[:self.population_size] + return population[: self.population_size] def get_result(self) -> R: return self.solutions[0] def get_name(self) -> str: - return 'Genetic algorithm' + return "Genetic algorithm" diff --git a/jmetal/algorithm/singleobjective/local_search.py b/jmetal/algorithm/singleobjective/local_search.py index 53b2c146..6db637bc 100644 --- a/jmetal/algorithm/singleobjective/local_search.py +++ b/jmetal/algorithm/singleobjective/local_search.py @@ -2,7 +2,7 @@ import random import threading import time -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.config import store from jmetal.core.algorithm import Algorithm @@ -12,8 +12,8 @@ from jmetal.util.comparator import Comparator from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: local_search @@ -25,12 +25,13 @@ class LocalSearch(Algorithm[S, R], threading.Thread): - - def __init__(self, - problem: Problem[S], - mutation: Mutation, - termination_criterion: TerminationCriterion = store.default_termination_criteria, - comparator: Comparator = store.default_comparator): + def __init__( + self, + problem: Problem[S], + mutation: Mutation, + termination_criterion: TerminationCriterion = store.default_termination_criteria, + comparator: Comparator = store.default_comparator, + ): super(LocalSearch, self).__init__() self.comparator = comparator self.problem = problem @@ -73,11 +74,15 @@ def update_progress(self) -> None: def get_observable_data(self) -> dict: ctime = time.time() - self.start_computing_time - return {'PROBLEM': self.problem, 'EVALUATIONS': self.evaluations, 'SOLUTIONS': self.get_result(), - 'COMPUTING_TIME': ctime} + return { + "PROBLEM": self.problem, + "EVALUATIONS": self.evaluations, + "SOLUTIONS": self.get_result(), + "COMPUTING_TIME": ctime, + } def get_result(self) -> R: return self.solutions[0] def get_name(self) -> str: - return 'LS' + return "LS" diff --git a/jmetal/algorithm/singleobjective/simulated_annealing.py b/jmetal/algorithm/singleobjective/simulated_annealing.py index 7d36f7c0..2713c3ff 100644 --- a/jmetal/algorithm/singleobjective/simulated_annealing.py +++ b/jmetal/algorithm/singleobjective/simulated_annealing.py @@ -2,7 +2,7 @@ import random import threading import time -from typing import TypeVar, List +from typing import List, TypeVar import numpy @@ -14,8 +14,8 @@ from jmetal.util.generator import Generator from jmetal.util.termination_criterion import TerminationCriterion -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: simulated_annealing @@ -27,12 +27,13 @@ class SimulatedAnnealing(Algorithm[S, R], threading.Thread): - - def __init__(self, - problem: Problem[S], - mutation: Mutation, - termination_criterion: TerminationCriterion, - solution_generator: Generator = store.default_generator): + def __init__( + self, + problem: Problem[S], + mutation: Mutation, + termination_criterion: TerminationCriterion, + solution_generator: Generator = store.default_generator, + ): super(SimulatedAnnealing, self).__init__() self.problem = problem self.mutation = mutation @@ -62,9 +63,8 @@ def step(self) -> None: mutated_solution = self.evaluate([mutated_solution])[0] acceptance_probability = self.compute_acceptance_probability( - self.solutions[0].objectives[0], - mutated_solution.objectives[0], - self.temperature) + self.solutions[0].objectives[0], mutated_solution.objectives[0], self.temperature + ) if acceptance_probability > random.random(): self.solutions[0] = mutated_solution @@ -87,11 +87,15 @@ def update_progress(self) -> None: def get_observable_data(self) -> dict: ctime = time.time() - self.start_computing_time - return {'PROBLEM': self.problem, 'EVALUATIONS': self.evaluations, 'SOLUTIONS': self.get_result(), - 'COMPUTING_TIME': ctime} + return { + "PROBLEM": self.problem, + "EVALUATIONS": self.evaluations, + "SOLUTIONS": self.get_result(), + "COMPUTING_TIME": ctime, + } def get_result(self) -> R: return self.solutions[0] def get_name(self) -> str: - return 'Simulated Annealing' + return "Simulated Annealing" diff --git a/jmetal/algorithm/test/ittest_algorithm.py b/jmetal/algorithm/test/ittest_algorithm.py index 9a7c5415..f214b774 100644 --- a/jmetal/algorithm/test/ittest_algorithm.py +++ b/jmetal/algorithm/test/ittest_algorithm.py @@ -10,7 +10,6 @@ class RunningAlgorithmsTestCases(unittest.TestCase): - def setUp(self): self.problem = ZDT1() self.population_size = 100 @@ -27,7 +26,7 @@ def test_NSGAII(self): offspring_population_size=self.offspring_size, mutation=self.mutation, crossover=self.crossover, - termination_criterion=StoppingByEvaluations(max_evaluations=1000) + termination_criterion=StoppingByEvaluations(max_evaluations=1000), ).run() def test_SMPSO(self): @@ -36,12 +35,11 @@ def test_SMPSO(self): swarm_size=self.population_size, mutation=self.mutation, leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=1000) + termination_criterion=StoppingByEvaluations(max_evaluations=1000), ).run() class IntegrationTestCases(unittest.TestCase): - def test_should_NSGAII_work_when_solving_problem_ZDT1_with_standard_settings(self): problem = ZDT1() @@ -53,7 +51,7 @@ def test_should_NSGAII_work_when_solving_problem_ZDT1_with_standard_settings(sel offspring_population_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), crossover=SBXCrossover(probability=1.0, distribution_index=20), - termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations) + termination_criterion=StoppingByEvaluations(max_evaluations=max_evaluations), ) algorithm.run() @@ -72,7 +70,7 @@ def test_should_SMPSO_work_when_solving_problem_ZDT1_with_standard_settings(self swarm_size=100, mutation=PolynomialMutation(probability=1.0 / problem.number_of_variables, distribution_index=20), leaders=CrowdingDistanceArchive(100), - termination_criterion=StoppingByEvaluations(max_evaluations=25000) + termination_criterion=StoppingByEvaluations(max_evaluations=25000), ) algorithm.run() @@ -84,5 +82,5 @@ def test_should_SMPSO_work_when_solving_problem_ZDT1_with_standard_settings(self self.assertTrue(value >= 0.655) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/config.py b/jmetal/config.py index 51597da3..76a58182 100644 --- a/jmetal/config.py +++ b/jmetal/config.py @@ -1,19 +1,19 @@ -from jmetal.operator import PolynomialMutation, BitFlipMutation +from jmetal.core.observer import Observable +from jmetal.operator import BitFlipMutation, PolynomialMutation from jmetal.util.comparator import DominanceComparator -from jmetal.util.evaluator import SequentialEvaluator +from jmetal.util.evaluator import Evaluator, SequentialEvaluator from jmetal.util.generator import RandomGenerator from jmetal.util.observable import DefaultObservable from jmetal.util.termination_criterion import StoppingByEvaluations class _Store: - @property - def default_observable(self): + def default_observable(self) -> Observable: return DefaultObservable() @property - def default_evaluator(self): + def default_evaluator(self) -> Evaluator: return SequentialEvaluator() @property @@ -30,10 +30,7 @@ def default_comparator(self): @property def default_mutation(self): - return { - 'real': PolynomialMutation(probability=0.15, distribution_index=20), - 'binary': BitFlipMutation(0.15) - } + return {"real": PolynomialMutation(probability=0.15, distribution_index=20), "binary": BitFlipMutation(0.15)} store = _Store() diff --git a/jmetal/core/algorithm.py b/jmetal/core/algorithm.py index ea602b54..93490756 100644 --- a/jmetal/core/algorithm.py +++ b/jmetal/core/algorithm.py @@ -1,17 +1,17 @@ -import logging import threading import time -from abc import abstractmethod, ABC -from typing import TypeVar, Generic, List +from abc import ABC, abstractmethod +from typing import Generic, List, TypeVar from jmetal.config import store from jmetal.core.problem import Problem from jmetal.core.solution import FloatSolution +from jmetal.logger import get_logger -LOGGER = logging.getLogger('jmetal') +logger = get_logger(__name__) -S = TypeVar('S') -R = TypeVar('R') +S = TypeVar("S") +R = TypeVar("R") """ .. module:: algorithm @@ -23,7 +23,6 @@ class Algorithm(Generic[S, R], threading.Thread, ABC): - def __init__(self): threading.Thread.__init__(self) @@ -36,54 +35,59 @@ def __init__(self): @abstractmethod def create_initial_solutions(self) -> List[S]: - """ Creates the initial list of solutions of a metaheuristic. """ + """Creates the initial list of solutions of a metaheuristic.""" pass @abstractmethod def evaluate(self, solution_list: List[S]) -> List[S]: - """ Evaluates a solution list. """ + """Evaluates a solution list.""" pass @abstractmethod def init_progress(self) -> None: - """ Initialize the algorithm. """ + """Initialize the algorithm.""" pass @abstractmethod def stopping_condition_is_met(self) -> bool: - """ The stopping condition is met or not. """ + """The stopping condition is met or not.""" pass @abstractmethod def step(self) -> None: - """ Performs one iteration/step of the algorithm's loop. """ + """Performs one iteration/step of the algorithm's loop.""" pass @abstractmethod def update_progress(self) -> None: - """ Update the progress after each iteration. """ + """Update the progress after each iteration.""" pass @abstractmethod def get_observable_data(self) -> dict: - """ Get observable data, with the information that will be send to all observers each time. """ + """Get observable data, with the information that will be send to all observers each time.""" pass def run(self): - """ Execute the algorithm. """ + """Execute the algorithm.""" self.start_computing_time = time.time() + logger.debug("Creating initial set of solutions...") self.solutions = self.create_initial_solutions() + + logger.debug("Evaluating solutions...") self.solutions = self.evaluate(self.solutions) - LOGGER.debug('Initializing progress') + logger.debug("Initializing progress...") self.init_progress() - LOGGER.debug('Running main loop until termination criteria is met') + logger.debug("Running main loop until termination criteria is met") while not self.stopping_condition_is_met(): self.step() self.update_progress() + logger.debug("Finished!") + self.total_computing_time = time.time() - self.start_computing_time @abstractmethod @@ -96,18 +100,13 @@ def get_name(self) -> str: class DynamicAlgorithm(Algorithm[S, R], ABC): - @abstractmethod def restart(self) -> None: pass class EvolutionaryAlgorithm(Algorithm[S, R], ABC): - - def __init__(self, - problem: Problem[S], - population_size: int, - offspring_population_size: int): + def __init__(self, problem: Problem[S], population_size: int, offspring_population_size: int): super(EvolutionaryAlgorithm, self).__init__() self.problem = problem self.population_size = population_size @@ -115,24 +114,26 @@ def __init__(self, @abstractmethod def selection(self, population: List[S]) -> List[S]: - """ Select the best-fit individuals for reproduction (parents). """ + """Select the best-fit individuals for reproduction (parents).""" pass @abstractmethod def reproduction(self, population: List[S]) -> List[S]: - """ Breed new individuals through crossover and mutation operations to give birth to offspring. """ + """Breed new individuals through crossover and mutation operations to give birth to offspring.""" pass @abstractmethod def replacement(self, population: List[S], offspring_population: List[S]) -> List[S]: - """ Replace least-fit population with new individuals. """ + """Replace least-fit population with new individuals.""" pass def get_observable_data(self) -> dict: - return {'PROBLEM': self.problem, - 'EVALUATIONS': self.evaluations, - 'SOLUTIONS': self.get_result(), - 'COMPUTING_TIME': time.time() - self.start_computing_time} + return { + "PROBLEM": self.problem, + "EVALUATIONS": self.evaluations, + "SOLUTIONS": self.get_result(), + "COMPUTING_TIME": time.time() - self.start_computing_time, + } def init_progress(self) -> None: self.evaluations = self.population_size @@ -155,14 +156,11 @@ def update_progress(self) -> None: @property def label(self) -> str: - return f'{self.get_name()}.{self.problem.get_name()}' + return f"{self.get_name()}.{self.problem.get_name()}" class ParticleSwarmOptimization(Algorithm[FloatSolution, List[FloatSolution]], ABC): - - def __init__(self, - problem: Problem[S], - swarm_size: int): + def __init__(self, problem: Problem[S], swarm_size: int): super(ParticleSwarmOptimization, self).__init__() self.problem = problem self.swarm_size = swarm_size @@ -200,10 +198,12 @@ def perturbation(self, swarm: List[FloatSolution]) -> None: pass def get_observable_data(self) -> dict: - return {'PROBLEM': self.problem, - 'EVALUATIONS': self.evaluations, - 'SOLUTIONS': self.get_result(), - 'COMPUTING_TIME': time.time() - self.start_computing_time} + return { + "PROBLEM": self.problem, + "EVALUATIONS": self.evaluations, + "SOLUTIONS": self.get_result(), + "COMPUTING_TIME": time.time() - self.start_computing_time, + } def init_progress(self) -> None: self.evaluations = self.swarm_size @@ -231,4 +231,4 @@ def update_progress(self) -> None: @property def label(self) -> str: - return f'{self.get_name()}.{self.problem.get_name()}' + return f"{self.get_name()}.{self.problem.get_name()}" diff --git a/jmetal/core/observer.py b/jmetal/core/observer.py index a8c36730..b2a0be99 100644 --- a/jmetal/core/observer.py +++ b/jmetal/core/observer.py @@ -1,4 +1,4 @@ -from abc import abstractmethod, ABC +from abc import ABC, abstractmethod """ .. module:: Observable @@ -10,16 +10,13 @@ class Observer(ABC): - @abstractmethod def update(self, *args, **kwargs): - """ Update method. - """ + """Update method.""" pass class Observable(ABC): - @abstractmethod def register(self, observer): pass @@ -35,5 +32,3 @@ def deregister_all(self): @abstractmethod def notify_all(self, *args, **kwargs): pass - - diff --git a/jmetal/core/operator.py b/jmetal/core/operator.py index d68f18d6..7a96543c 100644 --- a/jmetal/core/operator.py +++ b/jmetal/core/operator.py @@ -1,8 +1,10 @@ from abc import ABC, abstractmethod -from typing import TypeVar, Generic, List +from typing import Generic, List, TypeVar -S = TypeVar('S') -R = TypeVar('R') +from jmetal.core.solution import Solution + +S = TypeVar("S", bound=Solution) +R = TypeVar("R", bound=Solution) """ .. module:: Operator @@ -14,7 +16,7 @@ class Operator(Generic[S, R], ABC): - """ Class representing operator """ + """Class representing operator""" @abstractmethod def execute(self, source: S) -> R: @@ -28,17 +30,18 @@ def get_name(self) -> str: def check_valid_probability_value(func): def func_wrapper(self, probability: float): if probability > 1.0: - raise Exception('The probability is greater than one: {}'.format(probability)) + raise Exception("The probability is greater than one: {}".format(probability)) elif probability < 0.0: - raise Exception('The probability is lower than zero: {}'.format(probability)) + raise Exception("The probability is lower than zero: {}".format(probability)) res = func(self, probability) return res + return func_wrapper class Mutation(Operator[S, S], ABC): - """ Class representing mutation operator. """ + """Class representing mutation operator.""" @check_valid_probability_value def __init__(self, probability: float): @@ -46,7 +49,7 @@ def __init__(self, probability: float): class Crossover(Operator[List[S], List[R]], ABC): - """ Class representing crossover operator. """ + """Class representing crossover operator.""" @check_valid_probability_value def __init__(self, probability: float): @@ -62,7 +65,7 @@ def get_number_of_children(self) -> int: class Selection(Operator[S, R], ABC): - """ Class representing selection operator. """ + """Class representing selection operator.""" def __init__(self): pass diff --git a/jmetal/core/problem.py b/jmetal/core/problem.py index 9519fac5..0dc7eb43 100644 --- a/jmetal/core/problem.py +++ b/jmetal/core/problem.py @@ -1,18 +1,23 @@ -import logging import random from abc import ABC, abstractmethod -from typing import Generic, TypeVar, List +from typing import Generic, List, TypeVar from jmetal.core.observer import Observer -from jmetal.core.solution import BinarySolution, FloatSolution, IntegerSolution, PermutationSolution +from jmetal.core.solution import ( + BinarySolution, + FloatSolution, + IntegerSolution, + PermutationSolution, +) +from jmetal.logger import get_logger -LOGGER = logging.getLogger('jmetal') +logger = get_logger(__name__) -S = TypeVar('S') +S = TypeVar("S") class Problem(Generic[S], ABC): - """ Class representing problems. """ + """Class representing problems.""" MINIMIZE = -1 MAXIMIZE = 1 @@ -29,17 +34,17 @@ def __init__(self): @abstractmethod def create_solution(self) -> S: - """ Creates a random_search solution to the problem. + """Creates a random_search solution to the problem. - :return: Solution. """ + :return: Solution.""" pass @abstractmethod def evaluate(self, solution: S) -> S: - """ Evaluate a solution. For any new problem inheriting from :class:`Problem`, this method should be - replaced. Note that this framework ASSUMES minimization, thus solutions must be evaluated in consequence. + """Evaluate a solution. For any new problem inheriting from :class:`Problem`, this method should be replaced. + Note that this framework ASSUMES minimization, thus solutions must be evaluated in consequence. - :return: Evaluated solution. """ + :return: Evaluated solution.""" pass @abstractmethod @@ -48,7 +53,6 @@ def get_name(self) -> str: class DynamicProblem(Problem[S], Observer, ABC): - @abstractmethod def the_problem_has_changed(self) -> bool: pass @@ -59,14 +63,14 @@ def clear_changed(self) -> None: class BinaryProblem(Problem[BinarySolution], ABC): - """ Class representing binary problems. """ + """Class representing binary problems.""" def __init__(self): super(BinaryProblem, self).__init__() class FloatProblem(Problem[FloatSolution], ABC): - """ Class representing float problems. """ + """Class representing float problems.""" def __init__(self): super(FloatProblem, self).__init__() @@ -75,19 +79,18 @@ def __init__(self): def create_solution(self) -> FloatSolution: new_solution = FloatSolution( - self.lower_bound, - self.upper_bound, - self.number_of_objectives, - self.number_of_constraints) - new_solution.variables = \ - [random.uniform(self.lower_bound[i] * 1.0, self.upper_bound[i] * 1.0) for i in - range(self.number_of_variables)] + self.lower_bound, self.upper_bound, self.number_of_objectives, self.number_of_constraints + ) + new_solution.variables = [ + random.uniform(self.lower_bound[i] * 1.0, self.upper_bound[i] * 1.0) + for i in range(self.number_of_variables) + ] return new_solution class IntegerProblem(Problem[IntegerSolution], ABC): - """ Class representing integer problems. """ + """Class representing integer problems.""" def __init__(self): super(IntegerProblem, self).__init__() @@ -96,19 +99,18 @@ def __init__(self): def create_solution(self) -> IntegerSolution: new_solution = IntegerSolution( - self.lower_bound, - self.upper_bound, - self.number_of_objectives, - self.number_of_constraints) - new_solution.variables = \ - [int(random.uniform(self.lower_bound[i] * 1.0, self.upper_bound[i] * 1.0)) - for i in range(self.number_of_variables)] + self.lower_bound, self.upper_bound, self.number_of_objectives, self.number_of_constraints + ) + new_solution.variables = [ + round(random.uniform(self.lower_bound[i] * 1.0, self.upper_bound[i] * 1.0)) + for i in range(self.number_of_variables) + ] return new_solution class PermutationProblem(Problem[PermutationSolution], ABC): - """ Class representing permutation problems. """ + """Class representing permutation problems.""" def __init__(self): super(PermutationProblem, self).__init__() @@ -148,31 +150,31 @@ def __init__(self): self.constraints = [] self.name = None - def set_name(self, name): + def set_name(self, name) -> "OnTheFlyFloatProblem": self.name = name return self - def add_function(self, function): + def add_function(self, function) -> "OnTheFlyFloatProblem": self.functions.append(function) self.number_of_objectives += 1 return self - def add_constraint(self, constraint): + def add_constraint(self, constraint) -> "OnTheFlyFloatProblem": self.constraints.append(constraint) self.number_of_constraints += 1 return self - def add_variable(self, lower_bound, upper_bound): + def add_variable(self, lower_bound, upper_bound) -> "OnTheFlyFloatProblem": self.lower_bound.append(lower_bound) self.upper_bound.append(upper_bound) self.number_of_variables += 1 return self - def evaluate(self, solution: FloatSolution): + def evaluate(self, solution: FloatSolution) -> None: for i in range(self.number_of_objectives): solution.objectives[i] = self.functions[i](solution.variables) diff --git a/jmetal/core/quality_indicator.py b/jmetal/core/quality_indicator.py index 809ca247..b58766e9 100644 --- a/jmetal/core/quality_indicator.py +++ b/jmetal/core/quality_indicator.py @@ -5,7 +5,6 @@ class QualityIndicator(ABC): - def __init__(self, is_minimization: bool): self.is_minimization = is_minimization @@ -40,10 +39,10 @@ def compute(self, solutions: np.array): return mean def get_name(self) -> str: - return 'Fitness' + return "Fitness" def get_short_name(self) -> str: - return 'Fitness' + return "Fitness" class GenerationalDistance(QualityIndicator): @@ -57,17 +56,17 @@ def __init__(self, reference_front: np.array = None): def compute(self, solutions: np.array): if self.reference_front is None: - raise Exception('Reference front is none') + raise Exception("Reference front is none") distances = spatial.distance.cdist(solutions, self.reference_front) return np.mean(np.min(distances, axis=1)) def get_short_name(self) -> str: - return 'GD' + return "GD" def get_name(self) -> str: - return 'Generational Distance' + return "Generational Distance" class InvertedGenerationalDistance(QualityIndicator): @@ -77,17 +76,17 @@ def __init__(self, reference_front: np.array = None): def compute(self, solutions: np.array): if self.reference_front is None: - raise Exception('Reference front is none') + raise Exception("Reference front is none") distances = spatial.distance.cdist(self.reference_front, solutions) return np.mean(np.min(distances, axis=1)) def get_short_name(self) -> str: - return 'IGD' + return "IGD" def get_name(self) -> str: - return 'Inverted Generational Distance' + return "Inverted Generational Distance" class EpsilonIndicator(QualityIndicator): @@ -96,18 +95,17 @@ def __init__(self, reference_front: np.array = None): self.reference_front = reference_front def compute(self, front: np.array) -> float: - return max([min( - [max([s2[k] - s1[k] for k in range(len(s2))]) for s2 in front]) for s1 in self.reference_front]) + return max([min([max([s2[k] - s1[k] for k in range(len(s2))]) for s2 in front]) for s1 in self.reference_front]) def get_short_name(self) -> str: - return 'EP' + return "EP" def get_name(self) -> str: return "Additive Epsilon" class HyperVolume(QualityIndicator): - """ Hypervolume computation based on variant 3 of the algorithm in the paper: + """Hypervolume computation based on variant 3 of the algorithm in the paper: * C. M. Fonseca, L. Paquete, and M. Lopez-Ibanez. An improved dimension-sweep algorithm for the hypervolume indicator. In IEEE Congress on Evolutionary @@ -192,7 +190,8 @@ def _hv_recursive(self, dim_index: int, length: int, bounds: list): q = q.prev[dim_index] q = p.prev[dim_index] while length > 1 and ( - q.cargo[dim_index] > bounds[dim_index] or q.prev[dim_index].cargo[dim_index] >= bounds[dim_index]): + q.cargo[dim_index] > bounds[dim_index] or q.prev[dim_index].cargo[dim_index] >= bounds[dim_index] + ): p = q remove(p, dim_index, bounds) q = p.prev[dim_index] @@ -202,10 +201,11 @@ def _hv_recursive(self, dim_index: int, length: int, bounds: list): q_prev_dim_index = q.prev[dim_index] if length > 1: hvol = q_prev_dim_index.volume[dim_index] + q_prev_dim_index.area[dim_index] * ( - q_cargo[dim_index] - q_prev_dim_index.cargo[dim_index]) + q_cargo[dim_index] - q_prev_dim_index.cargo[dim_index] + ) else: q_area[0] = 1 - q_area[1:dim_index + 1] = [q_area[i] * -q_cargo[i] for i in range(dim_index)] + q_area[1 : dim_index + 1] = [q_area[i] * -q_cargo[i] for i in range(dim_index)] q.volume[dim_index] = hvol if q.ignore >= dim_index: q_area[dim_index] = q_prev_dim_index.area[dim_index] @@ -251,7 +251,7 @@ def _sort_by_dimension(self, nodes, i): nodes[:] = [node for (_, node) in decorated] def get_short_name(self) -> str: - return 'HV' + return "HV" def get_name(self) -> str: return "Hypervolume (Fonseca et al. implementation)" @@ -265,7 +265,6 @@ class MultiList: """ class Node: - def __init__(self, number_lists, cargo=None): self.cargo = cargo self.next = [None] * number_lists @@ -278,8 +277,7 @@ def __str__(self): return str(self.cargo) def __init__(self, number_lists): - """ Builds 'numberLists' doubly linked lists. - """ + """Builds 'numberLists' doubly linked lists.""" self.number_lists = number_lists self.sentinel = MultiList.Node(number_lists) self.sentinel.next = [self.sentinel] * number_lists @@ -314,7 +312,7 @@ def get_length(self, i): return length def append(self, node, index): - """ Appends a node to the end of the list at the given index.""" + """Appends a node to the end of the list at the given index.""" last_but_one = self.sentinel.prev[index] node.next[index] = self.sentinel node.prev[index] = last_but_one @@ -323,7 +321,7 @@ def append(self, node, index): last_but_one.next[index] = node def extend(self, nodes, index): - """ Extends the list at the given index with the nodes.""" + """Extends the list at the given index with the nodes.""" sentinel = self.sentinel for node in nodes: last_but_one = sentinel.prev[index] @@ -334,7 +332,7 @@ def extend(self, nodes, index): last_but_one.next[index] = node def remove(self, node, index, bounds): - """ Removes and returns 'node' from all lists in [0, 'index'[.""" + """Removes and returns 'node' from all lists in [0, 'index'[.""" for i in range(index): predecessor = node.prev[i] successor = node.next[i] @@ -345,7 +343,7 @@ def remove(self, node, index, bounds): return node def reinsert(self, node, index, bounds): - """ Inserts 'node' at the position it had in all lists in [0, 'index'[ + """Inserts 'node' at the position it had in all lists in [0, 'index'[ before it was removed. This method assumes that the next and previous nodes of the node that is reinserted are in the list. """ diff --git a/jmetal/core/solution.py b/jmetal/core/solution.py index 6d8a994f..ed09314a 100644 --- a/jmetal/core/solution.py +++ b/jmetal/core/solution.py @@ -1,14 +1,14 @@ from abc import ABC -from typing import List, Generic, TypeVar +from typing import Generic, List, TypeVar from jmetal.util.ckecking import Check BitSet = List[bool] -S = TypeVar('S') +S = TypeVar("S") class Solution(Generic[S], ABC): - """ Class representing solutions """ + """Class representing solutions""" def __init__(self, number_of_variables: int, number_of_objectives: int, number_of_constraints: int = 0): self.number_of_variables = number_of_variables @@ -25,20 +25,19 @@ def __eq__(self, solution) -> bool: return False def __str__(self) -> str: - return 'Solution(variables={},objectives={},constraints={})'.format(self.variables, self.objectives, - self.constraints) + return "Solution(variables={},objectives={},constraints={})".format( + self.variables, self.objectives, self.constraints + ) class BinarySolution(Solution[BitSet]): - """ Class representing float solutions """ + """Class representing float solutions""" def __init__(self, number_of_variables: int, number_of_objectives: int, number_of_constraints: int = 0): super(BinarySolution, self).__init__(number_of_variables, number_of_objectives, number_of_constraints) def __copy__(self): - new_solution = BinarySolution( - self.number_of_variables, - self.number_of_objectives) + new_solution = BinarySolution(self.number_of_variables, self.number_of_objectives) new_solution.objectives = self.objectives[:] new_solution.variables = self.variables[:] @@ -56,25 +55,28 @@ def get_total_number_of_bits(self) -> int: def get_binary_string(self) -> str: string = "" for bit in self.variables[0]: - string += '1' if bit else '0' + string += "1" if bit else "0" return string class FloatSolution(Solution[float]): - """ Class representing float solutions """ - - def __init__(self, lower_bound: List[float], upper_bound: List[float], number_of_objectives: int, - number_of_constraints: int = 0): + """Class representing float solutions""" + + def __init__( + self, + lower_bound: List[float], + upper_bound: List[float], + number_of_objectives: int, + number_of_constraints: int = 0, + ): super(FloatSolution, self).__init__(len(lower_bound), number_of_objectives, number_of_constraints) self.lower_bound = lower_bound self.upper_bound = upper_bound def __copy__(self): new_solution = FloatSolution( - self.lower_bound, - self.upper_bound, - self.number_of_objectives, - self.number_of_constraints) + self.lower_bound, self.upper_bound, self.number_of_objectives, self.number_of_constraints + ) new_solution.objectives = self.objectives[:] new_solution.variables = self.variables[:] new_solution.constraints = self.constraints[:] @@ -85,20 +87,19 @@ def __copy__(self): class IntegerSolution(Solution[int]): - """ Class representing integer solutions """ + """Class representing integer solutions""" - def __init__(self, lower_bound: List[int], upper_bound: List[int], number_of_objectives: int, - number_of_constraints: int = 0): + def __init__( + self, lower_bound: List[int], upper_bound: List[int], number_of_objectives: int, number_of_constraints: int = 0 + ): super(IntegerSolution, self).__init__(len(lower_bound), number_of_objectives, number_of_constraints) self.lower_bound = lower_bound self.upper_bound = upper_bound def __copy__(self): new_solution = IntegerSolution( - self.lower_bound, - self.upper_bound, - self.number_of_objectives, - self.number_of_constraints) + self.lower_bound, self.upper_bound, self.number_of_objectives, self.number_of_constraints + ) new_solution.objectives = self.objectives[:] new_solution.variables = self.variables[:] new_solution.constraints = self.constraints[:] @@ -109,7 +110,7 @@ def __copy__(self): class CompositeSolution(Solution): - """ Class representing solutions composed of a list of solutions. The idea is that each decision variable can + """Class representing solutions composed of a list of solutions. The idea is that each decision variable can be a solution of any type, so we can create mixed solutions (e.g., solutions combining any of the existing encodings). The adopted approach has the advantage of easing the reuse of existing variation operators, but all the solutions in the list will need to have the same function and constraint violation values. @@ -118,18 +119,23 @@ class CompositeSolution(Solution): """ def __init__(self, solutions: List[Solution]): - super(CompositeSolution, self).__init__(len(solutions), solutions[0].number_of_objectives, - solutions[0].number_of_constraints) + super(CompositeSolution, self).__init__( + len(solutions), solutions[0].number_of_objectives, solutions[0].number_of_constraints + ) Check.is_not_none(solutions) Check.collection_is_not_empty(solutions) for solution in solutions: - Check.that(solution.number_of_objectives == solutions[0].number_of_objectives, - "The solutions in the list must have the same number of objectives: " + str( - solutions[0].number_of_objectives)) - Check.that(solution.number_of_constraints == solutions[0].number_of_constraints, - "The solutions in the list must have the same number of constraints: " + str( - solutions[0].number_of_constraints)) + Check.that( + solution.number_of_objectives == solutions[0].number_of_objectives, + "The solutions in the list must have the same number of objectives: " + + str(solutions[0].number_of_objectives), + ) + Check.that( + solution.number_of_constraints == solutions[0].number_of_constraints, + "The solutions in the list must have the same number of constraints: " + + str(solutions[0].number_of_constraints), + ) self.variables = solutions @@ -144,15 +150,13 @@ def __copy__(self): class PermutationSolution(Solution): - """ Class representing permutation solutions """ + """Class representing permutation solutions""" def __init__(self, number_of_variables: int, number_of_objectives: int, number_of_constraints: int = 0): super(PermutationSolution, self).__init__(number_of_variables, number_of_objectives, number_of_constraints) def __copy__(self): - new_solution = PermutationSolution( - self.number_of_variables, - self.number_of_objectives) + new_solution = PermutationSolution(self.number_of_variables, self.number_of_objectives) new_solution.objectives = self.objectives[:] new_solution.variables = self.variables[:] diff --git a/jmetal/core/test/test_observable.py b/jmetal/core/test/test_observable.py index 6ef40ea1..874799d3 100644 --- a/jmetal/core/test/test_observable.py +++ b/jmetal/core/test/test_observable.py @@ -4,16 +4,15 @@ from jmetal.util.observable import DefaultObservable -class ObservableTestCases(unittest.TestCase): - - class DummyObserver(Observer): +class DummyObserver(Observer): + def update(self, *args, **kwargs): + pass - def update(self, *args, **kwargs): - pass +class ObservableTestCases(unittest.TestCase): def setUp(self): self.observable = DefaultObservable() - self.observer = self.DummyObserver() + self.observer = DummyObserver() def test_should_register_add_one_observer(self): self.observable.register(self.observer) @@ -21,7 +20,7 @@ def test_should_register_add_one_observer(self): self.assertEqual(1, len(self.observable.observers)) def test_should_register_add_two_observers(self): - observer_two = self.DummyObserver() + observer_two = DummyObserver() self.observable.register(self.observer) self.observable.register(observer_two) @@ -29,7 +28,7 @@ def test_should_register_add_two_observers(self): self.assertEqual(2, len(self.observable.observers)) def test_should_deregister_remove_the_observer_if_it_is_registered(self): - observer_two = self.DummyObserver() + observer_two = DummyObserver() self.observable.register(self.observer) self.observable.register(observer_two) @@ -38,7 +37,7 @@ def test_should_deregister_remove_the_observer_if_it_is_registered(self): self.assertEqual(1, len(self.observable.observers)) def test_should_deregister_not_remove_the_observer_if_it_is_not_registered(self): - observer_two = self.DummyObserver() + observer_two = DummyObserver() self.observable.register(self.observer) self.observable.deregister(observer_two) diff --git a/jmetal/core/test/test_operator.py b/jmetal/core/test/test_operator.py index 6604bca9..8b7bbe53 100644 --- a/jmetal/core/test/test_operator.py +++ b/jmetal/core/test/test_operator.py @@ -1,39 +1,32 @@ import unittest -from typing import TypeVar -from jmetal.core.operator import Mutation, Crossover +from jmetal.core.operator import Crossover, Mutation from jmetal.core.solution import Solution -S = TypeVar('S') -R = TypeVar('R') - - -class DummyMutation(Mutation[Solution]): +class DummyMutation(Mutation): def __init__(self, probability: float): super(DummyMutation, self).__init__(probability=probability) - def execute(self, source: Solution) -> Solution: - return None + def execute(self, source: Solution) -> None: + pass def get_name(self) -> str: - return "" + pass -class DummyCrossover(Crossover[Solution, Solution]): - +class DummyCrossover(Crossover): def __init__(self, probability: float): super(DummyCrossover, self).__init__(probability=probability) - def execute(self, source: Solution) -> Solution: - return None + def execute(self, source: Solution) -> None: + pass def get_name(self) -> str: - return "" + pass class OperatorTestCase(unittest.TestCase): - def test_should_mutation_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): DummyMutation(-1) @@ -51,5 +44,5 @@ def test_should_crossover_constructor_raises_an_exception_is_probability_is_high DummyMutation(1.1) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/core/test/test_problem.py b/jmetal/core/test/test_problem.py index ed8c5472..86c51d06 100644 --- a/jmetal/core/test/test_problem.py +++ b/jmetal/core/test/test_problem.py @@ -5,7 +5,6 @@ class DummyIntegerProblem(IntegerProblem): - def __init__(self): super(DummyIntegerProblem, self).__init__() @@ -17,7 +16,6 @@ def get_name(self) -> str: class DummyFloatProblem(FloatProblem): - def __init__(self): super(DummyFloatProblem, self).__init__() @@ -29,8 +27,7 @@ def get_name(self) -> str: class FloatProblemTestCases(unittest.TestCase): - - def test_should_default_constructor_create_a_valid_problem(self) -> None: + def test_should_default_constructor_create_a_valid_problem(self): number_of_objectives = 2 number_of_constraints = 0 lower_bound = [-1.0] @@ -49,7 +46,7 @@ def test_should_default_constructor_create_a_valid_problem(self) -> None: self.assertEqual([-1], problem.lower_bound) self.assertEqual([1], problem.upper_bound) - def test_should_create_solution_create_a_valid_solution(self) -> None: + def test_should_create_solution_create_a_valid_solution(self): problem = DummyFloatProblem() problem.number_of_variables = 2 problem.number_of_objectives = 2 @@ -64,8 +61,7 @@ def test_should_create_solution_create_a_valid_solution(self) -> None: class IntegerProblemTestCases(unittest.TestCase): - - def test_should_default_constructor_create_a_valid_problem(self) -> None: + def test_should_default_constructor_create_a_valid_problem(self): problem = DummyIntegerProblem() problem.number_of_variables = 1 problem.number_of_objectives = 2 @@ -79,7 +75,7 @@ def test_should_default_constructor_create_a_valid_problem(self) -> None: self.assertEqual([-1], problem.lower_bound) self.assertEqual([1], problem.upper_bound) - def test_should_create_solution_create_a_valid_solution(self) -> None: + def test_should_create_solution_create_a_valid_solution(self): problem = DummyIntegerProblem() problem.number_of_variables = 2 problem.number_of_objectives = 2 @@ -93,5 +89,5 @@ def test_should_create_solution_create_a_valid_solution(self) -> None: self.assertTrue(-2 <= solution.variables[1] <= 2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/core/test/test_quality_indicator.py b/jmetal/core/test/test_quality_indicator.py index f1c82048..b6b3b343 100644 --- a/jmetal/core/test/test_quality_indicator.py +++ b/jmetal/core/test/test_quality_indicator.py @@ -1,16 +1,20 @@ +import os import unittest -from os.path import dirname, join from pathlib import Path import numpy as np -from jmetal.core.quality_indicator import GenerationalDistance, InvertedGenerationalDistance, EpsilonIndicator, \ - HyperVolume +from jmetal.core.quality_indicator import ( + EpsilonIndicator, + GenerationalDistance, + HyperVolume, + InvertedGenerationalDistance, +) + +DIRNAME = os.path.dirname(os.path.abspath(__file__)) -class GenerationalDistanceTestCases(unittest.TestCase): - """ Class including unit tests for class GenerationalDistance - """ +class GenerationalDistanceTestCases(unittest.TestCase): def test_should_constructor_create_a_non_null_object(self) -> None: indicator = GenerationalDistance([]) self.assertIsNotNone(indicator) @@ -132,9 +136,6 @@ def test_case7(self): class InvertedGenerationalDistanceTestCases(unittest.TestCase): - """ Class including unit tests for class InvertedGenerationalDistance - """ - def test_should_constructor_create_a_non_null_object(self) -> None: indicator = InvertedGenerationalDistance([]) self.assertIsNotNone(indicator) @@ -231,19 +232,12 @@ def test_case5(self): class EpsilonIndicatorTestCases(unittest.TestCase): - """ Class including unit tests for class EpsilonIndicator - """ - def test_should_constructor_create_a_non_null_object(self) -> None: indicator = EpsilonIndicator(np.array([[1.0, 1.0], [2.0, 2.0]])) self.assertIsNotNone(indicator) class HyperVolumeTestCases(unittest.TestCase): - - def setUp(self): - self.file_path = dirname(join(dirname(__file__))) - def test_should_hypervolume_return_5_0(self): reference_point = [2, 2, 2] @@ -255,15 +249,13 @@ def test_should_hypervolume_return_5_0(self): self.assertEqual(5.0, value) def test_should_hypervolume_return_the_correct_value_when_applied_to_the_ZDT1_reference_front(self): - filename = 'jmetal/core/test/ZDT1.pf' + filepath = Path(DIRNAME, "ZDT1.pf") front = [] - if Path(filename).is_file(): - with open(filename) as file: - for line in file: - vector = [float(x) for x in line.split()] - front.append(vector) - else: - print("error") + + with open(filepath) as file: + for line in file: + vector = [float(x) for x in line.split()] + front.append(vector) reference_point = [1, 1] @@ -273,5 +265,5 @@ def test_should_hypervolume_return_the_correct_value_when_applied_to_the_ZDT1_re self.assertAlmostEqual(0.666, value, delta=0.001) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/core/test/test_solution.py b/jmetal/core/test/test_solution.py index 2b005bee..afd62af6 100644 --- a/jmetal/core/test/test_solution.py +++ b/jmetal/core/test/test_solution.py @@ -1,13 +1,18 @@ import copy import unittest -from jmetal.core.solution import BinarySolution, FloatSolution, IntegerSolution, Solution, CompositeSolution +from jmetal.core.solution import ( + BinarySolution, + CompositeSolution, + FloatSolution, + IntegerSolution, + Solution, +) from jmetal.util.ckecking import InvalidConditionException class SolutionTestCase(unittest.TestCase): - - def test_should_default_constructor_create_a_valid_solution(self) -> None: + def test_should_default_constructor_create_a_valid_solution(self): solution = Solution(2, 3) self.assertEqual(2, solution.number_of_variables) self.assertEqual(3, solution.number_of_objectives) @@ -17,12 +22,12 @@ def test_should_default_constructor_create_a_valid_solution(self) -> None: class BinarySolutionTestCase(unittest.TestCase): - def test_should_default_constructor_create_a_valid_solution(self) -> None: + def test_should_default_constructor_create_a_valid_solution(self): solution = BinarySolution(2, 3) self.assertEqual(2, solution.number_of_variables) self.assertEqual(3, solution.number_of_objectives) - def test_should_constructor_create_a_valid_solution(self) -> None: + def test_should_constructor_create_a_valid_solution(self): solution = BinarySolution(number_of_variables=2, number_of_objectives=3) solution.variables[0] = [True, False] solution.variables[1] = [False] @@ -33,7 +38,7 @@ def test_should_constructor_create_a_valid_solution(self) -> None: self.assertEqual([True, False], solution.variables[0]) self.assertEqual([False], solution.variables[1]) - def test_should_get_total_number_of_bits_return_zero_if_the_object_variables_are_not_initialized(self) -> None: + def test_should_get_total_number_of_bits_return_zero_if_the_object_variables_are_not_initialized(self): solution = BinarySolution(number_of_variables=2, number_of_objectives=3) self.assertEqual(0, solution.get_total_number_of_bits()) @@ -45,12 +50,11 @@ def test_should_get_total_number_of_bits_return_the_right_value(self) -> None: class FloatSolutionTestCase(unittest.TestCase): - - def test_should_constructor_create_a_non_null_object(self) -> None: + def test_should_constructor_create_a_non_null_object(self): solution = FloatSolution([], [], 2) self.assertIsNotNone(solution) - def test_should_default_constructor_create_a_valid_solution(self) -> None: + def test_should_default_constructor_create_a_valid_solution(self): solution = FloatSolution([0.0, 0.5], [1.0, 2.0], 3) self.assertEqual(2, solution.number_of_variables) @@ -82,12 +86,11 @@ def test_should_copy_work_properly(self) -> None: class IntegerSolutionTestCase(unittest.TestCase): - - def test_should_constructor_create_a_non_null_object(self) -> None: + def test_should_constructor_create_a_non_null_object(self): solution = IntegerSolution([], [], 2) self.assertIsNotNone(solution) - def test_should_default_constructor_create_a_valid_solution(self) -> None: + def test_should_default_constructor_create_a_valid_solution(self): solution = IntegerSolution([0, 5], [1, 2], 3, 0) self.assertEqual(2, solution.number_of_variables) @@ -98,7 +101,7 @@ def test_should_default_constructor_create_a_valid_solution(self) -> None: self.assertEqual([0, 5], solution.lower_bound) self.assertEqual([1, 2], solution.upper_bound) - def test_should_copy_work_properly(self) -> None: + def test_should_copy_work_properly(self): solution = IntegerSolution([0, 5], [1, 2], 3, 1) solution.variables = [1, 2] solution.objectives = [0.16, -2.34, 9.25] @@ -125,8 +128,8 @@ def test_should_constructor_create_a_valid_not_none_composite_solution_composed_ self.assertIsNotNone(composite_solution) def test_should_constructor_raise_an_exception_if_the_number_of_objectives_is_not_coherent(self): - float_solution: FloatSolution = FloatSolution([1.0], [3.0], 3) - integer_solution: IntegerSolution = IntegerSolution([2], [4], 2) + float_solution = FloatSolution([1.0], [3.0], 3) + integer_solution = IntegerSolution([2], [4], 2) with self.assertRaises(InvalidConditionException): CompositeSolution([float_solution, integer_solution]) @@ -134,10 +137,11 @@ def test_should_constructor_raise_an_exception_if_the_number_of_objectives_is_no def test_should_constructor_create_a_valid_soltion_composed_of_a_float_and_an_integer_solutions(self): number_of_objectives = 3 number_of_constraints = 1 - float_solution: FloatSolution = FloatSolution([1.0], [3.0], number_of_objectives, number_of_constraints) - integer_solution: IntegerSolution = IntegerSolution([2], [4], number_of_objectives, number_of_constraints) - solution: CompositeSolution = CompositeSolution([float_solution, integer_solution]) + float_solution = FloatSolution([1.0], [3.0], number_of_objectives, number_of_constraints) + integer_solution = IntegerSolution([2], [4], number_of_objectives, number_of_constraints) + + solution = CompositeSolution([float_solution, integer_solution]) self.assertIsNotNone(solution) self.assertEqual(2, solution.number_of_variables) @@ -153,11 +157,11 @@ def test_should_constructor_create_a_valid_soltion_composed_of_a_float_and_an_in def test_should_copy_work_properly(self): number_of_objectives = 3 number_of_constraints = 1 - float_solution: FloatSolution = FloatSolution([1.0], [3.0], number_of_objectives, number_of_constraints) - integer_solution: IntegerSolution = IntegerSolution([2], [4], number_of_objectives, number_of_constraints) + float_solution = FloatSolution([1.0], [3.0], number_of_objectives, number_of_constraints) + integer_solution = IntegerSolution([2], [4], number_of_objectives, number_of_constraints) - solution: CompositeSolution = CompositeSolution([float_solution, integer_solution]) - new_solution: CompositeSolution = copy.deepcopy(solution) + solution = CompositeSolution([float_solution, integer_solution]) + new_solution = copy.deepcopy(solution) self.assertEqual(solution.number_of_variables, new_solution.number_of_variables) self.assertEqual(solution.number_of_objectives, new_solution.number_of_objectives) @@ -172,5 +176,5 @@ def test_should_copy_work_properly(self): self.assertEqual(solution.variables[1].variables, new_solution.variables[1].variables) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/lab/experiment.py b/jmetal/lab/experiment.py index 8beb2a40..17298e62 100644 --- a/jmetal/lab/experiment.py +++ b/jmetal/lab/experiment.py @@ -1,5 +1,4 @@ import io -import logging import os from concurrent.futures import ProcessPoolExecutor from pathlib import Path @@ -13,9 +12,14 @@ from jmetal.core.algorithm import Algorithm from jmetal.core.quality_indicator import QualityIndicator -from jmetal.util.solution import print_function_values_to_file, print_variables_to_file, read_solutions +from jmetal.logger import get_logger +from jmetal.util.solution import ( + print_function_values_to_file, + print_variables_to_file, + read_solutions, +) -LOGGER = logging.getLogger('jmetal') +logger = get_logger(__name__) """ .. module:: laboratory @@ -27,32 +31,30 @@ class Job: - def __init__(self, algorithm: Algorithm, algorithm_tag: str, problem_tag: str, run: int): self.algorithm = algorithm self.algorithm_tag = algorithm_tag self.problem_tag = problem_tag self.run_tag = run - def execute(self, output_path: str = ''): + def execute(self, output_path: str = ""): self.algorithm.run() if output_path: - file_name = os.path.join(output_path, 'FUN.{}.tsv'.format(self.run_tag)) + file_name = os.path.join(output_path, "FUN.{}.tsv".format(self.run_tag)) print_function_values_to_file(self.algorithm.get_result(), filename=file_name) - file_name = os.path.join(output_path, 'VAR.{}.tsv'.format(self.run_tag)) + file_name = os.path.join(output_path, "VAR.{}.tsv".format(self.run_tag)) print_variables_to_file(self.algorithm.get_result(), filename=file_name) - file_name = os.path.join(output_path, 'TIME.{}'.format(self.run_tag)) - with open(file_name, 'w+') as of: + file_name = os.path.join(output_path, "TIME.{}".format(self.run_tag)) + with open(file_name, "w+") as of: of.write(str(self.algorithm.total_computing_time)) class Experiment: - def __init__(self, output_dir: str, jobs: List[Job], m_workers: int = 6): - """ Run an experiment to execute a list of jobs. + """Run an experiment to execute a list of jobs. :param output_dir: Base directory where each job will save its results. :param jobs: List of Jobs (from :py:mod:`jmetal.util.laboratory)`) to be executed. @@ -69,9 +71,10 @@ def run(self) -> None: executor.submit(job.execute(output_path)) -def generate_summary_from_experiment(input_dir: str, quality_indicators: List[QualityIndicator], - reference_fronts: str = ''): - """ Compute a list of quality indicators. The input data directory *must* met the following structure (this is generated +def generate_summary_from_experiment( + input_dir: str, quality_indicators: List[QualityIndicator], reference_fronts: str = "" +): + """Compute a list of quality indicators. The input data directory *must* met the following structure (this is generated automatically by the Experiment class): * @@ -95,36 +98,36 @@ def generate_summary_from_experiment(input_dir: str, quality_indicators: List[Qu if not quality_indicators: quality_indicators = [] - with open('QualityIndicatorSummary.csv', 'w+') as of: - of.write('Algorithm,Problem,ExecutionId,IndicatorName,IndicatorValue\n') + with open("QualityIndicatorSummary.csv", "w+") as of: + of.write("Algorithm,Problem,ExecutionId,IndicatorName,IndicatorValue\n") for dirname, _, filenames in os.walk(input_dir): for filename in filenames: try: # Linux filesystem - algorithm, problem = dirname.split('/')[-2:] + algorithm, problem = dirname.split("/")[-2:] except ValueError: # Windows filesystem - algorithm, problem = dirname.split('\\')[-2:] + algorithm, problem = dirname.split("\\")[-2:] - if 'TIME' in filename: - run_tag = [s for s in filename.split('.') if s.isdigit()].pop() + if "TIME" in filename: + run_tag = [s for s in filename.split(".") if s.isdigit()].pop() - with open(os.path.join(dirname, filename), 'r') as content_file: + with open(os.path.join(dirname, filename), "r") as content_file: content = content_file.read() - with open('QualityIndicatorSummary.csv', 'a+') as of: - of.write(','.join([algorithm, problem, run_tag, 'Time', str(content)])) - of.write('\n') + with open("QualityIndicatorSummary.csv", "a+") as of: + of.write(",".join([algorithm, problem, run_tag, "Time", str(content)])) + of.write("\n") - if 'FUN' in filename: + if "FUN" in filename: solutions = read_solutions(os.path.join(dirname, filename)) - run_tag = [s for s in filename.split('.') if s.isdigit()].pop() + run_tag = [s for s in filename.split(".") if s.isdigit()].pop() for indicator in quality_indicators: - reference_front_file = os.path.join(reference_fronts, problem + '.pf') + reference_front_file = os.path.join(reference_fronts, problem + ".pf") # Add reference front if any - if hasattr(indicator, 'reference_front'): + if hasattr(indicator, "reference_front"): if Path(reference_front_file).is_file(): reference_front = [] with open(reference_front_file) as file: @@ -133,18 +136,18 @@ def generate_summary_from_experiment(input_dir: str, quality_indicators: List[Qu indicator.reference_front = reference_front else: - LOGGER.warning('Reference front not found at', reference_front_file) + logger.warning("Reference front not found at", reference_front_file) result = indicator.compute([solutions[i].objectives for i in range(len(solutions))]) # Save quality indicator value to file - with open('QualityIndicatorSummary.csv', 'a+') as of: - of.write(','.join([algorithm, problem, run_tag, indicator.get_short_name(), str(result)])) - of.write('\n') + with open("QualityIndicatorSummary.csv", "a+") as of: + of.write(",".join([algorithm, problem, run_tag, indicator.get_short_name(), str(result)])) + of.write("\n") -def generate_boxplot(filename: str, output_dir: str = 'boxplot'): - """ Generate boxplot diagrams. +def generate_boxplot(filename: str, output_dir: str = "boxplot"): + """Generate boxplot diagrams. :param filename: Input filename (summary). :param output_dir: Output path. @@ -152,31 +155,32 @@ def generate_boxplot(filename: str, output_dir: str = 'boxplot'): df = pd.read_csv(filename, skipinitialspace=True) if len(set(df.columns.tolist())) != 5: - raise Exception('Wrong number of columns') + raise Exception("Wrong number of columns") if Path(output_dir).is_dir(): - LOGGER.warning('Directory {} exists. Removing contents.'.format(output_dir)) + logger.warning("Directory {} exists. Removing contents.".format(output_dir)) for file in os.listdir(output_dir): - os.remove('{0}/{1}'.format(output_dir, file)) + os.remove("{0}/{1}".format(output_dir, file)) else: - LOGGER.warning('Directory {} does not exist. Creating it.'.format(output_dir)) + logger.warning("Directory {} does not exist. Creating it.".format(output_dir)) Path(output_dir).mkdir(parents=True) - algorithms = pd.unique(df['Algorithm']) - problems = pd.unique(df['Problem']) - indicators = pd.unique(df['IndicatorName']) + algorithms = pd.unique(df["Algorithm"]) + problems = pd.unique(df["Problem"]) + indicators = pd.unique(df["IndicatorName"]) # We consider the quality indicator indicator_name for indicator_name in indicators: - data = df[df['IndicatorName'] == indicator_name] + data = df[df["IndicatorName"] == indicator_name] for pr in problems: data_to_plot = [] for alg in algorithms: - data_to_plot.append(data['IndicatorValue'][np.logical_and( - data['Algorithm'] == alg, data['Problem'] == pr)]) + data_to_plot.append( + data["IndicatorValue"][np.logical_and(data["Algorithm"] == alg, data["Problem"] == pr)] + ) # Create a figure instance fig = plt.figure(1, figsize=(9, 6)) @@ -188,13 +192,13 @@ def generate_boxplot(filename: str, output_dir: str = 'boxplot'): ax.set_xticklabels(algorithms) ax.tick_params(labelsize=20) - plt.savefig(os.path.join(output_dir, 'boxplot-{}-{}.png'.format(pr, indicator_name)), bbox_inches='tight') - plt.savefig(os.path.join(output_dir, 'boxplot-{}-{}.eps'.format(pr, indicator_name)), bbox_inches='tight') + plt.savefig(os.path.join(output_dir, "boxplot-{}-{}.png".format(pr, indicator_name)), bbox_inches="tight") + plt.savefig(os.path.join(output_dir, "boxplot-{}-{}.eps".format(pr, indicator_name)), bbox_inches="tight") plt.close(fig) -def generate_latex_tables(filename: str, output_dir: str = 'latex/statistical'): - """ Computes a number of statistical values (mean, median, standard deviation, interquartile range). +def generate_latex_tables(filename: str, output_dir: str = "latex/statistical"): + """Computes a number of statistical values (mean, median, standard deviation, interquartile range). :param filename: Input filename (summary). :param output_dir: Output path. @@ -202,24 +206,24 @@ def generate_latex_tables(filename: str, output_dir: str = 'latex/statistical'): df = pd.read_csv(filename, skipinitialspace=True) if len(set(df.columns.tolist())) != 5: - raise Exception('Wrong number of columns') + raise Exception("Wrong number of columns") if Path(output_dir).is_dir(): - LOGGER.warning('Directory {} exists. Removing contents.'.format(output_dir)) + logger.warning("Directory {} exists. Removing contents.".format(output_dir)) for file in os.listdir(output_dir): - os.remove('{0}/{1}'.format(output_dir, file)) + os.remove("{0}/{1}".format(output_dir, file)) else: - LOGGER.warning('Directory {} does not exist. Creating it.'.format(output_dir)) + logger.warning("Directory {} does not exist. Creating it.".format(output_dir)) Path(output_dir).mkdir(parents=True) # Generate median & iqr tables median, iqr = pd.DataFrame(), pd.DataFrame() mean, std = pd.DataFrame(), pd.DataFrame() - for algorithm_name, subset in df.groupby('Algorithm', sort=False): - subset = subset.drop('Algorithm', axis=1) - subset = subset.rename(columns={'IndicatorValue': algorithm_name}) - subset = subset.set_index(['Problem', 'IndicatorName', 'ExecutionId']) + for algorithm_name, subset in df.groupby("Algorithm", sort=False): + subset = subset.drop("Algorithm", axis=1) + subset = subset.rename(columns={"IndicatorValue": algorithm_name}) + subset = subset.set_index(["Problem", "IndicatorName", "ExecutionId"]) # Compute Median and Interquartile range median_ = subset.groupby(level=[0, 1]).median() @@ -236,63 +240,63 @@ def generate_latex_tables(filename: str, output_dir: str = 'latex/statistical'): std = pd.concat([std, std_], axis=1) # Generate mean & std tables - for indicator_name, subset in std.groupby('IndicatorName', sort=False): - subset = median.groupby('IndicatorName', sort=False).get_group(indicator_name) + for indicator_name, subset in std.groupby("IndicatorName", sort=False): + subset = median.groupby("IndicatorName", sort=False).get_group(indicator_name) subset.index = subset.index.droplevel(1) - subset.to_csv(os.path.join(output_dir, 'Median-{}.csv'.format(indicator_name)), sep='\t', encoding='utf-8') + subset.to_csv(os.path.join(output_dir, "Median-{}.csv".format(indicator_name)), sep="\t", encoding="utf-8") - subset = iqr.groupby('IndicatorName', sort=False).get_group(indicator_name) + subset = iqr.groupby("IndicatorName", sort=False).get_group(indicator_name) subset.index = subset.index.droplevel(1) - subset.to_csv(os.path.join(output_dir, 'IQR-{}.csv'.format(indicator_name)), sep='\t', encoding='utf-8') + subset.to_csv(os.path.join(output_dir, "IQR-{}.csv".format(indicator_name)), sep="\t", encoding="utf-8") - subset = mean.groupby('IndicatorName', sort=False).get_group(indicator_name) + subset = mean.groupby("IndicatorName", sort=False).get_group(indicator_name) subset.index = subset.index.droplevel(1) - subset.to_csv(os.path.join(output_dir, 'Mean-{}.csv'.format(indicator_name)), sep='\t', encoding='utf-8') + subset.to_csv(os.path.join(output_dir, "Mean-{}.csv".format(indicator_name)), sep="\t", encoding="utf-8") - subset = std.groupby('IndicatorName', sort=False).get_group(indicator_name) + subset = std.groupby("IndicatorName", sort=False).get_group(indicator_name) subset.index = subset.index.droplevel(1) - subset.to_csv(os.path.join(output_dir, 'Std-{}.csv'.format(indicator_name)), sep='\t', encoding='utf-8') + subset.to_csv(os.path.join(output_dir, "Std-{}.csv".format(indicator_name)), sep="\t", encoding="utf-8") # Generate LaTeX tables - for indicator_name in df.groupby('IndicatorName', sort=False).groups.keys(): + for indicator_name in df.groupby("IndicatorName", sort=False).groups.keys(): # Median & IQR - md = median.groupby('IndicatorName', sort=False).get_group(indicator_name) + md = median.groupby("IndicatorName", sort=False).get_group(indicator_name) md.index = md.index.droplevel(1) - i = iqr.groupby('IndicatorName', sort=False).get_group(indicator_name) + i = iqr.groupby("IndicatorName", sort=False).get_group(indicator_name) i.index = i.index.droplevel(1) - with open(os.path.join(output_dir, 'MedianIQR-{}.tex'.format(indicator_name)), 'w') as latex: + with open(os.path.join(output_dir, "MedianIQR-{}.tex".format(indicator_name)), "w") as latex: latex.write( __averages_to_latex( md, i, - caption='Median and Interquartile Range of the {} quality indicator.'.format(indicator_name), + caption="Median and Interquartile Range of the {} quality indicator.".format(indicator_name), minimization=check_minimization(indicator_name), - label='table:{}'.format(indicator_name) + label="table:{}".format(indicator_name), ) ) # Mean & Std - mn = mean.groupby('IndicatorName', sort=False).get_group(indicator_name) + mn = mean.groupby("IndicatorName", sort=False).get_group(indicator_name) mn.index = mn.index.droplevel(1) - s = std.groupby('IndicatorName', sort=False).get_group(indicator_name) + s = std.groupby("IndicatorName", sort=False).get_group(indicator_name) s.index = s.index.droplevel(1) - with open(os.path.join(output_dir, 'MeanStd-{}.tex'.format(indicator_name)), 'w') as latex: + with open(os.path.join(output_dir, "MeanStd-{}.tex".format(indicator_name)), "w") as latex: latex.write( __averages_to_latex( mn, s, - caption='Mean and Standard Deviation of the {} quality indicator.'.format(indicator_name), + caption="Mean and Standard Deviation of the {} quality indicator.".format(indicator_name), minimization=check_minimization(indicator_name), - label='table:{}'.format(indicator_name) + label="table:{}".format(indicator_name), ) ) -def compute_wilcoxon(filename: str, output_dir: str = 'latex/wilcoxon'): +def compute_wilcoxon(filename: str, output_dir: str = "latex/wilcoxon"): """ :param filename: Input filename (summary). :param output_dir: Output path. @@ -300,19 +304,19 @@ def compute_wilcoxon(filename: str, output_dir: str = 'latex/wilcoxon'): df = pd.read_csv(filename, skipinitialspace=True) if len(set(df.columns.tolist())) != 5: - raise Exception('Wrong number of columns') + raise Exception("Wrong number of columns") if Path(output_dir).is_dir(): - LOGGER.warning('Directory {} exists. Removing contents.'.format(output_dir)) + logger.warning("Directory {} exists. Removing contents.".format(output_dir)) for file in os.listdir(output_dir): - os.remove('{0}/{1}'.format(output_dir, file)) + os.remove("{0}/{1}".format(output_dir, file)) else: - LOGGER.warning('Directory {} does not exist. Creating it.'.format(output_dir)) + logger.warning("Directory {} does not exist. Creating it.".format(output_dir)) Path(output_dir).mkdir(parents=True) - algorithms = pd.unique(df['Algorithm']) - problems = pd.unique(df['Problem']) - indicators = pd.unique(df['IndicatorName']) + algorithms = pd.unique(df["Algorithm"]) + problems = pd.unique(df["Problem"]) + indicators = pd.unique(df["IndicatorName"]) table = pd.DataFrame(index=algorithms[0:-1], columns=algorithms[1:]) @@ -324,10 +328,16 @@ def compute_wilcoxon(filename: str, output_dir: str = 'latex/wilcoxon'): if i <= j: for problem in problems: - df1 = df[(df["Algorithm"] == row_algorithm) & (df["Problem"] == problem) & ( - df["IndicatorName"] == indicator_name)] - df2 = df[(df["Algorithm"] == col_algorithm) & (df["Problem"] == problem) & ( - df["IndicatorName"] == indicator_name)] + df1 = df[ + (df["Algorithm"] == row_algorithm) + & (df["Problem"] == problem) + & (df["IndicatorName"] == indicator_name) + ] + df2 = df[ + (df["Algorithm"] == col_algorithm) + & (df["Problem"] == problem) + & (df["IndicatorName"] == indicator_name) + ] data1 = df1["IndicatorValue"] data2 = df2["IndicatorValue"] @@ -340,49 +350,51 @@ def compute_wilcoxon(filename: str, output_dir: str = 'latex/wilcoxon'): if p <= 0.05: if check_minimization(indicator_name): if median1 <= median2: - line.append('+') + line.append("+") else: - line.append('o') + line.append("o") else: if median1 >= median2: - line.append('+') + line.append("+") else: - line.append('o') + line.append("o") else: - line.append('-') - wilcoxon.append(''.join(line)) + line.append("-") + wilcoxon.append("".join(line)) - if len(wilcoxon) < len(algorithms): wilcoxon = [''] * (len(algorithms) - len(wilcoxon) - 1) + wilcoxon + if len(wilcoxon) < len(algorithms): + wilcoxon = [""] * (len(algorithms) - len(wilcoxon) - 1) + wilcoxon table.loc[row_algorithm] = wilcoxon - table.to_csv(os.path.join(output_dir, 'Wilcoxon-{}.csv'.format(indicator_name)), sep='\t', encoding='utf-8') + table.to_csv(os.path.join(output_dir, "Wilcoxon-{}.csv".format(indicator_name)), sep="\t", encoding="utf-8") - with open(os.path.join(output_dir, 'Wilcoxon-{}.tex'.format(indicator_name)), 'w') as latex: + with open(os.path.join(output_dir, "Wilcoxon-{}.tex".format(indicator_name)), "w") as latex: latex.write( __wilcoxon_to_latex( table, - caption='Wilcoxon values of the {} quality indicator ({}).'.format(indicator_name, - ', '.join(problems)), - label='table:{}'.format(indicator_name) + caption="Wilcoxon values of the {} quality indicator ({}).".format( + indicator_name, ", ".join(problems) + ), + label="table:{}".format(indicator_name), ) ) def compute_mean_indicator(filename: str, indicator_name: str): - """ Compute the mean values of an indicator. + """Compute the mean values of an indicator. :param filename: :param indicator_name: Quality indicator name. """ df = pd.read_csv(filename, skipinitialspace=True) if len(set(df.columns.tolist())) != 5: - raise Exception('Wrong number of columns') + raise Exception("Wrong number of columns") - algorithms = pd.unique(df['Algorithm']) - problems = pd.unique(df['Problem']) + algorithms = pd.unique(df["Algorithm"]) + problems = pd.unique(df["Problem"]) # We consider the quality indicator indicator_name - data = df[df['IndicatorName'] == indicator_name] + data = df[df["IndicatorName"] == indicator_name] # Compute for each pair algorithm/problem the average of IndicatorValue average_values = np.zeros((problems.size, algorithms.size)) @@ -390,8 +402,9 @@ def compute_mean_indicator(filename: str, indicator_name: str): for alg in algorithms: i = 0 for pr in problems: - average_values[i, j] = data['IndicatorValue'][np.logical_and( - data['Algorithm'] == alg, data['Problem'] == pr)].mean() + average_values[i, j] = data["IndicatorValue"][ + np.logical_and(data["Algorithm"] == alg, data["Problem"] == pr) + ].mean() i += 1 j += 1 @@ -402,9 +415,15 @@ def compute_mean_indicator(filename: str, indicator_name: str): return df -def __averages_to_latex(central_tendency: pd.DataFrame, dispersion: pd.DataFrame, - caption: str, label: str, minimization=True, alignment: str = 'c'): - """ Convert a pandas DataFrame to a LaTeX tabular. Prints labels in bold and does use math mode. +def __averages_to_latex( + central_tendency: pd.DataFrame, + dispersion: pd.DataFrame, + caption: str, + label: str, + minimization=True, + alignment: str = "c", +): + """Convert a pandas DataFrame to a LaTeX tabular. Prints labels in bold and does use math mode. :param caption: LaTeX table caption. :param label: LaTeX table label. @@ -413,40 +432,40 @@ def __averages_to_latex(central_tendency: pd.DataFrame, dispersion: pd.DataFrame num_columns, num_rows = central_tendency.shape[1], central_tendency.shape[0] output = io.StringIO() - col_format = '{}|{}'.format(alignment, alignment * num_columns) - column_labels = ['\\textbf{{{0}}}'.format(label.replace('_', '\\_')) for label in central_tendency.columns] + col_format = "{}|{}".format(alignment, alignment * num_columns) + column_labels = ["\\textbf{{{0}}}".format(label.replace("_", "\\_")) for label in central_tendency.columns] # Write header - output.write('\\documentclass{article}\n') + output.write("\\documentclass{article}\n") - output.write('\\usepackage[utf8]{inputenc}\n') - output.write('\\usepackage{tabularx}\n') - output.write('\\usepackage{colortbl}\n') - output.write('\\usepackage[table*]{xcolor}\n') + output.write("\\usepackage[utf8]{inputenc}\n") + output.write("\\usepackage{tabularx}\n") + output.write("\\usepackage{colortbl}\n") + output.write("\\usepackage[table*]{xcolor}\n") - output.write('\\xdefinecolor{gray95}{gray}{0.65}\n') - output.write('\\xdefinecolor{gray25}{gray}{0.8}\n') + output.write("\\xdefinecolor{gray95}{gray}{0.65}\n") + output.write("\\xdefinecolor{gray25}{gray}{0.8}\n") - output.write('\\title{Median and IQR}\n') - output.write('\\author{}\n') + output.write("\\title{Median and IQR}\n") + output.write("\\author{}\n") - output.write('\\begin{document}\n') - output.write('\\maketitle\n') + output.write("\\begin{document}\n") + output.write("\\maketitle\n") - output.write('\\section{Table}\n') + output.write("\\section{Table}\n") - output.write('\\begin{table}[!htp]\n') - output.write(' \\caption{{{}}}\n'.format(caption)) - output.write(' \\label{{{}}}\n'.format(label)) - output.write(' \\centering\n') - output.write(' \\begin{scriptsize}\n') - output.write(' \\begin{tabular}{%s}\n' % col_format) - output.write(' & {} \\\\\\hline\n'.format(' & '.join(column_labels))) + output.write("\\begin{table}[!htp]\n") + output.write(" \\caption{{{}}}\n".format(caption)) + output.write(" \\label{{{}}}\n".format(label)) + output.write(" \\centering\n") + output.write(" \\begin{scriptsize}\n") + output.write(" \\begin{tabular}{%s}\n" % col_format) + output.write(" & {} \\\\\\hline\n".format(" & ".join(column_labels))) # Write data lines for i in range(num_rows): - central_values = [v for v in central_tendency.ix[i]] - dispersion_values = [v for v in dispersion.ix[i]] + central_values = [v for v in central_tendency.iloc[i]] + dispersion_values = [v for v in dispersion.iloc[i]] # Sort mean/median values (the lower the better if minimization) # Note that mean/median values could be the same: in that case, sort by Std/IQR (the lower the better) @@ -460,29 +479,32 @@ def __averages_to_latex(central_tendency: pd.DataFrame, dispersion: pd.DataFrame second_best, best = sorted_values[-1][2], sorted_values[-2][2] # Compose cell - values = ['{:.2e}_{{{:.2e}}}'.format(central_values[i], dispersion_values[i]) for i in - range(len(central_values))] + values = [ + "{:.2e}_{{{:.2e}}}".format(central_values[i], dispersion_values[i]) for i in range(len(central_values)) + ] # Highlight values - values[best] = '\\cellcolor{gray25} ' + values[best] - values[second_best] = '\\cellcolor{gray95} ' + values[second_best] + values[best] = "\\cellcolor{gray25} " + values[best] + values[second_best] = "\\cellcolor{gray95} " + values[second_best] - output.write(' \\textbf{{{0}}} & ${1}$ \\\\\n'.format( - central_tendency.index[i], ' $ & $ '.join([str(val) for val in values])) + output.write( + " \\textbf{{{0}}} & ${1}$ \\\\\n".format( + central_tendency.index[i], " $ & $ ".join([str(val) for val in values]) + ) ) # Write footer - output.write(' \\end{tabular}\n') - output.write(' \\end{scriptsize}\n') - output.write('\\end{table}\n') + output.write(" \\end{tabular}\n") + output.write(" \\end{scriptsize}\n") + output.write("\\end{table}\n") - output.write('\\end{document}') + output.write("\\end{document}") return output.getvalue() -def __wilcoxon_to_latex(df: pd.DataFrame, caption: str, label: str, minimization=True, alignment: str = 'c'): - """ Convert a pandas DataFrame to a LaTeX tabular. Prints labels in bold and does use math mode. +def __wilcoxon_to_latex(df: pd.DataFrame, caption: str, label: str, minimization=True, alignment: str = "c"): + """Convert a pandas DataFrame to a LaTeX tabular. Prints labels in bold and does use math mode. :param df: Pandas dataframe. :param caption: LaTeX table caption. @@ -492,58 +514,58 @@ def __wilcoxon_to_latex(df: pd.DataFrame, caption: str, label: str, minimization num_columns, num_rows = df.shape[1], df.shape[0] output = io.StringIO() - col_format = '{}|{}'.format(alignment, alignment * num_columns) - column_labels = ['\\textbf{{{0}}}'.format(label.replace('_', '\\_')) for label in df.columns] + col_format = "{}|{}".format(alignment, alignment * num_columns) + column_labels = ["\\textbf{{{0}}}".format(label.replace("_", "\\_")) for label in df.columns] # Write header - output.write('\\documentclass{article}\n') + output.write("\\documentclass{article}\n") - output.write('\\usepackage[utf8]{inputenc}\n') - output.write('\\usepackage{tabularx}\n') - output.write('\\usepackage{amssymb}\n') - output.write('\\usepackage{amsmath}\n') + output.write("\\usepackage[utf8]{inputenc}\n") + output.write("\\usepackage{tabularx}\n") + output.write("\\usepackage{amssymb}\n") + output.write("\\usepackage{amsmath}\n") - output.write('\\title{Wilcoxon - Mann-Whitney rank sum test}\n') - output.write('\\author{}\n') + output.write("\\title{Wilcoxon - Mann-Whitney rank sum test}\n") + output.write("\\author{}\n") - output.write('\\begin{document}\n') - output.write('\\maketitle\n') + output.write("\\begin{document}\n") + output.write("\\maketitle\n") - output.write('\\section{Table}\n') + output.write("\\section{Table}\n") - output.write('\\begin{table}[!htp]\n') - output.write(' \\caption{{{}}}\n'.format(caption)) - output.write(' \\label{{{}}}\n'.format(label)) - output.write(' \\centering\n') - output.write(' \\begin{scriptsize}\n') - output.write(' \\begin{tabular}{%s}\n' % col_format) - output.write(' & {} \\\\\\hline\n'.format(' & '.join(column_labels))) + output.write("\\begin{table}[!htp]\n") + output.write(" \\caption{{{}}}\n".format(caption)) + output.write(" \\label{{{}}}\n".format(label)) + output.write(" \\centering\n") + output.write(" \\begin{scriptsize}\n") + output.write(" \\begin{tabular}{%s}\n" % col_format) + output.write(" & {} \\\\\\hline\n".format(" & ".join(column_labels))) - symbolo = '\\triangledown\ ' - symbolplus = '\\blacktriangle\ ' + symbolo = "\\triangledown\ " + symbolplus = "\\blacktriangle\ " if not minimization: symbolo, symbolplus = symbolplus, symbolo # Write data lines for i in range(num_rows): - values = [val.replace('-', '\\text{--}\ ').replace('o', symbolo).replace('+', symbolplus) for val in df.ix[i]] - output.write(' \\textbf{{{0}}} & ${1}$ \\\\\n'.format( - df.index[i], ' $ & $ '.join([str(val) for val in values])) + values = [val.replace("-", "\\text{--}\ ").replace("o", symbolo).replace("+", symbolplus) for val in df.iloc[i]] + output.write( + " \\textbf{{{0}}} & ${1}$ \\\\\n".format(df.index[i], " $ & $ ".join([str(val) for val in values])) ) # Write footer - output.write(' \\end{tabular}\n') - output.write(' \\end{scriptsize}\n') - output.write('\\end{table}\n') + output.write(" \\end{tabular}\n") + output.write(" \\end{scriptsize}\n") + output.write("\\end{table}\n") - output.write('\\end{document}') + output.write("\\end{document}") return output.getvalue() def check_minimization(indicator) -> bool: - if indicator == 'HV': + if indicator == "HV": return False else: return True diff --git a/jmetal/lab/statistical_test/apv_procedures.py b/jmetal/lab/statistical_test/apv_procedures.py index 3aa7cb37..d0c8d235 100644 --- a/jmetal/lab/statistical_test/apv_procedures.py +++ b/jmetal/lab/statistical_test/apv_procedures.py @@ -21,14 +21,12 @@ def bonferroni_dunn(p_values, control): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if type(control) == str: control = int(np.where(algorithms == control)[0]) if control is None: - raise ValueError( - 'Initialization ERROR. Incorrect value for control.') + raise ValueError("Initialization ERROR. Incorrect value for control.") k = p_values.shape[1] @@ -38,10 +36,9 @@ def bonferroni_dunn(p_values, control): APVs = np.zeros((k - 1, 1)) comparison = [] for i in range(k - 1): - comparison.append(algorithms[control] + - ' vs ' + algorithms[argsorted_pvals[i]]) + comparison.append(algorithms[control] + " vs " + algorithms[argsorted_pvals[i]]) APVs[i, 0] = np.min([(k - 1) * p_values[0, argsorted_pvals[i]], 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Bonferroni']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Bonferroni"]) def holland(p_values, control): @@ -63,14 +60,12 @@ def holland(p_values, control): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if type(control) == str: control = int(np.where(algorithms == control)[0]) if control is None: - raise ValueError( - 'Initialization ERROR. Incorrect value for control.') + raise ValueError("Initialization ERROR. Incorrect value for control.") # -------------------------------------------------------------------------- # ------------------------------- Procedure -------------------------------- @@ -83,12 +78,11 @@ def holland(p_values, control): APVs = np.zeros((k - 1, 1)) comparison = [] for i in range(k - 1): - comparison.append(algorithms[control] + - ' vs ' + algorithms[argsorted_pvals[i]]) + comparison.append(algorithms[control] + " vs " + algorithms[argsorted_pvals[i]]) aux = k - 1 - np.arange(i + 1) - v = np.max(1 - (1 - p_values[0, argsorted_pvals[:(i + 1)]]) ** aux) + v = np.max(1 - (1 - p_values[0, argsorted_pvals[: (i + 1)]]) ** aux) APVs[i, 0] = np.min([v, 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Holland']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Holland"]) def finner(p_values, control): @@ -110,14 +104,12 @@ def finner(p_values, control): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if type(control) == str: control = int(np.where(algorithms == control)[0]) if control is None: - raise ValueError( - 'Initialization ERROR. Incorrect value for control.') + raise ValueError("Initialization ERROR. Incorrect value for control.") k = p_values.shape[1] @@ -127,12 +119,11 @@ def finner(p_values, control): APVs = np.zeros((k - 1, 1)) comparison = [] for i in range(k - 1): - comparison.append(algorithms[control] + - ' vs ' + algorithms[argsorted_pvals[i]]) + comparison.append(algorithms[control] + " vs " + algorithms[argsorted_pvals[i]]) aux = float(k - 1) / (np.arange(i + 1) + 1) - v = np.max(1 - (1 - p_values[0, argsorted_pvals[:(i + 1)]]) ** aux) + v = np.max(1 - (1 - p_values[0, argsorted_pvals[: (i + 1)]]) ** aux) APVs[i, 0] = np.min([v, 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Finner']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Finner"]) def hochberg(p_values, control): @@ -154,14 +145,12 @@ def hochberg(p_values, control): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if type(control) == str: control = int(np.where(algorithms == control)[0]) if control is None: - raise ValueError( - 'Initialization ERROR. Incorrect value for control.') + raise ValueError("Initialization ERROR. Incorrect value for control.") k = p_values.shape[1] @@ -171,12 +160,11 @@ def hochberg(p_values, control): APVs = np.zeros((k - 1, 1)) comparison = [] for i in range(k - 1): - comparison.append(algorithms[control] + - ' vs ' + algorithms[argsorted_pvals[i]]) + comparison.append(algorithms[control] + " vs " + algorithms[argsorted_pvals[i]]) aux = np.arange(k, i, -1).astype(np.uint8) v = np.max(p_values[0, argsorted_pvals[aux - 1]] * (k - aux)) APVs[i, 0] = np.min([v, 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Hochberg']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Hochberg"]) def li(p_values, control): @@ -200,14 +188,12 @@ def li(p_values, control): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if type(control) == str: control = int(np.where(algorithms == control)[0]) if control is None: - raise ValueError( - 'Initialization ERROR. Incorrect value for control.') + raise ValueError("Initialization ERROR. Incorrect value for control.") k = p_values.shape[1] @@ -217,11 +203,15 @@ def li(p_values, control): APVs = np.zeros((k - 1, 1)) comparison = [] for i in range(k - 1): - comparison.append(algorithms[control] + - ' vs ' + algorithms[argsorted_pvals[i]]) - APVs[i, 0] = np.min([p_values[0, argsorted_pvals[-2]], p_values[0, argsorted_pvals[i]] / ( - p_values[0, argsorted_pvals[i]] + 1 - p_values[0, argsorted_pvals[-2]])]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Li']) + comparison.append(algorithms[control] + " vs " + algorithms[argsorted_pvals[i]]) + APVs[i, 0] = np.min( + [ + p_values[0, argsorted_pvals[-2]], + p_values[0, argsorted_pvals[i]] + / (p_values[0, argsorted_pvals[i]] + 1 - p_values[0, argsorted_pvals[-2]]), + ] + ) + return pd.DataFrame(data=APVs, index=comparison, columns=["Li"]) def holm(p_values, control=None): @@ -245,8 +235,7 @@ def holm(p_values, control=None): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if type(control) == str: control = int(np.where(algorithms == control)[0]) @@ -261,9 +250,8 @@ def holm(p_values, control=None): comparison = [] for i in range(k - 1): aux = k - 1 - np.arange(i + 1) - comparison.append( - algorithms[control] + ' vs ' + algorithms[argsorted_pvals[i]]) - v = np.max(aux * p_values[0, argsorted_pvals[:(i + 1)]]) + comparison.append(algorithms[control] + " vs " + algorithms[argsorted_pvals[i]]) + v = np.max(aux * p_values[0, argsorted_pvals[: (i + 1)]]) APVs[i, 0] = np.min([v, 1]) elif control is None: @@ -281,10 +269,10 @@ def holm(p_values, control=None): for i in range(m): row = pairs_index[0][pairs_sorted[i]] col = pairs_index[1][pairs_sorted[i]] - comparison.append(algorithms[row] + ' vs ' + algorithms[col]) - v = np.max(aux[:i + 1]) + comparison.append(algorithms[row] + " vs " + algorithms[col]) + v = np.max(aux[: i + 1]) APVs[i, 0] = np.min([v, 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Holm']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Holm"]) def shaffer(p_values): @@ -320,8 +308,7 @@ def S(k): TrueHset = [0] if k > 1: for j in np.arange(k, 0, -1, dtype=int): - TrueHset = list(set(TrueHset) | set( - [binomial(j, 2) + x for x in S(k - j)])) + TrueHset = list(set(TrueHset) | set([binomial(j, 2) + x for x in S(k - j)])) return TrueHset # Initial Checking @@ -329,15 +316,12 @@ def S(k): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if p_values.ndim != 2: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") elif p_values.shape[0] != p_values.shape[1]: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") # define parameters k = p_values.shape[0] @@ -356,15 +340,15 @@ def S(k): # Adjust p-values APVs = np.zeros((m, 1)) - aux = (pairs_pvals[pairs_sorted] * t) + aux = pairs_pvals[pairs_sorted] * t comparison = [] for i in range(m): row = pairs_index[0][pairs_sorted[i]] col = pairs_index[1][pairs_sorted[i]] - comparison.append(algorithms[row] + ' vs ' + algorithms[col]) - v = np.max(aux[:i + 1]) + comparison.append(algorithms[row] + " vs " + algorithms[col]) + v = np.max(aux[: i + 1]) APVs[i, 0] = np.min([v, 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Shaffer']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Shaffer"]) def nemenyi(p_values): @@ -385,15 +369,12 @@ def nemenyi(p_values): algorithms = p_values.columns p_values = p_values.values elif type(p_values) == np.ndarray: - algorithms = np.array( - ['Alg%d' % alg for alg in range(p_values.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(p_values.shape[1])]) if p_values.ndim != 2: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") elif p_values.shape[0] != p_values.shape[1]: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") # define parameters k = p_values.shape[0] @@ -410,6 +391,6 @@ def nemenyi(p_values): for i in range(m): row = pairs_index[0][pairs_sorted[i]] col = pairs_index[1][pairs_sorted[i]] - comparison.append(algorithms[row] + ' vs ' + algorithms[col]) + comparison.append(algorithms[row] + " vs " + algorithms[col]) APVs[i, 0] = np.min([pairs_pvals[pairs_sorted[i]] * m, 1]) - return pd.DataFrame(data=APVs, index=comparison, columns=['Nemenyi']) + return pd.DataFrame(data=APVs, index=comparison, columns=["Nemenyi"]) diff --git a/jmetal/lab/statistical_test/bayesian.py b/jmetal/lab/statistical_test/bayesian.py index c3924624..c79eda6e 100644 --- a/jmetal/lab/statistical_test/bayesian.py +++ b/jmetal/lab/statistical_test/bayesian.py @@ -2,9 +2,10 @@ import pandas as pd -def bayesian_sign_test(data, rope_limits=[-0.01, 0.01], prior_strength=0.5, prior_place='rope', sample_size=50000, - return_sample=False): - """ Bayesian version of the sign test. +def bayesian_sign_test( + data, rope_limits=[-0.01, 0.01], prior_strength=0.5, prior_place="rope", sample_size=50000, return_sample=False +): + """Bayesian version of the sign test. :param data: An (n x 2) array or DataFrame contaning the results. In data, each column represents an algorithm and, and each row a problem. :param rope_limits: array_like. Default [-0.01, 0.01]. Limits of the practical equivalence. @@ -27,16 +28,13 @@ def bayesian_sign_test(data, rope_limits=[-0.01, 0.01], prior_strength=0.5, prio sample1, sample2 = data[:, 0], data[:, 1] n = data.shape[0] else: - raise ValueError( - 'Initialization ERROR. Incorrect number of dimensions for axis 1') + raise ValueError("Initialization ERROR. Incorrect number of dimensions for axis 1") if prior_strength <= 0: - raise ValueError( - 'Initialization ERROR. prior_strength mustb be a positive float') + raise ValueError("Initialization ERROR. prior_strength mustb be a positive float") - if prior_place not in ['left', 'rope', 'right']: - raise ValueError( - 'Initialization ERROR. Incorrect value fro prior_place') + if prior_place not in ["left", "rope", "right"]: + raise ValueError("Initialization ERROR. Incorrect value fro prior_place") # Compute the differences Z = sample1 - sample2 @@ -53,7 +51,7 @@ def bayesian_sign_test(data, rope_limits=[-0.01, 0.01], prior_strength=0.5, prio # Parameters of the Dirichlet distribution alpha = np.array([Nleft, Nequiv, Nright], dtype=float) + 1e-6 - alpha[['left', 'rope', 'right'].index(prior_place)] += prior_strength + alpha[["left", "rope", "right"].index(prior_place)] += prior_strength # Simulate dirichlet process Dprocess = np.random.dirichlet(alpha, sample_size) @@ -69,10 +67,10 @@ def bayesian_sign_test(data, rope_limits=[-0.01, 0.01], prior_strength=0.5, prio return np.array([win_left, win_rope, win_rifht]) / float(sample_size) -def bayesian_signed_rank_test(data, rope_limits=[-0.01, 0.01], prior_strength=1.0, prior_place='rope', - sample_size=10000, - return_sample=False): - """ Bayesian version of the signed rank test. +def bayesian_signed_rank_test( + data, rope_limits=[-0.01, 0.01], prior_strength=1.0, prior_place="rope", sample_size=10000, return_sample=False +): + """Bayesian version of the signed rank test. :param data: An (n x 2) array or DataFrame contaning the results. In data, each column represents an algorithm and, and each row a problem. :param rope_limits: array_like. Default [-0.01, 0.01]. Limits of the practical equivalence. @@ -98,21 +96,17 @@ def weights(n, s): sample1, sample2 = data[:, 0], data[:, 1] n = data.shape[0] else: - raise ValueError( - 'Initialization ERROR. Incorrect number of dimensions for axis 1') + raise ValueError("Initialization ERROR. Incorrect number of dimensions for axis 1") if prior_strength <= 0: - raise ValueError( - 'Initialization ERROR. prior_strength must be a positive float') + raise ValueError("Initialization ERROR. prior_strength must be a positive float") - if prior_place not in ['left', 'rope', 'right']: - raise ValueError( - 'Initialization ERROR. Incorrect value for prior_place') + if prior_place not in ["left", "rope", "right"]: + raise ValueError("Initialization ERROR. Incorrect value for prior_place") # Compute the differences Z = sample1 - sample2 - Z0 = [-float('Inf'), 0.0, float('Inf')][['left', - 'rope', 'right'].index(prior_place)] + Z0 = [-float("Inf"), 0.0, float("Inf")][["left", "rope", "right"].index(prior_place)] Z = np.concatenate(([Z0], Z), axis=None) # compute the the probabilities that the mean difference of accuracy is in diff --git a/jmetal/lab/statistical_test/critical_distance.py b/jmetal/lab/statistical_test/critical_distance.py index d03891c6..954c4832 100644 --- a/jmetal/lab/statistical_test/critical_distance.py +++ b/jmetal/lab/statistical_test/critical_distance.py @@ -7,7 +7,7 @@ def NemenyiCD(alpha: float, num_alg, num_dataset): - """ Computes Nemenyi's critical difference: + """Computes Nemenyi's critical difference: * CD = q_alpha * sqrt(num_alg*(num_alg + 1)/(6*num_prob)) where q_alpha is the critical value, of the Studentized range statistic divided by sqrt(2). :param alpha: {0.1, 0.999}. Significance level. @@ -24,8 +24,14 @@ def NemenyiCD(alpha: float, num_alg, num_dataset): return cd -def CDplot(results, alpha: float = 0.05, higher_is_better: bool=False, alg_names: list = None, output_filename: str = 'cdplot.eps'): - """ CDgraph plots the critical difference graph show in Janez Demsar's 2006 work: +def CDplot( + results, + alpha: float = 0.05, + higher_is_better: bool = False, + alg_names: list = None, + output_filename: str = "cdplot.eps", +): + """CDgraph plots the critical difference graph show in Janez Demsar's 2006 work: * Statistical Comparisons of Classifiers over Multiple Data Sets. :param results: A 2-D array containing results from each algorithm. Each row of 'results' represents an algorithm, and each column a dataset. :param alpha: {0.1, 0.999}. Significance level for the critical difference. @@ -40,8 +46,7 @@ def _join_alg(avranks, num_alg, cd): # get all pairs sets = (-1) * np.ones((num_alg, 2)) for i in range(num_alg): - elements = np.where(np.logical_and( - avranks - avranks[i] > 0, avranks - avranks[i] < cd))[0] + elements = np.where(np.logical_and(avranks - avranks[i] > 0, avranks - avranks[i] < cd))[0] if elements.size > 0: sets[i, :] = [avranks[i], avranks[elements[-1]]] sets = np.delete(sets, np.where(sets[:, 0] < 0)[0], axis=0) @@ -59,14 +64,12 @@ def _join_alg(avranks, num_alg, cd): alg_names = results.index results = results.values elif type(results) == np.ndarray and alg_names is None: - alg_names = np.array( - ['Alg%d' % alg for alg in range(results.shape[1])]) + alg_names = np.array(["Alg%d" % alg for alg in range(results.shape[1])]) if results.ndim == 2: num_alg, num_dataset = results.shape else: - raise ValueError( - 'Initialization ERROR: In CDplot(...) results must be 2-D array') + raise ValueError("Initialization ERROR: In CDplot(...) results must be 2-D array") # Get the critical difference cd = NemenyiCD(alpha, num_alg, num_dataset) @@ -90,7 +93,7 @@ def _join_alg(avranks, num_alg, cd): highest = np.ceil(np.max(avranks)).astype(np.uint8) # highest shown rank lowest = np.floor(np.min(avranks)).astype(np.uint8) # lowest shown rank width = 6 # default figure width (in inches) - height = (0.575 * (rows + 1)) # figure height + height = 0.575 * (rows + 1) # figure height """ FIGURE @@ -118,60 +121,79 @@ def _join_alg(avranks, num_alg, cd): lline = sright - sleft # Initialize figure - fig = plt.figure(figsize=(width, height), facecolor='white') + fig = plt.figure(figsize=(width, height), facecolor="white") ax = fig.add_axes([0, 0, 1, 1]) ax.set_xlim(0, 1) ax.set_ylim(0, 1) ax.set_axis_off() # Main horizontal axis - ax.hlines(stop, sleft, sright, color='black', linewidth=0.7) + ax.hlines(stop, sleft, sright, color="black", linewidth=0.7) for xi in range(highest - lowest + 1): # Plot mayor ticks - ax.vlines(x=sleft + (lline * xi) / (highest - lowest), - ymin=stop, ymax=stop + 0.05, color='black', linewidth=0.7) + ax.vlines( + x=sleft + (lline * xi) / (highest - lowest), ymin=stop, ymax=stop + 0.05, color="black", linewidth=0.7 + ) # Mayor ticks labels - ax.text(x=sleft + (lline * xi) / (highest - lowest), - y=stop + 0.06, - s=str(lowest + xi), ha='center', va='bottom') + ax.text( + x=sleft + (lline * xi) / (highest - lowest), y=stop + 0.06, s=str(lowest + xi), ha="center", va="bottom" + ) # Minor ticks if xi < highest - lowest: - ax.vlines(x=sleft + (lline * (xi + 0.5)) / (highest - lowest), - ymin=stop, ymax=stop + 0.025, color='black', linewidth=0.7) + ax.vlines( + x=sleft + (lline * (xi + 0.5)) / (highest - lowest), + ymin=stop, + ymax=stop + 0.025, + color="black", + linewidth=0.7, + ) # Plot lines/names for left models vspace = 0.5 * (stop - sbottom) / (spoint + 1) for i in range(spoint): - ax.vlines(x=sleft + (lline * (leftalg[i] - lowest)) / (highest - lowest), - ymin=sbottom + (spoint - 1 - i) * vspace, ymax=stop, color='black', linewidth=0.7) - ax.hlines(y=sbottom + (spoint - 1 - i) * vspace, xmin=sleft, - xmax=sleft + - (lline * (leftalg[i] - lowest)) / (highest - lowest), - color='black', linewidth=0.7) - ax.text(x=sleft - 0.01, y=sbottom + (spoint - 1 - i) * vspace, - s=alg_names[indices][i], ha='right', va='center') + ax.vlines( + x=sleft + (lline * (leftalg[i] - lowest)) / (highest - lowest), + ymin=sbottom + (spoint - 1 - i) * vspace, + ymax=stop, + color="black", + linewidth=0.7, + ) + ax.hlines( + y=sbottom + (spoint - 1 - i) * vspace, + xmin=sleft, + xmax=sleft + (lline * (leftalg[i] - lowest)) / (highest - lowest), + color="black", + linewidth=0.7, + ) + ax.text(x=sleft - 0.01, y=sbottom + (spoint - 1 - i) * vspace, s=alg_names[indices][i], ha="right", va="center") # Plot lines/names for right models vspace = 0.5 * (stop - sbottom) / (num_alg - spoint + 1) for i in range(num_alg - spoint): - ax.vlines(x=sleft + (lline * (rightalg[i] - lowest)) / (highest - lowest), - ymin=sbottom + i * vspace, ymax=stop, color='black', linewidth=0.7) - ax.hlines(y=sbottom + i * vspace, - xmin=sleft + - (lline * (rightalg[i] - lowest)) / (highest - lowest), - xmax=sright, color='black', linewidth=0.7) - ax.text(x=sright + 0.01, y=sbottom + i * vspace, - s=alg_names[indices][spoint + i], ha='left', va='center') + ax.vlines( + x=sleft + (lline * (rightalg[i] - lowest)) / (highest - lowest), + ymin=sbottom + i * vspace, + ymax=stop, + color="black", + linewidth=0.7, + ) + ax.hlines( + y=sbottom + i * vspace, + xmin=sleft + (lline * (rightalg[i] - lowest)) / (highest - lowest), + xmax=sright, + color="black", + linewidth=0.7, + ) + ax.text(x=sright + 0.01, y=sbottom + i * vspace, s=alg_names[indices][spoint + i], ha="left", va="center") # Plot critical difference rule if sleft + (cd * lline) / (highest - lowest) <= sright: - ax.hlines(y=stop + 0.2, xmin=sleft, xmax=sleft + - (cd * lline) / (highest - lowest), linewidth=1.5) - ax.text(x=sleft + 0.5 * (cd * lline) / - (highest - lowest), y=stop + 0.21, s='CD=%.3f' % cd, ha='center', va='bottom') + ax.hlines(y=stop + 0.2, xmin=sleft, xmax=sleft + (cd * lline) / (highest - lowest), linewidth=1.5) + ax.text( + x=sleft + 0.5 * (cd * lline) / (highest - lowest), y=stop + 0.21, s="CD=%.3f" % cd, ha="center", va="bottom" + ) else: - ax.text(x=(sleft + sright) / 2, y=stop + 0.2, s='CD=%.3f' % - cd, ha='center', va='bottom') + ax.text(x=(sleft + sright) / 2, y=stop + 0.2, s="CD=%.3f" % cd, ha="center", va="bottom") # Get pair of non-significant methods nonsig = _join_alg(avranks, num_alg, cd) @@ -180,29 +202,31 @@ def _join_alg(avranks, num_alg, cd): left_lines = np.reshape(nonsig[0, :], (1, 2)) right_lines = np.reshape(nonsig[1, :], (1, 2)) else: - left_lines = nonsig[:np.round( - nonsig.shape[0] / 2.0).astype(np.uint8), :] - right_lines = nonsig[np.round( - nonsig.shape[0] / 2.0).astype(np.uint8):, :] + left_lines = nonsig[: np.round(nonsig.shape[0] / 2.0).astype(np.uint8), :] + right_lines = nonsig[np.round(nonsig.shape[0] / 2.0).astype(np.uint8) :, :] else: left_lines = np.reshape(nonsig, (1, nonsig.shape[0])) # plot from the left vspace = 0.5 * (stop - sbottom) / (left_lines.shape[0] + 1) for i in range(left_lines.shape[0]): - ax.hlines(y=stop - (i + 1) * vspace, - xmin=sleft + lline * (left_lines[i, 0] - - lowest - 0.025) / (highest - lowest), - xmax=sleft + lline * (left_lines[i, 1] - lowest + 0.025) / (highest - lowest), linewidth=2) + ax.hlines( + y=stop - (i + 1) * vspace, + xmin=sleft + lline * (left_lines[i, 0] - lowest - 0.025) / (highest - lowest), + xmax=sleft + lline * (left_lines[i, 1] - lowest + 0.025) / (highest - lowest), + linewidth=2, + ) # plot from the rigth if nonsig.ndim == 2: vspace = 0.5 * (stop - sbottom) / (left_lines.shape[0]) for i in range(right_lines.shape[0]): - ax.hlines(y=stop - (i + 1) * vspace, - xmin=sleft + lline * (right_lines[i, 0] - - lowest - 0.025) / (highest - lowest), - xmax=sleft + lline * (right_lines[i, 1] - lowest + 0.025) / (highest - lowest), linewidth=2) - - plt.savefig(output_filename, bbox_inches='tight') + ax.hlines( + y=stop - (i + 1) * vspace, + xmin=sleft + lline * (right_lines[i, 0] - lowest - 0.025) / (highest - lowest), + xmax=sleft + lline * (right_lines[i, 1] - lowest + 0.025) / (highest - lowest), + linewidth=2, + ) + + plt.savefig(output_filename, bbox_inches="tight") plt.show() diff --git a/jmetal/lab/statistical_test/functions.py b/jmetal/lab/statistical_test/functions.py index 6f5d47da..f1e9b5c9 100644 --- a/jmetal/lab/statistical_test/functions.py +++ b/jmetal/lab/statistical_test/functions.py @@ -1,10 +1,10 @@ -from scipy.stats import chi2, f, binom, norm +from scipy.stats import binom, chi2, f, norm from jmetal.lab.statistical_test.apv_procedures import * def ranks(data: np.array, descending=False): - """ Computes the rank of the elements in data. + """Computes the rank of the elements in data. :param data: 2-D matrix :param descending: boolean (default False). If true, rank is sorted in descending order. @@ -17,23 +17,27 @@ def ranks(data: np.array, descending=False): ranks = np.ones(data.shape) for i in range(data.shape[0]): values, indices, rep = np.unique( - (-1) ** s * np.sort((-1) ** s * data[i, :]), return_index=True, return_counts=True, ) + (-1) ** s * np.sort((-1) ** s * data[i, :]), + return_index=True, + return_counts=True, + ) for j in range(data.shape[1]): - ranks[i, j] += indices[values == data[i, j]] + \ - 0.5 * (rep[values == data[i, j]] - 1) + ranks[i, j] += indices[values == data[i, j]] + 0.5 * (rep[values == data[i, j]] - 1) return ranks elif data.ndim == 1: ranks = np.ones((data.size,)) values, indices, rep = np.unique( - (-1) ** s * np.sort((-1) ** s * data), return_index=True, return_counts=True, ) + (-1) ** s * np.sort((-1) ** s * data), + return_index=True, + return_counts=True, + ) for i in range(data.size): - ranks[i] += indices[values == data[i]] + \ - 0.5 * (rep[values == data[i]] - 1) + ranks[i] += indices[values == data[i]] + 0.5 * (rep[values == data[i]] - 1) return ranks def sign_test(data): - """ Given the results drawn from two algorithms/methods X and Y, the sign test analyses if + """Given the results drawn from two algorithms/methods X and Y, the sign test analyses if there is a difference between X and Y. .. note:: Null Hypothesis: Pr(XY', 'p-value'], - columns=['Results']) + return pd.DataFrame( + data=np.array([Wminus, Wplus, p_value]), index=["Num XY", "p-value"], columns=["Results"] + ) def friedman_test(data): - """ Friedman ranking test. + """Friedman ranking test. ..note:: Null Hypothesis: In a set of k (>=2) treaments (or tested algorithms), all the treatments are equivalent, so their average ranks should be equal. @@ -88,11 +92,9 @@ def friedman_test(data): if data.ndim == 2: n_samples, k = data.shape else: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions") if k < 2: - raise ValueError( - 'Initialization Error. Incorrect number of dimensions for axis 1.') + raise ValueError("Initialization Error. Incorrect number of dimensions for axis 1.") # Compute ranks. datarank = ranks(data) @@ -101,18 +103,18 @@ def friedman_test(data): avranks = np.mean(datarank, axis=0) # Get Friedman statistics - friedman_stat = (12.0 * n_samples) / (k * (k + 1.0)) * \ - (np.sum(avranks ** 2) - (k * (k + 1) ** 2) / 4.0) + friedman_stat = (12.0 * n_samples) / (k * (k + 1.0)) * (np.sum(avranks**2) - (k * (k + 1) ** 2) / 4.0) # Compute p-value - p_value = (1.0 - chi2.cdf(friedman_stat, df=(k - 1))) + p_value = 1.0 - chi2.cdf(friedman_stat, df=(k - 1)) - return pd.DataFrame(data=np.array([friedman_stat, p_value]), index=['Friedman-statistic', 'p-value'], - columns=['Results']) + return pd.DataFrame( + data=np.array([friedman_stat, p_value]), index=["Friedman-statistic", "p-value"], columns=["Results"] + ) def friedman_aligned_rank_test(data): - """ Method of aligned ranks for the Friedman test. + """Method of aligned ranks for the Friedman test. ..note:: Null Hypothesis: In a set of k (>=2) treaments (or tested algorithms), all the treatments are equivalent, so their average ranks should be equal. @@ -128,11 +130,9 @@ def friedman_aligned_rank_test(data): if data.ndim == 2: n_samples, k = data.shape else: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions") if k < 2: - raise ValueError( - 'Initialization Error. Incorrect number of dimensions for axis 1.') + raise ValueError("Initialization Error. Incorrect number of dimensions for axis 1.") # Compute the average value achieved by all algorithms in each problem control = np.mean(data, axis=1) @@ -140,27 +140,28 @@ def friedman_aligned_rank_test(data): diff = [data[:, j] - control for j in range(data.shape[1])] # rank diff alignedRanks = ranks(np.ravel(diff)) - alignedRanks = np.reshape(alignedRanks, newshape=(n_samples, k), order='F') + alignedRanks = np.reshape(alignedRanks, newshape=(n_samples, k), order="F") # Compute statistic Rhat_i = np.sum(alignedRanks, axis=1) Rhat_j = np.sum(alignedRanks, axis=0) - si, sj = np.sum(Rhat_i ** 2), np.sum(Rhat_j ** 2) + si, sj = np.sum(Rhat_i**2), np.sum(Rhat_j**2) - A = sj - (k * n_samples ** 2 / 4.0) * (k * n_samples + 1) ** 2 - B1 = (k * n_samples * (k * n_samples + 1) * (2 * k * n_samples + 1) / 6.0) + A = sj - (k * n_samples**2 / 4.0) * (k * n_samples + 1) ** 2 + B1 = k * n_samples * (k * n_samples + 1) * (2 * k * n_samples + 1) / 6.0 B2 = si / float(k) alignedRanks_stat = ((k - 1) * A) / (B1 - B2) p_value = 1 - chi2.cdf(alignedRanks_stat, df=k - 1) - return pd.DataFrame(data=np.array([alignedRanks_stat, p_value]), index=['Aligned Rank stat', 'p-value'], - columns=['Results']) + return pd.DataFrame( + data=np.array([alignedRanks_stat, p_value]), index=["Aligned Rank stat", "p-value"], columns=["Results"] + ) def quade_test(data): - """ Quade test. + """Quade test. ..note:: Null Hypothesis: In a set of k (>=2) treaments (or tested algorithms), all the treatments are equivalent, so their average ranks should be equal. @@ -176,11 +177,9 @@ def quade_test(data): if data.ndim == 2: n_samples, k = data.shape else: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions") if k < 2: - raise ValueError( - 'Initialization Error. Incorrect number of dimensions for axis 1.') + raise ValueError("Initialization Error. Incorrect number of dimensions for axis 1.") # Compute ranks. datarank = ranks(data) @@ -197,8 +196,8 @@ def quade_test(data): Salg = np.sum(S_stat, axis=0) # Compute Fq (Quade Test statistic) and associated p_value - A = np.sum(S_stat ** 2) - B = np.sum(Salg ** 2) / float(n_samples) + A = np.sum(S_stat**2) + B = np.sum(Salg**2) / float(n_samples) if A == B: Fq = np.Inf @@ -207,11 +206,11 @@ def quade_test(data): Fq = (n_samples - 1.0) * B / (A - B) p_value = 1 - f.cdf(Fq, k - 1, (k - 1) * (n_samples - 1)) - return pd.DataFrame(data=np.array([Fq, p_value]), index=['Quade Test statistic', 'p-value'], columns=['Results']) + return pd.DataFrame(data=np.array([Fq, p_value]), index=["Quade Test statistic", "p-value"], columns=["Results"]) def friedman_ph_test(data, control=None, apv_procedure=None): - """ Friedman post-hoc test. + """Friedman post-hoc test. :param data: An (n x 2) array or DataFrame contaning the results. In data, each column represents an algorithm and, and each row a problem. :param control: optional int or string. Default None. Index or Name of the control algorithm. If control = None all FriedmanPosHocTest considers all possible comparisons among algorithms. @@ -233,7 +232,7 @@ def friedman_ph_test(data, control=None, apv_procedure=None): algorithms = data.columns data = data.values elif type(data) == np.ndarray: - algorithms = np.array(['Alg%d' % alg for alg in range(data.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(data.shape[1])]) if control is None: index = algorithms @@ -245,24 +244,29 @@ def friedman_ph_test(data, control=None, apv_procedure=None): if data.ndim == 2: n_samples, k = data.shape else: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") if k < 2: - raise ValueError( - 'Initialization Error. Incorrect number of dimensions for axis 1.') + raise ValueError("Initialization Error. Incorrect number of dimensions for axis 1.") if control is not None: if type(control) == int and control >= data.shape[1]: - raise ValueError('Initialization ERROR. control is out of bounds') + raise ValueError("Initialization ERROR. control is out of bounds") if type(control) == str and control not in algorithms: - raise ValueError( - 'Initialization ERROR. %s is not a column name of data' % control) + raise ValueError("Initialization ERROR. %s is not a column name of data" % control) if apv_procedure is not None: - if apv_procedure not in ['Bonferroni', 'Holm', 'Hochberg', 'Hommel', 'Holland', 'Finner', 'Li', 'Shaffer', - 'Nemenyi']: - raise ValueError( - 'Initialization ERROR. Incorrect value for APVprocedure.') + if apv_procedure not in [ + "Bonferroni", + "Holm", + "Hochberg", + "Hommel", + "Holland", + "Finner", + "Li", + "Shaffer", + "Nemenyi", + ]: + raise ValueError("Initialization ERROR. Incorrect value for APVprocedure.") # Compute ranks. datarank = ranks(data) @@ -294,28 +298,28 @@ def friedman_ph_test(data, control=None, apv_procedure=None): if apv_procedure is None: return zvalues_df, pvalues_df else: - if apv_procedure == 'Bonferroni': + if apv_procedure == "Bonferroni": ap_vs_df = bonferroni_dunn(pvalues_df, control=control) - elif apv_procedure == 'Holm': + elif apv_procedure == "Holm": ap_vs_df = holm(pvalues_df, control=control) - elif apv_procedure == 'Hochberg': + elif apv_procedure == "Hochberg": ap_vs_df = hochberg(pvalues_df, control=control) - elif apv_procedure == 'Holland': + elif apv_procedure == "Holland": ap_vs_df = holland(pvalues_df, control=control) - elif apv_procedure == 'Finner': + elif apv_procedure == "Finner": ap_vs_df = finner(pvalues_df, control=control) - elif apv_procedure == 'Li': + elif apv_procedure == "Li": ap_vs_df = li(pvalues_df, control=control) - elif apv_procedure == 'Shaffer': + elif apv_procedure == "Shaffer": ap_vs_df = shaffer(pvalues_df) - elif apv_procedure == 'Nemenyi': + elif apv_procedure == "Nemenyi": ap_vs_df = nemenyi(pvalues_df) return zvalues_df, pvalues_df, ap_vs_df def friedman_aligned_ph_test(data, control=None, apv_procedure=None): - """ Friedman Aligned Ranks post-hoc test. + """Friedman Aligned Ranks post-hoc test. :param data: An (n x 2) array or DataFrame contaning the results. In data, each column represents an algorithm and, and each row a problem. :param control: optional int or string. Default None. Index or Name of the control algorithm. If control = None all FriedmanPosHocTest considers all possible comparisons among algorithms. @@ -337,7 +341,7 @@ def friedman_aligned_ph_test(data, control=None, apv_procedure=None): algorithms = data.columns data = data.values elif type(data) == np.ndarray: - algorithms = np.array(['Alg%d' % alg for alg in range(data.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(data.shape[1])]) if control is None: index = algorithms @@ -349,18 +353,15 @@ def friedman_aligned_ph_test(data, control=None, apv_procedure=None): if data.ndim == 2: n_samples, k = data.shape else: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") if k < 2: - raise ValueError( - 'Initialization Error. Incorrect number of dimensions for axis 1.') + raise ValueError("Initialization Error. Incorrect number of dimensions for axis 1.") if control is not None: if type(control) == int and control >= data.shape[1]: - raise ValueError('Initialization ERROR. control is out of bounds') + raise ValueError("Initialization ERROR. control is out of bounds") if type(control) == str and control not in algorithms: - raise ValueError( - 'Initialization ERROR. %s is not a column name of data' % control) + raise ValueError("Initialization ERROR. %s is not a column name of data" % control) # Compute the average value achieved by all algorithms in each problem problemmean = np.mean(data, axis=1) @@ -399,28 +400,28 @@ def friedman_aligned_ph_test(data, control=None, apv_procedure=None): if apv_procedure is None: return zvalues_df, pvalues_df else: - if apv_procedure == 'Bonferroni': + if apv_procedure == "Bonferroni": ap_vs_df = bonferroni_dunn(pvalues_df, control=control) - elif apv_procedure == 'Holm': + elif apv_procedure == "Holm": ap_vs_df = holm(pvalues_df, control=control) - elif apv_procedure == 'Hochberg': + elif apv_procedure == "Hochberg": ap_vs_df = hochberg(pvalues_df, control=control) - elif apv_procedure == 'Holland': + elif apv_procedure == "Holland": ap_vs_df = holland(pvalues_df, control=control) - elif apv_procedure == 'Finner': + elif apv_procedure == "Finner": ap_vs_df = finner(pvalues_df, control=control) - elif apv_procedure == 'Li': + elif apv_procedure == "Li": ap_vs_df = li(pvalues_df, control=control) - elif apv_procedure == 'Shaffer': + elif apv_procedure == "Shaffer": ap_vs_df = shaffer(pvalues_df) - elif apv_procedure == 'Nemenyi': + elif apv_procedure == "Nemenyi": ap_vs_df = nemenyi(pvalues_df) return zvalues_df, pvalues_df, ap_vs_df def quade_ph_test(data, control=None, apv_procedure=None): - """ Quade post-hoc test. + """Quade post-hoc test. :param data: An (n x 2) array or DataFrame contaning the results. In data, each column represents an algorithm and, and each row a problem. :param control: optional int or string. Default None. Index or Name of the control algorithm. If control = None all FriedmanPosHocTest considers all possible comparisons among algorithms. @@ -442,7 +443,7 @@ def quade_ph_test(data, control=None, apv_procedure=None): algorithms = data.columns data = data.values elif type(data) == np.ndarray: - algorithms = np.array(['Alg%d' % alg for alg in range(data.shape[1])]) + algorithms = np.array(["Alg%d" % alg for alg in range(data.shape[1])]) if control is None: index = algorithms @@ -454,18 +455,15 @@ def quade_ph_test(data, control=None, apv_procedure=None): if data.ndim == 2: n_samples, k = data.shape else: - raise ValueError( - 'Initialization ERROR. Incorrect number of array dimensions.') + raise ValueError("Initialization ERROR. Incorrect number of array dimensions.") if k < 2: - raise ValueError( - 'Initialization Error. Incorrect number of dimensions for axis 1.') + raise ValueError("Initialization Error. Incorrect number of dimensions for axis 1.") if control is not None: if type(control) == int and control >= data.shape[1]: - raise ValueError('Initialization ERROR. control is out of bounds') + raise ValueError("Initialization ERROR. control is out of bounds") if type(control) == str and control not in algorithms: - raise ValueError( - 'Initialization ERROR. %s is not a column name of data' % control) + raise ValueError("Initialization ERROR. %s is not a column name of data" % control) # Compute ranks. datarank = ranks(data) @@ -480,8 +478,7 @@ def quade_ph_test(data, control=None, apv_procedure=None): W[i, :] = problemRank[i] * datarank[i, :] avranks = 2 * np.sum(W, axis=0) / (n_samples * (n_samples + 1)) # Compute test statistics - aux = 1.0 / np.sqrt(k * (k + 1) * (2 * n_samples + 1) * (k - 1) / - (18.0 * n_samples * (n_samples + 1))) + aux = 1.0 / np.sqrt(k * (k + 1) * (2 * n_samples + 1) * (k - 1) / (18.0 * n_samples * (n_samples + 1))) if control is None: z = np.zeros((k, k)) for i in range(k): @@ -504,21 +501,21 @@ def quade_ph_test(data, control=None, apv_procedure=None): if apv_procedure is None: return zvalues_df, pvalues_df else: - if apv_procedure == 'Bonferroni': + if apv_procedure == "Bonferroni": ap_vs_df = bonferroni_dunn(pvalues_df, control=control) - elif apv_procedure == 'Holm': + elif apv_procedure == "Holm": ap_vs_df = holm(pvalues_df, control=control) - elif apv_procedure == 'Hochberg': + elif apv_procedure == "Hochberg": ap_vs_df = hochberg(pvalues_df, control=control) - elif apv_procedure == 'Holland': + elif apv_procedure == "Holland": ap_vs_df = holland(pvalues_df, control=control) - elif apv_procedure == 'Finner': + elif apv_procedure == "Finner": ap_vs_df = finner(pvalues_df, control=control) - elif apv_procedure == 'Li': + elif apv_procedure == "Li": ap_vs_df = li(pvalues_df, control=control) - elif apv_procedure == 'Shaffer': + elif apv_procedure == "Shaffer": ap_vs_df = shaffer(pvalues_df) - elif apv_procedure == 'Nemenyi': + elif apv_procedure == "Nemenyi": ap_vs_df = nemenyi(pvalues_df) return zvalues_df, pvalues_df, ap_vs_df diff --git a/jmetal/lab/visualization/__init__.py b/jmetal/lab/visualization/__init__.py index 42ecc322..1cc15dd1 100644 --- a/jmetal/lab/visualization/__init__.py +++ b/jmetal/lab/visualization/__init__.py @@ -1,9 +1,8 @@ from jmetal.lab.statistical_test.critical_distance import CDplot + from .interactive import InteractivePlot from .plotting import Plot from .posterior import plot_posterior from .streaming import StreamingPlot -__all__ = [ - 'Plot', 'InteractivePlot', 'StreamingPlot', 'CDplot', 'plot_posterior' -] +__all__ = ["Plot", "InteractivePlot", "StreamingPlot", "CDplot", "plot_posterior"] diff --git a/jmetal/lab/visualization/chord_plot.py b/jmetal/lab/visualization/chord_plot.py index de69a0dd..59415ea4 100644 --- a/jmetal/lab/visualization/chord_plot.py +++ b/jmetal/lab/visualization/chord_plot.py @@ -14,30 +14,41 @@ def polar_to_cartesian(r, theta): return np.array([r * np.cos(theta), r * np.sin(theta)]) -def draw_sector(start_angle=0, end_angle=60, radius=1.0, width=0.2, lw=2, ls='-', ax=None, fc=(1, 0, 0), ec=(0, 0, 0), - z_order=1): +def draw_sector( + start_angle=0, end_angle=60, radius=1.0, width=0.2, lw=2, ls="-", ax=None, fc=(1, 0, 0), ec=(0, 0, 0), z_order=1 +): if start_angle > end_angle: start_angle, end_angle = end_angle, start_angle - start_angle *= np.pi / 180. - end_angle *= np.pi / 180. + start_angle *= np.pi / 180.0 + end_angle *= np.pi / 180.0 # https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves - opt = 4. / 3. * np.tan((end_angle - start_angle) / 4.) * radius + opt = 4.0 / 3.0 * np.tan((end_angle - start_angle) / 4.0) * radius inner = radius * (1 - width) - vertsPath = [polar_to_cartesian(radius, start_angle), - polar_to_cartesian(radius, start_angle) + polar_to_cartesian(opt, start_angle + 0.5 * np.pi), - polar_to_cartesian(radius, end_angle) + polar_to_cartesian(opt, end_angle - 0.5 * np.pi), - polar_to_cartesian(radius, end_angle), - polar_to_cartesian(inner, end_angle), - polar_to_cartesian(inner, end_angle) + polar_to_cartesian(opt * (1 - width), end_angle - 0.5 * np.pi), - polar_to_cartesian(inner, start_angle) + polar_to_cartesian(opt * (1 - width), - start_angle + 0.5 * np.pi), - polar_to_cartesian(inner, start_angle), - polar_to_cartesian(radius, start_angle)] - - codesPaths = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.LINETO, Path.CURVE4, Path.CURVE4, - Path.CURVE4, Path.CLOSEPOLY] + vertsPath = [ + polar_to_cartesian(radius, start_angle), + polar_to_cartesian(radius, start_angle) + polar_to_cartesian(opt, start_angle + 0.5 * np.pi), + polar_to_cartesian(radius, end_angle) + polar_to_cartesian(opt, end_angle - 0.5 * np.pi), + polar_to_cartesian(radius, end_angle), + polar_to_cartesian(inner, end_angle), + polar_to_cartesian(inner, end_angle) + polar_to_cartesian(opt * (1 - width), end_angle - 0.5 * np.pi), + polar_to_cartesian(inner, start_angle) + polar_to_cartesian(opt * (1 - width), start_angle + 0.5 * np.pi), + polar_to_cartesian(inner, start_angle), + polar_to_cartesian(radius, start_angle), + ] + + codesPaths = [ + Path.MOVETO, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.LINETO, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CLOSEPOLY, + ] if ax is None: return vertsPath, codesPaths @@ -45,38 +56,64 @@ def draw_sector(start_angle=0, end_angle=60, radius=1.0, width=0.2, lw=2, ls='-' path = Path(vertsPath, codesPaths) patch = patches.PathPatch(path, facecolor=fc, edgecolor=ec, lw=lw, linestyle=ls, zorder=z_order) ax.add_patch(patch) - return (patch) - - -def draw_chord(start_angle1=0, end_angle1=60, start_angle2=180, end_angle2=240, radius=1.0, chord_width=0.7, ax=None, - color=(1, 0, 0), z_order=1): + return patch + + +def draw_chord( + start_angle1=0, + end_angle1=60, + start_angle2=180, + end_angle2=240, + radius=1.0, + chord_width=0.7, + ax=None, + color=(1, 0, 0), + z_order=1, +): if start_angle1 > end_angle1: start_angle1, end_angle1 = end_angle1, start_angle1 if start_angle2 > end_angle2: start_angle2, end_angle2 = end_angle2, start_angle2 - start_angle1 *= np.pi / 180. - end_angle1 *= np.pi / 180. - start_angle2 *= np.pi / 180. - end_angle2 *= np.pi / 180. + start_angle1 *= np.pi / 180.0 + end_angle1 *= np.pi / 180.0 + start_angle2 *= np.pi / 180.0 + end_angle2 *= np.pi / 180.0 - optAngle1 = 4. / 3. * np.tan((end_angle1 - start_angle1) / 4.) * radius - optAngle2 = 4. / 3. * np.tan((end_angle2 - start_angle2) / 4.) * radius + optAngle1 = 4.0 / 3.0 * np.tan((end_angle1 - start_angle1) / 4.0) * radius + optAngle2 = 4.0 / 3.0 * np.tan((end_angle2 - start_angle2) / 4.0) * radius rchord = radius * (1 - chord_width) - vertsPath = [polar_to_cartesian(radius, start_angle1), - polar_to_cartesian(radius, start_angle1) + polar_to_cartesian(optAngle1, start_angle1 + 0.5 * np.pi), - polar_to_cartesian(radius, end_angle1) + polar_to_cartesian(optAngle1, end_angle1 - 0.5 * np.pi), - polar_to_cartesian(radius, end_angle1), - polar_to_cartesian(rchord, end_angle1), polar_to_cartesian(rchord, start_angle2), - polar_to_cartesian(radius, start_angle2), - polar_to_cartesian(radius, start_angle2) + polar_to_cartesian(optAngle2, start_angle2 + 0.5 * np.pi), - polar_to_cartesian(radius, end_angle2) + polar_to_cartesian(optAngle2, end_angle2 - 0.5 * np.pi), - polar_to_cartesian(radius, end_angle2), - polar_to_cartesian(rchord, end_angle2), polar_to_cartesian(rchord, start_angle1), - polar_to_cartesian(radius, start_angle1)] - - codesPath = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, - Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CURVE4] + vertsPath = [ + polar_to_cartesian(radius, start_angle1), + polar_to_cartesian(radius, start_angle1) + polar_to_cartesian(optAngle1, start_angle1 + 0.5 * np.pi), + polar_to_cartesian(radius, end_angle1) + polar_to_cartesian(optAngle1, end_angle1 - 0.5 * np.pi), + polar_to_cartesian(radius, end_angle1), + polar_to_cartesian(rchord, end_angle1), + polar_to_cartesian(rchord, start_angle2), + polar_to_cartesian(radius, start_angle2), + polar_to_cartesian(radius, start_angle2) + polar_to_cartesian(optAngle2, start_angle2 + 0.5 * np.pi), + polar_to_cartesian(radius, end_angle2) + polar_to_cartesian(optAngle2, end_angle2 - 0.5 * np.pi), + polar_to_cartesian(radius, end_angle2), + polar_to_cartesian(rchord, end_angle2), + polar_to_cartesian(rchord, start_angle1), + polar_to_cartesian(radius, start_angle1), + ] + + codesPath = [ + Path.MOVETO, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + ] if ax == None: return vertsPath, codesPath @@ -84,7 +121,7 @@ def draw_chord(start_angle1=0, end_angle1=60, start_angle2=180, end_angle2=240, path = Path(vertsPath, codesPath) patch = patches.PathPatch(path, facecolor=color + (0.5,), edgecolor=color + (0.4,), lw=2, alpha=0.5) ax.add_patch(patch) - return (patch) + return patch def hover_over_bin(event, handle_tickers, handle_plots, colors, fig): @@ -109,8 +146,14 @@ def hover_over_bin(event, handle_tickers, handle_plots, colors, fig): fig.canvas.draw_idle() -def chord_diagram(solutions: List[FloatSolution], nbins='auto', ax=None, obj_labels=None, - prop_labels=dict(fontsize=13, ha='center', va='center'), pad=6): +def chord_diagram( + solutions: List[FloatSolution], + nbins="auto", + ax=None, + obj_labels=None, + prop_labels=dict(fontsize=13, ha="center", va="center"), + pad=6, +): points_matrix = np.array([s.objectives for s in solutions]) (NPOINTS, NOBJ) = np.shape(points_matrix) @@ -119,13 +162,13 @@ def chord_diagram(solutions: List[FloatSolution], nbins='auto', ax=None, obj_lab if ax is None: fig = plt.figure(figsize=(6, 6)) - ax = plt.axes([0, 0, 1, 1], aspect='equal') + ax = plt.axes([0, 0, 1, 1], aspect="equal") ax.set_xlim(-2.3, 2.3) ax.set_ylim(-2.3, 2.3) - ax.axis('off') + ax.axis("off") - y = np.array([1. / NOBJ] * NOBJ) * (360 - pad * NOBJ) + y = np.array([1.0 / NOBJ] * NOBJ) * (360 - pad * NOBJ) sector_angles = [] labels_pos_and_ros = [] @@ -145,9 +188,13 @@ def chord_diagram(solutions: List[FloatSolution], nbins='auto', ax=None, obj_lab angleText -= 270 labels_pos_and_ros.append( - tuple(polar_to_cartesian(1.0, 0.5 * (start_angle + end_angle) * np.pi / 180.)) + (angle_diff,) + - tuple(polar_to_cartesian(0.725, (start_angle - 2.5) * np.pi / 180.)) + (angleText,) + - tuple(polar_to_cartesian(0.85, (start_angle - 2.5) * np.pi / 180.)) + (angleText,)) + tuple(polar_to_cartesian(1.0, 0.5 * (start_angle + end_angle) * np.pi / 180.0)) + + (angle_diff,) + + tuple(polar_to_cartesian(0.725, (start_angle - 2.5) * np.pi / 180.0)) + + (angleText,) + + tuple(polar_to_cartesian(0.85, (start_angle - 2.5) * np.pi / 180.0)) + + (angleText,) + ) start_angle = end_angle + pad arc_points = [] @@ -164,15 +211,41 @@ def chord_diagram(solutions: List[FloatSolution], nbins='auto', ax=None, obj_lab handle_tickers = [] handle_plots = [] - for iobj in tqdm(range(NOBJ), ascii=True, desc='Chord diagram'): - draw_sector(start_angle=sector_angles[iobj][0], end_angle=sector_angles[iobj][1], radius=0.925, width=0.225, - ax=ax, - fc=(1, 1, 1, 0.0), ec=(0, 0, 0), lw=2, z_order=10) - draw_sector(start_angle=sector_angles[iobj][0], end_angle=sector_angles[iobj][1], radius=0.925, width=0.05, - ax=ax, - fc=colors[iobj], ec=(0, 0, 0), lw=2, z_order=10) - draw_sector(start_angle=sector_angles[iobj][0], end_angle=sector_angles[iobj][1], radius=0.7 + 0.15, width=0.0, - ax=ax, fc=colors[iobj], ec=colors[iobj], lw=2, ls=':', z_order=5) + for iobj in tqdm(range(NOBJ), ascii=True, desc="Chord diagram"): + draw_sector( + start_angle=sector_angles[iobj][0], + end_angle=sector_angles[iobj][1], + radius=0.925, + width=0.225, + ax=ax, + fc=(1, 1, 1, 0.0), + ec=(0, 0, 0), + lw=2, + z_order=10, + ) + draw_sector( + start_angle=sector_angles[iobj][0], + end_angle=sector_angles[iobj][1], + radius=0.925, + width=0.05, + ax=ax, + fc=colors[iobj], + ec=(0, 0, 0), + lw=2, + z_order=10, + ) + draw_sector( + start_angle=sector_angles[iobj][0], + end_angle=sector_angles[iobj][1], + radius=0.7 + 0.15, + width=0.0, + ax=ax, + fc=colors[iobj], + ec=colors[iobj], + lw=2, + ls=":", + z_order=5, + ) histValues, binsDim = np.histogram(points_matrix[:, iobj], bins=nbins) relativeHeightBinPre = 0.025 @@ -181,70 +254,122 @@ def chord_diagram(solutions: List[FloatSolution], nbins='auto', ax=None, obj_lab handle_plots.append([]) for indexBin in range(len(histValues)): - startAngleBin = sector_angles[iobj][0] + (sector_angles[iobj][1] - sector_angles[iobj][0]) * binsDim[ - indexBin] - endAngleBin = sector_angles[iobj][0] + (sector_angles[iobj][1] - sector_angles[iobj][0]) * binsDim[ - indexBin + 1] + startAngleBin = ( + sector_angles[iobj][0] + (sector_angles[iobj][1] - sector_angles[iobj][0]) * binsDim[indexBin] + ) + endAngleBin = ( + sector_angles[iobj][0] + (sector_angles[iobj][1] - sector_angles[iobj][0]) * binsDim[indexBin + 1] + ) relativeHeightBin = 0.15 * histValues[indexBin] / max(histValues) handle_tickers[-1].append( - draw_sector(start_angle=startAngleBin, end_angle=endAngleBin, radius=0.69, width=0.08, ax=ax, lw=1, - fc=(1, 1, 1), ec=(0, 0, 0))) + draw_sector( + start_angle=startAngleBin, + end_angle=endAngleBin, + radius=0.69, + width=0.08, + ax=ax, + lw=1, + fc=(1, 1, 1), + ec=(0, 0, 0), + ) + ) handle_plots[-1].append([]) if histValues[indexBin] > 0: - draw_sector(start_angle=startAngleBin, end_angle=endAngleBin, radius=0.7 + relativeHeightBin, width=0, - ax=ax, lw=1, fc=colors[iobj], ec=colors[iobj]) - plotPoint1 = polar_to_cartesian(0.7 + relativeHeightBinPre, startAngleBin * np.pi / 180.) - plotPoint2 = polar_to_cartesian(0.7 + relativeHeightBin, startAngleBin * np.pi / 180.) + draw_sector( + start_angle=startAngleBin, + end_angle=endAngleBin, + radius=0.7 + relativeHeightBin, + width=0, + ax=ax, + lw=1, + fc=colors[iobj], + ec=colors[iobj], + ) + plotPoint1 = polar_to_cartesian(0.7 + relativeHeightBinPre, startAngleBin * np.pi / 180.0) + plotPoint2 = polar_to_cartesian(0.7 + relativeHeightBin, startAngleBin * np.pi / 180.0) plt.plot([plotPoint1[0], plotPoint2[0]], [plotPoint1[1], plotPoint2[1]], c=colors[iobj], lw=1) relativeHeightBinPre = relativeHeightBin else: - plotPoint1 = polar_to_cartesian(0.7 + relativeHeightBinPre, startAngleBin * np.pi / 180.) - plotPoint2 = polar_to_cartesian(0.725 + relativeHeightBin, startAngleBin * np.pi / 180.) + plotPoint1 = polar_to_cartesian(0.7 + relativeHeightBinPre, startAngleBin * np.pi / 180.0) + plotPoint2 = polar_to_cartesian(0.725 + relativeHeightBin, startAngleBin * np.pi / 180.0) plt.plot([plotPoint1[0], plotPoint2[0]], [plotPoint1[1], plotPoint2[1]], c=colors[iobj], lw=1) relativeHeightBinPre = 0.025 if indexBin == len(histValues) - 1: - plotPoint1 = polar_to_cartesian(0.7 + relativeHeightBin, endAngleBin * np.pi / 180.) - plotPoint2 = polar_to_cartesian(0.725, endAngleBin * np.pi / 180.) + plotPoint1 = polar_to_cartesian(0.7 + relativeHeightBin, endAngleBin * np.pi / 180.0) + plotPoint2 = polar_to_cartesian(0.725, endAngleBin * np.pi / 180.0) plt.plot([plotPoint1[0], plotPoint2[0]], [plotPoint1[1], plotPoint2[1]], c=colors[iobj], lw=1) for ipoint in range(len(points_matrix)): - plotPoint1 = polar_to_cartesian(0.6, arc_points[ipoint][iobj][0] * np.pi / 180.) - plotPoint2 = polar_to_cartesian(0.6, arc_points[ipoint][iobj][0] * np.pi / 180.) - plt.plot([plotPoint1[0], plotPoint2[0]], [plotPoint1[1], plotPoint2[1]], marker='o', markersize=3, - c=colors[iobj], lw=2) - - if binsDim[indexBin] < points_matrix[ipoint, iobj] <= binsDim[ - indexBin + 1]: + plotPoint1 = polar_to_cartesian(0.6, arc_points[ipoint][iobj][0] * np.pi / 180.0) + plotPoint2 = polar_to_cartesian(0.6, arc_points[ipoint][iobj][0] * np.pi / 180.0) + plt.plot( + [plotPoint1[0], plotPoint2[0]], + [plotPoint1[1], plotPoint2[1]], + marker="o", + markersize=3, + c=colors[iobj], + lw=2, + ) + + if binsDim[indexBin] < points_matrix[ipoint, iobj] <= binsDim[indexBin + 1]: for jdim in range(NOBJ): if jdim >= 1: handle_plots[iobj][indexBin].append( - draw_chord(arc_points[ipoint][jdim - 1][0], arc_points[ipoint][jdim - 1][1], - arc_points[ipoint][jdim][0], arc_points[ipoint][jdim][1], radius=0.55, - color=colors[iobj], chord_width=1, ax=ax)) + draw_chord( + arc_points[ipoint][jdim - 1][0], + arc_points[ipoint][jdim - 1][1], + arc_points[ipoint][jdim][0], + arc_points[ipoint][jdim][1], + radius=0.55, + color=colors[iobj], + chord_width=1, + ax=ax, + ) + ) handle_plots[iobj][indexBin][-1].set_visible(False) handle_plots[iobj][indexBin].append( - draw_chord(arc_points[ipoint][-1][0], arc_points[ipoint][-1][1], arc_points[ipoint][0][0], - arc_points[ipoint][0][1], radius=0.55, color=colors[iobj], chord_width=1, ax=ax)) + draw_chord( + arc_points[ipoint][-1][0], + arc_points[ipoint][-1][1], + arc_points[ipoint][0][0], + arc_points[ipoint][0][1], + radius=0.55, + color=colors[iobj], + chord_width=1, + ax=ax, + ) + ) handle_plots[iobj][indexBin][-1].set_visible(False) if obj_labels is None: - obj_labels = ['$f_{' + str(i) + '}(\mathbf{x})$' for i in range(NOBJ)] + obj_labels = ["$f_{" + str(i) + "}(\mathbf{x})$" for i in range(NOBJ)] - prop_legend_bins = dict(fontsize=9, ha='center', va='center') + prop_legend_bins = dict(fontsize=9, ha="center", va="center") for i in range(NOBJ): - p0, p1 = polar_to_cartesian(0.975, sector_angles[i][0] * np.pi / 180.) - ax.text(p0, p1, '0', **prop_legend_bins) - p0, p1 = polar_to_cartesian(0.975, sector_angles[i][1] * np.pi / 180.) - ax.text(p0, p1, '1', **prop_legend_bins) - ax.text(labels_pos_and_ros[i][0], labels_pos_and_ros[i][1], obj_labels[i], rotation=labels_pos_and_ros[i][2], - **prop_labels) - ax.text(labels_pos_and_ros[i][3], labels_pos_and_ros[i][4], '0', **prop_legend_bins, color=colors[i]) - ax.text(labels_pos_and_ros[i][6], labels_pos_and_ros[i][7], str(max_hist_values[i]), **prop_legend_bins, - color=colors[i]) + p0, p1 = polar_to_cartesian(0.975, sector_angles[i][0] * np.pi / 180.0) + ax.text(p0, p1, "0", **prop_legend_bins) + p0, p1 = polar_to_cartesian(0.975, sector_angles[i][1] * np.pi / 180.0) + ax.text(p0, p1, "1", **prop_legend_bins) + ax.text( + labels_pos_and_ros[i][0], + labels_pos_and_ros[i][1], + obj_labels[i], + rotation=labels_pos_and_ros[i][2], + **prop_labels + ) + ax.text(labels_pos_and_ros[i][3], labels_pos_and_ros[i][4], "0", **prop_legend_bins, color=colors[i]) + ax.text( + labels_pos_and_ros[i][6], + labels_pos_and_ros[i][7], + str(max_hist_values[i]), + **prop_legend_bins, + color=colors[i] + ) plt.axis([-1.2, 1.2, -1.2, 1.2]) - fig.canvas.mpl_connect("motion_notify_event", - lambda event: hover_over_bin(event, handle_tickers, handle_plots, colors, fig)) + fig.canvas.mpl_connect( + "motion_notify_event", lambda event: hover_over_bin(event, handle_tickers, handle_plots, colors, fig) + ) plt.show() diff --git a/jmetal/lab/visualization/interactive.py b/jmetal/lab/visualization/interactive.py index 00d78d42..673ee005 100644 --- a/jmetal/lab/visualization/interactive.py +++ b/jmetal/lab/visualization/interactive.py @@ -1,5 +1,5 @@ import logging -from typing import TypeVar, List +from typing import List, TypeVar import pandas as pd from plotly import graph_objs as go @@ -8,25 +8,26 @@ from jmetal.lab.visualization.plotting import Plot -LOGGER = logging.getLogger('jmetal') +logger = logging.getLogger(__name__) -S = TypeVar('S') +S = TypeVar("S") class InteractivePlot(Plot): - - def __init__(self, - title: str = 'Pareto front approximation', - reference_front: List[S] = None, - reference_point: list = None, - axis_labels: list = None): + def __init__( + self, + title: str = "Pareto front approximation", + reference_front: List[S] = None, + reference_point: list = None, + axis_labels: list = None, + ): super(InteractivePlot, self).__init__(title, reference_front, reference_point, axis_labels) self.figure = None self.layout = None self.data = [] - def plot(self, front, label=None, normalize: bool = False, filename: str = None, format: str = 'HTML'): - """ Plot a front of solutions (2D, 3D or parallel coordinates). + def plot(self, front, label=None, normalize: bool = False, filename: str = None, format: str = "HTML"): + """Plot a front of solutions (2D, 3D or parallel coordinates). :param front: List of solutions. :param label: Front name. @@ -39,50 +40,57 @@ def plot(self, front, label=None, normalize: bool = False, filename: str = None, self.layout = go.Layout( margin=dict(l=80, r=80, b=80, t=150), height=800, - title='{}
{}'.format(self.plot_title, label[0]), + title="{}
{}".format(self.plot_title, label[0]), scene=dict( xaxis=dict(title=self.axis_labels[0:1][0] if self.axis_labels[0:1] else None), yaxis=dict(title=self.axis_labels[1:2][0] if self.axis_labels[1:2] else None), - zaxis=dict(title=self.axis_labels[2:3][0] if self.axis_labels[2:3] else None) + zaxis=dict(title=self.axis_labels[2:3][0] if self.axis_labels[2:3] else None), ), - hovermode='closest' + hovermode="closest", ) # If any reference front, plot if self.reference_front: points, _ = self.get_points(self.reference_front) - trace = self.__generate_trace(points=points, legend='Reference front', normalize=normalize, - color='black', size=2) + trace = self.__generate_trace( + points=points, legend="Reference front", normalize=normalize, color="black", size=2 + ) self.data.append(trace) # If any reference point, plot if self.reference_point: points = pd.DataFrame(self.reference_point) - trace = self.__generate_trace(points=points, legend='Reference point', color='red', size=8) + trace = self.__generate_trace(points=points, legend="Reference point", color="red", size=8) self.data.append(trace) # Get points and metadata points, _ = self.get_points(front) metadata = list(solution.__str__() for solution in front) - trace = self.__generate_trace(points=points, metadata=metadata, legend='Front approximation', - normalize=normalize) + trace = self.__generate_trace( + points=points, metadata=metadata, legend="Front approximation", normalize=normalize + ) self.data.append(trace) self.figure = go.Figure(data=self.data, layout=self.layout) # Plot the figure if filename: - if format == 'HTML': + if format == "HTML": self.export_to_html(filename) + logger.info("Figure {_filename} exported to HTML file") else: - pio.write_image(self.figure, filename + '.' + format) + _filename = filename + "." + format + + pio.write_image(self.figure, _filename) + logger.info("Figure {_filename} saved to file") def export_to_html(self, filename: str) -> str: - """ Export the graph to an interactive HTML (solutions can be selected to show some metadata). + """Export the graph to an interactive HTML (solutions can be selected to show some metadata). :param filename: Output file name. - :return: Script as string. """ - html_string = ''' + :return: Script as string.""" + html_string = ( + """ @@ -92,7 +100,9 @@ def export_to_html(self, filename: str) -> str: - ''' + self.export_to_div(filename=None, include_plotlyjs=False) + ''' + """ + + self.export_to_div(filename=None, include_plotlyjs=False) + + """ - ''' + """ + ) - with open(filename + '.html', 'w') as outf: + with open(filename + ".html", "w") as outf: outf.write(html_string) return html_string def export_to_div(self, filename=None, include_plotlyjs: bool = False) -> str: - """ Export as a `div` for embedding the graph in an HTML file. + """Export as a `div` for embedding the graph in an HTML file. :param filename: Output file name (if desired, default to None). :param include_plotlyjs: If True, include plot.ly JS script (default to False). :return: Script as string. """ - script = offline.plot(self.figure, output_type='div', include_plotlyjs=include_plotlyjs, show_link=False) + script = offline.plot(self.figure, output_type="div", include_plotlyjs=include_plotlyjs, show_link=False) if filename: - with open(filename + '.html', 'w') as outf: + with open(filename + ".html", "w") as outf: outf.write(script) return script - def __generate_trace(self, points: pd.DataFrame, legend: str, metadata: list = None, normalize: bool = False, - **kwargs): + def __generate_trace( + self, points: pd.DataFrame, legend: str, metadata: list = None, normalize: bool = False, **kwargs + ): dimension = points.shape[1] # tweak points size for 3D plots @@ -154,49 +166,33 @@ def __generate_trace(self, points: pd.DataFrame, legend: str, metadata: list = N points = (points - points.min()) / (points.max() - points.min()) marker = dict( - color='#236FA4', - size=marker_size, - symbol='circle', - line=dict( - color='#236FA4', - width=1 - ), - opacity=0.8 + color="#236FA4", size=marker_size, symbol="circle", line=dict(color="#236FA4", width=1), opacity=0.8 ) marker.update(**kwargs) if dimension == 2: trace = go.Scattergl( - x=points[0], - y=points[1], - mode='markers', - marker=marker, - name=legend, - customdata=metadata + x=points[0], y=points[1], mode="markers", marker=marker, name=legend, customdata=metadata ) elif dimension == 3: trace = go.Scatter3d( - x=points[0], - y=points[1], - z=points[2], - mode='markers', - marker=marker, - name=legend, - customdata=metadata + x=points[0], y=points[1], z=points[2], mode="markers", marker=marker, name=legend, customdata=metadata ) else: dimensions = list() for column in points: dimensions.append( - dict(range=[0, 1], - label=self.axis_labels[column:column + 1][0] if self.axis_labels[column:column + 1] else None, - values=points[column]) + dict( + range=[0, 1], + label=self.axis_labels[column : column + 1][0] + if self.axis_labels[column : column + 1] + else None, + values=points[column], + ) ) trace = go.Parcoords( - line=dict( - color='#236FA4' - ), + line=dict(color="#236FA4"), dimensions=dimensions, name=legend, ) diff --git a/jmetal/lab/visualization/plotting.py b/jmetal/lab/visualization/plotting.py index dce85dc7..222561d4 100644 --- a/jmetal/lab/visualization/plotting.py +++ b/jmetal/lab/visualization/plotting.py @@ -1,23 +1,24 @@ import logging -from typing import TypeVar, List, Tuple +from typing import List, Tuple, TypeVar import numpy as np import pandas as pd from matplotlib import pyplot as plt from pandas import plotting -LOGGER = logging.getLogger('jmetal') +logger = logging.getLogger(__name__) -S = TypeVar('S') +S = TypeVar("S") class Plot: - - def __init__(self, - title: str = 'Pareto front approximation', - reference_front: List[S] = None, - reference_point: list = None, - axis_labels: list = None): + def __init__( + self, + title: str = "Pareto front approximation", + reference_front: List[S] = None, + reference_point: list = None, + axis_labels: list = None, + ): """ :param title: Title of the graph. :param axis_labels: List of axis labels. @@ -36,19 +37,19 @@ def __init__(self, @staticmethod def get_points(solutions: List[S]) -> Tuple[pd.DataFrame, int]: - """ Get points for each solution of the front. + """Get points for each solution of the front. :param solutions: List of solutions. :return: Pandas dataframe with one column for each objective and one row for each solution. """ if solutions is None: - raise Exception('Front is none!') + raise Exception("Front is none!") points = pd.DataFrame(list(solution.objectives for solution in solutions)) return points, points.shape[1] - def plot(self, front, label='', normalize: bool = False, filename: str = None, format: str = 'eps'): - """ Plot any arbitrary number of fronts in 2D, 3D or p-coords. + def plot(self, front, label="", normalize: bool = False, filename: str = None, format: str = "eps"): + """Plot any arbitrary number of fronts in 2D, 3D or p-coords. :param front: Pareto front or a list of them. :param label: Pareto front title or a list of them. @@ -63,7 +64,7 @@ def plot(self, front, label='', normalize: bool = False, filename: str = None, f label = [label] if len(front) != len(label): - raise Exception('Number of fronts and labels must be the same') + raise Exception("Number of fronts and labels must be the same") dimension = front[0][0].number_of_objectives @@ -74,8 +75,8 @@ def plot(self, front, label='', normalize: bool = False, filename: str = None, f else: self.pcoords(front, normalize, filename, format) - def two_dim(self, fronts: List[list], labels: List[str] = None, filename: str = None, format: str = 'eps'): - """ Plot any arbitrary number of fronts in 2D. + def two_dim(self, fronts: List[list], labels: List[str] = None, filename: str = None, format: str = "eps"): + """Plot any arbitrary number of fronts in 2D. :param fronts: List of fronts (containing solutions). :param labels: List of fronts title (if any). @@ -93,33 +94,36 @@ def two_dim(self, fronts: List[list], labels: List[str] = None, filename: str = points, _ = self.get_points(fronts[i]) ax = fig.add_subplot(n, n, i + 1) - points.plot(kind='scatter', x=0, y=1, ax=ax, s=10, color='#236FA4', alpha=1.0) + points.plot(kind="scatter", x=0, y=1, ax=ax, s=10, color="#236FA4", alpha=1.0) if labels: ax.set_title(labels[i]) if self.reference_front: - reference.plot(x=0, y=1, ax=ax, color='k', legend=False) + reference.plot(x=0, y=1, ax=ax, color="k", legend=False) if self.reference_point: for point in self.reference_point: - plt.plot([point[0]], [point[1]], marker='o', markersize=5, color='r') - plt.axvline(x=point[0], color='r', linestyle=':') - plt.axhline(y=point[1], color='r', linestyle=':') + plt.plot([point[0]], [point[1]], marker="o", markersize=5, color="r") + plt.axvline(x=point[0], color="r", linestyle=":") + plt.axhline(y=point[1], color="r", linestyle=":") if self.axis_labels: plt.xlabel(self.axis_labels[0]) plt.ylabel(self.axis_labels[1]) if filename: - plt.savefig(filename + '.' + format, format=format, dpi=200) + _filename = filename + "." + format + + plt.savefig(_filename, format=format, dpi=1000) + logger.info("Figure {_filename} saved to file") else: plt.show() plt.close(fig=fig) - def three_dim(self, fronts: List[list], labels: List[str] = None, filename: str = None, format: str = 'eps'): - """ Plot any arbitrary number of fronts in 3D. + def three_dim(self, fronts: List[list], labels: List[str] = None, filename: str = None, format: str = "eps"): + """Plot any arbitrary number of fronts in 3D. :param fronts: List of fronts (containing solutions). :param labels: List of fronts title (if any). @@ -130,18 +134,22 @@ def three_dim(self, fronts: List[list], labels: List[str] = None, filename: str fig.suptitle(self.plot_title, fontsize=16) for i, _ in enumerate(fronts): - ax = fig.add_subplot(n, n, i + 1, projection='3d') - ax.scatter([s.objectives[0] for s in fronts[i]], - [s.objectives[1] for s in fronts[i]], - [s.objectives[2] for s in fronts[i]]) + ax = fig.add_subplot(n, n, i + 1, projection="3d") + ax.scatter( + [s.objectives[0] for s in fronts[i]], + [s.objectives[1] for s in fronts[i]], + [s.objectives[2] for s in fronts[i]], + ) if labels: ax.set_title(labels[i]) if self.reference_front: - ax.scatter([s.objectives[0] for s in self.reference_front], - [s.objectives[1] for s in self.reference_front], - [s.objectives[2] for s in self.reference_front]) + ax.scatter( + [s.objectives[0] for s in self.reference_front], + [s.objectives[1] for s in self.reference_front], + [s.objectives[2] for s in self.reference_front], + ) if self.reference_point: # todo @@ -153,14 +161,17 @@ def three_dim(self, fronts: List[list], labels: List[str] = None, filename: str ax.locator_params(nbins=4) if filename: - plt.savefig(filename + '.' + format, format=format, dpi=1000) + _filename = filename + "." + format + + plt.savefig(_filename, format=format, dpi=1000) + logger.info("Figure {_filename} saved to file") else: plt.show() plt.close(fig=fig) - def pcoords(self, fronts: List[list], normalize: bool = False, filename: str = None, format: str = 'eps'): - """ Plot any arbitrary number of fronts in parallel coordinates. + def pcoords(self, fronts: List[list], normalize: bool = False, filename: str = None, format: str = "eps"): + """Plot any arbitrary number of fronts in parallel coordinates. :param fronts: List of fronts (containing solutions). :param filename: Output filename. @@ -178,8 +189,8 @@ def pcoords(self, fronts: List[list], normalize: bool = False, filename: str = N ax = fig.add_subplot(n, n, i + 1) min_, max_ = points.values.min(), points.values.max() - points['scale'] = np.linspace(0, 1, len(points)) * (max_ - min_) + min_ - pd.plotting.parallel_coordinates(points, 'scale', ax=ax) + points["scale"] = np.linspace(0, 1, len(points)) * (max_ - min_) + min_ + pd.plotting.parallel_coordinates(points, "scale", ax=ax) ax.get_legend().remove() @@ -187,7 +198,7 @@ def pcoords(self, fronts: List[list], normalize: bool = False, filename: str = N ax.set_xticklabels(self.axis_labels) if filename: - plt.savefig(filename + '.' + format, format=format, dpi=1000) + plt.savefig(filename + "." + format, format=format, dpi=1000) else: plt.show() diff --git a/jmetal/lab/visualization/posterior.py b/jmetal/lab/visualization/posterior.py index 7f5c4e8f..f28827ee 100644 --- a/jmetal/lab/visualization/posterior.py +++ b/jmetal/lab/visualization/posterior.py @@ -1,10 +1,19 @@ +import logging + import numpy as np import pandas as pd from matplotlib import pyplot as plt +logger = logging.getLogger(__name__) + -def plot_posterior(sample, higher_is_better: bool = False, min_points_per_hexbin: int = 2, alg_names: list = None, - filename: str = 'posterior.eps'): +def plot_posterior( + sample, + higher_is_better: bool = False, + min_points_per_hexbin: int = 2, + alg_names: list = None, + filename: str = "posterior.eps", +): """ Plots the sample from posterior distribution of a Bayesian statistical test. Parameters: @@ -24,20 +33,18 @@ def plot_posterior(sample, higher_is_better: bool = False, min_points_per_hexbin if sample.ndim == 2: nrow, ncol = sample.shape if ncol != 3: - raise ValueError( - 'Initialization ERROR. Incorrect number of dimensions in axis 1.') + raise ValueError("Initialization ERROR. Incorrect number of dimensions in axis 1.") else: - raise ValueError( - 'Initialization ERROR. Incorrect number of dimensions for sample') + raise ValueError("Initialization ERROR. Incorrect number of dimensions for sample") def transform(p): lambda1, lambda2, lambda3 = p.T - x = (0.1 * lambda1 + 0.5 * lambda2 + 0.9 * lambda3) + x = 0.1 * lambda1 + 0.5 * lambda2 + 0.9 * lambda3 y = (0.2 * lambda1 + 1.4 * lambda2 + 0.2 * lambda3) / np.sqrt(3) return np.vstack((x, y)).T # Initialize figure - fig = plt.figure(figsize=(5, 5), facecolor='white') + fig = plt.figure(figsize=(5, 5), facecolor="white") ax = fig.add_axes([0, 0, 1, 1]) ax.set_xlim(0, 1) ax.set_ylim(0, 1) @@ -47,34 +54,22 @@ def transform(p): if not higher_is_better: if not alg_names: - ax.text(x=0.5, y=1.4 / np.sqrt(3) + 0.005, - s='P(rope)', ha='center', va='bottom') - ax.text(x=0.15, y=0.175 / np.sqrt(3) - 0.005, - s='P(alg1 None: if self.sc is None: - raise Exception('Figure is none') + raise Exception("Figure is none") points, dimension = Plot.get_points(front) @@ -104,30 +112,32 @@ def update(self, front: List[S], reference_point: list = None) -> None: pause(0.01) def create_layout(self, dimension: int) -> None: + logger.info("Creating figure layout") + self.fig.canvas.set_window_title(self.plot_title) self.fig.suptitle(self.plot_title, fontsize=16) if dimension == 2: # Stylize axis - self.ax.spines['top'].set_visible(False) - self.ax.spines['right'].set_visible(False) + self.ax.spines["top"].set_visible(False) + self.ax.spines["right"].set_visible(False) self.ax.get_xaxis().tick_bottom() self.ax.get_yaxis().tick_left() elif dimension == 3: self.ax = Axes3D(self.fig) - self.ax.autoscale(enable=True, axis='both') + self.ax.autoscale(enable=True, axis="both") else: - raise Exception('Dimension must be either 2 or 3') + raise Exception("Dimension must be either 2 or 3") self.ax.set_autoscale_on(True) self.ax.autoscale_view(True, True, True) # Style options - self.ax.grid(color='#f0f0f5', linestyle='-', linewidth=0.5, alpha=0.5) + self.ax.grid(color="#f0f0f5", linestyle="-", linewidth=0.5, alpha=0.5) def pause(interval: float): - backend = plt.rcParams['backend'] + backend = plt.rcParams["backend"] if backend in matplotlib.rcsetup.interactive_bk: figManager = matplotlib._pylab_helpers.Gcf.get_active() diff --git a/jmetal/logger.py b/jmetal/logger.py new file mode 100644 index 00000000..0251e744 --- /dev/null +++ b/jmetal/logger.py @@ -0,0 +1,29 @@ +import logging.config + + +def configure_logging(): + DEFAULT_LOGGING_CONFIG = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "basic": { + "format": "[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s", + } + }, + "handlers": { + "console": { + "formatter": "basic", + "class": "logging.StreamHandler", + "stream": "ext://sys.stderr", + } + }, + "loggers": { + "jmetal": {"handlers": ["console"], "level": "DEBUG"}, + }, + } + + logging.config.dictConfig(DEFAULT_LOGGING_CONFIG) + + +def get_logger(module): + return logging.getLogger(module) diff --git a/jmetal/operator/__init__.py b/jmetal/operator/__init__.py index cd0b7f69..f4bf96b7 100644 --- a/jmetal/operator/__init__.py +++ b/jmetal/operator/__init__.py @@ -1,13 +1,51 @@ -from .crossover import NullCrossover, SBXCrossover, SPXCrossover, DifferentialEvolutionCrossover -from .mutation import NullMutation, BitFlipMutation, PolynomialMutation, IntegerPolynomialMutation, UniformMutation, \ - SimpleRandomMutation -from .selection import BestSolutionSelection, BinaryTournamentSelection, BinaryTournament2Selection, \ - RandomSolutionSelection, NaryRandomSolutionSelection, RankingAndCrowdingDistanceSelection +from .crossover import ( + CXCrossover, + DifferentialEvolutionCrossover, + NullCrossover, + PMXCrossover, + SBXCrossover, + SPXCrossover, +) +from .mutation import ( + BitFlipMutation, + IntegerPolynomialMutation, + NullMutation, + PermutationSwapMutation, + PolynomialMutation, + ScrambleMutation, + SimpleRandomMutation, + UniformMutation, +) +from .selection import ( + BestSolutionSelection, + BinaryTournament2Selection, + BinaryTournamentSelection, + NaryRandomSolutionSelection, + RandomSolutionSelection, + RankingAndCrowdingDistanceSelection, + RouletteWheelSelection, +) __all__ = [ - 'NullCrossover', 'SBXCrossover', 'SPXCrossover', 'DifferentialEvolutionCrossover', - 'NullMutation', 'BitFlipMutation', 'PolynomialMutation', 'IntegerPolynomialMutation', 'UniformMutation', - 'SimpleRandomMutation', - 'BestSolutionSelection', 'BinaryTournamentSelection', 'BinaryTournament2Selection', 'RandomSolutionSelection', - 'NaryRandomSolutionSelection', 'RankingAndCrowdingDistanceSelection' + "NullCrossover", + "SBXCrossover", + "SPXCrossover", + "DifferentialEvolutionCrossover", + "PMXCrossover", + "CXCrossover", + "NullMutation", + "BitFlipMutation", + "PolynomialMutation", + "IntegerPolynomialMutation", + "UniformMutation", + "SimpleRandomMutation", + "ScrambleMutation", + "PermutationSwapMutation", + "RouletteWheelSelection", + "BestSolutionSelection", + "BinaryTournamentSelection", + "BinaryTournament2Selection", + "RandomSolutionSelection", + "NaryRandomSolutionSelection", + "RankingAndCrowdingDistanceSelection", ] diff --git a/jmetal/operator/crossover.py b/jmetal/operator/crossover.py index 2e8bc30b..880fe867 100644 --- a/jmetal/operator/crossover.py +++ b/jmetal/operator/crossover.py @@ -3,8 +3,14 @@ from typing import List from jmetal.core.operator import Crossover -from jmetal.core.solution import Solution, FloatSolution, BinarySolution, PermutationSolution, IntegerSolution, \ - CompositeSolution +from jmetal.core.solution import ( + BinarySolution, + CompositeSolution, + FloatSolution, + IntegerSolution, + PermutationSolution, + Solution, +) from jmetal.util.ckecking import Check """ @@ -22,7 +28,7 @@ def __init__(self): def execute(self, parents: List[Solution]) -> List[Solution]: if len(parents) != 2: - raise Exception('The number of parents is not two: {}'.format(len(parents))) + raise Exception("The number of parents is not two: {}".format(len(parents))) return parents @@ -33,7 +39,7 @@ def get_number_of_children(self) -> int: return 2 def get_name(self): - return 'Null crossover' + return "Null crossover" class PMXCrossover(Crossover[PermutationSolution, PermutationSolution]): @@ -42,9 +48,9 @@ def __init__(self, probability: float): def execute(self, parents: List[PermutationSolution]) -> List[PermutationSolution]: if len(parents) != 2: - raise Exception('The number of parents is not two: {}'.format(len(parents))) + raise Exception("The number of parents is not two: {}".format(len(parents))) - offspring = [copy.deepcopy(parents[0]), copy.deepcopy(parents[1])] + offspring = copy.deepcopy(parents) permutation_length = offspring[0].number_of_variables rand = random.random() @@ -91,7 +97,7 @@ def get_number_of_children(self) -> int: return 2 def get_name(self): - return 'Partially Matched crossover' + return "Partially Matched crossover" class CXCrossover(Crossover[PermutationSolution, PermutationSolution]): @@ -100,28 +106,27 @@ def __init__(self, probability: float): def execute(self, parents: List[PermutationSolution]) -> List[PermutationSolution]: if len(parents) != 2: - raise Exception('The number of parents is not two: {}'.format(len(parents))) + raise Exception("The number of parents is not two: {}".format(len(parents))) - offspring = [copy.deepcopy(parents[1]), copy.deepcopy(parents[0])] + offspring = copy.deepcopy(parents[::-1]) rand = random.random() if rand <= self.probability: - for i in range(parents[0].number_of_variables): - idx = random.randint(0, len(parents[0].variables[i]) - 1) - curr_idx = idx - cycle = [] + idx = random.randint(0, len(parents[0].variables) - 1) + curr_idx = idx + cycle = [] - while True: - cycle.append(curr_idx) - curr_idx = parents[0].variables[i].index(parents[1].variables[i][curr_idx]) + while True: + cycle.append(curr_idx) + curr_idx = parents[0].variables.index(parents[1].variables[curr_idx]) - if curr_idx == idx: - break + if curr_idx == idx: + break - for j in range(len(parents[0].variables[i])): - if j in cycle: - offspring[0].variables[i][j] = parents[0].variables[i][j] - offspring[1].variables[i][j] = parents[0].variables[i][j] + for j in range(len(parents[0].variables)): + if j in cycle: + offspring[0].variables[j] = parents[0].variables[j] + offspring[1].variables[j] = parents[1].variables[j] return offspring @@ -132,7 +137,7 @@ def get_number_of_children(self) -> int: return 2 def get_name(self): - return 'Cycle crossover' + return "Cycle crossover" class SBXCrossover(Crossover[FloatSolution, FloatSolution]): @@ -147,9 +152,9 @@ def __init__(self, probability: float, distribution_index: float = 20.0): def execute(self, parents: List[FloatSolution]) -> List[FloatSolution]: Check.that(issubclass(type(parents[0]), FloatSolution), "Solution type invalid: " + str(type(parents[0]))) Check.that(issubclass(type(parents[1]), FloatSolution), "Solution type invalid") - Check.that(len(parents) == 2, 'The number of parents is not two: {}'.format(len(parents))) + Check.that(len(parents) == 2, "The number of parents is not two: {}".format(len(parents))) - offspring = [copy.deepcopy(parents[0]), copy.deepcopy(parents[1])] + offspring = copy.deepcopy(parents) rand = random.random() if rand <= self.probability: @@ -215,7 +220,7 @@ def get_number_of_children(self) -> int: return 2 def get_name(self) -> str: - return 'SBX crossover' + return "SBX crossover" class IntegerSBXCrossover(Crossover[IntegerSolution, IntegerSolution]): @@ -228,9 +233,9 @@ def __init__(self, probability: float, distribution_index: float = 20.0): def execute(self, parents: List[IntegerSolution]) -> List[IntegerSolution]: Check.that(issubclass(type(parents[0]), IntegerSolution), "Solution type invalid") Check.that(issubclass(type(parents[1]), IntegerSolution), "Solution type invalid") - Check.that(len(parents) == 2, 'The number of parents is not two: {}'.format(len(parents))) + Check.that(len(parents) == 2, "The number of parents is not two: {}".format(len(parents))) - offspring = [copy.deepcopy(parents[0]), copy.deepcopy(parents[1])] + offspring = copy.deepcopy(parents) rand = random.random() if rand <= self.probability: @@ -296,20 +301,19 @@ def get_number_of_children(self) -> int: return 2 def get_name(self) -> str: - return 'Integer SBX crossover' + return "Integer SBX crossover" class SPXCrossover(Crossover[BinarySolution, BinarySolution]): - def __init__(self, probability: float): super(SPXCrossover, self).__init__(probability=probability) def execute(self, parents: List[BinarySolution]) -> List[BinarySolution]: Check.that(type(parents[0]) is BinarySolution, "Solution type invalid") Check.that(type(parents[1]) is BinarySolution, "Solution type invalid") - Check.that(len(parents) == 2, 'The number of parents is not two: {}'.format(len(parents))) + Check.that(len(parents) == 2, "The number of parents is not two: {}".format(len(parents))) - offspring = [copy.deepcopy(parents[0]), copy.deepcopy(parents[1])] + offspring = copy.deepcopy(parents) rand = random.random() if rand <= self.probability: @@ -356,11 +360,11 @@ def get_number_of_children(self) -> int: return 2 def get_name(self) -> str: - return 'Single point crossover' + return "Single point crossover" class DifferentialEvolutionCrossover(Crossover[FloatSolution, FloatSolution]): - """ This operator receives two parameters: the current individual and an array of three parent individuals. The + """This operator receives two parameters: the current individual and an array of three parent individuals. The best and rand variants depends on the third parent, according whether it represents the current of the "best" individual or a random_search one. The implementation of both variants are the same, due to that the parent selection is external to the crossover operator. @@ -375,10 +379,9 @@ def __init__(self, CR: float, F: float, K: float = 0.5): self.current_individual: FloatSolution = None def execute(self, parents: List[FloatSolution]) -> List[FloatSolution]: - """ Execute the differential evolution crossover ('best/1/bin' variant in jMetal). - """ + """Execute the differential evolution crossover ('best/1/bin' variant in jMetal).""" if len(parents) != self.get_number_of_parents(): - raise Exception('The number of parents is not {}: {}'.format(self.get_number_of_parents(), len(parents))) + raise Exception("The number of parents is not {}: {}".format(self.get_number_of_parents(), len(parents))) child = copy.deepcopy(self.current_individual) @@ -407,13 +410,13 @@ def get_number_of_children(self) -> int: return 1 def get_name(self) -> str: - return 'Differential Evolution crossover' + return "Differential Evolution crossover" class CompositeCrossover(Crossover[CompositeSolution, CompositeSolution]): __EPS = 1.0e-14 - def __init__(self, crossover_operator_list:[Crossover]): + def __init__(self, crossover_operator_list: [Crossover]): super(CompositeCrossover, self).__init__(probability=1.0) Check.is_not_none(crossover_operator_list) @@ -448,4 +451,4 @@ def get_number_of_children(self) -> int: return 2 def get_name(self) -> str: - return 'Composite crossover' + return "Composite crossover" diff --git a/jmetal/operator/mutation.py b/jmetal/operator/mutation.py index 013c0d56..955af5b3 100644 --- a/jmetal/operator/mutation.py +++ b/jmetal/operator/mutation.py @@ -1,8 +1,14 @@ import random from jmetal.core.operator import Mutation -from jmetal.core.solution import BinarySolution, Solution, FloatSolution, IntegerSolution, PermutationSolution, \ - CompositeSolution +from jmetal.core.solution import ( + BinarySolution, + CompositeSolution, + FloatSolution, + IntegerSolution, + PermutationSolution, + Solution, +) from jmetal.util.ckecking import Check """ @@ -15,7 +21,6 @@ class NullMutation(Mutation[Solution]): - def __init__(self): super(NullMutation, self).__init__(probability=0) @@ -23,11 +28,10 @@ def execute(self, solution: Solution) -> Solution: return solution def get_name(self): - return 'Null mutation' + return "Null mutation" class BitFlipMutation(Mutation[BinarySolution]): - def __init__(self, probability: float): super(BitFlipMutation, self).__init__(probability=probability) @@ -43,11 +47,10 @@ def execute(self, solution: BinarySolution) -> BinarySolution: return solution def get_name(self): - return 'BitFlip mutation' + return "BitFlip mutation" class PolynomialMutation(Mutation[FloatSolution]): - def __init__(self, probability: float, distribution_index: float = 0.20): super(PolynomialMutation, self).__init__(probability=probability) self.distribution_index = distribution_index @@ -88,11 +91,10 @@ def execute(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'Polynomial mutation' + return "Polynomial mutation" class IntegerPolynomialMutation(Mutation[IntegerSolution]): - def __init__(self, probability: float, distribution_index: float = 0.20): super(IntegerPolynomialMutation, self).__init__(probability=probability) self.distribution_index = distribution_index @@ -115,11 +117,11 @@ def execute(self, solution: IntegerSolution) -> IntegerSolution: if rnd <= 0.5: xy = 1.0 - delta1 val = 2.0 * rnd + (1.0 - 2.0 * rnd) * (xy ** (self.distribution_index + 1.0)) - deltaq = val ** mut_pow - 1.0 + deltaq = val**mut_pow - 1.0 else: xy = 1.0 - delta2 val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * (xy ** (self.distribution_index + 1.0)) - deltaq = 1.0 - val ** mut_pow + deltaq = 1.0 - val**mut_pow y += deltaq * (yu - yl) if y < solution.lower_bound[i]: @@ -131,11 +133,10 @@ def execute(self, solution: IntegerSolution) -> IntegerSolution: return solution def get_name(self): - return 'Polynomial mutation (Integer)' + return "Polynomial mutation (Integer)" class SimpleRandomMutation(Mutation[FloatSolution]): - def __init__(self, probability: float): super(SimpleRandomMutation, self).__init__(probability=probability) @@ -145,16 +146,16 @@ def execute(self, solution: FloatSolution) -> FloatSolution: for i in range(solution.number_of_variables): rand = random.random() if rand <= self.probability: - solution.variables[i] = solution.lower_bound[i] + \ - (solution.upper_bound[i] - solution.lower_bound[i]) * random.random() + solution.variables[i] = ( + solution.lower_bound[i] + (solution.upper_bound[i] - solution.lower_bound[i]) * random.random() + ) return solution def get_name(self): - return 'Simple random_search mutation' + return "Simple random_search mutation" class UniformMutation(Mutation[FloatSolution]): - def __init__(self, probability: float, perturbation: float = 0.5): super(UniformMutation, self).__init__(probability=probability) self.perturbation = perturbation @@ -179,11 +180,10 @@ def execute(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'Uniform mutation' + return "Uniform mutation" class NonUniformMutation(Mutation[FloatSolution]): - def __init__(self, probability: float, perturbation: float = 0.5, max_iterations: int = 0.5): super(NonUniformMutation, self).__init__(probability=probability) self.perturbation = perturbation @@ -217,15 +217,18 @@ def set_current_iteration(self, current_iteration: int): self.current_iteration = current_iteration def __delta(self, y: float, b_mutation_parameter: float): - return (y * (1.0 - pow(random.random(), - pow((1.0 - 1.0 * self.current_iteration / self.max_iterations), b_mutation_parameter)))) + return y * ( + 1.0 + - pow( + random.random(), pow((1.0 - 1.0 * self.current_iteration / self.max_iterations), b_mutation_parameter) + ) + ) def get_name(self): - return 'Uniform mutation' + return "Uniform mutation" class PermutationSwapMutation(Mutation[PermutationSolution]): - def execute(self, solution: PermutationSolution) -> PermutationSolution: Check.that(type(solution) is PermutationSolution, "Solution type invalid") @@ -233,18 +236,20 @@ def execute(self, solution: PermutationSolution) -> PermutationSolution: if rand <= self.probability: pos_one, pos_two = random.sample(range(solution.number_of_variables - 1), 2) - solution.variables[pos_one], solution.variables[pos_two] = \ - solution.variables[pos_two], solution.variables[pos_one] + solution.variables[pos_one], solution.variables[pos_two] = ( + solution.variables[pos_two], + solution.variables[pos_one], + ) return solution def get_name(self): - return 'Permutation Swap mutation' + return "Permutation Swap mutation" class CompositeMutation(Mutation[Solution]): - def __init__(self, mutation_operator_list:[Mutation]): - super(CompositeMutation,self).__init__(probability=1.0) + def __init__(self, mutation_operator_list: [Mutation]): + super(CompositeMutation, self).__init__(probability=1.0) Check.is_not_none(mutation_operator_list) Check.collection_is_not_empty(mutation_operator_list) @@ -268,27 +273,25 @@ def get_name(self) -> str: class ScrambleMutation(Mutation[PermutationSolution]): - def execute(self, solution: PermutationSolution) -> PermutationSolution: - for i in range(solution.number_of_variables): - rand = random.random() + rand = random.random() - if rand <= self.probability: - point1 = random.randint(0, len(solution.variables[i])) - point2 = random.randint(0, len(solution.variables[i]) - 1) + if rand <= self.probability: + point1 = random.randint(0, len(solution.variables)) + point2 = random.randint(0, len(solution.variables) - 1) - if point2 >= point1: - point2 += 1 - else: - point1, point2 = point2, point1 + if point2 >= point1: + point2 += 1 + else: + point1, point2 = point2, point1 - if point2 - point1 >= 20: - point2 = point1 + 20 + if point2 - point1 >= 20: + point2 = point1 + 20 - values = solution.variables[i][point1:point2] - solution.variables[i][point1:point2] = random.sample(values, len(values)) + values = solution.variables[point1:point2] + solution.variables[point1:point2] = random.sample(values, len(values)) return solution def get_name(self): - return 'Scramble' + return "Scramble" diff --git a/jmetal/operator/selection.py b/jmetal/operator/selection.py index 40755baa..ee2059c7 100644 --- a/jmetal/operator/selection.py +++ b/jmetal/operator/selection.py @@ -4,11 +4,12 @@ import numpy as np from jmetal.core.operator import Selection +from jmetal.core.solution import Solution from jmetal.util.comparator import Comparator, DominanceComparator from jmetal.util.density_estimator import CrowdingDistance from jmetal.util.ranking import FastNonDominatedRanking -S = TypeVar('S') +S = TypeVar("S", bound=Solution) """ .. module:: selection @@ -20,17 +21,16 @@ class RouletteWheelSelection(Selection[List[S], S]): - """Performs roulette wheel selection. - """ + """Performs roulette wheel selection.""" def __init__(self): super(RouletteWheelSelection).__init__() def execute(self, front: List[S]) -> S: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") maximum = sum([solution.objectives[0] for solution in front]) rand = random.uniform(0.0, maximum) @@ -45,20 +45,19 @@ def execute(self, front: List[S]) -> S: return None def get_name(self) -> str: - return 'Roulette wheel selection' + return "Roulette wheel selection" class BinaryTournamentSelection(Selection[List[S], S]): - def __init__(self, comparator: Comparator = DominanceComparator()): super(BinaryTournamentSelection, self).__init__() self.comparator = comparator def execute(self, front: List[S]) -> S: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") if len(front) == 1: result = front[0] @@ -80,19 +79,18 @@ def execute(self, front: List[S]) -> S: return result def get_name(self) -> str: - return 'Binary tournament selection' + return "Binary tournament selection" class BestSolutionSelection(Selection[List[S], S]): - def __init__(self): super(BestSolutionSelection, self).__init__() def execute(self, front: List[S]) -> S: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") result = front[0] @@ -103,46 +101,44 @@ def execute(self, front: List[S]) -> S: return result def get_name(self) -> str: - return 'Best solution selection' + return "Best solution selection" class NaryRandomSolutionSelection(Selection[List[S], S]): - def __init__(self, number_of_solutions_to_be_returned: int = 1): super(NaryRandomSolutionSelection, self).__init__() if number_of_solutions_to_be_returned < 0: - raise Exception('The number of solutions to be returned must be positive integer') + raise Exception("The number of solutions to be returned must be positive integer") self.number_of_solutions_to_be_returned = number_of_solutions_to_be_returned def execute(self, front: List[S]) -> S: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") if len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") if len(front) < self.number_of_solutions_to_be_returned: - raise Exception('The front contains less elements than required') + raise Exception("The front contains less elements than required") # random_search sampling without replacement return random.sample(front, self.number_of_solutions_to_be_returned) def get_name(self) -> str: - return 'Nary random_search solution selection' + return "Nary random_search solution selection" class DifferentialEvolutionSelection(Selection[List[S], List[S]]): - def __init__(self): super(DifferentialEvolutionSelection, self).__init__() self.index_to_exclude = None def execute(self, front: List[S]) -> List[S]: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") elif len(front) < 4: - raise Exception('The front has less than four solutions: ' + str(len(front))) + raise Exception("The front has less than four solutions: " + str(len(front))) selected_indexes = random.sample(range(len(front)), 3) while self.index_to_exclude in selected_indexes: @@ -158,24 +154,22 @@ def get_name(self) -> str: class RandomSolutionSelection(Selection[List[S], S]): - def __init__(self): super(RandomSolutionSelection, self).__init__() def execute(self, front: List[S]) -> S: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") return random.choice(front) def get_name(self) -> str: - return 'Random solution selection' + return "Random solution selection" class RankingAndCrowdingDistanceSelection(Selection[List[S], List[S]]): - def __init__(self, max_population_size: int, dominance_comparator: Comparator = DominanceComparator()): super(RankingAndCrowdingDistanceSelection, self).__init__() self.max_population_size = max_population_size @@ -183,9 +177,9 @@ def __init__(self, max_population_size: int, dominance_comparator: Comparator = def execute(self, front: List[S]) -> List[S]: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") ranking = FastNonDominatedRanking(self.dominance_comparator) crowding_distance = CrowdingDistance() @@ -201,21 +195,20 @@ def execute(self, front: List[S]) -> List[S]: else: subfront = ranking.get_subfront(ranking_index) crowding_distance.compute_density_estimator(subfront) - sorted_subfront = sorted(subfront, key=lambda x: x.attributes['crowding_distance'], reverse=True) + sorted_subfront = sorted(subfront, key=lambda x: x.attributes["crowding_distance"], reverse=True) for i in range((self.max_population_size - len(new_solution_list))): new_solution_list.append(sorted_subfront[i]) return new_solution_list def get_name(self) -> str: - return 'Ranking and crowding distance selection' + return "Ranking and crowding distance selection" class RankingAndFitnessSelection(Selection[List[S], List[S]]): - - def __init__(self, - max_population_size: int, reference_point: S, - dominance_comparator: Comparator = DominanceComparator()): + def __init__( + self, max_population_size: int, reference_point: S, dominance_comparator: Comparator = DominanceComparator() + ): super(RankingAndFitnessSelection, self).__init__() self.max_population_size = max_population_size self.dominance_comparator = dominance_comparator @@ -242,8 +235,10 @@ def hypesub(self, l, A, actDim, bounds, pvec, alpha, k): h[p] = h[p] + extrusion * alpha[i - 1] else: if extrusion > 0: - h = [h[j] + extrusion * self.hypesub(l, S[0:i], actDim - 1, bounds, pvec[0:i], alpha, k)[j] for j in - range(l)] + h = [ + h[j] + extrusion * self.hypesub(l, S[0:i], actDim - 1, bounds, pvec[0:i], alpha, k)[j] + for j in range(l) + ] return h @@ -265,15 +260,15 @@ def compute_hypervol_fitness_values(self, population: List[S], reference_point: f = self.hypesub(population_size, points, actDim, bounds, pvec, alpha, k) for i in range(len(population)): - population[i].attributes['fitness'] = f[i] + population[i].attributes["fitness"] = f[i] return population def execute(self, front: List[S]) -> List[S]: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") ranking = FastNonDominatedRanking(self.dominance_comparator) ranking.compute_ranking(front) @@ -291,29 +286,28 @@ def execute(self, front: List[S]) -> List[S]: parameter_K = len(subfront) - (self.max_population_size - len(new_solution_list)) while parameter_K > 0: subfront = self.compute_hypervol_fitness_values(subfront, self.reference_point, parameter_K) - subfront = sorted(subfront, key=lambda x: x.attributes['fitness'], reverse=True) + subfront = sorted(subfront, key=lambda x: x.attributes["fitness"], reverse=True) subfront = subfront[:-1] parameter_K = parameter_K - 1 new_solution_list = new_solution_list + subfront return new_solution_list def get_name(self) -> str: - return 'Ranking and fitness selection' + return "Ranking and fitness selection" class BinaryTournament2Selection(Selection[List[S], S]): - def __init__(self, comparator_list: List[Comparator]): super(BinaryTournament2Selection, self).__init__() self.comparator_list = comparator_list def execute(self, front: List[S]) -> S: if front is None: - raise Exception('The front is null') + raise Exception("The front is null") elif len(front) == 0: - raise Exception('The front is empty') + raise Exception("The front is empty") elif not self.comparator_list: - raise Exception('The comparators\' list is empty') + raise Exception("The comparators' list is empty") winner = None @@ -350,4 +344,4 @@ def __winner(self, front: List[S], comparator: Comparator): return result def get_name(self) -> str: - return 'Binary tournament selection (experimental)' + return "Binary tournament selection (experimental)" diff --git a/jmetal/operator/test/test_crossover.py b/jmetal/operator/test/test_crossover.py index 41c72101..c69dd59d 100644 --- a/jmetal/operator/test/test_crossover.py +++ b/jmetal/operator/test/test_crossover.py @@ -3,14 +3,30 @@ from unittest import mock from jmetal.core.operator import Crossover -from jmetal.core.solution import BinarySolution, PermutationSolution, FloatSolution, CompositeSolution, IntegerSolution -from jmetal.operator.crossover import NullCrossover, SPXCrossover, CXCrossover, PMXCrossover, SBXCrossover, \ - CompositeCrossover, IntegerSBXCrossover -from jmetal.util.ckecking import NoneParameterException, EmptyCollectionException, InvalidConditionException +from jmetal.core.solution import ( + BinarySolution, + CompositeSolution, + FloatSolution, + IntegerSolution, + PermutationSolution, +) +from jmetal.operator.crossover import ( + CompositeCrossover, + CXCrossover, + IntegerSBXCrossover, + NullCrossover, + PMXCrossover, + SBXCrossover, + SPXCrossover, +) +from jmetal.util.ckecking import ( + EmptyCollectionException, + InvalidConditionException, + NoneParameterException, +) class NullCrossoverTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): solution = NullCrossover() self.assertIsNotNone(solution) @@ -32,7 +48,6 @@ def test_should_the_solution_remain_unchanged(self): class SinglePointTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): SPXCrossover(-1) @@ -68,7 +83,7 @@ def test_should_the_solution_remain_unchanged_if_the_probability_is_zero(self): self.assertEqual([True, False, False, True, True, False], offspring[0].variables[0]) self.assertEqual([False, True, False, False, True, False], offspring[1].variables[0]) - @mock.patch('random.randrange') + @mock.patch("random.randrange") def test_should_the_operator_work_if_the_first_bit_is_selected(self, random_call): operator = SPXCrossover(1.0) solution1 = BinarySolution(number_of_variables=1, number_of_objectives=1) @@ -81,7 +96,7 @@ def test_should_the_operator_work_if_the_first_bit_is_selected(self, random_call self.assertEqual([False, True, False, False, True, False], offspring[0].variables[0]) self.assertEqual([True, False, False, True, True, False], offspring[1].variables[0]) - @mock.patch('random.randrange') + @mock.patch("random.randrange") def test_should_the_operator_work_if_the_last_bit_is_selected(self, random_call): operator = SPXCrossover(1.0) solution1 = BinarySolution(number_of_variables=1, number_of_objectives=1) @@ -94,7 +109,7 @@ def test_should_the_operator_work_if_the_last_bit_is_selected(self, random_call) self.assertEqual([True, False, False, True, True, True], offspring[0].variables[0]) self.assertEqual([False, True, False, False, True, False], offspring[1].variables[0]) - @mock.patch('random.randrange') + @mock.patch("random.randrange") def test_should_the_operator_work_if_the_third_bit_is_selected(self, random_call): operator = SPXCrossover(1.0) solution1 = BinarySolution(number_of_variables=1, number_of_objectives=1) @@ -107,7 +122,7 @@ def test_should_the_operator_work_if_the_third_bit_is_selected(self, random_call self.assertEqual([True, False, False, False, True, True], offspring[0].variables[0]) self.assertEqual([False, True, False, True, True, False], offspring[1].variables[0]) - @mock.patch('random.randrange') + @mock.patch("random.randrange") def test_should_the_operator_work_with_a_solution_with_three_binary_variables(self, random_call): operator = SPXCrossover(1.0) solution1 = BinarySolution(number_of_variables=3, number_of_objectives=1) @@ -130,7 +145,6 @@ def test_should_the_operator_work_with_a_solution_with_three_binary_variables(se class PMXTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): PMXCrossover(-1) @@ -165,7 +179,7 @@ def test_should_the_solution_remain_unchanged_if_the_probability_is_zero(self): self.assertEqual([2, 3], offspring[1].variables[0]) self.assertEqual([5, 3], offspring[1].variables[1]) - @mock.patch('random.randint') + @mock.patch("random.randint") def test_should_the_operator_work_with_permutation_at_the_middle(self, random_call): operator = PMXCrossover(1.0) @@ -181,7 +195,7 @@ def test_should_the_operator_work_with_permutation_at_the_middle(self, random_ca self.assertEqual([0, 1, 12, 13, 4, 5, 6, 7, 8, 9], offspring[0].variables) self.assertEqual([10, 11, 2, 3, 14, 15, 16, 17, 18, 19], offspring[1].variables) - @mock.patch('random.randint') + @mock.patch("random.randint") def test_should_the_operator_work_with_permutation_at_the_beginning(self, random_call): operator = PMXCrossover(1.0) @@ -199,7 +213,6 @@ def test_should_the_operator_work_with_permutation_at_the_beginning(self, random class CXTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): CXCrossover(-1) @@ -224,25 +237,21 @@ def test_should_constructor_raise_an_exception_if_the_probability_is_lower_than_ with self.assertRaises(Exception): CXCrossover(-12) - @mock.patch('random.randint') - def test_should_the_operator_work_with_two_solutions_with_two_variables(self, random_call): + @mock.patch("random.randint") + def test_should_the_operator_work_with_two_solutions_with_same_number_of_variables(self, random_call): operator = CXCrossover(1.0) - solution1 = PermutationSolution(number_of_variables=2, number_of_objectives=1) - solution1.variables[0] = [1, 2, 3, 4, 7] - solution1.variables[1] = [2, 6, 4, 5, 3] + solution1 = PermutationSolution(number_of_variables=5, number_of_objectives=1) + solution1.variables = [1, 2, 3, 4, 7] - solution2 = PermutationSolution(number_of_variables=2, number_of_objectives=1) - solution2.variables[0] = [2, 3, 4, 1, 9] - solution2.variables[1] = [5, 3, 2, 4, 6] + solution2 = PermutationSolution(number_of_variables=5, number_of_objectives=1) + solution2.variables = [2, 3, 4, 1, 9] random_call.return_value = 0 offspring = operator.execute([solution1, solution2]) - self.assertEqual([1, 2, 3, 4, 9], offspring[0].variables[0]) - self.assertEqual([2, 3, 4, 5, 6], offspring[0].variables[1]) + self.assertEqual([1, 2, 3, 4, 9], offspring[0].variables) - self.assertEqual([1, 2, 3, 4, 7], offspring[1].variables[0]) - self.assertEqual([2, 6, 4, 5, 3], offspring[1].variables[1]) + self.assertEqual([2, 3, 4, 1, 7], offspring[1].variables) class SBXCrossoverTestCases(unittest.TestCase): @@ -297,10 +306,16 @@ def test_should_execute_return_the_parents_if_the_crossover_probability_is_zero( def test_should_execute_work_with_a_solution_subclass_of_float_solution(self): class NewFloatSolution(FloatSolution): - def __init__(self, lower_bound: List[float], upper_bound: List[float], number_of_objectives: int, - number_of_constraints: int = 0): - super(NewFloatSolution, self).__init__(lower_bound, upper_bound, number_of_objectives, - number_of_constraints) + def __init__( + self, + lower_bound: List[float], + upper_bound: List[float], + number_of_objectives: int, + number_of_constraints: int = 0, + ): + super(NewFloatSolution, self).__init__( + lower_bound, upper_bound, number_of_objectives, number_of_constraints + ) solution1 = NewFloatSolution([1, 2], [2, 4], 2, 2) solution2 = NewFloatSolution([1, 2], [2, 4], 2, 2) @@ -315,7 +330,6 @@ def __init__(self, lower_bound: List[float], upper_bound: List[float], number_of self.assertEqual(solution1.variables, offspring[0].variables) self.assertEqual(solution2.variables, offspring[1].variables) - def test_should_execute_produce_valid_solutions_when_crossing_two_single_variable_solutions(self): pass @@ -401,5 +415,5 @@ def test_should_execute_raise_and_exception_if_the_types_of_the_solutions_do_not operator.execute([composite_solution1, composite_solution2]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/operator/test/test_mutation.py b/jmetal/operator/test/test_mutation.py index 87752ee8..0d5d2b29 100644 --- a/jmetal/operator/test/test_mutation.py +++ b/jmetal/operator/test/test_mutation.py @@ -2,14 +2,28 @@ from typing import List from jmetal.core.operator import Mutation -from jmetal.core.solution import BinarySolution, FloatSolution, IntegerSolution, CompositeSolution -from jmetal.operator.mutation import BitFlipMutation, UniformMutation, SimpleRandomMutation, PolynomialMutation, \ - IntegerPolynomialMutation, CompositeMutation -from jmetal.util.ckecking import NoneParameterException, EmptyCollectionException, InvalidConditionException +from jmetal.core.solution import ( + BinarySolution, + CompositeSolution, + FloatSolution, + IntegerSolution, +) +from jmetal.operator.mutation import ( + BitFlipMutation, + CompositeMutation, + IntegerPolynomialMutation, + PolynomialMutation, + SimpleRandomMutation, + UniformMutation, +) +from jmetal.util.ckecking import ( + EmptyCollectionException, + InvalidConditionException, + NoneParameterException, +) class PolynomialMutationTestMethods(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): PolynomialMutation(-1) @@ -54,10 +68,16 @@ def test_should_the_solution_change__if_the_probability_is_one(self): def test_should_execute_work_with_a_solution_subclass_of_float_solution(self): class NewFloatSolution(FloatSolution): - def __init__(self, lower_bound: List[float], upper_bound: List[float], number_of_objectives: int, - number_of_constraints: int = 0): - super(NewFloatSolution, self).__init__(lower_bound, upper_bound, number_of_objectives, - number_of_constraints) + def __init__( + self, + lower_bound: List[float], + upper_bound: List[float], + number_of_objectives: int, + number_of_constraints: int = 0, + ): + super(NewFloatSolution, self).__init__( + lower_bound, upper_bound, number_of_objectives, number_of_constraints + ) operator = PolynomialMutation(1.0) solution = NewFloatSolution([-5, -5, -5], [5, 5, 5], 2) @@ -69,7 +89,6 @@ def __init__(self, lower_bound: List[float], upper_bound: List[float], number_of class BitFlipTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): BitFlipMutation(-1) @@ -114,7 +133,6 @@ def test_should_the_solution_change_all_the_bits_if_the_probability_is_one(self) class UniformMutationTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): UniformMutation(-1) @@ -170,7 +188,6 @@ def test_should_the_solution_change_between_max_and_min_value(self): class RandomMutationTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): SimpleRandomMutation(-1) @@ -223,7 +240,6 @@ def test_should_the_solution_change_between_max_and_min_value(self): class IntegerPolynomialMutationTestCases(unittest.TestCase): - def test_should_constructor_raises_an_exception_is_probability_is_negative(self) -> None: with self.assertRaises(Exception): IntegerPolynomialMutation(-1) @@ -278,7 +294,7 @@ def test_should_constructor_raise_an_exception_if_the_parameter_list_is_Empty(se CompositeMutation([]) def test_should_constructor_create_a_valid_operator_when_adding_a_single_mutation_operator(self): - mutation: Mutation = PolynomialMutation(0.9, 20.0) + mutation: Mutation = PolynomialMutation(0.9, 20.0) operator = CompositeMutation([mutation]) self.assertIsNotNone(operator) @@ -308,5 +324,5 @@ def test_should_execute_raise_and_exception_if_the_types_of_the_solutions_do_not operator.execute(composite_solution) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/operator/test/test_selection.py b/jmetal/operator/test/test_selection.py index a5099973..b7f27f59 100644 --- a/jmetal/operator/test/test_selection.py +++ b/jmetal/operator/test/test_selection.py @@ -1,16 +1,21 @@ import unittest -from hamcrest import assert_that, any_of +from hamcrest import any_of, assert_that from jmetal.core.solution import Solution -from jmetal.operator.selection import BinaryTournamentSelection, BestSolutionSelection, RandomSolutionSelection, \ - NaryRandomSolutionSelection, RankingAndCrowdingDistanceSelection, BinaryTournament2Selection, \ - DifferentialEvolutionSelection -from jmetal.util.comparator import SolutionAttributeComparator, EqualSolutionsComparator +from jmetal.operator.selection import ( + BestSolutionSelection, + BinaryTournament2Selection, + BinaryTournamentSelection, + DifferentialEvolutionSelection, + NaryRandomSolutionSelection, + RandomSolutionSelection, + RankingAndCrowdingDistanceSelection, +) +from jmetal.util.comparator import EqualSolutionsComparator, SolutionAttributeComparator class BinaryTournamentTestCases(unittest.TestCase): - def setUp(self): self.selection = BinaryTournamentSelection[Solution]() @@ -55,7 +60,6 @@ def test_should_execute_work_if_the_solution_list_contains_two_solutions_and_one class BestSolutionSelectionTestCases(unittest.TestCase): - def setUp(self): self.selection = BestSolutionSelection[Solution]() @@ -117,7 +121,6 @@ def test_should_execute_work_if_the_solution_list_contains_five_solutions_and_on class RandomSolutionSelectionTestCases(unittest.TestCase): - def setUp(self): self.selection = RandomSolutionSelection[Solution]() @@ -195,13 +198,13 @@ def test_should_execute_raise_an_exception_if_the_list_of_solutions_is_empty(sel def test_should_execute_raise_an_exception_if_the_list_of_solutions_is_smaller_than_required(self): selection = DifferentialEvolutionSelection[Solution]() - solution_list = [Solution(1, 1), Solution(1, 1), Solution(1,1)] + solution_list = [Solution(1, 1), Solution(1, 1), Solution(1, 1)] with self.assertRaises(Exception): selection.execute(solution_list) def test_should_execute_return_three_solutions_if_the_list_of_solutions_larger_than_three(self): selection = DifferentialEvolutionSelection[Solution]() - solution_list = [Solution(1, 1), Solution(1, 1), Solution(1,1), Solution(1,1)] + solution_list = [Solution(1, 1), Solution(1, 1), Solution(1, 1), Solution(1, 1)] self.assertEqual(3, len(selection.execute(solution_list))) @@ -231,7 +234,6 @@ def test_should_execute_exclude_the_indicated_solution_if_the_list_of_solutions_ class NaryRandomSolutionSelectionTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): selection = NaryRandomSolutionSelection[Solution]() self.assertIsNotNone(selection) @@ -297,7 +299,6 @@ def test_should_execute_work_if_the_solution_list_contains_five_solutions_and_on class DominanceRankingTestCases(unittest.TestCase): - def setUp(self): self.ranking_and_crowding_selection = RankingAndCrowdingDistanceSelection(5) @@ -335,7 +336,6 @@ def test_should_len_of_nsgaii_execute_be_5(self): class BinaryTournament2TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): selection = BinaryTournament2Selection[Solution]([]) @@ -385,5 +385,5 @@ def test_should_execute_work_properly_case1(self): self.assertTrue(1, selection1.attributes["dominance_ranking"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/problem/__init__.py b/jmetal/problem/__init__.py index 1149d8ad..d0b2bfa3 100644 --- a/jmetal/problem/__init__.py +++ b/jmetal/problem/__init__.py @@ -1,15 +1,27 @@ from .multiobjective.constrained import Srinivas, Tanaka from .multiobjective.dtlz import DTLZ1, DTLZ2 from .multiobjective.lz09 import LZ09_F2 -from .multiobjective.unconstrained import Kursawe, Fonseca, Schaffer, Viennet2 +from .multiobjective.unconstrained import Fonseca, Kursawe, Schaffer, Viennet2 from .multiobjective.zdt import ZDT1, ZDT2, ZDT3, ZDT4, ZDT6 +from .singleobjective.tsp import TSP from .singleobjective.unconstrained import OneMax, Sphere __all__ = [ - 'Srinivas', 'Tanaka', - 'Kursawe', 'Fonseca', 'Schaffer', 'Viennet2', - 'DTLZ1', 'DTLZ2', - 'ZDT1', 'ZDT2', 'ZDT3', 'ZDT4', 'ZDT6', - 'LZ09_F2', - 'OneMax', 'Sphere' + "Srinivas", + "Tanaka", + "Kursawe", + "Fonseca", + "Schaffer", + "Viennet2", + "DTLZ1", + "DTLZ2", + "ZDT1", + "ZDT2", + "ZDT3", + "ZDT4", + "ZDT6", + "LZ09_F2", + "OneMax", + "Sphere", + "TSP", ] diff --git a/jmetal/problem/multiobjective/constrained.py b/jmetal/problem/multiobjective/constrained.py index 00951082..4039148e 100644 --- a/jmetal/problem/multiobjective/constrained.py +++ b/jmetal/problem/multiobjective/constrained.py @@ -1,4 +1,4 @@ -from math import pi, cos, atan +from math import atan, cos, pi from jmetal.core.problem import FloatProblem from jmetal.core.solution import FloatSolution @@ -13,7 +13,7 @@ class Srinivas(FloatProblem): - """ Class representing problem Srinivas. """ + """Class representing problem Srinivas.""" def __init__(self): super(Srinivas, self).__init__() @@ -22,7 +22,7 @@ def __init__(self): self.number_of_constraints = 2 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [-20.0 for _ in range(self.number_of_variables)] self.upper_bound = [20.0 for _ in range(self.number_of_variables)] @@ -46,11 +46,11 @@ def __evaluate_constraints(self, solution: FloatSolution) -> None: solution.constraints[1] = (3.0 * x2 - x1) / 10.0 - 1.0 def get_name(self): - return 'Srinivas' + return "Srinivas" class Tanaka(FloatProblem): - """ Class representing problem Tanaka. """ + """Class representing problem Tanaka.""" def __init__(self): super(Tanaka, self).__init__() @@ -59,12 +59,11 @@ def __init__(self): self.number_of_constraints = 2 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [10e-5 for _ in range(self.number_of_variables)] self.upper_bound = [pi for _ in range(self.number_of_variables)] - def evaluate(self, solution: FloatSolution) -> FloatSolution: solution.objectives[0] = solution.variables[0] solution.objectives[1] = solution.variables[1] @@ -79,20 +78,19 @@ def __evaluate_constraints(self, solution: FloatSolution) -> None: x1 = solution.variables[0] x2 = solution.variables[1] - constraints[0] = (x1 * x1 + x2 * x2 - 1.0 - 0.1 * cos(16.0 * atan(x1 / x2))) + constraints[0] = x1 * x1 + x2 * x2 - 1.0 - 0.1 * cos(16.0 * atan(x1 / x2)) constraints[1] = -2.0 * ((x1 - 0.5) * (x1 - 0.5) + (x2 - 0.5) * (x2 - 0.5) - 0.5) solution.constraints = constraints - #set_overall_constraint_violation_degree(solution) - + # set_overall_constraint_violation_degree(solution) def get_name(self): - return 'Tanaka' + return "Tanaka" class Osyczka2(FloatProblem): - """ Class representing problem Osyczka2. """ + """Class representing problem Osyczka2.""" def __init__(self): super(Osyczka2, self).__init__() @@ -101,7 +99,7 @@ def __init__(self): self.number_of_constraints = 6 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [0.0, 0.0, 1.0, 0.0, 1.0, 0.0] self.upper_bound = [10.0, 10.0, 5.0, 6.0, 5.0, 10.0] @@ -111,12 +109,9 @@ def __init__(self): def evaluate(self, solution: FloatSolution) -> FloatSolution: x = solution.variables - solution.objectives[0] = - (25.0 * - (x[0] - 2.0) ** 2 + - (x[1] - 2.0) ** 2 + - (x[2] - 1.0) ** 2 + - (x[3] - 4.0) ** 2 + - (x[4] - 1.0) ** 2) + solution.objectives[0] = -( + 25.0 * (x[0] - 2.0) ** 2 + (x[1] - 2.0) ** 2 + (x[2] - 1.0) ** 2 + (x[3] - 4.0) ** 2 + (x[4] - 1.0) ** 2 + ) solution.objectives[1] = sum([x[i] ** 2 for i in range(len(x))]) @@ -138,11 +133,11 @@ def __evaluate_constraints(self, solution: FloatSolution) -> None: solution.constraints = constraints def get_name(self): - return 'Osyczka2' + return "Osyczka2" class Binh2(FloatProblem): - """ Class representing problem Binh2. """ + """Class representing problem Binh2.""" def __init__(self): super(Binh2, self).__init__() @@ -151,7 +146,7 @@ def __init__(self): self.number_of_constraints = 2 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [0.0, 0.0] self.upper_bound = [5.0, 3.0] @@ -176,4 +171,4 @@ def __evaluate_constraints(self, solution: FloatSolution) -> None: constraints[1] = (x[0] - 8) * (x[0] - 8) + (x[1] + 3) * (x[1] + 3) - 7.7 def get_name(self): - return 'Binh2' + return "Binh2" diff --git a/jmetal/problem/multiobjective/dtlz.py b/jmetal/problem/multiobjective/dtlz.py index 0f0e031c..d17b818a 100644 --- a/jmetal/problem/multiobjective/dtlz.py +++ b/jmetal/problem/multiobjective/dtlz.py @@ -1,4 +1,4 @@ -from math import pi, cos, sin +from math import cos, pi, sin from jmetal.core.problem import FloatProblem from jmetal.core.solution import FloatSolution @@ -13,21 +13,20 @@ class DTLZ1(FloatProblem): - """ Problem DTLZ1. Continuous problem having a flat Pareto front + """Problem DTLZ1. Continuous problem having a flat Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 7 and 3. """ def __init__(self, number_of_variables: int = 7, number_of_objectives=3): - """ :param number_of_variables: number of decision variables of the problem. - """ + """:param number_of_variables: number of decision variables of the problem.""" super(DTLZ1, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = number_of_objectives self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE] * number_of_objectives - self.obj_labels = ['$ f_{} $'.format(i) for i in range(number_of_objectives)] + self.obj_labels = ["$ f_{} $".format(i) for i in range(number_of_objectives)] self.lower_bound = self.number_of_variables * [0.0] self.upper_bound = self.number_of_variables * [1.0] @@ -35,8 +34,12 @@ def __init__(self, number_of_variables: int = 7, number_of_objectives=3): def evaluate(self, solution: FloatSolution) -> FloatSolution: k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([(x - 0.5) * (x - 0.5) - cos(20.0 * pi * (x - 0.5)) - for x in solution.variables[self.number_of_variables - k:]]) + g = sum( + [ + (x - 0.5) * (x - 0.5) - cos(20.0 * pi * (x - 0.5)) + for x in solution.variables[self.number_of_variables - k :] + ] + ) g = 100 * (k + g) @@ -52,24 +55,23 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'DTLZ1' + return "DTLZ1" class DTLZ2(DTLZ1): - """ Problem DTLZ2. Continuous problem having a convex Pareto front + """Problem DTLZ2. Continuous problem having a convex Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 12 and 3. """ def __init__(self, number_of_variables: int = 12, number_of_objectives=3): - """:param number_of_variables: number of decision variables of the problem - """ + """:param number_of_variables: number of decision variables of the problem""" super(DTLZ2, self).__init__(number_of_variables, number_of_objectives) def evaluate(self, solution: FloatSolution) -> FloatSolution: k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([(x - 0.5) * (x - 0.5) for x in solution.variables[self.number_of_variables - k:]]) + g = sum([(x - 0.5) * (x - 0.5) for x in solution.variables[self.number_of_variables - k :]]) solution.objectives = [1.0 + g] * self.number_of_objectives @@ -83,24 +85,25 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'DTLZ2' + return "DTLZ2" class DTLZ3(DTLZ1): - """ Problem DTLZ3. Continuous problem having a convex Pareto front + """Problem DTLZ3. Continuous problem having a convex Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 12 and 3. """ def __init__(self, number_of_variables: int = 12, number_of_objectives=3): - """:param number_of_variables: number of decision variables of the problem - """ + """:param number_of_variables: number of decision variables of the problem""" super(DTLZ3, self).__init__(number_of_variables, number_of_objectives) def evaluate(self, solution: FloatSolution) -> FloatSolution: k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([(x - 0.5) ** 2 - cos(20.0 * pi * (x - 0.5)) for x in solution.variables[self.number_of_variables - k:]]) + g = sum( + [(x - 0.5) ** 2 - cos(20.0 * pi * (x - 0.5)) for x in solution.variables[self.number_of_variables - k :]] + ) g = 100.0 * (k + g) f = [1.0 + g for _ in range(self.number_of_objectives)] @@ -118,25 +121,24 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'DTLZ3' + return "DTLZ3" class DTLZ4(DTLZ1): - """ Problem DTLZ4. Continuous problem having a convex Pareto front + """Problem DTLZ4. Continuous problem having a convex Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 12 and 3. """ def __init__(self, number_of_variables: int = 12, number_of_objectives=3): - """:param number_of_variables: number of decision variables of the problem - """ + """:param number_of_variables: number of decision variables of the problem""" super(DTLZ4, self).__init__(number_of_variables, number_of_objectives) def evaluate(self, solution: FloatSolution) -> FloatSolution: alpha = 100.0 k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([(x - 0.5) ** 2 for x in solution.variables[self.number_of_variables - k:]]) + g = sum([(x - 0.5) ** 2 for x in solution.variables[self.number_of_variables - k :]]) f = [1.0 + g for _ in range(self.number_of_objectives)] for i in range(self.number_of_objectives): @@ -152,29 +154,28 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'DTLZ4' + return "DTLZ4" class DTLZ5(DTLZ1): - """ Problem DTLZ5. Continuous problem having a convex Pareto front + """Problem DTLZ5. Continuous problem having a convex Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 12 and 3. """ def __init__(self, number_of_variables: int = 12, number_of_objectives=3): - """:param number_of_variables: number of decision variables of the problem - """ + """:param number_of_variables: number of decision variables of the problem""" super(DTLZ5, self).__init__(number_of_variables, number_of_objectives) def evaluate(self, solution: FloatSolution) -> FloatSolution: k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([(x - 0.5) ** 2 for x in solution.variables[self.number_of_variables - k:]]) - t = pi/(4.0 * (1.0 + g)) + g = sum([(x - 0.5) ** 2 for x in solution.variables[self.number_of_variables - k :]]) + t = pi / (4.0 * (1.0 + g)) - theta = [0.0]*(self.number_of_objectives - 1) - theta[0] = solution.variables[0]*pi/2.0 - theta[1:] = [t * (1.0 + 2.0 * g * solution.variables[i]) for i in range(1,self.number_of_objectives-1)] + theta = [0.0] * (self.number_of_objectives - 1) + theta[0] = solution.variables[0] * pi / 2.0 + theta[1:] = [t * (1.0 + 2.0 * g * solution.variables[i]) for i in range(1, self.number_of_objectives - 1)] f = [1.0 + g for _ in range(self.number_of_objectives)] @@ -191,29 +192,28 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'DTLZ5' + return "DTLZ5" class DTLZ6(DTLZ1): - """ Problem DTLZ6. Continuous problem having a convex Pareto front + """Problem DTLZ6. Continuous problem having a convex Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 12 and 3. """ def __init__(self, number_of_variables: int = 12, number_of_objectives=3): - """:param number_of_variables: number of decision variables of the problem - """ + """:param number_of_variables: number of decision variables of the problem""" super(DTLZ6, self).__init__(number_of_variables, number_of_objectives) def evaluate(self, solution: FloatSolution) -> FloatSolution: k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([pow(x, 0.1) for x in solution.variables[self.number_of_variables - k:]]) - t = pi/(4.0 * (1.0 + g)) + g = sum([pow(x, 0.1) for x in solution.variables[self.number_of_variables - k :]]) + t = pi / (4.0 * (1.0 + g)) - theta = [0.0]*(self.number_of_objectives - 1) - theta[0] = solution.variables[0]*pi/2.0 - theta[1:] = [t * (1.0 + 2.0 * g * solution.variables[i]) for i in range(1,self.number_of_objectives-1)] + theta = [0.0] * (self.number_of_objectives - 1) + theta[0] = solution.variables[0] * pi / 2.0 + theta[1:] = [t * (1.0 + 2.0 * g * solution.variables[i]) for i in range(1, self.number_of_objectives - 1)] f = [1.0 + g for _ in range(self.number_of_objectives)] @@ -230,33 +230,34 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'DTLZ6' + return "DTLZ6" class DTLZ7(DTLZ1): - """ Problem DTLZ6. Continuous problem having a disconnected Pareto front + """Problem DTLZ6. Continuous problem having a disconnected Pareto front .. note:: Unconstrained problem. The default number of variables and objectives are, respectively, 22 and 3. """ def __init__(self, number_of_variables: int = 22, number_of_objectives=3): - """:param number_of_variables: number of decision variables of the problem - """ + """:param number_of_variables: number of decision variables of the problem""" super(DTLZ7, self).__init__(number_of_variables, number_of_objectives) def evaluate(self, solution: FloatSolution) -> FloatSolution: k = self.number_of_variables - self.number_of_objectives + 1 - g = sum([x for x in solution.variables[self.number_of_variables - k:]]) + g = sum([x for x in solution.variables[self.number_of_variables - k :]]) g = 1.0 + (9.0 * g) / k - h = sum([(x / (1.0 + g)) * (1 + sin(3.0 * pi * x)) for x in solution.variables[:self.number_of_objectives-1]]) + h = sum( + [(x / (1.0 + g)) * (1 + sin(3.0 * pi * x)) for x in solution.variables[: self.number_of_objectives - 1]] + ) h = self.number_of_objectives - h - solution.objectives[:self.number_of_objectives-1] = solution.variables[:self.number_of_objectives-1] + solution.objectives[: self.number_of_objectives - 1] = solution.variables[: self.number_of_objectives - 1] solution.objectives[-1] = (1.0 + g) * h return solution def get_name(self): - return 'DTLZ7' + return "DTLZ7" diff --git a/jmetal/problem/multiobjective/fda.py b/jmetal/problem/multiobjective/fda.py index 250187b9..56340f93 100644 --- a/jmetal/problem/multiobjective/fda.py +++ b/jmetal/problem/multiobjective/fda.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod -from math import sqrt, pow, sin, pi, floor, cos +from math import cos, floor, pi, pow, sin, sqrt import numpy -from jmetal.core.problem import FloatProblem, DynamicProblem +from jmetal.core.problem import DynamicProblem, FloatProblem from jmetal.core.solution import FloatSolution """ @@ -40,21 +40,20 @@ def evaluate(self, solution: FloatSolution): class FDA1(FDA): - """ Problem FDA1. + """Problem FDA1. .. note:: Bi-objective dynamic unconstrained problem. The default number of variables is 100. """ def __init__(self, number_of_variables: int = 100): - """ :param number_of_variables: Number of decision variables of the problem. - """ + """:param number_of_variables: Number of decision variables of the problem.""" super(FDA1, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 2 self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = self.number_of_variables * [-1.0] self.upper_bound = self.number_of_variables * [1.0] @@ -80,25 +79,24 @@ def __eval_h(self, f: float, g: float) -> float: return 1.0 - sqrt(f / g) def get_name(self): - return 'FDA1' + return "FDA1" class FDA2(FDA): - """ Problem FDA2 + """Problem FDA2 .. note:: Bi-objective dynamic unconstrained problem. The default number of variables is 31. """ def __init__(self, number_of_variables: int = 31): - """ :param number_of_variables: Number of decision variables of the problem. - """ + """:param number_of_variables: Number of decision variables of the problem.""" super(FDA2, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 2 self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = self.number_of_variables * [-1.0] self.upper_bound = self.number_of_variables * [1.0] @@ -125,18 +123,17 @@ def __eval_h(self, f: float, g: float) -> float: return 1.0 - pow(f / g, ht) def get_name(self): - return 'FDA2' + return "FDA2" class FDA3(FDA): - """ Problem FDA3 + """Problem FDA3 .. note:: Bi-objective dynamic unconstrained problem. The default number of variables is 30. """ def __init__(self, number_of_variables: int = 30): - """ :param number_of_variables: Number of decision variables of the problem. - """ + """:param number_of_variables: Number of decision variables of the problem.""" super(FDA3, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 2 @@ -146,7 +143,7 @@ def __init__(self, number_of_variables: int = 30): self.limitInfII = 1 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = self.number_of_variables * [-1.0] self.upper_bound = self.number_of_variables * [1.0] @@ -182,26 +179,26 @@ def __eval_h(self, f: float, g: float) -> float: return h def get_name(self): - return 'FDA3' + return "FDA3" class FDA4(FDA): - """ Problem FDA4 + """Problem FDA4 .. note:: Three-objective dynamic unconstrained problem. The default number of variables is 12. """ + M = 3 def __init__(self, number_of_variables: int = 12): - """ :param number_of_variables: Number of decision variables of the problem. - """ + """:param number_of_variables: Number of decision variables of the problem.""" super(FDA4, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 3 self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)', 'f(z)'] + self.obj_labels = ["f(x)", "f(y)", "f(z)"] self.lower_bound = self.number_of_variables * [0.0] self.upper_bound = self.number_of_variables * [1.0] @@ -223,14 +220,14 @@ def __eval_g(self, solution: FloatSolution, lower_limit: int): def __eval_f1(self, solution: FloatSolution, g: float) -> float: f = 1.0 + g - mult = numpy.prod([cos(v * pi / 2.0) for v in solution.variables[:self.M - 1]]) + mult = numpy.prod([cos(v * pi / 2.0) for v in solution.variables[: self.M - 1]]) return f * mult def __eval_fk(self, solution: FloatSolution, g: float, k: int) -> float: f = 1.0 + g aux = sin((solution.variables[self.M - k] * pi) / 2.0) - mult = numpy.prod([cos(v * pi / 2.0) for v in solution.variables[:self.M - k]]) + mult = numpy.prod([cos(v * pi / 2.0) for v in solution.variables[: self.M - k]]) return f * mult * aux @@ -241,26 +238,26 @@ def __eval_fm(self, solution: FloatSolution, g: float) -> float: return fm def get_name(self): - return 'FDA4' + return "FDA4" class FDA5(FDA): - """ Problem FDA5 + """Problem FDA5 .. note:: Three-objective dynamic unconstrained problem. The default number of variables is 12. """ + M = 3 def __init__(self, number_of_variables: int = 12): - """ :param number_of_variables: Number of decision variables of the problem. - """ + """:param number_of_variables: Number of decision variables of the problem.""" super(FDA5, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 3 self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)', 'f(z)'] + self.obj_labels = ["f(x)", "f(y)", "f(z)"] self.lower_bound = self.number_of_variables * [0.0] self.upper_bound = self.number_of_variables * [1.0] @@ -283,14 +280,14 @@ def __eval_g(self, solution: FloatSolution, lower_limit: int): def __eval_f1(self, solution: FloatSolution, g: float, ft: float) -> float: f = 1.0 + g - mult = numpy.prod([cos(pow(v, ft) * pi / 2.0) for v in solution.variables[:self.M - 1]]) + mult = numpy.prod([cos(pow(v, ft) * pi / 2.0) for v in solution.variables[: self.M - 1]]) return f * mult def __eval_fk(self, solution: FloatSolution, g: float, k: int, ft: float) -> float: f = 1.0 + g - mult = numpy.prod([cos(pow(v, ft) * pi / 2.0) for v in solution.variables[:self.M - k]]) + mult = numpy.prod([cos(pow(v, ft) * pi / 2.0) for v in solution.variables[: self.M - k]]) yy = pow(solution.variables[self.M - k], ft) mult *= sin(yy * pi / 2.0) @@ -304,4 +301,4 @@ def __eval_fm(self, solution: FloatSolution, g: float, ft: float) -> float: return fm * mult def get_name(self): - return 'FDA5' + return "FDA5" diff --git a/jmetal/problem/multiobjective/lircmop.py b/jmetal/problem/multiobjective/lircmop.py index cab9f2f9..85d41950 100644 --- a/jmetal/problem/multiobjective/lircmop.py +++ b/jmetal/problem/multiobjective/lircmop.py @@ -1,11 +1,12 @@ -from math import sin, pi, cos, sqrt +from math import cos, pi, sin, sqrt +from typing import List from jmetal.core.problem import FloatProblem from jmetal.core.solution import FloatSolution class LIRCMOP1(FloatProblem): - """ Class representing problem LIR-CMOP1, defined in: + """Class representing problem LIR-CMOP1, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -18,7 +19,7 @@ def __init__(self, number_of_variables: int = 30): self.number_of_constraints = 2 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [0.0 for _ in range(self.number_of_variables)] self.upper_bound = [1.0 for _ in range(self.number_of_variables)] @@ -47,14 +48,14 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: return solution - def g1(self, x: [float]) -> float: + def g1(self, x: List[float]) -> float: result = 0 for i in range(2, self.number_of_variables, 2): result += pow(x[i] - sin(0.5 * pi * x[0]), 2.0) return result - def g2(self, x: [float]) -> float: + def g2(self, x: List[float]) -> float: result = 0 for i in range(1, self.number_of_variables, 2): result += pow(x[i] - cos(0.5 * pi * x[0]), 2.0) @@ -62,11 +63,11 @@ def g2(self, x: [float]) -> float: return result def get_name(self): - return 'LIR-CMOP1' + return "LIR-CMOP1" class LIRCMOP2(LIRCMOP1): - """ Class representing problem LIR-CMOP1, defined in: + """Class representing problem LIR-CMOP1, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -86,11 +87,11 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'LIR-CMOP2' + return "LIR-CMOP2" class LIRCMOP3(LIRCMOP1): - """ Class representing problem LIR-CMOP3, defined in: + """Class representing problem LIR-CMOP3, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -116,11 +117,11 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'LIR-CMOP3' + return "LIR-CMOP3" class LIRCMOP4(LIRCMOP2): - """ Class representing problem LIR-CMOP4, defined in: + """Class representing problem LIR-CMOP4, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -146,11 +147,11 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'LIR-CMOP4' + return "LIR-CMOP4" class LIRCMOP5(FloatProblem): - """ Class representing problem LIR-CMOP5, defined in: + """Class representing problem LIR-CMOP5, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -163,7 +164,7 @@ def __init__(self, number_of_variables: int = 30): self.number_of_constraints = 2 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [0.0 for _ in range(self.number_of_variables)] self.upper_bound = [1.0 for _ in range(self.number_of_variables)] @@ -191,11 +192,11 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f2 = solution.objectives[1] for i in range(len(x_offset)): - constraints[i] = pow( - ((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + \ - pow( - ((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], - 2) - r + constraints[i] = ( + pow(((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + + pow(((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], 2) + - r + ) solution.constraints = constraints @@ -216,11 +217,11 @@ def g2(self, x: [float]) -> float: return result def get_name(self): - return 'LIR-CMOP5' + return "LIR-CMOP5" class LIRCMOP6(LIRCMOP5): - """ Class representing problem LIR-CMOP6, defined in: + """Class representing problem LIR-CMOP6, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -252,22 +253,22 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f2 = solution.objectives[1] for i in range(len(x_offset)): - constraints[i] = pow( - ((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + \ - pow( - ((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], - 2) - r + constraints[i] = ( + pow(((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + + pow(((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP6' + return "LIR-CMOP6" class LIRCMOP7(LIRCMOP5): - """ Class representing problem LIR-CMOP7, defined in: + """Class representing problem LIR-CMOP7, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -289,22 +290,22 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f2 = solution.objectives[1] for i in range(len(x_offset)): - constraints[i] = pow( - ((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + \ - pow( - ((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], - 2) - r + constraints[i] = ( + pow(((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + + pow(((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP7' + return "LIR-CMOP7" class LIRCMOP8(LIRCMOP6): - """ Class representing problem LIR-CMOP8, defined in: + """Class representing problem LIR-CMOP8, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -326,22 +327,22 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f2 = solution.objectives[1] for i in range(len(x_offset)): - constraints[i] = pow( - ((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + \ - pow( - ((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], - 2) - r + constraints[i] = ( + pow(((f1 - x_offset[i]) * cos(theta) - (f2 - y_offset[i]) * sin(theta)) / a_array[i], 2) + + pow(((f1 - x_offset[i]) * sin(theta) + (f2 - y_offset[i]) * cos(theta)) / b_array[i], 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP8' + return "LIR-CMOP8" class LIRCMOP9(LIRCMOP8): - """ Class representing problem LIR-CMOP9, defined in: + """Class representing problem LIR-CMOP9, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -369,27 +370,30 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f0 = solution.objectives[0] f1 = solution.objectives[1] - constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 2; + constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 2 x_offset = 1.40 y_offset = 1.40 a = 1.5 b = 6.0 - r = 0.1; + r = 0.1 - constraints[1] = pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + pow( - ((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) - r + constraints[1] = ( + pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + + pow(((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP9' + return "LIR-CMOP9" class LIRCMOP10(LIRCMOP8): - """ Class representing problem LIR-CMOP10, defined in: + """Class representing problem LIR-CMOP10, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -416,27 +420,30 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f0 = solution.objectives[0] f1 = solution.objectives[1] - constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 1; + constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 1 x_offset = 1.1 y_offset = 1.2 a = 2.0 b = 4.0 - r = 0.1; + r = 0.1 - constraints[1] = pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + pow( - ((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) - r + constraints[1] = ( + pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + + pow(((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP10' + return "LIR-CMOP10" class LIRCMOP11(LIRCMOP10): - """ Class representing problem LIR-CMOP11, defined in: + """Class representing problem LIR-CMOP11, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -453,27 +460,30 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f0 = solution.objectives[0] f1 = solution.objectives[1] - constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 2.1; + constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 2.1 x_offset = 1.2 y_offset = 1.2 a = 1.5 b = 5.0 - r = 0.1; + r = 0.1 - constraints[1] = pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + pow( - ((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) - r + constraints[1] = ( + pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + + pow(((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP11' + return "LIR-CMOP11" class LIRCMOP12(LIRCMOP9): - """ Class representing problem LIR-CMOP9, defined in: + """Class representing problem LIR-CMOP9, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -490,27 +500,30 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: f0 = solution.objectives[0] f1 = solution.objectives[1] - constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 2.5; + constraints[0] = f0 * sin(theta) + f1 * cos(theta) - sin(n * pi * (f0 * cos(theta) - f1 * sin(theta))) - 2.5 x_offset = 1.6 y_offset = 1.6 a = 1.5 b = 6.0 - r = 0.1; + r = 0.1 - constraints[1] = pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + pow( - ((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) - r + constraints[1] = ( + pow(((f0 - x_offset) * cos(theta) - (f1 - y_offset) * sin(theta)) / a, 2) + + pow(((f0 - x_offset) * sin(theta) + (f1 - y_offset) * cos(theta)) / b, 2) + - r + ) solution.constraints = constraints return solution def get_name(self): - return 'LIR-CMOP12' + return "LIR-CMOP12" class LIRCMOP13(FloatProblem): - """ Class representing problem LIR-CMOP13, defined in: + """Class representing problem LIR-CMOP13, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -523,7 +536,7 @@ def __init__(self, number_of_variables: int = 30): self.number_of_constraints = 2 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [0.0 for _ in range(self.number_of_variables)] self.upper_bound = [1.0 for _ in range(self.number_of_variables)] @@ -559,11 +572,11 @@ def g1(self, x: [float]) -> float: return result def get_name(self): - return 'LIR-CMOP13' + return "LIR-CMOP13" class LIRCMOP14(LIRCMOP13): - """ Class representing problem LIR-CMOP14, defined in: + """Class representing problem LIR-CMOP14, defined in: * An Improved epsilon-constrained Method in MOEA/D for CMOPs with Large Infeasible Regions. Fan, Z., Li, W., Cai, X. et al. Soft Comput (2019). https://doi.org/10.1007/s00500-019-03794-x @@ -587,4 +600,4 @@ def evaluate_constraints(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'LIR-CMOP14' + return "LIR-CMOP14" diff --git a/jmetal/problem/multiobjective/lz09.py b/jmetal/problem/multiobjective/lz09.py index 7d484b97..5fd3af51 100644 --- a/jmetal/problem/multiobjective/lz09.py +++ b/jmetal/problem/multiobjective/lz09.py @@ -17,14 +17,16 @@ class LZ09(FloatProblem): __metaclass__ = ABCMeta - def __init__(self, - number_of_variables: int, - number_of_objectives: int, - number_of_constraints: int, - ptype: int, - dtype: int, - ltype: int): - """ LZ09 benchmark family as defined in: + def __init__( + self, + number_of_variables: int, + number_of_objectives: int, + number_of_constraints: int, + ptype: int, + dtype: int, + ltype: int, + ): + """LZ09 benchmark family as defined in: * H. Li and Q. Zhang. Multiobjective optimization problems with complicated pareto sets, MOEA/D and NSGA-II. IEEE Transactions on Evolutionary Computation, 12(2):284-302, April 2009. @@ -35,7 +37,7 @@ def __init__(self, self.number_of_constraints = number_of_constraints self.obj_directions = [self.MINIMIZE, self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)', 'f(z)'] + self.obj_labels = ["f(x)", "f(y)", "f(z)"] self.lower_bound = self.number_of_variables * [0.0] self.upper_bound = self.number_of_variables * [1.0] @@ -54,7 +56,7 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def __ps_func2(self, x: float, t1: float, dim: int, type: int, css: int) -> float: - """ Control the PS shapes of 2-D instances. + """Control the PS shapes of 2-D instances. :param type: The type of the curve. :param css: The class of the index. @@ -108,26 +110,25 @@ def __ps_func2(self, x: float, t1: float, dim: int, type: int, css: int) -> floa return beta def __ps_func3(self, x: float, t1: float, t2: float, dim: int, type: int): - """ Control the PS shapes of 3-D instances. + """Control the PS shapes of 3-D instances. :param type: The type of curve. """ beta = 0.0 dim += 1 if type == 31: - xy = 4 * (x - .5) + xy = 4 * (x - 0.5) rate = 1.0 * dim / self.number_of_variables beta = xy - 4 * (t1 * t1 * rate + t2 * (1.0 - rate)) + 2 if type == 32: theta = 2 * math.pi * t1 + dim * math.pi / self.number_of_variables - xy = 4 * (x - .5) + xy = 4 * (x - 0.5) beta = xy - 2 * t2 * math.sin(theta) return beta def __alpha_func(self, x: list, dim: int, type: int) -> list: - """ Control the PF shape. - """ + """Control the PF shape.""" alpha = [0.0] * dim if dim == 2: @@ -164,8 +165,7 @@ def __alpha_func(self, x: list, dim: int, type: int) -> list: return alpha def __beta_func(self, x: list, type: int) -> float: - """ Control the distance. - """ + """Control the distance.""" beta = 0.0 dim = len(x) @@ -183,7 +183,7 @@ def __beta_func(self, x: list, type: int) -> float: sum, xx = 0, 0 for i in range(dim): xx = 2 * x[i] - sum += (xx * xx - math.cos(4 * math.pi * xx) + 1) + sum += xx * xx - math.cos(4 * math.pi * xx) + 1 beta = 2.0 * sum / dim if type == 4: sum, prod, xx = 0, 1, 0 @@ -268,94 +268,94 @@ def objective(self, x_variables: list) -> list: return y_objectives def get_name(self): - return 'LZ09' + return "LZ09" class LZ09_F1(LZ09): - def __init__(self): - super(LZ09_F1, self).__init__(number_of_variables=10, number_of_objectives=2, number_of_constraints=0, - dtype=1, ltype=21, ptype=21) + super(LZ09_F1, self).__init__( + number_of_variables=10, number_of_objectives=2, number_of_constraints=0, dtype=1, ltype=21, ptype=21 + ) def get_name(self): - return 'LZ09_F1' + return "LZ09_F1" class LZ09_F2(LZ09): - def __init__(self): - super(LZ09_F2, self).__init__(number_of_variables=30, number_of_objectives=2, number_of_constraints=0, - dtype=1, ltype=22, ptype=21) + super(LZ09_F2, self).__init__( + number_of_variables=30, number_of_objectives=2, number_of_constraints=0, dtype=1, ltype=22, ptype=21 + ) def get_name(self): - return 'LZ09_F2' + return "LZ09_F2" class LZ09_F3(LZ09): - def __init__(self): - super(LZ09_F3, self).__init__(number_of_variables=30, number_of_objectives=2, number_of_constraints=0, - dtype=1, ltype=23, ptype=21) + super(LZ09_F3, self).__init__( + number_of_variables=30, number_of_objectives=2, number_of_constraints=0, dtype=1, ltype=23, ptype=21 + ) def get_name(self): - return 'LZ09_F3' + return "LZ09_F3" class LZ09_F4(LZ09): - def __init__(self): - super(LZ09_F4, self).__init__(number_of_variables=30, number_of_objectives=2, number_of_constraints=0, - dtype=1, ltype=24, ptype=21) + super(LZ09_F4, self).__init__( + number_of_variables=30, number_of_objectives=2, number_of_constraints=0, dtype=1, ltype=24, ptype=21 + ) def get_name(self): - return 'LZ09_F4' + return "LZ09_F4" class LZ09_F5(LZ09): - def __init__(self): - super(LZ09_F5, self).__init__(number_of_variables=30, number_of_objectives=2, number_of_constraints=0, - dtype=1, ltype=26, ptype=21) + super(LZ09_F5, self).__init__( + number_of_variables=30, number_of_objectives=2, number_of_constraints=0, dtype=1, ltype=26, ptype=21 + ) def get_name(self): - return 'LZ09_F5' + return "LZ09_F5" class LZ09_F6(LZ09): - def __init__(self): - super(LZ09_F6, self).__init__(number_of_variables=10, number_of_objectives=3, number_of_constraints=0, - dtype=1, ltype=32, ptype=31) + super(LZ09_F6, self).__init__( + number_of_variables=10, number_of_objectives=3, number_of_constraints=0, dtype=1, ltype=32, ptype=31 + ) def get_name(self): - return 'LZ09_F6' + return "LZ09_F6" class LZ09_F7(LZ09): - def __init__(self): - super(LZ09_F7, self).__init__(number_of_variables=10, number_of_objectives=2, number_of_constraints=0, - dtype=3, ltype=21, ptype=21) + super(LZ09_F7, self).__init__( + number_of_variables=10, number_of_objectives=2, number_of_constraints=0, dtype=3, ltype=21, ptype=21 + ) def get_name(self): - return 'LZ09_F7' + return "LZ09_F7" class LZ09_F8(LZ09): - def __init__(self): - super(LZ09_F8, self).__init__(number_of_variables=10, number_of_objectives=2, number_of_constraints=0, - dtype=4, ltype=21, ptype=21) + super(LZ09_F8, self).__init__( + number_of_variables=10, number_of_objectives=2, number_of_constraints=0, dtype=4, ltype=21, ptype=21 + ) def get_name(self): - return 'LZ09_F8' + return "LZ09_F8" class LZ09_F9(LZ09): - def __init__(self): - super(LZ09_F9, self).__init__(number_of_variables=30, number_of_objectives=2, number_of_constraints=0, - dtype=1, ltype=22, ptype=22) + super(LZ09_F9, self).__init__( + number_of_variables=30, number_of_objectives=2, number_of_constraints=0, dtype=1, ltype=22, ptype=22 + ) def get_name(self): - return 'LZ09_F9' \ No newline at end of file + return "LZ09_F9" diff --git a/jmetal/problem/multiobjective/test/test_constrained.py b/jmetal/problem/multiobjective/test/test_constrained.py index 7d0ac8e1..985b6336 100644 --- a/jmetal/problem/multiobjective/test/test_constrained.py +++ b/jmetal/problem/multiobjective/test/test_constrained.py @@ -5,7 +5,6 @@ class SrinivasTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = Srinivas() self.assertIsNotNone(problem) @@ -35,7 +34,6 @@ def test_should_get_name_return_the_right_name(self): class TanakaTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = Tanaka() self.assertIsNotNone(problem) @@ -64,5 +62,5 @@ def test_should_get_name_return_the_right_name(self): self.assertEqual("Tanaka", problem.get_name()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/problem/multiobjective/test/test_unconstrained.py b/jmetal/problem/multiobjective/test/test_unconstrained.py index f2a41612..e08a6aa3 100644 --- a/jmetal/problem/multiobjective/test/test_unconstrained.py +++ b/jmetal/problem/multiobjective/test/test_unconstrained.py @@ -1,10 +1,14 @@ import unittest -from jmetal.problem.multiobjective.unconstrained import Kursawe, Fonseca, Schaffer, Viennet2 +from jmetal.problem.multiobjective.unconstrained import ( + Fonseca, + Kursawe, + Schaffer, + Viennet2, +) class KursaweTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = Kursawe(3) self.assertIsNotNone(problem) @@ -45,7 +49,6 @@ def test_should_get_name_return_the_right_name(self): class FonsecaTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): problem = Fonseca() self.assertIsNotNone(problem) @@ -94,7 +97,6 @@ def test_should_get_name_return_the_right_name(self): class SchafferTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): problem = Schaffer() self.assertIsNotNone(problem) @@ -147,7 +149,6 @@ def test_should_get_name_return_the_right_name(self): class Viennet2TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): problem = Viennet2() self.assertIsNotNone(problem) @@ -194,5 +195,5 @@ def test_should_get_name_return_the_right_name(self): self.assertEqual("Viennet2", problem.get_name()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/problem/multiobjective/test/test_zdt.py b/jmetal/problem/multiobjective/test/test_zdt.py index a87168ba..fadb6360 100644 --- a/jmetal/problem/multiobjective/test/test_zdt.py +++ b/jmetal/problem/multiobjective/test/test_zdt.py @@ -4,7 +4,6 @@ class ZDT1TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = ZDT1() self.assertIsNotNone(problem) @@ -23,8 +22,8 @@ def test_should_constructor_create_a_valid_problem_with_5_variables(self) -> Non self.assertEqual(2, problem.number_of_objectives) self.assertEqual(0, problem.number_of_constraints) - self.assertEqual(5*[0.0], problem.lower_bound) - self.assertEqual(5*[1.0], problem.upper_bound) + self.assertEqual(5 * [0.0], problem.lower_bound) + self.assertEqual(5 * [1.0], problem.upper_bound) def test_should_create_solution_create_a_valid_float_solution(self) -> None: problem = ZDT1() @@ -45,7 +44,6 @@ def test_should_get_name_return_the_right_name(self): class ZDT2TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = ZDT2() self.assertIsNotNone(problem) @@ -64,8 +62,8 @@ def test_should_constructor_create_a_valid_problem_with_7_variables(self) -> Non self.assertEqual(2, problem.number_of_objectives) self.assertEqual(0, problem.number_of_constraints) - self.assertEqual(7*[0.0], problem.lower_bound) - self.assertEqual(7*[1.0], problem.upper_bound) + self.assertEqual(7 * [0.0], problem.lower_bound) + self.assertEqual(7 * [1.0], problem.upper_bound) def test_should_create_solution_create_a_valid_float_solution(self) -> None: problem = ZDT2() @@ -86,7 +84,6 @@ def test_should_get_name_return_the_right_name(self): class ZDT3TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = ZDT3() self.assertIsNotNone(problem) @@ -105,8 +102,8 @@ def test_should_constructor_create_a_valid_problem_with_7_variables(self) -> Non self.assertEqual(2, problem.number_of_objectives) self.assertEqual(0, problem.number_of_constraints) - self.assertEqual(7*[0.0], problem.lower_bound) - self.assertEqual(7*[1.0], problem.upper_bound) + self.assertEqual(7 * [0.0], problem.lower_bound) + self.assertEqual(7 * [1.0], problem.upper_bound) def test_should_create_solution_create_a_valid_float_solution(self) -> None: problem = ZDT3() @@ -127,7 +124,6 @@ def test_should_get_name_return_the_right_name(self): class ZDT4TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = ZDT4() self.assertIsNotNone(problem) @@ -176,7 +172,6 @@ def test_should_get_name_return_the_right_name(self): class ZDT6TestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = ZDT6() self.assertIsNotNone(problem) @@ -195,8 +190,8 @@ def test_should_constructor_create_a_valid_problem_with_7_variables(self) -> Non self.assertEqual(2, problem.number_of_objectives) self.assertEqual(0, problem.number_of_constraints) - self.assertEqual(7*[0.0], problem.lower_bound) - self.assertEqual(7*[1.0], problem.upper_bound) + self.assertEqual(7 * [0.0], problem.lower_bound) + self.assertEqual(7 * [1.0], problem.upper_bound) def test_should_create_solution_create_a_valid_float_solution(self) -> None: problem = ZDT6() @@ -216,5 +211,5 @@ def test_should_get_name_return_the_right_name(self): self.assertEqual("ZDT6", problem.get_name()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/problem/multiobjective/uf.py b/jmetal/problem/multiobjective/uf.py index 3058b7ca..93694bf7 100644 --- a/jmetal/problem/multiobjective/uf.py +++ b/jmetal/problem/multiobjective/uf.py @@ -13,21 +13,20 @@ class UF1(FloatProblem): - """ Problem UF1. + """Problem UF1. .. note:: Unconstrained problem. The default number of variables is 30. """ def __init__(self, number_of_variables: int = 30): - """ :param number_of_variables: number of decision variables of the problem. - """ + """:param number_of_variables: number of decision variables of the problem.""" super(UF1, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 2 self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE] * self.number_of_objectives - self.obj_labels = ['$ f_{} $'.format(i) for i in range(self.number_of_objectives)] + self.obj_labels = ["$ f_{} $".format(i) for i in range(self.number_of_objectives)] self.lower_bound = self.number_of_variables * [-1.0] self.upper_bound = self.number_of_variables * [1.0] @@ -43,22 +42,20 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: x = solution.variables for i in range(2, self.number_of_variables): - y = x[i-1] - sin(6.0 * pi * x[0] + i * pi/solution.number_of_variables) - y = y*y + y = x[i - 1] - sin(6.0 * pi * x[0] + i * pi / solution.number_of_variables) + y = y * y - if i % 2 is 0: + if i % 2 == 0: sum2 += y - count2 +=1 + count2 += 1 else: - sum1 +=y + sum1 += y count1 += 1 - solution.objectives[0] = x[0] + 2.0 * sum1 /(1.0 * count1) + solution.objectives[0] = x[0] + 2.0 * sum1 / (1.0 * count1) solution.objectives[1] = 1.0 - sqrt(x[0]) + 2.0 * sum2 / (1.0 * count2) - return solution def get_name(self): - return 'UF1' - + return "UF1" diff --git a/jmetal/problem/multiobjective/unconstrained.py b/jmetal/problem/multiobjective/unconstrained.py index 36c71aa8..26f8dc3a 100644 --- a/jmetal/problem/multiobjective/unconstrained.py +++ b/jmetal/problem/multiobjective/unconstrained.py @@ -1,8 +1,13 @@ import random -from math import sqrt, exp, pow, sin +from math import exp, pow, sin, sqrt -from jmetal.core.problem import FloatProblem, BinaryProblem, Problem -from jmetal.core.solution import FloatSolution, BinarySolution, CompositeSolution, IntegerSolution +from jmetal.core.problem import BinaryProblem, FloatProblem, Problem +from jmetal.core.solution import ( + BinarySolution, + CompositeSolution, + FloatSolution, + IntegerSolution, +) """ .. module:: constrained @@ -14,7 +19,7 @@ class Kursawe(FloatProblem): - """ Class representing problem Kursawe. """ + """Class representing problem Kursawe.""" def __init__(self, number_of_variables: int = 3): super(Kursawe, self).__init__() @@ -23,7 +28,7 @@ def __init__(self, number_of_variables: int = 3): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [-5.0 for _ in range(number_of_variables)] self.upper_bound = [5.0 for _ in range(number_of_variables)] @@ -38,6 +43,8 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: xj = solution.variables[i + 1] * solution.variables[i + 1] aux = -0.2 * sqrt(xi + xj) fx[0] += -10 * exp(aux) + + for i in range(self.number_of_variables): fx[1] += pow(abs(solution.variables[i]), 0.8) + 5.0 * sin(pow(solution.variables[i], 3.0)) solution.objectives[0] = fx[0] @@ -46,11 +53,10 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'Kursawe' + return "Kursawe" class Fonseca(FloatProblem): - def __init__(self): super(Fonseca, self).__init__() self.number_of_variables = 3 @@ -58,7 +64,7 @@ def __init__(self): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = self.number_of_variables * [-4] self.upper_bound = self.number_of_variables * [4] @@ -68,17 +74,16 @@ def __init__(self): def evaluate(self, solution: FloatSolution) -> FloatSolution: n = self.number_of_variables - solution.objectives[0] = 1 - exp(-sum([(x - 1.0 / n ** 0.5) ** 2 for x in solution.variables])) - solution.objectives[1] = 1 - exp(-sum([(x + 1.0 / n ** 0.5) ** 2 for x in solution.variables])) + solution.objectives[0] = 1 - exp(-sum([(x - 1.0 / n**0.5) ** 2 for x in solution.variables])) + solution.objectives[1] = 1 - exp(-sum([(x + 1.0 / n**0.5) ** 2 for x in solution.variables])) return solution def get_name(self): - return 'Fonseca' + return "Fonseca" class Schaffer(FloatProblem): - def __init__(self): super(Schaffer, self).__init__() self.number_of_variables = 1 @@ -86,7 +91,7 @@ def __init__(self): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)'] + self.obj_labels = ["f(x)", "f(y)"] self.lower_bound = [-100000] self.upper_bound = [100000] @@ -97,17 +102,16 @@ def __init__(self): def evaluate(self, solution: FloatSolution) -> FloatSolution: value = solution.variables[0] - solution.objectives[0] = value ** 2 + solution.objectives[0] = value**2 solution.objectives[1] = (value - 2) ** 2 return solution def get_name(self): - return 'Schaffer' + return "Schaffer" class Viennet2(FloatProblem): - def __init__(self): super(Viennet2, self).__init__() self.number_of_variables = 2 @@ -115,14 +119,11 @@ def __init__(self): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['f(x)', 'f(y)', 'f(z)'] + self.obj_labels = ["f(x)", "f(y)", "f(z)"] self.lower_bound = self.number_of_variables * [-4] self.upper_bound = self.number_of_variables * [4] - FloatSolution.lower_bound = self.lower_bound - FloatSolution.upper_bound = self.upper_bound - def evaluate(self, solution: FloatSolution) -> FloatSolution: x0 = solution.variables[0] x1 = solution.variables[1] @@ -138,13 +139,12 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self): - return 'Viennet2' + return "Viennet2" class SubsetSum(BinaryProblem): - def __init__(self, C: int, W: list): - """ The goal is to find a subset S of W whose elements sum is closest to (without exceeding) C. + """The goal is to find a subset S of W whose elements sum is closest to (without exceeding) C. :param C: Large integer. :param W: Set of non-negative integers.""" @@ -158,7 +158,7 @@ def __init__(self, C: int, W: list): self.number_of_constraints = 0 self.obj_directions = [self.MAXIMIZE, self.MINIMIZE] - self.obj_labels = ['Sum', 'No. of Objects'] + self.obj_labels = ["Sum", "No. of Objects"] def evaluate(self, solution: BinarySolution) -> BinarySolution: total_sum = 0.0 @@ -181,19 +181,18 @@ def evaluate(self, solution: BinarySolution) -> BinarySolution: return solution def create_solution(self) -> BinarySolution: - new_solution = BinarySolution(number_of_variables=self.number_of_variables, - number_of_objectives=self.number_of_objectives) - new_solution.variables[0] = \ - [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] + new_solution = BinarySolution( + number_of_variables=self.number_of_variables, number_of_objectives=self.number_of_objectives + ) + new_solution.variables[0] = [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] return new_solution def get_name(self) -> str: - return 'Subset Sum' + return "Subset Sum" class OneZeroMax(BinaryProblem): - def __init__(self, number_of_bits: int = 256): super(OneZeroMax, self).__init__() self.number_of_bits = number_of_bits @@ -202,7 +201,7 @@ def __init__(self, number_of_bits: int = 256): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE] - self.obj_labels = ['Ones'] + self.obj_labels = ["Ones"] def evaluate(self, solution: BinarySolution) -> BinarySolution: counter_of_ones = 0 @@ -219,19 +218,26 @@ def evaluate(self, solution: BinarySolution) -> BinarySolution: return solution def create_solution(self) -> BinarySolution: - new_solution = BinarySolution(number_of_variables=self.number_of_variables, - number_of_objectives=self.number_of_objectives) - new_solution.variables[0] = \ - [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] + new_solution = BinarySolution( + number_of_variables=self.number_of_variables, number_of_objectives=self.number_of_objectives + ) + new_solution.variables[0] = [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] return new_solution def get_name(self) -> str: - return 'OneZeroMax' + return "OneZeroMax" class MixedIntegerFloatProblem(Problem): - def __init__(self, number_of_integer_variables=10, number_of_float_variables=10, n=100, m=-100, lower_bound=-1000, - upper_bound=1000): + def __init__( + self, + number_of_integer_variables=10, + number_of_float_variables=10, + n=100, + m=-100, + lower_bound=-1000, + upper_bound=1000, + ): super(MixedIntegerFloatProblem, self).__init__() self.number_of_objectives = 2 self.number_of_variables = 2 @@ -246,7 +252,7 @@ def __init__(self, number_of_integer_variables=10, number_of_float_variables=10, self.int_upper_bound = [upper_bound for _ in range(number_of_integer_variables)] self.obj_directions = [self.MINIMIZE] - self.obj_labels = ['Ones'] + self.obj_labels = ["Ones"] def evaluate(self, solution: CompositeSolution) -> CompositeSolution: distance_to_n = sum([abs(self.n - value) for value in solution.variables[0].variables]) @@ -261,23 +267,24 @@ def evaluate(self, solution: CompositeSolution) -> CompositeSolution: return solution def create_solution(self) -> CompositeSolution: - integer_solution = IntegerSolution(self.int_lower_bound, self.int_upper_bound, self.number_of_objectives, - self.number_of_constraints) + integer_solution = IntegerSolution( + self.int_lower_bound, self.int_upper_bound, self.number_of_objectives, self.number_of_constraints + ) float_solution = FloatSolution( - self.float_lower_bound, - self.float_upper_bound, - self.number_of_objectives, self.number_of_constraints) + self.float_lower_bound, self.float_upper_bound, self.number_of_objectives, self.number_of_constraints + ) - float_solution.variables = \ - [random.uniform(self.float_lower_bound[i] * 1.0, self.float_upper_bound[i] * .01) for i in - range(len(self.int_lower_bound))] + float_solution.variables = [ + random.uniform(self.float_lower_bound[i] * 1.0, self.float_upper_bound[i] * 0.01) + for i in range(len(self.int_lower_bound)) + ] - integer_solution.variables = \ - [random.uniform(self.float_lower_bound[i], self.float_upper_bound[i]) for i in - range(len(self.float_lower_bound))] + integer_solution.variables = [ + random.uniform(self.float_lower_bound[i], self.float_upper_bound[i]) + for i in range(len(self.float_lower_bound)) + ] return CompositeSolution([integer_solution, float_solution]) def get_name(self) -> str: return "Mixed Integer Float Problem" - diff --git a/jmetal/problem/multiobjective/zdt.py b/jmetal/problem/multiobjective/zdt.py index 3d61d07f..52a7d486 100644 --- a/jmetal/problem/multiobjective/zdt.py +++ b/jmetal/problem/multiobjective/zdt.py @@ -1,4 +1,4 @@ -from math import sqrt, pow, sin, pi, cos +from math import cos, pi, pow, sin, sqrt from jmetal.core.problem import FloatProblem from jmetal.core.solution import FloatSolution @@ -13,22 +13,21 @@ class ZDT1(FloatProblem): - """ Problem ZDT1. + """Problem ZDT1. .. note:: Bi-objective unconstrained problem. The default number of variables is 30. .. note:: Continuous problem having a convex Pareto front """ - def __init__(self, number_of_variables: int=30): - """ :param number_of_variables: Number of decision variables of the problem. - """ + def __init__(self, number_of_variables: int = 30): + """:param number_of_variables: Number of decision variables of the problem.""" super(ZDT1, self).__init__() self.number_of_variables = number_of_variables self.number_of_objectives = 2 self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE, self.MINIMIZE] - self.obj_labels = ['x', 'y'] + self.obj_labels = ["x", "y"] self.lower_bound = self.number_of_variables * [0.0] self.upper_bound = self.number_of_variables * [1.0] @@ -53,18 +52,19 @@ def eval_h(self, f: float, g: float) -> float: return 1.0 - sqrt(f / g) def get_name(self): - return 'ZDT1' + return "ZDT1" class ZDT1Modified(ZDT1): - """ Problem ZDT1Modified. + """Problem ZDT1Modified. .. note:: Version including a loop for increasing the computing time of the evaluation functions. """ - def __init__(self, number_of_variables = 30): + + def __init__(self, number_of_variables=30): super(ZDT1Modified, self).__init__(number_of_variables) - def evaluate(self, solution:FloatSolution) -> FloatSolution: + def evaluate(self, solution: FloatSolution) -> FloatSolution: s: float = 0.0 for i in range(1000): for j in range(10000): @@ -73,7 +73,7 @@ def evaluate(self, solution:FloatSolution) -> FloatSolution: class ZDT2(ZDT1): - """ Problem ZDT2. + """Problem ZDT2. .. note:: Bi-objective unconstrained problem. The default number of variables is 30. .. note:: Continuous problem having a non-convex Pareto front @@ -83,32 +83,32 @@ def eval_h(self, f: float, g: float) -> float: return 1.0 - pow(f / g, 2.0) def get_name(self): - return 'ZDT2' + return "ZDT2" class ZDT3(ZDT1): - """ Problem ZDT3. + """Problem ZDT3. .. note:: Bi-objective unconstrained problem. The default number of variables is 30. .. note:: Continuous problem having a partitioned Pareto front """ + def eval_h(self, f: float, g: float) -> float: return 1.0 - sqrt(f / g) - (f / g) * sin(10.0 * f * pi) def get_name(self): - return 'ZDT3' + return "ZDT3" class ZDT4(ZDT1): - """ Problem ZDT4. + """Problem ZDT4. .. note:: Bi-objective unconstrained problem. The default number of variables is 10. .. note:: Continuous multi-modal problem having a convex Pareto front """ - def __init__(self, number_of_variables: int=10): - """ :param number_of_variables: Number of decision variables of the problem. - """ + def __init__(self, number_of_variables: int = 10): + """:param number_of_variables: Number of decision variables of the problem.""" super(ZDT4, self).__init__(number_of_variables=number_of_variables) self.lower_bound = self.number_of_variables * [-5.0] self.upper_bound = self.number_of_variables * [5.0] @@ -129,21 +129,31 @@ def eval_h(self, f: float, g: float) -> float: return 1.0 - sqrt(f / g) def get_name(self): - return 'ZDT4' + return "ZDT4" class ZDT6(ZDT1): - """ Problem ZDT6. + """Problem ZDT6. .. note:: Bi-objective unconstrained problem. The default number of variables is 10. .. note:: Continuous problem having a non-convex Pareto front """ - def __init__(self, number_of_variables: int=10): - """ :param number_of_variables: Number of decision variables of the problem. - """ + def __init__(self, number_of_variables: int = 10): + """:param number_of_variables: Number of decision variables of the problem.""" super(ZDT6, self).__init__(number_of_variables=number_of_variables) + def evaluate(self, solution: FloatSolution) -> FloatSolution: + solution.objectives[0] = ( + 1.0 - exp(-4.0 * solution.variables[0]) * (sin(6.0 * pi * solution.variables[0])) ** 6.0 + ) + + g = self.eval_g(solution) + h = self.eval_h(solution.objectives[0], g) + solution.objectives[1] = h * g + + return solution + def eval_g(self, solution: FloatSolution): g = sum(solution.variables) - solution.variables[0] g = g / (solution.number_of_variables - 1) @@ -157,4 +167,4 @@ def eval_h(self, f: float, g: float) -> float: return 1.0 - pow(f / g, 2.0) def get_name(self): - return 'ZDT6' + return "ZDT6" diff --git a/jmetal/problem/singleobjective/knapsack.py b/jmetal/problem/singleobjective/knapsack.py index 578ac389..eb7f6369 100644 --- a/jmetal/problem/singleobjective/knapsack.py +++ b/jmetal/problem/singleobjective/knapsack.py @@ -15,10 +15,17 @@ class Knapsack(BinaryProblem): - """ Class representing Knapsack Problem. """ - - def __init__(self, number_of_items: int = 50, capacity: float = 1000, weights: list = None, - profits: list = None, from_file: bool = False, filename: str = None): + """Class representing Knapsack Problem.""" + + def __init__( + self, + number_of_items: int = 50, + capacity: float = 1000, + weights: list = None, + profits: list = None, + from_file: bool = False, + filename: str = None, + ): super(Knapsack, self).__init__() if from_file: @@ -48,7 +55,7 @@ def __read_from_file(self, filename: str): """ if filename is None: - raise FileNotFoundError('Filename can not be None') + raise FileNotFoundError("Filename can not be None") with open(filename) as file: lines = file.readlines() @@ -78,14 +85,13 @@ def evaluate(self, solution: BinarySolution) -> BinarySolution: return solution def create_solution(self) -> BinarySolution: - new_solution = BinarySolution(number_of_variables=self.number_of_variables, - number_of_objectives=self.number_of_objectives) + new_solution = BinarySolution( + number_of_variables=self.number_of_variables, number_of_objectives=self.number_of_objectives + ) - new_solution.variables[0] = \ - [True if random.randint(0, 1) == 0 else False for _ in range( - self.number_of_bits)] + new_solution.variables[0] = [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] return new_solution def get_name(self): - return 'Knapsack' + return "Knapsack" diff --git a/jmetal/problem/singleobjective/test/test_knapsack.py b/jmetal/problem/singleobjective/test/test_knapsack.py index 7e82ae6b..62dd7f52 100644 --- a/jmetal/problem/singleobjective/test/test_knapsack.py +++ b/jmetal/problem/singleobjective/test/test_knapsack.py @@ -5,7 +5,6 @@ class KnapsackTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = Knapsack() self.assertIsNotNone(problem) @@ -36,14 +35,16 @@ def test_should_create_solution_a_valid_binary_solution(self) -> None: self.assertEqual(256, len(solution.variables[0])) def test_should_create_solution_from_file(self) -> None: - filename = 'resources/Knapsack_instances/KnapsackInstance_50_0_0.kp' - - data = "50\n13629\n 865 445\n395 324\n777 626\n912 656\n431 935\n42 210 \n266 990\n989 566\n524 489\n" \ - "498 454\n415 887\n941 534\n803 267\n850 64 \n311 825\n992 941\n489 562\n367 938\n598 15 \n914 96 \n" \ - "930 737\n224 861\n517 409\n143 728\n289 845\n144 804\n774 685\n98 641 \n634 2 \n819 627\n257 506\n" \ - "932 848\n546 889\n723 342\n830 250\n617 748\n924 334\n151 721\n318 892\n102 65 \n748 196\n76 940 \n" \ - "921 582\n871 228\n701 245\n339 823\n484 991\n574 146\n104 823\n363 557" - with mock.patch('jmetal.problem.singleobjective.knapsack.open', new=mock.mock_open(read_data=data)): + filename = "resources/Knapsack_instances/KnapsackInstance_50_0_0.kp" + + data = ( + "50\n13629\n 865 445\n395 324\n777 626\n912 656\n431 935\n42 210 \n266 990\n989 566\n524 489\n" + "498 454\n415 887\n941 534\n803 267\n850 64 \n311 825\n992 941\n489 562\n367 938\n598 15 \n914 96 \n" + "930 737\n224 861\n517 409\n143 728\n289 845\n144 804\n774 685\n98 641 \n634 2 \n819 627\n257 506\n" + "932 848\n546 889\n723 342\n830 250\n617 748\n924 334\n151 721\n318 892\n102 65 \n748 196\n76 940 \n" + "921 582\n871 228\n701 245\n339 823\n484 991\n574 146\n104 823\n363 557" + ) + with mock.patch("jmetal.problem.singleobjective.knapsack.open", new=mock.mock_open(read_data=data)): problem = Knapsack(from_file=True, filename=filename) self.assertEqual(1, problem.number_of_variables) self.assertEqual(1, problem.number_of_objectives) @@ -52,4 +53,4 @@ def test_should_create_solution_from_file(self) -> None: def test_should_get_name_return_the_right_name(self): problem = Knapsack() - self.assertEqual('Knapsack', problem.get_name()) + self.assertEqual("Knapsack", problem.get_name()) diff --git a/jmetal/problem/singleobjective/test/test_unconstrained.py b/jmetal/problem/singleobjective/test/test_unconstrained.py index 5f2ae81c..f1f2aa3e 100644 --- a/jmetal/problem/singleobjective/test/test_unconstrained.py +++ b/jmetal/problem/singleobjective/test/test_unconstrained.py @@ -4,7 +4,6 @@ class OneMaxTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self) -> None: problem = OneMax() self.assertIsNotNone(problem) @@ -41,7 +40,6 @@ def test_should_get_name_return_the_right_name(self): class SphereTestCases(unittest.TestCase): - def test_should_constructor_create_a_non_null_object(self): problem = Sphere(3) self.assertIsNotNone(problem) @@ -102,5 +100,5 @@ def test_should_get_name_return_the_right_name(self): self.assertEqual("Sphere", problem.get_name()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/problem/singleobjective/tsp.py b/jmetal/problem/singleobjective/tsp.py index bb2f47c5..444cf783 100644 --- a/jmetal/problem/singleobjective/tsp.py +++ b/jmetal/problem/singleobjective/tsp.py @@ -15,7 +15,7 @@ class TSP(PermutationProblem): - """ Class representing TSP Problem. """ + """Class representing TSP Problem.""" def __init__(self, instance: str = None): super(TSP, self).__init__() @@ -38,24 +38,24 @@ def __read_from_file(self, filename: str): """ if filename is None: - raise FileNotFoundError('Filename can not be None') + raise FileNotFoundError("Filename can not be None") with open(filename) as file: lines = file.readlines() data = [line.lstrip() for line in lines if line != ""] - dimension = re.compile(r'[^\d]+') + dimension = re.compile(r"[^\d]+") for item in data: - if item.startswith('DIMENSION'): - dimension = int(dimension.sub('', item)) + if item.startswith("DIMENSION"): + dimension = int(dimension.sub("", item)) break c = [-1.0] * (2 * dimension) for item in data: if item[0].isdigit(): - j, city_a, city_b = [int(x.strip()) for x in item.split(' ')] + j, city_a, city_b = [int(x.strip()) for x in item.split(" ")] c[2 * (j - 1)] = city_a c[2 * (j - 1) + 1] = city_b @@ -89,8 +89,9 @@ def evaluate(self, solution: PermutationSolution) -> PermutationSolution: return solution def create_solution(self) -> PermutationSolution: - new_solution = PermutationSolution(number_of_variables=self.number_of_variables, - number_of_objectives=self.number_of_objectives) + new_solution = PermutationSolution( + number_of_variables=self.number_of_variables, number_of_objectives=self.number_of_objectives + ) new_solution.variables = random.sample(range(self.number_of_variables), k=self.number_of_variables) return new_solution @@ -100,4 +101,4 @@ def number_of_cities(self): return self.number_of_variables def get_name(self): - return 'Symmetric TSP' + return "Symmetric TSP" diff --git a/jmetal/problem/singleobjective/unconstrained.py b/jmetal/problem/singleobjective/unconstrained.py index e68061ba..15f38f73 100644 --- a/jmetal/problem/singleobjective/unconstrained.py +++ b/jmetal/problem/singleobjective/unconstrained.py @@ -14,7 +14,6 @@ class OneMax(BinaryProblem): - def __init__(self, number_of_bits: int = 256): super(OneMax, self).__init__() self.number_of_bits = number_of_bits @@ -23,7 +22,7 @@ def __init__(self, number_of_bits: int = 256): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE] - self.obj_labels = ['Ones'] + self.obj_labels = ["Ones"] def evaluate(self, solution: BinarySolution) -> BinarySolution: counter_of_ones = 0 @@ -37,16 +36,14 @@ def evaluate(self, solution: BinarySolution) -> BinarySolution: def create_solution(self) -> BinarySolution: new_solution = BinarySolution(number_of_variables=1, number_of_objectives=1) - new_solution.variables[0] = \ - [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] + new_solution.variables[0] = [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] return new_solution def get_name(self) -> str: - return 'OneMax' + return "OneMax" class Sphere(FloatProblem): - def __init__(self, number_of_variables: int = 10): super(Sphere, self).__init__() self.number_of_objectives = 1 @@ -54,7 +51,7 @@ def __init__(self, number_of_variables: int = 10): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE] - self.obj_labels = ['f(x)'] + self.obj_labels = ["f(x)"] self.lower_bound = [-5.12 for _ in range(number_of_variables)] self.upper_bound = [5.12 for _ in range(number_of_variables)] @@ -72,11 +69,10 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self) -> str: - return 'Sphere' + return "Sphere" class Rastrigin(FloatProblem): - def __init__(self, number_of_variables: int = 10): super(Rastrigin, self).__init__() self.number_of_objectives = 1 @@ -84,7 +80,7 @@ def __init__(self, number_of_variables: int = 10): self.number_of_constraints = 0 self.obj_directions = [self.MINIMIZE] - self.obj_labels = ['f(x)'] + self.obj_labels = ["f(x)"] self.lower_bound = [-5.12 for _ in range(number_of_variables)] self.upper_bound = [5.12 for _ in range(number_of_variables)] @@ -105,13 +101,12 @@ def evaluate(self, solution: FloatSolution) -> FloatSolution: return solution def get_name(self) -> str: - return 'Rastrigin' + return "Rastrigin" class SubsetSum(BinaryProblem): - def __init__(self, C: int, W: list): - """ The goal is to find a subset S of W whose elements sum is closest to (without exceeding) C. + """The goal is to find a subset S of W whose elements sum is closest to (without exceeding) C. :param C: Large integer. :param W: Set of non-negative integers.""" @@ -125,7 +120,7 @@ def __init__(self, C: int, W: list): self.number_of_constraints = 0 self.obj_directions = [self.MAXIMIZE] - self.obj_labels = ['Sum'] + self.obj_labels = ["Sum"] def evaluate(self, solution: BinarySolution) -> BinarySolution: total_sum = 0.0 @@ -145,12 +140,12 @@ def evaluate(self, solution: BinarySolution) -> BinarySolution: return solution def create_solution(self) -> BinarySolution: - new_solution = BinarySolution(number_of_variables=self.number_of_variables, - number_of_objectives=self.number_of_objectives) - new_solution.variables[0] = \ - [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] + new_solution = BinarySolution( + number_of_variables=self.number_of_variables, number_of_objectives=self.number_of_objectives + ) + new_solution.variables[0] = [True if random.randint(0, 1) == 0 else False for _ in range(self.number_of_bits)] return new_solution def get_name(self) -> str: - return 'Subset Sum' + return "Subset Sum" diff --git a/jmetal/util/aggregative_function.py b/jmetal/util/aggregative_function.py index b8c85018..f6aba20a 100644 --- a/jmetal/util/aggregative_function.py +++ b/jmetal/util/aggregative_function.py @@ -12,7 +12,6 @@ class AggregativeFunction(ABC): - @abstractmethod def compute(self, vector: [], weight_vector: []) -> float: pass @@ -23,7 +22,6 @@ def update(self, vector: []) -> None: class WeightedSum(AggregativeFunction): - def compute(self, vector: [], weight_vector: []) -> float: return sum(map(lambda x, y: x * y, vector, weight_vector)) @@ -32,12 +30,11 @@ def update(self, vector: []) -> None: class Tschebycheff(AggregativeFunction): - def __init__(self, dimension: int): self.ideal_point = IdealPoint(dimension) def compute(self, vector: [], weight_vector: []) -> float: - max_fun = -1.0e+30 + max_fun = -1.0e30 for i in range(len(vector)): diff = abs(vector[i] - self.ideal_point.point[i]) diff --git a/jmetal/util/archive.py b/jmetal/util/archive.py index 9281f9c8..ccf12331 100644 --- a/jmetal/util/archive.py +++ b/jmetal/util/archive.py @@ -2,12 +2,16 @@ import random from abc import ABC, abstractmethod from threading import Lock -from typing import TypeVar, Generic, List +from typing import Generic, List, TypeVar -from jmetal.util.comparator import Comparator, DominanceComparator, SolutionAttributeComparator -from jmetal.util.density_estimator import DensityEstimator, CrowdingDistance +from jmetal.util.comparator import ( + Comparator, + DominanceComparator, + SolutionAttributeComparator, +) +from jmetal.util.density_estimator import CrowdingDistance, DensityEstimator -S = TypeVar('S') +S = TypeVar("S") """ .. module:: archive @@ -19,7 +23,6 @@ class Archive(Generic[S], ABC): - def __init__(self): self.solution_list: List[S] = [] @@ -38,11 +41,7 @@ def get_name(self) -> str: class BoundedArchive(Archive[S]): - - def __init__(self, - maximum_size: int, - comparator: Comparator[S] = None, - density_estimator: DensityEstimator = None): + def __init__(self, maximum_size: int, comparator: Comparator[S] = None, density_estimator: DensityEstimator = None): super(BoundedArchive, self).__init__() self.maximum_size = maximum_size self.comparator = comparator @@ -67,7 +66,7 @@ def add(self, solution: S) -> bool: def __find_worst_solution(self, solution_list: List[S]) -> S: if solution_list is None: raise Exception("The solution list is None") - elif len(solution_list) is 0: + elif len(solution_list) == 0: raise Exception("The solution list is empty") worst_solution = solution_list[0] @@ -82,7 +81,6 @@ def __find_worst_solution(self, solution_list: List[S]) -> S: class NonDominatedSolutionsArchive(Archive[S]): - def __init__(self, dominance_comparator: Comparator = DominanceComparator()): super(NonDominatedSolutionsArchive, self).__init__() self.comparator = dominance_comparator @@ -119,22 +117,22 @@ def add(self, solution: S) -> bool: class CrowdingDistanceArchive(BoundedArchive[S]): - - def __init__(self, - maximum_size: int): + def __init__(self, maximum_size: int): super(CrowdingDistanceArchive, self).__init__( maximum_size=maximum_size, comparator=SolutionAttributeComparator("crowding_distance", lowest_is_best=False), - density_estimator=CrowdingDistance()) + density_estimator=CrowdingDistance(), + ) class ArchiveWithReferencePoint(BoundedArchive[S]): - - def __init__(self, - maximum_size: int, - reference_point: List[float], - comparator: Comparator[S], - density_estimator: DensityEstimator): + def __init__( + self, + maximum_size: int, + reference_point: List[float], + comparator: Comparator[S], + density_estimator: DensityEstimator, + ): super(ArchiveWithReferencePoint, self).__init__(maximum_size, comparator, density_estimator) self.__reference_point = reference_point self.__comparator = comparator @@ -172,9 +170,9 @@ def add(self, solution: S) -> bool: def filter(self): # In case of having at least a solution which is non-dominated with the reference point, filter it if len(self.solution_list) > 1: - self.solution_list[:] = \ - [sol for sol in self.solution_list - if self.__dominance_test(sol.objectives, self.__reference_point) != 0] + self.solution_list[:] = [ + sol for sol in self.solution_list if self.__dominance_test(sol.objectives, self.__reference_point) != 0 + ] def update_reference_point(self, new_reference_point) -> None: with self.lock: @@ -212,12 +210,10 @@ def __dominance_test(self, vector1: List[float], vector2: List[float]) -> int: class CrowdingDistanceArchiveWithReferencePoint(ArchiveWithReferencePoint[S]): - - def __init__(self, - maximum_size: int, - reference_point: List[float]): + def __init__(self, maximum_size: int, reference_point: List[float]): super(CrowdingDistanceArchiveWithReferencePoint, self).__init__( maximum_size=maximum_size, reference_point=reference_point, comparator=SolutionAttributeComparator("crowding_distance", lowest_is_best=False), - density_estimator=CrowdingDistance()) + density_estimator=CrowdingDistance(), + ) diff --git a/jmetal/util/ckecking.py b/jmetal/util/ckecking.py index dd13a5b9..2ddcf41b 100644 --- a/jmetal/util/ckecking.py +++ b/jmetal/util/ckecking.py @@ -21,14 +21,21 @@ def __init__(self): class InvalidProbabilityValueException(RuntimeError): def __init__(self, value: float): super(InvalidProbabilityValueException, self).__init__( - "The parameter " + str(value) + " is not a valid probability value") + "The parameter " + str(value) + " is not a valid probability value" + ) class ValueOutOfRangeException(RuntimeError): def __init__(self, value: float, lowest_value: float, highest_value: float): super(ValueOutOfRangeException, self).__init__( - "The parameter " + str(value) + " is not in the range (" + str(lowest_value) + ", " + str( - highest_value) + ")") + "The parameter " + + str(value) + + " is not in the range (" + + str(lowest_value) + + ", " + + str(highest_value) + + ")" + ) class Check: diff --git a/jmetal/util/comparator.py b/jmetal/util/comparator.py index 38904db8..aae33528 100644 --- a/jmetal/util/comparator.py +++ b/jmetal/util/comparator.py @@ -1,22 +1,20 @@ import math from abc import ABC, abstractmethod -from typing import TypeVar, Generic +from typing import Generic, TypeVar from jmetal.core.solution import Solution from jmetal.util.constraint_handling import overall_constraint_violation_degree -S = TypeVar('S') +S = TypeVar("S") class Comparator(Generic[S], ABC): - @abstractmethod def compare(self, solution1: S, solution2: S) -> int: pass class EqualSolutionsComparator(Comparator): - def compare(self, solution1: Solution, solution2: Solution) -> int: if solution1 is None: return 1 @@ -51,7 +49,6 @@ def compare(self, solution1: Solution, solution2: Solution) -> int: class SolutionAttributeComparator(Comparator): - def __init__(self, key: str, lowest_is_best: bool = True): self.key = key self.lowest_is_best = lowest_is_best @@ -99,27 +96,23 @@ def compare(self, solution1: Solution, solution2: Solution) -> int: class RankingAndCrowdingDistanceComparator(Comparator): - def compare(self, solution1: Solution, solution2: Solution) -> int: - result = \ - SolutionAttributeComparator("dominance_ranking").compare(solution1, solution2) + result = SolutionAttributeComparator("dominance_ranking").compare(solution1, solution2) - if result is 0: - result = \ - SolutionAttributeComparator("crowding_distance", lowest_is_best=False).compare(solution1, solution2) + if result == 0: + result = SolutionAttributeComparator("crowding_distance", lowest_is_best=False).compare( + solution1, solution2 + ) return result class StrengthAndKNNDistanceComparator(Comparator): - def compare(self, solution1: Solution, solution2: Solution) -> int: - result = \ - SolutionAttributeComparator('dominance_ranking').compare(solution1, solution2) + result = SolutionAttributeComparator("dominance_ranking").compare(solution1, solution2) - if result is 0: - result = \ - SolutionAttributeComparator("knn_density", lowest_is_best=False).compare(solution1, solution2) + if result == 0: + result = SolutionAttributeComparator("knn_density", lowest_is_best=False).compare(solution1, solution2) return result @@ -146,7 +139,6 @@ def compare(self, solution1: Solution, solution2: Solution) -> int: class DominanceComparator(Comparator): - def __init__(self, constraint_comparator: Comparator = OverallConstraintViolationComparator()): self.constraint_comparator = constraint_comparator @@ -202,10 +194,11 @@ def dominance_test(vector1: [float], vector2: [float]) -> int: class GDominanceComparator(DominanceComparator): - - def __init__(self, - reference_point: (), - constraint_comparator: Comparator = SolutionAttributeComparator('overall_constraint_violation', False)): + def __init__( + self, + reference_point: (), + constraint_comparator: Comparator = SolutionAttributeComparator("overall_constraint_violation", False), + ): super(GDominanceComparator, self).__init__(constraint_comparator) self.reference_point = reference_point @@ -235,10 +228,11 @@ def __flag(self, solution: Solution): class EpsilonDominanceComparator(DominanceComparator): - - def __init__(self, - epsilon: float, - constraint_comparator: Comparator = SolutionAttributeComparator('overall_constraint_violation', False)): + def __init__( + self, + epsilon: float, + constraint_comparator: Comparator = SolutionAttributeComparator("overall_constraint_violation", False), + ): super(EpsilonDominanceComparator, self).__init__(constraint_comparator) self.epsilon = epsilon diff --git a/jmetal/util/density_estimator.py b/jmetal/util/density_estimator.py index fcbc45c3..d558f5aa 100644 --- a/jmetal/util/density_estimator.py +++ b/jmetal/util/density_estimator.py @@ -1,16 +1,16 @@ -import logging from abc import ABC, abstractmethod from functools import cmp_to_key -from typing import TypeVar, List +from typing import List, TypeVar import numpy from scipy.spatial.distance import euclidean -from jmetal.util.comparator import SolutionAttributeComparator, Comparator +from jmetal.logger import get_logger +from jmetal.util.comparator import Comparator, SolutionAttributeComparator -LOGGER = logging.getLogger('jmetal') +logger = get_logger(__name__) -S = TypeVar('S') +S = TypeVar("S") """ .. module:: density_estimator @@ -22,8 +22,7 @@ class DensityEstimator(List[S], ABC): - """This is the interface of any density estimator algorithm. - """ + """This is the interface of any density estimator algorithm.""" @abstractmethod def compute_density_estimator(self, solutions: List[S]) -> float: @@ -39,8 +38,7 @@ def get_comparator(cls) -> Comparator: class CrowdingDistance(DensityEstimator[List[S]]): - """This class implements a DensityEstimator based on the crowding distance of algorithm NSGA-II. - """ + """This class implements a DensityEstimator based on the crowding distance of algorithm NSGA-II.""" def compute_density_estimator(self, front: List[S]): """This function performs the computation of the crowding density estimation over the solution list. @@ -52,18 +50,18 @@ def compute_density_estimator(self, front: List[S]): """ size = len(front) - if size is 0: + if size == 0: return - elif size is 1: - front[0].attributes['crowding_distance'] = float("inf") + elif size == 1: + front[0].attributes["crowding_distance"] = float("inf") return - elif size is 2: - front[0].attributes['crowding_distance'] = float("inf") - front[1].attributes['crowding_distance'] = float("inf") + elif size == 2: + front[0].attributes["crowding_distance"] = float("inf") + front[1].attributes["crowding_distance"] = float("inf") return for i in range(len(front)): - front[i].attributes['crowding_distance'] = 0.0 + front[i].attributes["crowding_distance"] = 0.0 number_of_objectives = front[0].number_of_objectives @@ -74,20 +72,21 @@ def compute_density_estimator(self, front: List[S]): objective_maxn = front[len(front) - 1].objectives[i] # Set de crowding distance - front[0].attributes['crowding_distance'] = float('inf') - front[size - 1].attributes['crowding_distance'] = float('inf') + front[0].attributes["crowding_distance"] = float("inf") + front[size - 1].attributes["crowding_distance"] = float("inf") for j in range(1, size - 1): distance = front[j + 1].objectives[i] - front[j - 1].objectives[i] # Check if minimum and maximum are the same (in which case do nothing) if objective_maxn - objective_minn == 0: - pass; # LOGGER.warning('Minimum and maximum are the same!') + pass + # logger.warning('Minimum and maximum are the same!') else: distance = distance / (objective_maxn - objective_minn) - distance += front[j].attributes['crowding_distance'] - front[j].attributes['crowding_distance'] = distance + distance += front[j].attributes["crowding_distance"] + front[j].attributes["crowding_distance"] = distance def sort(self, solutions: List[S]) -> List[S]: solutions.sort(key=cmp_to_key(self.get_comparator().compare)) @@ -98,8 +97,7 @@ def get_comparator(cls) -> Comparator: class KNearestNeighborDensityEstimator(DensityEstimator[List[S]]): - """This class implements a density estimator based on the distance to the k-th nearest solution. - """ + """This class implements a density estimator based on the distance to the k-th nearest solution.""" def __init__(self, k: int = 1): super().__init__() @@ -119,15 +117,16 @@ def compute_density_estimator(self, solutions: List[S]): self.distance_matrix = numpy.zeros(shape=(solutions_size, solutions_size)) for i in range(solutions_size): for j in range(solutions_size): - self.distance_matrix[i, j] = self.distance_matrix[j, i] = euclidean(solutions[i].objectives, - solutions[j].objectives) + self.distance_matrix[i, j] = self.distance_matrix[j, i] = euclidean( + solutions[i].objectives, solutions[j].objectives + ) # Gets the k-nearest distance of all the solutions for i in range(solutions_size): distances = [] for j in range(solutions_size): distances.append(self.distance_matrix[i, j]) distances.sort() - solutions[i].attributes['knn_density'] = distances[self.k] + solutions[i].attributes["knn_density"] = distances[self.k] def sort(self, solutions: List[S]) -> List[S]: def compare(solution1, solution2): diff --git a/jmetal/util/distance.py b/jmetal/util/distance.py index 2829c371..63c84f84 100644 --- a/jmetal/util/distance.py +++ b/jmetal/util/distance.py @@ -13,32 +13,35 @@ class Distance(ABC): - @abstractmethod def get_distance(self, element1, element2) -> float: pass class EuclideanDistance(Distance): - def get_distance(self, list1: [], list2: []): return distance.euclidean(list1, list2) class CosineDistance(Distance): - def __init__(self, reference_point: []): self.reference_point = reference_point def get_distance(self, list1: [], list2: []): - total = sum(numpy.multiply([(x - r) for x, r in zip(list1, self.reference_point)], - [(y - r) for y, r in zip(list2, self.reference_point)])) - - a = distance.cosine([x - y for x, y in zip(list1, self.reference_point)], - [x - y for x, y in zip(list2, self.reference_point)]) - - b = total / (self.__sum_of_distances_to_reference_point(list1) * - self.__sum_of_distances_to_reference_point(list2)) + total = sum( + numpy.multiply( + [(x - r) for x, r in zip(list1, self.reference_point)], + [(y - r) for y, r in zip(list2, self.reference_point)], + ) + ) + + a = distance.cosine( + [x - y for x, y in zip(list1, self.reference_point)], [x - y for x, y in zip(list2, self.reference_point)] + ) + + b = total / ( + self.__sum_of_distances_to_reference_point(list1) * self.__sum_of_distances_to_reference_point(list2) + ) return b diff --git a/jmetal/util/evaluator.py b/jmetal/util/evaluator.py index 6566d64d..2628eb46 100644 --- a/jmetal/util/evaluator.py +++ b/jmetal/util/evaluator.py @@ -1,7 +1,7 @@ import functools from abc import ABC, abstractmethod -from multiprocessing.pool import ThreadPool, Pool -from typing import TypeVar, List, Generic +from multiprocessing.pool import Pool, ThreadPool +from typing import Generic, List, TypeVar try: import dask @@ -15,11 +15,10 @@ from jmetal.core.problem import Problem -S = TypeVar('S') +S = TypeVar("S") class Evaluator(Generic[S], ABC): - @abstractmethod def evaluate(self, solution_list: List[S], problem: Problem) -> List[S]: pass @@ -30,7 +29,6 @@ def evaluate_solution(solution: S, problem: Problem) -> None: class SequentialEvaluator(Evaluator[S]): - def evaluate(self, solution_list: List[S], problem: Problem) -> List[S]: for solution in solution_list: Evaluator.evaluate_solution(solution, problem) @@ -39,7 +37,6 @@ def evaluate(self, solution_list: List[S], problem: Problem) -> List[S]: class MapEvaluator(Evaluator[S]): - def __init__(self, processes: int = None): self.pool = ThreadPool(processes) @@ -69,9 +66,7 @@ def __init__(self, processes: int = 8): def evaluate(self, solution_list: List[S], problem: Problem) -> List[S]: solutions_to_evaluate = self.spark_context.parallelize(solution_list) - return solutions_to_evaluate \ - .map(lambda s: problem.evaluate(s)) \ - .collect() + return solutions_to_evaluate.map(lambda s: problem.evaluate(s)).collect() def evaluate_solution(solution, problem): @@ -80,11 +75,13 @@ def evaluate_solution(solution, problem): class DaskEvaluator(Evaluator[S]): - def __init__(self, scheduler='processes'): + def __init__(self, scheduler="processes"): self.scheduler = scheduler def evaluate(self, solution_list: List[S], problem: Problem) -> List[S]: with dask.config.set(scheduler=self.scheduler): - return list(dask.compute(*[ - dask.delayed(evaluate_solution)(solution=solution, problem=problem) for solution in solution_list - ])) + return list( + dask.compute( + *[dask.delayed(evaluate_solution)(solution=solution, problem=problem) for solution in solution_list] + ) + ) diff --git a/jmetal/util/generator.py b/jmetal/util/generator.py index f1a29965..078b91ce 100644 --- a/jmetal/util/generator.py +++ b/jmetal/util/generator.py @@ -1,11 +1,11 @@ import copy from abc import ABC, abstractmethod -from typing import TypeVar, Generic, List +from typing import Generic, List, TypeVar from jmetal.core.problem import Problem from jmetal.core.solution import Solution -R = TypeVar('R') +R = TypeVar("R") """ .. module:: generator @@ -17,26 +17,20 @@ class Generator(Generic[R], ABC): - @abstractmethod def new(self, problem: Problem) -> R: pass class RandomGenerator(Generator): - def new(self, problem: Problem): return problem.create_solution() class InjectorGenerator(Generator): - def __init__(self, solutions: List[Solution]): super(InjectorGenerator, self).__init__() - self.population = [] - - for solution in solutions: - self.population.append(copy.deepcopy(solution)) + self.population = copy.deepcopy(solutions) def new(self, problem: Problem): if len(self.population) > 0: diff --git a/jmetal/util/neighborhood.py b/jmetal/util/neighborhood.py index 3ba8ae2a..09dffc45 100644 --- a/jmetal/util/neighborhood.py +++ b/jmetal/util/neighborhood.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod from pathlib import Path -from typing import TypeVar, Generic, List +from typing import Generic, List, TypeVar import numpy @@ -16,23 +16,23 @@ .. moduleauthor:: Antonio J. Nebro """ -S = TypeVar('S') +S = TypeVar("S") class Neighborhood(Generic[S], ABC): - @abstractmethod def get_neighbors(self, index: int, solution_list: List[S]) -> List[S]: pass class WeightNeighborhood(Neighborhood[Solution], ABC): - - def __init__(self, - number_of_weight_vectors: int, - neighborhood_size: int, - weight_vector_size: int = 2, - weights_path: str = None): + def __init__( + self, + number_of_weight_vectors: int, + neighborhood_size: int, + weight_vector_size: int = 2, + weights_path: str = None, + ): self.number_of_weight_vectors = number_of_weight_vectors self.neighborhood_size = neighborhood_size self.weight_vector_size = weight_vector_size @@ -43,19 +43,21 @@ def __init__(self, class WeightVectorNeighborhood(WeightNeighborhood): - - def __init__(self, - number_of_weight_vectors: int, - neighborhood_size: int, - weight_vector_size: int = 2, - weights_path: str = None): - super(WeightVectorNeighborhood, self).__init__(number_of_weight_vectors, neighborhood_size, weight_vector_size, - weights_path) + def __init__( + self, + number_of_weight_vectors: int, + neighborhood_size: int, + weight_vector_size: int = 2, + weights_path: str = None, + ): + super(WeightVectorNeighborhood, self).__init__( + number_of_weight_vectors, neighborhood_size, weight_vector_size, weights_path + ) self.__initialize_uniform_weight(weight_vector_size, number_of_weight_vectors) self.__initialize_neighborhood() def __initialize_uniform_weight(self, weight_vector_size: int, number_of_weight_vectors: int) -> None: - """ Precomputed weights from + """Precomputed weights from * Zhang, Multiobjective Optimization Problems With Complicated Pareto Sets, MOEA/D and NSGA-II @@ -69,8 +71,8 @@ def __initialize_uniform_weight(self, weight_vector_size: int, number_of_weight_ self.weight_vectors[i, 0] = v self.weight_vectors[i, 1] = 1 - v else: - file_name = 'W{}D_{}.dat'.format(weight_vector_size, number_of_weight_vectors) - file_path = self.weights_path + '/' + file_name + file_name = "W{}D_{}.dat".format(weight_vector_size, number_of_weight_vectors) + file_path = self.weights_path + "/" + file_name if Path(file_path).is_file(): with open(file_path) as file: @@ -78,7 +80,7 @@ def __initialize_uniform_weight(self, weight_vector_size: int, number_of_weight_ vector = [float(x) for x in line.split()] self.weight_vectors[index][:] = vector else: - raise FileNotFoundError('Failed to initialize weights: {} not found'.format(file_path)) + raise FileNotFoundError("Failed to initialize weights: {} not found".format(file_path)) def __initialize_neighborhood(self) -> None: distance = numpy.zeros((len(self.weight_vectors), len(self.weight_vectors))) @@ -88,13 +90,13 @@ def __initialize_neighborhood(self) -> None: distance[i][j] = numpy.linalg.norm(self.weight_vectors[i] - self.weight_vectors[j]) indexes = numpy.argsort(distance[i, :]) - self.neighborhood[i, :] = indexes[0:self.neighborhood_size] + self.neighborhood[i, :] = indexes[0 : self.neighborhood_size] def get_neighbors(self, index: int, solution_list: List[Solution]) -> List[Solution]: neighbors_indexes = self.neighborhood[index] if any(i > len(solution_list) for i in neighbors_indexes): - raise IndexError('Neighbor index out of range') + raise IndexError("Neighbor index out of range") return [solution_list[i] for i in neighbors_indexes] @@ -115,7 +117,7 @@ def __init__(self, rows: int, columns: int, neighborhood: [[]]): self.__create_mesh() def __create_mesh(self): - """ Example: + """Example: if rows = 5, and columns=3, we need to fill the mesh as follows ---------- |00-01-02| @@ -194,23 +196,23 @@ def get_neighbors(self, index: int, solution_list: List[Solution]) -> List[Solut class C9(TwoDimensionalMesh): """ - Class defining an C9 neighborhood of a solution belonging to a list of solutions which is - structured as a bi-dimensional mesh. The neighbors are those solutions that are in 1-hop distance - - Shape: - * * * - * o * - * * * - - Topology: - north = {-1, 0} - south = { 1 , 0} - east = { 0 , 1} - west = { 0 ,-1} - north_east = {-1, 1} - north_west = {-1, -1} - south_east = { 1 , 1} - south_west = { 1 ,-1} + Class defining an C9 neighborhood of a solution belonging to a list of solutions which is + structured as a bi-dimensional mesh. The neighbors are those solutions that are in 1-hop distance + + Shape: + * * * + * o * + * * * + + Topology: + north = {-1, 0} + south = { 1 , 0} + east = { 0 , 1} + west = { 0 ,-1} + north_east = {-1, 1} + north_west = {-1, -1} + south_east = { 1 , 1} + south_west = { 1 ,-1} """ def __init__(self, rows: int, columns: int): diff --git a/jmetal/util/observable.py b/jmetal/util/observable.py index 15dcb73d..c297bfca 100644 --- a/jmetal/util/observable.py +++ b/jmetal/util/observable.py @@ -4,7 +4,7 @@ from jmetal.core.observer import Observable, Observer -LOGGER = logging.getLogger('jmetal') +LOGGER = logging.getLogger("jmetal") """ .. module:: observable @@ -15,7 +15,6 @@ class DefaultObservable(Observable): - def __init__(self): self.observers = [] diff --git a/jmetal/util/observer.py b/jmetal/util/observer.py index d30c0632..1c88d945 100644 --- a/jmetal/util/observer.py +++ b/jmetal/util/observer.py @@ -3,17 +3,18 @@ from pathlib import Path from typing import List, TypeVar +import numpy as np from tqdm import tqdm from jmetal.core.observer import Observer from jmetal.core.problem import DynamicProblem from jmetal.core.quality_indicator import InvertedGenerationalDistance -from jmetal.lab.visualization import StreamingPlot, Plot +from jmetal.lab.visualization import Plot, StreamingPlot from jmetal.util.solution import print_function_values_to_file -S = TypeVar('S') +S = TypeVar("S") -LOGGER = logging.getLogger('jmetal') +LOGGER = logging.getLogger("jmetal") """ .. module:: observer @@ -25,9 +26,8 @@ class ProgressBarObserver(Observer): - def __init__(self, max: int) -> None: - """ Show a smart progress meter with the number of evaluations and computing time. + """Show a smart progress meter with the number of evaluations and computing time. :param max: Number of expected iterations. """ @@ -37,9 +37,9 @@ def __init__(self, max: int) -> None: def update(self, *args, **kwargs): if not self.progress_bar: - self.progress_bar = tqdm(total=self._max, ascii=True, desc='Progress') + self.progress_bar = tqdm(total=self._max, ascii=True, desc="Progress") - evaluations = kwargs['EVALUATIONS'] + evaluations = kwargs["EVALUATIONS"] self.progress_bar.update(evaluations - self.progress) self.progress = evaluations @@ -49,17 +49,16 @@ def update(self, *args, **kwargs): class BasicObserver(Observer): + def __init__(self, frequency: int = 1) -> None: + """Show the number of evaluations, best fitness and computing time. - def __init__(self, frequency: float = 1.0) -> None: - """ Show the number of evaluations, best fitness and computing time. - - :param frequency: Display frequency. """ + :param frequency: Display frequency.""" self.display_frequency = frequency def update(self, *args, **kwargs): - computing_time = kwargs['COMPUTING_TIME'] - evaluations = kwargs['EVALUATIONS'] - solutions = kwargs['SOLUTIONS'] + computing_time = kwargs["COMPUTING_TIME"] + evaluations = kwargs["EVALUATIONS"] + solutions = kwargs["SOLUTIONS"] if (evaluations % self.display_frequency) == 0 and solutions: if type(solutions) == list: @@ -68,23 +67,20 @@ def update(self, *args, **kwargs): fitness = solutions.objectives LOGGER.info( - 'Evaluations: {} \n Best fitness: {} \n Computing time: {}'.format( - evaluations, fitness, computing_time - ) + "Evaluations: {} \n Best fitness: {} \n Computing time: {}".format(evaluations, fitness, computing_time) ) class PrintObjectivesObserver(Observer): + def __init__(self, frequency: int = 1) -> None: + """Show the number of evaluations, best fitness and computing time. - def __init__(self, frequency: float = 1.0) -> None: - """ Show the number of evaluations, best fitness and computing time. - - :param frequency: Display frequency. """ + :param frequency: Display frequency.""" self.display_frequency = frequency def update(self, *args, **kwargs): - evaluations = kwargs['EVALUATIONS'] - solutions = kwargs['SOLUTIONS'] + evaluations = kwargs["EVALUATIONS"] + solutions = kwargs["SOLUTIONS"] if (evaluations % self.display_frequency) == 0 and solutions: if type(solutions) == list: @@ -92,105 +88,101 @@ def update(self, *args, **kwargs): else: fitness = solutions.objectives - LOGGER.info( - 'Evaluations: {}. fitness: {}'.format( - evaluations, fitness - ) - ) + LOGGER.info("Evaluations: {}. fitness: {}".format(evaluations, fitness)) class WriteFrontToFileObserver(Observer): - def __init__(self, output_directory: str) -> None: - """ Write function values of the front into files. + """Write function values of the front into files. - :param output_directory: Output directory. Each front will be saved on a file `FUN.x`. """ + :param output_directory: Output directory. Each front will be saved on a file `FUN.x`.""" self.counter = 0 self.directory = output_directory if Path(self.directory).is_dir(): - LOGGER.warning('Directory {} exists. Removing contents.'.format(self.directory)) + LOGGER.warning("Directory {} exists. Removing contents.".format(self.directory)) for file in os.listdir(self.directory): - os.remove('{0}/{1}'.format(self.directory, file)) + os.remove("{0}/{1}".format(self.directory, file)) else: - LOGGER.warning('Directory {} does not exist. Creating it.'.format(self.directory)) + LOGGER.warning("Directory {} does not exist. Creating it.".format(self.directory)) Path(self.directory).mkdir(parents=True) def update(self, *args, **kwargs): - problem = kwargs['PROBLEM'] - solutions = kwargs['SOLUTIONS'] + problem = kwargs["PROBLEM"] + solutions = kwargs["SOLUTIONS"] if solutions: if isinstance(problem, DynamicProblem): - termination_criterion_is_met = kwargs.get('TERMINATION_CRITERIA_IS_MET', None) + termination_criterion_is_met = kwargs.get("TERMINATION_CRITERIA_IS_MET", None) if termination_criterion_is_met: - print_function_values_to_file(solutions, '{}/FUN.{}'.format(self.directory, self.counter)) + print_function_values_to_file(solutions, "{}/FUN.{}".format(self.directory, self.counter)) self.counter += 1 else: - print_function_values_to_file(solutions, '{}/FUN.{}'.format(self.directory, self.counter)) + print_function_values_to_file(solutions, "{}/FUN.{}".format(self.directory, self.counter)) self.counter += 1 class PlotFrontToFileObserver(Observer): - def __init__(self, output_directory: str, step: int = 100, **kwargs) -> None: - """ Plot and save Pareto front approximations into files. + """Plot and save Pareto front approximations into files. :param output_directory: Output directory. """ self.directory = output_directory - self.plot_front = Plot(title='Pareto front approximation', **kwargs) + self.plot_front = Plot(title="Pareto front approximation", **kwargs) self.last_front = [] self.fronts = [] self.counter = 0 self.step = step if Path(self.directory).is_dir(): - LOGGER.warning('Directory {} exists. Removing contents.'.format(self.directory)) + LOGGER.warning("Directory {} exists. Removing contents.".format(self.directory)) for file in os.listdir(self.directory): - os.remove('{0}/{1}'.format(self.directory, file)) + os.remove("{0}/{1}".format(self.directory, file)) else: - LOGGER.warning('Directory {} does not exist. Creating it.'.format(self.directory)) + LOGGER.warning("Directory {} does not exist. Creating it.".format(self.directory)) Path(self.directory).mkdir(parents=True) def update(self, *args, **kwargs): - problem = kwargs['PROBLEM'] - solutions = kwargs['SOLUTIONS'] - evaluations = kwargs['EVALUATIONS'] + problem = kwargs["PROBLEM"] + solutions = kwargs["SOLUTIONS"] + evaluations = kwargs["EVALUATIONS"] if solutions: if (evaluations % self.step) == 0: if isinstance(problem, DynamicProblem): - termination_criterion_is_met = kwargs.get('TERMINATION_CRITERIA_IS_MET', None) + termination_criterion_is_met = kwargs.get("TERMINATION_CRITERIA_IS_MET", None) if termination_criterion_is_met: if self.counter > 0: - igd = InvertedGenerationalDistance(self.last_front) - igd_value = igd.compute(solutions) + igd = InvertedGenerationalDistance(np.array([s.objectives for s in self.last_front])) + igd_value = igd.compute(np.array([s.objectives for s in solutions])) else: igd_value = 1 if igd_value > 0.005: self.fronts += solutions - self.plot_front.plot([self.fronts], - label=problem.get_name(), - filename=f'{self.directory}/front-{evaluations}') + self.plot_front.plot( + [self.fronts], + label=problem.get_name(), + filename=f"{self.directory}/front-{evaluations}", + ) self.counter += 1 self.last_front = solutions else: - self.plot_front.plot([solutions], - label=f'{evaluations} evaluations', - filename=f'{self.directory}/front-{evaluations}') + self.plot_front.plot( + [solutions], + label=f"{evaluations} evaluations", + filename=f"{self.directory}/front-{evaluations}", + ) self.counter += 1 class VisualizerObserver(Observer): - - def __init__(self, - reference_front: List[S] = None, - reference_point: list = None, - display_frequency: int = 1) -> None: + def __init__( + self, reference_front: List[S] = None, reference_point: list = None, display_frequency: int = 1 + ) -> None: self.figure = None self.display_frequency = display_frequency @@ -198,18 +190,17 @@ def __init__(self, self.reference_front = reference_front def update(self, *args, **kwargs): - evaluations = kwargs['EVALUATIONS'] - solutions = kwargs['SOLUTIONS'] + evaluations = kwargs["EVALUATIONS"] + solutions = kwargs["SOLUTIONS"] if solutions: if self.figure is None: - self.figure = StreamingPlot(reference_point=self.reference_point, - reference_front=self.reference_front) + self.figure = StreamingPlot(reference_point=self.reference_point, reference_front=self.reference_front) self.figure.plot(solutions) if (evaluations % self.display_frequency) == 0: # check if reference point has changed - reference_point = kwargs.get('REFERENCE_POINT', None) + reference_point = kwargs.get("REFERENCE_POINT", None) if reference_point: self.reference_point = reference_point @@ -217,4 +208,4 @@ def update(self, *args, **kwargs): else: self.figure.update(solutions) - self.figure.ax.set_title('Eval: {}'.format(evaluations), fontsize=13) + self.figure.ax.set_title("Eval: {}".format(evaluations), fontsize=13) diff --git a/jmetal/util/point.py b/jmetal/util/point.py index 9476b8b8..14e2aa9b 100644 --- a/jmetal/util/point.py +++ b/jmetal/util/point.py @@ -10,17 +10,14 @@ class Point(ABC): - @abstractmethod def update(self, vector: []) -> None: pass class IdealPoint(Point): - def __init__(self, dimension: int): self.point = dimension * [float("inf")] def update(self, vector: []) -> None: self.point = [y if x > y else x for x, y in zip(self.point, vector)] - diff --git a/jmetal/util/ranking.py b/jmetal/util/ranking.py index 81fa6555..d81397ce 100644 --- a/jmetal/util/ranking.py +++ b/jmetal/util/ranking.py @@ -1,13 +1,16 @@ from abc import ABC, abstractmethod -from typing import TypeVar, List +from typing import List, TypeVar -from jmetal.util.comparator import DominanceComparator, Comparator, SolutionAttributeComparator +from jmetal.util.comparator import ( + Comparator, + DominanceComparator, + SolutionAttributeComparator, +) -S = TypeVar('S') +S = TypeVar("S") class Ranking(List[S], ABC): - def __init__(self, comparator: Comparator = DominanceComparator()): super(Ranking, self).__init__() self.number_of_comparisons = 0 @@ -23,7 +26,7 @@ def get_nondominated(self): def get_subfront(self, rank: int): if rank >= len(self.ranked_sublists): - raise Exception('Invalid rank: {0}. Max rank: {1}'.format(rank, len(self.ranked_sublists) - 1)) + raise Exception("Invalid rank: {0}. Max rank: {1}".format(rank, len(self.ranked_sublists) - 1)) return self.ranked_sublists[rank] def get_number_of_subfronts(self): @@ -35,13 +38,13 @@ def get_comparator(cls) -> Comparator: class FastNonDominatedRanking(Ranking[List[S]]): - """ Class implementing the non-dominated ranking of NSGA-II proposed by Deb et al., see [Deb2002]_ """ + """Class implementing the non-dominated ranking of NSGA-II proposed by Deb et al., see [Deb2002]_""" def __init__(self, comparator: Comparator = DominanceComparator()): super(FastNonDominatedRanking, self).__init__(comparator) def compute_ranking(self, solutions: List[S], k: int = None): - """ Compute ranking of solutions. + """Compute ranking of solutions. :param solutions: Solution list. :param k: Number of individuals. @@ -63,14 +66,14 @@ def compute_ranking(self, solutions: List[S], k: int = None): if dominance_test_result == -1: ith_dominated[p].append(q) dominating_ith[q] += 1 - elif dominance_test_result is 1: + elif dominance_test_result == 1: ith_dominated[q].append(p) dominating_ith[p] += 1 for i in range(len(solutions)): - if dominating_ith[i] is 0: + if dominating_ith[i] == 0: front[0].append(i) - solutions[i].attributes['dominance_ranking'] = 0 + solutions[i].attributes["dominance_ranking"] = 0 i = 0 while len(front[i]) != 0: @@ -79,9 +82,9 @@ def compute_ranking(self, solutions: List[S], k: int = None): if p <= len(ith_dominated): for q in ith_dominated[p]: dominating_ith[q] -= 1 - if dominating_ith[q] is 0: + if dominating_ith[q] == 0: front[i].append(q) - solutions[q].attributes['dominance_ranking'] = i + solutions[q].attributes["dominance_ranking"] = i self.ranked_sublists = [[]] * i for j in range(i): @@ -95,18 +98,18 @@ def compute_ranking(self, solutions: List[S], k: int = None): for i, front in enumerate(self.ranked_sublists): count += len(front) if count >= k: - self.ranked_sublists = self.ranked_sublists[:i + 1] + self.ranked_sublists = self.ranked_sublists[: i + 1] break return self.ranked_sublists @classmethod def get_comparator(cls) -> Comparator: - return SolutionAttributeComparator('dominance_ranking') + return SolutionAttributeComparator("dominance_ranking") class StrengthRanking(Ranking[List[S]]): - """ Class implementing a ranking scheme based on the strength ranking used in SPEA2. """ + """Class implementing a ranking scheme based on the strength ranking used in SPEA2.""" def __init__(self, comparator: Comparator = DominanceComparator()): super(StrengthRanking, self).__init__(comparator) @@ -136,7 +139,7 @@ def compute_ranking(self, solutions: List[S], k: int = None): max_fitness_value: int = 0 for i in range(len(solutions)): - solutions[i].attributes['strength_ranking'] = raw_fitness[i] + solutions[i].attributes["strength_ranking"] = raw_fitness[i] if raw_fitness[i] > max_fitness_value: max_fitness_value = raw_fitness[i] @@ -145,7 +148,7 @@ def compute_ranking(self, solutions: List[S], k: int = None): # Assign each solution to its corresponding front for solution in solutions: - self.ranked_sublists[int(solution.attributes['strength_ranking'])].append(solution) + self.ranked_sublists[int(solution.attributes["strength_ranking"])].append(solution) # Remove empty fronts counter = 0 @@ -159,4 +162,4 @@ def compute_ranking(self, solutions: List[S], k: int = None): @classmethod def get_comparator(cls) -> Comparator: - return SolutionAttributeComparator('strength_ranking') + return SolutionAttributeComparator("strength_ranking") diff --git a/jmetal/util/replacement.py b/jmetal/util/replacement.py index 3b50fca2..fd2c6b3c 100644 --- a/jmetal/util/replacement.py +++ b/jmetal/util/replacement.py @@ -1,10 +1,10 @@ from enum import Enum -from typing import TypeVar, List +from typing import List, TypeVar from jmetal.util.density_estimator import DensityEstimator from jmetal.util.ranking import Ranking -S = TypeVar('S') +S = TypeVar("S") class RemovalPolicyType(Enum): @@ -12,10 +12,10 @@ class RemovalPolicyType(Enum): ONE_SHOT = 2 -class RankingAndDensityEstimatorReplacement(): - - def __init__(self, ranking: Ranking, density_estimator: DensityEstimator, - removal_policy=RemovalPolicyType.ONE_SHOT): +class RankingAndDensityEstimatorReplacement: + def __init__( + self, ranking: Ranking, density_estimator: DensityEstimator, removal_policy=RemovalPolicyType.ONE_SHOT + ): self.ranking = ranking self.density_estimator = density_estimator self.removal_policy = removal_policy @@ -39,8 +39,9 @@ def sequential_truncation(self, ranking_id: int, size_of_the_result_list: int) - if len(current_ranked_solutions) < size_of_the_result_list: result_list.extend(self.ranking.get_subfront(ranking_id)) - result_list.extend(self.sequential_truncation(ranking_id + 1, size_of_the_result_list - len( - current_ranked_solutions))) + result_list.extend( + self.sequential_truncation(ranking_id + 1, size_of_the_result_list - len(current_ranked_solutions)) + ) else: for solution in current_ranked_solutions: result_list.append(solution) @@ -61,8 +62,9 @@ def one_shot_truncation(self, ranking_id: int, size_of_the_result_list: int) -> if len(current_ranked_solutions) < size_of_the_result_list: result_list.extend(self.ranking.get_subfront(ranking_id)) - result_list.extend(self.one_shot_truncation(ranking_id + 1, size_of_the_result_list - len( - current_ranked_solutions))) + result_list.extend( + self.one_shot_truncation(ranking_id + 1, size_of_the_result_list - len(current_ranked_solutions)) + ) else: self.density_estimator.sort(current_ranked_solutions) i = 0 diff --git a/jmetal/util/solution.py b/jmetal/util/solution.py index 93dd171c..56cef665 100644 --- a/jmetal/util/solution.py +++ b/jmetal/util/solution.py @@ -4,9 +4,9 @@ from typing import List from jmetal.core.solution import FloatSolution, Solution -from jmetal.util.archive import NonDominatedSolutionsArchive, Archive +from jmetal.util.archive import Archive, NonDominatedSolutionsArchive -LOGGER = logging.getLogger('jmetal') +logger = logging.getLogger(__name__) """ @@ -28,7 +28,7 @@ def get_non_dominated_solutions(solutions: List[Solution]) -> List[Solution]: def read_solutions(filename: str) -> List[FloatSolution]: - """ Reads a reference front from a file. + """Reads a reference front from a file. :param filename: File path where the front is located. """ @@ -44,13 +44,13 @@ def read_solutions(filename: str) -> List[FloatSolution]: front.append(solution) else: - LOGGER.warning('Reference front file was not found at {}'.format(filename)) + logger.warning("Reference front file was not found at {}".format(filename)) return front def print_variables_to_file(solutions, filename: str): - LOGGER.info('Output file (variables): ' + filename) + logger.info("Output file (variables): " + filename) try: os.makedirs(os.path.dirname(filename), exist_ok=True) @@ -60,7 +60,7 @@ def print_variables_to_file(solutions, filename: str): if type(solutions) is not list: solutions = [solutions] - with open(filename, 'w') as of: + with open(filename, "w") as of: for solution in solutions: for variables in solution.variables: of.write(str(variables) + " ") @@ -76,7 +76,7 @@ def print_variables_to_screen(solutions): def print_function_values_to_file(solutions, filename: str): - LOGGER.info('Output file (function values): ' + filename) + logger.info("Output file (function values): " + filename) try: os.makedirs(os.path.dirname(filename), exist_ok=True) @@ -86,11 +86,11 @@ def print_function_values_to_file(solutions, filename: str): if type(solutions) is not list: solutions = [solutions] - with open(filename, 'w') as of: + with open(filename, "w") as of: for solution in solutions: for function_value in solution.objectives: - of.write(str(function_value) + ' ') - of.write('\n') + of.write(str(function_value) + " ") + of.write("\n") def print_function_values_to_screen(solutions): @@ -98,6 +98,6 @@ def print_function_values_to_screen(solutions): solutions = [solutions] for solution in solutions: - print(str(solutions.index(solution)) + ": ", sep=' ', end='', flush=True) - print(solution.objectives, sep=' ', end='', flush=True) + print(str(solutions.index(solution)) + ": ", sep=" ", end="", flush=True) + print(solution.objectives, sep=" ", end="", flush=True) print() diff --git a/jmetal/util/termination_criterion.py b/jmetal/util/termination_criterion.py index b2be1cdf..6dabd89e 100644 --- a/jmetal/util/termination_criterion.py +++ b/jmetal/util/termination_criterion.py @@ -14,7 +14,6 @@ class TerminationCriterion(Observer, ABC): - @abstractmethod def update(self, *args, **kwargs): pass @@ -26,14 +25,13 @@ def is_met(self): class StoppingByEvaluations(TerminationCriterion): - def __init__(self, max_evaluations: int): super(StoppingByEvaluations, self).__init__() self.max_evaluations = max_evaluations self.evaluations = 0 def update(self, *args, **kwargs): - self.evaluations = kwargs['EVALUATIONS'] + self.evaluations = kwargs["EVALUATIONS"] @property def is_met(self): @@ -41,14 +39,13 @@ def is_met(self): class StoppingByTime(TerminationCriterion): - def __init__(self, max_seconds: int): super(StoppingByTime, self).__init__() self.max_seconds = max_seconds self.seconds = 0.0 def update(self, *args, **kwargs): - self.seconds = kwargs['COMPUTING_TIME'] + self.seconds = kwargs["COMPUTING_TIME"] @property def is_met(self): @@ -56,12 +53,11 @@ def is_met(self): def key_has_been_pressed(stopping_by_keyboard): - input('PRESS ANY KEY + ENTER: ') + input("PRESS ANY KEY + ENTER: ") stopping_by_keyboard.key_pressed = True class StoppingByKeyboard(TerminationCriterion): - def __init__(self): super(StoppingByKeyboard, self).__init__() self.key_pressed = False @@ -77,7 +73,6 @@ def is_met(self): class StoppingByQualityIndicator(TerminationCriterion): - def __init__(self, quality_indicator: QualityIndicator, expected_value: float, degree: float): super(StoppingByQualityIndicator, self).__init__() self.quality_indicator = quality_indicator @@ -86,7 +81,7 @@ def __init__(self, quality_indicator: QualityIndicator, expected_value: float, d self.value = 0.0 def update(self, *args, **kwargs): - solutions = kwargs['SOLUTIONS'] + solutions = kwargs["SOLUTIONS"] if solutions: self.value = self.quality_indicator.compute(solutions) diff --git a/jmetal/util/test/test_aggregativefunction.py b/jmetal/util/test/test_aggregativefunction.py index a90804f8..6b6d85b3 100644 --- a/jmetal/util/test/test_aggregativefunction.py +++ b/jmetal/util/test/test_aggregativefunction.py @@ -4,7 +4,6 @@ class WeightedSumTestCases(unittest.TestCase): - def test_should_aggregative_sum_work_properly_with_2D_vectors(self) -> None: aggregative_function = WeightedSum() @@ -13,5 +12,5 @@ def test_should_aggregative_sum_work_properly_with_2D_vectors(self) -> None: self.assertEqual(1.5 / 2.0 + 2.9 / 2.0, aggregative_function.compute([1.5, 2.9], [0.5, 0.5])) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_archive.py b/jmetal/util/test/test_archive.py index 8fb1bf97..fce451f7 100644 --- a/jmetal/util/test/test_archive.py +++ b/jmetal/util/test/test_archive.py @@ -1,12 +1,16 @@ import unittest from jmetal.core.solution import Solution -from jmetal.util.archive import NonDominatedSolutionsArchive, BoundedArchive, CrowdingDistanceArchive, Archive +from jmetal.util.archive import ( + Archive, + BoundedArchive, + CrowdingDistanceArchive, + NonDominatedSolutionsArchive, +) class ArchiveTestCases(unittest.TestCase): class DummyArchive(Archive): - def add(self, solution) -> bool: pass @@ -21,7 +25,6 @@ def test_should_constructor_create_an_empty_list(self): class BoundedArchiveTestCases(unittest.TestCase): - def setUp(self): self.archive = BoundedArchive(5) @@ -33,7 +36,6 @@ def test_should_constructor_set_the_max_size(self): class NonDominatedSolutionListArchiveTestCases(unittest.TestCase): - def setUp(self): self.archive = NonDominatedSolutionsArchive() @@ -70,8 +72,7 @@ def test_should_adding_two_solutions_work_properly_if_both_are_non_dominated(sel self.archive.add(solution2) self.assertEqual(2, self.archive.size()) - self.assertTrue(solution1 in self.archive.solution_list and - solution2 in self.archive.solution_list) + self.assertTrue(solution1 in self.archive.solution_list and solution2 in self.archive.solution_list) def test_should_adding_four_solutions_work_properly_if_one_dominates_the_others(self): solution1 = Solution(1, 2) @@ -110,12 +111,10 @@ def test_should_adding_three_solutions_work_properly_if_two_of_them_are_equal(se self.assertEqual(2, self.archive.size()) self.assertFalse(result) - self.assertTrue(solution1 in self.archive.solution_list - or solution3 in self.archive.solution_list) + self.assertTrue(solution1 in self.archive.solution_list or solution3 in self.archive.solution_list) class CrowdingDistanceArchiveTestCases(unittest.TestCase): - def setUp(self): self.archive = CrowdingDistanceArchive[Solution](5) @@ -136,8 +135,7 @@ def test_should_add_a_solution_when_the_archive_is_empty_work_properly(self): self.assertEqual(solution, self.archive.get(0)) def test_should_add_work_properly_case1(self): - """ Case 1: add a dominated solution when the archive size is 1 must not include the solution. - """ + """Case 1: add a dominated solution when the archive size is 1 must not include the solution.""" solution1 = Solution(2, 2) solution1.objectives = [1, 2] solution2 = Solution(2, 2) @@ -150,8 +148,7 @@ def test_should_add_work_properly_case1(self): self.assertEqual(solution1, self.archive.get(0)) def test_should_add_work_properly_case2(self): - """ Case 2: add a non-dominated solution when the archive size is 1 must include the solution. - """ + """Case 2: add a non-dominated solution when the archive size is 1 must include the solution.""" solution1 = Solution(2, 2) solution1.objectives = [1, 2] solution2 = Solution(2, 2) @@ -165,8 +162,7 @@ def test_should_add_work_properly_case2(self): self.assertTrue(solution2 in self.archive.solution_list) def test_should_add_work_properly_case3(self): - """ Case 3: add a non-dominated solution when the archive size is 3 must include the solution. - """ + """Case 3: add a non-dominated solution when the archive size is 3 must include the solution.""" solution1 = Solution(2, 2) solution1.objectives = [1.0, 2.0] solution2 = Solution(2, 2) @@ -188,8 +184,7 @@ def test_should_add_work_properly_case3(self): self.assertTrue(solution4 in self.archive.solution_list) def test_should_add_work_properly_case4(self): - """ Case 4: add a dominated solution when the archive size is 3 must not include the solution. - """ + """Case 4: add a dominated solution when the archive size is 3 must not include the solution.""" solution1 = Solution(2, 2) solution1.objectives = [1.0, 2.0] solution2 = Solution(2, 2) @@ -210,8 +205,7 @@ def test_should_add_work_properly_case4(self): self.assertTrue(solution3 in self.archive.solution_list) def test_should_add_work_properly_case5(self): - """ Case 5: add a dominated solution when the archive is full should not include the solution. - """ + """Case 5: add a dominated solution when the archive is full should not include the solution.""" solution1 = Solution(2, 2) solution1.objectives = [1.0, 2.0] solution2 = Solution(2, 2) @@ -232,7 +226,7 @@ def test_should_add_work_properly_case5(self): self.assertTrue(solution3 in self.archive.solution_list) def test_should_add_work_properly_case6(self): - """ Case 6: add a non-dominated solution when the archive is full should not include + """Case 6: add a non-dominated solution when the archive is full should not include the solution if it has the highest distance crowding value. """ archive = CrowdingDistanceArchive(4) @@ -264,8 +258,7 @@ def test_should_add_work_properly_case6(self): self.assertTrue(new_solution not in archive.solution_list) def test_should_add_work_properly_case7(self): - """ Case 7: add a non-dominated solution when the archive is full should remove all the dominated solutions. - """ + """Case 7: add a non-dominated solution when the archive is full should remove all the dominated solutions.""" archive = CrowdingDistanceArchive(4) solution1 = Solution(2, 2) @@ -290,8 +283,7 @@ def test_should_add_work_properly_case7(self): self.assertTrue(new_solution in archive.solution_list) def test_should_compute_density_estimator_work_properly_case1(self): - """ Case 1: The archive contains one solution. - """ + """Case 1: The archive contains one solution.""" archive = CrowdingDistanceArchive(4) solution1 = Solution(2, 2) @@ -304,8 +296,7 @@ def test_should_compute_density_estimator_work_properly_case1(self): self.assertEqual(float("inf"), solution1.attributes["crowding_distance"]) def test_should_compute_density_estimator_work_properly_case2(self): - """ Case 2: The archive contains two solutions. - """ + """Case 2: The archive contains two solutions.""" archive = CrowdingDistanceArchive(4) solution1 = Solution(2, 2) @@ -323,8 +314,7 @@ def test_should_compute_density_estimator_work_properly_case2(self): self.assertEqual(float("inf"), solution2.attributes["crowding_distance"]) def test_should_compute_density_estimator_work_properly_case3(self): - """ Case 3: The archive contains two solutions. - """ + """Case 3: The archive contains two solutions.""" archive = CrowdingDistanceArchive(4) solution1 = Solution(2, 2) @@ -346,5 +336,5 @@ def test_should_compute_density_estimator_work_properly_case3(self): self.assertTrue(solution2.attributes["crowding_distance"] < float("inf")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_checking.py b/jmetal/util/test/test_checking.py index f9792f7c..00201a39 100644 --- a/jmetal/util/test/test_checking.py +++ b/jmetal/util/test/test_checking.py @@ -1,11 +1,15 @@ import unittest -from jmetal.util.ckecking import Check, NoneParameterException, InvalidProbabilityValueException, \ - ValueOutOfRangeException, InvalidConditionException +from jmetal.util.ckecking import ( + Check, + InvalidConditionException, + InvalidProbabilityValueException, + NoneParameterException, + ValueOutOfRangeException, +) class CheckingTestCases(unittest.TestCase): - def test_should_is_not_null_raise_an_exception(self) -> None: with self.assertRaises(NoneParameterException): Check.is_not_none(None) @@ -31,5 +35,5 @@ def test_should_that_raise_an_exception_if_the_expression_is_false(self) -> None Check.that(False, "The expression is false") -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_comparator.py b/jmetal/util/test/test_comparator.py index 989f946d..d8b1c55b 100644 --- a/jmetal/util/test/test_comparator.py +++ b/jmetal/util/test/test_comparator.py @@ -1,10 +1,16 @@ import unittest -from mockito import mock, when, verify, never +from mockito import mock, never, verify, when from jmetal.core.solution import Solution -from jmetal.util.comparator import DominanceComparator, SolutionAttributeComparator, \ - RankingAndCrowdingDistanceComparator, Comparator, OverallConstraintViolationComparator, MultiComparator +from jmetal.util.comparator import ( + Comparator, + DominanceComparator, + MultiComparator, + OverallConstraintViolationComparator, + RankingAndCrowdingDistanceComparator, + SolutionAttributeComparator, +) class OverallConstraintViolationComparatorTestCases(unittest.TestCase): @@ -45,7 +51,6 @@ def test_should_comparator_return_1_if_solution_2_has_higher_constraint_violatio class DominanceComparatorTestCases(unittest.TestCase): - def setUp(self): self.comparator = DominanceComparator() @@ -70,7 +75,8 @@ def test_should_dominance_comparator_return_zero_if_the_two_solutions_have_one_o self.assertEqual(0, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_return_one_if_the_two_solutions_have_one_objective_and_the_second_one_is_lower( - self): + self, + ): solution = Solution(1, 1) solution2 = Solution(1, 1) solution.objectives = [2.0] @@ -79,7 +85,8 @@ def test_should_dominance_comparator_return_one_if_the_two_solutions_have_one_ob self.assertEqual(1, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_return_minus_one_if_the_two_solutions_have_one_objective_and_the_first_one_is_lower( - self): + self, + ): solution = Solution(1, 1) solution2 = Solution(1, 1) solution.objectives = [1.0] @@ -88,8 +95,7 @@ def test_should_dominance_comparator_return_minus_one_if_the_two_solutions_have_ self.assertEqual(-1, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_work_properly_case_a(self): - """ Case A: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [2.0, 6.0, 15.0] - """ + """Case A: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [2.0, 6.0, 15.0]""" solution = Solution(1, 3) solution2 = Solution(1, 3) solution.objectives = [-1.0, 5.0, 9.0] @@ -98,8 +104,7 @@ def test_should_dominance_comparator_work_properly_case_a(self): self.assertEqual(-1, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_work_properly_case_b(self): - """ Case b: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-1.0, 5.0, 10.0] - """ + """Case b: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-1.0, 5.0, 10.0]""" solution = Solution(1, 3) solution2 = Solution(1, 3) solution.objectives = [-1.0, 5.0, 9.0] @@ -108,8 +113,7 @@ def test_should_dominance_comparator_work_properly_case_b(self): self.assertEqual(-1, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_work_properly_case_c(self): - """ Case c: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-2.0, 5.0, 9.0] - """ + """Case c: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-2.0, 5.0, 9.0]""" solution = Solution(1, 3) solution2 = Solution(1, 3) solution.objectives = [-1.0, 5.0, 9.0] @@ -118,8 +122,7 @@ def test_should_dominance_comparator_work_properly_case_c(self): self.assertEqual(1, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_work_properly_case_d(self): - """ Case d: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-1.0, 5.0, 8.0] - """ + """Case d: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-1.0, 5.0, 8.0]""" solution = Solution(1, 3) solution2 = Solution(1, 3) solution.objectives = [-1.0, 5.0, 9.0] @@ -128,8 +131,7 @@ def test_should_dominance_comparator_work_properly_case_d(self): self.assertEqual(1, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_work_properly_case_3(self): - """ Case d: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-2.0, 5.0, 10.0] - """ + """Case d: solution1 has objectives [-1.0, 5.0, 9.0] and solution2 has [-2.0, 5.0, 10.0]""" solution = Solution(1, 3) solution2 = Solution(1, 3) solution.objectives = [-1.0, 5.0, 9.0] @@ -138,8 +140,7 @@ def test_should_dominance_comparator_work_properly_case_3(self): self.assertEqual(0, self.comparator.compare(solution, solution2)) def test_should_dominance_comparator_work_properly_with_constrains_case_1(self): - """ Case 1: solution1 has a higher degree of constraint violation than solution 2 - """ + """Case 1: solution1 has a higher degree of constraint violation than solution 2""" solution1 = Solution(1, 3, 1) solution2 = Solution(1, 3, 1) @@ -152,8 +153,7 @@ def test_should_dominance_comparator_work_properly_with_constrains_case_1(self): self.assertEqual(-1, self.comparator.compare(solution1, solution2)) def test_should_dominance_comparator_work_properly_with_constrains_case_2(self): - """ Case 2: solution1 has a lower degree of constraint violation than solution 2 - """ + """Case 2: solution1 has a lower degree of constraint violation than solution 2""" solution1 = Solution(1, 3, 1) solution2 = Solution(1, 3, 1) @@ -167,7 +167,6 @@ def test_should_dominance_comparator_work_properly_with_constrains_case_2(self): class SolutionAttributeComparatorTestCases(unittest.TestCase): - def setUp(self): self.comparator = SolutionAttributeComparator("attribute") @@ -200,8 +199,7 @@ def test_should_compare_return_zero_if_both_solutions_have_the_same_attribute_va self.assertEqual(0, self.comparator.compare(solution1, solution2)) def test_should_compare_works_properly_case1(self): - """ Case 1: solution1.attribute < solution2.attribute (lowest is best) - """ + """Case 1: solution1.attribute < solution2.attribute (lowest is best)""" solution1 = Solution(1, 1) solution2 = Solution(1, 1) solution1.attributes["attribute"] = 0.0 @@ -210,8 +208,7 @@ def test_should_compare_works_properly_case1(self): self.assertEqual(-1, self.comparator.compare(solution1, solution2)) def test_should_compare_works_properly_case2(self): - """ Case 2: solution1.attribute > solution2.attribute (lowest is best) - """ + """Case 2: solution1.attribute > solution2.attribute (lowest is best)""" solution1 = Solution(1, 1) solution2 = Solution(1, 1) solution1.attributes["attribute"] = 1.0 @@ -220,8 +217,7 @@ def test_should_compare_works_properly_case2(self): self.assertEqual(1, self.comparator.compare(solution1, solution2)) def test_should_compare_works_properly_case3(self): - """ Case 3: solution1.attribute < solution2.attribute (highest is best) - """ + """Case 3: solution1.attribute < solution2.attribute (highest is best)""" comparator = SolutionAttributeComparator("attribute", False) solution1 = Solution(1, 1) solution2 = Solution(1, 1) @@ -231,8 +227,7 @@ def test_should_compare_works_properly_case3(self): self.assertEqual(1, comparator.compare(solution1, solution2)) def test_should_compare_works_properly_case4(self): - """ Case 4: solution1.attribute > solution2.attribute (highest is best) - """ + """Case 4: solution1.attribute > solution2.attribute (highest is best)""" solution1 = Solution(1, 1) solution2 = Solution(1, 1) solution1.attributes["attribute"] = 1.0 @@ -243,13 +238,11 @@ def test_should_compare_works_properly_case4(self): class RankingAndCrowdingComparatorTestCases(unittest.TestCase): - def setUp(self): self.comparator = RankingAndCrowdingDistanceComparator() def test_should_compare_work_properly_case_1(self): - """ Case 1: solution1.ranking < solution2.ranking - """ + """Case 1: solution1.ranking < solution2.ranking""" solution1 = Solution(1, 1) solution2 = Solution(1, 1) solution1.attributes["dominance_ranking"] = 1.0 @@ -258,8 +251,7 @@ def test_should_compare_work_properly_case_1(self): self.assertEqual(-1, self.comparator.compare(solution1, solution2)) def test_should_compare_work_properly_case_2(self): - """ Case 2: solution1.ranking > solution2.ranking - """ + """Case 2: solution1.ranking > solution2.ranking""" solution1 = Solution(1, 1) solution2 = Solution(1, 1) solution1.attributes["dominance_ranking"] = 2.0 @@ -268,8 +260,8 @@ def test_should_compare_work_properly_case_2(self): self.assertEqual(1, self.comparator.compare(solution1, solution2)) def test_should_compare_work_properly_case_3(self): - """ Case 3: solution1.ranking == solution2.ranking - solution1.crowding < solution2.crowding + """Case 3: solution1.ranking == solution2.ranking + solution1.crowding < solution2.crowding """ solution1 = Solution(1, 1) solution2 = Solution(1, 1) @@ -281,8 +273,8 @@ def test_should_compare_work_properly_case_3(self): self.assertEqual(1, self.comparator.compare(solution1, solution2)) def test_should_compare_work_properly_case_4(self): - """ Case 4: solution1.ranking == solution2.ranking - solution1.crowding > solution2.crowding + """Case 4: solution1.ranking == solution2.ranking + solution1.crowding > solution2.crowding """ solution1 = Solution(1, 1) solution2 = Solution(1, 1) @@ -294,8 +286,8 @@ def test_should_compare_work_properly_case_4(self): self.assertEqual(-1, self.comparator.compare(solution1, solution2)) def test_should_compare_work_properly_case_5(self): - """ Case 5: solution1.ranking == solution2.ranking - solution1.crowding == solution2.crowding + """Case 5: solution1.ranking == solution2.ranking + solution1.crowding == solution2.crowding """ solution1 = Solution(1, 1) solution2 = Solution(1, 1) @@ -308,7 +300,6 @@ def test_should_compare_work_properly_case_5(self): class MultiComparatorTestCases(unittest.TestCase): - def test_should_compare_return_zero_if_the_comparator_list_is_empty(self): solution1 = Solution(2, 2) solution2 = Solution(2, 2) @@ -317,8 +308,7 @@ def test_should_compare_return_zero_if_the_comparator_list_is_empty(self): self.assertEqual(0, multi_comparator.compare(solution1, solution2)) def test_should_compare_work_properly_case_1(self): - """ Case 1: a comparator returning 0. - """ + """Case 1: a comparator returning 0.""" solution1 = Solution(2, 2) solution2 = Solution(2, 2) @@ -333,8 +323,8 @@ def test_should_compare_work_properly_case_1(self): verify(mocked_comparator, times=1).compare(solution1, solution2) def test_should_compare_work_properly_case_2(self): - """ Case 2: two comparators; the first returns 1 and the second one returns 0. - Expected result: 1 + """Case 2: two comparators; the first returns 1 and the second one returns 0. + Expected result: 1 """ solution1 = Solution(2, 2) solution2 = Solution(2, 2) @@ -353,8 +343,8 @@ def test_should_compare_work_properly_case_2(self): verify(mocked_comparator2, never).compare(solution1, solution2) def test_should_compare_work_properly_case_3(self): - """ Case 2: two comparators; the first returns 0 and the second one returns -1. - Expected result: -1 + """Case 2: two comparators; the first returns 0 and the second one returns -1. + Expected result: -1 """ solution1 = Solution(2, 2) solution2 = Solution(2, 2) @@ -373,5 +363,5 @@ def test_should_compare_work_properly_case_3(self): verify(mocked_comparator2, times=1).compare(solution1, solution2) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_constraint_handling.py b/jmetal/util/test/test_constraint_handling.py index 06c9771a..4fa4463c 100644 --- a/jmetal/util/test/test_constraint_handling.py +++ b/jmetal/util/test/test_constraint_handling.py @@ -1,12 +1,15 @@ import unittest from jmetal.core.solution import Solution -from jmetal.util.constraint_handling import is_feasible, number_of_violated_constraints, \ - overall_constraint_violation_degree, feasibility_ratio +from jmetal.util.constraint_handling import ( + feasibility_ratio, + is_feasible, + number_of_violated_constraints, + overall_constraint_violation_degree, +) class ConstraintHandlingTestCases(unittest.TestCase): - def test_should_is_feasible_return_true_if_the_solution_has_no_constraints(self) -> None: solution = Solution(number_of_variables=2, number_of_objectives=2, number_of_constraints=0) @@ -29,7 +32,9 @@ def test_should_number_of_violated_constraints_return_zero_if_the_solution_has_n self.assertEqual(0, number_of_violated_constraints(solution)) - def test_should_number_of_violated_constraints_return_zero_if_the_solution_has_not_violated_constraints(self) -> None: + def test_should_number_of_violated_constraints_return_zero_if_the_solution_has_not_violated_constraints( + self, + ) -> None: solution = Solution(number_of_variables=2, number_of_objectives=2, number_of_constraints=2) self.assertEqual(0, number_of_violated_constraints(solution)) @@ -90,8 +95,8 @@ def test_should_feasibility_ratio_return_the_right_percentage_of_feasible_soluti solution2.constraints[0] = 0 solution3.constraints[0] = -2 - self.assertEqual(1/3, feasibility_ratio([solution1, solution2, solution3])) + self.assertEqual(1 / 3, feasibility_ratio([solution1, solution2, solution3])) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_density_estimator.py b/jmetal/util/test/test_density_estimator.py index c89752bf..ade19053 100644 --- a/jmetal/util/test/test_density_estimator.py +++ b/jmetal/util/test/test_density_estimator.py @@ -2,11 +2,13 @@ from math import sqrt from jmetal.core.solution import Solution -from jmetal.util.density_estimator import CrowdingDistance, KNearestNeighborDensityEstimator +from jmetal.util.density_estimator import ( + CrowdingDistance, + KNearestNeighborDensityEstimator, +) class CrowdingDistanceTestCases(unittest.TestCase): - def setUp(self): self.crowding = CrowdingDistance() @@ -89,18 +91,17 @@ def test_should_the_crowding_distance_of_four_solutions_correctly_assigned(self) class KNearestNeighborDensityEstimatorTest(unittest.TestCase): - def setUp(self): self.knn = KNearestNeighborDensityEstimator() def test_should_the_density_estimator_compute_the_right_distances_case1(self): """ - 5 1 - 4 2 - 3 3 - 2 - 1 4 - 0 1 2 3 4 5 + 5 1 + 4 2 + 3 3 + 2 + 1 4 + 0 1 2 3 4 5 """ solution1 = Solution(2, 2) solution1.objectives = [1, 5] @@ -115,24 +116,24 @@ def test_should_the_density_estimator_compute_the_right_distances_case1(self): self.knn.compute_density_estimator(solution_list) - self.assertEqual(sqrt(2), solution1.attributes['knn_density']) - self.assertEqual(sqrt(2), solution2.attributes['knn_density']) - self.assertEqual(sqrt(2), solution3.attributes['knn_density']) - self.assertEqual(sqrt(2 * 2 + 2 * 2), solution4.attributes['knn_density']) + self.assertEqual(sqrt(2), solution1.attributes["knn_density"]) + self.assertEqual(sqrt(2), solution2.attributes["knn_density"]) + self.assertEqual(sqrt(2), solution3.attributes["knn_density"]) + self.assertEqual(sqrt(2 * 2 + 2 * 2), solution4.attributes["knn_density"]) # self.knn.sort(solution_list) def test_should_the_density_estimator_sort_the_solution_list(self): """ - 5 1 - 4 2 - 3 3 - 2 5 - 1 4 - 0 1 2 3 4 5 - - List: 1,2,3,4,5 - Expected result: 4, 1, 2, 5, 3 + 5 1 + 4 2 + 3 3 + 2 5 + 1 4 + 0 1 2 3 4 5 + + List: 1,2,3,4,5 + Expected result: 4, 1, 2, 5, 3 """ solution1 = Solution(2, 2) solution1.objectives = [1, 5] @@ -157,14 +158,14 @@ def test_should_the_density_estimator_sort_the_solution_list(self): def test_should_the_density_estimator_sort_the_solution_list_considering_the_draws(self): """ - 5 1 - 4 2 - 3 3 - 2 - 1 4 - 0 1 2 3 4 5 - - Expected result after sort: 4, 3, 1, 2 + 5 1 + 4 2 + 3 3 + 2 + 1 4 + 0 1 2 3 4 5 + + Expected result after sort: 4, 3, 1, 2 """ solution1 = Solution(2, 2) solution1.objectives = [1, 5] @@ -194,11 +195,13 @@ def test_should_the_density_estimator_sort_the_solution_list_considering_the_dra 0.25529404008730594 2.922302861104415 """ - points = [[0.13436424411240122, 4.323216008886963], - [0.020818108509287336, 5.1051826661880515], - [0.1028341459863098, 4.9409270526888935], - [0.8967291504209932, 2.506948771242972], - [0.25529404008730594, 2.922302861104415]] + points = [ + [0.13436424411240122, 4.323216008886963], + [0.020818108509287336, 5.1051826661880515], + [0.1028341459863098, 4.9409270526888935], + [0.8967291504209932, 2.506948771242972], + [0.25529404008730594, 2.922302861104415], + ] population = [] for i in range(len(points)): diff --git a/jmetal/util/test/test_distance.py b/jmetal/util/test/test_distance.py index bbdb3209..ce80a6be 100644 --- a/jmetal/util/test/test_distance.py +++ b/jmetal/util/test/test_distance.py @@ -4,21 +4,20 @@ class EuclideanDistanceTestCases(unittest.TestCase): - def test_should_get_distance_work_properly_case_1(self): - """ Case 1: [1], [1] -> distance == 0 """ + """Case 1: [1], [1] -> distance == 0""" distance = EuclideanDistance() self.assertEqual(0, distance.get_distance([1], [1])) def test_should_get_distance_work_properly_case_2(self): - """ Case 2: [1, 0, 0], [0, 1, 0] -> distance == 1.4142135623730951 """ + """Case 2: [1, 0, 0], [0, 1, 0] -> distance == 1.4142135623730951""" distance = EuclideanDistance() self.assertEqual(1.4142135623730951, distance.get_distance([1, 0, 0], [0, 1, 0])) def test_should_get_distance_work_properly_case_3(self): - """ Case 3: [1, 1, 0], [0, 1, 0] -> distance == 1.0 """ + """Case 3: [1, 1, 0], [0, 1, 0] -> distance == 1.0""" distance = EuclideanDistance() self.assertEqual(1.0, distance.get_distance([1, 1, 0], [0, 1, 0])) @@ -45,5 +44,5 @@ def test_should_two_perpendicular_points_have_a_distance_of_one(self): self.assertEqual(1.0, distance.get_distance([0.0, 1.0], [1.0, 0.0])) """ -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_evaluator.py b/jmetal/util/test/test_evaluator.py index 320a43fa..542c4e67 100644 --- a/jmetal/util/test/test_evaluator.py +++ b/jmetal/util/test/test_evaluator.py @@ -2,11 +2,10 @@ from jmetal.core.problem import FloatProblem from jmetal.core.solution import FloatSolution -from jmetal.util.evaluator import SequentialEvaluator, MapEvaluator +from jmetal.util.evaluator import MapEvaluator, SequentialEvaluator class MockedProblem(FloatProblem): - def __init__(self, number_of_variables: int = 3): super(MockedProblem, self).__init__() self.number_of_objectives = 2 @@ -30,7 +29,6 @@ def get_name(self) -> str: class SequentialEvaluatorTestCases(unittest.TestCase): - def setUp(self): self.evaluator = SequentialEvaluator() self.problem = MockedProblem() @@ -57,7 +55,6 @@ def test_should_evaluate_a_list_of_problem_work_properly(self): class ParallelEvaluatorTestCases(unittest.TestCase): - def setUp(self): self.evaluator = MapEvaluator() self.problem = MockedProblem() diff --git a/jmetal/util/test/test_neighborhood.py b/jmetal/util/test/test_neighborhood.py index 12d275c2..303e6430 100644 --- a/jmetal/util/test/test_neighborhood.py +++ b/jmetal/util/test/test_neighborhood.py @@ -3,12 +3,11 @@ import numpy from jmetal.core.solution import Solution -from jmetal.util.ckecking import NoneParameterException, InvalidConditionException -from jmetal.util.neighborhood import WeightVectorNeighborhood, TwoDimensionalMesh, L5 +from jmetal.util.ckecking import InvalidConditionException, NoneParameterException +from jmetal.util.neighborhood import L5, TwoDimensionalMesh, WeightVectorNeighborhood class WeightVectorNeighborhoodTestCases(unittest.TestCase): - def test_should_constructor_work_properly(self) -> None: number_of_weight_vectors = 100 neighborhood_size = 20 @@ -25,10 +24,18 @@ def test_should_constructor_work_properly(self) -> None: self.assertEqual(1.0, neighborhood.weight_vectors[99][0]) self.assertEqual(0.0, neighborhood.weight_vectors[99][1]) - self.assertTrue(numpy.array_equal(numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), - neighborhood.neighborhood[0])) - self.assertTrue(numpy.array_equal(numpy.array([69, 70, 68, 71, 67, 72, 66, 73, 65, 64, 74, 75, 63, 76, 62, 77, 61, 78, 60, 79]), - neighborhood.neighborhood[69])) + self.assertTrue( + numpy.array_equal( + numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), + neighborhood.neighborhood[0], + ) + ) + self.assertTrue( + numpy.array_equal( + numpy.array([69, 70, 68, 71, 67, 72, 66, 73, 65, 64, 74, 75, 63, 76, 62, 77, 61, 78, 60, 79]), + neighborhood.neighborhood[69], + ) + ) def test_should_get_neighbors_work_properly_with_two_objectives(self): number_of_weight_vectors = 100 @@ -225,7 +232,7 @@ def test_should_get_neighbors_return_four_neighbors_case2(self): solution_list = [] for i in range(rows * columns): solution = Solution(i, 2) - solution.variables = [i, i+1] + solution.variables = [i, i + 1] solution_list.append(solution) neighborhood = L5(rows, columns) @@ -276,5 +283,5 @@ def test_should_get_neighbors_return_four_neighbors_case4(self): self.assertEqual(2, result.count(solution_list[2])) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_point.py b/jmetal/util/test/test_point.py index cdc4a504..f8eaf142 100644 --- a/jmetal/util/test/test_point.py +++ b/jmetal/util/test/test_point.py @@ -4,7 +4,6 @@ class IdealPointTestCases(unittest.TestCase): - def test_should_constructor_create_a_correctly_initialized_point(self) -> None: point = IdealPoint(2) @@ -40,5 +39,5 @@ def test_should_update_with_three_solutions_work_properly(self) -> None: self.assertEqual([0.2, 1.0, 1.5], point.point) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/jmetal/util/test/test_ranking.py b/jmetal/util/test/test_ranking.py index ee9520e9..a4b17e29 100644 --- a/jmetal/util/test/test_ranking.py +++ b/jmetal/util/test/test_ranking.py @@ -1,11 +1,10 @@ import unittest from jmetal.core.solution import Solution -from jmetal.util.ranking import FastNonDominatedRanking, StrengthRanking, Ranking +from jmetal.util.ranking import FastNonDominatedRanking, Ranking, StrengthRanking class FastNonDominatedRankingTestCases(unittest.TestCase): - def setUp(self): self.ranking = FastNonDominatedRanking() @@ -41,8 +40,7 @@ def test_should_compute_ranking_return_a_subfront_if_the_solution_list_contains_ self.assertEqual(solution2, ranking[0][1]) def test_should_compute_ranking_work_properly_case1(self): - """ The list contains two solutions and one of them is dominated by the other one. - """ + """The list contains two solutions and one of them is dominated by the other one.""" solution = Solution(2, 2) solution.objectives = [2, 3] solution2 = Solution(2, 2) @@ -109,8 +107,7 @@ def test_should_ranking_of_a_population_with_five_solutions_work_properly(self): self.assertEqual(solution5, ranking[1][1]) def test_should_compute_ranking_work_properly_with_constraints_case1(self): - """ The list contains two solutions and one is infeasible - """ + """The list contains two solutions and one is infeasible""" solution = Solution(2, 2, 1) solution.objectives = [2, 3] solution.constraints[0] = -1 @@ -126,8 +123,7 @@ def test_should_compute_ranking_work_properly_with_constraints_case1(self): self.assertEqual(solution, ranking[1][0]) def test_should_compute_ranking_work_properly_with_constraints_case2(self): - """ The list contains two solutions and both are infeasible with different violation degree - """ + """The list contains two solutions and both are infeasible with different violation degree""" solution = Solution(2, 2, 1) solution.objectives = [2, 3] solution.constraints[0] = -1 @@ -143,8 +139,7 @@ def test_should_compute_ranking_work_properly_with_constraints_case2(self): self.assertEqual(solution2, ranking[1][0]) def test_should_compute_ranking_work_properly_with_constraints_case3(self): - """ The list contains two solutions and both are infeasible with equal violation degree - """ + """The list contains two solutions and both are infeasible with equal violation degree""" solution = Solution(2, 2, 1) solution.objectives = [2, 3] solution.constraints[0] = -1 @@ -161,20 +156,19 @@ def test_should_compute_ranking_work_properly_with_constraints_case3(self): class StrengthRankingTestCases(unittest.TestCase): - def setUp(self): - self.ranking:Ranking = StrengthRanking() + self.ranking: Ranking = StrengthRanking() def test_should_ranking_assing_zero_to_all_the_solutions_if_they_are_nondominated(self): """ - 5 1 - 4 2 - 3 3 - 2 - 1 4 - 0 1 2 3 4 5 - - Points 1, 2, 3 and 4 are nondominated + 5 1 + 4 2 + 3 3 + 2 + 1 4 + 0 1 2 3 4 5 + + Points 1, 2, 3 and 4 are nondominated """ solution1 = Solution(2, 2) solution1.objectives = [1, 5] @@ -197,15 +191,15 @@ def test_should_ranking_assing_zero_to_all_the_solutions_if_they_are_nondominate def test_should_ranking_work_properly(self): """ - 5 1 - 4 2 - 3 3 - 2 5 - 1 4 - 0 1 2 3 4 5 - - Solutions: 1, 2, 3, 4, 5 - Expected result: two ranks (rank 0: 1, 2, 5, 4; rank 1: 3) + 5 1 + 4 2 + 3 3 + 2 5 + 1 4 + 0 1 2 3 4 5 + + Solutions: 1, 2, 3, 4, 5 + Expected result: two ranks (rank 0: 1, 2, 5, 4; rank 1: 3) """ solution1 = Solution(2, 2) @@ -229,11 +223,11 @@ def test_should_ranking_work_properly(self): self.assertTrue(solution3 in self.ranking.get_subfront(1)) self.assertTrue(solution4 in self.ranking.get_subfront(0)) self.assertTrue(solution5 in self.ranking.get_subfront(0)) - self.assertEqual(0, solution1.attributes['strength_ranking']) - self.assertEqual(0, solution2.attributes['strength_ranking']) - self.assertEqual(1, solution3.attributes['strength_ranking']) - self.assertEqual(0, solution4.attributes['strength_ranking']) - self.assertEqual(0, solution5.attributes['strength_ranking']) + self.assertEqual(0, solution1.attributes["strength_ranking"]) + self.assertEqual(0, solution2.attributes["strength_ranking"]) + self.assertEqual(1, solution3.attributes["strength_ranking"]) + self.assertEqual(0, solution4.attributes["strength_ranking"]) + self.assertEqual(0, solution5.attributes["strength_ranking"]) if __name__ == "__main__": diff --git a/jmetal/util/test/test_replacement.py b/jmetal/util/test/test_replacement.py index 8b66b7cc..36f51a1b 100644 --- a/jmetal/util/test/test_replacement.py +++ b/jmetal/util/test/test_replacement.py @@ -2,20 +2,19 @@ from jmetal.core.solution import Solution from jmetal.util.density_estimator import KNearestNeighborDensityEstimator -from jmetal.util.ranking import StrengthRanking, FastNonDominatedRanking +from jmetal.util.ranking import FastNonDominatedRanking, StrengthRanking from jmetal.util.replacement import RankingAndDensityEstimatorReplacement class RankingAndDensityEstimatorReplacementTestCases(unittest.TestCase): - def test_should_replacement_return_the_list_if_the_offspring_list_is_empty(self): """ - 5 1 - 4 2 - 3 3 - 2 - 1 4 - 0 1 2 3 4 5 + 5 1 + 4 2 + 3 3 + 2 + 1 4 + 0 1 2 3 4 5 """ ranking = StrengthRanking() density_estimator = KNearestNeighborDensityEstimator(1) @@ -35,22 +34,22 @@ def test_should_replacement_return_the_list_if_the_offspring_list_is_empty(self) result_list = replacement.replace(solution_list, []) self.assertEqual(4, len(result_list)) - self.assertEqual(0, solution1.attributes['strength_ranking']) - self.assertEqual(0, solution2.attributes['strength_ranking']) - self.assertEqual(0, solution3.attributes['strength_ranking']) - self.assertEqual(0, solution4.attributes['strength_ranking']) + self.assertEqual(0, solution1.attributes["strength_ranking"]) + self.assertEqual(0, solution2.attributes["strength_ranking"]) + self.assertEqual(0, solution3.attributes["strength_ranking"]) + self.assertEqual(0, solution4.attributes["strength_ranking"]) def test_should_replacement_return_the_right_value_case1(self): """ - 5 1 - 4 2 - 3 3 - 2 - 1 4 - 0 1 2 3 4 5 - - List: 1,2,3 OffspringList: 4 - Expected result: 4, 1, 3 + 5 1 + 4 2 + 3 3 + 2 + 1 4 + 0 1 2 3 4 5 + + List: 1,2,3 OffspringList: 4 + Expected result: 4, 1, 3 """ ranking = StrengthRanking() density_estimator = KNearestNeighborDensityEstimator(1) @@ -77,15 +76,15 @@ def test_should_replacement_return_the_right_value_case1(self): def test_should_replacement_return_the_right_value_case2(self): """ - 5 1 - 4 2 - 3 3 - 2 5 - 1 4 - 0 1 2 3 4 5 - - List: 1,2,4 OffspringList: 3,5 - Expected result: 1, 5, 4 + 5 1 + 4 2 + 3 3 + 2 5 + 1 4 + 0 1 2 3 4 5 + + List: 1,2,4 OffspringList: 3,5 + Expected result: 1, 5, 4 """ ranking = StrengthRanking() density_estimator = KNearestNeighborDensityEstimator(1) @@ -107,11 +106,11 @@ def test_should_replacement_return_the_right_value_case2(self): offspring_list = [solution3, solution5] result_list = replacement.replace(solution_list, offspring_list) - self.assertEqual(0, solution1.attributes['strength_ranking']) - self.assertEqual(0, solution2.attributes['strength_ranking']) - self.assertEqual(1, solution3.attributes['strength_ranking']) - self.assertEqual(0, solution4.attributes['strength_ranking']) - self.assertEqual(0, solution5.attributes['strength_ranking']) + self.assertEqual(0, solution1.attributes["strength_ranking"]) + self.assertEqual(0, solution2.attributes["strength_ranking"]) + self.assertEqual(1, solution3.attributes["strength_ranking"]) + self.assertEqual(0, solution4.attributes["strength_ranking"]) + self.assertEqual(0, solution5.attributes["strength_ranking"]) self.assertEqual(3, len(result_list)) self.assertTrue(solution1 in result_list) @@ -119,30 +118,33 @@ def test_should_replacement_return_the_right_value_case2(self): self.assertTrue(solution4 in result_list) def test_should_replacement_return_the_right_value_case3(self): - """ - """ - - points_population = [[0.13436424411240122, 4.323216008886963], - [0.23308445025757263, 4.574937990387161], - [0.17300740157905092, 4.82329350808847], - [0.9571162814602269, 3.443495331489301], - [0.25529404008730594, 3.36387501100745], - [0.020818108509287336, 5.1051826661880515], - [0.8787178982088466, 3.2716009445324103], - [0.6744550697237632, 3.901350307095427], - [0.7881164487252263, 3.1796004913916516], - [0.1028341459863098, 4.9409270526888935]] - - points_offspring_population = [[0.3150521745650882, 4.369120371847888], - [0.8967291504209932, 2.506948771242972], - [0.6744550697237632, 3.9361442668874504], - [0.9571162814602269, 3.4388386707431433], - [0.13436424411240122, 4.741872175943253], - [0.25529404008730594, 2.922302861104415], - [0.23308445025757263, 4.580180404770213], - [0.23308445025757263, 4.591260299892424], - [0.9571162814602269, 2.9865495383518694], - [0.25529404008730594, 3.875587748122183]] + """""" + + points_population = [ + [0.13436424411240122, 4.323216008886963], + [0.23308445025757263, 4.574937990387161], + [0.17300740157905092, 4.82329350808847], + [0.9571162814602269, 3.443495331489301], + [0.25529404008730594, 3.36387501100745], + [0.020818108509287336, 5.1051826661880515], + [0.8787178982088466, 3.2716009445324103], + [0.6744550697237632, 3.901350307095427], + [0.7881164487252263, 3.1796004913916516], + [0.1028341459863098, 4.9409270526888935], + ] + + points_offspring_population = [ + [0.3150521745650882, 4.369120371847888], + [0.8967291504209932, 2.506948771242972], + [0.6744550697237632, 3.9361442668874504], + [0.9571162814602269, 3.4388386707431433], + [0.13436424411240122, 4.741872175943253], + [0.25529404008730594, 2.922302861104415], + [0.23308445025757263, 4.580180404770213], + [0.23308445025757263, 4.591260299892424], + [0.9571162814602269, 2.9865495383518694], + [0.25529404008730594, 3.875587748122183], + ] ranking = FastNonDominatedRanking() density_estimator = KNearestNeighborDensityEstimator(1) @@ -160,15 +162,13 @@ def test_should_replacement_return_the_right_value_case3(self): replacement = RankingAndDensityEstimatorReplacement(ranking, density_estimator) result_list = replacement.replace(population, offspring_population) - self.assertEqual(10,len(result_list)) + self.assertEqual(10, len(result_list)) for solution in result_list[0:4]: - self.assertEqual(0, solution.attributes['dominance_ranking']) + self.assertEqual(0, solution.attributes["dominance_ranking"]) for solution in result_list[5:9]: - self.assertEqual(1, solution.attributes['dominance_ranking']) - - + self.assertEqual(1, solution.attributes["dominance_ranking"]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 00000000..27cdb10f --- /dev/null +++ b/mypy.ini @@ -0,0 +1,12 @@ +[mypy] +check_untyped_defs = True +ignore_errors = False +ignore_missing_imports = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_unreachable = True +warn_unused_configs = True +pretty = True + +[mypy-*.test.*] +ignore_errors = True \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..02d79c94 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 120 +include = '\.pyi?$' +exclude = ''' +/( + \.git + | \.mypy_cache + | \.venv + | _build + | build + | dist +)/ +''' \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index b88034e4..b037079a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,59 @@ [metadata] -description-file = README.md +name = jmetalpy +version = 1.5.7 +description = Python version of the jMetal framework +long_description = file: README.md +long_description_content_type = text/markdown; charset=UTF-8 +url = https://github.com/jMetal/jMetalPy +author = Antonio J. Nebro +author_email = antonio@lcc.uma.es +license = MIT +license_file = LICENSE +classifiers = + Development Status :: 5 - Production/Stable + Intended Audience :: Science/Research + License :: OSI Approved :: MIT License + Topic :: Scientific/Engineering :: Artificial Intelligence + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 +project_urls = + Source = https://github.com/jMetal/jMetalPy + Tracker = https://github.com/jMetal/jMetalPy/issues + +[options] +zip_safe = False +packages = find: +platforms = any +include_package_data = True +install_requires = + tqdm + numpy>=1.16.0 + pandas>=0.24.2 + plotly>=3.3.0 + matplotlib>=3.0.2 + scipy>=1.3.0 + statsmodels>=0.9.0 +python_requires = >=3.7 +setup_requires = + setuptools + +[bdist_wheel] +universal = 1 + +[options.extras_require] +distributed = + dask[complete]>=1.2.2 + distributed>=1.28.1 + pyspark>=2.4.0 +dev = + isort + black + mypy +test = + mockito + PyHamcrest +all = + %(distributed)s + %(dev)s + %(test)s \ No newline at end of file diff --git a/setup.py b/setup.py index 058ded15..4a15e68f 100644 --- a/setup.py +++ b/setup.py @@ -1,53 +1,4 @@ -from os.path import abspath, dirname, join +import setuptools -from setuptools import find_packages, setup - -basedir = abspath(dirname(__file__)) - -with open(join(basedir, 'README.md'), encoding='utf-8') as f: - README = f.read() - -install_requires = [ - 'tqdm', - 'numpy>=1.16.0', - 'pandas>=0.24.2', - 'plotly>=3.3.0', - 'matplotlib>=3.0.2', - 'scipy>=1.3.0', - 'statsmodels>=0.9.0' -] -extras_require = { - 'core': install_requires, - 'docs': install_requires + ['jupyter', 'nbsphinx'], - 'distributed': install_requires + ['dask[complete]>=1.2.2', 'distributed>=1.28.1', 'pyspark>=2.4.0'] -} -extras_require['complete'] = {v for req in extras_require.values() for v in req} - -setup( - name='jmetalpy', - version='1.5.5', - description='Python version of the jMetal framework', - long_description=README, - long_description_content_type='text/markdown', - author='Antonio J. Nebro', - author_email='antonio@lcc.uma.es', - maintainer='Antonio J. Nebro, Antonio Benitez-Hidalgo', - maintainer_email='antonio@lcc.uma.es, antonio.benitez@lcc.uma.es', - license='MIT', - url='https://github.com/jMetal/jMetalPy', - packages=find_packages(exclude=['test_']), - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: MIT License', - 'Topic :: Scientific/Engineering :: Artificial Intelligence', - 'Programming Language :: Python :: 3.6' - ], - install_requires=install_requires, - extras_require=extras_require, - tests_require=[ - 'mockito', - 'PyHamcrest', - 'mock' - ] -) +if __name__ == "__main__": + setuptools.setup() \ No newline at end of file