Skip to content

Repository files navigation

Quantum Encoding Atlas

The comprehensive library for quantum data encodings in machine learning

PyPI version Python versions License: MIT CI codecov Documentation DOI Website

Documentation | Website | Tutorials | API Reference | PyPI


Overview

The Quantum Encoding Atlas is the definitive open-source resource for understanding, comparing, and selecting quantum data encodings for machine learning applications.

Features

  • 📊 16 Encoding Methods — Comprehensive implementations of all major quantum data encodings
  • 🔀 Multi-Framework Support — Works seamlessly with PennyLane, Qiskit, and Cirq
  • 📈 Analysis Tools — Compute expressibility, entanglement capability, and trainability
  • 🧪 Benchmarking Framework — Systematic comparison infrastructure, with scikit-learn-compatible estimators
  • 🧭 Decision Guide — Evidence-based encoding recommendations, plus training-free screening on your own data
  • 🗺️ Empirical Atlas — Query the measured benchmark results (rank, accuracy, expressibility, trainability, …) bundled with the package
  • 📉 Concentration Diagnostics — Measure whether an encoding's kernel survives to wider circuits, and what it costs in shots
  • 📐 Scaling Sensitivity — Measure what the feature range costs; for entangling maps it moves accuracy more than the encoding does
  • 📚 Extensive Documentation — Tutorials, API docs, and theoretical background

Installation

pip install encoding-atlas

With optional backends:

# With Qiskit support
pip install encoding-atlas[qiskit]

# With Cirq support
pip install encoding-atlas[cirq]

# With all backends
pip install encoding-atlas[all]

# Development installation
pip install encoding-atlas[dev]

Quick Start

from encoding_atlas import IQPEncoding, AngleEncoding
from encoding_atlas.analysis import compute_expressibility
import numpy as np

# Create encodings
iqp = IQPEncoding(n_features=4, reps=2)
angle = AngleEncoding(n_features=4, rotation='Y')

# Generate circuits (PennyLane by default)
X = np.random.randn(10, 4)
circuit = iqp.get_circuit(X[0])

# Analyze properties
print(f"IQP qubits: {iqp.n_qubits}")
print(f"IQP depth: {iqp.depth}")
print(f"IQP expressibility: {compute_expressibility(iqp, n_samples=500):.4f}")

# Get encoding recommendation
from encoding_atlas.guide import recommend_encoding

rec = recommend_encoding(
    n_features=4,
    n_samples=500,
    task='classification',
    hardware='simulator'
)
print(f"Recommended: {rec.encoding_name}")
print(f"Reason: {rec.explanation}")

Screen encodings on your own data

recommend_encoding answers from metadata. Once you have data, screen the encodings against it — no training, about a second for all 16:

from encoding_atlas.benchmark import get_dataset, evaluate_encoding
from encoding_atlas.guide import screen_encodings

X, y = get_dataset("moons", n_samples=200, seed=0)
result = screen_encodings(X, y, seed=0)

for c in result.top(3):
    print(f"{c.rank}. {c.name:22s} alignment={c.alignment:+.3f}")

# Candidates come back built and ready to train
for c in result.top(3):
    print(c.name, evaluate_encoding(c.encoding, X, y, method="kernel")["mean"])

The ranking key is the centered kernel-target alignment, which the benchmark found tracks kernel accuracy closely (Spearman ρ = 0.91 across encodings and datasets). Treat the result as a shortlist, not an oracle: on the benchmark's eight datasets the top-3 shortlist lands within 0.001 of the best achievable accuracy, while the single top pick (0.960) is no better than simply always choosing angle (0.958). Screening buys you a 3-encoding shortlist instead of 16, and adapts when your data doesn't resemble the benchmark's.

Encodings that can't be built at your feature count are reported, not raised:

result.skipped     # {'so2_equivariant': 'ValueError: ... requires n_features=2 ...'}

Choose how to scale your features

Encodings turn numbers into rotation angles, so the range you scale into changes the kernel's geometry. It is not a minor knob — IQP swings 34 accuracy points across four ranges, and [0, 2π] (a full rotation period, and the pipeline's own default) is the worst of them for every entangling map:

from encoding_atlas.analysis import recommend_feature_range, scale_to_range

low, high = recommend_feature_range(IQPEncoding(n_features=2, reps=2), X, y, seed=0)
X_scaled = scale_to_range(X, low, high)

Search encodings and ranges together by passing feature_ranges= to the screener:

from encoding_atlas.analysis import DEFAULT_FEATURE_RANGES

result = screen_encodings(X, y, seed=0, feature_ranges=DEFAULT_FEATURE_RANGES)
print(result.best().name, result.best().feature_range)

The measured sensitivity for all 16 encodings ships with the package, including how far the benchmark's own expressibility-versus-accuracy correlation moves with the range — it reverses sign between [0, π/2] (ρ = +0.78) and the pipeline's [0, 2π] (ρ = −0.54), both significant. See Feature Scaling.

from encoding_atlas.atlas import scaling_sensitive_encodings

print([(p.name, round(p.accuracy_spread, 2)) for p in scaling_sensitive_encodings()][:3])
# [('iqp', 0.34), ('hamiltonian', 0.27), ('pauli_feature_map', 0.21)]

Query the empirical atlas

The measured benchmark results for every encoding ship with the package as a queryable, read-only API:

from encoding_atlas.atlas import get_encoding_profile, rank_encodings, pareto_front

# Measured profile of a single encoding
angle = get_encoding_profile("angle")
print(angle.rank, round(angle.metric("kernel_accuracy"), 3))   # 1 0.958

# Rank encodings by any measured metric
print([p.name for p in rank_encodings(by="kernel_accuracy", limit=3)])
# ['angle', 'cyclic_equivariant', 'qaoa']

# Including the benchmark's validated predictor of accuracy
print([p.name for p in rank_encodings(by="kernel_target_alignment", limit=3)])
# ['amplitude', 'angle', 'so2_equivariant']

# The Pareto-optimal set across accuracy, depth, trainability, and noise
print(sorted(p.name for p in pareto_front()))
# ['angle', 'basis', 'higher_order_angle', 'swap_equivariant']

Benchmark encodings on your own data

Run variational-quantum-classifier and quantum-kernel comparisons with paired cross-validation, classical baselines, and statistical testing:

from encoding_atlas import AngleEncoding, IQPEncoding
from encoding_atlas.benchmark import EncodingBenchmark, evaluate_encoding

# Compare encodings across datasets and methods
bench = EncodingBenchmark(
    encodings=[AngleEncoding(n_features=2), IQPEncoding(n_features=2)],
    datasets=["moons", "circles"],
    methods=("vqc", "kernel"),
    n_runs=3,
    n_folds=5,
    baselines=("svm_rbf",),
    seed=0,
)
results = bench.run()
stats = bench.statistical_tests()   # Wilcoxon + Holm–Bonferroni + Cliff's delta

# ...or evaluate a single encoding on your own (X, y)
report = evaluate_encoding(AngleEncoding(n_features=2), X, y, method="kernel")
print(report["mean"], report["ci_low"], report["ci_high"])

Both binary and multi-class classification are supported — pass multi-class labels or a built-in multi-class dataset (list_multiclass_datasets(), e.g. "iris3", "blobs3"); the VQC uses a one-vs-rest ensemble and metrics switch to macro averaging automatically.

Regression is supported via task="regression", which reports R² and uses K-fold splits (stratification is undefined for continuous targets):

from encoding_atlas.benchmark import get_regression_dataset

X, y = get_regression_dataset("sine_reg", n_samples=120, seed=0)
report = evaluate_encoding(
    AngleEncoding(n_features=2), X, y, task="regression", method="kernel"
)
print(report["score_metric"], report["mean"])   # r2 0.97

Use the estimators with scikit-learn

VQCClassifier, VQCRegressor, QuantumKernelClassifier and QuantumKernelRegressor follow scikit-learn's estimator contract, so they drop straight into the tooling you already use:

from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import MinMaxScaler

from encoding_atlas import AngleEncoding, IQPEncoding
from encoding_atlas.benchmark import QuantumKernelClassifier, get_dataset

X, y = get_dataset("moons", n_samples=120, seed=0)
clf = QuantumKernelClassifier(AngleEncoding(n_features=2))

cross_val_score(clf, X, y, cv=5)

# Scaling matters (see below), so tune it in a pipeline
pipe = make_pipeline(MinMaxScaler((0, 3.14 / 2)), clf).fit(X, y)

# The encoding itself is a tunable hyper-parameter
search = GridSearchCV(
    clf,
    {"encoding": [AngleEncoding(n_features=2), IQPEncoding(n_features=2, reps=2)],
     "C": [0.5, 1.0, 2.0]},
    cv=5,
).fit(X, y)
print(search.best_params_)

Pipeline, cross_validate, learning_curve, VotingClassifier, CalibratedClassifierCV and anything else that clones an estimator all work. QuantumKernelClassifier also exposes decision_function, so ROC-AUC and probability calibration are available.

As in scikit-learn, hyper-parameters are validated at fit time rather than in the constructor — QuantumKernelClassifier(enc, C=-1) constructs and then raises when fitted, exactly like SVC(C=-1).

Diagnose why an encoding generalizes

Cheap, training-free kernel-geometry metrics that predict downstream performance — kernel-target alignment, geometric difference, and effective dimension:

from encoding_atlas.analysis import (
    compute_kernel_target_alignment,
    compute_geometric_difference,
    compute_effective_dimension,
)

# How well the encoding's kernel matches the task (predicts accuracy)
kta = compute_kernel_target_alignment(AngleEncoding(n_features=2), X, y)

# How distinct the quantum kernel is from a classical one (advantage diagnostic)
gd = compute_geometric_difference(AngleEncoding(n_features=2), X)

# Effective feature-space dimension the encoding uses (capacity)
d_eff = compute_effective_dimension(AngleEncoding(n_features=2), X)

Check whether an encoding survives to wider circuits

Every other axis describes an encoding at a fixed width. Kernel concentration describes what happens as the width grows — whether the fidelity kernel keeps enough structure to learn from, and what it costs in shots:

from encoding_atlas.analysis import compute_kernel_concentration

angle = compute_kernel_concentration(AngleEncoding(n_features=6), seed=0)
iqp = compute_kernel_concentration(IQPEncoding(n_features=6, reps=2), seed=0)

print(angle.concentration_ratio, angle.is_concentrated)   # 9.0  False
print(iqp.concentration_ratio, iqp.is_concentrated)       # 1.0  True
print(iqp.shots_per_entry)                                # 259 shots per kernel entry

concentration_ratio is the kernel's off-diagonal variance divided by the Haar-random variance at the same width. A value near 1 means the kernel has collapsed to the identity up to sampling noise — a kernel method cannot generalize from it at any shot budget. Sweep it across widths to get a decay rate and an extrapolated horizon:

from encoding_atlas.analysis import estimate_concentration_scaling

scaling = estimate_concentration_scaling(
    lambda d: IQPEncoding(n_features=d, reps=2), feature_counts=(2, 4, 6, 8), seed=0
)
print(scaling.decay_rate)               # 3.9 — near the maximal (Haar) rate of 4.0
print(scaling.concentration_horizon())  # 2  — already at the floor
print(scaling.shots_per_entry_at(20))   # extrapolated hardware cost at 20 qubits

The scan for all 16 encodings ships with the package. The four encodings whose kernels reach the Haar floor are exactly the four with expressibility ≈ 0.999, and four of the five worst-ranked in the benchmark — which is why expressibility fails to predict accuracy:

from encoding_atlas.atlas import concentrated_encodings

print(sorted(p.name for p in concentrated_encodings()))
# ['hamiltonian', 'iqp', 'pauli_feature_map', 'zz_feature_map']

Run diagnostics under a realistic shot budget

Pass shots= to get the kernel a real device would return. The compute-uncompute estimator's all-zeros count is exactly Binomial(shots, K), so this is statistically identical to running the circuits:

from encoding_atlas.analysis import compute_fidelity_kernel

K = compute_fidelity_kernel(AngleEncoding(n_features=2), X, shots=1000, seed=0)
kta = compute_kernel_target_alignment(
    AngleEncoding(n_features=2), X, y, shots=1000, seed=0
)

Sampled kernels stay symmetric with a unit diagonal but are no longer PSD — project with encoding_atlas.benchmark.kernel.ensure_psd before fitting.

Measure noise resilience

Simulate an encoding under a depolarizing noise model and measure the retained state fidelity — entangling encodings degrade far more than non-entangling ones:

from encoding_atlas.analysis import compute_noise_resilience

result = compute_noise_resilience(AngleEncoding(n_features=4), noise_level="medium")
print(result.retained_fidelity, result.fidelity_decay)   # e.g. 0.987 0.013

Profile any encoding in one call

Characterize an encoding — including your own custom one — across every axis, and rank it against the 16 built-in encodings:

from encoding_atlas.analysis import profile_encoding, compare_to_atlas

profile = profile_encoding(AngleEncoding(n_features=2), X=X, y=y)
print(profile.metrics)            # depth, expressibility, entanglement, trainability,
                                  # noise, kernel-target alignment, effective dimension, ...

cmp = compare_to_atlas(profile, "expressibility")
print(cmp["rank"], cmp["percentile"])   # where it ranks among the atlas encodings

Supported Encodings

Category Encodings
Amplitude-based AmplitudeEncoding
Angle-based AngleEncoding (RX/RY/RZ), HigherOrderAngleEncoding
Basis BasisEncoding
Entangling IQPEncoding, ZZFeatureMap, PauliFeatureMap
Advanced DataReuploading, HardwareEfficientEncoding, QAOAEncoding, HamiltonianEncoding
Symmetry & Equivariant SymmetryInspiredFeatureMap, SO2EquivariantFeatureMap, CyclicEquivariantFeatureMap, SwapEquivariantFeatureMap
Trainable TrainableEncoding

See the full encoding list for details.

Documentation

Citation

If you use this library in your research, please cite:

@software{Mishra2026encoding,
  title={Quantum Encoding Atlas: A Comprehensive Library for Quantum Data Encodings},
  author={Mishra, Ashutosh},
  year={2026},
  doi={10.5281/zenodo.18780936},
  url={https://doi.org/10.5281/zenodo.18780936},
  version={1.0.0}
}

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Open Source Python library for Quantum Data Encodings in Quantum ML - multi-framework support, analysis tools

Topics

Resources

Contributing

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages