Skip to main content

Tensor Operations for Research in Quantum systems.

Project description

TorQ Quantum Library

TorQ is a lightweight, Torch-based statevector library for fast quantum layers inside neural networks.

Developed while writing the paper: Quantum Physics-Informed Neural Networks for Maxwell's Equations: Circuit Design, "Black Hole" Barren Plateaus Mitigation, and GPU Acceleration

by Ziv Chen, Gal G. Shaviner, Hemanth Chandravamsi, Shimon Pisnoy, Steven H. Frankel, Uzi Pereg

https://arxiv.org/abs/2506.23246

For the simpler version associated with the following paper, please use the simple_for_PINNACLE branch: PINNACLE: An Open-Source Computational Framework for Classical and Quantum PINNs

by Shimon Pisnoy, Hemanth Chandravamsi, Ziv Chen, Aaron Goldgewert, Gal Shaviner, Boris Shragner, Steven H. Frankel

https://arxiv.org/abs/2604.15645

It is compatible with the TorQ-bench simple_for_PINNACLE branch and the PINNACLE repos.

When to use

  • You want a differentiable quantum layer inside a PyTorch model.
  • You care about batched statevector throughput on CPU or GPU.
  • You need analytic expectation values rather than shot-based sampling.

When not to use

  • You need realistic hardware noise models or error channels.
  • You need shot-based measurements or sampling.
  • You need hardware-aware compilation or execution on QPUs.
  • You need multi-GPU or distributed statevector simulation.

What this library optimizes for

  • Speed inside a neural-network forward and backward pass.
  • Batched evaluation of many inputs at once.
  • Single-device training workflows.

This library was benchmarked primarily on NVIDIA L40s and A100 GPUs. Performance on other hardware has not been tuned and may differ.

Install

TorQ requires Python 3.10+ and PyTorch 1.13+.

# install from PyPI
python -m pip install torq-quantum

# optional: editable install for local development
python -m pip install -e .

The PyPI package name is torq-quantum, while the Python import path is torq.

If you want to use the optional PennyLane comparison backend, you also need importable pennylane and torq_bench packages in the same environment.

Quickstart

torq.simple.Circuit is the recommended student-facing API.

import torch
from torq.simple import Circuit, CircuitConfig

circuit = Circuit(
    n_qubits=4,
    n_layers=2,
    ansatz_name="basic_entangling",
    config=CircuitConfig(),
)

x = torch.rand(8, 4)
y = circuit(x)

print(y.shape)  # torch.Size([8, 4])

By default, the output is the local Pauli-Z expectation value on each qubit, so the shape is [batch, n_qubits].

Student-facing API

  • Circuit: torch.nn.Module wrapper around TorQ's internal QLayer.
  • CircuitConfig: configuration object for encoding, ansatz options, measurements, and backend selection.
  • circuit.params: trainable main parameter tensor.
  • circuit.params_last_layer_reupload: extra trainable tensor used only when data_reupload_every > 0.

TorQ also exposes lower-level helpers through torq.simple:

from torq.simple import (
    angle_embedding,
    data_reuploading,
    data_reuploading_gates,
    get_initial_state,
    measure,
)

Supported ansatzes

TorQ currently supports these ansatz names:

  • basic_entangling
  • single_rot_basic_ent
  • strongly_entangling
  • tile
  • cross_mesh
  • cross_mesh_2_rots
  • cross_mesh_cx_rot
  • no_entanglement_ansatz

Notes:

  • single_rot_basic_ent uses the same CNOT ladder as basic_entangling, but only one rotation parameter per qubit. The rotation axis is chosen with single_rotation_gate.
  • tile uses a brick-wall CNOT pattern. Within each sublayer it applies (0,1), (2,3), ..., then (1,2), (3,4), .... If tile_cyclic=True and n_qubits is even, it also adds a wraparound CX(n_qubits - 1, 0) per sublayer.
  • no_entanglement_ansatz applies only single-qubit rotations.

Relevant CircuitConfig fields:

  • single_rotation_gate: rotation axis used by single_rot_basic_ent, and by tile when tile_rotation_params=1. Supported values are "x", "rx", "y", "ry", "z", "rz".
  • tile_rotation_params: 1 or 3.
  • tile_sublayers: number of repeated brick-wall sublayers per layer.
  • tile_cyclic: whether tile adds the even-qubit wraparound CNOT.

Example: tile

import torch
from torq.simple import Circuit, CircuitConfig

cfg = CircuitConfig(
    tile_rotation_params=1,
    single_rotation_gate="rz",
    tile_sublayers=2,
    tile_cyclic=True,
)

circuit = Circuit(
    n_qubits=6,
    n_layers=2,
    ansatz_name="tile",
    config=cfg,
)

x = torch.rand(8, 6)
y = circuit(x)

Angle embedding and scaling

CircuitConfig controls angle embedding with these fields:

  • basis_angle_embedding: "x", "rx", "y", "ry", "z", or "rz".
  • angle_scaling_method: "none", "scale", "scale_with_bias", "asin", or "acos".
  • angle_scaling: scaling factor used by "scale" and "scale_with_bias".

The nonlinear scaling modes are mainly intended for inputs that already live near [-1, 1], for example after a tanh.

Scaling methods:

  • "none": leaves the input unchanged.
  • "scale": computes angles * angle_scaling.
  • "scale_with_bias": computes (angles + 1) * (angle_scaling / 2).
  • "asin": computes asin(angles) + pi / 2 after a small internal clamp for numerical stability.
  • "acos": computes acos(angles) after a small internal clamp for numerical stability.
import torch
from torq.simple import Circuit, CircuitConfig

cfg = CircuitConfig(
    angle_scaling_method="scale",
    angle_scaling=torch.pi,
    basis_angle_embedding="Y",
)

circuit = Circuit(
    n_qubits=4,
    n_layers=2,
    ansatz_name="basic_entangling",
    config=cfg,
)

x = torch.rand(8, 4)
y = circuit(x)

Data reuploading

Set data_reupload_every > 0 to enable TorQ's legacy repeated-upload execution scheme.

When data_reupload_every = k:

  • each logical layer applies k ansatz blocks before a data upload,
  • after the final upload, TorQ applies one more tail of k ansatz blocks,
  • the model therefore owns both circuit.params and circuit.params_last_layer_reupload.

This increases simulation cost and memory use.

import torch
from torq.simple import Circuit, CircuitConfig

cfg = CircuitConfig(data_reupload_every=2)
circuit = Circuit(
    n_qubits=4,
    n_layers=2,
    ansatz_name="cross_mesh",
    config=cfg,
)

x = torch.rand(8, 4)
y = circuit(x)

Notes:

  • For strongly_entangling, data_reupload_every must be <= n_layers.
  • If you pass manual weights and data_reupload_every == 0, weights may be shaped as either [n_layers, ...] or [n_layers, 1, ...].
  • If you pass manual weights and data_reupload_every > 0, weights must have shape [n_layers, data_reupload_every, ...], and weights_last_layer_data_re must have shape [data_reupload_every, ...].

Measurements and observables

Use CircuitConfig(observables=...) to control the output measurement.

Supported inputs:

  • None: default local Pauli-Z on every qubit, returning [batch, n_qubits].
  • Pauli string: one or more Pauli words separated by _, case-insensitive.
  • Hermitian matrix or matrices:
    • [2, 2] shared local observable for every qubit
    • [n_qubits, 2, 2] per-qubit local observables
    • [2**n, 2**n] one full-system observable
    • [m, 2**n, 2**n] multiple full-system observables

Pauli-string rules:

  • Allowed characters are I, X, Y, Z, and _.
  • A Pauli word of length L is measured on every contiguous L-qubit window.
  • _ concatenates multiple Pauli-word groups into one output tensor.
  • An all-identity observable such as "I_I_I" is rejected.

Examples:

  • "z" returns local Z_i on every qubit.
  • "xx" returns X_i X_{i+1} on every adjacent pair.
  • "z_zz_x" returns all Z_i, then all Z_i Z_{i+1}, then all X_i.

pauli_measurement_chunk_size tunes the throughput-versus-memory tradeoff for grouped Pauli-string measurements. Repeated all-Z words such as "zz" and "zzz" use a dedicated fast path.

import torch
from torq.simple import Circuit, CircuitConfig

q = 4

cfg = CircuitConfig(
    observables="z_zz_x",
    pauli_measurement_chunk_size=8,
)

circuit = Circuit(
    n_qubits=q,
    n_layers=2,
    ansatz_name="basic_entangling",
    config=cfg,
)

x = torch.rand(8, q)
y = circuit(x)

print(y.shape)  # torch.Size([8, 11])

If local Pauli-Z is the only output you need, leaving observables=None is still the fastest path.

Initialization and advanced options

Useful CircuitConfig flags:

  • init_identity=True: initialize all parameters to 0.
  • init_ones=True: initialize all parameters to pi.
  • init_pi_half=True: initialize all parameters to pi / 2.
  • reparametrize_sin_cos=True: internally wraps angles through atan2(sin(theta), cos(theta)).
  • pennylane_backend=True: try to run through the optional PennyLane comparison backend.
  • pennylane_dev_name: PennyLane device name, defaulting to "default.qubit".

noise_all_q_layers is only used by TorQ's legacy param_init_dict initialization path.

Optional PennyLane backend

TorQ can optionally delegate execution to a PennyLane comparison backend:

from torq.simple import Circuit, CircuitConfig

cfg = CircuitConfig(
    pennylane_backend=True,
    pennylane_dev_name="default.qubit",
)

circuit = Circuit(
    n_qubits=2,
    n_layers=1,
    ansatz_name="strongly_entangling",
    config=cfg,
)

Notes:

  • TorQ only uses this path if both pennylane and torq_bench are importable.
  • If the requested basis, observables, or ansatz are unsupported by the PennyLane comparison backend, TorQ emits a warning and falls back to the native TorQ backend.
  • This path is mainly useful for parity checks and benchmarking rather than for normal TorQ usage.

Benchmarking

For benchmark scripts and PennyLane comparisons, use the TorQ-bench repository:

https://github.com/zivchen9993/TorQ-bench

Limitations

  • Statevector simulation only, so memory scales as O(2^n_qubits).
  • Analytic measurements only; no shots or sampling.
  • Ideal, noise-free gates and measurements.

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

torq_quantum-0.1.3.tar.gz (36.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

torq_quantum-0.1.3-py3-none-any.whl (31.9 kB view details)

Uploaded Python 3

File details

Details for the file torq_quantum-0.1.3.tar.gz.

File metadata

  • Download URL: torq_quantum-0.1.3.tar.gz
  • Upload date:
  • Size: 36.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.13

File hashes

Hashes for torq_quantum-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a92793d331143397b353e9735e472ad12bbe4e2d2ed8a4c107276ebf237ef0c6
MD5 37175658ca212766a2f9e84577bed413
BLAKE2b-256 02b6ab27d4e44c3cfcc6be3a338442fde043b02ac352c4de08b3c0a6316fb8ab

See more details on using hashes here.

File details

Details for the file torq_quantum-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: torq_quantum-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 31.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.13

File hashes

Hashes for torq_quantum-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 a301312da3b88f4726b48bf32fef87725a5d1c30fd6d764f0ccc8080cae370dc
MD5 b8ecc697ba27938447c3788d808a66ba
BLAKE2b-256 c3931c28c4ce5b49c85bc0c066fc78da7fc917545571063424e0d4930d3bc942

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page