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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased
- Fix `np.shuffle` crash and wrong return type in `Searchspace` distributed random and LHS samplers

## [1.5.0] - 2026-08-20
- Kernel Tuner can now be used from Julia, [see KernelTuner.jl](https://github.com/KernelTuner/KernelTuner.jl)
Expand Down
6 changes: 3 additions & 3 deletions kernel_tuner/searchspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -1267,13 +1267,13 @@ def get_distributed_random_sample_indices(self, num_samples: int, sampling_facto
)
num_samples = round(self.size / 2)
if num_samples == self.size:
return np.shuffle([range(self.size)])
return np.random.permutation(self.size).tolist()

# adjust the number of random samples if necessary
sampling_factor = max(1, sampling_factor)
num_random_samples = min(sampling_factor * num_samples, self.size)
if num_random_samples == self.size or num_random_samples <= 1:
return self.get_random_sample(num_random_samples)
return self.get_random_sample_indices(num_samples).tolist()
random_samples_indices = self.get_random_sample_indices(num_random_samples)

# calculate the desired parameter configuration indices, starting at the edges of the parameter indices and halving each time
Expand Down Expand Up @@ -1340,7 +1340,7 @@ def get_LHS_sample_indices(self, num_samples: int) -> List[int]:
)
num_samples = round(self.size / 2)
if num_samples == self.size:
return np.shuffle([range(self.size)])
return np.random.permutation(self.size).tolist()
if self.params_values_indices is None:
self.__prepare_neighbors_index()

Expand Down
27 changes: 27 additions & 0 deletions test/test_searchspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from unittest.mock import patch

import numpy as np
import pytest
from constraint import ExactSumConstraint

from kernel_tuner.interface import Options
Expand Down Expand Up @@ -562,6 +563,19 @@ def test_get_distributed_random_sample():
for index in distributed_random_sample_indices:
assert 0 <= index < searchspace.size

# check that requesting exactly the searchspace size returns every index exactly once
full_sample_indices = searchspace.get_distributed_random_sample_indices(num_samples=searchspace.size)
assert len(full_sample_indices) == searchspace.size
assert sorted(full_sample_indices) == list(range(searchspace.size))

# check that requesting more than the searchspace size warns and reduces the sample size
with pytest.warns(UserWarning):
oversized_sample_indices = searchspace.get_distributed_random_sample_indices(num_samples=searchspace.size + 6)
assert len(oversized_sample_indices) == round(searchspace.size / 2)
assert len(set(oversized_sample_indices)) == len(oversized_sample_indices)
for index in oversized_sample_indices:
assert 0 <= index < searchspace.size

def test_get_LHS_sample_indices():
"""Test whether the distributed random sample indices are as expected."""
# create a searchspace with mixed parameter types
Expand All @@ -588,6 +602,19 @@ def test_get_LHS_sample_indices():
for index in distributed_random_sample_indices:
assert 0 <= index < searchspace.size

# check that requesting exactly the searchspace size returns every index exactly once
full_sample_indices = searchspace.get_LHS_sample_indices(num_samples=searchspace.size)
assert len(full_sample_indices) == searchspace.size
assert sorted(full_sample_indices) == list(range(searchspace.size))

# check that requesting more than the searchspace size warns and reduces the sample size
with pytest.warns(UserWarning):
oversized_sample_indices = searchspace.get_LHS_sample_indices(num_samples=searchspace.size + 6)
assert len(oversized_sample_indices) == round(searchspace.size / 2)
assert len(set(oversized_sample_indices)) == len(oversized_sample_indices)
for index in oversized_sample_indices:
assert 0 <= index < searchspace.size

def test_small_searchspace():
"""Test a small real-world searchspace and the usage of the `max_threads` parameter."""
max_threads = 1024
Expand Down
Loading