diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dea0f70..960788d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,8 @@ name: Build -on: [push] +on: + push: + branches: ["main"] env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 86391d2..22243ce 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,19 +17,27 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: actions-rust-lang/setup-rust-toolchain@stable - - uses: actions/setup-python@v6 + + - name: Setup Python + uses: actions/setup-python@v6 with: python-version: "3.12" - cache: pip - - run: pip install -r pyproject.toml - - name: Install app via Maturin + - name: Setup Python env + run: python -m venv .venv + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Build app via Maturin uses: PyO3/maturin-action@v1 with: - command: develop + command: build args: --release + - name: Install app + run: python -m pip install target/wheels/react_rs*.whl + - name: Install Python test dependencies run: pip install pytest mock codecov pydocstyle pytest-cov pylint pylint_junit diff --git a/Cargo.toml b/Cargo.toml index 70fbe66..0e057e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -version = "0.9.2" +version = "0.9.3" name = "react-rs" edition = "2024" diff --git a/README.md b/README.md index 46deca2..f6bbdf1 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@

REACT_RS

+[![Test](https://github.com/DNYFZR/react-rs/actions/workflows/test.yml/badge.svg)](https://github.com/DNYFZR/react-rs/actions/workflows/test.yml) [![Build](https://github.com/DNYFZR/react-rs/actions/workflows/build.yml/badge.svg)](https://github.com/DNYFZR/react-rs/actions/workflows/build.yml) + ## **Summary** React_rs (reactors) is Python package with Rust backend functionality for executing Discrete Event simulations in a fast & cost efficient way. -- Exposed Rust functions have a corresponding Python function in the [API definition](python/react_rs/__init__.py) which allows the application to convert the Rust polars DataFrame into a Python polars DataFrame & vice versa. - -- There are also native Python components to the package, which are in dedicated scripts in the [Python directory](python/react_rs). - The core functionality of the app is : - Fit, adjust & generate of a range of Weibull model survival curves -- Simulation of discrete events over a user-defined number of timesteps & simulations based on the survival curve in the probabilities column of the input dataset - these can be from the internal Weibull module, or from any other user-defined model +- Simulation of discrete events over a user-defined number of timesteps & simulations based on the survival curve in the probabilities column of the input dataset + + - Survival curves can be from the internal Weibull module, or from any other user-defined model, so long as there is a column in the input table & its name is defined under 'probs_col' (see example below) -- Application of financial limits to simulation outputs, and reallocation of replacement events in line with these limits +- Application of financial constraints to simulation outputs, with randomised reallocation of replacement events in line with each timestep limit -- Event or cost based aggregations are summaries of the totals for each simulation & timestep +- Event & cost based aggregations showing a summary of totals for each simulation & timestep -- Profile based aggregation creates a summary of the count of items ages at each timestep within each simulation iteration +- Profile based aggregation creates a count of item ages at each timestep within each iteration ## **Usage** @@ -41,14 +41,17 @@ for model, params in model_config.items(): # Fit method auto-handles base model & adjustments to mean wb.fit(model_name=model, **params) -# Generate survival curve DataFrame under 'curves' attribute +# Generate survival curve dictionary under 'curves' attribute wb.generate() -# Join survival curves DataFrame to input DataFrame +# Join survival curves to input DataFrame df = pl.read_parquet("./tests/data/input.parquet").join( - pl.DataFrame({"model": wb.curves.keys(), "curve": wb.curves.values()}), - "model", - "left", + other=pl.DataFrame({ + "model": wb.curves.keys(), + "curve": wb.curves.values() + }), + on="model", + how="left", ) # Execute simulation in Rust @@ -60,7 +63,7 @@ sim_result = react_rs.simulate( probs_col="curve", n_sims=100, n_steps=50, - parallel_limit=10, + parallel_limit=10, # control concurrent parallel operations ) # Constrain simulation output in Rust @@ -68,19 +71,19 @@ sim_result_constrained = react_rs.constrain( df=sim_result, constrain_steps=30, # limit steps taken through constraint system iter_regex="step", - cost_col="cost", - constraints=[int(50e6) for _ in range(30)], + cost_col="cost", # name is standardised to 'cost' by simulate function + constraints=[int(50e6) for _ in range(30)], partition_by="sim_id", parallel_limit=10, ) -# Aggregate simulation outputs +# Aggregate simulation outputs) sim_result_agg = react_rs.aggregate( df=sim_result, partition_by="sim_id", iter_regex="step", target_value=0, - cost_col="cost", # None if events are req'd + cost_col="cost", # set to None if events are req'd ) sim_result_const_agg = react_rs.aggregate( @@ -107,6 +110,10 @@ sim_constrained_profile = react_rs.profile( ## **Development** +- Exposed Rust functions have a corresponding Python function in the [API definition](python/react_rs/__init__.py) which mirrors the input structure of the Rust function & returns its output. Should there be an error while running the function, the Rust errors will be propogated back to the user. + +- There are native Python components to the package, which are in dedicated scripts in the [Python directory](python/react_rs). + ### **Build** The [build workflow](.github/workflows/build.yml) is configured to build for Windows, Linux & MacOS : @@ -125,4 +132,4 @@ These tests call all of the functionality within the native Python code & the Ru ### **Notes** -- When working on [__init__.py](python/react_rs/__init__.py), your IDE may highlight imports from the react_rs package with an error - this is normal and can be ignored. +- If working on the [Python API](python/react_rs/__init__.py), your IDE may highlight imports from the react_rs package with an error - this is normal and can be ignored. diff --git a/tests/test_weibull.py b/tests/test_weibull.py index 609ef61..5bb2a21 100644 --- a/tests/test_weibull.py +++ b/tests/test_weibull.py @@ -1,12 +1,7 @@ # Weibull Module Test Script -import sys - import numpy as np import pytest - -sys.path.append("..") - -from python.react_rs._weibull import Weibull +from react_rs import Weibull test_case = [ {