Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
53ece9f
Start development of v0.2.0
MLopez-Ibanez Nov 2, 2025
8f89f5e
c/hv4d.c (restart_base_setup_z_and_closest): Simplify. Help autovecto…
MLopez-Ibanez Oct 31, 2025
09b4186
c/eaf.c (eaf_check_polygons): Do not call polygons_intersect() twice.
MLopez-Ibanez Nov 1, 2025
faa5579
README.md, c/README.md: Fix testsuite badge.
MLopez-Ibanez Nov 2, 2025
2b29d73
* python/src/moocore/_utils.py (_get_seed_for_c): New.
MLopez-Ibanez Nov 2, 2025
2224a59
* python/tests/test_moocore.py (test_hv_approx_default_seed): New test.
MLopez-Ibanez Nov 2, 2025
dd1ddbb
* c/hv_priv.h (init_sentinels): Make sure HV_DIMENSION is correct.
MLopez-Ibanez Nov 2, 2025
9f4c5de
* c/mt19937/mt19937.c (mt19937_init_by_array,init_genrand): Remove u…
MLopez-Ibanez Nov 3, 2025
5d5a7df
c/Makefile (clean): Clean .i and .s.
MLopez-Ibanez Nov 3, 2025
0232647
c/epsilon.c: Fix error message.
MLopez-Ibanez Nov 3, 2025
b899ffc
c/epsilon.h: Use _attr_optimize_finite_math. Improve function special…
MLopez-Ibanez Nov 3, 2025
5ee51d1
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Nov 3, 2025
ccb2dd8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 3, 2025
d443ecf
r/DESCRIPTION: Edit Description.
MLopez-Ibanez Nov 4, 2025
8290a66
c/hvapprox.c: Simplify ASSUME conditions.
MLopez-Ibanez Nov 4, 2025
f28adef
README.md: Mention QuantumAnnealingMOO.
MLopez-Ibanez Nov 4, 2025
958a090
README.md: Mention IOHinspector
MLopez-Ibanez Nov 5, 2025
3dff60b
* python/doc/source/whatsnew/index.rst: Fix link.
MLopez-Ibanez Nov 6, 2025
f40e169
* c/whv.c (print_point): Rename to debug_print_point.
MLopez-Ibanez Nov 5, 2025
cdde0c8
c/hv_priv.h: Use restrict for x.
MLopez-Ibanez Nov 7, 2025
3654bd6
c/hv4d.c: Remove unlikely.
MLopez-Ibanez Nov 11, 2025
d570c48
* c/gcc.mk: Add notes about GCC options.
MLopez-Ibanez Nov 12, 2025
8b8e97d
c/hv.c: Remove unused code.
MLopez-Ibanez Nov 5, 2025
52d521b
c/hv.c (fpli_setup_cdllist): Simplify.
MLopez-Ibanez Nov 11, 2025
da0f2f7
c/hv.c: Separate fpli_hv_ge5d() from hv_recursive(). Add debug counters.
MLopez-Ibanez Nov 6, 2025
ccba320
* c/gcc_attribs.h (ASAN_POISON_MEMORY_REGION): New.
MLopez-Ibanez Nov 13, 2025
7eef75e
* c/hv.c: Merge fpli_dlnode_t into dlnode_t.
MLopez-Ibanez Nov 13, 2025
bdc4689
DEVEL-README.md, c/README.md: More details about building and testing.
MLopez-Ibanez Nov 14, 2025
eaa51e8
Compute a 4D hv contribution in the base case.
apguerreiro Nov 25, 2025
f11a07f
* hv4d_priv.h: Add return type.
MLopez-Ibanez Nov 26, 2025
66cfa22
hv4d_priv.h: Simplify code and add comments.
MLopez-Ibanez Nov 26, 2025
f00321c
hv4d_priv.h: Add a few comments.
MLopez-Ibanez Nov 26, 2025
96a7aa4
hv4d_priv.h: Use weakly_dominates().
MLopez-Ibanez Nov 28, 2025
7141650
hv4d_priv.h: Online restore if ignore < 3.
MLopez-Ibanez Nov 28, 2025
b4dc3a7
Improve the 4D base case of FPL:
apguerreiro Dec 11, 2025
025dd67
*c/hv4d_priv.h: Remove assert and fix minor bug.
apguerreiro Dec 12, 2025
3ef5f2d
* c/hv.c: Use ->vol instead of ->x for the auxiliary vectors.
MLopez-Ibanez Dec 12, 2025
5639151
Few minor cleanups
MLopez-Ibanez Dec 13, 2025
15055a7
Add documentation.
MLopez-Ibanez Dec 13, 2025
1731299
more simplifications
MLopez-Ibanez Dec 13, 2025
63d2faa
avoid newp != the_point.
MLopez-Ibanez Dec 13, 2025
50f8bf8
more cleanups
MLopez-Ibanez Dec 13, 2025
139c27e
hv4d_priv.h: Move newp_aux++ within the if().
MLopez-Ibanez Dec 15, 2025
bb2ec51
hv4d_priv.h: Avoid warning with DEBUG=0.
MLopez-Ibanez Dec 15, 2025
3b2089b
* c/hv4d_priv.h: Fix bug related to repeated coordinates.
apguerreiro Dec 17, 2025
a2f88fa
hv4d_priv.h: Detect dominated points and set ignore to 3.
apguerreiro Dec 18, 2025
94559a0
Bump R version to 4.1
MLopez-Ibanez Dec 29, 2025
8eff865
* hv.c: Add FORCE_BUG.
MLopez-Ibanez Dec 30, 2025
11ccef9
*c/hv4d_priv.h: Fix bug related to repeated coordinates
apguerreiro Jan 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/R.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ jobs:
os: [ ubuntu-22.04, windows-latest, macos-15-intel, macos-14 ]
r: [ release ]
include:
# Use 4.0 to check with rtools40's older compiler
- { os: windows-latest, r: '4.0' }
- { os: windows-latest, r: '4.1' }
# Use latest ubuntu to make it easier to install dependencies
- { os: ubuntu-24.04, r: 'devel', http-user-agent: 'release' }
env:
Expand Down
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ci:

repos:
- repo: https://github.com/lorenzwalthert/precommit
rev: v0.4.3.9014
rev: v0.4.3.9017
hooks:
- id: parsable-R
- id: no-browser-statement
Expand Down Expand Up @@ -43,19 +43,19 @@ repos:
exclude: '(\.Rd|python/doc/source/reference/.*|test-doctest-.*)'

- repo: https://github.com/tox-dev/tox-ini-fmt
rev: "1.6.0"
rev: "1.7.0"
hooks:
- id: tox-ini-fmt

- repo: https://github.com/tox-dev/pyproject-fmt
rev: "v2.6.0"
rev: "v2.11.0"
hooks:
- id: pyproject-fmt
additional_dependencies: ["tox>=4.12.1"]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.13.0
rev: v0.14.3
hooks:
# Run the formatter.
- id: ruff-format
Expand All @@ -67,6 +67,6 @@ repos:
require_serial: true

- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.0
rev: v1.0.1
hooks:
- id: sphinx-lint
26 changes: 26 additions & 0 deletions DEVEL-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,32 @@ How to release
1. `git ci -a -m "Start development of v{NEW_VERSION}"`


Building the code
=================

C code
-----

See [*Compilation*](https://github.com/multi-objective/moocore/tree/main/c#compilation) to compile the C code under `c/`.

R and Python packages
---------------------

Under `r/` or `python/`, the commands `make build` and `make install` will build and install the R and Python packages.


Testing
========

The C code and the Python and R packages have their own testsuites. See [C testsuite](https://github.com/multi-objective/moocore/tree/main/c#testsuite) to setup and run the C testsuite.

The Python and R testsuites are run automatically via Github Actions for every push and pull request. You can run then manually by running `make test` under `r/` or `python/`.

You can run all testsuites at once by executing at the top-level:

make test


How to extend the Python API
============================

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PACKAGEVERSION=0.1.9
PACKAGEVERSION=0.2.0

.PHONY: default clean check test pre-commit

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ The following projects currently use `moocore`:
- [`pymoo`](https://pymoo.org/)
- [`Liger`](https://www.ide.uk/project-liger)
- [`DESDEO`](https://github.com/industrial-optimization-group/DESDEO/)
- [`IOHInspector`](https://github.com/IOHprofiler/IOHinspector?tab=readme-ov-file)
- [QuantumAnnealingMOO](https://github.com/andrew-d-king/QuantumAnnealingMOO) (D-Wave Quantum Inc)



[c-build-badge]: https://github.com/multi-objective/moocore/actions/workflows/C.yml/badge.svg?event=push
Expand All @@ -79,5 +82,5 @@ The following projects currently use `moocore`:
[r-universe-build-link]: https://github.com/r-universe/multi-objective/actions/workflows/build.yml
[r-universe-version]: https://multi-objective.r-universe.dev/moocore
[r-universe-version-badge]: https://multi-objective.r-universe.dev/badges/moocore
[testsuite-badge]: https://github.com/multi-objective/testsuite/actions/workflows/moocore.yml/badge.svg?event=push
[testsuite-badge]: https://github.com/multi-objective/testsuite/actions/workflows/moocore.yml/badge.svg
[testsuite-link]: https://github.com/multi-objective/testsuite/actions/workflows/moocore.yml
4 changes: 3 additions & 1 deletion c/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#-----------------------------------------------------------------------
# Makefile for moocore
#-----------------------------------------------------------------------
VERSION = 0.17.0
VERSION = 0.17.0$(REVISION)

S=
## Quiet / verbose output:
Expand Down Expand Up @@ -96,6 +96,7 @@ HDRS = avl.h \
hvapprox.h \
hv_priv.h \
hv3d_priv.h \
hv4d_priv.h \
igd.h \
io.h \
io_priv.h \
Expand Down Expand Up @@ -224,6 +225,7 @@ $(CXXSHLIB): $(LIBHV_OBJS)
$(CXX) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^ $(SHLIB_LDFLAGS)

clean:
@-$(RM) *.s *.i
@-$(RM) config.status config.log
@-$(RM) Hypervolume_MEX.mex
@-$(RM) $(SHLIB) $(CXXSHLIB)
Expand Down
21 changes: 17 additions & 4 deletions c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ This uses the option `"-march=native"`. If your GCC version does not support `"n

make all MARCH=x86-64-v2

See the [GCC manual](https://gcc.gnu.org/onlinedocs/gcc/Submodel-Options.html** for the names of the architectures supported by your version of GCC.
See the [GCC manual](https://gcc.gnu.org/onlinedocs/gcc/Submodel-Options.html) for the names of the architectures supported by your version of GCC.

You can compile the code with various runtime checks enabled using the option `DEBUG=1`. This will slow down the code significantly.
You can compile the code with various runtime checks enabled using the option `DEBUG=1`. This will slow down the code significantly. If this is too slow for your purposes, you can disable the [sanitizers](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fsanitize_003daddress) using `make all DEBUG=1 SANITIZERS=""`.

The build system will try to pick good compiler flags for you, but if you need to, you can override them by passing the option `OPT_CFLAGS`. For example, to disable compiler optimization and enabled debug symbols, you could run:

make all OPT_CFLAGS="-O0 -g"


If you do not want to see the command line of each compiler
invocation, pass `S=1` to `make`.
invocation, you pass `S=1` to `make`.


Embedding (shared library)
Expand Down Expand Up @@ -314,12 +314,25 @@ The **moocore** executables are validated using a [comprehensive testsuite](http
git clone https://github.com/multi-objective/moocore moocore
# Download the testsuite
git clone https://github.com/multi-objective/testsuite moocore/testsuite
# Install required python packages
python3 -m pip install -r testsuite/requirements.txt
# Testing
make -C moocore/c/ test
# Timing
make -C moocore/c/ time
```

Under `moocore/c/`, `make test` will compile the code with `DEBUG=1 SANTIZERS="" OPT_CFLAGS="-Og -g3"`. This is useful for debugging failures.

`make time` will compile the code with `DEBUG=0 SANITIZERS="" OPT_CLAGS="-O3 -ftlo -march=native"`. This is useful for benchmarking code and making sure compiler optimizations do not break anything.

Neither `make test` nor `make time` recompile the code that has not been modified. So you can compile the code first with your preferred compiler flags and then run the testsuite. For example, if you compile with `make all DEBUG=1`, the code will be compiler with several [sanitizers](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fsanitize_003daddress) enabled. You can then call `make test` to run the testsuite with the sanitizers enabled. This is much slower, but very helpful to track crashes.

Under `c/` there are various targets to run only parts of the testsuite, for example:

make test-hv
make test-nondominated
...



Expand Down Expand Up @@ -348,5 +361,5 @@ See the [LICENSE](/LICENSE) and [COPYRIGHTS](/r/inst/COPYRIGHTS) files.
[r-moocore-cran]: https://cran.r-project.org/package=moocore
[r-moocore-github]: https://github.com/multi-objective/moocore/tree/main/r#readme
[r-moocore-homepage]: https://multi-objective.github.io/moocore/r/
[testsuite-badge]: https://github.com/multi-objective/testsuite/actions/workflows/moocore.yml/badge.svg?event=push
[testsuite-badge]: https://github.com/multi-objective/testsuite/actions/workflows/moocore.yml/badge.svg
[testsuite-link]: https://github.com/multi-objective/testsuite/actions/workflows/moocore.yml
2 changes: 1 addition & 1 deletion c/eaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ eaf_check_polygons(eaf_polygon_t *p, int nobj)
polygon_print(pi, nobj);
polygon_print(pj, nobj);
#endif
assert(!polygons_intersect(pi, pj, nobj));
assert(false);
}
pj = next_polygon(pj, nobj, end);
}
Expand Down
2 changes: 1 addition & 1 deletion c/epsilon.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ do_file (const char *filename, double *reference, size_t reference_size,
// time_elapsed = Timer_elapsed_virtual ();
fprintf (outfile, indicator_printf_format "\n", epsilon);
if ((additive_flag && epsilon < 0) || (!additive_flag && epsilon < 1)) {
errprintf ("%s: some points are not dominated by the reference set",
errprintf ("%s: some points are not dominated by the reference set",
filename);
exit (EXIT_FAILURE);
}/*
Expand Down
131 changes: 93 additions & 38 deletions c/epsilon.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
static inline bool
all_positive(const double * restrict points, size_t size, dimension_t dim)
{
ASSUME(dim <= 32);
for (size_t a = 0; a < size; a++)
for (dimension_t d = 0; d < dim; d++)
if (points[a * dim + d] <= 0)
return false;
ASSUME(size > 0);
ASSUME(1 <= dim && dim <= 32);
const size_t len = size * dim;
for (size_t a = 0; a < len; a++)
if (points[a] <= 0)
return false;

return true;
}
Expand All @@ -43,19 +44,19 @@ all_positive(const double * restrict points, size_t size, dimension_t dim)
for negative values doesn't make sense.
*/

static inline double
eps_value_(bool do_ratio, double a, double b)
{
return do_ratio ? a / b : a - b;
}

_attr_optimize_finite_math
static inline double
epsilon_helper_(bool do_mult, const enum objs_agree_t agree,
const signed char * restrict minmax, dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
// Converting this macro to an inline function hinders vectorization.
#define eps_value_(X,Y) (do_mult ? ((X) / (Y)) : ((X) - (Y)))

ASSUME(2 <= dim && dim <= 32);
ASSUME(size_a > 0 && size_b > 0);
ASSUME(agree == AGREE_MINIMISE || agree == AGREE_MAXIMISE || agree == AGREE_NONE);
ASSUME(minmax == NULL || agree != AGREE_NONE);
double epsilon = do_mult ? 0 : -INFINITY;
Expand All @@ -65,29 +66,25 @@ epsilon_helper_(bool do_mult, const enum objs_agree_t agree,
const double * restrict pb = &points_b[b * dim];
for (size_t a = 0; a < size_a; a++) {
const double * restrict pa = &points_a[a * dim];
double epsilon_max;
if (agree == AGREE_NONE) {
epsilon_max = MAX(minmax[0] * eps_value_(do_mult, pb[0], pa[0]),
minmax[1] * eps_value_(do_mult, pb[1], pa[1]));
if (epsilon_max >= epsilon_min)
continue;
for (dimension_t d = 2; d < dim; d++) {
double epsilon_temp = minmax[d] * eps_value_(do_mult, pb[d], pa[d]);
epsilon_max = MAX(epsilon_max, epsilon_temp);
}
} else {
epsilon_max = (agree == AGREE_MINIMISE)
? MAX(eps_value_(do_mult, pa[0], pb[0]), eps_value_(do_mult, pa[1], pb[1]))
: MAX(eps_value_(do_mult, pb[0], pa[0]), eps_value_(do_mult, pb[1], pa[1]));
if (epsilon_max >= epsilon_min)
continue;
for (dimension_t d = 2; d < dim; d++) {
double epsilon_temp = (agree == AGREE_MINIMISE)
? eps_value_(do_mult, pa[d], pb[d])
: eps_value_(do_mult, pb[d], pa[d]);
epsilon_max = MAX(epsilon_max, epsilon_temp);
}
double epsilon_max = (agree == AGREE_NONE)
? MAX(minmax[0] * eps_value_(pb[0], pa[0]),
minmax[1] * eps_value_(pb[1], pa[1]))
: ((agree == AGREE_MINIMISE)
? MAX(eps_value_(pa[0], pb[0]), eps_value_(pa[1], pb[1]))
: MAX(eps_value_(pb[0], pa[0]), eps_value_(pb[1], pa[1])));

if (epsilon_max >= epsilon_min)
continue;

for (dimension_t d = 2; d < dim; d++) {
double epsilon_temp = (agree == AGREE_NONE)
? minmax[d] * eps_value_(pb[d], pa[d])
: ((agree == AGREE_MINIMISE)
? eps_value_(pa[d], pb[d])
: eps_value_(pb[d], pa[d]));
epsilon_max = MAX(epsilon_max, epsilon_temp);
}

if (epsilon_max <= epsilon) {
skip_max = true;
break;
Expand All @@ -100,6 +97,63 @@ epsilon_helper_(bool do_mult, const enum objs_agree_t agree,
return epsilon;
}

_attr_optimize_finite_math
static inline double
epsilon_mult_agree_none(const signed char * restrict minmax, dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
return epsilon_helper_(/* do_mult=*/true, AGREE_NONE, minmax, dim, points_a, size_a, points_b, size_b);
}

_attr_optimize_finite_math
static inline double
epsilon_mult_agree_min(dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
return epsilon_helper_(/* do_mult=*/true, AGREE_MINIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
}

_attr_optimize_finite_math
static inline double
epsilon_mult_agree_max(dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
return epsilon_helper_(/* do_mult=*/true, AGREE_MAXIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
}


_attr_optimize_finite_math
static inline double
epsilon_addi_agree_none(const signed char * restrict minmax, dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
return epsilon_helper_(/* do_mult=*/false, AGREE_NONE, minmax, dim, points_a, size_a, points_b, size_b);
}

_attr_optimize_finite_math
static inline double
epsilon_addi_agree_min(dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
return epsilon_helper_(/* do_mult=*/false, AGREE_MINIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
}

_attr_optimize_finite_math
static inline double
epsilon_addi_agree_max(dimension_t dim,
const double * restrict points_a, size_t size_a,
const double * restrict points_b, size_t size_b)
{
return epsilon_helper_(/* do_mult=*/false, AGREE_MAXIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
}


_attr_optimize_finite_math
static inline double
epsilon_mult_minmax(const signed char * restrict minmax, dimension_t dim,
const double * restrict points_a, size_t size_a,
Expand All @@ -114,14 +168,15 @@ epsilon_mult_minmax(const signed char * restrict minmax, dimension_t dim,
// This forces the compiler to generate three specialized versions of the function.
switch (check_all_minimize_maximize(minmax, dim)) {
case AGREE_MINIMISE:
return epsilon_helper_(/* do_mult=*/true, AGREE_MINIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
return epsilon_mult_agree_min(dim, points_a, size_a, points_b, size_b);
case AGREE_MAXIMISE:
return epsilon_helper_(/* do_mult=*/true, AGREE_MAXIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
return epsilon_mult_agree_max(dim, points_a, size_a, points_b, size_b);
default:
return epsilon_helper_(/* do_mult=*/true, AGREE_NONE, minmax, dim, points_a, size_a, points_b, size_b);
return epsilon_mult_agree_none(minmax, dim, points_a, size_a, points_b, size_b);
}
}

_attr_optimize_finite_math
static inline double
epsilon_additive_minmax(const signed char * restrict minmax, dimension_t dim,
const double * restrict points_a, size_t size_a,
Expand All @@ -130,11 +185,11 @@ epsilon_additive_minmax(const signed char * restrict minmax, dimension_t dim,
// This forces the compiler to generate three specialized versions of the function.
switch (check_all_minimize_maximize(minmax, dim)) {
case AGREE_MINIMISE:
return epsilon_helper_(/* do_mult=*/false, AGREE_MINIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
return epsilon_addi_agree_min(dim, points_a, size_a, points_b, size_b);
case AGREE_MAXIMISE:
return epsilon_helper_(/* do_mult=*/false, AGREE_MAXIMISE, /*minmax=*/NULL, dim, points_a, size_a, points_b, size_b);
return epsilon_addi_agree_max(dim, points_a, size_a, points_b, size_b);
default:
return epsilon_helper_(/* do_mult=*/false, AGREE_NONE, minmax, dim, points_a, size_a, points_b, size_b);
return epsilon_addi_agree_none(minmax, dim, points_a, size_a, points_b, size_b);
}
}

Expand Down
Loading
Loading