Skip to content
Merged
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
19 changes: 11 additions & 8 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Linux Tests
name: Tests

on: [ push, pull_request ]

Expand All @@ -13,20 +13,23 @@ concurrency:
cancel-in-progress: true

jobs:
gcc_x86_64_linux:
name: GCC X86_64 Linux
runs-on: ubuntu-22.04
tests:
name: ${{ matrix.environment }} ${{ matrix.runs-on }}
runs-on: ${{ matrix.runs-on }}
env:
XSREF_TABLES_PATH: "${{ github.workspace }}/xsref/tables"
strategy:
fail-fast: false
matrix:
environment: [tests-ci]
runs-on: [ubuntu-latest, macos-latest]

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: prefix-dev/setup-pixi@92815284c57faa15cd896c4d5cfb2d59f32dc43d # v0.8.3
with:
pixi-version: v0.44.0
cache: true
environments: ${{ matrix.environment }}
- name: Run tests
run: |
pixi run configure-tests
pixi run build-only -j2
pixi run tests -j2
run: pixi run --environment=tests-ci tests-ci
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# xsf
Special function implementations
Special function implementations.

See https://github.com/scipy/xsf/issues/1 for context.

## Tests

Expand All @@ -9,16 +11,19 @@ To run the tests:
- [install Pixi](https://pixi.sh/latest/#installation)
- `pixi run tests`

For subsequent test runs, you can skip re-cloning [`xsref`](https://github.com/scipy/xsref) with:
You can trigger a rebuild inbetween test runs with:

```shell
pixi run --skip-deps tests
pixi run build-tests
```

You can trigger a rebuild inbetween test runs with:
For subsequent test runs, to skip re-cloning [`xsref`](https://github.com/scipy/xsref) or to control parallelism for individual commands, you can use:

```shell
pixi run build-tests
pixi run clone-xsf
pixi run configure-tests
pixi run build-only -j8
pixi run --skip-deps tests -j2
```

> [!NOTE]
Expand Down
567 changes: 464 additions & 103 deletions pixi.lock

Large diffs are not rendered by default.

20 changes: 17 additions & 3 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ depends-on = ["configure", "build-only"]

[feature.tests.dependencies]
catch2 = ">=3.8.0,<4"
ccache = ">=4.11.2,<5"
libarrow-all = ">=19.0.1,<20"

[feature.tests.tasks]
Expand All @@ -63,10 +62,24 @@ configure-tests.env.XSREF_TABLES_PATH = "$PWD/xsref/tables"
# build for tests
build-tests.depends-on = ["configure-tests", "build-only"]
# run tests
tests.cmd = "ctest --output-on-failure --test-dir build/tests"
tests.cmd = ["ctest", "--output-on-failure", "--test-dir", "build/tests"]
tests.depends-on = ["clone-xsref", "build-tests"]
tests.cwd = "."

[feature.tests-ci.dependencies]
ccache = ">=4.11.2,<5"

[feature.tests-ci.tasks]
# TODO: use a task arg for parallelism https://github.com/prefix-dev/pixi/pull/3433
build-tests-ci.cmd = ["cmake", "--build", "build", "-j3"]
build-tests-ci.depends-on = ["clone-xsref", "configure-tests"]
build-tests-ci.cwd = "."

# run tests
tests-ci.cmd = ["ctest", "--output-on-failure", "--test-dir", "build/tests", "-j3"]
tests-ci.depends-on = ["build-tests-ci"]
tests-ci.cwd = "."

## Coverage

# [feature.coverage.dependencies]
Expand All @@ -93,4 +106,5 @@ tests.cwd = "."
# cmd = "ctest"

[environments]
default = ["build", "tests"]
default = { features = ["build", "tests"], solve-group = "default" }
tests-ci = { features = ["build", "tests", "tests-ci"], solve-group = "default" }
17 changes: 0 additions & 17 deletions tests/scipy_special_tests/test_bdtr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,3 @@ TEST_CASE("bdtr dpd->d scipy_special_tests", "[bdtr][dpd->d][scipy_special_tests
CAPTURE(k, n, p, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}

TEST_CASE("bdtr ddd->d scipy_special_tests", "[bdtr][ddd->d][scipy_special_tests]") {
SET_FP_FORMAT()
auto [input, output, tol] =
GENERATE(xsf_test_cases<std::tuple<double, double, double>, std::tuple<double, bool>, double>(
tables_path / "In_d_d_d-d.parquet", tables_path / "Out_d_d_d-d.parquet",
tables_path / ("Err_d_d_d-d_" + get_platform_str() + ".parquet")
));

auto [k, n, p] = input;
auto [desired, fallback] = output;
auto out = xsf::bdtr(k, n, p);
auto error = xsf::extended_relative_error(out, desired);
tol = adjust_tolerance(tol);
CAPTURE(k, n, p, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}
17 changes: 0 additions & 17 deletions tests/scipy_special_tests/test_bdtrc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,3 @@ TEST_CASE("bdtrc dpd->d scipy_special_tests", "[bdtrc][dpd->d][scipy_special_tes
CAPTURE(k, n, p, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}

TEST_CASE("bdtrc ddd->d scipy_special_tests", "[bdtrc][ddd->d][scipy_special_tests]") {
SET_FP_FORMAT()
auto [input, output, tol] =
GENERATE(xsf_test_cases<std::tuple<double, double, double>, std::tuple<double, bool>, double>(
tables_path / "In_d_d_d-d.parquet", tables_path / "Out_d_d_d-d.parquet",
tables_path / ("Err_d_d_d-d_" + get_platform_str() + ".parquet")
));

auto [k, n, p] = input;
auto [desired, fallback] = output;
auto out = xsf::bdtrc(k, n, p);
auto error = xsf::extended_relative_error(out, desired);
tol = adjust_tolerance(tol);
CAPTURE(k, n, p, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}
17 changes: 0 additions & 17 deletions tests/scipy_special_tests/test_bdtri.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,3 @@ TEST_CASE("bdtri dpd->d scipy_special_tests", "[bdtri][dpd->d][scipy_special_tes
CAPTURE(k, n, y, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}

TEST_CASE("bdtri ddd->d scipy_special_tests", "[bdtri][ddd->d][scipy_special_tests]") {
SET_FP_FORMAT()
auto [input, output, tol] =
GENERATE(xsf_test_cases<std::tuple<double, double, double>, std::tuple<double, bool>, double>(
tables_path / "In_d_d_d-d.parquet", tables_path / "Out_d_d_d-d.parquet",
tables_path / ("Err_d_d_d-d_" + get_platform_str() + ".parquet")
));

auto [k, n, y] = input;
auto [desired, fallback] = output;
auto out = xsf::bdtri(k, n, y);
auto error = xsf::extended_relative_error(out, desired);
tol = adjust_tolerance(tol);
CAPTURE(k, n, y, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}
2 changes: 1 addition & 1 deletion tests/scipy_special_tests/test_cyl_bessel_i.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ TEST_CASE("cyl_bessel_i dD->D scipy_special_tests", "[cyl_bessel_i][dD->D][scipy
auto [desired, fallback] = output;
auto out = xsf::cyl_bessel_i(v, z);
auto error = xsf::extended_relative_error(out, desired);
tol = adjust_tolerance(tol);
tol = adjust_tolerance(tol, 12.0);
CAPTURE(v, z, out, desired, error, tol, fallback);
REQUIRE(error <= tol);
}
31 changes: 20 additions & 11 deletions tests/testing_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ class TableReader {
V imag;
*stream_ >> real >> imag;
element = U(real, imag);
} else if constexpr (std::is_same_v<U, std::ptrdiff_t>) {
std::int64_t val;
*stream_ >> val;
element = static_cast<std::ptrdiff_t>(val);
} else {
*stream_ >> element;
}
Expand Down Expand Up @@ -127,25 +131,30 @@ Catch::Generators::GeneratorWrapper<std::tuple<T1, T2, T3>> xsf_test_cases(
);
}


template <typename T>
T adjust_tolerance(T tol) {
T adjust_tolerance(T tol, T factor = 4) {
// Add some wiggle room to tolerance from table.
return 4 * std::max(std::numeric_limits<T>::epsilon(), tol);
return factor * std::max(std::numeric_limits<T>::epsilon(), tol);
}


std::string get_platform_str() {
/* This is going to get a string "<compiler>-<os>-<architecture>" using conditional
* compilation, but for now we're just stubbing things out. */
/* This should use Boost.Predef
* https://www.boost.org/doc/libs/1_87_0/libs/predef/doc/index.html
* (Boost isn't a dependency yet but this is planned)
* and we should have tolerance files for a wider variety of
* compiler/os/architecture combos, including for specific compiler
* versions. For now, there are these two platforms with tolerance
* files and we use the former with Clang on Mac and the later
* otherwise. */
#if defined(__clang__) && defined(__APPLE__)
return "clang-darwin-aarch64";
#else
return "gcc-linux-x86_64";
#endif
}



} // namespace


#define SET_FP_FORMAT() \
Catch::StringMaker<double>::precision = std::numeric_limits<double>::max_digits10; \
#define SET_FP_FORMAT() \
Catch::StringMaker<double>::precision = std::numeric_limits<double>::max_digits10; \
Catch::StringMaker<float>::precision = std::numeric_limits<float>::max_digits10;