Getting Started¶
Install the package, run a circuit, read the results. If Matrix Product State, bond dimension, or truncation are new to you, read Concepts first: this page assumes them.
Installation¶
Wheels are published on tagged releases to the QPerfect GitLab package registry, which requires authentication:
pip install mimiq-tensorweaver \
--index-url https://__token__:<your-access-token>@gitlab.qperfect.io/api/v4/projects/29/packages/pypi/simple
To avoid repeating the index URL, configure it in ~/.pip/pip.conf:
[global]
index-url = https://__token__:<your-access-token>@gitlab.qperfect.io/api/v4/projects/29/packages/pypi/simple
then pip install mimiq-tensorweaver.
index-url, not extra-index-url. The same distribution name is published on
public PyPI as the unlicensed mock (see Without a licence), and with
both indexes in play pip is free to take either copy of a name it finds in
both, so pip install -U could replace a licensed install with the mock. An
exclusive index-url removes the ambiguity.
The registry does not proxy PyPI, so dependencies have to come from somewhere:
pass --extra-index-url https://pypi.org/simple on the install, or keep a
second [install] section for it, rather than demoting the QPerfect index back
to an extra.
With uv¶
uv does not read pip.conf. For a one-off install, pass the registry as an
index:
uv pip install mimiq-tensorweaver \
--index https://__token__:<your-access-token>@gitlab.qperfect.io/api/v4/projects/29/packages/pypi/simple
uv takes each package from the first index that has it, so the licensed wheel wins over the PyPI mock and every other dependency still comes from PyPI.
In a uv project, declare the registry in pyproject.toml and pin
mimiq-tensorweaver to it:
[[tool.uv.index]]
name = "qperfect"
url = "https://gitlab.qperfect.io/api/v4/projects/29/packages/pypi/simple"
explicit = true # only packages pinned below are fetched from it
[tool.uv.sources]
mimiq-tensorweaver = { index = "qperfect" }
and keep the token out of the file by passing it through the environment:
export UV_INDEX_QPERFECT_USERNAME=__token__
export UV_INDEX_QPERFECT_PASSWORD=<your-access-token>
uv add mimiq-tensorweaver
To make the registry available everywhere instead, put the same table in
~/.config/uv/uv.toml as [[index]], without explicit = true (uv.toml has
no sources table to pin a package with). The first-index rule then keeps the
licensed wheel ahead of the mock.
The Qiskit integration is an optional extra:
So are the plots in tensorweaver.visualization, which need matplotlib:
Supported platforms¶
Wheels target Python's stable ABI, so one wheel per platform serves Python 3.11 and later. The free-threaded interpreter is served by a wheel of its own, since it has no stable ABI to target; see Free-threaded Python.
| Platform | Wheel tag | Requires |
|---|---|---|
| Linux x86_64 | manylinux_2_35_x86_64 |
glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+); pulls the mkl runtime (~224 MB) |
| Linux x86_64 | manylinux_2_34_x86_64 |
glibc 2.34 (RHEL 9 and its rebuilds); pulls the mkl runtime (~224 MB) |
| macOS arm64 | macosx_26_0_arm64 |
macOS 26 or later, Apple Silicon |
| Windows x86_64 | win_amd64 |
Windows 10/11 x64; pulls the mkl runtime (~180 MB) |
Linux x86_64, python3.14t |
cp314-cp314t-manylinux_2_35_x86_64 |
glibc 2.35 or newer; free-threaded 3.14 only |
Linux x86_64, python3.14t |
cp314-cp314t-manylinux_2_34_x86_64 |
glibc 2.34 (RHEL 9 and its rebuilds); free-threaded 3.14 only |
The mkl dependency is what makes linalg="mkl" work out of the box. MKL cannot
be bundled into a wheel, so the wheels that have an MKL engine depend on it
instead; see Linear-algebra
engine. The
Linux default engine is the vendored OpenBLAS and needs nothing.
Linux has two wheels, for glibc 2.35 and for glibc 2.34, because RHEL 9 ships
2.34. pip selects the one matching your host automatically. Check your version
with ldd --version. Hosts below 2.34, such as RHEL 8 and Ubuntu 20.04, are not
covered.
There are no wheels for Intel macOS or Linux aarch64. If pip reports no
matching distribution, check this table first.
Licensing¶
The published wheel is licensed, and one binary serves both models. The license file decides at runtime which applies.
| Model | How it validates |
|---|---|
| Node-locked | Checks ~/.mimiq/license.key against the machine fingerprint, fully offline |
| Floating | Leases a short-lived seat from $QP_LICENSE_SERVER |
Activate with the bundled qp-license CLI, also reachable as
tensorweaver license:
From source¶
Source builds need a Rust toolchain, OpenBLAS + LAPACKE development packages,
protoc, and SSH access to the QPerfect GitLab: Cargo fetches the Rust core,
tensorweaver-rs, at the revision pinned in Cargo.toml.
git clone git@gitlab.qperfect.io:development/tensorweaver/tensorweaver-python.git
cd tensorweaver-python
scripts/dev-build.sh # builds both BLAS engines into an editable install
To build against a local checkout of tensorweaver-rs instead, clone it next to
tensorweaver-python and pass --config 'paths=["../tensorweaver-rs"]' to
cargo or maturin.
maturin develop on its own builds only the MKL engine. That still runs, since
the default engine follows the build, but it needs the MKL runtime on the
system and gives you nothing to compare against, which is why dev-build.sh
exists. See Linear-algebra engine
for the runtime switch, and the repository README for build variants.
Verify the install¶
The documentation ships inside the wheel, with nothing loaded from the network, so it works on a machine that has none. Read it with:
That serves the site on a free loopback port and opens a browser on it, and
keeps running until you interrupt it. Pass --port to pin the port, or
--print-path to print where the files live instead of serving them.
Your first circuit¶
Build the circuit with mimiqcircuits, run it with execute().
from mimiqcircuits import Circuit, GateH, GateCX, Measure
from tensorweaver import execute
# A Bell pair: H on qubit 0, then CX from 0 to 1.
c = Circuit()
c.push(GateH(), 0)
c.push(GateCX(), 0, 1)
c.push(Measure(), 0, 0)
c.push(Measure(), 1, 1)
results = execute(c, nsamples=1000, bonddim=64, seed=42)
Two keywords carry most of the meaning:
nsamplesis how many shots you want.bonddimcaps the bond dimension, which is the accuracy/cost dial. 64 is ample for a Bell pair; see Concepts for how to choose it, and Circuit Execution for every other keyword.
Reading the results¶
execute() returns a MIMIQ QCSResults.
print(results.histogram())
# {bs"00": 511, bs"11": 489}
print(results.fidelities[0])
# 1.0 -- nothing was discarded to truncation
print(results.timings)
# {'compile': ..., 'apply': ..., 'sample': ..., 'total': ...}
histogram()counts each measured classical state. Roughly half00and half11, with no01or10, is the Bell correlation.fidelitiesreports how much weight truncation discarded, one entry per evolution.1.0means none. Treat it as a screen rather than a certificate: reading the reported fidelity explains what it does and does not cover.timingsbreaks wall-clock seconds intocompile,apply,sample, andtotal.
Individual shots are in results.cstates:
Asking for amplitudes¶
Pass the bitstrings you want and read them back from results.amplitudes.
The amplitudes are read at the end of the circuit, so leave the measurements
out: a measured state has already collapsed.
from mimiqcircuits import BitString
bell = Circuit()
bell.push(GateH(), 0)
bell.push(GateCX(), 0, 1)
bs00, bs11 = BitString([0, 0]), BitString([1, 1])
results = execute(bell, nsamples=1, bonddim=64, bitstrings=[bs00, bs11])
print(results.amplitudes[bs00]) # ~0.7071+0j
print(results.amplitudes[bs11]) # ~0.7071+0j
Qiskit users
TensorWeaver is little-endian by qubit index: bitstring position i is
qubit i, so bs[0] is qubit 0. Qiskit puts the highest-indexed qubit on
the left, so bitstrings from results.cstates, results.histogram(), and
mps.sample_bitstring() appear reversed compared to Qiskit output. The
same convention applies to any BitString you pass in.
Plotting the bond structure¶
With the visualization extra, plotbonds shows the bond dimension and the
entanglement entropy of every cut, with the bonds at the cap in red, and
plotschmidt the Schmidt spectrum of one cut. BondWindow follows a state as
you evolve it.
from tensorweaver.visualization import plotbonds
fig = plotbonds(state) # state: a TwState, such as TwSimulator.evolvezerostate returns
See Visualization for how to read the plots and use the window.
Where to go next¶
- Concepts for bond dimension, fidelity, and execution modes.
- Circuit Execution for every
execute()keyword. - Examples for runnable scripts bundled with the package.
- Visualization to plot the bond structure, or watch it grow.
- API Reference for the low-level
MPSandMPOclasses.
The examples ship inside the installed package: