From c905a54ff0d50c8adfad84726cd2afc8e51721b6 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:08:15 +0100 Subject: [PATCH 01/19] python/ Remove requirements_dev.txt --- .github/workflows/python.yml | 3 +-- python/Makefile | 2 +- python/requirements_dev.txt | 32 -------------------------------- python/tox.ini | 20 ++++++++------------ 4 files changed, 10 insertions(+), 47 deletions(-) delete mode 100644 python/requirements_dev.txt diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 5f3ae717b..8048b2242 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -120,7 +120,6 @@ jobs: with: python-version: '3.10' cache: 'pip' - cache-dependency-path: '**/requirements_dev.txt' - name: Ensure Pip and Build run: | @@ -137,7 +136,7 @@ jobs: - name: install the doc build requirements run: | - python3 -m pip install -r requirements_dev.txt + python3 -m pip install .[docs] working-directory: python - name: Build the docs 🔧 diff --git a/python/Makefile b/python/Makefile index 78c51fa46..b88ba9d27 100644 --- a/python/Makefile +++ b/python/Makefile @@ -20,7 +20,7 @@ pre-commit: pre-commit run -a docdeps: - python3 -m pip install -r requirements_dev.txt --disable-pip-version-check --quiet + python3 -m pip install .[docs] --disable-pip-version-check --quiet show: $(MAKE) -C doc show diff --git a/python/requirements_dev.txt b/python/requirements_dev.txt deleted file mode 100644 index c5d5b4923..000000000 --- a/python/requirements_dev.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Sync with .pre-commit-config.yaml -setuptools>=77.0.3 -cffi >= 1.17.1 -numpy >= 1.23.0 - -pre-commit >= 3.3.2 -ruff >= 0.11.2 - -tox >= 4.6.2 # Sync with tox.ini -pytest >= 7 # Sync with tox.ini -pytest-cov >= 4.1.0 -virtualenv >= 20 -build - -sphinx >= 6.0 -pydata_sphinx_theme>=0.16.0 -jupyter -ipykernel -kaleido -sphinx-gallery>=0.19.0 -sphinxcontrib-napoleon -sphinxcontrib-bibtex -sphinx-autodoc-typehints -sphinx-copybutton -sphinx-design -jupyterlab -ipywidgets - -# Gallery examples -pandas >=2.0.0 -seaborn -plotly diff --git a/python/tox.ini b/python/tox.ini index 1afa12d37..a3e89a824 100644 --- a/python/tox.ini +++ b/python/tox.ini @@ -1,6 +1,6 @@ [tox] requires = - tox>=4.2 + tox>=4.6.2 env_list = numpy-v2 py{312, 311, 310} @@ -11,10 +11,9 @@ package = wheel wheel_build_env = .pkg deps = numpy<2 - pandas>=2 - pytest>=7 - cov: coverage[toml] - cov: gcovr +extras = + test + cov: coverage commands = pytest --doctest-modules --doctest-continue-on-failure --import-mode=importlib {envsitepackagesdir}/moocore tests @@ -25,10 +24,9 @@ package = wheel wheel_build_env = .pkg deps = numpy>=2 - pandas>=2 - pytest>=7 - cov: coverage[toml] - cov: gcovr +extras = + test + cov: coverage commands = pytest --doctest-modules --doctest-continue-on-failure --import-mode=importlib {envsitepackagesdir}/moocore tests @@ -51,10 +49,8 @@ commands = [testenv:docs] description = Build documentation -deps = - -r{toxinidir}/requirements_dev.txt extras = - doc + docs commands = sphinx-build -M html ./doc/source ./doc/_build/ -WT --keep-going -d ./doc/_build/doctrees From 31dc582d06ceb577874e36177eb4bd8043394fe3 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:22:58 +0100 Subject: [PATCH 02/19] python/pyproject.toml (tool.cibuildwheel): Replace test-groups by test-extras. --- python/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index ace69a2c8..9ddddfa86 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -88,8 +88,8 @@ skip = [ "*_i686", # Skip 32-bit builds ] build-verbosity = 2 -# Will cause the wheel to be installed with these groups of dependencies -test-groups = [ "test" ] +# Will cause the wheel to be installed with these optional-dependencies +test-extras = [ "test" ] test-command = [ "pytest --doctest-modules --doctest-continue-on-failure {package}/tests {package}/src/moocore/_moocore.py", ] From 6f81cdfd0f1e3cc9c397562c35782fa7606af8c6 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:41:52 +0100 Subject: [PATCH 03/19] * update.bib.sh: Simplify code. Remove ids field. * python/doc/source/REFERENCES.bib, r/inst/REFERENCES.bib: Regenerate. --- python/doc/source/REFERENCES.bib | 16 ++++++++++------ r/inst/REFERENCES.bib | 16 ++++++++++------ update_bib.sh | 13 ++++++------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/python/doc/source/REFERENCES.bib b/python/doc/source/REFERENCES.bib index 89f42d001..ecfb5ed1e 100644 --- a/python/doc/source/REFERENCES.bib +++ b/python/doc/source/REFERENCES.bib @@ -200,8 +200,7 @@ @article{DiaLop2020ejor @article{DubLopStu2011amai, author = { J{\'e}r{\'e}mie Dubois-Lacoste and Manuel L{\'o}pez-Ib{\'a}{\~n}ez and Thomas St{\"u}tzle }, - title = {Improving the Anytime Behavior of Two-Phase Local - Search}, + title = {Improving the Anytime Behavior of Two-Phase Local Search}, journal = {Annals of Mathematics and Artificial Intelligence}, year = 2011, volume = 61, @@ -233,7 +232,8 @@ @article{GueFonPaq2021hv year = 2021, volume = 54, number = 6, - pages = {1--42} + pages = {1--42}, + doi = {10.1145/3453474} } @article{HerWer1987tabucol, @@ -296,6 +296,9 @@ @article{LopVerDreDoe2025 Single-objective Black-box Optimization Algorithms}, journal = {IEEE Transactions on Evolutionary Computation}, year = 2025, + volume = 29, + number = 5, + pages = {1774--1782}, annote = {Pre-print: \url{https://doi.org/10.48550/arXiv.2404.02031}}, doi = {10.1109/TEVC.2024.3462758}, abstract = {A widely accepted way to assess the performance of iterative @@ -366,10 +369,11 @@ @article{ZitThiLauFon2003:tec year = 2003, volume = 7, number = 2, - amonth = apr, pages = {117--132}, - doi = {10.1109/TEVC.2003.810758}, - annote = {Proposed the combination of quality indicators; proposed epsilon-indicator} + annote = {Proposed the combination of quality indicators; proposed + epsilon-indicator}, + amonth = apr, + doi = {10.1109/TEVC.2003.810758} } @incollection{AugBadBroZit2009gecco, diff --git a/r/inst/REFERENCES.bib b/r/inst/REFERENCES.bib index 89f42d001..ecfb5ed1e 100644 --- a/r/inst/REFERENCES.bib +++ b/r/inst/REFERENCES.bib @@ -200,8 +200,7 @@ @article{DiaLop2020ejor @article{DubLopStu2011amai, author = { J{\'e}r{\'e}mie Dubois-Lacoste and Manuel L{\'o}pez-Ib{\'a}{\~n}ez and Thomas St{\"u}tzle }, - title = {Improving the Anytime Behavior of Two-Phase Local - Search}, + title = {Improving the Anytime Behavior of Two-Phase Local Search}, journal = {Annals of Mathematics and Artificial Intelligence}, year = 2011, volume = 61, @@ -233,7 +232,8 @@ @article{GueFonPaq2021hv year = 2021, volume = 54, number = 6, - pages = {1--42} + pages = {1--42}, + doi = {10.1145/3453474} } @article{HerWer1987tabucol, @@ -296,6 +296,9 @@ @article{LopVerDreDoe2025 Single-objective Black-box Optimization Algorithms}, journal = {IEEE Transactions on Evolutionary Computation}, year = 2025, + volume = 29, + number = 5, + pages = {1774--1782}, annote = {Pre-print: \url{https://doi.org/10.48550/arXiv.2404.02031}}, doi = {10.1109/TEVC.2024.3462758}, abstract = {A widely accepted way to assess the performance of iterative @@ -366,10 +369,11 @@ @article{ZitThiLauFon2003:tec year = 2003, volume = 7, number = 2, - amonth = apr, pages = {117--132}, - doi = {10.1109/TEVC.2003.810758}, - annote = {Proposed the combination of quality indicators; proposed epsilon-indicator} + annote = {Proposed the combination of quality indicators; proposed + epsilon-indicator}, + amonth = apr, + doi = {10.1109/TEVC.2003.810758} } @incollection{AugBadBroZit2009gecco, diff --git a/update_bib.sh b/update_bib.sh index 22e7e134c..b9907f335 100755 --- a/update_bib.sh +++ b/update_bib.sh @@ -12,18 +12,17 @@ for file in $BIBFILES; do done tmpbib=$(mktemp --tmpdir tmpXXXXXXXXXX.bib) keys=$(paste -d '#' -s bibkeys.txt | sed 's/#/\\\|/g') -bib2bib --warn-error --expand --expand-xrefs --no-comment --expand-xrefs $BIBFILES --remove pdf --remove alias -c "(\$key : \"$keys\")" -ob $tmpbib -oc /dev/null +bib2bib --warn-error --expand --expand-xrefs --no-comment --expand-xrefs $BIBFILES --remove pdf --remove ids -c "(\$key : \"$keys\")" -ob $tmpbib -oc /dev/null if [ ! -s "${tmpbib}" ]; then echo "error: ${tmpbib} is empty! keys:= $keys" exit 1 fi # Workaround https://github.com/GeoBosh/rbibutils/issues/9 -sed -i 's#\\slash #~/ #g' $tmpbib -sed -i 's#\\hspace{0pt}#{}{}{}#g' $tmpbib -# Work around broken URL: -sed -i 's%researchrepository.napier.ac.uk/id/eprint/3044%lopez-ibanez.eu/publications#LopezIbanezPhD%g' $tmpbib +sed -i -e 's#\\slash #~/ #g' \ + -e 's#\\hspace{0pt}#{}{}{}#g' \ + -e 's%researchrepository.napier.ac.uk/id/eprint/3044%lopez-ibanez.eu/publications#LopezIbanezPhD%g' \ + $tmpbib comment='% DO NOT EDIT THIS FILE. It is auto-generated by "update_bib.sh".' -PYTHON_DOC_DIR="./python/doc/source" echo $comment | cat --squeeze-blank - $tmpbib > r/inst/REFERENCES.bib -echo $comment | cat --squeeze-blank - $tmpbib > $PYTHON_DOC_DIR/REFERENCES.bib +cp --force r/inst/REFERENCES.bib ./python/doc/source/REFERENCES.bib rm -f $BIBFILES $tmpbib From 7c77c19268f5c26f7c09cf95180949af1d185ef7 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:48:53 +0100 Subject: [PATCH 04/19] .pre-commit-config.yaml: Fix roxygenize hook. --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d6062d98d..2199e5089 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: args: [--root=r/] exclude: '(do\.R|vignettes/articles/.+\.Rmd)' - id: roxygenize - args: [--root=] + args: [--root=r/] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 From 281fd3c864b73949117536364cb6eab48e6bd295 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:53:24 +0100 Subject: [PATCH 05/19] .pre-commit-config.yaml: Fix roxygenize hook. --- .pre-commit-config.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2199e5089..9f2d2bd4d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,10 +14,13 @@ repos: - id: no-print-statement - id: no-debug-statement - id: deps-in-desc - args: [--root=r/] + args: [--root=./r/] exclude: '(do\.R|vignettes/articles/.+\.Rmd)' - id: roxygenize - args: [--root=r/] + args: [--root=./r/] + additional_dependencies: + - doctest + - Rdpack - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 From c070f6d86ddadb7a297c6b97710fb1f83543d229 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Thu, 16 Oct 2025 14:55:12 +0100 Subject: [PATCH 06/19] Improve documentation of `generate_ndset()` in R and Python --- python/src/moocore/_moocore.py | 10 +++++----- r/R/generate.R | 11 +++++------ r/man/generate_ndset.Rd | 11 +++++------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/python/src/moocore/_moocore.py b/python/src/moocore/_moocore.py index 0894c730f..44c5d6e3b 100644 --- a/python/src/moocore/_moocore.py +++ b/python/src/moocore/_moocore.py @@ -1024,9 +1024,9 @@ def generate_ndset( :footcite:p:`RubMel1998simulation`. Values sampled from the exponential distribution are guaranteed to be positive. - Sampling from either the standard normal distribution, as suggested by - :footcite:t:`GueFonPaq2021hv`, or the uniform distribution, as suggested by - :footcite:t:`LacKlaFon2017box`, does not produce a uniform distribution + Sampling from either the standard normal distribution + :footcite:p:`GueFonPaq2021hv` or the uniform distribution + :footcite:p:`LacKlaFon2017box` does not produce a uniform distribution when projected into the simplex. Method ``"concave-sphere"`` uniformly samples points on the positive @@ -1038,8 +1038,8 @@ def generate_ndset( :math:`z_i = \frac{|x_i|}{\|\vec{x}\|_2}` :footcite:p:`Muller1959sphere`. The absolute value in the numerator ensures that points are sampled on the positive orthant of the hyper-sphere. - Sampling from the uniform distribution, as suggested by - :footcite:t:`LacKlaFon2017box`, does not result in a uniform sampling when + Sampling from the uniform distribution :footcite:p:`LacKlaFon2017box` + does not result in a uniform sampling when projected onto the surface of the hyper-sphere. Method ``"convex-sphere"`` is quivalent to ``1 - generate_ndset(..., diff --git a/r/R/generate.R b/r/R/generate.R index 87b3e890c..103242ebb 100644 --- a/r/R/generate.R +++ b/r/R/generate.R @@ -42,10 +42,9 @@ #' \eqn{z_i = x_i / \sum_{i=1}^d x_i} \citep{RubMel1998simulation}. Values #' sampled from the exponential distribution are guaranteed to be positive. #' -#' Sampling from either the standard normal distribution, as suggested by -#' \citet{GueFonPaq2021hv}, or the uniform distribution, as suggested by -#' \citet{LacKlaFon2017box}, does not produce a uniform distribution when -#' projected into the simplex. +#' Sampling from either the standard normal distribution +#' \citep{GueFonPaq2021hv} or the uniform distribution \citep{LacKlaFon2017box} +#' does not produce a uniform distribution when projected into the simplex. #' #' Method `"concave-sphere"` uniformly samples points on the positive orthant #' of the hyper-sphere, which is concave when all objectives are minimised. @@ -55,8 +54,8 @@ #' then dividing each value by the l2-norm of the vector, \eqn{z_i = #' \frac{|x_i|}{\|\vec{x}\|_2}} \citep{Muller1959sphere}. The absolute value in #' the numerator ensures that points are sampled on the positive orthant of the -#' hyper-sphere. Sampling from the uniform distribution, as suggested by -#' \citet{LacKlaFon2017box}, does not result in a uniform sampling when +#' hyper-sphere. Sampling from the uniform distribution +#' \citep{LacKlaFon2017box} does not result in a uniform sampling when #' projected onto the surface of the hyper-sphere. #' #' Method `"convex-sphere"` is quivalent to `1 - generate_ndset(..., diff --git a/r/man/generate_ndset.Rd b/r/man/generate_ndset.Rd index 421d28b08..1f3a60226 100644 --- a/r/man/generate_ndset.Rd +++ b/r/man/generate_ndset.Rd @@ -55,10 +55,9 @@ distribution, then dividing each value by the L1-norm of the vector, \eqn{z_i = x_i / \sum_{i=1}^d x_i} \citep{RubMel1998simulation}. Values sampled from the exponential distribution are guaranteed to be positive. -Sampling from either the standard normal distribution, as suggested by -\citet{GueFonPaq2021hv}, or the uniform distribution, as suggested by -\citet{LacKlaFon2017box}, does not produce a uniform distribution when -projected into the simplex. +Sampling from either the standard normal distribution +\citep{GueFonPaq2021hv} or the uniform distribution \citep{LacKlaFon2017box} +does not produce a uniform distribution when projected into the simplex. Method \code{"concave-sphere"} uniformly samples points on the positive orthant of the hyper-sphere, which is concave when all objectives are minimised. @@ -68,8 +67,8 @@ sampling \eqn{d} independent and identically distributed values then dividing each value by the l2-norm of the vector, \eqn{z_i = \frac{|x_i|}{\|\vec{x}\|_2}} \citep{Muller1959sphere}. The absolute value in the numerator ensures that points are sampled on the positive orthant of the -hyper-sphere. Sampling from the uniform distribution, as suggested by -\citet{LacKlaFon2017box}, does not result in a uniform sampling when +hyper-sphere. Sampling from the uniform distribution +\citep{LacKlaFon2017box} does not result in a uniform sampling when projected onto the surface of the hyper-sphere. Method \code{"convex-sphere"} is quivalent to \code{1 - generate_ndset(..., method="concave-sphere")}, which is convex for minimisation problems. It From e6513677d5a20435f4cca4b421c304f5a71a9312 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:02:38 +0100 Subject: [PATCH 07/19] * python/pyproject.toml: Build universal2 for macos, native wheels for the rest. * .github/workflows/python.yml: Simplify wheels job. Build ubuntu-22.04-arm. --- .github/workflows/python.yml | 16 ++++------------ python/pyproject.toml | 18 +++++++----------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 8048b2242..5169d2eff 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -202,10 +202,11 @@ jobs: matrix: # FIXME: add windows-11-arm and ubuntu-24.04-arm # https://github.com/scipy/scipy/blob/6b79a4dec1f9ca2db4e49c328d04d293880991c6/.github/workflows/wheels.yml#L78 - # macos-14 is apple silicon - os: [ubuntu-22.04, windows-2025, macos-14] + # https://github.com/numpy/numpy-release/blob/main/.github/workflows/wheels.yml + # macos-14 is Apple Silicon (arm64), but we build an universal2 wheel. + # The configuration of cibuildwheel can be found in pyproject.toml + os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2025, macos-14] python-version: ['3.10'] - CIBW_ARCHS_MACOS: ['universal2'] steps: - uses: actions/checkout@v5 @@ -215,17 +216,8 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Set up QEMU - if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - - name: Build wheels uses: pypa/cibuildwheel@v2.23.3 - env: - CIBW_ARCHS_MACOS: ${{ matrix.CIBW_ARCHS_MACOS }} - CIBW_TEST_SKIP: ${{ matrix.CIBW_TEST_SKIP }} with: package-dir: python output-dir: wheelhouse diff --git a/python/pyproject.toml b/python/pyproject.toml index 9ddddfa86..73941ff4e 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -93,14 +93,14 @@ test-extras = [ "test" ] test-command = [ "pytest --doctest-modules --doctest-continue-on-failure {package}/tests {package}/src/moocore/_moocore.py", ] -test-skip = "*-*linux_{aarch64,ppc64le,s390x}" +#test-skip = "*-*linux_{aarch64,ppc64le,s390x}" [tool.cibuildwheel.linux] -archs = [ - "x86_64", - # "aarch64", FAILS doctests -] +archs = [ "native" ] manylinux-x86_64-image = "manylinux_2_28" +manylinux-aarch64-image = "manylinux_2_28" +musllinux-x86_64-image = "musllinux_1_2" +musllinux-aarch64-image = "musllinux_1_2" # Use abi3audit to catch issues with Limited API wheels repair-wheel-command = [ "auditwheel repair -w {dest_dir} {wheel}", @@ -108,9 +108,7 @@ repair-wheel-command = [ ] [tool.cibuildwheel.windows] -archs = [ - "AMD64", -] +archs = [ "native" ] # Use delvewheel on windows before-build = "pip install delvewheel" repair-wheel-command = [ @@ -119,9 +117,7 @@ repair-wheel-command = [ ] [tool.cibuildwheel.macos] -archs = [ - "universal2", -] +archs = [ "universal2" ] repair-wheel-command = [ "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}", # "pipx run abi3audit --verbose --strict --report {wheel}", From 9767862aac0de36af91b6ff081d93cab05452973 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:16:36 +0100 Subject: [PATCH 08/19] * python/benchmarks/bench_ndom.py: Make sure that numba is available. * python/benchmarks/python-requirements.txt: Add numba, sort lines. --- python/benchmarks/bench_ndom.py | 4 ++-- python/benchmarks/python-requirements.txt | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/python/benchmarks/bench_ndom.py b/python/benchmarks/bench_ndom.py index aa81f4f2f..ed4f90f38 100644 --- a/python/benchmarks/bench_ndom.py +++ b/python/benchmarks/bench_ndom.py @@ -65,7 +65,7 @@ def get_dataset(name): z, maximise=True, keep_weakly=False ), "botorch": lambda z: botorch_is_nondominated(z, deduplicate=True), - "paretoset": lambda z: paretoset( + "paretoset (numba)": lambda z: paretoset( z, sense=z.shape[1] * ["max"], distinct=True, use_numba=True ), }, @@ -116,7 +116,7 @@ def get_dataset(name): "botorch": lambda z: bool2pos( botorch_is_nondominated(z, deduplicate=False) ), - "paretoset": lambda z: bool2pos( + "paretoset (numba)": lambda z: bool2pos( paretoset( z, sense=z.shape[1] * ["max"], diff --git a/python/benchmarks/python-requirements.txt b/python/benchmarks/python-requirements.txt index 33fe23d4c..bf2dcd640 100644 --- a/python/benchmarks/python-requirements.txt +++ b/python/benchmarks/python-requirements.txt @@ -1,10 +1,11 @@ +botorch cpuinfo +desdeo +jmetal +matplotlib +nevergrad +numba numpy pandas -matplotlib -botorch -pymoo -jmetal -desdeo paretoset -nevergrad +pymoo From 3f3dee90fe1a61d865db97a8955bb30b44ac6292 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:17:15 +0100 Subject: [PATCH 09/19] * .github/workflows/python.yml: Build wheels for windows_arm64. * .github/windows_arm64_steps/action.yml: New. --- .github/windows_arm64_steps/action.yml | 22 ++++++++++++++++++++++ .github/workflows/python.yml | 9 +++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .github/windows_arm64_steps/action.yml diff --git a/.github/windows_arm64_steps/action.yml b/.github/windows_arm64_steps/action.yml new file mode 100644 index 000000000..14b7f41a1 --- /dev/null +++ b/.github/windows_arm64_steps/action.yml @@ -0,0 +1,22 @@ +name: Build Dependencies(Win-ARM64) +description: "Setup LLVM for Win-ARM64 builds" +# https://github.com/numpy/numpy-release/blob/295d6a70a867972774ff05ae98d7a560a659e2b4/.github/windows_arm64_steps/action.yml + +runs: + using: "composite" + steps: + - name: Install LLVM with checksum verification + shell: pwsh + run: | + Invoke-WebRequest https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.6/LLVM-20.1.6-woa64.exe -UseBasicParsing -OutFile LLVM-woa64.exe + $expectedHash = "92f69a1134e32e54b07d51c6e24d9594852f6476f32c3d70471ae00fffc2d462" + $fileHash = (Get-FileHash -Path "LLVM-woa64.exe" -Algorithm SHA256).Hash + if ($fileHash -ne $expectedHash) { + Write-Error "Checksum verification failed. The downloaded file may be corrupted or tampered with." + exit 1 + } + Start-Process -FilePath ".\LLVM-woa64.exe" -ArgumentList "/S" -Wait + echo "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "CC=clang-cl" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "CXX=clang-cl" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "FC=flang-new" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 5169d2eff..76f3f73e3 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -98,7 +98,7 @@ jobs: - name: Publish artifacts uses: actions/upload-artifact@v4 with: - name: moocore-wheels-${{ matrix.os }}-${{ matrix.python-version }} + name: moocore-wheels-sdist-${{ matrix.os }}-${{ matrix.python-version }} path: python/dist/*.tar.gz build-doc: @@ -205,7 +205,7 @@ jobs: # https://github.com/numpy/numpy-release/blob/main/.github/workflows/wheels.yml # macos-14 is Apple Silicon (arm64), but we build an universal2 wheel. # The configuration of cibuildwheel can be found in pyproject.toml - os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2025, macos-14] + os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2025, windows-11-arm, macos-14] python-version: ['3.10'] steps: @@ -215,6 +215,11 @@ jobs: uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Setup LLVM for Windows ARM64 + if: ${{ matrix.os == 'windows-11-arm' }} + uses: ./.github/windows_arm64_steps - name: Build wheels uses: pypa/cibuildwheel@v2.23.3 From b9170b64a5e7fbfb6eee02307e2b9d24282c7b15 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:35:00 +0100 Subject: [PATCH 10/19] .github/workflows/python.yml: Use Python 3.11 for Windows ARM64. --- .github/workflows/python.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 76f3f73e3..dfd76f0be 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -205,8 +205,12 @@ jobs: # https://github.com/numpy/numpy-release/blob/main/.github/workflows/wheels.yml # macos-14 is Apple Silicon (arm64), but we build an universal2 wheel. # The configuration of cibuildwheel can be found in pyproject.toml - os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2025, windows-11-arm, macos-14] + os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2025, macos-14] python-version: ['3.10'] + include: + # 3.11 is the earliest version on windows-arm + - os: windows-11-arm + python-version: "3.11" steps: - uses: actions/checkout@v5 From a7507ed549d42a91851c6f67b8767c5a281178cb Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:12:31 +0100 Subject: [PATCH 11/19] .github/workflows/python.yml: Simplify. --- .github/workflows/python.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index dfd76f0be..baa90411b 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -95,6 +95,7 @@ jobs: run: python3 -m build working-directory: python + # This is needed for publishing to PyPI - name: Publish artifacts uses: actions/upload-artifact@v4 with: @@ -130,13 +131,8 @@ jobs: run: python3 -m build working-directory: python - - name: install the package - run: python3 -m pip install . - working-directory: python - - - name: install the doc build requirements - run: | - python3 -m pip install .[docs] + - name: Install the package and the doc build requirements + run: python3 -m pip install .[docs] working-directory: python - name: Build the docs 🔧 @@ -160,7 +156,6 @@ jobs: name: Coverage ${{ matrix.os }} (${{ matrix.python-version }}) runs-on: ${{ matrix.os }} strategy: - # When set to true, GitHub cancels all in-progress jobs if any matrix job fails. matrix: os: [ubuntu-latest] python-version: ['3.10'] From 1664f361f5134bf103ada87012a9e12f9b653a70 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:13:08 +0100 Subject: [PATCH 12/19] python/doc/source/whatsnew/index.rst: Document new wheels. --- python/doc/source/whatsnew/index.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/python/doc/source/whatsnew/index.rst b/python/doc/source/whatsnew/index.rst index d0144e3a1..49780a49f 100644 --- a/python/doc/source/whatsnew/index.rst +++ b/python/doc/source/whatsnew/index.rst @@ -7,15 +7,20 @@ What's new Version 0.1.9 (dev) ------------------- -- :func:`~moocore.hv_contributions` ignores dominated points by default. Set ``ignore_dominated=False`` to restore the previous behavior. The 3D case uses the HVC3D algorithm. +- :func:`~moocore.hv_contributions` ignores dominated points by default. + Set ``ignore_dominated=False`` to restore the previous behavior. + The 3D case uses the HVC3D algorithm. - New function :func:`~moocore.any_dominated` to quickly detect if a set is nondominated. - New function :func:`~moocore.generate_ndset` to generate random nondominated sets with different shapes. - New example :ref:`sphx_glr_auto_examples_plot_generate.py`. -- :func:`~moocore.is_nondominated`, :func:`~moocore.any_dominated`, :func:`~moocore.pareto_rank` now handle single-objective inputs correctly (:issue:`27`, :issue:`29`). +- :func:`~moocore.is_nondominated`, :func:`~moocore.any_dominated`, + :func:`~moocore.pareto_rank` now handle single-objective inputs correctly (:issue:`27`, :issue:`29`). - Ranks returned by :func:`~moocore.pareto_rank` are 0-based. - :func:`~moocore.is_nondominated` and :func:`~moocore.filter_dominated` are faster for dimensions larger than 3. +- ``moocore`` wheels are now built for ``aarch64`` (ARM64) in Linux and Windows. + See the `installation instructions `_. Version 0.1.8 (15/07/2025) -------------------------- From 6ec7c6eb7c0cb9e29276809d53a21723dfbd2619 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:13:44 +0100 Subject: [PATCH 13/19] * python/src/moocore/_ffi_build.py: Build C code with /arch:AVX on Windows and -march=x86-64-v2 on x86-64 Linux and MacOS to enable basic vectorization. --- python/src/moocore/_ffi_build.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/python/src/moocore/_ffi_build.py b/python/src/moocore/_ffi_build.py index 3f120aec8..7f8990438 100644 --- a/python/src/moocore/_ffi_build.py +++ b/python/src/moocore/_ffi_build.py @@ -47,9 +47,6 @@ sources = [sources_path + f for f in sources] -is_windows = platform.system() == "Windows" - - def get_config(): from distutils.core import Distribution from distutils.sysconfig import get_config_vars @@ -64,8 +61,8 @@ def uses_msvc(): return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif') -# Try to detect cross-compilation. -def _get_target_platform(arch_flags, default): +def _get_target_platform(): + arch_flags = os.environ.get("ARCHFLAGS", "") flags = [f for f in arch_flags.split(" ") if f.strip() != ""] try: pos = flags.index("-arch") @@ -74,9 +71,14 @@ def _get_target_platform(arch_flags, default): except ValueError: pass - return default + return platform.machine() +is_windows = platform.system() == "Windows" +target_platform = _get_target_platform() +is_x86_64 = target_platform in ("i686", "x86", "x86_64", "AMD64") + +# Compiler flags. MSVC_CFLAGS = ["/GL", "/O2", "/GS-", "/wd4996"] MSVC_LDFLAGS = ["/LTCG"] GCC_CFLAGS = ["-flto", "-O3"] @@ -86,17 +88,14 @@ def _get_target_platform(arch_flags, default): if is_windows and uses_msvc(): extra_compile_args.extend(MSVC_CFLAGS) extra_link_args.extend(MSVC_LDFLAGS) + if is_x86_64: + extra_compile_args.append("/arch:AVX") else: extra_compile_args.extend(GCC_CFLAGS) extra_link_args.extend(GCC_CFLAGS) - target_platform = _get_target_platform( - os.environ.get("ARCHFLAGS", ""), platform.machine() - ) - # Optimized version requires SSE2 extensions. They have been around since - # 2001 so we try to compile it on every recent-ish x86. - sse2 = target_platform in ("i686", "x86", "x86_64", "AMD64") - if sse2: - extra_compile_args.append("-msse2") + # Compile for sufficiently old x86-64 architecture. + if is_x86_64: + extra_compile_args.append("-march=x86-64-v2") cflags = os.environ.get("CFLAGS", "") if cflags != "": From 29936d303a3a350fe7866f3ec53211f357b3a505 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:23:13 +0100 Subject: [PATCH 14/19] python/src/moocore/_ffi_build.py: Add /DMOOCORE_SHARED_LIB to MSVC_CFLAGS. --- python/src/moocore/_ffi_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/moocore/_ffi_build.py b/python/src/moocore/_ffi_build.py index 7f8990438..d80ab7fc9 100644 --- a/python/src/moocore/_ffi_build.py +++ b/python/src/moocore/_ffi_build.py @@ -79,7 +79,7 @@ def _get_target_platform(): is_x86_64 = target_platform in ("i686", "x86", "x86_64", "AMD64") # Compiler flags. -MSVC_CFLAGS = ["/GL", "/O2", "/GS-", "/wd4996"] +MSVC_CFLAGS = ["/GL", "/O2", "/GS-", "/wd4996", "/DMOOCORE_SHARED_LIB"] MSVC_LDFLAGS = ["/LTCG"] GCC_CFLAGS = ["-flto", "-O3"] From 7c3602e2a6899fe2e38b8d15b7e102155fad4e60 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:07:09 +0100 Subject: [PATCH 15/19] pyproject.toml: Run abi3audit on wheels. --- python/pyproject.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index 73941ff4e..658c4fef1 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -86,6 +86,8 @@ skip = [ "*_ppc64le", "*_s390x", "*_i686", # Skip 32-bit builds + "cp313t-*", + "cp314t-*", # Skip free-threaded builds ] build-verbosity = 2 # Will cause the wheel to be installed with these optional-dependencies @@ -104,7 +106,7 @@ musllinux-aarch64-image = "musllinux_1_2" # Use abi3audit to catch issues with Limited API wheels repair-wheel-command = [ "auditwheel repair -w {dest_dir} {wheel}", - # "pipx run abi3audit --verbose --strict --report {wheel}", + "pipx run abi3audit --verbose --strict --report {wheel}", ] [tool.cibuildwheel.windows] @@ -113,14 +115,14 @@ archs = [ "native" ] before-build = "pip install delvewheel" repair-wheel-command = [ "delvewheel repair -w {dest_dir} {wheel}", - # "pipx run abi3audit --verbose --strict --report {wheel}", + "pipx run abi3audit --verbose --strict --report {wheel}", ] [tool.cibuildwheel.macos] archs = [ "universal2" ] repair-wheel-command = [ "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}", - # "pipx run abi3audit --verbose --strict --report {wheel}", + "pipx run abi3audit --verbose --strict --report {wheel}", ] [tool.ruff] From 10b2405155ed68c4a97ac550902627736791a407 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:35:12 +0100 Subject: [PATCH 16/19] enabled abi3audit --- python/pyproject.toml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index 658c4fef1..6fefe3ef0 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -104,25 +104,27 @@ manylinux-aarch64-image = "manylinux_2_28" musllinux-x86_64-image = "musllinux_1_2" musllinux-aarch64-image = "musllinux_1_2" # Use abi3audit to catch issues with Limited API wheels +before-build = "pip install abi3audit" repair-wheel-command = [ "auditwheel repair -w {dest_dir} {wheel}", - "pipx run abi3audit --verbose --strict --report {wheel}", + "abi3audit --verbose --strict --report {wheel}", ] [tool.cibuildwheel.windows] archs = [ "native" ] # Use delvewheel on windows -before-build = "pip install delvewheel" +before-build = "pip install delvewheel abi3audit" repair-wheel-command = [ "delvewheel repair -w {dest_dir} {wheel}", - "pipx run abi3audit --verbose --strict --report {wheel}", + "abi3audit --verbose --strict --report {wheel}", ] [tool.cibuildwheel.macos] archs = [ "universal2" ] +before-build = "pip install abi3audit" repair-wheel-command = [ "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}", - "pipx run abi3audit --verbose --strict --report {wheel}", + "abi3audit --verbose --strict --report {wheel}", ] [tool.ruff] From f7253138df20a391e8b0404dcf7d441c519ce8d4 Mon Sep 17 00:00:00 2001 From: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:35:45 +0100 Subject: [PATCH 17/19] Bump cibuildwheel to v3.2.1 --- .github/workflows/python.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index baa90411b..51c826c0d 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -216,12 +216,12 @@ jobs: python-version: ${{ matrix.python-version }} cache: 'pip' - - name: Setup LLVM for Windows ARM64 + - name: Setup LLVM for Windows ARM64 (NOT WORKING/FIXME) if: ${{ matrix.os == 'windows-11-arm' }} uses: ./.github/windows_arm64_steps - name: Build wheels - uses: pypa/cibuildwheel@v2.23.3 + uses: pypa/cibuildwheel@v3.2.1 with: package-dir: python output-dir: wheelhouse From 7da3108855d9f7189104a944d1cb8c9856387023 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:53:05 +0000 Subject: [PATCH 18/19] Initial plan From c69566e4e6abbbd482971e883ed2237e16319207 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:04:57 +0000 Subject: [PATCH 19/19] Fix limited-API (abi3) wheels configuration Co-authored-by: MLopez-Ibanez <2620021+MLopez-Ibanez@users.noreply.github.com> --- python/setup.py | 16 +++++++++------- python/src/moocore/_ffi_build.py | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/python/setup.py b/python/setup.py index 40c41b354..ac7925f0b 100644 --- a/python/setup.py +++ b/python/setup.py @@ -3,17 +3,19 @@ from wheel.bdist_wheel import bdist_wheel as _bdist_wheel -class bdist_wheel_abi_none(_bdist_wheel): +class bdist_wheel_abi3(_bdist_wheel): def finalize_options(self): _bdist_wheel.finalize_options(self) - self.root_is_pure = False - - def get_tag(self): - _python, _abi, plat = _bdist_wheel.get_tag(self) - return "py3", "none", plat + # Automatically detect py_limited_api from extension modules + if not self.py_limited_api: + for ext in self.distribution.ext_modules or []: + if getattr(ext, "py_limited_api", False): + # Use cp310 as the minimum Python version for abi3 + self.py_limited_api = "cp310" + break setup( cffi_modules=["src/moocore/_ffi_build.py:ffibuilder"], - cmdclass={"bdist_wheel": bdist_wheel_abi_none}, + cmdclass={"bdist_wheel": bdist_wheel_abi3}, ) diff --git a/python/src/moocore/_ffi_build.py b/python/src/moocore/_ffi_build.py index d80ab7fc9..a7d53c1a7 100644 --- a/python/src/moocore/_ffi_build.py +++ b/python/src/moocore/_ffi_build.py @@ -118,7 +118,8 @@ def _get_target_platform(): sources=sources, include_dirs=[libmoocore_path], extra_compile_args=extra_compile_args, - extra_link_args=extra_compile_args, + extra_link_args=extra_link_args, + py_limited_api=True, ) if __name__ == "__main__":