Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ci:

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

- repo: https://github.com/tox-dev/tox-ini-fmt
rev: 1.7.2
rev: 1.9.0
hooks:
- id: tox-ini-fmt

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

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.21
rev: v0.16.8
hooks:
# Run the formatter.
- id: ruff-format
Expand Down
3 changes: 2 additions & 1 deletion r/NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# moocore (development)
# moocore 0.3.2.900

* `is_nondominated` is up to 10x faster in some inputs thanks to a customized radixsort implementation.
* New shapes `"cliff-concave"` and `"cliff-convex"` added to `generate_ndset()`.


# moocore 0.3.2
Expand Down
46 changes: 43 additions & 3 deletions r/R/generate.R
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,31 @@
#' hypersphere to the positive orthant. Thus, the sampling remains uniform.
#'
#' }
#' \item{`'cliff-concave'`}{
#'
#' Equivalent to generating a 2D set using
#' `method='concave-sphere'`, then generating the other `d-2` columns
#' uniformly at random within the unit hypercube
#' \citep{EmmFon2011emo,GueFon2017hv4d}. This method does not make sense
#' for `d=2`.
#'
#' In the resulting set, the first two columns are mutually nondominated,
#' that is, no point can dominate another regardless of the other
#' objectives, while the remaining `d-2` columns do not provide any
#' ordering. These sets are adversarial for algorithms that aim to exploit
#' dominance structure.
#'
#' The dimensions that are generated uniformly at random should be chosen
#' adversarially according to the algorithm being tested. Alternatively, the
#' columns may be randomly shuffled.
#'
#' }
#' \item{`'cliff-convex'`}{
#'
#' Equivalent to `1 - generate_ndset(..., method='cliff-concave')`.
#' This method does not make sense for `d=2`.
#'
#' }
#' \item{`'convex-simplex'`}{
#'
#' Equivalent to `generate_ndset(..., method='simplex')^2`, which is convex
Expand Down Expand Up @@ -114,6 +139,7 @@
#' generate_ndset(5, 3, "simplex", seed = 42, integer = TRUE)
#' generate_ndset(4, 2, "sphere", seed = 123)
#' generate_ndset(3, 5, "convex-sphere", seed = 123)
#' generate_ndset(3, 5, "cliff-convex", seed = 42)
#' generate_ndset(4, 4, "convex-simplex", seed = 123)
#'
#' @export
Expand All @@ -129,14 +155,23 @@ generate_ndset <- function(n, d, method, seed = NULL, integer = FALSE)
x
}

sample_sphere <- function() {
x <- abs(rnorm(n * d))
dim(x) <- c(n, d)
sample_sphere <- function(dims = d) {
x <- abs(rnorm(n * dims))
dim(x) <- c(n, dims)
x <- x / sqrt(rowSums(x * x))
x
}

sample_cliff_concave <- function() {
x <- matrix(0, nrow = n, ncol = d)
x[, 1:2] <- sample_sphere(2L)
cols <- seq.int(3L, d)
x[, cols] <- matrix(runif(n * (d - 2L)), nrow = n, ncol = d - 2L)
x
}

sample_convex_sphere <- function() 1. - sample_sphere()
sample_cliff_convex <- function() 1. - sample_cliff_concave()
sample_convex_simplex <- function() sample_simplex()^2
sample_inverted_simplex <- function() 1. - sample_simplex()
sample_concave_simplex <- function() 1. - sample_convex_simplex()
Expand All @@ -145,6 +180,11 @@ generate_ndset <- function(n, d, method, seed = NULL, integer = FALSE)
if (method %in% c("simplex", "linear", "L")) sample_simplex
else if (method %in% c("concave-sphere", "sphere", "C")) sample_sphere
else if (method %in% c("convex-sphere", "X")) sample_convex_sphere
else if (method %in% c("cliff-concave", "cliff-convex")) {
if (d <= 2L)
stop("method='", method, "' requires at least 3 dimensions")
if (method == "cliff-concave") sample_cliff_concave else sample_cliff_convex
}
else if (method == "convex-simplex") sample_convex_simplex
else if (method %in% c("inverted-simplex", "inverted-linear")) sample_inverted_simplex
else if (method == "concave-simplex") sample_concave_simplex
Expand Down
26 changes: 26 additions & 0 deletions r/man/generate_ndset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions r/tests/testthat/test-generate.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,30 @@ test_that("generate_ndset", {
one <- replicate(n,1)
for (dim in seq(5,10)) {
points <- generate_ndset(n, dim, "simplex")
expect_false(any_dominated(points))
expect_equal(rowSums(points), one)
points <- generate_ndset(n, dim, "concave-sphere")
expect_false(any_dominated(points))
expect_equal(rowSums(points**2), one)
points <- generate_ndset(n, dim, "convex-simplex")
expect_false(any_dominated(points))
expect_equal(rowSums(sqrt(points)), one)
points <- generate_ndset(n, dim, "cliff-concave")
expect_false(any_dominated(points))
expect_equal(rowSums(points[, 1:2]^2), one)
expect_true(all(points[, 3:dim] >= 0 & points[, 3:dim] <= 1))
points <- generate_ndset(n, dim, "cliff-convex")
expect_false(any_dominated(points))
expect_equal(rowSums((1 - points[, 1:2])^2), one)
expect_true(all(points[, 3:dim] >= 0 & points[, 3:dim] <= 1))
}

expect_error(
generate_ndset(n, 2L, "cliff-concave"),
"requires at least 3 dimensions"
)
expect_error(
generate_ndset(n, 2L, "cliff-convex"),
"requires at least 3 dimensions"
)
})
13 changes: 13 additions & 0 deletions r/vignettes/articles/generate.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,19 @@ fig2 <- plot_3d("simplex", moocore::generate_ndset(n, 3, "concave-simplex", seed
plotly_side_by_side(fig1, fig2)
```

# Cliff sets (3D)

The `cliff` type is often used to test the performance of algorithms for
computing the hypervolume [@EmmFon2011emo; @GueFon2017hv4d], due to its
particular structure.

```{r generate_3d_cliff}
fig1 <- plot_3d("simplex", moocore::generate_ndset(n, 3, "cliff-concave", seed = 42), title = 'method="cliff-concave"')
fig2 <- plot_3d("simplex", moocore::generate_ndset(n, 3, "cliff-convex", seed = 42), title = 'method="cliff-convex"')

plotly_side_by_side(fig1, fig2)
```

# Uniform sampling (moocore) vs projections of uniform samples (naive)

Naive methods for sampling such sets usually sample points uniformly in the
Expand Down