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
166 changes: 166 additions & 0 deletions .github/workflows/publish-native.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
name: Publish native companion

on:
workflow_dispatch:
release:
types: [published]

permissions:
contents: read

jobs:
validate:
name: Validate native release
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'native-v') }}
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false

- name: Match release tag to package version
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
python3 - <<'PY'
import os
import pathlib
import tomllib

metadata = tomllib.loads(pathlib.Path("native/pyproject.toml").read_text())
expected = f"native-v{metadata['project']['version']}"
actual = os.environ.get("RELEASE_TAG", "")
if actual and actual != expected:
raise SystemExit(f"release tag {actual!r} must equal {expected!r}")
print(expected)
PY

build:
name: Build ${{ matrix.platform }} wheels
needs: validate
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'native-v') }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- platform: linux-x86_64
os: ubuntu-latest
arch: x86_64
build: cp310-* cp311-* cp312-* cp313-* cp314-*
- platform: macos-x86_64
os: macos-15-intel
arch: x86_64
build: cp310-* cp311-* cp312-*
- platform: macos-arm64
os: macos-15
arch: arm64
build: cp310-* cp311-* cp312-* cp313-* cp314-*
- platform: windows-amd64
os: windows-latest
arch: AMD64
build: cp310-* cp311-* cp312-* cp313-* cp314-*

steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false

- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
env:
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_BUILD: ${{ matrix.build }}
with:
package-dir: native
output-dir: wheelhouse

- name: Upload wheels
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: native-wheels-${{ matrix.platform }}
path: wheelhouse/*.whl
if-no-files-found: error

sdist:
name: Build source distribution
needs: validate
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'native-v') }}
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Check out repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false

- name: Install uv and Python
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.8.15"
python-version: "3.10"
enable-cache: false

- name: Build source distribution
run: uv build --sdist native --out-dir wheelhouse

- name: Upload source distribution
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: native-sdist
path: wheelhouse/*.tar.gz
if-no-files-found: error

attach:
name: Attach distributions to release
needs: [validate, build, sdist]
if: ${{ github.event_name == 'release' && startsWith(github.event.release.tag_name, 'native-v') }}
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Download wheels
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: native-*
path: wheelhouse
merge-multiple: true

- name: Attach wheels
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: gh release upload "$RELEASE_TAG" wheelhouse/*

publish:
name: Publish native distributions
needs: [validate, build, sdist]
if: ${{ github.event_name == 'release' && startsWith(github.event.release.tag_name, 'native-v') }}
runs-on: ubuntu-latest
timeout-minutes: 10
environment:
name: pypi
url: https://pypi.org/p/rosa-torch-native
permissions:
id-token: write

steps:
- name: Download wheels
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: native-*
path: wheelhouse
merge-multiple: true

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
packages-dir: wheelhouse
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ semantic versioning while it remains in the 0.x development series.

- The public `rosa` imports and existing stateful inference APIs are unchanged.
- The distribution remains `rosa-torch` and supports Python 3.10+.
- The optional native companion remains separately versioned and optional.
- The optional `rosa-torch-native 0.3.0` companion remains separately versioned
and requires `rosa-torch[numba]>=0.3,<0.4`.

## 0.2.0 — 2026-08-11

Expand Down
15 changes: 5 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,15 @@ Install the stateful Link-Cut Tree backend with:
uv add 'rosa-torch[numba]'
```

For the lowest CPU step latency, build and install the optional native companion
locally. `rosa-torch-native` is not currently published on PyPI because it
requires per-platform and per-Python ABI wheels:
For the lowest CPU step latency, install the optional native companion. Wheels
are published separately for each supported platform and Python ABI:

```bash
git clone https://github.com/aabbdev/rosa.git
cd rosa
uv sync --extra numba
uv build --wheel native --out-dir native/dist
uv pip install native/dist/rosa_torch_native-0.2.0-*.whl
uv add rosa-torch-native
```

The native sources are available from the Git repository and are not included
in the pure-Python `rosa-torch` source distribution on PyPI.
The native sources remain available from the Git repository and are not
included in the pure-Python `rosa-torch` source distribution.

The stateful backend detects it lazily and otherwise falls back to Numba.

Expand Down
21 changes: 21 additions & 0 deletions native/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Lucas

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
32 changes: 16 additions & 16 deletions native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ main Python package.
The C++ core implements the validated exact production state machine. It binds
the NumPy arrays of a `_StatefulInferenceState` once, updates them in place,
and releases the GIL during computation. It neither includes nor calls
libtorch. The runtime dependency `rosa-torch[numba]>=0.2,<0.3` provides the
libtorch. The runtime dependency `rosa-torch[numba]>=0.3,<0.4` provides the
compatible state contract together with PyTorch, NumPy, and Numba.

The constructor validates every shape, dtype, counter, and ABI version before
retaining any pointer. The current native state ABI is `1`.

The module also provides fused online RLBWT inference for exact dense top-1
retrieval. `NativeRLBWTState` is the explicit baseline,
`NativeRLBWTCompactState` stores vocabularies of at most 256 IDs in adaptive
packed leaves, and `NativeRLBWTStateMC` exposes the separately named opt-in
Monte-Carlo variants. The Python package keeps these backends explicit;
`backend="auto"` continues to select the production suffix-automaton path.

The module also exposes `NativeCandidateState` for the exact rich state in
`rosa._stateful_candidates_numba`. Its batched `step` maintains the same K
suffixes, R newest occurrences, unbounded frequencies, and
Expand All @@ -37,17 +44,10 @@ wheel does not provide a newer optional method.

## Installation and usage

`rosa-torch-native` is not currently published on PyPI. Build a wheel from a
Git checkout using the target Python interpreter, then install the matching
wheel for the current platform and ABI:
Install the matching wheel for the current platform and Python ABI from PyPI:

```bash
git clone https://github.com/aabbdev/rosa.git
cd rosa
uv sync --extra numba
uv build --python .venv/bin/python --wheel native --out-dir native/dist
uv pip install --python .venv/bin/python \
native/dist/rosa_torch_native-0.2.0-*.whl
uv add rosa-torch-native
```

`rosa-torch` detects the extension automatically from its Numba inference
Expand Down Expand Up @@ -102,7 +102,7 @@ uv build --python .venv/bin/python --wheel native \
--out-dir /tmp/rosa-native-dist
uv run --isolated \
--with '.[numba]' \
--with /tmp/rosa-native-dist/rosa_torch_native-0.2.0-*.whl \
--with /tmp/rosa-native-dist/rosa_torch_native-0.3.0-*.whl \
native/tests/smoke.py
```

Expand All @@ -115,8 +115,8 @@ respectively, in the same isolated environment.

## Multi-platform publication

The next publication step is a dedicated `cibuildwheel` workflow after defining
the supported Python and architecture matrix, manylinux targets, and release
policy. No such workflow is included yet because an unvalidated matrix must not
be published. Every wheel contains native code and must be built separately for
each Python ABI and platform.
The release workflow builds CPython 3.10–3.14 wheels for Linux x86-64, macOS
arm64, and Windows x64, plus CPython 3.10–3.12 wheels for macOS x86-64. Each
wheel is smoke-tested by importing the extension and checking its production
and compact RLBWT ABI versions before it is attached to the GitHub Release and
published through PyPI Trusted Publishing.
12 changes: 9 additions & 3 deletions native/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ build-backend = "setuptools.build_meta"

[project]
name = "rosa-torch-native"
version = "0.2.0"
description = "Optional native CPU step companion for rosa-torch"
version = "0.3.0"
description = "Optional native CPU inference companion for rosa-torch"
readme = "README.md"
requires-python = ">=3.10"
license = "MIT"
license-files = ["LICENSE"]
classifiers = [
"Development Status :: 3 - Alpha",
"Programming Language :: C++",
Expand All @@ -25,7 +26,7 @@ classifiers = [
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"rosa-torch[numba]>=0.2,<0.3",
"rosa-torch[numba]>=0.3,<0.4",
]

[project.urls]
Expand All @@ -34,3 +35,8 @@ Issues = "https://github.com/aabbdev/rosa/issues"

[tool.setuptools]
include-package-data = false

[tool.cibuildwheel]
build = ["cp310-*", "cp311-*", "cp312-*", "cp313-*", "cp314-*"]
skip = ["*-musllinux_*", "*-manylinux_i686", "*-win32"]
test-command = "python -c \"import rosa_native_step as native; assert native.candidate_abi_version == 1; assert native.rlbwt_compact_abi_version == 1\""
10 changes: 5 additions & 5 deletions native/uv.lock

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

Loading