This is an automated email from the ASF dual-hosted git repository.
400Ping pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git
The following commit(s) were added to refs/heads/main by this push:
new 603dd36bb [Website] Add Community over Code Glasgow 2026 hackathon
post with Colab notebook and slides (#1513)
603dd36bb is described below
commit 603dd36bb525ba2923823844ea2bd4b73b3d7e01
Author: Jie-Kai Chang <[email protected]>
AuthorDate: Wed Oct 14 13:59:13 2026 +0800
[Website] Add Community over Code Glasgow 2026 hackathon post with Colab
notebook and slides (#1513)
* [Website] Add Community over Code Glasgow 2026 hackathon post with Colab
notebook and slides
Signed-off-by: 400Ping <[email protected]>
* update
Signed-off-by: 400Ping <[email protected]>
* [Website] Format hackathon notebook with ruff
Signed-off-by: 400Ping <[email protected]>
---------
Signed-off-by: 400Ping <[email protected]>
---
.../index.md | 122 +++++
.../slide-01.jpg | Bin 0 -> 75774 bytes
.../slide-02.jpg | Bin 0 -> 94214 bytes
.../slide-03.jpg | Bin 0 -> 94548 bytes
.../slide-04.jpg | Bin 0 -> 96872 bytes
.../slide-05.jpg | Bin 0 -> 118171 bytes
.../slide-06.jpg | Bin 0 -> 101718 bytes
.../slide-07.jpg | Bin 0 -> 95610 bytes
.../slide-08.jpg | Bin 0 -> 116052 bytes
.../slide-09.jpg | Bin 0 -> 116024 bytes
.../slide-10.jpg | Bin 0 -> 110109 bytes
.../slide-11.jpg | Bin 0 -> 164889 bytes
.../slide-12.jpg | Bin 0 -> 86393 bytes
.../slide-13.jpg | Bin 0 -> 70780 bytes
website/static/hackathon/mahout-hackathon-deck.pdf | Bin 0 -> 781208 bytes
.../static/hackathon/mahout-hackathon-deck.pptx | Bin 0 -> 1264326 bytes
website/static/hackathon/mahout-hackathon-tasks.md | 135 ++++++
.../static/hackathon/mahout_hackathon_colab.ipynb | 513 +++++++++++++++++++++
18 files changed, 770 insertions(+)
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/index.md
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/index.md
new file mode 100644
index 000000000..3715e48dc
--- /dev/null
+++ b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/index.md
@@ -0,0 +1,122 @@
+---
+title: Apache Mahout Hackathon at Community over Code Glasgow 2026
+date: 2026-10-13
+tags: [news, hackathon, qumat, qdp]
+authors: [mahout-team]
+---
+
+Apache Mahout is running a hands-on hackathon at [Community over Code Glasgow
2026](https://events.apache.org/events/2026/community-over-code/mahout.html).
This post collects everything a participant needs in one place: the Google
Colab notebook, the kickoff slides, and the task list.
+
+- **When:** Tuesday, 13 October 2026, 15:00 to 18:40
+- **Where:** The Wee Dram Room, Community over Code, Glasgow, UK
+- **Mentors:** Andrew Musselman and Krishna Dave, plus Mahout committers in
the room
+- **Bring:** a laptop with Python 3.10 to 3.12, git and a GitHub account. No
GPU needed; the GPU part runs in Colab.
+
+<!-- truncate -->
+
+## Downloads
+
+| | |
+|---|---|
+| **Colab notebook** | [](https://colab.research.google.com/github/apache/mahout/blob/main/website/static/hackathon/mahout_hackathon_colab.ipynb)
or <a href="pathname:///hackathon/mahout_hackathon_colab.ipynb"
download>download the .ipynb</a> and upload it with **File > Upload notebook**
in Colab |
+| **Kickoff slides** | [View as
PDF](pathname:///hackathon/mahout-hackathon-deck.pdf) or <a
href="pathname:///hackathon/mahout-hackathon-deck.pptx" download>download the
.pptx</a>. The slides are also shown below. |
+| **Task sheet** |
[mahout-hackathon-tasks.md](pathname:///hackathon/mahout-hackathon-tasks.md),
with reproduction steps and ready-to-file issue text for every task |
+| **Event page** | [events.apache.org: Apache Mahout
hackathon](https://events.apache.org/events/2026/community-over-code/mahout.html)
|
+
+## Colab setup: one minute before you run anything
+
+Colab's default runtime is Python 3.13, and Mahout 0.6.0 supports Python 3.10
to 3.12. Set the runtime first, or the install fails and the QDP part cannot
run.
+
+1. Menu **Runtime > Change runtime type**.
+2. **Runtime version:** choose **2026.07** (Python 3.12.13), not "Latest".
+3. **Hardware accelerator:** choose **T4 GPU**.
+4. Click **Save**, then **Runtime > Run all**.
+
+The first cell prints the Python version. It should say `3.12`. If it says
`3.13`, repeat step 2.
+
+The notebook follows the same order as the talk:
+
+- **Parts 0 to 3:** install, a Bell state, the same circuit on Qiskit, Cirq
and Braket, and the state vector. Spend at most 10 minutes here.
+- **Parts 4 and 5:** optional extras, parameterized circuits and the swap test.
+- **Part 6:** QDP encoding on the GPU. Needs the T4 and the 2026.07 runtime.
+- **Part 7:** the task list, also reproduced below.
+
+## Kickoff slides
+
+*Quantum computing in Python with Qumat and QDP*, presented by Andrew K.
Musselman and Krishna Dave.
[PDF](pathname:///hackathon/mahout-hackathon-deck.pdf) · <a
href="pathname:///hackathon/mahout-hackathon-deck.pptx" download>PPTX</a>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Hackathon tasks
+
+Every task is sized for one to two hours, needs no GPU, and ends in a pull
request with a test. Claim a task by commenting on its issue. Full details,
including reproduction steps, are in the [task
sheet](pathname:///hackathon/mahout-hackathon-tasks.md).
+
+**Track A: Qumat (Python only).** All reproduced on `main` and on `qumat`
0.6.0. Each issue has the reproduction steps.
+
+| # | Issue | Task |
+|---|---|---|
+| A1 | [#1506](https://github.com/apache/mahout/issues/1506) | Clear
`ValueError` for an unknown backend name (today a `ModuleNotFoundError` leaks) |
+| A2 | [#1507](https://github.com/apache/mahout/issues/1507) | Unsupported
`simulator_type` should raise instead of `print()` and silently continuing |
+| A3 | [#1508](https://github.com/apache/mahout/issues/1508) | Cirq backend
ignores the initialized simulator and creates its own `cirq.Simulator()` |
+| A4 | [#1509](https://github.com/apache/mahout/issues/1509) | Bug: reusing a
parameter name on two gates fails on Qiskit only (`name conflict adding
parameter 't'`) |
+| A5 | [#1510](https://github.com/apache/mahout/issues/1510) |
`create_empty_circuit()` without `num_qubits`: Qiskit raises, Cirq and Braket
allocate on demand |
+| A6 | [#1511](https://github.com/apache/mahout/issues/1511) | Add **one**
missing gate per person: S, S-dagger, T-dagger, CZ or Phase, on all three
backends with a test |
+| A7 | [#1512](https://github.com/apache/mahout/issues/1512) | Python 3.13
support: lift the `<3.13` cap in `pyproject.toml` and add 3.13 to CI |
+
+**Track B: QDP.** B1 to B3 are pure Python. B4 to B6 are Rust: take one only
if `cargo` is already installed, and start the first `cargo build` right away
(5 to 10 minutes). No CUDA needed, the build uses stubs like CI does.
+
+| # | Issue | Task |
+|---|---|---|
+| B1 | [#1469](https://github.com/apache/mahout/issues/1469) | `QdpBenchmark`
does not validate builder argument ranges |
+| B2 | [#1331](https://github.com/apache/mahout/issues/1331) | QDP tests
should skip, not error, when no GPU is present |
+| B3 | [#1468](https://github.com/apache/mahout/issues/1468) | File loader
ignores the configured batch limit (one-line wrapper fix plus a test) |
+| B4 | [#1472](https://github.com/apache/mahout/issues/1472) | Read default
LZ4-compressed Feather files (Rust reader) |
+| B5 | [#787](https://github.com/apache/mahout/issues/787) | NumPy file size
check to prevent OOM (Rust reader) |
+| B6 | [#1436](https://github.com/apache/mahout/issues/1436) |
`StreamingProducer`: `VecDeque` for O(1) buffer advance (Rust) |
+
+## From idea to merged pull request
+
+Setup takes about a minute in a terminal (not in Colab):
+
+```bash
+git clone https://github.com/<you>/mahout.git && cd mahout
+pip install uv
+uv sync # Qumat and the Python QDP package
+uv run pre-commit install # ruff + type checks on every commit
+uv run pytest testing/qumat # smoke test
+```
+
+Then: comment on the issue to claim it, branch, make the change with a test,
and open a PR that links the issue. One committer approval is required to
merge, so ping a mentor in the room. Your PR does not have to be finished by
18:40; mentors will keep reviewing afterwards.
+
+## Getting help
+
+- In the room: ask a mentor.
+- Slack: the `#hackathon` channel on
[apachecon.slack.com](https://apachecon.slack.com)
+- Mailing list: [[email protected]](mailto:[email protected])
(subscribe via [email protected])
+- Code and issues: [github.com/apache/mahout](https://github.com/apache/mahout)
+
+Have fun, and thanks for hacking on Apache Mahout!
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-01.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-01.jpg
new file mode 100644
index 000000000..c7e29beb5
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-01.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-02.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-02.jpg
new file mode 100644
index 000000000..ee3572da8
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-02.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-03.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-03.jpg
new file mode 100644
index 000000000..4d775977d
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-03.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-04.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-04.jpg
new file mode 100644
index 000000000..deb5c87b5
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-04.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-05.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-05.jpg
new file mode 100644
index 000000000..63e413b87
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-05.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-06.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-06.jpg
new file mode 100644
index 000000000..d4d05c2d0
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-06.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-07.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-07.jpg
new file mode 100644
index 000000000..bb4c3918d
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-07.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-08.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-08.jpg
new file mode 100644
index 000000000..df7100005
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-08.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-09.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-09.jpg
new file mode 100644
index 000000000..a98001088
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-09.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-10.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-10.jpg
new file mode 100644
index 000000000..4ba3447aa
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-10.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-11.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-11.jpg
new file mode 100644
index 000000000..3447db839
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-11.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-12.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-12.jpg
new file mode 100644
index 000000000..673e0eb7d
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-12.jpg differ
diff --git a/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-13.jpg
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-13.jpg
new file mode 100644
index 000000000..0fa724ac1
Binary files /dev/null and
b/docs/blog/2026-10-13-Community-Over-Code-Hackathon/slide-13.jpg differ
diff --git a/website/static/hackathon/mahout-hackathon-deck.pdf
b/website/static/hackathon/mahout-hackathon-deck.pdf
new file mode 100644
index 000000000..facc9af4c
Binary files /dev/null and b/website/static/hackathon/mahout-hackathon-deck.pdf
differ
diff --git a/website/static/hackathon/mahout-hackathon-deck.pptx
b/website/static/hackathon/mahout-hackathon-deck.pptx
new file mode 100644
index 000000000..a98597d6f
Binary files /dev/null and
b/website/static/hackathon/mahout-hackathon-deck.pptx differ
diff --git a/website/static/hackathon/mahout-hackathon-tasks.md
b/website/static/hackathon/mahout-hackathon-tasks.md
new file mode 100644
index 000000000..49e9486b9
--- /dev/null
+++ b/website/static/hackathon/mahout-hackathon-tasks.md
@@ -0,0 +1,135 @@
+# Apache Mahout Hackathon Tasks (3-hour format)
+
+**Schedule**
+
+| Time | What |
+|---|---|
+| 0:00 – 0:20 | Intro talk, `pip install qumat`, open the Colab notebook
(Parts 0 to 3 only, 10 minutes) |
+| 0:20 – 0:30 | Pick a task below, comment on the issue to claim it, fork and
branch |
+| 0:30 – 2:30 | Hack. Mentors in the room; one has a GPU box for QDP
verification |
+| 2:30 – 3:00 | Show and tell: open PRs, demo, next steps |
+
+Every task below is sized for **one to two hours** and needs **no GPU**. Each
one ends in a PR with a test. Anything bigger lives in the appendix for after
the event.
+
+Setup for every task: `git clone` your fork, `pip install uv`, `uv sync`, `uv
run pre-commit install`, `uv run pytest testing/qumat` (about a minute).
+
+---
+
+## Track A: Qumat (Python only)
+
+All items reproduced on 2026-10-09 against `main` (commit `bbce3c392`) and
PyPI `qumat` 0.6.0. Code: `qumat/qumat.py` and
`qumat/{qiskit,cirq,amazon_braket}_backend.py`. Tests: `testing/qumat/`. Each
task has a GitHub issue; comment on it to claim the task.
+
+### A1 Clear error for an unknown backend name
([#1506](https://github.com/apache/mahout/issues/1506))
+
+```python
+QuMat({"backend_name": "pennylane", "backend_options": {}})
+# ModuleNotFoundError: No module named 'qumat.pennylane_backend'
+```
+
+`QuMat.__init__` builds the module path from `backend_name` and lets the
import error leak. Raise a `ValueError` listing the supported backends
(`qiskit`, `cirq`, `amazon_braket`) and add a test.
+
+### A2 Unsupported `simulator_type` should raise, not `print()`
([#1507](https://github.com/apache/mahout/issues/1507))
+
+```python
+QuMat({"backend_name": "cirq", "backend_options": {"simulator_type":
"density_matrix"}})
+# prints "Simulator type 'density_matrix' is not supported in Cirq. Ignoring
this argument" and runs anyway
+
+QuMat({"backend_name": "amazon_braket", "backend_options": {"simulator_type":
"sv1"}})
+# prints "... Using default.", falls back to the AWS SV1 device, then fails
with NoRegionError
+```
+
+`cirq_backend.py:34` and `amazon_braket_backend.py:51` `print()` and continue.
Replace with a `ValueError` (or `warnings.warn`), add tests for the error path.
+
+### A3 Cirq backend ignores the initialized simulator
([#1508](https://github.com/apache/mahout/issues/1508))
+
+`cirq_backend.initialize_backend` returns a simulator, but `execute_circuit`
and `get_final_state_vector` create a fresh `cirq.Simulator()` and never use
the `backend` argument. Make the backend object the one that runs the circuit.
(Density-matrix support is a follow-up, see appendix.)
+
+### A4 Bug: reusing a parameter name on two gates fails on Qiskit only
([#1509](https://github.com/apache/mahout/issues/1509))
+
+```python
+qc = QuMat(qiskit_config); qc.create_empty_circuit(2)
+qc.apply_rx_gate(0, "t"); qc.apply_rx_gate(1, "t")
+# qiskit: CircuitError: "name conflict adding parameter 't'"
+# cirq: ok [Counter({3: 100})]
+# amazon_braket: ok Counter({'11': 100})
+```
+
+Cache one `qiskit.circuit.Parameter` per name in the Qiskit backend and add a
cross-backend test for shared parameters.
+
+### A5 `create_empty_circuit()` without `num_qubits` behaves differently per
backend ([#1510](https://github.com/apache/mahout/issues/1510))
+
+```python
+qc.create_empty_circuit(); qc.apply_hadamard_gate(0)
+# qiskit: CircuitError: 'Index 0 out of range for size 0.'
+# cirq / braket: ok, qubit allocated on demand
+```
+
+Pick one behavior (a clear `ValueError` from `QuMat` when `num_qubits` is
missing is the quick option) and make all three backends match, with tests.
+
+### A6 Add one missing gate (one gate per person)
([#1511](https://github.com/apache/mahout/issues/1511))
+
+`QuMat` exposes exactly `not, hadamard, cnot, toffoli, swap, cswap, pauli_x,
pauli_y, pauli_z, t, rx, ry, rz, u`. Pick **one** of: **S**, **S-dagger**,
**T-dagger**, **CZ**, **Phase P(λ)**. Add `QuMat.apply_<gate>_gate`, implement
it in all three backends (copy the pattern of `apply_t_gate`), add a row to
`docs/qumat/basic-gates.md`, and a test in
`testing/qumat/test_single_qubit_gates.py` or `test_multi_qubit_gates.py` that
checks the state vector on all backends.
+
+### A7 Python 3.13 support
([#1512](https://github.com/apache/mahout/issues/1512))
+
+Lift the `<3.13` cap in `pyproject.toml` and add 3.13 to the CI matrix. All
dependencies already ship 3.13 wheels.
+
+---
+
+## Track B: QDP
+
+### Python only, no Rust toolchain needed
+
+| # | Issue | Task | Where |
+|---|---|---|---|
+| B1 | [#1469](https://github.com/apache/mahout/issues/1469) | `QdpBenchmark`
does not validate builder argument ranges (zero batches, zero qubits, negative
warmup are accepted) | `qdp/qdp-python/qumat_qdp/`, pure Python; tests in
`testing/qdp_python/` run without the extension |
+| B2 | [#1331](https://github.com/apache/mahout/issues/1331) | QDP tests
instantiate `QdpEngine` or use `device="cuda"` without a GPU check |
`testing/qdp/`; add `requires_qdp` / `pytest.mark.skipif` so the suite skips
instead of erroring |
+| B3 | [#1468](https://github.com/apache/mahout/issues/1468) | Rust-backed
file loader ignores the configured batch limit | one-line fix at
`qumat_qdp/loader.py:620` (`batch_limit=None`) plus a unit test with a fake
engine, like `testing/qdp_python/test_fallback.py`; a mentor verifies on the
GPU box |
+
+### Rust, only if you already have `cargo` installed
+
+The first `cargo build` of `qdp-core` pulls arrow, parquet and friends and
takes 5 to 10 minutes on a laptop, so start it right after claiming. No CUDA
needed: without `nvcc` the build uses stubs (`QDP_NO_CUDA=1 cargo test -p
qdp-core --test <name>`), exactly like CI.
+
+| # | Issue | Task | Where |
+|---|---|---|---|
+| B4 | [#1472](https://github.com/apache/mahout/issues/1472) | QDP cannot read
default LZ4-compressed Feather files | `qdp-core/src/readers/arrow_ipc.rs`;
enable Arrow's `ipc_compression` feature in `qdp/Cargo.toml`, add an LZ4
fixture test to `qdp-core/tests/arrow_ipc_io.rs` |
+| B5 | [#787](https://github.com/apache/mahout/issues/787) | NumPy file size
check to prevent OOM | `qdp-core/src/readers/numpy.rs`; check the file size
against the expected shape before reading, test in `qdp-core/tests/numpy.rs` |
+| B6 | [#1436](https://github.com/apache/mahout/issues/1436) |
`StreamingProducer`: use `VecDeque` for O(1) buffer advance |
`qdp-core/src/pipeline_runner.rs`; the StreamingProducer inline tests run on
CPU |
+
+---
+
+## Appendix: follow-ups after the hackathon
+
+Half-day and larger items, kept here so teams that finish early or want to
continue afterwards can pick them up.
+
+**Qumat**
+
+- Density-matrix simulation on Cirq (`simulator_type="density_matrix"`),
builds on A3.
+- Controlled rotations CRx, CRy, CRz and RZZ accepting a float or a parameter
name.
+- Unified result format and bit ordering: today X on qubit 0 gives `{'01':
10}` on Qiskit, `[Counter({2: 10})]` on Cirq, `Counter({'10': 10})` on Braket.
+- `QuMat.measure(qubits)`; `examples/qumat/quantum_teleportation.py` currently
calls `qc.circuit.measure` directly, Qiskit only.
+- `QuMat.expectation_value(observable)` for Pauli strings, then
parameter-shift gradients.
+- OpenQASM export, batch parameter sweeps, ansatz templates,
`initialize_state(vector)` as the QDP-to-Qumat bridge.
+
+**QDP, fix on a laptop, verify once on a GPU**
+
+- [#1471](https://github.com/apache/mahout/issues/1471) `float32_pipeline`
keyword mismatch in `qdp-python/src/lib.rs:36`
+- [#1467](https://github.com/apache/mahout/issues/1467) `.pt`/`.pth` loading:
enable the existing `pytorch` feature in the wheel build (needs libtorch)
+- [#1434](https://github.com/apache/mahout/issues/1434) `Source` enum for
`PipelineIterator`
+- [#1430](https://github.com/apache/mahout/issues/1430) fail fast when
`estimate_memory()` exceeds free VRAM
+- [#1431](https://github.com/apache/mahout/issues/1431) PyO3 bindings for
`Preprocessor`, then [#1432](https://github.com/apache/mahout/issues/1432) docs
+- [#1433](https://github.com/apache/mahout/issues/1433) `KernelElem` trait for
the f32/f64 FFI stubs
+
+**QDP, needs CUDA kernel work**
+
+- [#1008](https://github.com/apache/mahout/issues/1008) ZZFeatureMap encoding
+- [#1370](https://github.com/apache/mahout/issues/1370) drop mid-stream D2H
norm validation in batch encoding
+
+**Building QDP from source with a GPU** (your own Linux box or a Colab T4;
first build 10 to 20 minutes on Colab):
+
+```bash
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+export QDP_CUDA_ARCH_LIST=75 # T4; omit to build every supported
architecture
+pip install --no-deps . && pip install ./qdp/qdp-python
+python -m pytest testing/qdp testing/qdp_python -q
+```
diff --git a/website/static/hackathon/mahout_hackathon_colab.ipynb
b/website/static/hackathon/mahout_hackathon_colab.ipynb
new file mode 100644
index 000000000..fcfec78f8
--- /dev/null
+++ b/website/static/hackathon/mahout_hackathon_colab.ipynb
@@ -0,0 +1,513 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "cell-00",
+ "metadata": {},
+ "source": "# Apache Mahout Hackathon: Qumat and QDP in Google
Colab\n\nWelcome! This notebook installs Apache Mahout's `qumat` package and
walks through the examples from the kickoff talk, so you can run everything in
the browser.\n\n## Before you run anything: set the runtime (1
minute)\n\nColab's default runtime is **Python 3.13**, and Mahout 0.6.0
supports **Python 3.10 to 3.12**. Pick the older runtime and a GPU first,
otherwise the install fails and the QDP part cannot run.\n\n1. [...]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-01",
+ "metadata": {},
+ "source": "## Part 0: Install\n\nApache Mahout ships on PyPI as `qumat`.
The current release, 0.6.0, declares **Python 3.10 to 3.12**. Run the next cell
first: it tells you which Python this runtime has and what to do if it is
newer.\n\n**If it reports Python 3.13 or newer** (the Colab default may have
moved past 3.12): the clean fix is `Runtime > Change runtime type > Runtime
version` and pick **2026.07** (Python 3.12.13), then `Runtime > Run all` again.
Without that, pip silently fa [...]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-02",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import platform\n",
+ "import sys\n",
+ "\n",
+ "PY = sys.version_info[:2]\n",
+ "print(\"Python\", platform.python_version(), \"on\",
platform.system())\n",
+ "!nvidia-smi -L 2>/dev/null || echo \"No GPU attached (that is fine for
Parts 0-5)\"\n",
+ "\n",
+ "if PY > (3, 12):\n",
+ " print(\n",
+ " \"\\nThis Python is newer than qumat 0.6.0 declares. Recommended:
Runtime > Change runtime type >\"\n",
+ " \"\\nRuntime version > 2026.07 (Python 3.12), then Run all again.
Step 1 will otherwise install\"\n",
+ " \"\\nqumat with --ignore-requires-python; Step 2 (the QDP wheel)
will be skipped.\"\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-03",
+ "metadata": {},
+ "source": "### Step 1: Qumat (pure Python, works everywhere)"
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-04",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if PY > (3, 12):\n",
+ " # All of qumat 0.6.0's dependencies ship wheels for 3.13; only
qumat's own metadata says <3.13.\n",
+ " %pip install -q --ignore-requires-python \"qumat==0.6.0\"\n",
+ "else:\n",
+ " %pip install -q qumat"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-05",
+ "metadata": {},
+ "source": "### Step 2: QDP, the GPU extra\n\n`pip install \"qumat[qdp]\"`
adds the `qumat-qdp` package: a prebuilt Linux wheel for Python 3.10 to 3.12
that bundles the Rust engine and CUDA kernels. It installs on any Linux
machine, including a CPU-only Colab runtime, but it needs an NVIDIA GPU to
actually encode anything (Part 6). There are no macOS, Windows or Python 3.13
wheels, so the cell skips itself in those cases.\n\nChanging QDP's Rust or CUDA
code means rebuilding it from sou [...]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-06",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if platform.system() != \"Linux\":\n",
+ " print(\"qumat-qdp only ships Linux wheels; skipping on\",
platform.system())\n",
+ "elif PY > (3, 12):\n",
+ " print(\n",
+ " \"qumat-qdp has no wheel for Python\",\n",
+ " platform.python_version(),\n",
+ " \"- pin the runtime version to 2026.07 to use Part 6\",\n",
+ " )\n",
+ "else:\n",
+ " %pip install -q \"qumat[qdp]\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-07",
+ "metadata": {},
+ "source": "If Colab shows a *Restart runtime* button after the installs,
click it and continue from the next cell. The packages stay installed."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-08",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from importlib.metadata import PackageNotFoundError, version\n",
+ "\n",
+ "from qumat import QuMat\n",
+ "\n",
+ "print(\"qumat \", version(\"qumat\"))\n",
+ "try:\n",
+ " print(\n",
+ " \"qumat-qdp\",\n",
+ " version(\"qumat-qdp\"),\n",
+ " \"(GPU extra installed; needs a GPU at run time)\",\n",
+ " )\n",
+ "except PackageNotFoundError:\n",
+ " print(\"qumat-qdp not installed (Parts 1-5 do not need it)\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-09",
+ "metadata": {},
+ "source": "## Part 1: Your first circuit, a Bell state\n\n`QuMat` is the
one class you need. You give it a backend config (which simulator to use and
how many shots), then build the circuit gate by gate.\n\nA Bell state is the
\"hello world\" of quantum computing: a Hadamard puts qubit 0 into
superposition, and a CNOT entangles qubit 1 with it. Measuring should give only
`00` and `11`, each about half the time."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "qiskit_config = {\n",
+ " \"backend_name\": \"qiskit\",\n",
+ " \"backend_options\": {\"simulator_type\": \"aer_simulator\",
\"shots\": 1024},\n",
+ "}\n",
+ "\n",
+ "qc = QuMat(qiskit_config)\n",
+ "qc.create_empty_circuit(num_qubits=2)\n",
+ "qc.apply_hadamard_gate(0)\n",
+ "qc.apply_cnot_gate(0, 1)\n",
+ "\n",
+ "print(qc.draw())\n",
+ "counts = qc.execute_circuit()\n",
+ "print(counts)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "plt.bar(counts.keys(), counts.values(), color=\"#F28C28\")\n",
+ "plt.title(\"Bell state, 1024 shots\")\n",
+ "plt.xlabel(\"measured bit string\")\n",
+ "plt.ylabel(\"counts\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-12",
+ "metadata": {},
+ "source": "**Try it:** add `qc.apply_pauli_x_gate(0)` before executing and
see how the histogram changes."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-13",
+ "metadata": {},
+ "source": "## Part 2: Same circuit, three backends\n\nThe backend is just a
config dictionary. The same gate calls run on Qiskit Aer, Cirq, or the Amazon
Braket local simulator."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bell(backend_name, simulator_type, shots=100):\n",
+ " qc = QuMat(\n",
+ " {\n",
+ " \"backend_name\": backend_name,\n",
+ " \"backend_options\": {\"simulator_type\": simulator_type,
\"shots\": shots},\n",
+ " }\n",
+ " )\n",
+ " qc.create_empty_circuit(2)\n",
+ " qc.apply_hadamard_gate(0)\n",
+ " qc.apply_cnot_gate(0, 1)\n",
+ " return qc.execute_circuit()\n",
+ "\n",
+ "\n",
+ "for name, sim in [\n",
+ " (\"qiskit\", \"aer_simulator\"),\n",
+ " (\"cirq\", \"default\"),\n",
+ " (\"amazon_braket\", \"local\"),\n",
+ "]:\n",
+ " print(f\"{name:14s} -> {bell(name, sim)}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-15",
+ "metadata": {},
+ "source": "Notice the result formats differ slightly: Qiskit and Braket
return a dict of bit strings, Cirq returns a list with integer basis states
(`3` is `11`). A small helper that normalizes these would make a nice hackathon
contribution."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-16",
+ "metadata": {},
+ "source": "## Part 3: Look at the state vector\n\nCounts are samples.
`get_final_state_vector()` returns the exact amplitudes, which is handy for
debugging and for teaching.\n\nFor the Bell state you should see amplitude
`1/sqrt(2) ~ 0.707` on `|00>` and `|11>` and zero elsewhere."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-17",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "qc = QuMat(qiskit_config)\n",
+ "qc.create_empty_circuit(2)\n",
+ "qc.apply_hadamard_gate(0)\n",
+ "qc.apply_cnot_gate(0, 1)\n",
+ "\n",
+ "state = np.asarray(qc.get_final_state_vector())\n",
+ "for index, amplitude in enumerate(state):\n",
+ " print(\n",
+ " f\"|{index:02b}> amplitude = {np.round(amplitude, 3)}
probability = {abs(amplitude) ** 2:.3f}\"\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-18",
+ "metadata": {},
+ "source": "## Part 4: Parameterized circuits and a tiny
optimization\n\nRotation gates accept a **parameter name** instead of a number.
You bind values when you execute, which is exactly what variational algorithms
(VQE, QAOA, quantum ML) need.\n\nFirst, sweep `theta` on an `Rx` gate. Theory
says `P(1) = sin^2(theta / 2)`."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-19",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "qc = QuMat(qiskit_config)\n",
+ "qc.create_empty_circuit(1)\n",
+ "qc.apply_rx_gate(0, \"theta\") # symbolic parameter\n",
+ "\n",
+ "thetas = np.linspace(0, 2 * np.pi, 13)\n",
+ "measured = []\n",
+ "for theta in thetas:\n",
+ " counts = qc.execute_circuit(parameter_values={\"theta\":
float(theta)})\n",
+ " measured.append(counts.get(\"1\", 0) / 1024)\n",
+ "\n",
+ "plt.plot(\n",
+ " thetas, np.sin(thetas / 2) ** 2, label=\"theory: sin^2(theta/2)\",
color=\"#1FA3A3\"\n",
+ ")\n",
+ "plt.plot(thetas, measured, \"o\", label=\"measured (1024 shots)\",
color=\"#F28C28\")\n",
+ "plt.xlabel(\"theta\")\n",
+ "plt.ylabel(\"P(1)\")\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-20",
+ "metadata": {},
+ "source": "Now let an optimizer drive the parameter. The cost function runs
the circuit and returns how far `P(1)` is from a target of 0.25. SciPy's COBYLA
is gradient-free, so shot noise is fine."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-21",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from scipy.optimize import minimize\n",
+ "\n",
+ "TARGET = 0.25\n",
+ "history = []\n",
+ "\n",
+ "\n",
+ "def cost(x):\n",
+ " counts = qc.execute_circuit(parameter_values={\"theta\":
float(x[0])})\n",
+ " p1 = counts.get(\"1\", 0) / 1024\n",
+ " history.append(p1)\n",
+ " return (p1 - TARGET) ** 2\n",
+ "\n",
+ "\n",
+ "result = minimize(\n",
+ " cost, x0=[0.1], method=\"COBYLA\", options={\"maxiter\": 40,
\"rhobeg\": 0.5}\n",
+ ")\n",
+ "print(f\"best theta = {result.x[0]:.3f} (theory: {2 *
np.arcsin(np.sqrt(TARGET)):.3f})\")\n",
+ "print(f\"P(1) at best theta = {history[-1]:.3f}\")\n",
+ "\n",
+ "plt.plot(history, color=\"#F28C28\")\n",
+ "plt.axhline(TARGET, linestyle=\"--\", color=\"#1FA3A3\",
label=\"target\")\n",
+ "plt.xlabel(\"evaluation\")\n",
+ "plt.ylabel(\"P(1)\")\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-22",
+ "metadata": {},
+ "source": "## Part 5: Swap test, how similar are two states?\n\nQumat has a
built-in swap test. `measure_overlap(q1, q2, ancilla_qubit)` returns the
fidelity `|<psi|phi>|^2` between the states on two qubits.\n\n- `|0>` vs `|0>`
should give about `1.0`\n- `|0>` vs `|+>` (after a Hadamard) should give about
`0.5`\n- `|0>` vs `|1>` should give about `0.0`"
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-23",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def overlap(prepare_second):\n",
+ " qc = QuMat(\n",
+ " {\n",
+ " \"backend_name\": \"qiskit\",\n",
+ " \"backend_options\": {\"simulator_type\": \"aer_simulator\",
\"shots\": 4096},\n",
+ " }\n",
+ " )\n",
+ " qc.create_empty_circuit(\n",
+ " 3\n",
+ " ) # qubit 0 = ancilla, qubit 1 = |0>, qubit 2 = state under test\n",
+ " prepare_second(qc)\n",
+ " return qc.measure_overlap(1, 2, ancilla_qubit=0)\n",
+ "\n",
+ "\n",
+ "print(\"|0> vs |0> :\", round(overlap(lambda qc: None), 3))\n",
+ "print(\"|0> vs |+> :\", round(overlap(lambda qc:
qc.apply_hadamard_gate(2)), 3))\n",
+ "print(\"|0> vs |1> :\", round(overlap(lambda qc:
qc.apply_pauli_x_gate(2)), 3))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-24",
+ "metadata": {},
+ "source": "## Part 6 (GPU): QDP, encoding classical data on the GPU\n\nQDP
(Quantum Data Plane) is the second half of Mahout. It is a Rust engine with
CUDA kernels that turns classical data into quantum state vectors directly on
the GPU and hands them to PyTorch through DLPack with no host copy.\n\n**This
part needs a GPU runtime and a Python 3.10 to 3.12 runtime** (the `qumat-qdp`
wheel has no 3.13 build yet). On the free tier pick `Runtime > Change runtime
type > T4 GPU` and, if Par [...]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import torch\n",
+ "\n",
+ " HAS_GPU = torch.cuda.is_available()\n",
+ "except ImportError: # torch is preinstalled on Colab; this only matters
elsewhere\n",
+ " HAS_GPU = False\n",
+ "\n",
+ "try:\n",
+ " import _qdp # the native extension inside the qumat-qdp wheel\n",
+ "\n",
+ " HAS_QDP = True\n",
+ "except ImportError:\n",
+ " HAS_QDP = False\n",
+ "\n",
+ "QDP_OK = HAS_GPU and HAS_QDP\n",
+ "print(\"CUDA available:\", HAS_GPU, \"| qumat-qdp installed:\",
HAS_QDP)\n",
+ "if not HAS_GPU:\n",
+ " print(\n",
+ " \"Switch to a GPU runtime and re-run from Part 0 to try QDP. The
cells below skip themselves.\"\n",
+ " )\n",
+ "elif not HAS_QDP:\n",
+ " print(\n",
+ " \"GPU found, but the qumat-qdp wheel is not installed for
Python\",\n",
+ " platform.python_version() + \".\"\n",
+ " \"\\nWheels exist for 3.10 to 3.12 only: Runtime > Change runtime
type > Runtime version > 2026.07,\"\n",
+ " \"\\nthen re-run from Part 0. The cells below skip
themselves.\",\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-26",
+ "metadata": {},
+ "source": "QDP itself was installed in Part 0 (`pip install
\"qumat[qdp]\"`). Encode four numbers into a 2-qubit state and check the
amplitudes against NumPy."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if QDP_OK:\n",
+ " from qumat.qdp import QdpEngine\n",
+ "\n",
+ " engine = QdpEngine(device_id=0) # CUDA backend by default\n",
+ "\n",
+ " data = [1.0, 2.0, 3.0, 4.0]\n",
+ " qtensor = engine.encode(data, num_qubits=2,
encoding_method=\"amplitude\")\n",
+ "\n",
+ " # DLPack hand-off: single use, so convert once and keep the
tensor.\n",
+ " state = torch.from_dlpack(qtensor)\n",
+ " print(\"shape:\", tuple(state.shape), \"dtype:\", state.dtype,
\"device:\", state.device)\n",
+ "\n",
+ " expected = np.array(data) / np.linalg.norm(data)\n",
+ " print(\"GPU amplitudes :\", state[0].real.cpu().numpy().round(4))\n",
+ " print(\"numpy reference:\", expected.round(4))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-28",
+ "metadata": {},
+ "source": "Batches are where QDP shines. Encode a few thousand samples at
once and time it."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cell-29",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if QDP_OK:\n",
+ " import time\n",
+ "\n",
+ " NUM_QUBITS = 10 # 1024 amplitudes per sample\n",
+ " BATCH = 4096\n",
+ " batch = torch.rand(BATCH, 2**NUM_QUBITS, dtype=torch.float32,
device=\"cuda\")\n",
+ "\n",
+ " torch.cuda.synchronize()\n",
+ " t0 = time.perf_counter()\n",
+ " qtensor = engine.encode(batch, num_qubits=NUM_QUBITS,
encoding_method=\"amplitude\")\n",
+ " states = torch.from_dlpack(qtensor)\n",
+ " torch.cuda.synchronize()\n",
+ " elapsed = time.perf_counter() - t0\n",
+ "\n",
+ " print(\"encoded:\", tuple(states.shape), states.dtype,
states.device)\n",
+ " print(\n",
+ " f\"{BATCH} samples in {elapsed * 1000:.1f} ms ({BATCH /
elapsed:,.0f} samples/s)\"\n",
+ " )\n",
+ "\n",
+ " # Each row is a normalized quantum state.\n",
+ " norms = states.abs().pow(2).sum(dim=1)\n",
+ " print(\"row norms (should all be ~1):\",
norms[:5].cpu().numpy().round(4))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-30",
+ "metadata": {},
+ "source": "Other encoders use the same call: `encoding_method=\"angle\"`
(one angle per qubit), `\"basis\"` (an integer index), `\"phase\"`, `\"iqp\"`
and `\"iqp-z\"`. The encoded tensor can go straight into a PyTorch model; see
`examples/qdp/simple.ipynb` in the repository for a full training loop."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cell-31",
+ "metadata": {},
+ "source": [
+ "## Part 7: Hackathon tasks and how to contribute\n",
+ "\n",
+ "Today is a **3-hour** hackathon, so every task below is sized for one to
two hours, needs no GPU, and ends in a PR with a test. The full sheet with
reproduction steps and ready-to-file issue text is `tasks.md` in the hackathon
kit; bigger follow-ups are in its appendix.\n",
+ "\n",
+ "**Track A: Qumat (Python only).** All reproduced on `main` and on `qumat`
0.6.0.\n",
+ "\n",
+ "| # | Issue | Task |\n",
+ "|---|---|---|\n",
+ "| A1 | [#1506](https://github.com/apache/mahout/issues/1506) | Clear
`ValueError` for an unknown backend name (today a `ModuleNotFoundError` leaks)
|\n",
+ "| A2 | [#1507](https://github.com/apache/mahout/issues/1507) |
Unsupported `simulator_type` should raise instead of `print()` and silently
continuing |\n",
+ "| A3 | [#1508](https://github.com/apache/mahout/issues/1508) | Cirq
backend ignores the initialized simulator and creates its own
`cirq.Simulator()` |\n",
+ "| A4 | [#1509](https://github.com/apache/mahout/issues/1509) | Bug:
reusing a parameter name on two gates fails on Qiskit only (`name conflict
adding parameter 't'`) |\n",
+ "| A5 | [#1510](https://github.com/apache/mahout/issues/1510) |
`create_empty_circuit()` without `num_qubits`: Qiskit raises, Cirq and Braket
allocate on demand |\n",
+ "| A6 | [#1511](https://github.com/apache/mahout/issues/1511) | Add
**one** missing gate per person: S, S-dagger, T-dagger, CZ or Phase, on all
three backends with a test |\n",
+ "| A7 | [#1512](https://github.com/apache/mahout/issues/1512) | Python
3.13 support: lift the `<3.13` cap in `pyproject.toml` and add 3.13 to CI (all
dependencies already ship 3.13 wheels; see Part 0) |\n",
+ "\n",
+ "**Track B: QDP.** B1 to B3 are pure Python. B4 to B6 are Rust: take one
only if `cargo` is already installed, and start the first `cargo build` right
away (5 to 10 minutes). No CUDA needed, the build uses stubs like CI does.\n",
+ "\n",
+ "| # | Issue | Task |\n",
+ "|---|---|---|\n",
+ "| B1 | [#1469](https://github.com/apache/mahout/issues/1469) |
`QdpBenchmark` does not validate builder argument ranges |\n",
+ "| B2 | [#1331](https://github.com/apache/mahout/issues/1331) | QDP tests
should skip, not error, when no GPU is present |\n",
+ "| B3 | [#1468](https://github.com/apache/mahout/issues/1468) | File
loader ignores the configured batch limit (one-line wrapper fix plus a test)
|\n",
+ "| B4 | [#1472](https://github.com/apache/mahout/issues/1472) | Read
default LZ4-compressed Feather files (Rust reader) |\n",
+ "| B5 | [#787](https://github.com/apache/mahout/issues/787) | NumPy file
size check to prevent OOM (Rust reader) |\n",
+ "| B6 | [#1436](https://github.com/apache/mahout/issues/1436) |
`StreamingProducer`: `VecDeque` for O(1) buffer advance (Rust) |\n",
+ "\n",
+ "**Setup** (in a terminal, not in Colab; about a minute):\n",
+ "\n",
+ "```bash\n",
+ "git clone https://github.com/<you>/mahout.git && cd mahout\n",
+ "pip install uv\n",
+ "uv sync # Qumat and the Python QDP package\n",
+ "uv run pre-commit install # ruff + type checks on every commit\n",
+ "uv run pytest testing/qumat # smoke test\n",
+ "```\n",
+ "\n",
+ "**Workflow:** comment on the issue to claim it, branch, make the change
with a test, open a PR that links the issue. One committer approval is required
to merge, so ping a mentor in the room. Discussion happens on
[email protected].\n",
+ "\n",
+ "Have fun, and thanks for hacking on Apache Mahout!"
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "gpuType": "T4",
+ "name": "mahout_hackathon_colab.ipynb",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}